diff options
author | Pedro Martelletto <pedro@cvs.openbsd.org> | 2006-03-31 17:18:38 +0000 |
---|---|---|
committer | Pedro Martelletto <pedro@cvs.openbsd.org> | 2006-03-31 17:18:38 +0000 |
commit | 34d7f43fc5c799e366d7e64254ce09b7109e90af (patch) | |
tree | 9ef13d2a8da428970b44a602e70abba91b38cb4a /sys/dev/pci | |
parent | cacbfa4f8310f60eecf9faf915b52dd499a3e0d8 (diff) |
Backout, causes panics
Diffstat (limited to 'sys/dev/pci')
-rw-r--r-- | sys/dev/pci/if_iwi.c | 789 | ||||
-rw-r--r-- | sys/dev/pci/if_iwireg.h | 101 | ||||
-rw-r--r-- | sys/dev/pci/if_iwivar.h | 69 |
3 files changed, 403 insertions, 556 deletions
diff --git a/sys/dev/pci/if_iwi.c b/sys/dev/pci/if_iwi.c index bdefff19b1a..e744161efe1 100644 --- a/sys/dev/pci/if_iwi.c +++ b/sys/dev/pci/if_iwi.c @@ -1,4 +1,4 @@ -/* $OpenBSD: if_iwi.c,v 1.62 2006/03/27 20:46:35 damien Exp $ */ +/* $OpenBSD: if_iwi.c,v 1.63 2006/03/31 17:18:36 pedro Exp $ */ /*- * Copyright (c) 2004-2006 @@ -97,27 +97,19 @@ int iwi_match(struct device *, void *, void *); void iwi_attach(struct device *, struct device *, void *); int iwi_detach(struct device *, int); void iwi_power(int, void *); -int iwi_alloc_cmd_ring(struct iwi_softc *, struct iwi_cmd_ring *); -void iwi_reset_cmd_ring(struct iwi_softc *, struct iwi_cmd_ring *); -void iwi_free_cmd_ring(struct iwi_softc *, struct iwi_cmd_ring *); -int iwi_alloc_tx_ring(struct iwi_softc *, struct iwi_tx_ring *, - bus_addr_t, bus_addr_t); -void iwi_reset_tx_ring(struct iwi_softc *, struct iwi_tx_ring *); -void iwi_free_tx_ring(struct iwi_softc *, struct iwi_tx_ring *); -int iwi_alloc_rx_ring(struct iwi_softc *, struct iwi_rx_ring *); -void iwi_reset_rx_ring(struct iwi_softc *, struct iwi_rx_ring *); -void iwi_free_rx_ring(struct iwi_softc *, struct iwi_rx_ring *); +int iwi_dma_alloc(struct iwi_softc *); +void iwi_release(struct iwi_softc *); int iwi_media_change(struct ifnet *); void iwi_media_status(struct ifnet *, struct ifmediareq *); uint16_t iwi_read_prom_word(struct iwi_softc *, uint8_t); int iwi_find_txnode(struct iwi_softc *, const uint8_t *); int iwi_newstate(struct ieee80211com *, enum ieee80211_state, int); -void iwi_frame_intr(struct iwi_softc *, struct iwi_rx_data *, +void iwi_frame_intr(struct iwi_softc *, struct iwi_rx_buf *, int, struct iwi_frame *); -void iwi_notification_intr(struct iwi_softc *, struct iwi_rx_data *, +void iwi_notification_intr(struct iwi_softc *, struct iwi_rx_buf *, struct iwi_notif *); void iwi_rx_intr(struct iwi_softc *); -void iwi_tx_intr(struct iwi_softc *, struct iwi_tx_ring *); +void iwi_tx_intr(struct iwi_softc *); int iwi_intr(void *); int iwi_cmd(struct iwi_softc *, uint8_t, void *, uint8_t, int); int iwi_tx_start(struct ifnet *, struct mbuf *, @@ -129,8 +121,8 @@ int iwi_get_radio(struct iwi_softc *, int *); int iwi_ioctl(struct ifnet *, u_long, caddr_t); void iwi_stop_master(struct iwi_softc *); int iwi_reset(struct iwi_softc *); -int iwi_load_ucode(struct iwi_softc *, const char *, int); -int iwi_load_firmware(struct iwi_softc *, const char *, int); +int iwi_load_ucode(struct iwi_softc *, const char *); +int iwi_load_firmware(struct iwi_softc *, const char *); int iwi_config(struct iwi_softc *); int iwi_set_chan(struct iwi_softc *, struct ieee80211_channel *); int iwi_scan(struct iwi_softc *); @@ -211,6 +203,9 @@ iwi_attach(struct device *parent, struct device *self, void *aux) sc->sc_sh = memh; sc->sc_dmat = pa->pa_dmat; + /* disable interrupts */ + CSR_WRITE_4(sc, IWI_CSR_INTR_MASK, 0); + if (pci_intr_map(pa, &ih) != 0) { printf(": could not map interrupt\n"); return; @@ -233,61 +228,19 @@ iwi_attach(struct device *parent, struct device *self, void *aux) return; } - /* - * Allocate rings. - */ - error = iwi_alloc_cmd_ring(sc, &sc->cmdq); - if (error != 0) { - printf(": could not allocate Cmd ring\n"); + if (iwi_dma_alloc(sc) != 0) { + printf(": could not allocate DMA resources\n"); return; } - error = iwi_alloc_tx_ring(sc, &sc->txq[0], IWI_CSR_TX1_RIDX, - IWI_CSR_TX1_WIDX); - if (error != 0) { - printf(": could not allocate Tx ring 1\n"); - goto fail1; - } - - error = iwi_alloc_tx_ring(sc, &sc->txq[1], IWI_CSR_TX2_RIDX, - IWI_CSR_TX2_WIDX); - if (error != 0) { - printf(": could not allocate Tx ring 2\n"); - goto fail2; - } - - error = iwi_alloc_tx_ring(sc, &sc->txq[2], IWI_CSR_TX3_RIDX, - IWI_CSR_TX3_WIDX); - if (error != 0) { - printf(": could not allocate Tx ring 3\n"); - goto fail3; - } - - error = iwi_alloc_tx_ring(sc, &sc->txq[3], IWI_CSR_TX4_RIDX, - IWI_CSR_TX4_WIDX); - if (error != 0) { - printf(": could not allocate Tx ring 4\n"); - goto fail4; - } - - error = iwi_alloc_rx_ring(sc, &sc->rxq); - if (error != 0) { - printf(": could not allocate Rx ring\n"); - goto fail5; - } - - ic->ic_phytype = IEEE80211_T_OFDM; /* not only, but not used */ - ic->ic_opmode = IEEE80211_M_STA; /* default to BSS mode */ + ic->ic_phytype = IEEE80211_T_OFDM; + ic->ic_opmode = IEEE80211_M_STA; ic->ic_state = IEEE80211_S_INIT; /* set device capabilities */ - ic->ic_caps = - IEEE80211_C_IBSS | /* IBSS mode supported */ - IEEE80211_C_MONITOR | /* monitor mode supported */ - IEEE80211_C_WEP | /* h/w WEP supported */ - IEEE80211_C_TXPMGT | /* tx power management */ - IEEE80211_C_SHPREAMBLE | /* short preamble supported */ - IEEE80211_C_SCANALL; /* h/w scanning */ + ic->ic_caps = IEEE80211_C_IBSS | IEEE80211_C_PMGT | IEEE80211_C_WEP | + IEEE80211_C_TXPMGT | IEEE80211_C_SHPREAMBLE | IEEE80211_C_MONITOR | + IEEE80211_C_SCANALL; /* read MAC address from EEPROM */ val = iwi_read_prom_word(sc, IWI_EEPROM_MAC + 0); @@ -368,14 +321,6 @@ iwi_attach(struct device *parent, struct device *self, void *aux) sc->sc_txtap.wt_ihdr.it_len = htole16(sc->sc_txtap_len); sc->sc_txtap.wt_ihdr.it_present = htole32(IWI_TX_RADIOTAP_PRESENT); #endif - - return; - -fail5: iwi_free_tx_ring(sc, &sc->txq[3]); -fail4: iwi_free_tx_ring(sc, &sc->txq[2]); -fail3: iwi_free_tx_ring(sc, &sc->txq[1]); -fail2: iwi_free_tx_ring(sc, &sc->txq[0]); -fail1: iwi_free_cmd_ring(sc, &sc->cmdq); } int @@ -389,12 +334,7 @@ iwi_detach(struct device* self, int flags) ieee80211_ifdetach(ifp); if_detach(ifp); - iwi_free_cmd_ring(sc, &sc->cmdq); - iwi_free_tx_ring(sc, &sc->txq[0]); - iwi_free_tx_ring(sc, &sc->txq[1]); - iwi_free_tx_ring(sc, &sc->txq[2]); - iwi_free_tx_ring(sc, &sc->txq[3]); - iwi_free_rx_ring(sc, &sc->rxq); + iwi_release(sc); if (sc->sc_ih != NULL) { pci_intr_disestablish(sc->sc_pct, sc->sc_ih); @@ -430,268 +370,193 @@ iwi_power(int why, void *arg) } int -iwi_alloc_cmd_ring(struct iwi_softc *sc, struct iwi_cmd_ring *ring) +iwi_dma_alloc(struct iwi_softc *sc) { - int nsegs, error; - - ring->queued = 0; - ring->cur = ring->next = 0; + int i, nsegs, error; + /* + * Allocate and map Tx ring. + */ error = bus_dmamap_create(sc->sc_dmat, - sizeof (struct iwi_cmd_desc) * IWI_CMD_RING_COUNT, 1, - sizeof (struct iwi_cmd_desc) * IWI_CMD_RING_COUNT, 0, - BUS_DMA_NOWAIT, &ring->map); + sizeof (struct iwi_tx_desc) * IWI_TX_RING_SIZE, 1, + sizeof (struct iwi_tx_desc) * IWI_TX_RING_SIZE, 0, BUS_DMA_NOWAIT, + &sc->tx_ring_map); if (error != 0) { - printf("%s: could not create cmd ring DMA map\n", + printf("%s: could not create tx ring DMA map\n", sc->sc_dev.dv_xname); goto fail; } error = bus_dmamem_alloc(sc->sc_dmat, - sizeof (struct iwi_cmd_desc) * IWI_CMD_RING_COUNT, PAGE_SIZE, 0, - &ring->seg, 1, &nsegs, BUS_DMA_NOWAIT); + sizeof (struct iwi_tx_desc) * IWI_TX_RING_SIZE, PAGE_SIZE, 0, + &sc->tx_ring_seg, 1, &nsegs, BUS_DMA_NOWAIT); if (error != 0) { - printf("%s: could not allocate cmd ring DMA memory\n", + printf("%s: could not allocate tx ring DMA memory\n", sc->sc_dev.dv_xname); goto fail; } - error = bus_dmamem_map(sc->sc_dmat, &ring->seg, nsegs, - sizeof (struct iwi_cmd_desc) * IWI_CMD_RING_COUNT, - (caddr_t *)&ring->desc, BUS_DMA_NOWAIT); + error = bus_dmamem_map(sc->sc_dmat, &sc->tx_ring_seg, nsegs, + sizeof (struct iwi_tx_desc) * IWI_TX_RING_SIZE, + (caddr_t *)&sc->tx_desc, BUS_DMA_NOWAIT); if (error != 0) { - printf("%s: could not map cmd ring DMA memory\n", + printf("%s: could not map tx ring DMA memory\n", sc->sc_dev.dv_xname); goto fail; } - error = bus_dmamap_load(sc->sc_dmat, ring->map, ring->desc, - sizeof (struct iwi_cmd_desc) * IWI_CMD_RING_COUNT, NULL, + error = bus_dmamap_load(sc->sc_dmat, sc->tx_ring_map, sc->tx_desc, + sizeof (struct iwi_tx_desc) * IWI_TX_RING_SIZE, NULL, BUS_DMA_NOWAIT); if (error != 0) { - printf("%s: could not load cmd ring DMA map\n", + printf("%s: could not load tx ring DMA map\n", sc->sc_dev.dv_xname); goto fail; } - bzero(ring->desc, sizeof (struct iwi_cmd_desc) * IWI_CMD_RING_COUNT); - return 0; - -fail: iwi_free_cmd_ring(sc, ring); - return error; -} - -void -iwi_reset_cmd_ring(struct iwi_softc *sc, struct iwi_cmd_ring *ring) -{ - ring->queued = 0; - ring->cur = ring->next = 0; -} - -void -iwi_free_cmd_ring(struct iwi_softc *sc, struct iwi_cmd_ring *ring) -{ - if (ring->map != NULL) { - if (ring->desc != NULL) { - bus_dmamap_unload(sc->sc_dmat, ring->map); - bus_dmamem_unmap(sc->sc_dmat, (caddr_t)ring->desc, - sizeof (struct iwi_cmd_desc) * IWI_CMD_RING_COUNT); - bus_dmamem_free(sc->sc_dmat, &ring->seg, 1); - } - bus_dmamap_destroy(sc->sc_dmat, ring->map); - } -} - -int -iwi_alloc_tx_ring(struct iwi_softc *sc, struct iwi_tx_ring *ring, - bus_addr_t csr_ridx, bus_addr_t csr_widx) -{ - struct iwi_tx_data *data; - int i, nsegs, error; - - ring->queued = 0; - ring->cur = ring->next = 0; - ring->csr_ridx = csr_ridx; - ring->csr_widx = csr_widx; + bzero(sc->tx_desc, sizeof (struct iwi_tx_desc) * IWI_TX_RING_SIZE); + /* + * Allocate and map command ring. + */ error = bus_dmamap_create(sc->sc_dmat, - sizeof (struct iwi_tx_desc) * IWI_TX_RING_COUNT, 1, - sizeof (struct iwi_tx_desc) * IWI_TX_RING_COUNT, 0, BUS_DMA_NOWAIT, - &ring->map); + sizeof (struct iwi_cmd_desc) * IWI_CMD_RING_SIZE, 1, + sizeof (struct iwi_cmd_desc) * IWI_CMD_RING_SIZE, 0, + BUS_DMA_NOWAIT, &sc->cmd_ring_map); if (error != 0) { - printf("%s: could not create tx ring DMA map\n", + printf("%s: could not create command ring DMA map\n", sc->sc_dev.dv_xname); goto fail; } error = bus_dmamem_alloc(sc->sc_dmat, - sizeof (struct iwi_tx_desc) * IWI_TX_RING_COUNT, PAGE_SIZE, 0, - &ring->seg, 1, &nsegs, BUS_DMA_NOWAIT); + sizeof (struct iwi_cmd_desc) * IWI_CMD_RING_SIZE, PAGE_SIZE, 0, + &sc->cmd_ring_seg, 1, &nsegs, BUS_DMA_NOWAIT); if (error != 0) { - printf("%s: could not allocate tx ring DMA memory\n", + printf("%s: could not allocate command ring DMA memory\n", sc->sc_dev.dv_xname); goto fail; } - error = bus_dmamem_map(sc->sc_dmat, &ring->seg, nsegs, - sizeof (struct iwi_tx_desc) * IWI_TX_RING_COUNT, - (caddr_t *)&ring->desc, BUS_DMA_NOWAIT); + error = bus_dmamem_map(sc->sc_dmat, &sc->cmd_ring_seg, nsegs, + sizeof (struct iwi_cmd_desc) * IWI_CMD_RING_SIZE, + (caddr_t *)&sc->cmd_desc, BUS_DMA_NOWAIT); if (error != 0) { - printf("%s: could not map tx ring DMA memory\n", + printf("%s: could not map command ring DMA memory\n", sc->sc_dev.dv_xname); goto fail; } - error = bus_dmamap_load(sc->sc_dmat, ring->map, ring->desc, - sizeof (struct iwi_tx_desc) * IWI_TX_RING_COUNT, NULL, + error = bus_dmamap_load(sc->sc_dmat, sc->cmd_ring_map, sc->cmd_desc, + sizeof (struct iwi_cmd_desc) * IWI_CMD_RING_SIZE, NULL, BUS_DMA_NOWAIT); if (error != 0) { - printf("%s: could not load tx ring DMA map\n", + printf("%s: could not load command ring DMA map\n", sc->sc_dev.dv_xname); goto fail; } - bzero(ring->desc, sizeof (struct iwi_tx_desc) * IWI_TX_RING_COUNT); - - for (i = 0; i < IWI_TX_RING_COUNT; i++) { - data = &ring->data[i]; + bzero(sc->cmd_desc, sizeof (struct iwi_cmd_desc) * IWI_CMD_RING_SIZE); + /* + * Allocate Tx buffers DMA maps. + */ + for (i = 0; i < IWI_TX_RING_SIZE; i++) { error = bus_dmamap_create(sc->sc_dmat, MCLBYTES, - IWI_MAX_SCATTER, MCLBYTES, 0, BUS_DMA_NOWAIT, &data->map); + IWI_MAX_NSEG - 2, MCLBYTES, 0, BUS_DMA_NOWAIT, + &sc->tx_buf[i].map); if (error != 0) { - printf("%s: could not create tx buf DMA map\n", + printf("%s: could not create tx buf DMA map", sc->sc_dev.dv_xname); goto fail; } } - return 0; - -fail: iwi_free_tx_ring(sc, ring); - return error; -} - -void -iwi_reset_tx_ring(struct iwi_softc *sc, struct iwi_tx_ring *ring) -{ - struct iwi_tx_data *data; - int i; - - for (i = 0; i < IWI_TX_RING_COUNT; i++) { - data = &ring->data[i]; - - if (data->m != NULL) { - bus_dmamap_unload(sc->sc_dmat, data->map); - m_freem(data->m); - data->m = NULL; - } - } - - ring->queued = 0; - ring->cur = ring->next = 0; -} - -void -iwi_free_tx_ring(struct iwi_softc *sc, struct iwi_tx_ring *ring) -{ - struct iwi_tx_data *data; - int i; - - if (ring->map != NULL) { - if (ring->desc != NULL) { - bus_dmamap_unload(sc->sc_dmat, ring->map); - bus_dmamem_unmap(sc->sc_dmat, (caddr_t)ring->desc, - sizeof (struct iwi_tx_desc) * IWI_TX_RING_COUNT); - bus_dmamem_free(sc->sc_dmat, &ring->seg, 1); - } - bus_dmamap_destroy(sc->sc_dmat, ring->map); - } - - for (i = 0; i < IWI_TX_RING_COUNT; i++) { - data = &ring->data[i]; - - if (data->m != NULL) { - bus_dmamap_unload(sc->sc_dmat, data->map); - m_freem(data->m); - } - bus_dmamap_destroy(sc->sc_dmat, data->map); - } -} - -int -iwi_alloc_rx_ring(struct iwi_softc *sc, struct iwi_rx_ring *ring) -{ - struct iwi_rx_data *data; - int i, error; - - ring->cur = 0; - - for (i = 0; i < IWI_RX_RING_COUNT; i++) { - data = &sc->rxq.data[i]; + /* + * Allocate and map Rx buffers. + */ + for (i = 0; i < IWI_RX_RING_SIZE; i++) { error = bus_dmamap_create(sc->sc_dmat, MCLBYTES, 1, MCLBYTES, - 0, BUS_DMA_NOWAIT, &data->map); + 0, BUS_DMA_NOWAIT, &sc->rx_buf[i].map); if (error != 0) { - printf("%s: could not create rx buf DMA map\n", + printf("%s: could not create rx buf DMA map", sc->sc_dev.dv_xname); goto fail; } - MGETHDR(data->m, M_DONTWAIT, MT_DATA); - if (data->m == NULL) { + MGETHDR(sc->rx_buf[i].m, M_DONTWAIT, MT_DATA); + if (sc->rx_buf[i].m == NULL) { printf("%s: could not allocate rx mbuf\n", sc->sc_dev.dv_xname); error = ENOMEM; goto fail; } - MCLGET(data->m, M_DONTWAIT); - if (!(data->m->m_flags & M_EXT)) { - m_freem(data->m); - data->m = NULL; + MCLGET(sc->rx_buf[i].m, M_DONTWAIT); + if (!(sc->rx_buf[i].m->m_flags & M_EXT)) { + m_freem(sc->rx_buf[i].m); printf("%s: could not allocate rx mbuf cluster\n", sc->sc_dev.dv_xname); error = ENOMEM; goto fail; } - error = bus_dmamap_load(sc->sc_dmat, data->map, - mtod(data->m, void *), MCLBYTES, NULL, BUS_DMA_NOWAIT); + error = bus_dmamap_load(sc->sc_dmat, sc->rx_buf[i].map, + mtod(sc->rx_buf[i].m, void *), MCLBYTES, NULL, + BUS_DMA_NOWAIT); if (error != 0) { printf("%s: could not load rx buf DMA map\n", sc->sc_dev.dv_xname); goto fail; } - - data->reg = IWI_CSR_RX_BASE + i * 4; } return 0; -fail: iwi_free_rx_ring(sc, ring); +fail: iwi_release(sc); return error; } void -iwi_reset_rx_ring(struct iwi_softc *sc, struct iwi_rx_ring *ring) -{ - ring->cur = 0; -} - -void -iwi_free_rx_ring(struct iwi_softc *sc, struct iwi_rx_ring *ring) +iwi_release(struct iwi_softc *sc) { - struct iwi_rx_data *data; int i; - for (i = 0; i < IWI_RX_RING_COUNT; i++) { - data = &sc->rxq.data[i]; + if (sc->tx_ring_map != NULL) { + if (sc->tx_desc != NULL) { + bus_dmamap_unload(sc->sc_dmat, sc->tx_ring_map); + bus_dmamem_unmap(sc->sc_dmat, (caddr_t)sc->tx_desc, + sizeof (struct iwi_tx_desc) * IWI_TX_RING_SIZE); + bus_dmamem_free(sc->sc_dmat, &sc->tx_ring_seg, 1); + } + bus_dmamap_destroy(sc->sc_dmat, sc->tx_ring_map); + } + + if (sc->cmd_ring_map != NULL) { + if (sc->cmd_desc != NULL) { + bus_dmamap_unload(sc->sc_dmat, sc->cmd_ring_map); + bus_dmamem_unmap(sc->sc_dmat, (caddr_t)sc->cmd_desc, + sizeof (struct iwi_cmd_desc) * IWI_CMD_RING_SIZE); + bus_dmamem_free(sc->sc_dmat, &sc->cmd_ring_seg, 1); + } + bus_dmamap_destroy(sc->sc_dmat, sc->cmd_ring_map); + } + + for (i = 0; i < IWI_TX_RING_SIZE; i++) { + if (sc->tx_buf[i].m != NULL) { + bus_dmamap_unload(sc->sc_dmat, sc->tx_buf[i].map); + m_freem(sc->tx_buf[i].m); + } + bus_dmamap_destroy(sc->sc_dmat, sc->tx_buf[i].map); + } - if (data->m != NULL) { - bus_dmamap_unload(sc->sc_dmat, data->map); - m_freem(data->m); + for (i = 0; i < IWI_RX_RING_SIZE; i++) { + if (sc->rx_buf[i].m != NULL) { + bus_dmamap_unload(sc->sc_dmat, sc->rx_buf[i].map); + m_freem(sc->rx_buf[i].m); } - bus_dmamap_destroy(sc->sc_dmat, data->map); + bus_dmamap_destroy(sc->sc_dmat, sc->rx_buf[i].map); } } @@ -904,7 +769,7 @@ iwi_read_prom_word(struct iwi_softc *sc, uint8_t addr) } void -iwi_frame_intr(struct iwi_softc *sc, struct iwi_rx_data *data, +iwi_frame_intr(struct iwi_softc *sc, struct iwi_rx_buf *buf, int i, struct iwi_frame *frame) { struct ieee80211com *ic = &sc->sc_ic; @@ -914,10 +779,10 @@ iwi_frame_intr(struct iwi_softc *sc, struct iwi_rx_data *data, struct ieee80211_node *ni; int error; - DPRINTFN(5, ("received frame len=%u chan=%u rssi=%u\n", - letoh16(frame->len), frame->chan, frame->rssi_dbm)); + DPRINTFN(5, ("RX!DATA!%u!%u!%u\n", letoh16(frame->len), frame->chan, + frame->rssi_dbm)); - bus_dmamap_sync(sc->sc_dmat, data->map, sizeof (struct iwi_hdr), + bus_dmamap_sync(sc->sc_dmat, buf->map, sizeof (struct iwi_hdr), sizeof (struct iwi_frame) + letoh16(frame->len), BUS_DMASYNC_POSTREAD); @@ -947,16 +812,16 @@ iwi_frame_intr(struct iwi_softc *sc, struct iwi_rx_data *data, return; } - bus_dmamap_unload(sc->sc_dmat, data->map); + bus_dmamap_unload(sc->sc_dmat, buf->map); - error = bus_dmamap_load(sc->sc_dmat, data->map, mtod(mnew, void *), + error = bus_dmamap_load(sc->sc_dmat, buf->map, mtod(mnew, void *), MCLBYTES, NULL, BUS_DMA_NOWAIT); if (error != 0) { m_freem(mnew); /* try to reload the old mbuf */ - error = bus_dmamap_load(sc->sc_dmat, data->map, - mtod(data->m, void *), MCLBYTES, NULL, BUS_DMA_NOWAIT); + error = bus_dmamap_load(sc->sc_dmat, buf->map, + mtod(buf->m, void *), MCLBYTES, NULL, BUS_DMA_NOWAIT); if (error != 0) { /* very unlikely that it will fail... */ panic("%s: could not load old rx mbuf", @@ -966,9 +831,9 @@ iwi_frame_intr(struct iwi_softc *sc, struct iwi_rx_data *data, return; } - m = data->m; - data->m = mnew; - CSR_WRITE_4(sc, data->reg, data->map->dm_segs[0].ds_addr); + m = buf->m; + buf->m = mnew; + CSR_WRITE_4(sc, IWI_CSR_RX_BASE + i * 4, buf->map->dm_segs->ds_addr); /* finalize mbuf */ m->m_pkthdr.rcvif = ifp; @@ -1021,12 +886,11 @@ iwi_frame_intr(struct iwi_softc *sc, struct iwi_rx_data *data, /* send the frame to the upper layer */ ieee80211_input(ifp, m, ni, frame->rssi_dbm, 0); - /* node is no longer needed */ ieee80211_release_node(ic, ni); } void -iwi_notification_intr(struct iwi_softc *sc, struct iwi_rx_data *data, +iwi_notification_intr(struct iwi_softc *sc, struct iwi_rx_buf *buf, struct iwi_notif *notif) { struct ieee80211com *ic = &sc->sc_ic; @@ -1036,7 +900,7 @@ iwi_notification_intr(struct iwi_softc *sc, struct iwi_rx_data *data, struct iwi_notif_authentication *auth; struct iwi_notif_association *assoc; - bus_dmamap_sync(sc->sc_dmat, data->map, sizeof (struct iwi_hdr), + bus_dmamap_sync(sc->sc_dmat, buf->map, sizeof (struct iwi_hdr), sizeof (struct iwi_notif) + letoh16(notif->len), BUS_DMASYNC_POSTREAD); @@ -1044,7 +908,7 @@ iwi_notification_intr(struct iwi_softc *sc, struct iwi_rx_data *data, case IWI_NOTIF_TYPE_SCAN_CHANNEL: chan = (struct iwi_notif_scan_channel *)(notif + 1); - DPRINTFN(2, ("Scanning channel (%u)\n", chan->nchan)); + DPRINTFN(2, ("Scan channel (%u)\n", chan->nchan)); break; case IWI_NOTIF_TYPE_SCAN_COMPLETE: @@ -1112,28 +976,30 @@ iwi_notification_intr(struct iwi_softc *sc, struct iwi_rx_data *data, void iwi_rx_intr(struct iwi_softc *sc) { - struct iwi_rx_data *data; + struct iwi_rx_buf *buf; struct iwi_hdr *hdr; - uint32_t hw; + uint32_t r, i; - hw = CSR_READ_4(sc, IWI_CSR_RX_RIDX); + r = CSR_READ_4(sc, IWI_CSR_RX_READ_INDEX); - for (; sc->rxq.cur != hw;) { - data = &sc->rxq.data[sc->rxq.cur]; + for (i = (sc->rx_cur + 1) % IWI_RX_RING_SIZE; i != r; + i = (i + 1) % IWI_RX_RING_SIZE) { - bus_dmamap_sync(sc->sc_dmat, data->map, 0, + buf = &sc->rx_buf[i]; + + bus_dmamap_sync(sc->sc_dmat, buf->map, 0, sizeof (struct iwi_hdr), BUS_DMASYNC_POSTREAD); - hdr = mtod(data->m, struct iwi_hdr *); + hdr = mtod(buf->m, struct iwi_hdr *); switch (hdr->type) { case IWI_HDR_TYPE_FRAME: - iwi_frame_intr(sc, data, + iwi_frame_intr(sc, buf, i, (struct iwi_frame *)(hdr + 1)); break; case IWI_HDR_TYPE_NOTIF: - iwi_notification_intr(sc, data, + iwi_notification_intr(sc, buf, (struct iwi_notif *)(hdr + 1)); break; @@ -1141,41 +1007,45 @@ iwi_rx_intr(struct iwi_softc *sc) printf("%s: unknown hdr type %u\n", sc->sc_dev.dv_xname, hdr->type); } - - sc->rxq.cur = (sc->rxq.cur + 1) % IWI_RX_RING_COUNT; } /* tell the firmware what we have processed */ - hw = (hw == 0) ? IWI_RX_RING_COUNT - 1 : hw - 1; - CSR_WRITE_4(sc, IWI_CSR_RX_WIDX, hw); + sc->rx_cur = (r == 0) ? IWI_RX_RING_SIZE - 1 : r - 1; + CSR_WRITE_4(sc, IWI_CSR_RX_WRITE_INDEX, sc->rx_cur); } void -iwi_tx_intr(struct iwi_softc *sc, struct iwi_tx_ring *txq) +iwi_tx_intr(struct iwi_softc *sc) { struct ieee80211com *ic = &sc->sc_ic; struct ifnet *ifp = &ic->ic_if; - struct iwi_tx_data *data; - uint32_t hw; + struct iwi_tx_buf *buf; + uint32_t r, i; + + r = CSR_READ_4(sc, IWI_CSR_TX1_READ_INDEX); - hw = CSR_READ_4(sc, txq->csr_ridx); + for (i = (sc->tx_old + 1) % IWI_TX_RING_SIZE; i != r; + i = (i + 1) % IWI_TX_RING_SIZE) { - for (; txq->next != hw;) { - data = &txq->data[txq->next]; + buf = &sc->tx_buf[i]; - bus_dmamap_unload(sc->sc_dmat, data->map); - m_freem(data->m); - data->m = NULL; - ieee80211_release_node(ic, data->ni); - data->ni = NULL; + bus_dmamap_unload(sc->sc_dmat, buf->map); + m_freem(buf->m); + buf->m = NULL; + ieee80211_release_node(ic, buf->ni); + buf->ni = NULL; ifp->if_opackets++; + sc->tx_queued--; - txq->queued--; - txq->next = (txq->next + 1) % IWI_TX_RING_COUNT; + /* kill watchdog timer */ + sc->sc_tx_timer = 0; } - sc->sc_tx_timer = 0; + /* remember what the firmware has processed */ + sc->tx_old = (r == 0) ? IWI_TX_RING_SIZE - 1 : r - 1; + + /* call start() since some buffer descriptors have been released */ ifp->if_flags &= ~IFF_OACTIVE; (*ifp->if_start)(ifp); } @@ -1192,13 +1062,11 @@ iwi_intr(void *arg) /* disable interrupts */ CSR_WRITE_4(sc, IWI_CSR_INTR_MASK, 0); - /* acknowledge interrupts */ - CSR_WRITE_4(sc, IWI_CSR_INTR, r); + DPRINTFN(8, ("INTR!0x%08x\n", r)); if (r & (IWI_INTR_FATAL_ERROR | IWI_INTR_PARITY_ERROR)) { printf("%s: fatal error\n", sc->sc_dev.dv_xname); iwi_stop(&sc->sc_ic.ic_if, 1); - r = 0; /* don't process more interrupts */ } if (r & IWI_INTR_FW_INITED) { @@ -1209,26 +1077,19 @@ iwi_intr(void *arg) if (r & IWI_INTR_RADIO_OFF) { DPRINTF(("radio transmitter off\n")); iwi_stop(&sc->sc_ic.ic_if, 1); - r = 0; /* don't process more interrupts */ } - if (r & IWI_INTR_CMD_DONE) - wakeup(sc); - - if (r & IWI_INTR_TX1_DONE) - iwi_tx_intr(sc, &sc->txq[0]); - - if (r & IWI_INTR_TX2_DONE) - iwi_tx_intr(sc, &sc->txq[1]); + if (r & IWI_INTR_RX_TRANSFER) + iwi_rx_intr(sc); - if (r & IWI_INTR_TX3_DONE) - iwi_tx_intr(sc, &sc->txq[2]); + if (r & IWI_INTR_CMD_TRANSFER) + wakeup(sc); - if (r & IWI_INTR_TX4_DONE) - iwi_tx_intr(sc, &sc->txq[3]); + if (r & IWI_INTR_TX1_TRANSFER) + iwi_tx_intr(sc); - if (r & IWI_INTR_RX_DONE) - iwi_rx_intr(sc); + /* acknowledge interrupts */ + CSR_WRITE_4(sc, IWI_CSR_INTR, r); /* re-enable interrupts */ CSR_WRITE_4(sc, IWI_CSR_INTR_MASK, IWI_INTR_MASK); @@ -1241,22 +1102,21 @@ iwi_cmd(struct iwi_softc *sc, uint8_t type, void *data, uint8_t len, int async) { struct iwi_cmd_desc *desc; - desc = &sc->cmdq.desc[sc->cmdq.cur]; + DPRINTFN(2, ("TX!CMD!%u!%u\n", type, len)); + + desc = &sc->cmd_desc[sc->cmd_cur]; desc->hdr.type = IWI_HDR_TYPE_COMMAND; desc->hdr.flags = IWI_HDR_FLAG_IRQ; desc->type = type; desc->len = len; bcopy(data, desc->data, len); - bus_dmamap_sync(sc->sc_dmat, sc->cmdq.map, - sc->cmdq.cur * sizeof (struct iwi_cmd_desc), + bus_dmamap_sync(sc->sc_dmat, sc->cmd_ring_map, + sc->cmd_cur * sizeof (struct iwi_cmd_desc), sizeof (struct iwi_cmd_desc), BUS_DMASYNC_PREWRITE); - DPRINTFN(2, ("sending command idx=%u type=%u len=%u\n", sc->cmdq.cur, - type, len)); - - sc->cmdq.cur = (sc->cmdq.cur + 1) % IWI_CMD_RING_COUNT; - CSR_WRITE_4(sc, IWI_CSR_CMD_WIDX, sc->cmdq.cur); + sc->cmd_cur = (sc->cmd_cur + 1) % IWI_CMD_RING_SIZE; + CSR_WRITE_4(sc, IWI_CSR_CMD_WRITE_INDEX, sc->cmd_cur); return async ? 0 : tsleep(sc, 0, "iwicmd", hz); } @@ -1266,9 +1126,8 @@ iwi_tx_start(struct ifnet *ifp, struct mbuf *m0, struct ieee80211_node *ni) { struct iwi_softc *sc = ifp->if_softc; struct ieee80211com *ic = &sc->sc_ic; - struct iwi_tx_data *data; + struct iwi_tx_buf *buf; struct iwi_tx_desc *desc; - struct iwi_tx_ring *txq = &sc->txq[0]; struct mbuf *mnew; int error, i, station = 0; @@ -1290,8 +1149,8 @@ iwi_tx_start(struct ifnet *ifp, struct mbuf *m0, struct ieee80211_node *ni) } #endif - data = &txq->data[txq->cur]; - desc = &txq->desc[txq->cur]; + buf = &sc->tx_buf[sc->tx_cur]; + desc = &sc->tx_desc[sc->tx_cur]; /* save and trim IEEE802.11 header */ m_copydata(m0, 0, sizeof (struct ieee80211_frame), (caddr_t)&desc->wh); @@ -1307,8 +1166,7 @@ iwi_tx_start(struct ifnet *ifp, struct mbuf *m0, struct ieee80211_node *ni) } } - error = bus_dmamap_load_mbuf(sc->sc_dmat, data->map, m0, - BUS_DMA_NOWAIT); + error = bus_dmamap_load_mbuf(sc->sc_dmat, buf->map, m0, BUS_DMA_NOWAIT); if (error != 0 && error != EFBIG) { printf("%s: could not map mbuf (error %d)\n", sc->sc_dev.dv_xname, error); @@ -1339,7 +1197,7 @@ iwi_tx_start(struct ifnet *ifp, struct mbuf *m0, struct ieee80211_node *ni) mnew->m_len = mnew->m_pkthdr.len; m0 = mnew; - error = bus_dmamap_load_mbuf(sc->sc_dmat, data->map, m0, + error = bus_dmamap_load_mbuf(sc->sc_dmat, buf->map, m0, BUS_DMA_NOWAIT); if (error != 0) { printf("%s: could not map mbuf (error %d)\n", @@ -1349,8 +1207,8 @@ iwi_tx_start(struct ifnet *ifp, struct mbuf *m0, struct ieee80211_node *ni) } } - data->m = m0; - data->ni = ni; + buf->m = m0; + buf->ni = ni; desc->hdr.type = IWI_HDR_TYPE_DATA; desc->hdr.flags = IWI_HDR_FLAG_IRQ; @@ -1371,25 +1229,25 @@ iwi_tx_start(struct ifnet *ifp, struct mbuf *m0, struct ieee80211_node *ni) if (ic->ic_flags & IEEE80211_F_SHPREAMBLE) desc->flags |= IWI_DATA_FLAG_SHPREAMBLE; - desc->nseg = htole32(data->map->dm_nsegs); - for (i = 0; i < data->map->dm_nsegs; i++) { - desc->seg_addr[i] = htole32(data->map->dm_segs[i].ds_addr); - desc->seg_len[i] = htole16(data->map->dm_segs[i].ds_len); + desc->nseg = htole32(buf->map->dm_nsegs); + for (i = 0; i < buf->map->dm_nsegs; i++) { + desc->seg_addr[i] = htole32(buf->map->dm_segs[i].ds_addr); + desc->seg_len[i] = htole16(buf->map->dm_segs[i].ds_len); } - bus_dmamap_sync(sc->sc_dmat, txq->map, - txq->cur * sizeof (struct iwi_tx_desc), + bus_dmamap_sync(sc->sc_dmat, sc->tx_ring_map, + sc->tx_cur * sizeof (struct iwi_tx_desc), sizeof (struct iwi_tx_desc), BUS_DMASYNC_PREWRITE); - bus_dmamap_sync(sc->sc_dmat, data->map, 0, MCLBYTES, + bus_dmamap_sync(sc->sc_dmat, buf->map, 0, MCLBYTES, BUS_DMASYNC_PREWRITE); - DPRINTFN(5, ("sending data frame idx=%u len=%u nseg=%u\n", txq->cur, - letoh16(desc->len), data->map->dm_nsegs)); + DPRINTFN(5, ("TX!DATA!%u!%u\n", letoh16(desc->len), desc->nseg)); - txq->queued++; - txq->cur = (txq->cur + 1) % IWI_TX_RING_COUNT; - CSR_WRITE_4(sc, txq->csr_widx, txq->cur); + /* inform firmware about this new packet */ + sc->tx_queued++; + sc->tx_cur = (sc->tx_cur + 1) % IWI_TX_RING_SIZE; + CSR_WRITE_4(sc, IWI_CSR_TX1_WRITE_INDEX, sc->tx_cur); return 0; } @@ -1410,7 +1268,7 @@ iwi_start(struct ifnet *ifp) if (m0 == NULL) break; - if (sc->txq[0].queued >= IWI_TX_RING_COUNT - 8) { + if (sc->tx_queued >= IWI_TX_RING_SIZE - 8) { IF_PREPEND(&ifp->if_snd, m0); ifp->if_flags |= IFF_OACTIVE; break; @@ -1556,10 +1414,8 @@ iwi_stop_master(struct iwi_softc *sc) break; DELAY(10); } - if (ntries == 5) { - printf("%s: timeout waiting for master\n", - sc->sc_dev.dv_xname); - } + if (ntries == 5) + printf("%s: timeout waiting for master\n", sc->sc_dev.dv_xname); CSR_WRITE_4(sc, IWI_CSR_RST, CSR_READ_4(sc, IWI_CSR_RST) | IWI_RST_PRINCETON_RESET); @@ -1578,6 +1434,7 @@ iwi_reset(struct iwi_softc *sc) CSR_WRITE_4(sc, IWI_CSR_CTL, CSR_READ_4(sc, IWI_CSR_CTL) | IWI_CTL_INIT); + /* initialize phase-locked level (PLL) */ CSR_WRITE_4(sc, IWI_CSR_READ_INT, IWI_READ_INT_INIT_HOST); /* wait for clock stabilization */ @@ -1586,11 +1443,8 @@ iwi_reset(struct iwi_softc *sc) break; DELAY(200); } - if (ntries == 1000) { - printf("%s: timeout waiting for clock stabilization\n", - sc->sc_dev.dv_xname); + if (ntries == 1000) return EIO; - } CSR_WRITE_4(sc, IWI_CSR_RST, CSR_READ_4(sc, IWI_CSR_RST) | IWI_RST_SW_RESET); @@ -1609,10 +1463,27 @@ iwi_reset(struct iwi_softc *sc) } int -iwi_load_ucode(struct iwi_softc *sc, const char *data, int size) +iwi_load_ucode(struct iwi_softc *sc, const char *name) { - const uint16_t *w; - int ntries, i; + u_char *uc, *data; + size_t size; + uint16_t *w; + int error, ntries, i; + + if ((error = loadfirmware(name, &data, &size)) != 0) { + printf("%s: could not read ucode %s, error %d\n", + sc->sc_dev.dv_xname, name, error); + goto fail1; + } + + if (size < sizeof (struct iwi_firmware_hdr)) { + error = EINVAL; + goto fail2; + } + + uc = data; + uc += sizeof (struct iwi_firmware_hdr); + size -= sizeof (struct iwi_firmware_hdr); CSR_WRITE_4(sc, IWI_CSR_RST, CSR_READ_4(sc, IWI_CSR_RST) | IWI_RST_STOP_MASTER); @@ -1622,17 +1493,15 @@ iwi_load_ucode(struct iwi_softc *sc, const char *data, int size) DELAY(10); } if (ntries == 5) { - printf("%s: timeout waiting for master\n", - sc->sc_dev.dv_xname); - return EIO; + printf("%s: timeout waiting for master\n", sc->sc_dev.dv_xname); + error = EIO; + goto fail2; } MEM_WRITE_4(sc, 0x3000e0, 0x80000000); DELAY(5000); - CSR_WRITE_4(sc, IWI_CSR_RST, CSR_READ_4(sc, IWI_CSR_RST) & ~IWI_RST_PRINCETON_RESET); - DELAY(5000); MEM_WRITE_4(sc, 0x3000e0, 0); DELAY(1000); @@ -1642,16 +1511,15 @@ iwi_load_ucode(struct iwi_softc *sc, const char *data, int size) DELAY(1000); MEM_WRITE_1(sc, 0x200000, 0x00); MEM_WRITE_1(sc, 0x200000, 0x40); - DELAY(1000); /* adapter is buggy, we must set the address for each word */ - for (w = (const uint16_t *)data; size > 0; w++, size -= 2) + for (w = (uint16_t *)uc; size > 0; w++, size -= 2) MEM_WRITE_2(sc, 0x200010, htole16(*w)); MEM_WRITE_1(sc, 0x200000, 0x00); MEM_WRITE_1(sc, 0x200000, 0x80); - /* wait until we get an answer */ + /* wait until we get a response in the uc queue */ for (ntries = 0; ntries < 100; ntries++) { if (MEM_READ_1(sc, 0x200000) & 1) break; @@ -1660,24 +1528,27 @@ iwi_load_ucode(struct iwi_softc *sc, const char *data, int size) if (ntries == 100) { printf("%s: timeout waiting for ucode to initialize\n", sc->sc_dev.dv_xname); - return EIO; + error = EIO; + goto fail2; } - /* read the answer or the firmware will not initialize properly */ + /* empty the uc queue or the firmware will not initialize properly */ for (i = 0; i < 7; i++) MEM_READ_4(sc, 0x200004); MEM_WRITE_1(sc, 0x200000, 0x00); - return 0; +fail2: free(data, M_DEVBUF); +fail1: return error; } /* macro to handle unaligned little endian data in firmware image */ #define GETLE32(p) ((p)[0] | (p)[1] << 8 | (p)[2] << 16 | (p)[3] << 24) - int -iwi_load_firmware(struct iwi_softc *sc, const char *data, int size) +iwi_load_firmware(struct iwi_softc *sc, const char *name) { + u_char *fw, *data; + size_t size; bus_dmamap_t map; bus_dma_segment_t seg; caddr_t virtaddr; @@ -1685,21 +1556,40 @@ iwi_load_firmware(struct iwi_softc *sc, const char *data, int size) uint32_t sentinel, ctl, src, dst, sum, len, mlen; int ntries, nsegs, error; + if ((error = loadfirmware(name, &data, &size)) != 0) { + printf("%s: could not read firmware %s, error %d\n", + sc->sc_dev.dv_xname, name, error); + goto fail1; + } + + if (size < sizeof (struct iwi_firmware_hdr)) { + error = EINVAL; + goto fail2; + } + + fw = data; + fw += sizeof (struct iwi_firmware_hdr); + size -= sizeof (struct iwi_firmware_hdr); + /* allocate DMA memory for storing firmware image */ error = bus_dmamap_create(sc->sc_dmat, size, 1, size, 0, BUS_DMA_NOWAIT, &map); if (error != 0) { printf("%s: could not create firmware DMA map\n", sc->sc_dev.dv_xname); - goto fail1; + goto fail2; } + /* + * We cannot map fw directly because of some hardware constraints on + * the mapping address. + */ error = bus_dmamem_alloc(sc->sc_dmat, size, PAGE_SIZE, 0, &seg, 1, &nsegs, BUS_DMA_NOWAIT); if (error != 0) { printf("%s: could allocate firmware DMA memory\n", sc->sc_dev.dv_xname); - goto fail2; + goto fail3; } error = bus_dmamem_map(sc->sc_dmat, &seg, nsegs, size, &virtaddr, @@ -1707,7 +1597,7 @@ iwi_load_firmware(struct iwi_softc *sc, const char *data, int size) if (error != 0) { printf("%s: could not map firmware DMA memory\n", sc->sc_dev.dv_xname); - goto fail3; + goto fail4; } error = bus_dmamap_load(sc->sc_dmat, map, virtaddr, size, NULL, @@ -1715,11 +1605,11 @@ iwi_load_firmware(struct iwi_softc *sc, const char *data, int size) if (error != 0) { printf("%s: could not load firmware DMA map\n", sc->sc_dev.dv_xname); - goto fail4; + goto fail5; } /* copy firmware image to DMA memory */ - bcopy(data, virtaddr, size); + bcopy(fw, virtaddr, size); /* make sure the adapter will get up-to-date values */ bus_dmamap_sync(sc->sc_dmat, map, 0, size, BUS_DMASYNC_PREWRITE); @@ -1732,7 +1622,7 @@ iwi_load_firmware(struct iwi_softc *sc, const char *data, int size) * indirections. The adapter will read the firmware image through DMA * using information stored in command blocks. */ - src = map->dm_segs[0].ds_addr; + src = map->dm_segs->ds_addr; p = virtaddr; end = p + size; CSR_WRITE_4(sc, IWI_CSR_AUTOINC_ADDR, 0x27000); @@ -1779,7 +1669,7 @@ iwi_load_firmware(struct iwi_softc *sc, const char *data, int size) if (ntries == 400) { printf("%s: timeout processing cb\n", sc->sc_dev.dv_xname); error = EIO; - goto fail5; + goto fail6; } /* we're done with command blocks processing */ @@ -1790,7 +1680,6 @@ iwi_load_firmware(struct iwi_softc *sc, const char *data, int size) /* tell the adapter to initialize the firmware */ CSR_WRITE_4(sc, IWI_CSR_RST, 0); - CSR_WRITE_4(sc, IWI_CSR_CTL, CSR_READ_4(sc, IWI_CSR_CTL) | IWI_CTL_ALLOW_STANDBY); @@ -1798,14 +1687,16 @@ iwi_load_firmware(struct iwi_softc *sc, const char *data, int size) if ((error = tsleep(sc, 0, "iwiinit", hz)) != 0) { printf("%s: timeout waiting for firmware initialization to " "complete\n", sc->sc_dev.dv_xname); - goto fail5; + goto fail6; } -fail5: bus_dmamap_sync(sc->sc_dmat, map, 0, size, BUS_DMASYNC_POSTWRITE); +fail6: bus_dmamap_sync(sc->sc_dmat, map, 0, size, BUS_DMASYNC_POSTWRITE); bus_dmamap_unload(sc->sc_dmat, map); -fail4: bus_dmamem_unmap(sc->sc_dmat, virtaddr, size); -fail3: bus_dmamem_free(sc->sc_dmat, &seg, 1); -fail2: bus_dmamap_destroy(sc->sc_dmat, map); +fail5: bus_dmamem_unmap(sc->sc_dmat, virtaddr, size); +fail4: bus_dmamem_free(sc->sc_dmat, &seg, 1); +fail3: bus_dmamap_destroy(sc->sc_dmat, map); +fail2: free(data, M_DEVBUF); + fail1: return error; } @@ -1831,11 +1722,11 @@ iwi_config(struct iwi_softc *sc) bzero(&config, sizeof config); config.bluetooth_coexistence = 1; - config.antenna = 2; /* antenna diversity */ config.multicast_enabled = 1; config.answer_pbreq = (ic->ic_opmode == IEEE80211_M_IBSS) ? 1 : 0; DPRINTF(("Configuring adapter\n")); - error = iwi_cmd(sc, IWI_CMD_SET_CONFIG, &config, sizeof config, 0); + error = iwi_cmd(sc, IWI_CMD_SET_CONFIGURATION, &config, sizeof config, + 0); if (error != 0) return error; @@ -2019,14 +1910,13 @@ iwi_auth_and_assoc(struct iwi_softc *sc) /* enable b/g autodection */ bzero(&config, sizeof config); config.bluetooth_coexistence = 1; - config.antenna = 2; /* antenna diversity */ config.multicast_enabled = 1; config.bg_autodetection = 1; config.answer_pbreq = (ic->ic_opmode == IEEE80211_M_IBSS) ? 1 : 0; DPRINTF(("Configuring adapter\n")); - error = iwi_cmd(sc, IWI_CMD_SET_CONFIG, &config, sizeof config, - 1); + error = iwi_cmd(sc, IWI_CMD_SET_CONFIGURATION, &config, + sizeof config, 1); if (error != 0) return error; } @@ -2096,112 +1986,90 @@ iwi_init(struct ifnet *ifp) { struct iwi_softc *sc = ifp->if_softc; struct ieee80211com *ic = &sc->sc_ic; - struct iwi_firmware_hdr *hdr; - const char *name, *fw; - u_char *data; - size_t size; + const char *ucode, *main; int i, error; if ((error = iwi_reset(sc)) != 0) { printf("%s: could not reset adapter\n", sc->sc_dev.dv_xname); - goto fail1; + goto fail; + } + + if ((error = iwi_load_firmware(sc, "iwi-boot")) != 0) { + printf("%s: could not load boot firmware\n", + sc->sc_dev.dv_xname); + goto fail; } switch (sc->sc_ic.ic_opmode) { case IEEE80211_M_STA: case IEEE80211_M_HOSTAP: - name = "iwi-bss"; + ucode = "iwi-ucode-bss"; + main = "iwi-bss"; break; + case IEEE80211_M_IBSS: case IEEE80211_M_AHDEMO: - name = "iwi-ibss"; + ucode = "iwi-ucode-ibss"; + main = "iwi-ibss"; break; + case IEEE80211_M_MONITOR: - name = "iwi-monitor"; + ucode = "iwi-ucode-monitor"; + main = "iwi-monitor"; break; - default: - name = NULL; /* should not get there */ } - if ((error = loadfirmware(name, &data, &size)) != 0) { - printf("%s: could not read firmware %s\n", - sc->sc_dev.dv_xname, name); - goto fail1; - } - - if (size < sizeof (struct iwi_firmware_hdr)) { - printf("%s: firmware image too short: %zu bytes\n", - sc->sc_dev.dv_xname, size); - goto fail2; - } - - hdr = (struct iwi_firmware_hdr *)data; - - if (size < sizeof (struct iwi_firmware_hdr) + letoh32(hdr->bootsz) + - letoh32(hdr->ucodesz) + letoh32(hdr->mainsz)) { - printf("%s: firmware image too short: %zu bytes\n", - sc->sc_dev.dv_xname, size); - goto fail2; - } - - fw = (const char *)data + sizeof (struct iwi_firmware_hdr); - if ((error = iwi_load_firmware(sc, fw, letoh32(hdr->bootsz))) != 0) { - printf("%s: could not load boot firmware\n", - sc->sc_dev.dv_xname); - goto fail2; - } - - fw = (const char *)data + sizeof (struct iwi_firmware_hdr) + - letoh32(hdr->bootsz); - if ((error = iwi_load_ucode(sc, fw, letoh32(hdr->ucodesz))) != 0) { + if ((error = iwi_load_ucode(sc, ucode)) != 0) { printf("%s: could not load microcode\n", sc->sc_dev.dv_xname); - goto fail2; + goto fail; } iwi_stop_master(sc); - CSR_WRITE_4(sc, IWI_CSR_CMD_BASE, sc->cmdq.map->dm_segs[0].ds_addr); - CSR_WRITE_4(sc, IWI_CSR_CMD_SIZE, IWI_CMD_RING_COUNT); - CSR_WRITE_4(sc, IWI_CSR_CMD_WIDX, sc->cmdq.cur); + sc->tx_cur = 0; + sc->tx_queued = 0; + sc->tx_old = IWI_TX_RING_SIZE - 1; + sc->cmd_cur = 0; + sc->rx_cur = IWI_RX_RING_SIZE - 1; - CSR_WRITE_4(sc, IWI_CSR_TX1_BASE, sc->txq[0].map->dm_segs[0].ds_addr); - CSR_WRITE_4(sc, IWI_CSR_TX1_SIZE, IWI_TX_RING_COUNT); - CSR_WRITE_4(sc, IWI_CSR_TX1_WIDX, sc->txq[0].cur); + CSR_WRITE_4(sc, IWI_CSR_CMD_BASE, sc->cmd_ring_map->dm_segs->ds_addr); + CSR_WRITE_4(sc, IWI_CSR_CMD_SIZE, IWI_CMD_RING_SIZE); + CSR_WRITE_4(sc, IWI_CSR_CMD_WRITE_INDEX, sc->cmd_cur); - CSR_WRITE_4(sc, IWI_CSR_TX2_BASE, sc->txq[1].map->dm_segs[0].ds_addr); - CSR_WRITE_4(sc, IWI_CSR_TX2_SIZE, IWI_TX_RING_COUNT); - CSR_WRITE_4(sc, IWI_CSR_TX2_WIDX, sc->txq[1].cur); + CSR_WRITE_4(sc, IWI_CSR_TX1_BASE, sc->tx_ring_map->dm_segs->ds_addr); + CSR_WRITE_4(sc, IWI_CSR_TX1_SIZE, IWI_TX_RING_SIZE); + CSR_WRITE_4(sc, IWI_CSR_TX1_WRITE_INDEX, sc->tx_cur); - CSR_WRITE_4(sc, IWI_CSR_TX3_BASE, sc->txq[2].map->dm_segs[0].ds_addr); - CSR_WRITE_4(sc, IWI_CSR_TX3_SIZE, IWI_TX_RING_COUNT); - CSR_WRITE_4(sc, IWI_CSR_TX3_WIDX, sc->txq[2].cur); + CSR_WRITE_4(sc, IWI_CSR_TX2_BASE, sc->tx_ring_map->dm_segs->ds_addr); + CSR_WRITE_4(sc, IWI_CSR_TX2_SIZE, IWI_TX_RING_SIZE); + CSR_WRITE_4(sc, IWI_CSR_TX2_WRITE_INDEX, sc->tx_cur); - CSR_WRITE_4(sc, IWI_CSR_TX4_BASE, sc->txq[3].map->dm_segs[0].ds_addr); - CSR_WRITE_4(sc, IWI_CSR_TX4_SIZE, IWI_TX_RING_COUNT); - CSR_WRITE_4(sc, IWI_CSR_TX4_WIDX, sc->txq[3].cur); + CSR_WRITE_4(sc, IWI_CSR_TX3_BASE, sc->tx_ring_map->dm_segs->ds_addr); + CSR_WRITE_4(sc, IWI_CSR_TX3_SIZE, IWI_TX_RING_SIZE); + CSR_WRITE_4(sc, IWI_CSR_TX3_WRITE_INDEX, sc->tx_cur); - for (i = 0; i < IWI_RX_RING_COUNT; i++) { - struct iwi_rx_data *data = &sc->rxq.data[i]; - CSR_WRITE_4(sc, data->reg, data->map->dm_segs[0].ds_addr); - } + CSR_WRITE_4(sc, IWI_CSR_TX4_BASE, sc->tx_ring_map->dm_segs->ds_addr); + CSR_WRITE_4(sc, IWI_CSR_TX4_SIZE, IWI_TX_RING_SIZE); + CSR_WRITE_4(sc, IWI_CSR_TX4_WRITE_INDEX, sc->tx_cur); - CSR_WRITE_4(sc, IWI_CSR_RX_WIDX, IWI_RX_RING_COUNT - 1); + for (i = 0; i < IWI_RX_RING_SIZE; i++) + CSR_WRITE_4(sc, IWI_CSR_RX_BASE + i * 4, + sc->rx_buf[i].map->dm_segs->ds_addr); - fw = (const char *)data + sizeof (struct iwi_firmware_hdr) + - letoh32(hdr->bootsz) + letoh32(hdr->ucodesz); - if ((error = iwi_load_firmware(sc, fw, letoh32(hdr->mainsz))) != 0) { + CSR_WRITE_4(sc, IWI_CSR_RX_WRITE_INDEX, sc->rx_cur); + + if ((error = iwi_load_firmware(sc, main)) != 0) { printf("%s: could not load main firmware\n", sc->sc_dev.dv_xname); - goto fail2; + goto fail; } - free(data, M_DEVBUF); sc->flags |= IWI_FLAG_FW_INITED; if ((error = iwi_config(sc)) != 0) { printf("%s: device configuration failed\n", sc->sc_dev.dv_xname); - goto fail1; + goto fail; } if (ic->ic_opmode != IEEE80211_M_MONITOR) @@ -2214,8 +2082,8 @@ iwi_init(struct ifnet *ifp) return 0; -fail2: free(data, M_DEVBUF); -fail1: iwi_stop(ifp, 0); +fail: iwi_stop(ifp, 0); + return error; } @@ -2224,6 +2092,8 @@ iwi_stop(struct ifnet *ifp, int disable) { struct iwi_softc *sc = ifp->if_softc; struct ieee80211com *ic = &sc->sc_ic; + struct iwi_tx_buf *buf; + int i; sc->sc_tx_timer = 0; ifp->if_timer = 0; @@ -2232,16 +2102,21 @@ iwi_stop(struct ifnet *ifp, int disable) ieee80211_new_state(ic, IEEE80211_S_INIT, -1); iwi_stop_master(sc); - CSR_WRITE_4(sc, IWI_CSR_RST, IWI_RST_SW_RESET); - /* reset rings */ - iwi_reset_cmd_ring(sc, &sc->cmdq); - iwi_reset_tx_ring(sc, &sc->txq[0]); - iwi_reset_tx_ring(sc, &sc->txq[1]); - iwi_reset_tx_ring(sc, &sc->txq[2]); - iwi_reset_tx_ring(sc, &sc->txq[3]); - iwi_reset_rx_ring(sc, &sc->rxq); + /* + * Release Tx buffers. + */ + for (i = 0; i < IWI_TX_RING_SIZE; i++) { + buf = &sc->tx_buf[i]; + + if (buf->m != NULL) { + bus_dmamap_unload(sc->sc_dmat, buf->map); + m_freem(buf->m); + buf->m = NULL; + } + buf->ni = NULL; + } } struct cfdriver iwi_cd = { diff --git a/sys/dev/pci/if_iwireg.h b/sys/dev/pci/if_iwireg.h index 99fe34ee0d8..e01947ad329 100644 --- a/sys/dev/pci/if_iwireg.h +++ b/sys/dev/pci/if_iwireg.h @@ -1,4 +1,4 @@ -/* $OpenBSD: if_iwireg.h,v 1.21 2006/03/27 20:46:35 damien Exp $ */ +/* $OpenBSD: if_iwireg.h,v 1.22 2006/03/31 17:18:37 pedro Exp $ */ /*- * Copyright (c) 2004-2006 @@ -27,9 +27,9 @@ * SUCH DAMAGE. */ -#define IWI_CMD_RING_COUNT 16 -#define IWI_TX_RING_COUNT 64 -#define IWI_RX_RING_COUNT 32 +#define IWI_TX_RING_SIZE 64 +#define IWI_CMD_RING_SIZE 16 +#define IWI_RX_RING_SIZE 32 #define IWI_CSR_INTR 0x0008 #define IWI_CSR_INTR_MASK 0x000c @@ -50,42 +50,41 @@ #define IWI_CSR_TX3_SIZE 0x021c #define IWI_CSR_TX4_BASE 0x0220 #define IWI_CSR_TX4_SIZE 0x0224 -#define IWI_CSR_CMD_RIDX 0x0280 -#define IWI_CSR_TX1_RIDX 0x0284 -#define IWI_CSR_TX2_RIDX 0x0288 -#define IWI_CSR_TX3_RIDX 0x028c -#define IWI_CSR_TX4_RIDX 0x0290 -#define IWI_CSR_RX_RIDX 0x02a0 +#define IWI_CSR_CMD_READ_INDEX 0x0280 +#define IWI_CSR_TX1_READ_INDEX 0x0284 +#define IWI_CSR_TX2_READ_INDEX 0x0288 +#define IWI_CSR_TX3_READ_INDEX 0x028c +#define IWI_CSR_TX4_READ_INDEX 0x0290 +#define IWI_CSR_RX_READ_INDEX 0x02a0 #define IWI_CSR_RX_BASE 0x0500 #define IWI_CSR_TABLE0_SIZE 0x0700 #define IWI_CSR_TABLE0_BASE 0x0704 #define IWI_CSR_NODE_BASE 0x0c0c -#define IWI_CSR_CMD_WIDX 0x0f80 -#define IWI_CSR_TX1_WIDX 0x0f84 -#define IWI_CSR_TX2_WIDX 0x0f88 -#define IWI_CSR_TX3_WIDX 0x0f8c -#define IWI_CSR_TX4_WIDX 0x0f90 -#define IWI_CSR_RX_WIDX 0x0fa0 -#define IWI_CSR_READ_INT 0x0ff4 - -/* aliases */ #define IWI_CSR_CURRENT_TX_RATE IWI_CSR_TABLE0_BASE +#define IWI_CSR_CMD_WRITE_INDEX 0x0f80 +#define IWI_CSR_TX1_WRITE_INDEX 0x0f84 +#define IWI_CSR_TX2_WRITE_INDEX 0x0f88 +#define IWI_CSR_TX3_WRITE_INDEX 0x0f8c +#define IWI_CSR_TX4_WRITE_INDEX 0x0f90 +#define IWI_CSR_RX_WRITE_INDEX 0x0fa0 +#define IWI_CSR_READ_INT 0x0ff4 /* possible flags for IWI_CSR_INTR */ -#define IWI_INTR_RX_DONE 0x00000002 -#define IWI_INTR_CMD_DONE 0x00000800 -#define IWI_INTR_TX1_DONE 0x00001000 -#define IWI_INTR_TX2_DONE 0x00002000 -#define IWI_INTR_TX3_DONE 0x00004000 -#define IWI_INTR_TX4_DONE 0x00008000 +#define IWI_INTR_RX_TRANSFER 0x00000002 +#define IWI_INTR_CMD_TRANSFER 0x00000800 +#define IWI_INTR_TX1_TRANSFER 0x00001000 +#define IWI_INTR_TX2_TRANSFER 0x00002000 +#define IWI_INTR_TX3_TRANSFER 0x00004000 +#define IWI_INTR_TX4_TRANSFER 0x00008000 #define IWI_INTR_FW_INITED 0x01000000 #define IWI_INTR_RADIO_OFF 0x04000000 #define IWI_INTR_FATAL_ERROR 0x40000000 #define IWI_INTR_PARITY_ERROR 0x80000000 #define IWI_INTR_MASK \ - (IWI_INTR_RX_DONE | IWI_INTR_CMD_DONE | IWI_INTR_TX1_DONE | \ - IWI_INTR_TX2_DONE | IWI_INTR_TX3_DONE | IWI_INTR_TX4_DONE | \ + (IWI_INTR_RX_TRANSFER | IWI_INTR_CMD_TRANSFER | \ + IWI_INTR_TX1_TRANSFER | IWI_INTR_TX2_TRANSFER | \ + IWI_INTR_TX3_TRANSFER | IWI_INTR_TX4_TRANSFER | \ IWI_INTR_FW_INITED | IWI_INTR_RADIO_OFF | \ IWI_INTR_FATAL_ERROR | IWI_INTR_PARITY_ERROR) @@ -130,9 +129,7 @@ /* firmware binary image header */ struct iwi_firmware_hdr { uint32_t version; - uint32_t bootsz; - uint32_t ucodesz; - uint32_t mainsz; + uint32_t mode; } __packed; struct iwi_hdr { @@ -141,11 +138,9 @@ struct iwi_hdr { #define IWI_HDR_TYPE_COMMAND 1 #define IWI_HDR_TYPE_NOTIF 3 #define IWI_HDR_TYPE_FRAME 9 - uint8_t seq; uint8_t flags; #define IWI_HDR_FLAG_IRQ 0x04 - uint8_t reserved; } __packed; @@ -159,7 +154,6 @@ struct iwi_notif { #define IWI_NOTIF_TYPE_BEACON 17 #define IWI_NOTIF_TYPE_CALIBRATION 20 #define IWI_NOTIF_TYPE_NOISE 25 - uint8_t flags; uint16_t len; } __packed; @@ -176,7 +170,6 @@ struct iwi_notif_association { uint8_t state; #define IWI_DEASSOCIATED 0 #define IWI_ASSOCIATED 12 - struct ieee80211_frame frame; uint16_t capinfo; uint16_t status; @@ -222,7 +215,6 @@ struct iwi_tx_desc { uint8_t reserved2[3]; uint8_t cmd; #define IWI_DATA_CMD_TX 0x0b - uint8_t seq; uint16_t len; uint8_t priority; @@ -230,7 +222,6 @@ struct iwi_tx_desc { #define IWI_DATA_FLAG_SHPREAMBLE 0x04 #define IWI_DATA_FLAG_NO_WEP 0x20 #define IWI_DATA_FLAG_NEED_ACK 0x80 - uint8_t xflags; uint8_t wep_txkey; uint8_t wepkey[IEEE80211_KEYBUF_SIZE]; @@ -243,7 +234,6 @@ struct iwi_tx_desc { uint32_t nseg; #define IWI_MAX_NSEG 6 -#define IWI_MAX_SCATTER (IWI_MAX_NSEG - 2) uint32_t seg_addr[IWI_MAX_NSEG]; uint16_t seg_len[IWI_MAX_NSEG]; @@ -253,22 +243,21 @@ struct iwi_tx_desc { struct iwi_cmd_desc { struct iwi_hdr hdr; uint8_t type; -#define IWI_CMD_ENABLE 2 -#define IWI_CMD_SET_CONFIG 6 -#define IWI_CMD_SET_ESSID 8 -#define IWI_CMD_SET_MAC_ADDRESS 11 -#define IWI_CMD_SET_RTS_THRESHOLD 15 -#define IWI_CMD_SET_FRAG_THRESHOLD 16 -#define IWI_CMD_SET_POWER_MODE 17 -#define IWI_CMD_SET_WEP_KEY 18 -#define IWI_CMD_ASSOCIATE 21 -#define IWI_CMD_SET_RATES 22 -#define IWI_CMD_SCAN 26 -#define IWI_CMD_DISABLE 33 -#define IWI_CMD_SET_IV 34 -#define IWI_CMD_SET_TX_POWER 35 -#define IWI_CMD_SET_SENSITIVITY 42 - +#define IWI_CMD_ENABLE 2 +#define IWI_CMD_SET_CONFIGURATION 6 +#define IWI_CMD_SET_ESSID 8 +#define IWI_CMD_SET_MAC_ADDRESS 11 +#define IWI_CMD_SET_RTS_THRESHOLD 15 +#define IWI_CMD_SET_FRAG_THRESHOLD 16 +#define IWI_CMD_SET_POWER_MODE 17 +#define IWI_CMD_SET_WEP_KEY 18 +#define IWI_CMD_ASSOCIATE 21 +#define IWI_CMD_SET_RATES 22 +#define IWI_CMD_SCAN 26 +#define IWI_CMD_DISABLE 33 +#define IWI_CMD_SET_IV 34 +#define IWI_CMD_SET_TX_POWER 35 +#define IWI_CMD_SET_SENSITIVITY 42 uint8_t len; uint16_t reserved; uint8_t data[120]; @@ -285,6 +274,9 @@ struct iwi_node { #define IWI_MODE_11B 1 #define IWI_MODE_11G 2 +/* macro for command IWI_CMD_SET_SENSITIVITY */ +#define IWI_RSSIDBM2RAW(rssi) ((rssi) - 112) + /* possible values for command IWI_CMD_SET_POWER_MODE */ #define IWI_POWER_MODE_CAM 0 @@ -295,7 +287,6 @@ struct iwi_rateset { uint8_t type; #define IWI_RATESET_TYPE_NEGOTIATED 0 #define IWI_RATESET_TYPE_SUPPORTED 1 - uint8_t reserved; uint8_t rates[12]; } __packed; @@ -319,7 +310,6 @@ struct iwi_associate { #define IWI_AUTH_OPEN 0 #define IWI_AUTH_SHARED 1 #define IWI_AUTH_NONE 3 - uint8_t type; uint8_t reserved1; uint16_t reserved2; @@ -384,7 +374,6 @@ struct iwi_configuration { struct iwi_wep_key { uint8_t cmd; #define IWI_WEP_KEY_CMD_SETKEY 0x08 - uint8_t seq; uint8_t idx; uint8_t len; diff --git a/sys/dev/pci/if_iwivar.h b/sys/dev/pci/if_iwivar.h index 3218973f381..ed0eb4b8a79 100644 --- a/sys/dev/pci/if_iwivar.h +++ b/sys/dev/pci/if_iwivar.h @@ -1,4 +1,4 @@ -/* $OpenBSD: if_iwivar.h,v 1.14 2006/03/27 20:46:35 damien Exp $ */ +/* $OpenBSD: if_iwivar.h,v 1.15 2006/03/31 17:18:37 pedro Exp $ */ /*- * Copyright (c) 2004-2006 @@ -55,45 +55,6 @@ struct iwi_tx_radiotap_header { ((1 << IEEE80211_RADIOTAP_FLAGS) | \ (1 << IEEE80211_RADIOTAP_CHANNEL)) - -struct iwi_cmd_ring { - bus_dmamap_t map; - bus_dma_segment_t seg; - struct iwi_cmd_desc desc[IWI_CMD_RING_COUNT]; - int queued; - int cur; - int next; -}; - -struct iwi_tx_data { - bus_dmamap_t map; - struct mbuf *m; - struct ieee80211_node *ni; -}; - -struct iwi_tx_ring { - bus_dmamap_t map; - bus_dma_segment_t seg; - bus_addr_t csr_ridx; - bus_addr_t csr_widx; - struct iwi_tx_desc *desc; - struct iwi_tx_data data[IWI_TX_RING_COUNT]; - int queued; - int cur; - int next; -}; - -struct iwi_rx_data { - bus_dmamap_t map; - struct mbuf *m; - uint32_t reg; -}; - -struct iwi_rx_ring { - struct iwi_rx_data data[IWI_RX_RING_COUNT]; - int cur; -}; - struct iwi_softc { struct device sc_dev; @@ -106,9 +67,31 @@ struct iwi_softc { bus_dma_tag_t sc_dmat; - struct iwi_cmd_ring cmdq; - struct iwi_tx_ring txq[4]; - struct iwi_rx_ring rxq; + struct iwi_tx_desc *tx_desc; + bus_dmamap_t tx_ring_map; + bus_dma_segment_t tx_ring_seg; + + struct iwi_tx_buf { + bus_dmamap_t map; + struct mbuf *m; + struct ieee80211_node *ni; + } tx_buf[IWI_TX_RING_SIZE]; + + int tx_cur; + int tx_old; + int tx_queued; + + struct iwi_cmd_desc *cmd_desc; + bus_dmamap_t cmd_ring_map; + bus_dma_segment_t cmd_ring_seg; + int cmd_cur; + + struct iwi_rx_buf { + bus_dmamap_t map; + struct mbuf *m; + } rx_buf[IWI_RX_RING_SIZE]; + + int rx_cur; #define IWI_MAX_NODE 32 uint8_t sta[IWI_MAX_NODE][IEEE80211_ADDR_LEN]; |