First of all, big thanks to Christian `naddy` who sent me a dc(4). I also
managed to get my hands on a PNIC. This diff add mclgeti support plus 2 bug
fixes that suppress idle timeouts, and autonegocation which is broken on the
PNIC. As usual, you know who to complain to.
Index: src/sys/dev/ic/dc.c
===================================================================
RCS file: /cvs/src/sys/dev/ic/dc.c,v
retrieving revision 1.121
diff -u -p -r1.121 dc.c
--- src/sys/dev/ic/dc.c 7 Sep 2010 16:21:42 -0000 1.121
+++ src/sys/dev/ic/dc.c 13 Dec 2010 18:43:42 -0000
@@ -131,12 +131,11 @@
int dc_intr(void *);
struct dc_type *dc_devtype(void *);
-int dc_newbuf(struct dc_softc *, int, struct mbuf *);
+int dc_newbuf(struct dc_softc *);
int dc_encap(struct dc_softc *, struct mbuf *, u_int32_t *);
int dc_coal(struct dc_softc *, struct mbuf **);
void dc_pnic_rx_bug_war(struct dc_softc *, int);
-int dc_rx_resync(struct dc_softc *);
void dc_rxeof(struct dc_softc *);
void dc_txeof(struct dc_softc *);
void dc_tick(void *);
@@ -178,6 +177,7 @@ void dc_setfilt(struct dc_softc *);
void dc_reset(struct dc_softc *);
int dc_list_rx_init(struct dc_softc *);
+void dc_fill_rx_ring(struct dc_softc *);
int dc_list_tx_init(struct dc_softc *);
void dc_read_srom(struct dc_softc *, int);
@@ -1224,7 +1224,7 @@ dc_setcfg(struct dc_softc *sc, int media
}
if (i == DC_TIMEOUT) {
- if (!(isr & DC_ISR_TX_IDLE) && !DC_IS_ASIX(sc))
+ if (!(isr & DC_ISR_TX_IDLE) && !DC_IS_ASIX(sc) &&
!DC_IS_PNIC(sc))
printf("%s: failed to force tx to idle state\n",
sc->sc_dev.dv_xname);
if (!((isr & DC_ISR_RX_STATE) == DC_RXSTATE_STOPPED ||
@@ -1737,7 +1737,7 @@ hasmac:
bcopy(sc->sc_dev.dv_xname, ifp->if_xname, IFNAMSIZ);
ifp->if_capabilities = IFCAP_VLAN_MTU;
-
+ m_clsetwms(ifp, MCLBYTES, 2, DC_RX_LIST_CNT - 1);
/* Do MII setup. If this is a 21143, check for a PHY on the
* MII bus after applying any necessary fixups to twiddle the
* GPIO bits. If we don't end up finding a PHY, restore the
@@ -1792,9 +1792,11 @@ hasmac:
ifmedia_add(&sc->sc_mii.mii_media, IFM_ETHER|IFM_NONE, 0, NULL);
ifmedia_set(&sc->sc_mii.mii_media, IFM_ETHER|IFM_NONE);
printf("%s: MII without any PHY!\n", sc->sc_dev.dv_xname);
- } else if (sc->dc_type == DC_TYPE_21145) {
+ } else if (sc->dc_type == DC_TYPE_21145)
ifmedia_set(&sc->sc_mii.mii_media, IFM_ETHER|IFM_10_T);
- } else
+ else if (sc->dc_type == DC_TYPE_PNIC)
+ ifmedia_set(&sc->sc_mii.mii_media, IFM_ETHER|IFM_10_T);
+ else
ifmedia_set(&sc->sc_mii.mii_media, IFM_ETHER|IFM_AUTO);
if (DC_IS_DAVICOM(sc) && sc->dc_revision >= DC_REVISION_DM9102A)
@@ -1867,8 +1869,6 @@ dc_list_rx_init(struct dc_softc *sc)
ld = sc->dc_ldata;
for (i = 0; i < DC_RX_LIST_CNT; i++) {
- if (dc_newbuf(sc, i, NULL) == ENOBUFS)
- return (ENOBUFS);
next = sc->sc_listmap->dm_segs[0].ds_addr;
if (i == (DC_RX_LIST_CNT - 1))
next +=
@@ -1879,52 +1879,52 @@ dc_list_rx_init(struct dc_softc *sc)
ld->dc_rx_list[i].dc_next = htole32(next);
}
- cd->dc_rx_prod = 0;
-
+ cd->dc_rx_prod = cd->dc_rx_cons = cd->dc_rx_cnt = 0;
+ dc_fill_rx_ring(sc);
return (0);
}
+void dc_fill_rx_ring(struct dc_softc *sc) {
+ struct dc_chain_data *cd;
+ struct dc_list_data *ld;
+
+ cd = &sc->dc_cdata;
+ ld = sc->dc_ldata;
+
+ while (cd->dc_rx_cnt < DC_RX_LIST_CNT) {
+ if(dc_newbuf(sc) == ENOBUFS)
+ break;
+ DC_INC(cd->dc_rx_prod, DC_RX_LIST_CNT);
+ cd->dc_rx_cnt++;
+ }
+}
+
/*
* Initialize an RX descriptor and attach an MBUF cluster.
*/
int
-dc_newbuf(struct dc_softc *sc, int i, struct mbuf *m)
+dc_newbuf(struct dc_softc *sc)
{
struct mbuf *m_new = NULL;
struct dc_desc *c;
bus_dmamap_t map;
-
+ int i;
+ i = sc->dc_cdata.dc_rx_prod;
c = &sc->dc_ldata->dc_rx_list[i];
- if (m == NULL) {
- MGETHDR(m_new, M_DONTWAIT, MT_DATA);
- if (m_new == NULL)
- return (ENOBUFS);
-
- MCLGET(m_new, M_DONTWAIT);
- if (!(m_new->m_flags & M_EXT)) {
- m_freem(m_new);
- return (ENOBUFS);
- }
- m_new->m_len = m_new->m_pkthdr.len = MCLBYTES;
- if (bus_dmamap_load_mbuf(sc->sc_dmat, sc->sc_rx_sparemap,
- m_new, BUS_DMA_NOWAIT) != 0) {
- m_freem(m_new);
- return (ENOBUFS);
- }
- map = sc->dc_cdata.dc_rx_chain[i].sd_map;
- sc->dc_cdata.dc_rx_chain[i].sd_map = sc->sc_rx_sparemap;
- sc->sc_rx_sparemap = map;
- } else {
- /*
- * We're re-using a previously allocated mbuf;
- * be sure to re-init pointers and lengths to
- * default values.
- */
- m_new = m;
- m_new->m_len = m_new->m_pkthdr.len = MCLBYTES;
- m_new->m_data = m_new->m_ext.ext_buf;
- }
+ m_new = MCLGETI(NULL, M_DONTWAIT, &sc->sc_arpcom.ac_if, MCLBYTES);
+ if (!m_new)
+ return (ENOBUFS);
+
+ m_new->m_len = m_new->m_pkthdr.len = MCLBYTES;
+ if (bus_dmamap_load_mbuf(sc->sc_dmat, sc->sc_rx_sparemap,
+ m_new, BUS_DMA_NOWAIT) != 0) {
+ m_freem(m_new);
+ return (ENOBUFS);
+ }
+ map = sc->dc_cdata.dc_rx_chain[i].sd_map;
+ sc->dc_cdata.dc_rx_chain[i].sd_map = sc->sc_rx_sparemap;
+ sc->sc_rx_sparemap = map;
m_adj(m_new, sizeof(u_int64_t));
@@ -2033,8 +2033,7 @@ dc_pnic_rx_bug_war(struct dc_softc *sc,
/* If this is the last buffer, break out. */
if (i == idx || rxstat & DC_RXSTAT_LASTFRAG)
break;
- dc_newbuf(sc, i, m);
- DC_INC(i, DC_RX_LIST_CNT);
+ m_freem(m);
}
/* Find the length of the actual receive frame. */
@@ -2058,52 +2057,11 @@ dc_pnic_rx_bug_war(struct dc_softc *sc,
* the status word to make it look like a successful
* frame reception.
*/
- dc_newbuf(sc, i, m);
+ m_freem(m);
bcopy(ptr, mtod(m, char *), total_len);
cur_rx->dc_status = htole32(rxstat | DC_RXSTAT_FIRSTFRAG);
}
-/*
- * This routine searches the RX ring for dirty descriptors in the
- * event that the rxeof routine falls out of sync with the chip's
- * current descriptor pointer. This may happen sometimes as a result
- * of a "no RX buffer available" condition that happens when the chip
- * consumes all of the RX buffers before the driver has a chance to
- * process the RX ring. This routine may need to be called more than
- * once to bring the driver back in sync with the chip, however we
- * should still be getting RX DONE interrupts to drive the search
- * for new packets in the RX ring, so we should catch up eventually.
- */
-int
-dc_rx_resync(struct dc_softc *sc)
-{
- u_int32_t stat;
- int i, pos, offset;
-
- pos = sc->dc_cdata.dc_rx_prod;
-
- for (i = 0; i < DC_RX_LIST_CNT; i++) {
-
- offset = offsetof(struct dc_list_data, dc_rx_list[pos]);
- bus_dmamap_sync(sc->sc_dmat, sc->sc_listmap,
- offset, sizeof(struct dc_desc),
- BUS_DMASYNC_POSTREAD | BUS_DMASYNC_POSTWRITE);
-
- stat = sc->dc_ldata->dc_rx_list[pos].dc_status;
- if (!(stat & htole32(DC_RXSTAT_OWN)))
- break;
- DC_INC(pos, DC_RX_LIST_CNT);
- }
-
- /* If the ring really is empty, then just return. */
- if (i == DC_RX_LIST_CNT)
- return (0);
-
- /* We've fallen behind the chip: catch it. */
- sc->dc_cdata.dc_rx_prod = pos;
-
- return (EAGAIN);
-}
/*
* A frame has been uploaded: pass the resulting mbuf chain up to
@@ -2119,9 +2077,8 @@ dc_rxeof(struct dc_softc *sc)
u_int32_t rxstat;
ifp = &sc->sc_arpcom.ac_if;
- i = sc->dc_cdata.dc_rx_prod;
- for(;;) {
+ for(i = sc->dc_cdata.dc_rx_cons; sc->dc_cdata.dc_rx_cnt > 0;
DC_INC(i,DC_RX_LIST_CNT)) {
struct mbuf *m0 = NULL;
offset = offsetof(struct dc_list_data, dc_rx_list[i]);
@@ -2145,18 +2102,16 @@ dc_rxeof(struct dc_softc *sc)
if ((rxstat & DC_WHOLEFRAME) != DC_WHOLEFRAME) {
if (rxstat & DC_RXSTAT_FIRSTFRAG)
sc->dc_pnic_rx_bug_save = i;
- if ((rxstat & DC_RXSTAT_LASTFRAG) == 0) {
- DC_INC(i, DC_RX_LIST_CNT);
+ if ((rxstat & DC_RXSTAT_LASTFRAG) == 0)
continue;
- }
dc_pnic_rx_bug_war(sc, i);
rxstat = letoh32(cur_rx->dc_status);
total_len = DC_RXBYTES(rxstat);
}
}
- sc->dc_cdata.dc_rx_chain[i].sd_mbuf = NULL;
-
+ sc->dc_cdata.dc_rx_chain[i].sd_mbuf = NULL;
+ sc->dc_cdata.dc_rx_cnt--;
/*
* If an error occurs, update stats, clear the
* status word and leave the mbuf cluster in place:
@@ -2172,9 +2127,8 @@ dc_rxeof(struct dc_softc *sc)
ifp->if_ierrors++;
if (rxstat & DC_RXSTAT_COLLSEEN)
ifp->if_collisions++;
- dc_newbuf(sc, i, m);
+ m_freem(m);
if (rxstat & DC_RXSTAT_CRCERR) {
- DC_INC(i, DC_RX_LIST_CNT);
continue;
} else {
dc_init(sc);
@@ -2189,8 +2143,7 @@ dc_rxeof(struct dc_softc *sc)
m->m_pkthdr.rcvif = ifp;
m0 = m_devget(mtod(m, char *), total_len, ETHER_ALIGN,
ifp, NULL);
- dc_newbuf(sc, i, m);
- DC_INC(i, DC_RX_LIST_CNT);
+ m_freem(m);
if (m0 == NULL) {
ifp->if_ierrors++;
continue;
@@ -2205,7 +2158,8 @@ dc_rxeof(struct dc_softc *sc)
ether_input_mbuf(ifp, m);
}
- sc->dc_cdata.dc_rx_prod = i;
+ sc->dc_cdata.dc_rx_cons = i;
+ dc_fill_rx_ring(sc);
}
/*
@@ -2489,15 +2443,8 @@ dc_intr(void *arg)
claimed = 1;
CSR_WRITE_4(sc, DC_ISR, status);
- if (status & DC_ISR_RX_OK) {
- int curpkts;
- curpkts = ifp->if_ipackets;
+ if (status & DC_ISR_RX_OK)
dc_rxeof(sc);
- if (curpkts == ifp->if_ipackets) {
- while(dc_rx_resync(sc))
- dc_rxeof(sc);
- }
- }
if (status & (DC_ISR_TX_OK|DC_ISR_TX_NOBUF))
dc_txeof(sc);
@@ -2514,15 +2461,8 @@ dc_intr(void *arg)
dc_tx_underrun(sc);
if ((status & DC_ISR_RX_WATDOGTIMEO)
- || (status & DC_ISR_RX_NOBUF)) {
- int curpkts;
- curpkts = ifp->if_ipackets;
+ || (status & DC_ISR_RX_NOBUF))
dc_rxeof(sc);
- if (curpkts == ifp->if_ipackets) {
- while(dc_rx_resync(sc))
- dc_rxeof(sc);
- }
- }
if (status & DC_ISR_BUS_ERR) {
dc_reset(sc);
Index: src/sys/dev/ic/dcreg.h
===================================================================
RCS file: /cvs/src/sys/dev/ic/dcreg.h,v
retrieving revision 1.48
diff -u -p -r1.48 dcreg.h
--- src/sys/dev/ic/dcreg.h 7 Sep 2010 16:21:42 -0000 1.48
+++ src/sys/dev/ic/dcreg.h 13 Dec 2010 18:43:43 -0000
@@ -502,6 +502,8 @@ struct dc_chain_data {
int dc_tx_cons;
int dc_tx_cnt;
int dc_rx_prod;
+ int dc_rx_cons;
+ int dc_rx_cnt;
};
struct dc_mediainfo {