A bug in busdma_machdep-v6.c?
Thomas Skibo
ThomasSkibo at sbcglobal.net
Sun Mar 3 00:02:52 UTC 2013
Hello.
I've been trying to solve a tcp checksum bug and I think I see a problem
in _bus_dmamap_load_buffer():
In the following code bit, a segment is tacked onto the previous
segment's slist[] entry if it is adjacent to the previous segment in
virtual memory. That's okay if all cache operations use virtual
addresses but if the level 2 cache operations need physical addresses
(ARM_L2_PIPT), the physical address of the second segment is lost. I
don't think bus_dmamap_sync() is properly wb/invalidating the second
segment from the level 2 cache.
1008 sl = &map->slist[map->sync_count - 1];
1009 if (map->sync_count == 0 ||
1010 vaddr != sl->vaddr + sl->datacount) {
1011 if (++map->sync_count > dmat->nsegments)
1012 goto cleanup;
1013 sl++;
1014 sl->vaddr = vaddr;
1015 sl->datacount = sgsize;
1016 sl->busaddr = curaddr;
1017 } else
1018 sl->datacount += sgsize;
1019 }
I was seeing bad checksums on large packets. While examining the dma
descriptors of the offending packets, I noticed that the second of three
segments always ended on a page boundary so I just guessed the second
and third were one buffer straddling a page boundary.
So far, this patch is fixing the problem for me:
***************
*** 1007,1012 ****
--- 1007,1015 ----
} else {
sl = &map->slist[map->sync_count - 1];
if (map->sync_count == 0 ||
+ #ifdef ARM_L2_PIPT
+ curaddr != sl->busaddr + sl->datacount ||
+ #endif
vaddr != sl->vaddr + sl->datacount) {
if (++map->sync_count > dmat->nsegments)
goto cleanup;
--
--------
Thomas Skibo
ThomasSkibo at sbcglobal.net
More information about the freebsd-arm
mailing list