5.2-RC oerrs and collisions on dc0
Don Lewis
truckman at FreeBSD.org
Mon Jan 5 12:07:30 PST 2004
On 5 Jan, Maxime Henrion wrote:
> Don Lewis wrote:
>> I just took a closer look at the busdma diff, and this change to
>> dc_txeof() looks very suspicious:
>>
>> @@ -2663,7 +2809,7 @@
>> if (txstat & DC_TXSTAT_OWN)
>> break;
>>
>> - if (!(cur_tx->dc_ctl & DC_TXCTL_LASTFRAG) ||
>> + if (!(cur_tx->dc_ctl & DC_TXCTL_FIRSTFRAG) ||
>> cur_tx->dc_ctl & DC_TXCTL_SETUP) {
>> if (cur_tx->dc_ctl & DC_TXCTL_SETUP) {
>> /*
>>
>> The code in the "if" block ends with a "continue" which will cause the
>> error handling code to be skipped if the "if" condition is true. I'm
>> pretty sure that the error status bits are only set in the last
>> descriptor for the frame, so we want to execute the "continue" unless
>> the DC_TXCTL_LASTFRAG bit is set.
>>
>> Try reverting this part of the busdma change.
>
> I think you actually found the culprit, though fixing this is not as
> simple as reverting this line. I changed the check to
> DC_TXCTL_FIRSTFRAG because that's the descriptor which will have a link
> to the mbuf, while it was previously done for the LASTFRAG descriptor.
> However, I didn't think about the code flow enough it seems. If you
> don't have a fix for this soon, I should be able to do it pretty easily,
> assuming I find the time.
How about something like the following. I can't test it because I don't
have the appropriate hardware, but at least it compiles ;-)
Index: sys/pci/if_dc.c
===================================================================
RCS file: /home/ncvs/src/sys/pci/if_dc.c,v
retrieving revision 1.137
diff -u -r1.137 if_dc.c
--- sys/pci/if_dc.c 6 Dec 2003 02:29:31 -0000 1.137
+++ sys/pci/if_dc.c 5 Jan 2004 20:00:04 -0000
@@ -2859,7 +2859,7 @@
if (txstat & DC_TXSTAT_OWN)
break;
- if (!(ctl & DC_TXCTL_FIRSTFRAG) || ctl & DC_TXCTL_SETUP) {
+ if (!(ctl & DC_TXCTL_LASTFRAG) || ctl & DC_TXCTL_SETUP) {
if (ctl & DC_TXCTL_SETUP) {
/*
* Yes, the PNIC is so brain damaged
@@ -3262,6 +3262,7 @@
sc->dc_cdata.dc_tx_prod = frag;
sc->dc_cdata.dc_tx_cnt += nseg;
sc->dc_ldata->dc_tx_list[cur].dc_ctl |= htole32(DC_TXCTL_LASTFRAG);
+ sc->dc_cdata.dc_tx_chain[cur] = sc->dc_cdata.dc_tx_mapping;
if (sc->dc_flags & DC_TX_INTR_FIRSTFRAG)
sc->dc_ldata->dc_tx_list[first].dc_ctl |=
htole32(DC_TXCTL_FINT);
@@ -3311,13 +3312,13 @@
* of fragments or hit the end of the mbuf chain.
*/
idx = sc->dc_cdata.dc_tx_prod;
+ sc->dc_cdata.dc_tx_mapping = *m_head;
error = bus_dmamap_load_mbuf(sc->dc_mtag, sc->dc_cdata.dc_tx_map[idx],
*m_head, dc_dma_map_txbuf, sc, 0);
if (error)
return (error);
if (sc->dc_cdata.dc_tx_err != 0)
return (sc->dc_cdata.dc_tx_err);
- sc->dc_cdata.dc_tx_chain[idx] = *m_head;
bus_dmamap_sync(sc->dc_mtag, sc->dc_cdata.dc_tx_map[idx],
BUS_DMASYNC_PREWRITE);
bus_dmamap_sync(sc->dc_ltag, sc->dc_lmap,
Index: sys/pci/if_dcreg.h
===================================================================
RCS file: /home/ncvs/src/sys/pci/if_dcreg.h,v
retrieving revision 1.40
diff -u -r1.40 if_dcreg.h
--- sys/pci/if_dcreg.h 6 Dec 2003 02:29:31 -0000 1.40
+++ sys/pci/if_dcreg.h 5 Jan 2004 19:58:05 -0000
@@ -486,6 +486,7 @@
struct dc_chain_data {
struct mbuf *dc_rx_chain[DC_RX_LIST_CNT];
struct mbuf *dc_tx_chain[DC_TX_LIST_CNT];
+ struct mbuf *dc_tx_mapping;
bus_dmamap_t dc_rx_map[DC_RX_LIST_CNT];
bus_dmamap_t dc_tx_map[DC_TX_LIST_CNT];
u_int32_t *dc_sbuf;
More information about the freebsd-current
mailing list