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 {

Reply via email to