diff options
author | Damien Bergamini <damien@cvs.openbsd.org> | 2009-05-12 19:10:58 +0000 |
---|---|---|
committer | Damien Bergamini <damien@cvs.openbsd.org> | 2009-05-12 19:10:58 +0000 |
commit | 713fc07f280e9ec10aa464332ad21f7455bfae4b (patch) | |
tree | 1518ffa3383eb75e3580dc3b9a27f0d52adef350 /sys/dev | |
parent | 9cd2545ee85e9608354e60c0e52cffb59446f3a8 (diff) |
switch wpi(4) and iwn(4) over to MCLGETI.
notice that i'm not using the per-ifp mbuf accounting/mitigation yet.
for iwn(4), this means we wont' be able to support full 8KB AMSDU on
machines without an IOMMU since >4KB clusters are not guaranteed to
be physcontig. fortunately, we can program the hardware to do 4KB
AMSDUs only.
simplify {pwi,iwn}_dma_contig_alloc while i'm here: use BUS_DMA_ZERO
Diffstat (limited to 'sys/dev')
-rw-r--r-- | sys/dev/pci/if_iwn.c | 328 | ||||
-rw-r--r-- | sys/dev/pci/if_iwnvar.h | 18 | ||||
-rw-r--r-- | sys/dev/pci/if_wpi.c | 258 | ||||
-rw-r--r-- | sys/dev/pci/if_wpivar.h | 15 |
4 files changed, 261 insertions, 358 deletions
diff --git a/sys/dev/pci/if_iwn.c b/sys/dev/pci/if_iwn.c index 94e902c7e67..296ca0dd63a 100644 --- a/sys/dev/pci/if_iwn.c +++ b/sys/dev/pci/if_iwn.c @@ -1,4 +1,4 @@ -/* $OpenBSD: if_iwn.c,v 1.52 2009/05/11 19:36:00 damien Exp $ */ +/* $OpenBSD: if_iwn.c,v 1.53 2009/05/12 19:10:57 damien Exp $ */ /*- * Copyright (c) 2007-2009 Damien Bergamini <damien.bergamini@free.fr> @@ -104,7 +104,7 @@ int iwn_nic_lock(struct iwn_softc *); int iwn_eeprom_lock(struct iwn_softc *); int iwn_read_prom_data(struct iwn_softc *, uint32_t, void *, int); int iwn_dma_contig_alloc(bus_dma_tag_t, struct iwn_dma_info *, - void **, bus_size_t, bus_size_t, int); + void **, bus_size_t, bus_size_t); void iwn_dma_contig_free(struct iwn_dma_info *); int iwn_alloc_sched(struct iwn_softc *); void iwn_free_sched(struct iwn_softc *); @@ -112,10 +112,6 @@ int iwn_alloc_kw(struct iwn_softc *); void iwn_free_kw(struct iwn_softc *); int iwn_alloc_fwmem(struct iwn_softc *); void iwn_free_fwmem(struct iwn_softc *); -struct iwn_rbuf *iwn_alloc_rbuf(struct iwn_softc *); -void iwn_free_rbuf(caddr_t, u_int, void *); -int iwn_alloc_rpool(struct iwn_softc *); -void iwn_free_rpool(struct iwn_softc *); int iwn_alloc_rx_ring(struct iwn_softc *, struct iwn_rx_ring *); void iwn_reset_rx_ring(struct iwn_softc *, struct iwn_rx_ring *); void iwn_free_rx_ring(struct iwn_softc *, struct iwn_rx_ring *); @@ -137,14 +133,18 @@ void iwn_iter_func(void *, struct ieee80211_node *); void iwn_calib_timeout(void *); int iwn_ccmp_decap(struct iwn_softc *, struct mbuf *, struct ieee80211_key *); -void iwn_rx_phy(struct iwn_softc *, struct iwn_rx_desc *); +void iwn_rx_phy(struct iwn_softc *, struct iwn_rx_desc *, + struct iwn_rx_data *); void iwn_rx_done(struct iwn_softc *, struct iwn_rx_desc *, struct iwn_rx_data *); void iwn5000_rx_calib_results(struct iwn_softc *, - struct iwn_rx_desc *); -void iwn_rx_statistics(struct iwn_softc *, struct iwn_rx_desc *); -void iwn4965_tx_done(struct iwn_softc *, struct iwn_rx_desc *); -void iwn5000_tx_done(struct iwn_softc *, struct iwn_rx_desc *); + struct iwn_rx_desc *, struct iwn_rx_data *); +void iwn_rx_statistics(struct iwn_softc *, struct iwn_rx_desc *, + struct iwn_rx_data *); +void iwn4965_tx_done(struct iwn_softc *, struct iwn_rx_desc *, + struct iwn_rx_data *); +void iwn5000_tx_done(struct iwn_softc *, struct iwn_rx_desc *, + struct iwn_rx_data *); void iwn_tx_done(struct iwn_softc *, struct iwn_rx_desc *, int, uint8_t); void iwn_cmd_done(struct iwn_softc *, struct iwn_rx_desc *); @@ -416,24 +416,18 @@ iwn_attach(struct device *parent, struct device *self, void *aux) goto fail2; } - /* Allocate RX buffers. */ - if ((error = iwn_alloc_rpool(sc)) != 0) { - printf(": could not allocate RX buffers\n"); - goto fail3; - } - /* Allocate TX rings (16 on 4965AGN, 20 on 5000.) */ for (i = 0; i < hal->ntxqs; i++) { if ((error = iwn_alloc_tx_ring(sc, &sc->txq[i], i)) != 0) { printf(": could not allocate TX ring %d\n", i); - goto fail4; + goto fail3; } } /* Allocate RX ring. */ if ((error = iwn_alloc_rx_ring(sc, &sc->rxq)) != 0) { printf(": could not allocate RX ring\n"); - goto fail4; + goto fail3; } /* Power OFF adapter. */ @@ -515,10 +509,9 @@ iwn_attach(struct device *parent, struct device *self, void *aux) return; /* Free allocated memory if something failed during attachment. */ -fail4: while (--i >= 0) +fail3: while (--i >= 0) iwn_free_tx_ring(sc, &sc->txq[i]); - iwn_free_rpool(sc); -fail3: iwn_free_sched(sc); + iwn_free_sched(sc); fail2: iwn_free_kw(sc); fail1: iwn_free_fwmem(sc); } @@ -821,31 +814,33 @@ iwn_read_prom_data(struct iwn_softc *sc, uint32_t addr, void *data, int count) int iwn_dma_contig_alloc(bus_dma_tag_t tag, struct iwn_dma_info *dma, void **kvap, - bus_size_t size, bus_size_t alignment, int flags) + bus_size_t size, bus_size_t alignment) { int nsegs, error; dma->tag = tag; dma->size = size; - error = bus_dmamap_create(tag, size, 1, size, 0, flags, &dma->map); + error = bus_dmamap_create(tag, size, 1, size, 0, BUS_DMA_NOWAIT, + &dma->map); if (error != 0) goto fail; error = bus_dmamem_alloc(tag, size, alignment, 0, &dma->seg, 1, &nsegs, - flags); + BUS_DMA_NOWAIT | BUS_DMA_ZERO); if (error != 0) goto fail; - error = bus_dmamem_map(tag, &dma->seg, 1, size, &dma->vaddr, flags); + error = bus_dmamem_map(tag, &dma->seg, 1, size, &dma->vaddr, + BUS_DMA_NOWAIT); if (error != 0) goto fail; - error = bus_dmamap_load_raw(tag, dma->map, &dma->seg, 1, size, flags); + error = bus_dmamap_load_raw(tag, dma->map, &dma->seg, 1, size, + BUS_DMA_NOWAIT); if (error != 0) goto fail; - memset(dma->vaddr, 0, size); bus_dmamap_sync(tag, dma->map, 0, size, BUS_DMASYNC_PREWRITE); dma->paddr = dma->map->dm_segs[0].ds_addr; @@ -880,7 +875,7 @@ iwn_alloc_sched(struct iwn_softc *sc) { /* TX scheduler rings must be aligned on a 1KB boundary. */ return iwn_dma_contig_alloc(sc->sc_dmat, &sc->sched_dma, - (void **)&sc->sched, sc->sc_hal->schedsz, 1024, BUS_DMA_NOWAIT); + (void **)&sc->sched, sc->sc_hal->schedsz, 1024); } void @@ -894,7 +889,7 @@ iwn_alloc_kw(struct iwn_softc *sc) { /* "Keep Warm" page must be aligned on a 4KB boundary. */ return iwn_dma_contig_alloc(sc->sc_dmat, &sc->kw_dma, NULL, 4096, - 4096, BUS_DMA_NOWAIT); + 4096); } void @@ -908,7 +903,7 @@ iwn_alloc_fwmem(struct iwn_softc *sc) { /* Must be aligned on a 16-byte boundary. */ return iwn_dma_contig_alloc(sc->sc_dmat, &sc->fw_dma, NULL, - sc->sc_hal->fwsz, 16, BUS_DMA_NOWAIT); + sc->sc_hal->fwsz, 16); } void @@ -917,66 +912,6 @@ iwn_free_fwmem(struct iwn_softc *sc) iwn_dma_contig_free(&sc->fw_dma); } -struct iwn_rbuf * -iwn_alloc_rbuf(struct iwn_softc *sc) -{ - struct iwn_rbuf *rbuf; - - rbuf = SLIST_FIRST(&sc->rxq.freelist); - if (rbuf == NULL) - return NULL; - SLIST_REMOVE_HEAD(&sc->rxq.freelist, next); - return rbuf; -} - -/* - * This is called automatically by the network stack when the mbuf to which - * our RX buffer is attached is freed. - */ -void -iwn_free_rbuf(caddr_t buf, u_int size, void *arg) -{ - struct iwn_rbuf *rbuf = arg; - struct iwn_softc *sc = rbuf->sc; - - /* Put the RX buffer back in the free list. */ - SLIST_INSERT_HEAD(&sc->rxq.freelist, rbuf, next); -} - -int -iwn_alloc_rpool(struct iwn_softc *sc) -{ - struct iwn_rx_ring *ring = &sc->rxq; - int i, error; - - /* Allocate a big chunk of DMA'able memory... */ - error = iwn_dma_contig_alloc(sc->sc_dmat, &ring->buf_dma, NULL, - IWN_RBUF_COUNT * IWN_RBUF_SIZE, 4096, BUS_DMA_NOWAIT); - if (error != 0) { - printf("%s: could not allocate RX buffers DMA memory\n", - sc->sc_dev.dv_xname); - return error; - } - /* ...and split it into chunks of IWN_RBUF_SIZE bytes. */ - SLIST_INIT(&ring->freelist); - for (i = 0; i < IWN_RBUF_COUNT; i++) { - struct iwn_rbuf *rbuf = &ring->rbuf[i]; - - rbuf->sc = sc; /* Backpointer for callbacks. */ - rbuf->vaddr = ring->buf_dma.vaddr + i * IWN_RBUF_SIZE; - rbuf->paddr = ring->buf_dma.paddr + i * IWN_RBUF_SIZE; - - SLIST_INSERT_HEAD(&ring->freelist, rbuf, next); - } - return 0; -} - -void -iwn_free_rpool(struct iwn_softc *sc) -{ - iwn_dma_contig_free(&sc->rxq.buf_dma); -} - int iwn_alloc_rx_ring(struct iwn_softc *sc, struct iwn_rx_ring *ring) { @@ -988,7 +923,7 @@ iwn_alloc_rx_ring(struct iwn_softc *sc, struct iwn_rx_ring *ring) /* Allocate RX descriptors (256-byte aligned.) */ size = IWN_RX_RING_COUNT * sizeof (uint32_t); error = iwn_dma_contig_alloc(sc->sc_dmat, &ring->desc_dma, - (void **)&ring->desc, size, 256, BUS_DMA_NOWAIT); + (void **)&ring->desc, size, 256); if (error != 0) { printf("%s: could not allocate RX ring DMA memory\n", sc->sc_dev.dv_xname); @@ -997,8 +932,7 @@ iwn_alloc_rx_ring(struct iwn_softc *sc, struct iwn_rx_ring *ring) /* Allocate RX status area (16-byte aligned.) */ error = iwn_dma_contig_alloc(sc->sc_dmat, &ring->stat_dma, - (void **)&ring->stat, sizeof (struct iwn_rx_status), 16, - BUS_DMA_NOWAIT); + (void **)&ring->stat, sizeof (struct iwn_rx_status), 16); if (error != 0) { printf("%s: could not allocate RX status DMA memory\n", sc->sc_dev.dv_xname); @@ -1006,11 +940,18 @@ iwn_alloc_rx_ring(struct iwn_softc *sc, struct iwn_rx_ring *ring) } /* - * Allocate RX buffers. + * Allocate and map RX buffers. */ for (i = 0; i < IWN_RX_RING_COUNT; i++) { struct iwn_rx_data *data = &ring->data[i]; - struct iwn_rbuf *rbuf; + + error = bus_dmamap_create(sc->sc_dmat, IWN_RBUF_SIZE, 1, + IWN_RBUF_SIZE, 0, BUS_DMA_NOWAIT, &data->map); + if (error != 0) { + printf("%s: could not create RX buf DMA map\n", + sc->sc_dev.dv_xname); + goto fail; + } MGETHDR(data->m, M_DONTWAIT, MT_DATA); if (data->m == NULL) { @@ -1019,24 +960,29 @@ iwn_alloc_rx_ring(struct iwn_softc *sc, struct iwn_rx_ring *ring) error = ENOMEM; goto fail; } - if ((rbuf = iwn_alloc_rbuf(sc)) == NULL) { - m_freem(data->m); - data->m = NULL; - printf("%s: could not allocate RX buffer\n", + MCLGETI(data->m, M_DONTWAIT, NULL, IWN_RBUF_SIZE); + if (!(data->m->m_flags & M_EXT)) { + printf("%s: could not allocate RX mbuf cluster\n", sc->sc_dev.dv_xname); - error = ENOMEM; + error = ENOBUFS; + goto fail; + } + + error = bus_dmamap_load(sc->sc_dmat, data->map, + mtod(data->m, void *), IWN_RBUF_SIZE, NULL, + BUS_DMA_NOWAIT); + if (error != 0) { + printf("%s: can't not map mbuf (error %d)\n", + sc->sc_dev.dv_xname, error); goto fail; } - /* Attach RX buffer to mbuf header. */ - MEXTADD(data->m, rbuf->vaddr, IWN_RBUF_SIZE, 0, iwn_free_rbuf, - rbuf); /* Set physical address of RX buffer (256-byte aligned.) */ - ring->desc[i] = htole32(rbuf->paddr >> 8); + ring->desc[i] = htole32(data->map->dm_segs[0].ds_addr >> 8); } - bus_dmamap_sync(sc->sc_dmat, ring->desc_dma.map, - 0, ring->desc_dma.size, BUS_DMASYNC_PREWRITE); + bus_dmamap_sync(sc->sc_dmat, ring->desc_dma.map, 0, size, + BUS_DMASYNC_PREWRITE); return 0; @@ -1072,8 +1018,16 @@ iwn_free_rx_ring(struct iwn_softc *sc, struct iwn_rx_ring *ring) iwn_dma_contig_free(&ring->stat_dma); for (i = 0; i < IWN_RX_RING_COUNT; i++) { - if (ring->data[i].m != NULL) - m_freem(ring->data[i].m); + struct iwn_rx_data *data = &ring->data[i]; + + if (data->m != NULL) { + bus_dmamap_sync(sc->sc_dmat, data->map, 0, + data->map->dm_mapsize, BUS_DMASYNC_POSTREAD); + bus_dmamap_unload(sc->sc_dmat, data->map); + m_freem(data->m); + } + if (data->map != NULL) + bus_dmamap_destroy(sc->sc_dmat, data->map); } } @@ -1091,7 +1045,7 @@ iwn_alloc_tx_ring(struct iwn_softc *sc, struct iwn_tx_ring *ring, int qid) /* Allocate TX descriptors (256-byte aligned.) */ size = IWN_TX_RING_COUNT * sizeof (struct iwn_tx_desc); error = iwn_dma_contig_alloc(sc->sc_dmat, &ring->desc_dma, - (void **)&ring->desc, size, 256, BUS_DMA_NOWAIT); + (void **)&ring->desc, size, 256); if (error != 0) { printf("%s: could not allocate TX ring DMA memory\n", sc->sc_dev.dv_xname); @@ -1107,7 +1061,7 @@ iwn_alloc_tx_ring(struct iwn_softc *sc, struct iwn_tx_ring *ring, int qid) size = IWN_TX_RING_COUNT * sizeof (struct iwn_tx_cmd); error = iwn_dma_contig_alloc(sc->sc_dmat, &ring->cmd_dma, - (void **)&ring->cmd, size, 4, BUS_DMA_NOWAIT); + (void **)&ring->cmd, size, 4); if (error != 0) { printf("%s: could not allocate TX cmd DMA memory\n", sc->sc_dev.dv_xname); @@ -1610,14 +1564,14 @@ iwn_ccmp_decap(struct iwn_softc *sc, struct mbuf *m, struct ieee80211_key *k) * followed by an MPDU_RX_DONE notification. */ void -iwn_rx_phy(struct iwn_softc *sc, struct iwn_rx_desc *desc) +iwn_rx_phy(struct iwn_softc *sc, struct iwn_rx_desc *desc, + struct iwn_rx_data *data) { struct iwn_rx_stat *stat = (struct iwn_rx_stat *)(desc + 1); DPRINTFN(2, ("received PHY stats\n")); - bus_dmamap_sync(sc->sc_dmat, sc->rxq.buf_dma.map, - (caddr_t)stat - sc->rxq.buf_dma.vaddr, sizeof (*stat), - BUS_DMASYNC_POSTREAD); + bus_dmamap_sync(sc->sc_dmat, data->map, sizeof (*desc), + sizeof (*stat), BUS_DMASYNC_POSTREAD); /* Save RX statistics, they will be used on MPDU_RX_DONE. */ memcpy(&sc->last_rx_stat, stat, sizeof (*stat)); @@ -1636,7 +1590,6 @@ iwn_rx_done(struct iwn_softc *sc, struct iwn_rx_desc *desc, struct ieee80211com *ic = &sc->sc_ic; struct ifnet *ifp = &ic->ic_if; struct iwn_rx_ring *ring = &sc->rxq; - struct iwn_rbuf *rbuf; struct ieee80211_frame *wh; struct ieee80211_rxinfo rxi; struct ieee80211_node *ni; @@ -1644,7 +1597,7 @@ iwn_rx_done(struct iwn_softc *sc, struct iwn_rx_desc *desc, struct iwn_rx_stat *stat; caddr_t head; uint32_t flags; - int len, rssi; + int error, len, rssi; if (desc->type == IWN_MPDU_RX_DONE) { /* Check for prior RX_PHY notification. */ @@ -1658,8 +1611,7 @@ iwn_rx_done(struct iwn_softc *sc, struct iwn_rx_desc *desc, } else stat = (struct iwn_rx_stat *)(desc + 1); - bus_dmamap_sync(sc->sc_dmat, ring->buf_dma.map, - (caddr_t)(desc + 1) - ring->buf_dma.vaddr, IWN_RBUF_SIZE, + bus_dmamap_sync(sc->sc_dmat, data->map, 0, IWN_RBUF_SIZE, BUS_DMASYNC_POSTREAD); if (stat->cfg_phy_len > IWN_STAT_MAXLEN) { @@ -1669,8 +1621,7 @@ iwn_rx_done(struct iwn_softc *sc, struct iwn_rx_desc *desc, return; } if (desc->type == IWN_MPDU_RX_DONE) { - struct iwn_rx_mpdu *mpdu = - (struct iwn_rx_mpdu *)(desc + 1); + struct iwn_rx_mpdu *mpdu = (struct iwn_rx_mpdu *)(desc + 1); head = (caddr_t)(mpdu + 1); len = letoh16(mpdu->len); } else { @@ -1687,14 +1638,58 @@ iwn_rx_done(struct iwn_softc *sc, struct iwn_rx_desc *desc, return; } /* Discard frames that are too short. */ - if (len < sizeof (struct ieee80211_frame)) { + if (len < sizeof (*wh)) { DPRINTF(("frame too short: %d\n", len)); ic->ic_stats.is_rx_tooshort++; ifp->if_ierrors++; return; } + MGETHDR(m1, M_DONTWAIT, MT_DATA); + if (m1 == NULL) { + ic->ic_stats.is_rx_nombuf++; + ifp->if_ierrors++; + return; + } + MCLGETI(m1, M_DONTWAIT, NULL, IWN_RBUF_SIZE); + if (!(m1->m_flags & M_EXT)) { + m_freem(m1); + ic->ic_stats.is_rx_nombuf++; + ifp->if_ierrors++; + return; + } + bus_dmamap_unload(sc->sc_dmat, data->map); + + error = bus_dmamap_load(sc->sc_dmat, data->map, mtod(m1, void *), + IWN_RBUF_SIZE, NULL, BUS_DMA_NOWAIT); + if (error != 0) { + m_freem(m1); + + /* Try to reload the old mbuf. */ + error = bus_dmamap_load(sc->sc_dmat, data->map, + mtod(data->m, void *), IWN_RBUF_SIZE, NULL, + BUS_DMA_NOWAIT); + if (error != 0) { + panic("%s: could not load old RX mbuf", + sc->sc_dev.dv_xname); + } + /* Physical address may have changed. */ + ring->desc[ring->cur] = + htole32(data->map->dm_segs[0].ds_addr >> 8); + bus_dmamap_sync(sc->sc_dmat, ring->desc_dma.map, + ring->cur * sizeof (uint32_t), sizeof (uint32_t), + BUS_DMASYNC_PREWRITE); + ifp->if_ierrors++; + return; + } + m = data->m; + data->m = m1; + /* Update RX descriptor. */ + ring->desc[ring->cur] = htole32(data->map->dm_segs[0].ds_addr >> 8); + bus_dmamap_sync(sc->sc_dmat, ring->desc_dma.map, + ring->cur * sizeof (uint32_t), sizeof (uint32_t), + BUS_DMASYNC_PREWRITE); /* Finalize mbuf. */ m->m_pkthdr.rcvif = ifp; @@ -1733,36 +1728,6 @@ iwn_rx_done(struct iwn_softc *sc, struct iwn_rx_desc *desc, rxi.rxi_flags |= IEEE80211_RXI_HWDEC; } - if ((rbuf = SLIST_FIRST(&sc->rxq.freelist)) != NULL) { - MGETHDR(m1, M_DONTWAIT, MT_DATA); - if (m1 == NULL) { - ic->ic_stats.is_rx_nombuf++; - ifp->if_ierrors++; - return; - } - /* Attach RX buffer to mbuf header. */ - MEXTADD(m1, rbuf->vaddr, IWN_RBUF_SIZE, 0, iwn_free_rbuf, - rbuf); - SLIST_REMOVE_HEAD(&sc->rxq.freelist, next); - - data->m = m1; - - /* Update RX descriptor. */ - ring->desc[ring->cur] = htole32(rbuf->paddr >> 8); - bus_dmamap_sync(sc->sc_dmat, ring->desc_dma.map, - ring->cur * sizeof (uint32_t), sizeof (uint32_t), - BUS_DMASYNC_PREWRITE); - } else { - /* No free rbufs, copy frame into an mbuf. */ - m = m_copym2(m, 0, M_COPYALL, M_DONTWAIT); - if (m == NULL) { - /* No free mbufs either, drop frame. */ - ic->ic_stats.is_rx_nombuf++; - ifp->if_ierrors++; - return; - } - } - rssi = hal->get_rssi(stat); #if NBPFILTER > 0 @@ -1823,7 +1788,8 @@ iwn_rx_done(struct iwn_softc *sc, struct iwn_rx_desc *desc, * firmware on response to a CMD_CALIB_CONFIG command (5000 only.) */ void -iwn5000_rx_calib_results(struct iwn_softc *sc, struct iwn_rx_desc *desc) +iwn5000_rx_calib_results(struct iwn_softc *sc, struct iwn_rx_desc *desc, + struct iwn_rx_data *data) { struct iwn_phy_calib *calib = (struct iwn_phy_calib *)(desc + 1); int len, idx = -1; @@ -1833,8 +1799,7 @@ iwn5000_rx_calib_results(struct iwn_softc *sc, struct iwn_rx_desc *desc) return; len = (letoh32(desc->len) & 0x3fff) - 4; - bus_dmamap_sync(sc->sc_dmat, sc->rxq.buf_dma.map, - (caddr_t)calib - sc->rxq.buf_dma.vaddr, len, + bus_dmamap_sync(sc->sc_dmat, data->map, sizeof (*desc), len, BUS_DMASYNC_POSTREAD); switch (calib->code) { @@ -1879,7 +1844,8 @@ iwn5000_rx_calib_results(struct iwn_softc *sc, struct iwn_rx_desc *desc) * The latter is sent by the firmware after each received beacon. */ void -iwn_rx_statistics(struct iwn_softc *sc, struct iwn_rx_desc *desc) +iwn_rx_statistics(struct iwn_softc *sc, struct iwn_rx_desc *desc, + struct iwn_rx_data *data) { const struct iwn_hal *hal = sc->sc_hal; struct ieee80211com *ic = &sc->sc_ic; @@ -1891,9 +1857,8 @@ iwn_rx_statistics(struct iwn_softc *sc, struct iwn_rx_desc *desc) if (ic->ic_state != IEEE80211_S_RUN) return; - bus_dmamap_sync(sc->sc_dmat, sc->rxq.buf_dma.map, - (caddr_t)stats - sc->rxq.buf_dma.vaddr, sizeof (*stats), - BUS_DMASYNC_POSTREAD); + bus_dmamap_sync(sc->sc_dmat, data->map, sizeof (*desc), + sizeof (*stats), BUS_DMASYNC_POSTREAD); DPRINTFN(3, ("received statistics (cmd=%d)\n", desc->type)); sc->calib_cnt = 0; /* Reset TX power calibration timeout. */ @@ -1936,27 +1901,27 @@ iwn_rx_statistics(struct iwn_softc *sc, struct iwn_rx_desc *desc) * and 5000 adapters have different incompatible TX status formats. */ void -iwn4965_tx_done(struct iwn_softc *sc, struct iwn_rx_desc *desc) +iwn4965_tx_done(struct iwn_softc *sc, struct iwn_rx_desc *desc, + struct iwn_rx_data *data) { struct iwn4965_tx_stat *stat = (struct iwn4965_tx_stat *)(desc + 1); - bus_dmamap_sync(sc->sc_dmat, sc->rxq.buf_dma.map, - (caddr_t)stat - sc->rxq.buf_dma.vaddr, sizeof (*stat), - BUS_DMASYNC_POSTREAD); + bus_dmamap_sync(sc->sc_dmat, data->map, sizeof (*desc), + sizeof (*stat), BUS_DMASYNC_POSTREAD); iwn_tx_done(sc, desc, stat->retrycnt, letoh32(stat->status) & 0xff); } void -iwn5000_tx_done(struct iwn_softc *sc, struct iwn_rx_desc *desc) +iwn5000_tx_done(struct iwn_softc *sc, struct iwn_rx_desc *desc, + struct iwn_rx_data *data) { struct iwn5000_tx_stat *stat = (struct iwn5000_tx_stat *)(desc + 1); /* Reset TX scheduler slot. */ iwn5000_reset_sched(sc, desc->qid & 0xf, desc->idx); - bus_dmamap_sync(sc->sc_dmat, sc->rxq.buf_dma.map, - (caddr_t)stat - sc->rxq.buf_dma.vaddr, sizeof (*stat), - BUS_DMASYNC_POSTREAD); + bus_dmamap_sync(sc->sc_dmat, data->map, sizeof (*desc), + sizeof (*stat), BUS_DMASYNC_POSTREAD); iwn_tx_done(sc, desc, stat->retrycnt, letoh16(stat->status) & 0xff); } @@ -2044,11 +2009,11 @@ iwn_notif_intr(struct iwn_softc *sc) hw = letoh16(sc->rxq.stat->closed_count) & 0xfff; while (sc->rxq.cur != hw) { struct iwn_rx_data *data = &sc->rxq.data[sc->rxq.cur]; - struct iwn_rx_desc *desc = (void *)data->m->m_ext.ext_buf; + struct iwn_rx_desc *desc; - bus_dmamap_sync(sc->sc_dmat, sc->rxq.buf_dma.map, - (caddr_t)desc - sc->rxq.buf_dma.vaddr, sizeof (*desc), + bus_dmamap_sync(sc->sc_dmat, data->map, 0, sizeof (*desc), BUS_DMASYNC_POSTREAD); + desc = mtod(data->m, struct iwn_rx_desc *); DPRINTFN(4, ("notification qid=%d idx=%d flags=%x type=%d\n", desc->qid & 0xf, desc->idx, desc->flags, desc->type)); @@ -2058,7 +2023,7 @@ iwn_notif_intr(struct iwn_softc *sc) switch (desc->type) { case IWN_RX_PHY: - iwn_rx_phy(sc, desc); + iwn_rx_phy(sc, desc, data); break; case IWN_RX_DONE: /* 4965AGN only. */ @@ -2069,12 +2034,12 @@ iwn_notif_intr(struct iwn_softc *sc) case IWN_TX_DONE: /* An 802.11 frame has been transmitted. */ - sc->sc_hal->tx_done(sc, desc); + sc->sc_hal->tx_done(sc, desc, data); break; case IWN_RX_STATISTICS: case IWN_BEACON_STATISTICS: - iwn_rx_statistics(sc, desc); + iwn_rx_statistics(sc, desc, data); break; case IWN_BEACON_MISSED: @@ -2082,8 +2047,7 @@ iwn_notif_intr(struct iwn_softc *sc) struct iwn_beacon_missed *miss = (struct iwn_beacon_missed *)(desc + 1); - bus_dmamap_sync(sc->sc_dmat, sc->rxq.buf_dma.map, - (caddr_t)miss - sc->rxq.buf_dma.vaddr, + bus_dmamap_sync(sc->sc_dmat, data->map, sizeof (*desc), sizeof (*miss), BUS_DMASYNC_POSTREAD); /* * If more than 5 consecutive beacons are missed, @@ -2102,8 +2066,7 @@ iwn_notif_intr(struct iwn_softc *sc) (struct iwn_ucode_info *)(desc + 1); /* The microcontroller is ready. */ - bus_dmamap_sync(sc->sc_dmat, sc->rxq.buf_dma.map, - (caddr_t)uc - sc->rxq.buf_dma.vaddr, + bus_dmamap_sync(sc->sc_dmat, data->map, sizeof (*desc), sizeof (*uc), BUS_DMASYNC_POSTREAD); DPRINTF(("microcode alive notification version=%d.%d " "subtype=%x alive=%x\n", uc->major, uc->minor, @@ -2127,8 +2090,7 @@ iwn_notif_intr(struct iwn_softc *sc) uint32_t *status = (uint32_t *)(desc + 1); /* Enabled/disabled notification. */ - bus_dmamap_sync(sc->sc_dmat, sc->rxq.buf_dma.map, - (caddr_t)status - sc->rxq.buf_dma.vaddr, + bus_dmamap_sync(sc->sc_dmat, data->map, sizeof (*desc), sizeof (*status), BUS_DMASYNC_POSTREAD); DPRINTF(("state changed to %x\n", letoh32(*status))); @@ -2148,8 +2110,7 @@ iwn_notif_intr(struct iwn_softc *sc) struct iwn_start_scan *scan = (struct iwn_start_scan *)(desc + 1); - bus_dmamap_sync(sc->sc_dmat, sc->rxq.buf_dma.map, - (caddr_t)scan - sc->rxq.buf_dma.vaddr, + bus_dmamap_sync(sc->sc_dmat, data->map, sizeof (*desc), sizeof (*scan), BUS_DMASYNC_POSTREAD); DPRINTFN(2, ("scanning channel %d status %x\n", scan->chan, letoh32(scan->status))); @@ -2163,8 +2124,7 @@ iwn_notif_intr(struct iwn_softc *sc) struct iwn_stop_scan *scan = (struct iwn_stop_scan *)(desc + 1); - bus_dmamap_sync(sc->sc_dmat, sc->rxq.buf_dma.map, - (caddr_t)scan - sc->rxq.buf_dma.vaddr, + bus_dmamap_sync(sc->sc_dmat, data->map, sizeof (*desc), sizeof (*scan), BUS_DMASYNC_POSTREAD); DPRINTF(("scan finished nchan=%d status=%d chan=%d\n", scan->nchan, scan->status, scan->chan)); @@ -2182,7 +2142,7 @@ iwn_notif_intr(struct iwn_softc *sc) break; } case IWN5000_CALIBRATION_RESULT: - iwn5000_rx_calib_results(sc, desc); + iwn5000_rx_calib_results(sc, desc, data); break; case IWN5000_CALIBRATION_DONE: diff --git a/sys/dev/pci/if_iwnvar.h b/sys/dev/pci/if_iwnvar.h index 1fef43daddc..827b17ee693 100644 --- a/sys/dev/pci/if_iwnvar.h +++ b/sys/dev/pci/if_iwnvar.h @@ -1,4 +1,4 @@ -/* $OpenBSD: if_iwnvar.h,v 1.9 2009/02/15 08:58:22 damien Exp $ */ +/* $OpenBSD: if_iwnvar.h,v 1.10 2009/05/12 19:10:57 damien Exp $ */ /*- * Copyright (c) 2007, 2008 @@ -79,30 +79,19 @@ struct iwn_tx_ring { int cur; }; -#define IWN_RBUF_COUNT (IWN_RX_RING_COUNT + 32) - struct iwn_softc; -struct iwn_rbuf { - struct iwn_softc *sc; - caddr_t vaddr; - bus_addr_t paddr; - SLIST_ENTRY(iwn_rbuf) next; -}; - struct iwn_rx_data { struct mbuf *m; + bus_dmamap_t map; }; struct iwn_rx_ring { struct iwn_dma_info desc_dma; struct iwn_dma_info stat_dma; - struct iwn_dma_info buf_dma; uint32_t *desc; struct iwn_rx_status *stat; struct iwn_rx_data data[IWN_RX_RING_COUNT]; - struct iwn_rbuf rbuf[IWN_RBUF_COUNT]; - SLIST_HEAD(, iwn_rbuf) freelist; int cur; }; @@ -181,7 +170,8 @@ struct iwn_hal { int (*set_gains)(struct iwn_softc *); int (*add_node)(struct iwn_softc *, struct iwn_node_info *, int); - void (*tx_done)(struct iwn_softc *, struct iwn_rx_desc *); + void (*tx_done)(struct iwn_softc *, struct iwn_rx_desc *, + struct iwn_rx_data *); #ifndef IEEE80211_NO_HT void (*ampdu_tx_start)(struct iwn_softc *, struct ieee80211_node *, uint8_t, uint16_t); diff --git a/sys/dev/pci/if_wpi.c b/sys/dev/pci/if_wpi.c index b4f774cd94e..307cd95563c 100644 --- a/sys/dev/pci/if_wpi.c +++ b/sys/dev/pci/if_wpi.c @@ -1,4 +1,4 @@ -/* $OpenBSD: if_wpi.c,v 1.85 2009/04/26 02:20:58 cnst Exp $ */ +/* $OpenBSD: if_wpi.c,v 1.86 2009/05/12 19:10:57 damien Exp $ */ /*- * Copyright (c) 2006-2008 @@ -82,16 +82,12 @@ void wpi_power(int, void *); int wpi_nic_lock(struct wpi_softc *); int wpi_read_prom_data(struct wpi_softc *, uint32_t, void *, int); int wpi_dma_contig_alloc(bus_dma_tag_t, struct wpi_dma_info *, - void **, bus_size_t, bus_size_t, int); + void **, bus_size_t, bus_size_t); void wpi_dma_contig_free(struct wpi_dma_info *); int wpi_alloc_shared(struct wpi_softc *); void wpi_free_shared(struct wpi_softc *); int wpi_alloc_fwmem(struct wpi_softc *); void wpi_free_fwmem(struct wpi_softc *); -struct wpi_rbuf *wpi_alloc_rbuf(struct wpi_softc *); -void wpi_free_rbuf(caddr_t, u_int, void *); -int wpi_alloc_rpool(struct wpi_softc *); -void wpi_free_rpool(struct wpi_softc *); int wpi_alloc_rx_ring(struct wpi_softc *, struct wpi_rx_ring *); void wpi_reset_rx_ring(struct wpi_softc *, struct wpi_rx_ring *); void wpi_free_rx_ring(struct wpi_softc *, struct wpi_rx_ring *); @@ -260,24 +256,18 @@ wpi_attach(struct device *parent, struct device *self, void *aux) goto fail1; } - /* Allocate RX buffers. */ - if ((error = wpi_alloc_rpool(sc)) != 0) { - printf(": could not allocate RX buffers\n"); - goto fail2; - } - /* Allocate TX rings. */ for (i = 0; i < WPI_NTXQUEUES; i++) { if ((error = wpi_alloc_tx_ring(sc, &sc->txq[i], i)) != 0) { printf(": could not allocate TX ring %d\n", i); - goto fail3; + goto fail2; } } /* Allocate RX ring. */ if ((error = wpi_alloc_rx_ring(sc, &sc->rxq)) != 0) { printf(": could not allocate Rx ring\n"); - goto fail3; + goto fail2; } /* Power OFF adapter. */ @@ -347,10 +337,9 @@ wpi_attach(struct device *parent, struct device *self, void *aux) return; /* Free allocated memory if something failed during attachment. */ -fail3: while (--i >= 0) +fail2: while (--i >= 0) wpi_free_tx_ring(sc, &sc->txq[i]); - wpi_free_rpool(sc); -fail2: wpi_free_shared(sc); + wpi_free_shared(sc); fail1: wpi_free_fwmem(sc); } @@ -536,31 +525,33 @@ wpi_read_prom_data(struct wpi_softc *sc, uint32_t addr, void *data, int count) int wpi_dma_contig_alloc(bus_dma_tag_t tag, struct wpi_dma_info *dma, void **kvap, - bus_size_t size, bus_size_t alignment, int flags) + bus_size_t size, bus_size_t alignment) { int nsegs, error; dma->tag = tag; dma->size = size; - error = bus_dmamap_create(tag, size, 1, size, 0, flags, &dma->map); + error = bus_dmamap_create(tag, size, 1, size, 0, BUS_DMA_NOWAIT, + &dma->map); if (error != 0) goto fail; error = bus_dmamem_alloc(tag, size, alignment, 0, &dma->seg, 1, &nsegs, - flags); + BUS_DMA_NOWAIT | BUS_DMA_ZERO); if (error != 0) goto fail; - error = bus_dmamem_map(tag, &dma->seg, 1, size, &dma->vaddr, flags); + error = bus_dmamem_map(tag, &dma->seg, 1, size, &dma->vaddr, + BUS_DMA_NOWAIT); if (error != 0) goto fail; - error = bus_dmamap_load_raw(tag, dma->map, &dma->seg, 1, size, flags); + error = bus_dmamap_load_raw(tag, dma->map, &dma->seg, 1, size, + BUS_DMA_NOWAIT); if (error != 0) goto fail; - memset(dma->vaddr, 0, size); bus_dmamap_sync(tag, dma->map, 0, size, BUS_DMASYNC_PREWRITE); dma->paddr = dma->map->dm_segs[0].ds_addr; @@ -595,8 +586,7 @@ wpi_alloc_shared(struct wpi_softc *sc) { /* Shared buffer must be aligned on a 4KB boundary. */ return wpi_dma_contig_alloc(sc->sc_dmat, &sc->shared_dma, - (void **)&sc->shared, sizeof (struct wpi_shared), 4096, - BUS_DMA_NOWAIT); + (void **)&sc->shared, sizeof (struct wpi_shared), 4096); } void @@ -610,7 +600,7 @@ wpi_alloc_fwmem(struct wpi_softc *sc) { /* Allocate enough contiguous space to store text and data. */ return wpi_dma_contig_alloc(sc->sc_dmat, &sc->fw_dma, NULL, - WPI_FW_TEXT_MAXSZ + WPI_FW_DATA_MAXSZ, 16, BUS_DMA_NOWAIT); + WPI_FW_TEXT_MAXSZ + WPI_FW_DATA_MAXSZ, 16); } void @@ -619,67 +609,6 @@ wpi_free_fwmem(struct wpi_softc *sc) wpi_dma_contig_free(&sc->fw_dma); } -struct wpi_rbuf * -wpi_alloc_rbuf(struct wpi_softc *sc) -{ - struct wpi_rbuf *rbuf; - - rbuf = SLIST_FIRST(&sc->rxq.freelist); - if (rbuf == NULL) - return NULL; - SLIST_REMOVE_HEAD(&sc->rxq.freelist, next); - return rbuf; -} - -/* - * This is called automatically by the network stack when the mbuf to which - * our RX buffer is attached is freed. - */ -void -wpi_free_rbuf(caddr_t buf, u_int size, void *arg) -{ - struct wpi_rbuf *rbuf = arg; - struct wpi_softc *sc = rbuf->sc; - - /* Put the RX buffer back in the free list. */ - SLIST_INSERT_HEAD(&sc->rxq.freelist, rbuf, next); -} - -int -wpi_alloc_rpool(struct wpi_softc *sc) -{ - struct wpi_rx_ring *ring = &sc->rxq; - int i, error; - - /* Allocate a big chunk of DMA'able memory... */ - error = wpi_dma_contig_alloc(sc->sc_dmat, &ring->buf_dma, NULL, - WPI_RBUF_COUNT * WPI_RBUF_SIZE, 4096, BUS_DMA_NOWAIT); - if (error != 0) { - printf("%s: could not allocate Rx buffers DMA memory\n", - sc->sc_dev.dv_xname); - return error; - } - - /* ...and split it into chunks of WPI_RBUF_SIZE bytes. */ - SLIST_INIT(&ring->freelist); - for (i = 0; i < WPI_RBUF_COUNT; i++) { - struct wpi_rbuf *rbuf = &ring->rbuf[i]; - - rbuf->sc = sc; /* Backpointer for callbacks. */ - rbuf->vaddr = ring->buf_dma.vaddr + i * WPI_RBUF_SIZE; - rbuf->paddr = ring->buf_dma.paddr + i * WPI_RBUF_SIZE; - - SLIST_INSERT_HEAD(&ring->freelist, rbuf, next); - } - return 0; -} - -void -wpi_free_rpool(struct wpi_softc *sc) -{ - wpi_dma_contig_free(&sc->rxq.buf_dma); -} - int wpi_alloc_rx_ring(struct wpi_softc *sc, struct wpi_rx_ring *ring) { @@ -691,7 +620,7 @@ wpi_alloc_rx_ring(struct wpi_softc *sc, struct wpi_rx_ring *ring) /* Allocate RX descriptors (16KB aligned.) */ size = WPI_RX_RING_COUNT * sizeof (uint32_t); error = wpi_dma_contig_alloc(sc->sc_dmat, &ring->desc_dma, - (void **)&ring->desc, size, 16 * 1024, BUS_DMA_NOWAIT); + (void **)&ring->desc, size, 16 * 1024); if (error != 0) { printf("%s: could not allocate RX ring DMA memory\n", sc->sc_dev.dv_xname); @@ -699,34 +628,50 @@ wpi_alloc_rx_ring(struct wpi_softc *sc, struct wpi_rx_ring *ring) } /* - * Allocate RX buffers. + * Allocate and map RX buffers. */ for (i = 0; i < WPI_RX_RING_COUNT; i++) { struct wpi_rx_data *data = &ring->data[i]; - struct wpi_rbuf *rbuf; + + error = bus_dmamap_create(sc->sc_dmat, WPI_RBUF_SIZE, 1, + WPI_RBUF_SIZE, 0, BUS_DMA_NOWAIT, &data->map); + if (error != 0) { + printf("%s: could not create RX buf DMA map\n", + sc->sc_dev.dv_xname); + goto fail; + } MGETHDR(data->m, M_DONTWAIT, MT_DATA); if (data->m == NULL) { printf("%s: could not allocate RX mbuf\n", sc->sc_dev.dv_xname); - error = ENOMEM; + error = ENOBUFS; goto fail; } - if ((rbuf = wpi_alloc_rbuf(sc)) == NULL) { - m_freem(data->m); - data->m = NULL; - printf("%s: could not allocate RX buffer\n", + MCLGETI(data->m, M_DONTWAIT, NULL, WPI_RBUF_SIZE); + if (!(data->m->m_flags & M_EXT)) { + printf("%s: could not allocate RX mbuf cluster\n", sc->sc_dev.dv_xname); - error = ENOMEM; + error = ENOBUFS; + goto fail; + } + + error = bus_dmamap_load(sc->sc_dmat, data->map, + mtod(data->m, void *), WPI_RBUF_SIZE, NULL, + BUS_DMA_NOWAIT); + if (error != 0) { + printf("%s: can't map mbuf (error %d)\n", + sc->sc_dev.dv_xname, error); goto fail; } - /* Attach RX buffer to mbuf header. */ - MEXTADD(data->m, rbuf->vaddr, WPI_RBUF_SIZE, 0, wpi_free_rbuf, - rbuf); /* Set physical address of RX buffer. */ - ring->desc[i] = htole32(rbuf->paddr); + ring->desc[i] = htole32(data->map->dm_segs[0].ds_addr); } + + bus_dmamap_sync(sc->sc_dmat, ring->desc_dma.map, 0, size, + BUS_DMASYNC_PREWRITE); + return 0; fail: wpi_free_rx_ring(sc, ring); @@ -759,8 +704,16 @@ wpi_free_rx_ring(struct wpi_softc *sc, struct wpi_rx_ring *ring) wpi_dma_contig_free(&ring->desc_dma); for (i = 0; i < WPI_RX_RING_COUNT; i++) { - if (ring->data[i].m != NULL) - m_freem(ring->data[i].m); + struct wpi_rx_data *data = &ring->data[i]; + + if (data->m != NULL) { + bus_dmamap_sync(sc->sc_dmat, data->map, 0, + data->map->dm_mapsize, BUS_DMASYNC_POSTREAD); + bus_dmamap_unload(sc->sc_dmat, data->map); + m_freem(data->m); + } + if (data->map != NULL) + bus_dmamap_destroy(sc->sc_dmat, data->map); } } @@ -778,7 +731,7 @@ wpi_alloc_tx_ring(struct wpi_softc *sc, struct wpi_tx_ring *ring, int qid) /* Allocate TX descriptors (16KB aligned.) */ size = WPI_TX_RING_COUNT * sizeof (struct wpi_tx_desc); error = wpi_dma_contig_alloc(sc->sc_dmat, &ring->desc_dma, - (void **)&ring->desc, size, 16 * 1024, BUS_DMA_NOWAIT); + (void **)&ring->desc, size, 16 * 1024); if (error != 0) { printf("%s: could not allocate TX ring DMA memory\n", sc->sc_dev.dv_xname); @@ -800,7 +753,7 @@ wpi_alloc_tx_ring(struct wpi_softc *sc, struct wpi_tx_ring *ring, int qid) size = WPI_TX_RING_COUNT * sizeof (struct wpi_tx_cmd); error = wpi_dma_contig_alloc(sc->sc_dmat, &ring->cmd_dma, - (void **)&ring->cmd, size, 4, BUS_DMA_NOWAIT); + (void **)&ring->cmd, size, 4); if (error != 0) { printf("%s: could not allocate TX cmd DMA memory\n", sc->sc_dev.dv_xname); @@ -1216,17 +1169,16 @@ wpi_rx_done(struct wpi_softc *sc, struct wpi_rx_desc *desc, struct wpi_rx_stat *stat; struct wpi_rx_head *head; struct wpi_rx_tail *tail; - struct wpi_rbuf *rbuf; struct ieee80211_frame *wh; struct ieee80211_rxinfo rxi; struct ieee80211_node *ni; struct mbuf *m, *m1; uint32_t flags; + int error; - stat = (struct wpi_rx_stat *)(desc + 1); - bus_dmamap_sync(sc->sc_dmat, ring->buf_dma.map, - (caddr_t)stat - ring->buf_dma.vaddr, WPI_RBUF_SIZE, + bus_dmamap_sync(sc->sc_dmat, data->map, 0, WPI_RBUF_SIZE, BUS_DMASYNC_POSTREAD); + stat = (struct wpi_rx_stat *)(desc + 1); if (stat->len > WPI_STAT_MAXLEN) { printf("%s: invalid RX statistic header\n", @@ -1245,14 +1197,57 @@ wpi_rx_done(struct wpi_softc *sc, struct wpi_rx_desc *desc, return; } /* Discard frames that are too short. */ - if (letoh16(head->len) < sizeof (struct ieee80211_frame)) { + if (letoh16(head->len) < sizeof (*wh)) { DPRINTF(("frame too short: %d\n", letoh16(head->len))); ic->ic_stats.is_rx_tooshort++; ifp->if_ierrors++; return; } + MGETHDR(m1, M_DONTWAIT, MT_DATA); + if (m1 == NULL) { + ic->ic_stats.is_rx_nombuf++; + ifp->if_ierrors++; + return; + } + MCLGETI(m1, M_DONTWAIT, NULL, WPI_RBUF_SIZE); + if (!(m1->m_flags & M_EXT)) { + m_freem(m1); + ic->ic_stats.is_rx_nombuf++; + ifp->if_ierrors++; + return; + } + bus_dmamap_unload(sc->sc_dmat, data->map); + + error = bus_dmamap_load(sc->sc_dmat, data->map, mtod(m1, void *), + WPI_RBUF_SIZE, NULL, BUS_DMA_NOWAIT); + if (error != 0) { + m_freem(m1); + + /* Try to reload the old mbuf. */ + error = bus_dmamap_load(sc->sc_dmat, data->map, + mtod(data->m, void *), WPI_RBUF_SIZE, NULL, + BUS_DMA_NOWAIT); + if (error != 0) { + panic("%s: could not load old RX mbuf", + sc->sc_dev.dv_xname); + } + /* Physical address may have changed. */ + ring->desc[ring->cur] = htole32(data->map->dm_segs[0].ds_addr); + bus_dmamap_sync(sc->sc_dmat, ring->desc_dma.map, + ring->cur * sizeof (uint32_t), sizeof (uint32_t), + BUS_DMASYNC_PREWRITE); + ifp->if_ierrors++; + return; + } + m = data->m; + data->m = m1; + /* Update RX descriptor. */ + ring->desc[ring->cur] = htole32(data->map->dm_segs[0].ds_addr); + bus_dmamap_sync(sc->sc_dmat, ring->desc_dma.map, + ring->cur * sizeof (uint32_t), sizeof (uint32_t), + BUS_DMASYNC_PREWRITE); /* Finalize mbuf. */ m->m_pkthdr.rcvif = ifp; @@ -1287,33 +1282,6 @@ wpi_rx_done(struct wpi_softc *sc, struct wpi_rx_desc *desc, rxi.rxi_flags |= IEEE80211_RXI_HWDEC; } - if ((rbuf = SLIST_FIRST(&sc->rxq.freelist)) != NULL) { - MGETHDR(m1, M_DONTWAIT, MT_DATA); - if (m1 == NULL) { - ic->ic_stats.is_rx_nombuf++; - ifp->if_ierrors++; - return; - } - /* Attach RX buffer to mbuf header. */ - MEXTADD(m1, rbuf->vaddr, WPI_RBUF_SIZE, 0, wpi_free_rbuf, - rbuf); - SLIST_REMOVE_HEAD(&sc->rxq.freelist, next); - - data->m = m1; - - /* Update RX descriptor. */ - ring->desc[ring->cur] = htole32(rbuf->paddr); - } else { - /* No free rbufs, copy frame into an mbuf. */ - m = m_copym2(m, 0, M_COPYALL, M_DONTWAIT); - if (m == NULL) { - /* No free mbufs either, drop frame. */ - ic->ic_stats.is_rx_nombuf++; - ifp->if_ierrors++; - return; - } - } - #if NBPFILTER > 0 if (sc->sc_drvbpf != NULL) { struct mbuf mb; @@ -1442,11 +1410,11 @@ wpi_notif_intr(struct wpi_softc *sc) hw = letoh32(sc->shared->next); while (sc->rxq.cur != hw) { struct wpi_rx_data *data = &sc->rxq.data[sc->rxq.cur]; - struct wpi_rx_desc *desc = (void *)data->m->m_ext.ext_buf; + struct wpi_rx_desc *desc; - bus_dmamap_sync(sc->sc_dmat, sc->rxq.buf_dma.map, - (caddr_t)desc - sc->rxq.buf_dma.vaddr, sizeof (*desc), + bus_dmamap_sync(sc->sc_dmat, data->map, 0, sizeof (*desc), BUS_DMASYNC_POSTREAD); + desc = mtod(data->m, struct wpi_rx_desc *); DPRINTFN(4, ("rx notification qid=%x idx=%d flags=%x type=%d " "len=%d\n", desc->qid, desc->idx, desc->flags, desc->type, @@ -1472,8 +1440,7 @@ wpi_notif_intr(struct wpi_softc *sc) (struct wpi_ucode_info *)(desc + 1); /* The microcontroller is ready. */ - bus_dmamap_sync(sc->sc_dmat, sc->rxq.buf_dma.map, - (caddr_t)uc - sc->rxq.buf_dma.vaddr, + bus_dmamap_sync(sc->sc_dmat, data->map, sizeof (*desc), sizeof (*uc), BUS_DMASYNC_POSTREAD); DPRINTF(("microcode alive notification version %x " "alive %x\n", letoh32(uc->version), @@ -1494,8 +1461,7 @@ wpi_notif_intr(struct wpi_softc *sc) uint32_t *status = (uint32_t *)(desc + 1); /* Enabled/disabled notification. */ - bus_dmamap_sync(sc->sc_dmat, sc->rxq.buf_dma.map, - (caddr_t)status - sc->rxq.buf_dma.vaddr, + bus_dmamap_sync(sc->sc_dmat, data->map, sizeof (*desc), sizeof (*status), BUS_DMASYNC_POSTREAD); DPRINTF(("state changed to %x\n", letoh32(*status))); @@ -1515,8 +1481,7 @@ wpi_notif_intr(struct wpi_softc *sc) struct wpi_start_scan *scan = (struct wpi_start_scan *)(desc + 1); - bus_dmamap_sync(sc->sc_dmat, sc->rxq.buf_dma.map, - (caddr_t)scan - sc->rxq.buf_dma.vaddr, + bus_dmamap_sync(sc->sc_dmat, data->map, sizeof (*desc), sizeof (*scan), BUS_DMASYNC_POSTREAD); DPRINTFN(2, ("scanning channel %d status %x\n", scan->chan, letoh32(scan->status))); @@ -1530,8 +1495,7 @@ wpi_notif_intr(struct wpi_softc *sc) struct wpi_stop_scan *scan = (struct wpi_stop_scan *)(desc + 1); - bus_dmamap_sync(sc->sc_dmat, sc->rxq.buf_dma.map, - (caddr_t)scan - sc->rxq.buf_dma.vaddr, + bus_dmamap_sync(sc->sc_dmat, data->map, sizeof (*desc), sizeof (*scan), BUS_DMASYNC_POSTREAD); DPRINTF(("scan finished nchan=%d status=%d chan=%d\n", scan->nchan, scan->status, scan->chan)); diff --git a/sys/dev/pci/if_wpivar.h b/sys/dev/pci/if_wpivar.h index 15f442f24d9..29f8cc78194 100644 --- a/sys/dev/pci/if_wpivar.h +++ b/sys/dev/pci/if_wpivar.h @@ -1,4 +1,4 @@ -/* $OpenBSD: if_wpivar.h,v 1.18 2008/12/03 17:17:08 damien Exp $ */ +/* $OpenBSD: if_wpivar.h,v 1.19 2009/05/12 19:10:57 damien Exp $ */ /*- * Copyright (c) 2006-2008 @@ -80,28 +80,17 @@ struct wpi_tx_ring { int cur; }; -#define WPI_RBUF_COUNT (WPI_RX_RING_COUNT + 32) - struct wpi_softc; -struct wpi_rbuf { - struct wpi_softc *sc; - caddr_t vaddr; - bus_addr_t paddr; - SLIST_ENTRY(wpi_rbuf) next; -}; - struct wpi_rx_data { struct mbuf *m; + bus_dmamap_t map; }; struct wpi_rx_ring { struct wpi_dma_info desc_dma; - struct wpi_dma_info buf_dma; uint32_t *desc; struct wpi_rx_data data[WPI_RX_RING_COUNT]; - struct wpi_rbuf rbuf[WPI_RBUF_COUNT]; - SLIST_HEAD(, wpi_rbuf) freelist; int cur; }; |