PERFORCE change 66439 for review
Sam Leffler
sam at FreeBSD.org
Sat Dec 4 23:06:21 PST 2004
http://perforce.freebsd.org/chv.cgi?CH=66439
Change 66439 by sam at sam_ebb on 2004/12/05 07:05:37
Revamp descriptor allocation to improve success on systems
with fragment memory and for forthcoming multi-*ssid support.
o encapsulate descriptor+buffer state in new ath_dmadesc struct
o manage tx+rx+beacon dma state independently
o remove some assumptions about there being only one beacon frame
o improve error handling on failures during tx/rx setup
Affected files ...
.. //depot/projects/wifi/sys/dev/ath/if_ath.c#38 edit
.. //depot/projects/wifi/sys/dev/ath/if_athvar.h#15 edit
Differences ...
==== //depot/projects/wifi/sys/dev/ath/if_ath.c#38 (text+ko) ====
@@ -122,6 +122,8 @@
static void ath_bstuck_proc(void *, int);
static void ath_beacon_free(struct ath_softc *);
static void ath_beacon_config(struct ath_softc *);
+static void ath_descdma_cleanup(struct ath_softc *sc,
+ struct ath_descdma *, ath_bufhead *);
static int ath_desc_alloc(struct ath_softc *);
static void ath_desc_free(struct ath_softc *);
static struct ieee80211_node *ath_node_alloc(struct ieee80211_node_table *);
@@ -236,6 +238,8 @@
#define KEYPRINTF(sc, k, ix, mac)
#endif
+MALLOC_DEFINE(M_ATHDEV, "athdev", "ath driver dma buffers");
+
int
ath_attach(u_int16_t devid, struct ath_softc *sc)
{
@@ -1679,12 +1683,17 @@
static int
ath_beacon_alloc(struct ath_softc *sc, struct ieee80211_node *ni)
{
- struct ieee80211com *ic = &sc->sc_ic;
+ struct ieee80211com *ic = ni->ni_ic;
struct ath_buf *bf;
struct mbuf *m;
int error;
- bf = sc->sc_bcbuf;
+ bf = STAILQ_FIRST(&sc->sc_bbuf);
+ if (bf == NULL) {
+ DPRINTF(sc, ATH_DEBUG_BEACON, "%s: no dma buffers\n", __func__);
+ sc->sc_stats.ast_be_nombuf++; /* XXX */
+ return ENOMEM; /* XXX */
+ }
if (bf->bf_m != NULL) {
bus_dmamap_unload(sc->sc_dmat, bf->bf_dmamap);
m_freem(bf->bf_m);
@@ -1724,8 +1733,8 @@
#define USE_SHPREAMBLE(_ic) \
(((_ic)->ic_flags & (IEEE80211_F_SHPREAMBLE | IEEE80211_F_USEBARKER))\
== IEEE80211_F_SHPREAMBLE)
- struct ieee80211com *ic = &sc->sc_ic;
struct ieee80211_node *ni = bf->bf_node;
+ struct ieee80211com *ic = ni->ni_ic;
struct mbuf *m = bf->bf_m;
struct ath_hal *ah = sc->sc_ah;
struct ath_node *an = ATH_NODE(ni);
@@ -1798,8 +1807,9 @@
ath_beacon_proc(void *arg, int pending)
{
struct ath_softc *sc = arg;
- struct ieee80211com *ic = &sc->sc_ic;
- struct ath_buf *bf = sc->sc_bcbuf;
+ struct ath_buf *bf = STAILQ_FIRST(&sc->sc_bbuf);
+ struct ieee80211_node *ni = bf->bf_node;
+ struct ieee80211com *ic = ni->ni_ic;
struct ath_hal *ah = sc->sc_ah;
struct mbuf *m;
int ncabq, error, otherant;
@@ -1935,14 +1945,15 @@
static void
ath_beacon_free(struct ath_softc *sc)
{
- struct ath_buf *bf = sc->sc_bcbuf;
+ struct ath_buf *bf;
- if (bf->bf_m != NULL) {
- bus_dmamap_unload(sc->sc_dmat, bf->bf_dmamap);
- m_freem(bf->bf_m);
- bf->bf_m = NULL;
- bf->bf_node = NULL;
- }
+ STAILQ_FOREACH(bf, &sc->sc_bbuf, bf_list)
+ if (bf->bf_m != NULL) {
+ bus_dmamap_unload(sc->sc_dmat, bf->bf_dmamap);
+ m_freem(bf->bf_m);
+ bf->bf_m = NULL;
+ bf->bf_node = NULL;
+ }
}
/*
@@ -2088,121 +2099,162 @@
}
static int
-ath_desc_alloc(struct ath_softc *sc)
+ath_descdma_setup(struct ath_softc *sc,
+ struct ath_descdma *dd, ath_bufhead *head,
+ const char *name, int nbuf, int ndesc)
{
-#define DS2PHYS(_sc, _ds) \
- ((_sc)->sc_desc_paddr + ((caddr_t)(_ds) - (caddr_t)(_sc)->sc_desc))
- int i, bsize, error;
+#define DS2PHYS(_dd, _ds) \
+ ((_dd)->dd_desc_paddr + ((caddr_t)(_ds) - (caddr_t)(_dd)->dd_desc))
+ struct ifnet *ifp = &sc->sc_if;
struct ath_desc *ds;
struct ath_buf *bf;
+ int i, bsize, error;
+ DPRINTF(sc, ATH_DEBUG_RESET, "%s: %s DMA: %u buffers %u desc/buf\n",
+ __func__, name, nbuf, ndesc);
+
+ dd->dd_name = name;
+
/* allocate descriptors */
- sc->sc_desc_len = sizeof(struct ath_desc) *
- (ATH_TXBUF * ATH_TXDESC + ATH_RXBUF + 1);
- error = bus_dmamap_create(sc->sc_dmat, BUS_DMA_NOWAIT, &sc->sc_ddmamap);
- if (error != 0)
+ dd->dd_desc_len = sizeof(struct ath_desc) * nbuf * ndesc;
+ error = bus_dmamap_create(sc->sc_dmat, BUS_DMA_NOWAIT, &dd->dd_dmamap);
+ if (error != 0) {
+ if_printf(ifp, "unable to create dmamap for %s descriptors, "
+ "error %u\n", dd->dd_name, error);
return error;
+ }
- error = bus_dmamem_alloc(sc->sc_dmat, (void**) &sc->sc_desc,
- BUS_DMA_NOWAIT, &sc->sc_ddmamap);
- if (error != 0)
+ error = bus_dmamem_alloc(sc->sc_dmat, (void**) &dd->dd_desc,
+ BUS_DMA_NOWAIT, &dd->dd_dmamap);
+ if (error != 0) {
+ if_printf(ifp, "unable to alloc memory for %u %s descriptors, "
+ "error %u\n", nbuf * ndesc, dd->dd_name, error);
goto fail0;
+ }
- error = bus_dmamap_load(sc->sc_dmat, sc->sc_ddmamap,
- sc->sc_desc, sc->sc_desc_len,
- ath_load_cb, &sc->sc_desc_paddr,
+ error = bus_dmamap_load(sc->sc_dmat, dd->dd_dmamap,
+ dd->dd_desc, dd->dd_desc_len,
+ ath_load_cb, &dd->dd_desc_paddr,
BUS_DMA_NOWAIT);
- if (error != 0)
+ if (error != 0) {
+ if_printf(ifp, "unable to map %s descriptors, error %u\n",
+ dd->dd_name, error);
goto fail1;
+ }
- ds = sc->sc_desc;
- DPRINTF(sc, ATH_DEBUG_ANY, "%s: DMA map: %p (%lu) -> %p (%lu)\n",
- __func__, ds, (u_long) sc->sc_desc_len, (caddr_t) sc->sc_desc_paddr,
- /*XXX*/ (u_long) sc->sc_desc_len);
+ ds = dd->dd_desc;
+ DPRINTF(sc, ATH_DEBUG_RESET, "%s: %s DMA map: %p (%lu) -> %p (%lu)\n",
+ __func__, dd->dd_name, ds, (u_long) dd->dd_desc_len,
+ (caddr_t) dd->dd_desc_paddr, /*XXX*/ (u_long) dd->dd_desc_len);
- /* allocate buffers */
- bsize = sizeof(struct ath_buf) * (ATH_TXBUF + ATH_RXBUF + 1);
- bf = malloc(bsize, M_DEVBUF, M_NOWAIT | M_ZERO);
- if (bf == NULL)
+ /* allocate rx buffers */
+ bsize = sizeof(struct ath_buf) * nbuf;
+ bf = malloc(bsize, M_ATHDEV, M_NOWAIT | M_ZERO);
+ if (bf == NULL) {
+ if_printf(ifp, "malloc of %s buffers failed, size %u\n",
+ dd->dd_name, bsize);
goto fail2;
- sc->sc_bufptr = bf;
-
- STAILQ_INIT(&sc->sc_rxbuf);
- for (i = 0; i < ATH_RXBUF; i++, bf++, ds++) {
- bf->bf_desc = ds;
- bf->bf_daddr = DS2PHYS(sc, ds);
- error = bus_dmamap_create(sc->sc_dmat, BUS_DMA_NOWAIT,
- &bf->bf_dmamap);
- if (error != 0)
- break;
- STAILQ_INSERT_TAIL(&sc->sc_rxbuf, bf, bf_list);
}
+ dd->dd_bufptr = bf;
- STAILQ_INIT(&sc->sc_txbuf);
- for (i = 0; i < ATH_TXBUF; i++, bf++, ds += ATH_TXDESC) {
+ STAILQ_INIT(head);
+ for (i = 0; i < nbuf; i++, bf++, ds += ndesc) {
bf->bf_desc = ds;
- bf->bf_daddr = DS2PHYS(sc, ds);
+ bf->bf_daddr = DS2PHYS(dd, ds);
error = bus_dmamap_create(sc->sc_dmat, BUS_DMA_NOWAIT,
- &bf->bf_dmamap);
- if (error != 0)
- break;
- STAILQ_INSERT_TAIL(&sc->sc_txbuf, bf, bf_list);
+ &bf->bf_dmamap);
+ if (error != 0) {
+ if_printf(ifp, "unable to create dmamap for %s "
+ "buffer %u, error %u\n", dd->dd_name, i, error);
+ ath_descdma_cleanup(sc, dd, head);
+ return error;
+ }
+ STAILQ_INSERT_TAIL(head, bf, bf_list);
}
-
- /* beacon buffer */
- bf->bf_desc = ds;
- bf->bf_daddr = DS2PHYS(sc, ds);
- error = bus_dmamap_create(sc->sc_dmat, BUS_DMA_NOWAIT, &bf->bf_dmamap);
- if (error != 0)
- return error;
- sc->sc_bcbuf = bf;
return 0;
-
fail2:
- bus_dmamap_unload(sc->sc_dmat, sc->sc_ddmamap);
+ bus_dmamap_unload(sc->sc_dmat, dd->dd_dmamap);
fail1:
- bus_dmamem_free(sc->sc_dmat, sc->sc_desc, sc->sc_ddmamap);
+ bus_dmamem_free(sc->sc_dmat, dd->dd_desc, dd->dd_dmamap);
fail0:
- bus_dmamap_destroy(sc->sc_dmat, sc->sc_ddmamap);
- sc->sc_ddmamap = NULL;
+ bus_dmamap_destroy(sc->sc_dmat, dd->dd_dmamap);
+ memset(dd, 0, sizeof(*dd));
return error;
#undef DS2PHYS
}
static void
-ath_desc_free(struct ath_softc *sc)
+ath_descdma_cleanup(struct ath_softc *sc,
+ struct ath_descdma *dd, ath_bufhead *head)
{
struct ath_buf *bf;
+ struct ieee80211_node *ni;
- bus_dmamap_unload(sc->sc_dmat, sc->sc_ddmamap);
- bus_dmamem_free(sc->sc_dmat, sc->sc_desc, sc->sc_ddmamap);
- bus_dmamap_destroy(sc->sc_dmat, sc->sc_ddmamap);
+ bus_dmamap_unload(sc->sc_dmat, dd->dd_dmamap);
+ bus_dmamem_free(sc->sc_dmat, dd->dd_desc, dd->dd_dmamap);
+ bus_dmamap_destroy(sc->sc_dmat, dd->dd_dmamap);
- /*
- * NB: TX queues have already been freed in ath_draintxq(),
- * which must be called before calling this function.
- */
-
- STAILQ_FOREACH(bf, &sc->sc_txbuf, bf_list)
- bus_dmamap_destroy(sc->sc_dmat, bf->bf_dmamap);
- STAILQ_FOREACH(bf, &sc->sc_rxbuf, bf_list) {
+ STAILQ_FOREACH(bf, head, bf_list) {
if (bf->bf_m) {
- bus_dmamap_unload(sc->sc_dmat, bf->bf_dmamap);
- bus_dmamap_destroy(sc->sc_dmat, bf->bf_dmamap);
m_freem(bf->bf_m);
bf->bf_m = NULL;
}
+ if (bf->bf_dmamap != NULL) {
+ bus_dmamap_destroy(sc->sc_dmat, bf->bf_dmamap);
+ bf->bf_dmamap = NULL;
+ }
+ ni = bf->bf_node;
+ bf->bf_node = NULL;
+ if (ni != NULL) {
+ /*
+ * Reclaim node reference.
+ */
+ ieee80211_free_node(ni);
+ }
}
- if (sc->sc_bcbuf != NULL) {
- bus_dmamap_unload(sc->sc_dmat, sc->sc_bcbuf->bf_dmamap);
- bus_dmamap_destroy(sc->sc_dmat, sc->sc_bcbuf->bf_dmamap);
- sc->sc_bcbuf = NULL;
+
+ STAILQ_INIT(head);
+ free(dd->dd_bufptr, M_ATHDEV);
+ memset(dd, 0, sizeof(*dd));
+}
+
+static int
+ath_desc_alloc(struct ath_softc *sc)
+{
+ int error;
+
+ error = ath_descdma_setup(sc, &sc->sc_rxdma, &sc->sc_rxbuf,
+ "rx", ATH_RXBUF, 1);
+ if (error != 0)
+ return error;
+
+ error = ath_descdma_setup(sc, &sc->sc_txdma, &sc->sc_txbuf,
+ "tx", ATH_TXBUF, ATH_TXDESC);
+ if (error != 0) {
+ ath_descdma_cleanup(sc, &sc->sc_rxdma, &sc->sc_rxbuf);
+ return error;
+ }
+
+ error = ath_descdma_setup(sc, &sc->sc_bdma, &sc->sc_bbuf,
+ "beacon", 1, 1);
+ if (error != 0) {
+ ath_descdma_cleanup(sc, &sc->sc_txdma, &sc->sc_txbuf);
+ ath_descdma_cleanup(sc, &sc->sc_rxdma, &sc->sc_rxbuf);
+ return error;
}
+ return 0;
+}
- STAILQ_INIT(&sc->sc_rxbuf);
- STAILQ_INIT(&sc->sc_txbuf);
- free(sc->sc_bufptr, M_DEVBUF);
- sc->sc_bufptr = NULL;
+static void
+ath_desc_free(struct ath_softc *sc)
+{
+
+ if (sc->sc_bdma.dd_desc_len != 0)
+ ath_descdma_cleanup(sc, &sc->sc_bdma, &sc->sc_bbuf);
+ if (sc->sc_txdma.dd_desc_len != 0)
+ ath_descdma_cleanup(sc, &sc->sc_txdma, &sc->sc_txbuf);
+ if (sc->sc_rxdma.dd_desc_len != 0)
+ ath_descdma_cleanup(sc, &sc->sc_rxdma, &sc->sc_rxbuf);
}
static struct ieee80211_node *
@@ -2296,11 +2348,9 @@
struct ath_hal *ah = sc->sc_ah;
int error;
struct mbuf *m;
-struct mbuf *morig; /*XXX*/
struct ath_desc *ds;
m = bf->bf_m;
-morig = m; /* XXX */
if (m == NULL) {
/*
* NB: by assigning a page to the rx dma buffer we
@@ -2320,7 +2370,8 @@
bf->bf_m = m;
m->m_pkthdr.len = m->m_len = m->m_ext.ext_size;
- error = bus_dmamap_load_mbuf(sc->sc_dmat, bf->bf_dmamap, m,
+ error = bus_dmamap_load_mbuf(sc->sc_dmat,
+ bf->bf_dmamap, m,
ath_mbuf_load_cb, bf,
BUS_DMA_NOWAIT);
if (error != 0) {
@@ -2333,7 +2384,6 @@
KASSERT(bf->bf_nseg == 1, ("%s: multi-segment packet; nseg %u",
__func__, bf->bf_nseg));
}
- KASSERT(m->m_next == NULL, ("m_next %p morig %p (2)", m->m_next, morig));
bus_dmamap_sync(sc->sc_dmat, bf->bf_dmamap, BUS_DMASYNC_PREREAD);
/*
@@ -2428,8 +2478,8 @@
ath_rx_proc(void *arg, int npending)
{
#define PA2DESC(_sc, _pa) \
- ((struct ath_desc *)((caddr_t)(_sc)->sc_desc + \
- ((_pa) - (_sc)->sc_desc_paddr)))
+ ((struct ath_desc *)((caddr_t)(_sc)->sc_rxdma.dd_desc + \
+ ((_pa) - (_sc)->sc_rxdma.dd_desc_paddr)))
struct ath_softc *sc = arg;
struct ath_buf *bf;
struct ieee80211com *ic = &sc->sc_ic;
@@ -2482,10 +2532,6 @@
#endif
if (status == HAL_EINPROGRESS)
break;
- if (m->m_next != NULL) { /* XXX */
- if_printf(ifp, "m_next %p, patching!\n", m->m_next);
- m->m_next = NULL;
- }
STAILQ_REMOVE_HEAD(&sc->sc_rxbuf, bf_list);
if (ds->ds_rxstat.rs_more) {
/*
@@ -2535,7 +2581,7 @@
len = ds->ds_rxstat.rs_datalen;
if (len >= sizeof (struct ieee80211_frame)) {
bus_dmamap_sync(sc->sc_dmat,
- bf->bf_dmamap,
+ bf->bf_dmamap,
BUS_DMASYNC_POSTREAD);
ieee80211_notify_michael_failure(ic,
mtod(m, struct ieee80211_frame *),
@@ -2562,7 +2608,7 @@
* when the rx descriptor is setup again to receive
* another frame.
*/
- bus_dmamap_sync(sc->sc_dmat, bf->bf_dmamap,
+ bus_dmamap_sync(sc->sc_dmat, bf->bf_dmamap,
BUS_DMASYNC_POSTREAD);
bus_dmamap_unload(sc->sc_dmat, bf->bf_dmamap);
bf->bf_m = NULL;
@@ -2956,7 +3002,6 @@
bus_dmamap_sync(sc->sc_dmat, bf->bf_dmamap, BUS_DMASYNC_PREWRITE);
bf->bf_m = m0;
bf->bf_node = ni; /* NB: held reference */
-{ struct mbuf *n; bf->bf_nm = 0; for (n = bf->bf_m; n != NULL; n = n->m_next) bf->bf_mshadow[bf->bf_nm++] = n; }/*XXX*/
/* setup descriptors */
ds = bf->bf_desc;
@@ -3548,8 +3593,8 @@
ath_stoprecv(struct ath_softc *sc)
{
#define PA2DESC(_sc, _pa) \
- ((struct ath_desc *)((caddr_t)(_sc)->sc_desc + \
- ((_pa) - (_sc)->sc_desc_paddr)))
+ ((struct ath_desc *)((caddr_t)(_sc)->sc_rxdma.dd_desc + \
+ ((_pa) - (_sc)->sc_rxdma.dd_desc_paddr)))
struct ath_hal *ah = sc->sc_ah;
ath_hal_stoppcurecv(ah); /* disable PCU */
==== //depot/projects/wifi/sys/dev/ath/if_athvar.h#15 (text+ko) ====
@@ -83,16 +83,28 @@
struct ath_buf {
STAILQ_ENTRY(ath_buf) bf_list;
int bf_nseg;
- bus_dmamap_t bf_dmamap; /* DMA map of the buffer */
struct ath_desc *bf_desc; /* virtual addr of desc */
bus_addr_t bf_daddr; /* physical addr of desc */
+ bus_dmamap_t bf_dmamap; /* DMA map for mbuf chain */
struct mbuf *bf_m; /* mbuf for buf */
struct ieee80211_node *bf_node; /* pointer to the node */
bus_size_t bf_mapsize;
#define ATH_MAX_SCATTER 64
bus_dma_segment_t bf_segs[ATH_MAX_SCATTER];
-struct mbuf *bf_mshadow[ATH_MAX_SCATTER];/*XXX*/
-int bf_nm;
+};
+typedef STAILQ_HEAD(, ath_buf) ath_bufhead;
+
+/*
+ * DMA state for tx/rx descriptors.
+ */
+struct ath_descdma {
+ const char* dd_name;
+ struct ath_desc *dd_desc; /* descriptors */
+ bus_addr_t dd_desc_paddr; /* physical addr of dd_desc */
+ bus_addr_t dd_desc_len; /* size of dd_desc */
+ bus_dma_segment_t dd_dseg;
+ bus_dmamap_t dd_dmamap; /* DMA map for descriptors */
+ struct ath_buf *dd_bufptr; /* associated buffers */
};
/*
@@ -191,36 +203,32 @@
} u_rx_rt;
int sc_rx_th_len;
- struct ath_desc *sc_desc; /* TX/RX descriptors */
- bus_dma_segment_t sc_dseg;
- bus_dmamap_t sc_ddmamap; /* DMA map for descriptors */
- bus_addr_t sc_desc_paddr; /* physical addr of sc_desc */
- bus_addr_t sc_desc_len; /* size of sc_desc */
-
struct task sc_fataltask; /* fatal int processing */
- STAILQ_HEAD(, ath_buf) sc_rxbuf; /* receive buffer */
+ struct ath_descdma sc_rxdma; /* RX descriptos */
+ ath_bufhead sc_rxbuf; /* receive buffer */
u_int32_t *sc_rxlink; /* link ptr in last RX desc */
struct task sc_rxtask; /* rx int processing */
struct task sc_rxorntask; /* rxorn int processing */
u_int8_t sc_defant; /* current default antenna */
u_int8_t sc_rxotherant; /* rx's on non-default antenna*/
+ struct ath_descdma sc_txdma; /* TX descriptors */
+ ath_bufhead sc_txbuf; /* transmit buffer */
+ struct mtx sc_txbuflock; /* txbuf lock */
int sc_tx_timer; /* transmit timeout */
- STAILQ_HEAD(, ath_buf) sc_txbuf; /* transmit buffer */
- struct mtx sc_txbuflock; /* txbuf lock */
u_int sc_txqsetup; /* h/w queues setup */
u_int sc_txintrperiod;/* tx interrupt batching */
struct ath_txq sc_txq[HAL_NUM_TX_QUEUES];
struct ath_txq *sc_ac2q[5]; /* WME AC -> h/w q map */
struct task sc_txtask; /* tx int processing */
+ struct ath_descdma sc_bdma; /* beacon descriptors */
+ ath_bufhead sc_bbuf; /* beacon buffers */
u_int sc_bhalq; /* HAL q for outgoing beacons */
u_int sc_bmisscount; /* missed beacon transmits */
u_int32_t sc_ant_tx[8]; /* recent tx frames/antenna */
struct ath_txq *sc_cabq; /* tx q for cab frames */
- struct ath_buf *sc_bcbuf; /* beacon buffer */
- struct ath_buf *sc_bufptr; /* allocated buffer ptr */
struct ieee80211_beacon_offsets sc_boff;/* dynamic update state */
struct task sc_bmisstask; /* bmiss int processing */
struct task sc_bstucktask; /* stuck beacon processing */
More information about the p4-projects
mailing list