summaryrefslogtreecommitdiff
path: root/sys/dev
diff options
context:
space:
mode:
authorDamien Bergamini <damien@cvs.openbsd.org>2009-05-12 19:10:58 +0000
committerDamien Bergamini <damien@cvs.openbsd.org>2009-05-12 19:10:58 +0000
commit713fc07f280e9ec10aa464332ad21f7455bfae4b (patch)
tree1518ffa3383eb75e3580dc3b9a27f0d52adef350 /sys/dev
parent9cd2545ee85e9608354e60c0e52cffb59446f3a8 (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.c328
-rw-r--r--sys/dev/pci/if_iwnvar.h18
-rw-r--r--sys/dev/pci/if_wpi.c258
-rw-r--r--sys/dev/pci/if_wpivar.h15
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;
};