diff options
author | Damien Bergamini <damien@cvs.openbsd.org> | 2004-12-05 17:46:08 +0000 |
---|---|---|
committer | Damien Bergamini <damien@cvs.openbsd.org> | 2004-12-05 17:46:08 +0000 |
commit | e43c7748a013ce41ed5889a855a854a8e1885491 (patch) | |
tree | a83dc6edab58f9324ce168ece1e8e26b4f22fa8e /sys/dev/pci | |
parent | c7eb0b27ebd6d284e51c151a8446e619144d7db5 (diff) |
Clean Tx/Rx rings allocation and management.
Diffstat (limited to 'sys/dev/pci')
-rw-r--r-- | sys/dev/pci/if_ipw.c | 768 | ||||
-rw-r--r-- | sys/dev/pci/if_ipwreg.h | 6 | ||||
-rw-r--r-- | sys/dev/pci/if_ipwvar.h | 25 |
3 files changed, 336 insertions, 463 deletions
diff --git a/sys/dev/pci/if_ipw.c b/sys/dev/pci/if_ipw.c index e3dbebf2a7a..ad834ef122d 100644 --- a/sys/dev/pci/if_ipw.c +++ b/sys/dev/pci/if_ipw.c @@ -1,4 +1,4 @@ -/* $Id: if_ipw.c,v 1.29 2004/12/05 17:13:52 damien Exp $ */ +/* $Id: if_ipw.c,v 1.30 2004/12/05 17:46:07 damien Exp $ */ /*- * Copyright (c) 2004 @@ -80,6 +80,8 @@ static const struct ieee80211_rateset ipw_rateset_11b = int ipw_match(struct device *, void *, void *); void ipw_attach(struct device *, struct device *, void *); int ipw_detach(struct device *, int); +int ipw_dma_alloc(struct ipw_softc *); +void ipw_release(struct ipw_softc *); int ipw_media_change(struct ifnet *); void ipw_media_status(struct ifnet *, struct ifmediareq *); int ipw_newstate(struct ieee80211com *, enum ieee80211_state, int); @@ -103,12 +105,6 @@ int ipw_ioctl(struct ifnet *, u_long, caddr_t); u_int32_t ipw_read_table1(struct ipw_softc *, u_int32_t); void ipw_write_table1(struct ipw_softc *, u_int32_t, u_int32_t); int ipw_read_table2(struct ipw_softc *, u_int32_t, void *, u_int32_t *); -int ipw_dmamem_init(struct ipw_softc *); -void ipw_dmamem_stop(struct ipw_softc *); -int ipw_tx_init(struct ipw_softc *); -void ipw_tx_stop(struct ipw_softc *); -int ipw_rx_init(struct ipw_softc *); -void ipw_rx_stop(struct ipw_softc *); void ipw_stop_master(struct ipw_softc *); int ipw_reset(struct ipw_softc *); int ipw_load_ucode(struct ipw_softc *, u_char *, int); @@ -224,9 +220,8 @@ ipw_attach(struct device *parent, struct device *self, void *aux) return; } - /* set up dma memory */ - if (ipw_dmamem_init(sc) != 0) { - printf(": failed to initialize DMA memory\n"); + if (ipw_dma_alloc(sc) != 0) { + printf(": failed to allocate DMA resources\n"); return; } @@ -304,7 +299,6 @@ ipw_detach(struct device* self, int flags) struct ifnet *ifp = &sc->sc_ic.ic_if; ipw_stop(ifp, 1); - ipw_dmamem_stop(sc); #if NBPFILTER > 0 bpfdetach(ifp); @@ -312,6 +306,8 @@ ipw_detach(struct device* self, int flags) ieee80211_ifdetach(ifp); if_detach(ifp); + ipw_release(sc); + if (sc->sc_ih != NULL) { pci_intr_disestablish(sc->sc_pct, sc->sc_ih); sc->sc_ih = NULL; @@ -323,6 +319,265 @@ ipw_detach(struct device* self, int flags) } int +ipw_dma_alloc(struct ipw_softc *sc) +{ + struct ipw_soft_bd *sbd; + struct ipw_soft_hdr *shdr; + struct ipw_soft_buf *sbuf; + int i, nsegs, error; + + /* + * Allocate and map tx ring + */ + error = bus_dmamap_create(sc->sc_dmat, IPW_TBD_SZ, 1, IPW_TBD_SZ, 0, + BUS_DMA_NOWAIT, &sc->tbd_map); + if (error != 0) { + printf("%s: could not create tx ring DMA map\n"); + goto fail; + } + + error = bus_dmamem_alloc(sc->sc_dmat, IPW_TBD_SZ, PAGE_SIZE, 0, + &sc->tbd_seg, 1, &nsegs, BUS_DMA_NOWAIT); + if (error != 0) { + printf("%s: could not allocate tx ring DMA memory\n"); + goto fail; + } + + error = bus_dmamem_map(sc->sc_dmat, &sc->tbd_seg, nsegs, IPW_TBD_SZ, + (caddr_t *)&sc->tbd_list, BUS_DMA_NOWAIT); + if (error != 0) { + printf("%s: could not map tx ring DMA memory\n"); + goto fail; + } + + error = bus_dmamap_load(sc->sc_dmat, sc->tbd_map, sc->tbd_list, + IPW_TBD_SZ, NULL, BUS_DMA_NOWAIT); + if (error != 0) { + printf("%s: could not load tx ring DMA map\n"); + goto fail; + } + + /* + * Allocate and map rx ring + */ + error = bus_dmamap_create(sc->sc_dmat, IPW_RBD_SZ, 1, IPW_RBD_SZ, 0, + BUS_DMA_NOWAIT, &sc->rbd_map); + if (error != 0) { + printf("%s: could not create rx ring DMA map\n"); + goto fail; + } + + error = bus_dmamem_alloc(sc->sc_dmat, IPW_RBD_SZ, PAGE_SIZE, 0, + &sc->rbd_seg, 1, &nsegs, BUS_DMA_NOWAIT); + if (error != 0) { + printf("%s: could not allocate rx ring DMA memory\n"); + goto fail; + } + + error = bus_dmamem_map(sc->sc_dmat, &sc->rbd_seg, nsegs, IPW_RBD_SZ, + (caddr_t *)&sc->rbd_list, BUS_DMA_NOWAIT); + if (error != 0) { + printf("%s: could not map rx ring DMA memory\n"); + goto fail; + } + + error = bus_dmamap_load(sc->sc_dmat, sc->rbd_map, sc->rbd_list, + IPW_RBD_SZ, NULL, BUS_DMA_NOWAIT); + if (error != 0) { + printf("%s: could not load tx ring DMA map\n"); + goto fail; + } + + /* + * Allocate and map status ring + */ + error = bus_dmamap_create(sc->sc_dmat, IPW_STATUS_SZ, 1, IPW_STATUS_SZ, + 0, BUS_DMA_NOWAIT, &sc->status_map); + if (error != 0) { + printf("%s: could not create status ring DMA map\n"); + goto fail; + } + + error = bus_dmamem_alloc(sc->sc_dmat, IPW_STATUS_SZ, PAGE_SIZE, 0, + &sc->status_seg, 1, &nsegs, BUS_DMA_NOWAIT); + if (error != 0) { + printf("%s: could not allocate status ring DMA memory\n"); + goto fail; + } + + error = bus_dmamem_map(sc->sc_dmat, &sc->status_seg, nsegs, + IPW_STATUS_SZ, (caddr_t *)&sc->status_list, BUS_DMA_NOWAIT); + if (error != 0) { + printf("%s: could not map status ring DMA memory\n"); + goto fail; + } + + error = bus_dmamap_load(sc->sc_dmat, sc->status_map, sc->status_list, + IPW_STATUS_SZ, NULL, BUS_DMA_NOWAIT); + if (error != 0) { + printf("%s: could not load status ring DMA map\n"); + goto fail; + } + + /* + * Allocate command DMA map + */ + error = bus_dmamap_create(sc->sc_dmat, sizeof (struct ipw_cmd), 1, + sizeof (struct ipw_cmd), 0, BUS_DMA_NOWAIT, &sc->cmd_map); + if (error != 0) { + printf("%s: could not create command DMA map\n"); + goto fail; + } + + /* + * Allocate headers DMA maps + */ + SLIST_INIT(&sc->free_shdr); + for (i = 0; i < IPW_NDATA; i++) { + shdr = &sc->shdr_list[i]; + error = bus_dmamap_create(sc->sc_dmat, sizeof (struct ipw_hdr), + 1, sizeof (struct ipw_hdr), 0, BUS_DMA_NOWAIT, &shdr->map); + if (error != 0) { + printf("%s: could not create header DMA map\n"); + goto fail; + } + SLIST_INSERT_HEAD(&sc->free_shdr, shdr, next); + } + + /* + * Allocate tx buffers DMA maps + */ + SLIST_INIT(&sc->free_sbuf); + for (i = 0; i < IPW_NDATA; i++) { + sbuf = &sc->tx_sbuf_list[i]; + error = bus_dmamap_create(sc->sc_dmat, MCLBYTES, IPW_MAX_NSEG, + MCLBYTES, 0, BUS_DMA_NOWAIT, &sbuf->map); + if (error != 0) { + printf("%s: could not create tx DMA map\n"); + goto fail; + } + SLIST_INSERT_HEAD(&sc->free_sbuf, sbuf, next); + } + + /* + * Initialize tx ring + */ + for (i = 0; i < IPW_NTBD; i++) { + sbd = &sc->stbd_list[i]; + sbd->bd = &sc->tbd_list[i]; + sbd->type = IPW_SBD_TYPE_NOASSOC; + } + + /* + * Pre-allocate rx buffers and DMA maps + */ + for (i = 0; i < IPW_NRBD; i++) { + sbd = &sc->srbd_list[i]; + sbuf = &sc->rx_sbuf_list[i]; + sbd->bd = &sc->rbd_list[i]; + + MGETHDR(sbuf->m, M_DONTWAIT, MT_DATA); + if (sbuf->m == NULL) { + printf("%s: could not allocate rx mbuf\n"); + error = ENOMEM; + goto fail; + } + + MCLGET(sbuf->m, M_DONTWAIT); + if (!(sbuf->m->m_flags & M_EXT)) { + m_freem(sbuf->m); + printf("%s: could not allocate rx mbuf cluster\n"); + error = ENOMEM; + goto fail; + } + + error = bus_dmamap_create(sc->sc_dmat, MCLBYTES, 1, MCLBYTES, + 0, BUS_DMA_NOWAIT, &sbuf->map); + if (error != 0) { + printf("%s: could not create rx DMA map\n"); + goto fail; + } + + error = bus_dmamap_load(sc->sc_dmat, sbuf->map, + mtod(sbuf->m, void *), MCLBYTES, NULL, BUS_DMA_NOWAIT); + if (error != 0) { + printf("%s: could not map rx DMA memory\n"); + goto fail; + } + + sbd->type = IPW_SBD_TYPE_DATA; + sbd->priv = sbuf; + sbd->bd->physaddr = htole32(sbuf->map->dm_segs[0].ds_addr); + sbd->bd->len = htole32(MCLBYTES); + } + + bus_dmamap_sync(sc->sc_dmat, sc->rbd_map, 0, IPW_RBD_SZ, + BUS_DMASYNC_PREWRITE); + + return 0; + +fail: ipw_release(sc); + return error; +} + +void +ipw_release(struct ipw_softc *sc) +{ + struct ipw_soft_buf *sbuf; + int i; + + if (sc->tbd_map != NULL) { + if (sc->tbd_list != NULL) { + bus_dmamap_unload(sc->sc_dmat, sc->tbd_map); + bus_dmamem_unmap(sc->sc_dmat, (caddr_t)sc->tbd_list, + IPW_TBD_SZ); + bus_dmamem_free(sc->sc_dmat, &sc->tbd_seg, 1); + } + bus_dmamap_destroy(sc->sc_dmat, sc->tbd_map); + } + + if (sc->rbd_map != NULL) { + if (sc->rbd_list != NULL) { + bus_dmamap_unload(sc->sc_dmat, sc->rbd_map); + bus_dmamem_unmap(sc->sc_dmat, (caddr_t)sc->rbd_list, + IPW_RBD_SZ); + bus_dmamem_free(sc->sc_dmat, &sc->rbd_seg, 1); + } + bus_dmamap_destroy(sc->sc_dmat, sc->rbd_map); + } + + if (sc->status_map != NULL) { + if (sc->status_list != NULL) { + bus_dmamap_unload(sc->sc_dmat, sc->status_map); + bus_dmamem_unmap(sc->sc_dmat, (caddr_t)sc->status_list, + IPW_RBD_SZ); + bus_dmamem_free(sc->sc_dmat, &sc->status_seg, 1); + } + bus_dmamap_destroy(sc->sc_dmat, sc->status_map); + } + + if (sc->cmd_map != NULL) + bus_dmamap_destroy(sc->sc_dmat, sc->cmd_map); + + for (i = 0; i < IPW_NDATA; i++) + bus_dmamap_destroy(sc->sc_dmat, sc->shdr_list[i].map); + + for (i = 0; i < IPW_NDATA; i++) + bus_dmamap_destroy(sc->sc_dmat, sc->tx_sbuf_list[i].map); + + for (i = 0; i < IPW_NRBD; i++) { + sbuf = &sc->rx_sbuf_list[i]; + if (sbuf->map != NULL) { + if (sbuf->m != NULL) { + bus_dmamap_unload(sc->sc_dmat, sbuf->map); + m_freem(sbuf->m); + } + bus_dmamap_destroy(sc->sc_dmat, sbuf->map); + } + } +} + +int ipw_media_change(struct ifnet *ifp) { int error; @@ -678,7 +933,7 @@ ipw_rx_intr(struct ipw_softc *sc) void ipw_release_sbd(struct ipw_softc *sc, struct ipw_soft_bd *sbd) { - struct ieee80211com *ic; + struct ieee80211com *ic = &sc->sc_ic; struct ipw_soft_hdr *shdr; struct ipw_soft_buf *sbuf; @@ -690,19 +945,21 @@ ipw_release_sbd(struct ipw_softc *sc, struct ipw_soft_bd *sbd) case IPW_SBD_TYPE_HEADER: shdr = sbd->priv; bus_dmamap_unload(sc->sc_dmat, shdr->map); - TAILQ_INSERT_TAIL(&sc->sc_free_shdr, shdr, next); + SLIST_INSERT_HEAD(&sc->free_shdr, shdr, next); break; case IPW_SBD_TYPE_DATA: - ic = &sc->sc_ic; sbuf = sbd->priv; bus_dmamap_unload(sc->sc_dmat, sbuf->map); + SLIST_INSERT_HEAD(&sc->free_sbuf, sbuf, next); + m_freem(sbuf->m); + if (sbuf->ni != NULL && sbuf->ni != ic->ic_bss) ieee80211_free_node(ic, sbuf->ni); + /* kill watchdog timer */ sc->sc_tx_timer = 0; - TAILQ_INSERT_TAIL(&sc->sc_free_sbuf, sbuf, next); break; } sbd->type = IPW_SBD_TYPE_NOASSOC; @@ -716,15 +973,19 @@ ipw_tx_intr(struct ipw_softc *sc) r = CSR_READ_4(sc, IPW_CSR_TX_READ_INDEX); - for (i = (sc->txold + 1) % IPW_NTBD; i != r; i = (i + 1) % IPW_NTBD) + for (i = (sc->txold + 1) % IPW_NTBD; i != r; i = (i + 1) % IPW_NTBD) { ipw_release_sbd(sc, &sc->stbd_list[i]); + sc->txfree++; + } /* Remember what the firmware has processed */ sc->txold = (r == 0) ? IPW_NTBD - 1 : r - 1; /* Call start() since some buffer descriptors have been released */ - ifp->if_flags &= ~IFF_OACTIVE; - (*ifp->if_start)(ifp); + if (sc->txfree >= 1 + IPW_MAX_NSEG) { + ifp->if_flags &= ~IFF_OACTIVE; + (*ifp->if_start)(ifp); + } } int @@ -774,7 +1035,7 @@ ipw_cmd(struct ipw_softc *sc, u_int32_t type, void *data, u_int32_t len) sbd = &sc->stbd_list[sc->txcur]; - error = bus_dmamap_load(sc->sc_dmat, sc->cmd_map, sc->cmd, + error = bus_dmamap_load(sc->sc_dmat, sc->cmd_map, &sc->cmd, sizeof (struct ipw_cmd), NULL, BUS_DMA_NOWAIT); if (error != 0) { printf("%s: could not map cmd dma memory\n", @@ -782,12 +1043,12 @@ ipw_cmd(struct ipw_softc *sc, u_int32_t type, void *data, u_int32_t len) return error; } - sc->cmd->type = htole32(type); - sc->cmd->subtype = htole32(0); - sc->cmd->len = htole32(len); - sc->cmd->seq = htole32(0); + sc->cmd.type = htole32(type); + sc->cmd.subtype = htole32(0); + sc->cmd.len = htole32(len); + sc->cmd.seq = htole32(0); if (data != NULL) - bcopy(data, sc->cmd->data, len); + bcopy(data, sc->cmd.data, len); sbd->type = IPW_SBD_TYPE_COMMAND; sbd->bd->physaddr = htole32(sc->cmd_map->dm_segs[0].ds_addr); @@ -804,6 +1065,7 @@ ipw_cmd(struct ipw_softc *sc, u_int32_t type, void *data, u_int32_t len) BUS_DMASYNC_PREWRITE); sc->txcur = (sc->txcur + 1) % IPW_NTBD; + sc->txfree--; CSR_WRITE_4(sc, IPW_CSR_TX_WRITE_INDEX, sc->txcur); DPRINTFN(2, ("TX!CMD!%u!%u!%u!%u\n", type, 0, 0, len)); @@ -849,8 +1111,8 @@ ipw_tx_start(struct ifnet *ifp, struct mbuf *m, struct ieee80211_node *ni) wh = mtod(m, struct ieee80211_frame *); - shdr = TAILQ_FIRST(&sc->sc_free_shdr); - sbuf = TAILQ_FIRST(&sc->sc_free_sbuf); + shdr = SLIST_FIRST(&sc->free_shdr); + sbuf = SLIST_FIRST(&sc->free_sbuf); shdr->hdr.type = htole32(IPW_HDR_TYPE_SEND); shdr->hdr.subtype = htole32(0); @@ -890,8 +1152,8 @@ ipw_tx_start(struct ifnet *ifp, struct mbuf *m, struct ieee80211_node *ni) return error; } - TAILQ_REMOVE(&sc->sc_free_sbuf, sbuf, next); - TAILQ_REMOVE(&sc->sc_free_shdr, shdr, next); + SLIST_REMOVE_HEAD(&sc->free_sbuf, next); + SLIST_REMOVE_HEAD(&sc->free_shdr, next); sbd = &sc->stbd_list[sc->txcur]; sbd->type = IPW_SBD_TYPE_HEADER; @@ -912,6 +1174,7 @@ ipw_tx_start(struct ifnet *ifp, struct mbuf *m, struct ieee80211_node *ni) sizeof (struct ipw_bd), BUS_DMASYNC_PREWRITE); sc->txcur = (sc->txcur + 1) % IPW_NTBD; + sc->txfree--; sbuf->m = m; sbuf->ni = ni; @@ -939,6 +1202,7 @@ ipw_tx_start(struct ifnet *ifp, struct mbuf *m, struct ieee80211_node *ni) sizeof (struct ipw_bd), BUS_DMASYNC_PREWRITE); sc->txcur = (sc->txcur + 1) % IPW_NTBD; + sc->txfree--; } bus_dmamap_sync(sc->sc_dmat, shdr->map, 0, sizeof (struct ipw_hdr), @@ -950,6 +1214,9 @@ ipw_tx_start(struct ifnet *ifp, struct mbuf *m, struct ieee80211_node *ni) /* Inform firmware about this new packet */ CSR_WRITE_4(sc, IPW_CSR_TX_WRITE_INDEX, sc->txcur); + if (sc->txfree < 1 + IPW_MAX_NSEG) + ifp->if_flags |= IFF_OACTIVE; + return 0; } @@ -1153,415 +1420,6 @@ ipw_read_table2(struct ipw_softc *sc, u_int32_t off, void *buf, u_int32_t *len) return 0; } -/* - * Allocate and map DMAble memory. Do not call in interrupt context. - */ -int -ipw_dmamem_init(struct ipw_softc *sc) -{ - int error, nsegs; - char *errmsg; - - error = bus_dmamem_alloc(sc->sc_dmat, IPW_TBD_SZ, PAGE_SIZE, 0, - &sc->tbd_seg, 1, &nsegs, BUS_DMA_NOWAIT); - if (error != 0) { - errmsg = "could not allocate tbd dma memory"; - goto fail; - } - - error = bus_dmamem_map(sc->sc_dmat, &sc->tbd_seg, nsegs, IPW_TBD_SZ, - (caddr_t *)&sc->tbd_list, BUS_DMA_NOWAIT); - if (error != 0) { - errmsg = "could not map tbd dma memory"; - goto fail; - } - - error = bus_dmamem_alloc(sc->sc_dmat, sizeof (struct ipw_cmd), - PAGE_SIZE, 0, &sc->cmd_seg, 1, &nsegs, BUS_DMA_NOWAIT); - if (error != 0) { - errmsg = "could not allocate cmd dma memory"; - goto fail; - } - - error = bus_dmamem_map(sc->sc_dmat, &sc->cmd_seg, nsegs, - sizeof (struct ipw_cmd), (caddr_t *)&sc->cmd, BUS_DMA_NOWAIT); - if (error != 0) { - errmsg = "could not map cmd dma memory"; - goto fail; - } - - error = bus_dmamem_alloc(sc->sc_dmat, IPW_RBD_SZ, PAGE_SIZE, 0, - &sc->rbd_seg, 1, &nsegs, BUS_DMA_NOWAIT); - if (error != 0) { - errmsg = "could not allocate rbd dma memory"; - goto fail; - } - - error = bus_dmamem_map(sc->sc_dmat, &sc->rbd_seg, nsegs, IPW_RBD_SZ, - (caddr_t *)&sc->rbd_list, BUS_DMA_NOWAIT); - if (error != 0) { - errmsg = "could not map rbd dma memory"; - goto fail; - } - - error = bus_dmamem_alloc(sc->sc_dmat, IPW_STATUS_SZ, PAGE_SIZE, 0, - &sc->status_seg, 1, &nsegs, BUS_DMA_NOWAIT); - if (error != 0) { - errmsg = "could not allocate status dma memory"; - goto fail; - } - - error = bus_dmamem_map(sc->sc_dmat, &sc->status_seg, nsegs, - IPW_STATUS_SZ, (caddr_t *)&sc->status_list, BUS_DMA_NOWAIT); - if (error != 0) { - errmsg = "could not map status dma memory"; - goto fail; - } - - return 0; - -fail: printf("%s: %s", sc->sc_dev.dv_xname, errmsg); - ipw_dmamem_stop(sc); - - return error; -} - -/* - * Unmap and free DMAble memory. - */ -void -ipw_dmamem_stop(struct ipw_softc *sc) -{ - if (sc->tbd_list != NULL) { - bus_dmamem_unmap(sc->sc_dmat, (caddr_t)sc->tbd_list, - IPW_TBD_SZ); - bus_dmamem_free(sc->sc_dmat, &sc->tbd_seg, 1); - sc->tbd_list = NULL; - } - - if (sc->cmd != NULL) { - bus_dmamem_unmap(sc->sc_dmat, (caddr_t)sc->cmd, - sizeof (struct ipw_cmd)); - bus_dmamem_free(sc->sc_dmat, &sc->cmd_seg, 1); - sc->cmd = NULL; - } - - if (sc->rbd_list != NULL) { - bus_dmamem_unmap(sc->sc_dmat, (caddr_t)sc->rbd_list, - IPW_RBD_SZ); - bus_dmamem_free(sc->sc_dmat, &sc->rbd_seg, 1); - sc->rbd_list = NULL; - } - - if (sc->status_list != NULL) { - bus_dmamem_unmap(sc->sc_dmat, (caddr_t)sc->status_list, - IPW_STATUS_SZ); - bus_dmamem_free(sc->sc_dmat, &sc->status_seg, 1); - sc->status_list = NULL; - } -} - -int -ipw_tx_init(struct ipw_softc *sc) -{ - char *errmsg; - struct ipw_bd *bd; - struct ipw_soft_bd *sbd; - struct ipw_soft_hdr *shdr; - struct ipw_soft_buf *sbuf; - int error, i; - - /* Allocate transmission buffer descriptors */ - error = bus_dmamap_create(sc->sc_dmat, IPW_TBD_SZ, 1, IPW_TBD_SZ, 0, - BUS_DMA_NOWAIT, &sc->tbd_map); - if (error != 0) { - errmsg = "could not create tbd dma map"; - goto fail; - } - - error = bus_dmamap_load(sc->sc_dmat, sc->tbd_map, sc->tbd_list, - IPW_TBD_SZ, NULL, BUS_DMA_NOWAIT); - if (error != 0) { - errmsg = "could not load tbd dma memory"; - goto fail; - } - - sc->stbd_list = malloc(IPW_NTBD * sizeof (struct ipw_soft_bd), - M_DEVBUF, M_NOWAIT); - if (sc->stbd_list == NULL) { - errmsg = "could not allocate soft tbd"; - error = ENOMEM; - goto fail; - } - sbd = sc->stbd_list; - bd = sc->tbd_list; - for (i = 0; i < IPW_NTBD; i++, sbd++, bd++) { - sbd->type = IPW_SBD_TYPE_NOASSOC; - sbd->bd = bd; - } - - CSR_WRITE_4(sc, IPW_CSR_TX_BD_BASE, sc->tbd_map->dm_segs[0].ds_addr); - CSR_WRITE_4(sc, IPW_CSR_TX_BD_SIZE, IPW_NTBD); - CSR_WRITE_4(sc, IPW_CSR_TX_READ_INDEX, 0); - CSR_WRITE_4(sc, IPW_CSR_TX_WRITE_INDEX, 0); - sc->txold = IPW_NTBD - 1; /* latest bd index ack'ed by firmware */ - sc->txcur = 0; /* bd index to write to */ - - /* Allocate a DMA-able command */ - error = bus_dmamap_create(sc->sc_dmat, sizeof (struct ipw_cmd), 1, - sizeof (struct ipw_cmd), 0, BUS_DMA_NOWAIT, &sc->cmd_map); - if (error != 0) { - errmsg = "could not create cmd dma map"; - goto fail; - } - - /* Allocate a pool of DMA-able headers */ - sc->shdr_list = malloc(IPW_NDATA * sizeof (struct ipw_soft_hdr), - M_DEVBUF, M_NOWAIT); - if (sc->shdr_list == NULL) { - errmsg = "could not allocate soft hdr"; - error = ENOMEM; - goto fail; - } - TAILQ_INIT(&sc->sc_free_shdr); - for (i = 0, shdr = sc->shdr_list; i < IPW_NDATA; i++, shdr++) { - error = bus_dmamap_create(sc->sc_dmat, - sizeof (struct ipw_soft_hdr), 1, - sizeof (struct ipw_soft_hdr), 0, BUS_DMA_NOWAIT, - &shdr->map); - if (error != 0) { - errmsg = "could not create hdr dma map"; - goto fail; - } - TAILQ_INSERT_TAIL(&sc->sc_free_shdr, shdr, next); - } - - /* Allocate a pool of DMA-able buffers */ - sc->tx_sbuf_list = malloc(IPW_NDATA * sizeof (struct ipw_soft_buf), - M_DEVBUF, M_NOWAIT); - if (sc->tx_sbuf_list == NULL) { - errmsg = "could not allocate soft txbuf"; - error = ENOMEM; - goto fail; - } - TAILQ_INIT(&sc->sc_free_sbuf); - for (i = 0, sbuf = sc->tx_sbuf_list; i < IPW_NDATA; i++, sbuf++) { - error = bus_dmamap_create(sc->sc_dmat, MCLBYTES, IPW_NDATA, - MCLBYTES, 0, BUS_DMA_NOWAIT, &sbuf->map); - if (error != 0) { - errmsg = "could not create txbuf dma map"; - goto fail; - } - TAILQ_INSERT_TAIL(&sc->sc_free_sbuf, sbuf, next); - } - - return 0; - -fail: printf("%s: %s\n", sc->sc_dev.dv_xname, errmsg); - ipw_tx_stop(sc); - - return error; -} - -void -ipw_tx_stop(struct ipw_softc *sc) -{ - struct ipw_soft_hdr *shdr; - struct ipw_soft_buf *sbuf; - int i; - - if (sc->tbd_map != NULL) { - if (sc->tbd_list != NULL) - bus_dmamap_unload(sc->sc_dmat, sc->tbd_map); - bus_dmamap_destroy(sc->sc_dmat, sc->tbd_map); - sc->tbd_map = NULL; - } - - if (sc->stbd_list != NULL) { - for (i = 0; i < IPW_NTBD; i++) - ipw_release_sbd(sc, &sc->stbd_list[i]); - free(sc->stbd_list, M_DEVBUF); - sc->stbd_list = NULL; - } - - if (sc->cmd_map != NULL) { - bus_dmamap_destroy(sc->sc_dmat, sc->cmd_map); - sc->cmd_map = NULL; - } - - if (sc->shdr_list != NULL) { - TAILQ_FOREACH(shdr, &sc->sc_free_shdr, next) - bus_dmamap_destroy(sc->sc_dmat, shdr->map); - free(sc->shdr_list, M_DEVBUF); - sc->shdr_list = NULL; - } - - if (sc->tx_sbuf_list != NULL) { - TAILQ_FOREACH(sbuf, &sc->sc_free_sbuf, next) - bus_dmamap_destroy(sc->sc_dmat, sbuf->map); - free(sc->tx_sbuf_list, M_DEVBUF); - sc->tx_sbuf_list = NULL; - } -} - -int -ipw_rx_init(struct ipw_softc *sc) -{ - char *errmsg; - struct ipw_bd *bd; - struct ipw_soft_bd *sbd; - struct ipw_soft_buf *sbuf; - int error, i; - - /* Allocate reception buffer descriptors */ - error = bus_dmamap_create(sc->sc_dmat, IPW_RBD_SZ, 1, IPW_RBD_SZ, 0, - BUS_DMA_NOWAIT, &sc->rbd_map); - if (error != 0) { - errmsg = "could not create rbd dma map"; - goto fail; - } - - error = bus_dmamap_load(sc->sc_dmat, sc->rbd_map, sc->rbd_list, - IPW_RBD_SZ, NULL, BUS_DMA_NOWAIT); - if (error != 0) { - errmsg = "could not load rbd dma memory"; - goto fail; - } - - sc->srbd_list = malloc(IPW_NRBD * sizeof (struct ipw_soft_bd), - M_DEVBUF, M_NOWAIT); - if (sc->srbd_list == NULL) { - errmsg = "could not allocate soft rbd"; - error = ENOMEM; - goto fail; - } - sbd = sc->srbd_list; - bd = sc->rbd_list; - for (i = 0; i < IPW_NRBD; i++, sbd++, bd++) { - sbd->type = IPW_SBD_TYPE_NOASSOC; - sbd->bd = bd; - } - - CSR_WRITE_4(sc, IPW_CSR_RX_BD_BASE, sc->rbd_map->dm_segs[0].ds_addr); - CSR_WRITE_4(sc, IPW_CSR_RX_BD_SIZE, IPW_NRBD); - CSR_WRITE_4(sc, IPW_CSR_RX_READ_INDEX, 0); - CSR_WRITE_4(sc, IPW_CSR_RX_WRITE_INDEX, IPW_NRBD - 1); - sc->rxcur = IPW_NRBD - 1; /* latest bd index I've read */ - - /* Allocate status descriptors */ - error = bus_dmamap_create(sc->sc_dmat, IPW_STATUS_SZ, 1, IPW_STATUS_SZ, - 0, BUS_DMA_NOWAIT, &sc->status_map); - if (error != 0) { - errmsg = "could not create status dma map"; - goto fail; - } - - error = bus_dmamap_load(sc->sc_dmat, sc->status_map, sc->status_list, - IPW_STATUS_SZ, NULL, BUS_DMA_NOWAIT); - if (error != 0) { - errmsg = "could not load status dma memory"; - goto fail; - } - - CSR_WRITE_4(sc, IPW_CSR_RX_STATUS_BASE, - sc->status_map->dm_segs[0].ds_addr); - - sc->rx_sbuf_list = malloc(IPW_NRBD * sizeof (struct ipw_soft_buf), - M_DEVBUF, M_NOWAIT); - if (sc->rx_sbuf_list == NULL) { - errmsg = "could not allocate soft rxbuf"; - error = ENOMEM; - goto fail; - } - - sbuf = sc->rx_sbuf_list; - sbd = sc->srbd_list; - for (i = 0; i < IPW_NRBD; i++, sbuf++, sbd++) { - - MGETHDR(sbuf->m, M_DONTWAIT, MT_DATA); - if (sbuf->m == NULL) { - errmsg = "could not allocate rx mbuf"; - error = ENOMEM; - goto fail; - } - MCLGET(sbuf->m, M_DONTWAIT); - if (!(sbuf->m->m_flags & M_EXT)) { - m_freem(sbuf->m); - errmsg = "could not allocate rx mbuf cluster"; - error = ENOMEM; - goto fail; - } - - error = bus_dmamap_create(sc->sc_dmat, MCLBYTES, 1, MCLBYTES, - 0, BUS_DMA_NOWAIT, &sbuf->map); - if (error != 0) { - m_freem(sbuf->m); - errmsg = "could not create rxbuf dma map"; - goto fail; - } - error = bus_dmamap_load(sc->sc_dmat, sbuf->map, - mtod(sbuf->m, void *), MCLBYTES, NULL, BUS_DMA_NOWAIT); - if (error != 0) { - bus_dmamap_destroy(sc->sc_dmat, sbuf->map); - m_freem(sbuf->m); - errmsg = "could not map rxbuf dma memory"; - goto fail; - } - sbd->type = IPW_SBD_TYPE_DATA; - sbd->priv = sbuf; - sbd->bd->physaddr = htole32(sbuf->map->dm_segs[0].ds_addr); - sbd->bd->len = htole32(MCLBYTES); - } - - return 0; - -fail: printf("%s: %s\n", sc->sc_dev.dv_xname, errmsg); - ipw_rx_stop(sc); - - return error; -} - -void -ipw_rx_stop(struct ipw_softc *sc) -{ - struct ipw_soft_bd *sbd; - struct ipw_soft_buf *sbuf; - int i; - - if (sc->rbd_map != NULL) { - if (sc->rbd_list != NULL) - bus_dmamap_unload(sc->sc_dmat, sc->rbd_map); - bus_dmamap_destroy(sc->sc_dmat, sc->rbd_map); - sc->rbd_map = NULL; - } - - if (sc->status_map != NULL) { - if (sc->status_list != NULL) - bus_dmamap_unload(sc->sc_dmat, sc->status_map); - bus_dmamap_destroy(sc->sc_dmat, sc->status_map); - sc->status_map = NULL; - } - - if (sc->srbd_list != NULL) { - for (i = 0, sbd = sc->srbd_list; i < IPW_NRBD; i++, sbd++) { - if (sbd->type == IPW_SBD_TYPE_NOASSOC) - continue; - - sbuf = sbd->priv; - bus_dmamap_unload(sc->sc_dmat, sbuf->map); - bus_dmamap_destroy(sc->sc_dmat, sbuf->map); - m_freem(sbuf->m); - } - free(sc->srbd_list, M_DEVBUF); - sc->srbd_list = NULL; - } - - if (sc->rx_sbuf_list != NULL) { - free(sc->rx_sbuf_list, M_DEVBUF); - sc->rx_sbuf_list = NULL; - } -} - void ipw_stop_master(struct ipw_softc *sc) { @@ -1996,17 +1854,25 @@ ipw_init(struct ifnet *ifp) ipw_stop_master(sc); - if ((error = ipw_rx_init(sc)) != 0) { - printf("%s: could not initialize rx queue\n", - sc->sc_dev.dv_xname); - goto fail2; - } + /* + * Setup tx, rx and status rings + */ + CSR_WRITE_4(sc, IPW_CSR_TX_BD_BASE, sc->tbd_map->dm_segs[0].ds_addr); + CSR_WRITE_4(sc, IPW_CSR_TX_BD_SIZE, IPW_NTBD); + CSR_WRITE_4(sc, IPW_CSR_TX_READ_INDEX, 0); + CSR_WRITE_4(sc, IPW_CSR_TX_WRITE_INDEX, 0); + sc->txold = IPW_NTBD - 1; /* latest bd index ack'ed by firmware */ + sc->txcur = 0; /* bd index to write to */ + sc->txfree = IPW_NTBD - 2; - if ((error = ipw_tx_init(sc)) != 0) { - printf("%s: could not initialize tx queue\n", - sc->sc_dev.dv_xname); - goto fail2; - } + CSR_WRITE_4(sc, IPW_CSR_RX_BD_BASE, sc->rbd_map->dm_segs[0].ds_addr); + CSR_WRITE_4(sc, IPW_CSR_RX_BD_SIZE, IPW_NRBD); + CSR_WRITE_4(sc, IPW_CSR_RX_READ_INDEX, 0); + CSR_WRITE_4(sc, IPW_CSR_RX_WRITE_INDEX, IPW_NRBD - 1); + sc->rxcur = IPW_NRBD - 1; /* latest bd index I've read */ + + CSR_WRITE_4(sc, IPW_CSR_RX_STATUS_BASE, + sc->status_map->dm_segs[0].ds_addr); if ((error = ipw_load_firmware(sc, fw.main, fw.main_size)) != 0) { printf("%s: could not load firmware\n", sc->sc_dev.dv_xname); @@ -2043,12 +1909,16 @@ ipw_stop(struct ifnet *ifp, int disable) { struct ipw_softc *sc = ifp->if_softc; struct ieee80211com *ic = &sc->sc_ic; + int i; ipw_stop_master(sc); CSR_WRITE_4(sc, IPW_CSR_RST, IPW_RST_SW_RESET); - ipw_tx_stop(sc); - ipw_rx_stop(sc); + /* + * Release tx buffers + */ + for (i = 0; i < IPW_NTBD; i++) + ipw_release_sbd(sc, &sc->stbd_list[i]); ifp->if_timer = 0; ifp->if_flags &= ~(IFF_RUNNING | IFF_OACTIVE); diff --git a/sys/dev/pci/if_ipwreg.h b/sys/dev/pci/if_ipwreg.h index 2252fb0c1c5..ec525836c27 100644 --- a/sys/dev/pci/if_ipwreg.h +++ b/sys/dev/pci/if_ipwreg.h @@ -1,4 +1,4 @@ -/* $Id: if_ipwreg.h,v 1.6 2004/10/27 21:22:14 damien Exp $ */ +/* $Id: if_ipwreg.h,v 1.7 2004/12/05 17:46:07 damien Exp $ */ /*- * Copyright (c) 2004 @@ -27,10 +27,10 @@ * SUCH DAMAGE. */ -#define IPW_NTBD 256 +#define IPW_NTBD 128 #define IPW_TBD_SZ (IPW_NTBD * sizeof (struct ipw_bd)) #define IPW_NDATA (IPW_NTBD / 2) -#define IPW_NRBD 256 +#define IPW_NRBD 128 #define IPW_RBD_SZ (IPW_NRBD * sizeof (struct ipw_bd)) #define IPW_STATUS_SZ (IPW_NRBD * sizeof (struct ipw_status)) diff --git a/sys/dev/pci/if_ipwvar.h b/sys/dev/pci/if_ipwvar.h index f389a31bf05..e02759752a4 100644 --- a/sys/dev/pci/if_ipwvar.h +++ b/sys/dev/pci/if_ipwvar.h @@ -1,4 +1,4 @@ -/* $Id: if_ipwvar.h,v 1.4 2004/11/18 21:02:42 damien Exp $ */ +/* $Id: if_ipwvar.h,v 1.5 2004/12/05 17:46:07 damien Exp $ */ /*- * Copyright (c) 2004 @@ -48,14 +48,14 @@ struct ipw_soft_bd { struct ipw_soft_hdr { struct ipw_hdr hdr; bus_dmamap_t map; - TAILQ_ENTRY(ipw_soft_hdr) next; + SLIST_ENTRY(ipw_soft_hdr) next; }; struct ipw_soft_buf { struct mbuf *m; struct ieee80211_node *ni; bus_dmamap_t map; - TAILQ_ENTRY(ipw_soft_buf) next; + SLIST_ENTRY(ipw_soft_buf) next; }; struct ipw_rx_radiotap_header { @@ -82,6 +82,8 @@ struct ipw_tx_radiotap_header { ((1 << IEEE80211_RADIOTAP_FLAGS) | \ (1 << IEEE80211_RADIOTAP_CHANNEL)) +#define IPW_MAX_NSEG 6 + struct ipw_softc { struct device sc_dev; @@ -120,21 +122,22 @@ struct ipw_softc { struct ipw_bd *rbd_list; struct ipw_status *status_list; - struct ipw_cmd *cmd; - struct ipw_soft_bd *stbd_list; - struct ipw_soft_bd *srbd_list; - struct ipw_soft_hdr *shdr_list; - struct ipw_soft_buf *tx_sbuf_list; - struct ipw_soft_buf *rx_sbuf_list; + struct ipw_cmd cmd; + struct ipw_soft_bd stbd_list[IPW_NTBD]; + struct ipw_soft_buf tx_sbuf_list[IPW_NDATA]; + struct ipw_soft_hdr shdr_list[IPW_NDATA]; + struct ipw_soft_bd srbd_list[IPW_NRBD]; + struct ipw_soft_buf rx_sbuf_list[IPW_NRBD]; - TAILQ_HEAD(, ipw_soft_hdr) sc_free_shdr; - TAILQ_HEAD(, ipw_soft_buf) sc_free_sbuf; + SLIST_HEAD(, ipw_soft_hdr) free_shdr; + SLIST_HEAD(, ipw_soft_buf) free_sbuf; u_int32_t table1_base; u_int32_t table2_base; u_int32_t txcur; u_int32_t txold; + u_int32_t txfree; u_int32_t rxcur; #if NBPFILTER > 0 |