Skip site navigation (1)Skip section navigation (2)
Date:      Sat, 02 Mar 2013 16:02:45 -0800
From:      Thomas Skibo <ThomasSkibo@sbcglobal.net>
To:        freebsd-arm@freebsd.org
Subject:   A bug in busdma_machdep-v6.c?
Message-ID:  <51329325.7070301@sbcglobal.net>

next in thread | raw e-mail | index | archive | help

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@sbcglobal.net




Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?51329325.7070301>