Source-Changes-HG archive

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]

[src/trunk]: src/sys/dev/ic Clean up receive interrupt routine:



details:   https://anonhg.NetBSD.org/src/rev/42d850b1b803
branches:  trunk
changeset: 500012:42d850b1b803
user:      tsutsui <tsutsui%NetBSD.org@localhost>
date:      Sun Dec 03 14:24:17 2000 +0000

description:
Clean up receive interrupt routine:
- Use MGETHDR + MCLGET + memcpy rathar than m_devget + m_adj + m_copyback.
- Call bus_dmamap_sync(9) correctly for Rx buffer.

Mostly from thorpej's if_rtp.c.

diffstat:

 sys/dev/ic/rtl81x9.c |  144 ++++++++++++++++++++++++++++----------------------
 1 files changed, 80 insertions(+), 64 deletions(-)

diffs (216 lines):

diff -r 90780ab95081 -r 42d850b1b803 sys/dev/ic/rtl81x9.c
--- a/sys/dev/ic/rtl81x9.c      Sun Dec 03 13:43:40 2000 +0000
+++ b/sys/dev/ic/rtl81x9.c      Sun Dec 03 14:24:17 2000 +0000
@@ -1,4 +1,4 @@
-/*     $NetBSD: rtl81x9.c,v 1.21 2000/11/30 15:51:57 tsutsui Exp $     */
+/*     $NetBSD: rtl81x9.c,v 1.22 2000/12/03 14:24:17 tsutsui Exp $     */
 
 /*
  * Copyright (c) 1997, 1998
@@ -958,8 +958,7 @@
  * A frame has been uploaded: pass the resulting mbuf chain up to
  * the higher level protocols.
  *
- * You know there's something wrong with a PCI bus-master chip design
- * when you have to use m_devget().
+ * You know there's something wrong with a PCI bus-master chip design.
  *
  * The receive operation is badly documented in the datasheet, so I'll
  * attempt to document it here. The driver provides a buffer area and
@@ -972,25 +971,18 @@
  * the 'rx status register' mentioned in the datasheet.
  *
  * Note: to make the Alpha happy, the frame payload needs to be aligned
- * on a 32-bit boundary. To achieve this, we cheat a bit by copying from
- * the ring buffer starting at an address two bytes before the actual
- * data location. We can then shave off the first two bytes using m_adj().
- * The reason we do this is because m_devget() doesn't let us specify an
- * offset into the mbuf storage space, so we have to artificially create
- * one. The ring is allocated in such a way that there are a few unused
- * bytes of space preceecing it so that it will be safe for us to do the
- * 2-byte backstep even if reading from the ring at offset 0.
+ * on a 32-bit boundary. To achieve this, we copy the data to mbuf
+ * shifted forward 2 bytes.
  */
 STATIC void rtk_rxeof(sc)
        struct rtk_softc        *sc;
 {
         struct mbuf            *m;
         struct ifnet           *ifp;
-       int                     total_len = 0;
+       caddr_t                 rxbufpos, dst;
+       int                     total_len, wrap = 0;
        u_int32_t               rxstat;
-       caddr_t                 rxbufpos;
-       int                     wrap = 0;
-       u_int16_t               cur_rx;
+       u_int16_t               cur_rx, new_rx;
        u_int16_t               limit;
        u_int16_t               rx_bytes = 0, max_bytes;
 
@@ -1022,10 +1014,11 @@
                 * datasheet makes absolutely no mention of this and
                 * RealTek should be shot for this.
                 */
-               if ((u_int16_t)(rxstat >> 16) == RTK_RXSTAT_UNFINISHED)
+               total_len = rxstat >> 16;
+               if (total_len == RTK_RXSTAT_UNFINISHED)
                        break;
-       
-               if (!(rxstat & RTK_RXSTAT_RXOK)) {
+
+               if ((rxstat & RTK_RXSTAT_RXOK) == 0) {
                        ifp->if_ierrors++;
 
                        /*
@@ -1056,7 +1049,6 @@
                }
 
                /* No errors; receive the packet. */    
-               total_len = rxstat >> 16;
                rx_bytes += total_len + RTK_RXSTAT_LEN;
 
                /*
@@ -1066,49 +1058,84 @@
                if (rx_bytes > max_bytes)
                        break;
 
-               bus_dmamap_sync(sc->sc_dmat, sc->recv_dmamap,
-                   cur_rx + RTK_RXSTAT_LEN, total_len, BUS_DMASYNC_POSTREAD);
+               /*
+                * Skip the status word, wrapping around to the beginning
+                * of the Rx area, if necessary.
+                */
+               cur_rx += RTK_RXSTAT_LEN;
+               rxbufpos = sc->rtk_cdata.rtk_rx_buf + (cur_rx % RTK_RXBUFLEN);
 
-               rxbufpos = sc->rtk_cdata.rtk_rx_buf +
-                       ((cur_rx + RTK_RXSTAT_LEN) % RTK_RXBUFLEN);
+               /*
+                * Compute the number of bytes at which the packet
+                * will wrap to the beginning of the ring buffer.
+                */
+               wrap = RTK_RXBUFLEN - (cur_rx % RTK_RXBUFLEN);
 
-               if (rxbufpos == (sc->rtk_cdata.rtk_rx_buf + RTK_RXBUFLEN))
-                       rxbufpos = sc->rtk_cdata.rtk_rx_buf;
-
-               wrap = (sc->rtk_cdata.rtk_rx_buf + RTK_RXBUFLEN) - rxbufpos;
+               /*
+                * Compute where the next pending packet is.
+                */
+               if (total_len > wrap)
+                       new_rx = total_len - wrap;
+               else
+                       new_rx = cur_rx + total_len;
+               /* Round up to 32-bit boundary. */
+               new_rx = (new_rx + 3) & ~3;
 
-               if (total_len > wrap) {
-                       m = m_devget(rxbufpos - RTK_ETHER_ALIGN,
-                          wrap + RTK_ETHER_ALIGN, 0, ifp, NULL);
-                       if (m == NULL) {
+               /*
+                * Now allocate an mbuf (and possibly a cluster) to hold
+                * the packet. Note we offset the packet 2 bytes so that
+                * data after the Ethernet header will be 4-byte aligned.
+                */
+               MGETHDR(m, M_DONTWAIT, MT_DATA);
+               if (m == NULL) {
+                       printf("%s: unable to allocate Rx mbuf\n",
+                           sc->sc_dev.dv_xname);
+                       ifp->if_ierrors++;
+                       goto next_packet;
+               }
+               if (total_len > (MHLEN - RTK_ETHER_ALIGN)) {
+                       MCLGET(m, M_DONTWAIT);
+                       if ((m->m_flags & M_EXT) == 0) {
+                               printf("%s: unable to allocate Rx cluster\n",
+                                   sc->sc_dev.dv_xname);
                                ifp->if_ierrors++;
-                               printf("%s: out of mbufs, tried to "
-                                   "copy %d bytes\n", sc->sc_dev.dv_xname,
-                                   wrap);
-                       } else {
-                               m_adj(m, RTK_ETHER_ALIGN);
-                               m_copyback(m, wrap, total_len - wrap,
-                                       sc->rtk_cdata.rtk_rx_buf);
+                               m_freem(m);
+                               m = NULL;
+                               goto next_packet;
                        }
-                       cur_rx = total_len - wrap;
-               } else {
-                       m = m_devget(rxbufpos - RTK_ETHER_ALIGN,
-                           total_len + RTK_ETHER_ALIGN, 0, ifp, NULL);
-                       if (m == NULL) {
-                               ifp->if_ierrors++;
-                               printf("%s: out of mbufs, tried to "
-                                   "copy %d bytes\n", sc->sc_dev.dv_xname,
-                                   total_len);
-                       } else
-                               m_adj(m, RTK_ETHER_ALIGN);
-                       cur_rx += total_len + RTK_RXSTAT_LEN;
+               }
+               m->m_data += RTK_ETHER_ALIGN;   /* for alignment */
+               m->m_pkthdr.rcvif = ifp;
+               m->m_pkthdr.len = m->m_len = total_len;
+               dst = mtod(m, caddr_t);
+
+               /*
+                * If the packet wraps, copy up to the wrapping point.
+                */
+               if (total_len > wrap) {
+                       bus_dmamap_sync(sc->sc_dmat, sc->recv_dmamap,
+                           cur_rx, wrap, BUS_DMASYNC_POSTREAD);
+                       memcpy(dst, rxbufpos, wrap);
+                       bus_dmamap_sync(sc->sc_dmat, sc->recv_dmamap,
+                           cur_rx, wrap, BUS_DMASYNC_PREREAD);
+                       cur_rx = 0;
+                       rxbufpos = sc->rtk_cdata.rtk_rx_buf;
+                       total_len -= wrap;
+                       dst += wrap;
                }
 
                /*
-                * Round up to 32-bit boundary.
+                * ...and now the rest.
                 */
-               cur_rx = (cur_rx + 3) & ~3;
-               CSR_WRITE_2(sc, RTK_CURRXADDR, cur_rx - 16);
+               bus_dmamap_sync(sc->sc_dmat, sc->recv_dmamap,
+                   cur_rx, total_len, BUS_DMASYNC_POSTREAD);
+               memcpy(dst, rxbufpos, total_len);
+               bus_dmamap_sync(sc->sc_dmat, sc->recv_dmamap,
+                   cur_rx, total_len, BUS_DMASYNC_PREREAD);
+
+next_packet:
+               CSR_WRITE_2(sc, RTK_CURRXADDR, new_rx - 16);
+               cur_rx = new_rx;
 
                if (m == NULL)
                        continue;
@@ -1122,23 +1149,12 @@
                ifp->if_ipackets++;
 
 #if NBPFILTER > 0
-               /*
-                * Handle BPF listeners. Let the BPF user see the packet, but
-                * don't pass it up to the ether_input() layer unless it's
-                * a broadcast packet, multicast packet, matches our ethernet
-                * address or the interface is in promiscuous mode.
-                */
                if (ifp->if_bpf)
                        bpf_mtap(ifp->if_bpf, m);
 #endif
                /* pass it on. */
                (*ifp->if_input)(ifp, m);
-
-               bus_dmamap_sync(sc->sc_dmat, sc->recv_dmamap,
-                   cur_rx + RTK_RXSTAT_LEN, total_len, BUS_DMASYNC_PREREAD);
        }
-
-       return;
 }
 
 /*



Home | Main Index | Thread Index | Old Index