Source-Changes-HG archive

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

[src/trunk]: src/sys/dev/ic If defined(RTW_DEBUG), provide a sysctl (hw.rtw.r...



details:   https://anonhg.NetBSD.org/src/rev/dd3d666343dd
branches:  trunk
changeset: 572279:dd3d666343dd
user:      dyoung <dyoung%NetBSD.org@localhost>
date:      Tue Dec 28 22:21:15 2004 +0000

description:
If defined(RTW_DEBUG), provide a sysctl (hw.rtw.rxbufs_limit) for
limiting the number of rx buffers an rtw may allocate.  Use this
sysctl to test the code that copes with buffer exhaustion.

Allocate at most RTW_RXQLEN rx buffers, stopping at the sysctl
limit.  Record in sc_nrxdesc how many were allocated, and put the
end-of-ring indication on sc_rxdesc[sc_nrxdesc - 1].  In rtw_init,
if no rx buffers could be allocated, log a complaint, clear
IFF_RUNNING, and exit with an error.

Many changes to accomodate a short rx ring, mainly of the "add a
rx-ring length argument" variety.  XXX I really should consolidate
all of the rx ring variables in one struct and pass that to the
rx-ring subroutines.

Bug fix: after calling MCLGET, use the (m->m_flags & M_EXT) idiom
to check for success, instead of m != NULL.

Bug fix: at the top of rtw_start, if IFF_RUNNING is not set, or
IFF_OACTIVE is, get out.

diffstat:

 sys/dev/ic/rtw.c |  156 ++++++++++++++++++++++++++++++++----------------------
 1 files changed, 93 insertions(+), 63 deletions(-)

diffs (truncated from 375 to 300 lines):

diff -r eef1506855ad -r dd3d666343dd sys/dev/ic/rtw.c
--- a/sys/dev/ic/rtw.c  Tue Dec 28 22:07:04 2004 +0000
+++ b/sys/dev/ic/rtw.c  Tue Dec 28 22:21:15 2004 +0000
@@ -1,4 +1,4 @@
-/* $NetBSD: rtw.c,v 1.30 2004/12/27 20:04:45 dyoung Exp $ */
+/* $NetBSD: rtw.c,v 1.31 2004/12/28 22:21:15 dyoung Exp $ */
 /*-
  * Copyright (c) 2004, 2005 David Young.  All rights reserved.
  *
@@ -34,7 +34,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: rtw.c,v 1.30 2004/12/27 20:04:45 dyoung Exp $");
+__KERNEL_RCSID(0, "$NetBSD: rtw.c,v 1.31 2004/12/28 22:21:15 dyoung Exp $");
 
 #include "bpfilter.h"
 
@@ -90,6 +90,7 @@
 
 #ifdef RTW_DEBUG
 int rtw_debug = 0;
+int rtw_rxbufs_limit = RTW_RXQLEN;
 #endif /* RTW_DEBUG */
 
 #define NEXT_ATTACH_STATE(sc, state) do {                      \
@@ -108,6 +109,7 @@
 static void rtw_print_txdesc(struct rtw_softc *, const char *,
     struct rtw_txctl *, struct rtw_txdesc_blk *, int);
 static int rtw_sysctl_verify_debug(SYSCTLFN_PROTO);
+static int rtw_sysctl_verify_rxbufs_limit(SYSCTLFN_PROTO);
 #endif /* RTW_DEBUG */
 
 /*
@@ -139,6 +141,16 @@
            rtw_sysctl_verify_debug, 0, &rtw_debug, 0,
            CTL_CREATE, CTL_EOL)) != 0)
                goto err;
+
+       /* Limit rx buffers, for simulating resource exhaustion. */
+       if ((rc = sysctl_createv(clog, 0, &rnode, &cnode,
+           CTLFLAG_PERMANENT|CTLFLAG_READWRITE, CTLTYPE_INT,
+           "rxbufs_limit",
+           SYSCTL_DESCR("Set rx buffers limit"),
+           rtw_sysctl_verify_rxbufs_limit, 0, &rtw_rxbufs_limit, 0,
+           CTL_CREATE, CTL_EOL)) != 0)
+               goto err;
+
 #endif /* RTW_DEBUG */
        /* set fallback RF programming method */
        if ((rc = sysctl_createv(clog, 0, &rnode, &cnode,
@@ -203,6 +215,12 @@
        return rtw_sysctl_verify(SYSCTLFN_CALL(rnode), 0, RTW_DEBUG_MAX);
 }
 
+static int
+rtw_sysctl_verify_rxbufs_limit(SYSCTLFN_ARGS)
+{
+       return rtw_sysctl_verify(SYSCTLFN_CALL(rnode), 0, RTW_RXQLEN);
+}
+
 static void
 rtw_print_regs(struct rtw_regs *regs, const char *dvname, const char *where)
 {
@@ -574,14 +592,6 @@
 }
 
 static __inline void
-rtw_rxctls_setup(struct rtw_rxctl *descs)
-{
-       int i;
-       for (i = 0; i < RTW_RXQLEN; i++)
-               descs[i].srx_mbuf = NULL;
-}
-
-static __inline void
 rtw_rxdesc_dmamaps_destroy(bus_dma_tag_t dmat, struct rtw_rxctl *descs,
     u_int ndescs)
 {
@@ -1024,22 +1034,22 @@
 }
 
 static __inline void
-rtw_rxdescs_sync(bus_dma_tag_t dmat, bus_dmamap_t dmap, u_int desc0, u_int
-    nsync, int ops)
+rtw_rxdescs_sync(bus_dma_tag_t dmat, bus_dmamap_t dmap, int desc0, int nsync,
+    int ndesc, int ops)
 {
-       KASSERT(nsync <= RTW_RXQLEN);
+       KASSERT(nsync <= ndesc);
        /* sync to end of ring */
-       if (desc0 + nsync > RTW_RXQLEN) {
+       if (desc0 + nsync > ndesc) {
                bus_dmamap_sync(dmat, dmap,
                    offsetof(struct rtw_descs, hd_rx[desc0]),
-                   sizeof(struct rtw_rxdesc) * (RTW_RXQLEN - desc0), ops);
-               nsync -= (RTW_RXQLEN - desc0);
+                   sizeof(struct rtw_rxdesc) * (ndesc - desc0), ops);
+               nsync -= (ndesc - desc0);
                desc0 = 0;
        }
 
-       KASSERT(desc0 < RTW_RXQLEN);
-       KASSERT(nsync <= RTW_RXQLEN);
-       KASSERT(desc0 + nsync <= RTW_RXQLEN);
+       KASSERT(desc0 < ndesc);
+       KASSERT(nsync <= ndesc);
+       KASSERT(desc0 + nsync <= ndesc);
 
        /* sync what remains */
        bus_dmamap_sync(dmat, dmap,
@@ -1087,6 +1097,8 @@
 
        for (i = 0; i < RTW_RXQLEN; i++) {
                srx = &desc[i];
+               if (srx->srx_mbuf == NULL)
+                       continue;
                bus_dmamap_sync(dmat, srx->srx_dmamap, 0,
                    srx->srx_dmamap->dm_mapsize, BUS_DMASYNC_POSTREAD);
                bus_dmamap_unload(dmat, srx->srx_dmamap);
@@ -1106,8 +1118,10 @@
                return ENOBUFS;
 
        MCLGET(m, M_DONTWAIT); 
-       if (m == NULL)
+       if ((m->m_flags & M_EXT) == 0) {
+               m_freem(m);
                return ENOBUFS;
+       }
 
        m->m_pkthdr.len = m->m_len = m->m_ext.ext_size;
 
@@ -1129,31 +1143,37 @@
 
 static int
 rtw_rxctl_init_all(bus_dma_tag_t dmat, struct rtw_rxctl *desc,
-    u_int *next, const char *dvname)
+    int *ndesc, const char *dvname)
 {
-       int i, rc;
+       int i, rc = 0;
        struct rtw_rxctl *srx;
 
        for (i = 0; i < RTW_RXQLEN; i++) {
                srx = &desc[i];
-               if ((rc = rtw_rxbuf_alloc(dmat, srx)) == 0)
-                       continue;
-               printf("%s: failed rtw_rxbuf_alloc after %d buffers, rc = %d\n",
-                   dvname, i, rc);
-               if (i == 0) {
-                       rtw_rxbufs_release(dmat, desc);
-                       return rc;
+               /* we're in rtw_init, so there should be no mbufs allocated */
+               KASSERT(srx->srx_mbuf == NULL);
+#ifdef RTW_DEBUG
+               if (i == rtw_rxbufs_limit) {
+                       printf("%s: TEST hit %d-buffer limit\n", dvname, i);
+                       rc = ENOBUFS;
+                       break;
+               }
+#endif /* RTW_DEBUG */
+               if ((rc = rtw_rxbuf_alloc(dmat, srx)) != 0) {
+                       printf("%s: rtw_rxbuf_alloc failed, %d buffers, "
+                              "rc %d\n", dvname, i, rc);
+                       break;
                }
        }
-       *next = 0;
-       return 0;
+       *ndesc = i;
+       return rc;
 }
 
 static __inline void
 rtw_rxdesc_init(bus_dma_tag_t dmat, bus_dmamap_t dmam,
-    struct rtw_rxdesc *hrx, struct rtw_rxctl *srx, int idx, int kick)
+    struct rtw_rxdesc *hrx, struct rtw_rxctl *srx, int idx, int ndesc, int kick)
 {
-       int is_last = (idx == RTW_RXQLEN - 1);
+       int is_last = (idx == ndesc - 1);
        uint32_t ctl, octl, obuf;
 
        obuf = hrx->hrx_buf;
@@ -1187,16 +1207,16 @@
 
 static void
 rtw_rxdesc_init_all(bus_dma_tag_t dmat, bus_dmamap_t dmam,
-    struct rtw_rxdesc *desc, struct rtw_rxctl *ctl, int kick)
+    struct rtw_rxdesc *desc, struct rtw_rxctl *ctl, int ndesc, int kick)
 {
        int i;
        struct rtw_rxdesc *hrx;
        struct rtw_rxctl *srx;
 
-       for (i = 0; i < RTW_RXQLEN; i++) {
+       for (i = 0; i < ndesc; i++) {
                hrx = &desc[i];
                srx = &ctl[i];
-               rtw_rxdesc_init(dmat, dmam, hrx, srx, i, kick);
+               rtw_rxdesc_init(dmat, dmam, hrx, srx, i, ndesc, kick);
        }
 }
 
@@ -1241,11 +1261,12 @@
        struct ieee80211_node *ni;
        struct ieee80211_frame *wh;
 
-       KASSERT(sc->sc_rxnext < RTW_RXQLEN);
-
-       for (next = sc->sc_rxnext; ; next = (next + 1) % RTW_RXQLEN) {
+       KASSERT(sc->sc_rxnext < sc->sc_nrxdesc);
+
+       for (next = sc->sc_rxnext; ; next = (next + 1) % sc->sc_nrxdesc) {
                rtw_rxdescs_sync(sc->sc_dmat, sc->sc_desc_dmamap,
-                   next, 1, BUS_DMASYNC_POSTREAD|BUS_DMASYNC_POSTWRITE);
+                   next, 1, sc->sc_nrxdesc,
+                   BUS_DMASYNC_POSTREAD|BUS_DMASYNC_POSTWRITE);
                hrx = &sc->sc_rxdesc[next];
                srx = &sc->sc_rxctl[next];
 
@@ -1270,7 +1291,8 @@
 
                        /* sometimes the NIC skips to the 0th descriptor */
                        rtw_rxdescs_sync(sc->sc_dmat, sc->sc_desc_dmamap,
-                           0, 1, BUS_DMASYNC_POSTREAD|BUS_DMASYNC_POSTWRITE);
+                           0, 1, sc->sc_nrxdesc,
+                           BUS_DMASYNC_POSTREAD|BUS_DMASYNC_POSTWRITE);
                        hrx = &sc->sc_rxdesc[0];
                        if ((hrx->hrx_stat & htole32(RTW_RXSTAT_OWN)) != 0)
                                break;
@@ -1352,8 +1374,7 @@
                        break;
                case ENOBUFS:
                        printf("%s: rtw_rxbuf_alloc(, %d) failed, "
-                           "dropping this packet\n", sc->sc_dev.dv_xname,
-                           next);
+                           "dropping packet\n", sc->sc_dev.dv_xname, next);
                        goto next;
                default:
                        /* XXX shorten rx ring, instead? */
@@ -1393,12 +1414,12 @@
                ieee80211_release_node(&sc->sc_ic, ni);
 next:
                rtw_rxdesc_init(sc->sc_dmat, sc->sc_desc_dmamap,
-                   hrx, srx, next, 0);
+                   hrx, srx, next, sc->sc_nrxdesc, 0);
        }
-       KASSERT(sc->sc_rxnext < RTW_RXQLEN);
-
        sc->sc_rxnext = next;
 
+       KASSERT(sc->sc_rxnext < sc->sc_nrxdesc);
+
        return;
 }
 
@@ -1558,8 +1579,9 @@
 
        for (desc = 0; desc < RTW_RXQLEN; desc++) {
                hrx = &sc->sc_rxdesc[desc];
-               printf("%s: ctl %08x rsvd0/rssi %08x buf/tsftl %08x "
+               printf("%s: %sctl %08x rsvd0/rssi %08x buf/tsftl %08x "
                    "rsvd1/tsfth %08x\n", __func__,
+                   (desc >= sc->sc_nrxdesc) ? "UNUSED " : "",
                    le32toh(hrx->hrx_ctl), le32toh(hrx->hrx_rssi),
                    le32toh(hrx->hrx_buf), le32toh(hrx->hrx_tsfth));
        }
@@ -1593,26 +1615,30 @@
             (uintptr_t)RTW_RING_BASE(sc, hd_rx)));
 }
 
-static void
+static int
 rtw_swring_setup(struct rtw_softc *sc)
 {
+       int rc;
        rtw_txdesc_blk_init_all(&sc->sc_txdesc_blk[0]);
 
        rtw_txctl_blk_init_all(&sc->sc_txctl_blk[0]);
 
+       if ((rc = rtw_rxctl_init_all(sc->sc_dmat, sc->sc_rxctl, &sc->sc_nrxdesc,
+           sc->sc_dev.dv_xname)) != 0 && sc->sc_nrxdesc == 0) {
+               printf("%s: could not allocate rx buffers\n",
+                   sc->sc_dev.dv_xname);
+               return rc;
+       }
        rtw_rxdescs_sync(sc->sc_dmat, sc->sc_desc_dmamap,
-           0, RTW_RXQLEN, BUS_DMASYNC_POSTREAD|BUS_DMASYNC_POSTWRITE);
-       rtw_rxctl_init_all(sc->sc_dmat, sc->sc_rxctl, &sc->sc_rxnext,
-           sc->sc_dev.dv_xname);
+           0, sc->sc_nrxdesc, sc->sc_nrxdesc,
+           BUS_DMASYNC_POSTREAD|BUS_DMASYNC_POSTWRITE);
+       sc->sc_rxnext = 0;
        rtw_rxdesc_init_all(sc->sc_dmat, sc->sc_desc_dmamap,
-           sc->sc_rxdesc, sc->sc_rxctl, 1);
+           sc->sc_rxdesc, sc->sc_rxctl, sc->sc_nrxdesc, 1);
 
        rtw_txdescs_sync_all(sc->sc_dmat, sc->sc_desc_dmamap,
            &sc->sc_txdesc_blk[0]);
-#if 0  /* redundant with rtw_rxdesc_init_all */



Home | Main Index | Thread Index | Old Index