diff options
Diffstat (limited to 'sys/dev/pci/if_iwi.c')
-rw-r--r-- | sys/dev/pci/if_iwi.c | 789 |
1 files changed, 457 insertions, 332 deletions
diff --git a/sys/dev/pci/if_iwi.c b/sys/dev/pci/if_iwi.c index e744161efe1..c9e7a7fda11 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.63 2006/03/31 17:18:36 pedro Exp $ */ +/* $OpenBSD: if_iwi.c,v 1.64 2006/04/01 01:04:40 pedro Exp $ */ /*- * Copyright (c) 2004-2006 @@ -97,19 +97,27 @@ 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_dma_alloc(struct iwi_softc *); -void iwi_release(struct iwi_softc *); +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_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_buf *, int, +void iwi_frame_intr(struct iwi_softc *, struct iwi_rx_data *, struct iwi_frame *); -void iwi_notification_intr(struct iwi_softc *, struct iwi_rx_buf *, +void iwi_notification_intr(struct iwi_softc *, struct iwi_rx_data *, struct iwi_notif *); void iwi_rx_intr(struct iwi_softc *); -void iwi_tx_intr(struct iwi_softc *); +void iwi_tx_intr(struct iwi_softc *, struct iwi_tx_ring *); int iwi_intr(void *); int iwi_cmd(struct iwi_softc *, uint8_t, void *, uint8_t, int); int iwi_tx_start(struct ifnet *, struct mbuf *, @@ -121,8 +129,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 iwi_load_firmware(struct iwi_softc *, const char *); +int iwi_load_ucode(struct iwi_softc *, const char *, int); +int iwi_load_firmware(struct iwi_softc *, const char *, int); int iwi_config(struct iwi_softc *); int iwi_set_chan(struct iwi_softc *, struct ieee80211_channel *); int iwi_scan(struct iwi_softc *); @@ -203,9 +211,6 @@ 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; @@ -228,19 +233,61 @@ iwi_attach(struct device *parent, struct device *self, void *aux) return; } - if (iwi_dma_alloc(sc) != 0) { - printf(": could not allocate DMA resources\n"); + /* + * Allocate rings. + */ + error = iwi_alloc_cmd_ring(sc, &sc->cmdq); + if (error != 0) { + printf(": could not allocate Cmd ring\n"); return; } - ic->ic_phytype = IEEE80211_T_OFDM; - ic->ic_opmode = IEEE80211_M_STA; + 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_state = IEEE80211_S_INIT; /* set device capabilities */ - ic->ic_caps = IEEE80211_C_IBSS | IEEE80211_C_PMGT | IEEE80211_C_WEP | - IEEE80211_C_TXPMGT | IEEE80211_C_SHPREAMBLE | IEEE80211_C_MONITOR | - IEEE80211_C_SCANALL; + 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 */ /* read MAC address from EEPROM */ val = iwi_read_prom_word(sc, IWI_EEPROM_MAC + 0); @@ -321,6 +368,14 @@ 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 @@ -334,7 +389,12 @@ iwi_detach(struct device* self, int flags) ieee80211_ifdetach(ifp); if_detach(ifp); - iwi_release(sc); + 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); if (sc->sc_ih != NULL) { pci_intr_disestablish(sc->sc_pct, sc->sc_ih); @@ -370,193 +430,268 @@ iwi_power(int why, void *arg) } int -iwi_dma_alloc(struct iwi_softc *sc) +iwi_alloc_cmd_ring(struct iwi_softc *sc, struct iwi_cmd_ring *ring) { - int i, nsegs, error; + int nsegs, error; + + ring->queued = 0; + ring->cur = ring->next = 0; - /* - * Allocate and map Tx ring. - */ error = bus_dmamap_create(sc->sc_dmat, - 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); + 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); if (error != 0) { - printf("%s: could not create tx ring DMA map\n", + printf("%s: could not create cmd 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_SIZE, PAGE_SIZE, 0, - &sc->tx_ring_seg, 1, &nsegs, BUS_DMA_NOWAIT); + sizeof (struct iwi_cmd_desc) * IWI_CMD_RING_COUNT, PAGE_SIZE, 0, + &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 cmd ring DMA memory\n", sc->sc_dev.dv_xname); goto fail; } - 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); + 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); if (error != 0) { - printf("%s: could not map tx ring DMA memory\n", + printf("%s: could not map cmd ring DMA memory\n", sc->sc_dev.dv_xname); goto fail; } - error = bus_dmamap_load(sc->sc_dmat, sc->tx_ring_map, sc->tx_desc, - sizeof (struct iwi_tx_desc) * IWI_TX_RING_SIZE, NULL, + error = bus_dmamap_load(sc->sc_dmat, ring->map, ring->desc, + sizeof (struct iwi_cmd_desc) * IWI_CMD_RING_COUNT, NULL, BUS_DMA_NOWAIT); if (error != 0) { - printf("%s: could not load tx ring DMA map\n", + printf("%s: could not load cmd ring DMA map\n", sc->sc_dev.dv_xname); goto fail; } - bzero(sc->tx_desc, sizeof (struct iwi_tx_desc) * IWI_TX_RING_SIZE); + 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; - /* - * Allocate and map command ring. - */ error = bus_dmamap_create(sc->sc_dmat, - 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); + 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); if (error != 0) { - printf("%s: could not create command 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_SIZE, PAGE_SIZE, 0, - &sc->cmd_ring_seg, 1, &nsegs, BUS_DMA_NOWAIT); + sizeof (struct iwi_tx_desc) * IWI_TX_RING_COUNT, PAGE_SIZE, 0, + &ring->seg, 1, &nsegs, BUS_DMA_NOWAIT); if (error != 0) { - printf("%s: could not allocate command 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, &sc->cmd_ring_seg, nsegs, - sizeof (struct iwi_cmd_desc) * IWI_CMD_RING_SIZE, - (caddr_t *)&sc->cmd_desc, BUS_DMA_NOWAIT); + 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); if (error != 0) { - printf("%s: could not map command 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, sc->cmd_ring_map, sc->cmd_desc, - sizeof (struct iwi_cmd_desc) * IWI_CMD_RING_SIZE, NULL, + error = bus_dmamap_load(sc->sc_dmat, ring->map, ring->desc, + sizeof (struct iwi_tx_desc) * IWI_TX_RING_COUNT, NULL, BUS_DMA_NOWAIT); if (error != 0) { - printf("%s: could not load command ring DMA map\n", + printf("%s: could not load tx ring DMA map\n", sc->sc_dev.dv_xname); goto fail; } - bzero(sc->cmd_desc, sizeof (struct iwi_cmd_desc) * IWI_CMD_RING_SIZE); + 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]; - /* - * Allocate Tx buffers DMA maps. - */ - for (i = 0; i < IWI_TX_RING_SIZE; i++) { error = bus_dmamap_create(sc->sc_dmat, MCLBYTES, - IWI_MAX_NSEG - 2, MCLBYTES, 0, BUS_DMA_NOWAIT, - &sc->tx_buf[i].map); + IWI_MAX_SCATTER, MCLBYTES, 0, BUS_DMA_NOWAIT, &data->map); if (error != 0) { - printf("%s: could not create tx buf DMA map", + printf("%s: could not create tx buf DMA map\n", sc->sc_dev.dv_xname); goto fail; } } - /* - * Allocate and map Rx buffers. - */ - for (i = 0; i < IWI_RX_RING_SIZE; i++) { + 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]; error = bus_dmamap_create(sc->sc_dmat, MCLBYTES, 1, MCLBYTES, - 0, BUS_DMA_NOWAIT, &sc->rx_buf[i].map); + 0, BUS_DMA_NOWAIT, &data->map); if (error != 0) { - printf("%s: could not create rx buf DMA map", + printf("%s: could not create rx buf DMA map\n", sc->sc_dev.dv_xname); goto fail; } - MGETHDR(sc->rx_buf[i].m, M_DONTWAIT, MT_DATA); - if (sc->rx_buf[i].m == NULL) { + 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; goto fail; } - 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); + MCLGET(data->m, M_DONTWAIT); + if (!(data->m->m_flags & M_EXT)) { + m_freem(data->m); + data->m = NULL; 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, sc->rx_buf[i].map, - mtod(sc->rx_buf[i].m, void *), MCLBYTES, NULL, - BUS_DMA_NOWAIT); + error = bus_dmamap_load(sc->sc_dmat, data->map, + mtod(data->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_release(sc); +fail: iwi_free_rx_ring(sc, ring); return error; } void -iwi_release(struct iwi_softc *sc) +iwi_reset_rx_ring(struct iwi_softc *sc, struct iwi_rx_ring *ring) { - int 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); - } + ring->cur = 0; +} - 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); - } +void +iwi_free_rx_ring(struct iwi_softc *sc, struct iwi_rx_ring *ring) +{ + struct iwi_rx_data *data; + int i; - 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); - } + for (i = 0; i < IWI_RX_RING_COUNT; i++) { + data = &sc->rxq.data[i]; - 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); + if (data->m != NULL) { + bus_dmamap_unload(sc->sc_dmat, data->map); + m_freem(data->m); } - bus_dmamap_destroy(sc->sc_dmat, sc->rx_buf[i].map); + bus_dmamap_destroy(sc->sc_dmat, data->map); } } @@ -769,7 +904,7 @@ iwi_read_prom_word(struct iwi_softc *sc, uint8_t addr) } void -iwi_frame_intr(struct iwi_softc *sc, struct iwi_rx_buf *buf, int i, +iwi_frame_intr(struct iwi_softc *sc, struct iwi_rx_data *data, struct iwi_frame *frame) { struct ieee80211com *ic = &sc->sc_ic; @@ -779,10 +914,10 @@ iwi_frame_intr(struct iwi_softc *sc, struct iwi_rx_buf *buf, int i, struct ieee80211_node *ni; int error; - DPRINTFN(5, ("RX!DATA!%u!%u!%u\n", letoh16(frame->len), frame->chan, - frame->rssi_dbm)); + DPRINTFN(5, ("received frame len=%u chan=%u rssi=%u\n", + letoh16(frame->len), frame->chan, frame->rssi_dbm)); - bus_dmamap_sync(sc->sc_dmat, buf->map, sizeof (struct iwi_hdr), + bus_dmamap_sync(sc->sc_dmat, data->map, sizeof (struct iwi_hdr), sizeof (struct iwi_frame) + letoh16(frame->len), BUS_DMASYNC_POSTREAD); @@ -812,16 +947,16 @@ iwi_frame_intr(struct iwi_softc *sc, struct iwi_rx_buf *buf, int i, return; } - bus_dmamap_unload(sc->sc_dmat, buf->map); + bus_dmamap_unload(sc->sc_dmat, data->map); - error = bus_dmamap_load(sc->sc_dmat, buf->map, mtod(mnew, void *), + error = bus_dmamap_load(sc->sc_dmat, data->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, buf->map, - mtod(buf->m, void *), MCLBYTES, NULL, BUS_DMA_NOWAIT); + error = bus_dmamap_load(sc->sc_dmat, data->map, + mtod(data->m, void *), MCLBYTES, NULL, BUS_DMA_NOWAIT); if (error != 0) { /* very unlikely that it will fail... */ panic("%s: could not load old rx mbuf", @@ -831,9 +966,9 @@ iwi_frame_intr(struct iwi_softc *sc, struct iwi_rx_buf *buf, int i, return; } - m = buf->m; - buf->m = mnew; - CSR_WRITE_4(sc, IWI_CSR_RX_BASE + i * 4, buf->map->dm_segs->ds_addr); + m = data->m; + data->m = mnew; + CSR_WRITE_4(sc, data->reg, data->map->dm_segs[0].ds_addr); /* finalize mbuf */ m->m_pkthdr.rcvif = ifp; @@ -886,11 +1021,12 @@ iwi_frame_intr(struct iwi_softc *sc, struct iwi_rx_buf *buf, int i, /* 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_buf *buf, +iwi_notification_intr(struct iwi_softc *sc, struct iwi_rx_data *data, struct iwi_notif *notif) { struct ieee80211com *ic = &sc->sc_ic; @@ -900,7 +1036,7 @@ iwi_notification_intr(struct iwi_softc *sc, struct iwi_rx_buf *buf, struct iwi_notif_authentication *auth; struct iwi_notif_association *assoc; - bus_dmamap_sync(sc->sc_dmat, buf->map, sizeof (struct iwi_hdr), + bus_dmamap_sync(sc->sc_dmat, data->map, sizeof (struct iwi_hdr), sizeof (struct iwi_notif) + letoh16(notif->len), BUS_DMASYNC_POSTREAD); @@ -908,7 +1044,7 @@ iwi_notification_intr(struct iwi_softc *sc, struct iwi_rx_buf *buf, case IWI_NOTIF_TYPE_SCAN_CHANNEL: chan = (struct iwi_notif_scan_channel *)(notif + 1); - DPRINTFN(2, ("Scan channel (%u)\n", chan->nchan)); + DPRINTFN(2, ("Scanning channel (%u)\n", chan->nchan)); break; case IWI_NOTIF_TYPE_SCAN_COMPLETE: @@ -976,30 +1112,28 @@ iwi_notification_intr(struct iwi_softc *sc, struct iwi_rx_buf *buf, void iwi_rx_intr(struct iwi_softc *sc) { - struct iwi_rx_buf *buf; + struct iwi_rx_data *data; struct iwi_hdr *hdr; - uint32_t r, i; + uint32_t hw; - r = CSR_READ_4(sc, IWI_CSR_RX_READ_INDEX); + hw = CSR_READ_4(sc, IWI_CSR_RX_RIDX); - for (i = (sc->rx_cur + 1) % IWI_RX_RING_SIZE; i != r; - i = (i + 1) % IWI_RX_RING_SIZE) { + for (; sc->rxq.cur != hw;) { + data = &sc->rxq.data[sc->rxq.cur]; - buf = &sc->rx_buf[i]; - - bus_dmamap_sync(sc->sc_dmat, buf->map, 0, + bus_dmamap_sync(sc->sc_dmat, data->map, 0, sizeof (struct iwi_hdr), BUS_DMASYNC_POSTREAD); - hdr = mtod(buf->m, struct iwi_hdr *); + hdr = mtod(data->m, struct iwi_hdr *); switch (hdr->type) { case IWI_HDR_TYPE_FRAME: - iwi_frame_intr(sc, buf, i, + iwi_frame_intr(sc, data, (struct iwi_frame *)(hdr + 1)); break; case IWI_HDR_TYPE_NOTIF: - iwi_notification_intr(sc, buf, + iwi_notification_intr(sc, data, (struct iwi_notif *)(hdr + 1)); break; @@ -1007,45 +1141,41 @@ 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 */ - sc->rx_cur = (r == 0) ? IWI_RX_RING_SIZE - 1 : r - 1; - CSR_WRITE_4(sc, IWI_CSR_RX_WRITE_INDEX, sc->rx_cur); + hw = (hw == 0) ? IWI_RX_RING_COUNT - 1 : hw - 1; + CSR_WRITE_4(sc, IWI_CSR_RX_WIDX, hw); } void -iwi_tx_intr(struct iwi_softc *sc) +iwi_tx_intr(struct iwi_softc *sc, struct iwi_tx_ring *txq) { struct ieee80211com *ic = &sc->sc_ic; struct ifnet *ifp = &ic->ic_if; - struct iwi_tx_buf *buf; - uint32_t r, i; - - r = CSR_READ_4(sc, IWI_CSR_TX1_READ_INDEX); + struct iwi_tx_data *data; + uint32_t hw; - for (i = (sc->tx_old + 1) % IWI_TX_RING_SIZE; i != r; - i = (i + 1) % IWI_TX_RING_SIZE) { + hw = CSR_READ_4(sc, txq->csr_ridx); - buf = &sc->tx_buf[i]; + for (; txq->next != hw;) { + data = &txq->data[txq->next]; - bus_dmamap_unload(sc->sc_dmat, buf->map); - m_freem(buf->m); - buf->m = NULL; - ieee80211_release_node(ic, buf->ni); - buf->ni = NULL; + bus_dmamap_unload(sc->sc_dmat, data->map); + m_freem(data->m); + data->m = NULL; + ieee80211_release_node(ic, data->ni); + data->ni = NULL; ifp->if_opackets++; - sc->tx_queued--; - /* kill watchdog timer */ - sc->sc_tx_timer = 0; + txq->queued--; + txq->next = (txq->next + 1) % IWI_TX_RING_COUNT; } - /* 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 */ + sc->sc_tx_timer = 0; ifp->if_flags &= ~IFF_OACTIVE; (*ifp->if_start)(ifp); } @@ -1062,11 +1192,13 @@ iwi_intr(void *arg) /* disable interrupts */ CSR_WRITE_4(sc, IWI_CSR_INTR_MASK, 0); - DPRINTFN(8, ("INTR!0x%08x\n", r)); + /* acknowledge interrupts */ + CSR_WRITE_4(sc, IWI_CSR_INTR, 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) { @@ -1077,19 +1209,26 @@ 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_RX_TRANSFER) - iwi_rx_intr(sc); - - if (r & IWI_INTR_CMD_TRANSFER) + if (r & IWI_INTR_CMD_DONE) wakeup(sc); - if (r & IWI_INTR_TX1_TRANSFER) - iwi_tx_intr(sc); + if (r & IWI_INTR_TX1_DONE) + iwi_tx_intr(sc, &sc->txq[0]); - /* acknowledge interrupts */ - CSR_WRITE_4(sc, IWI_CSR_INTR, r); + if (r & IWI_INTR_TX2_DONE) + iwi_tx_intr(sc, &sc->txq[1]); + + if (r & IWI_INTR_TX3_DONE) + iwi_tx_intr(sc, &sc->txq[2]); + + if (r & IWI_INTR_TX4_DONE) + iwi_tx_intr(sc, &sc->txq[3]); + + if (r & IWI_INTR_RX_DONE) + iwi_rx_intr(sc); /* re-enable interrupts */ CSR_WRITE_4(sc, IWI_CSR_INTR_MASK, IWI_INTR_MASK); @@ -1102,21 +1241,22 @@ iwi_cmd(struct iwi_softc *sc, uint8_t type, void *data, uint8_t len, int async) { struct iwi_cmd_desc *desc; - DPRINTFN(2, ("TX!CMD!%u!%u\n", type, len)); - - desc = &sc->cmd_desc[sc->cmd_cur]; + desc = &sc->cmdq.desc[sc->cmdq.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->cmd_ring_map, - sc->cmd_cur * sizeof (struct iwi_cmd_desc), + bus_dmamap_sync(sc->sc_dmat, sc->cmdq.map, + sc->cmdq.cur * sizeof (struct iwi_cmd_desc), sizeof (struct iwi_cmd_desc), BUS_DMASYNC_PREWRITE); - sc->cmd_cur = (sc->cmd_cur + 1) % IWI_CMD_RING_SIZE; - CSR_WRITE_4(sc, IWI_CSR_CMD_WRITE_INDEX, sc->cmd_cur); + 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); return async ? 0 : tsleep(sc, 0, "iwicmd", hz); } @@ -1126,8 +1266,9 @@ 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_buf *buf; + struct iwi_tx_data *data; struct iwi_tx_desc *desc; + struct iwi_tx_ring *txq = &sc->txq[0]; struct mbuf *mnew; int error, i, station = 0; @@ -1149,8 +1290,8 @@ iwi_tx_start(struct ifnet *ifp, struct mbuf *m0, struct ieee80211_node *ni) } #endif - buf = &sc->tx_buf[sc->tx_cur]; - desc = &sc->tx_desc[sc->tx_cur]; + data = &txq->data[txq->cur]; + desc = &txq->desc[txq->cur]; /* save and trim IEEE802.11 header */ m_copydata(m0, 0, sizeof (struct ieee80211_frame), (caddr_t)&desc->wh); @@ -1166,7 +1307,8 @@ iwi_tx_start(struct ifnet *ifp, struct mbuf *m0, struct ieee80211_node *ni) } } - error = bus_dmamap_load_mbuf(sc->sc_dmat, buf->map, m0, BUS_DMA_NOWAIT); + error = bus_dmamap_load_mbuf(sc->sc_dmat, data->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); @@ -1197,7 +1339,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, buf->map, m0, + error = bus_dmamap_load_mbuf(sc->sc_dmat, data->map, m0, BUS_DMA_NOWAIT); if (error != 0) { printf("%s: could not map mbuf (error %d)\n", @@ -1207,8 +1349,8 @@ iwi_tx_start(struct ifnet *ifp, struct mbuf *m0, struct ieee80211_node *ni) } } - buf->m = m0; - buf->ni = ni; + data->m = m0; + data->ni = ni; desc->hdr.type = IWI_HDR_TYPE_DATA; desc->hdr.flags = IWI_HDR_FLAG_IRQ; @@ -1229,25 +1371,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(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); + 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); } - bus_dmamap_sync(sc->sc_dmat, sc->tx_ring_map, - sc->tx_cur * sizeof (struct iwi_tx_desc), + bus_dmamap_sync(sc->sc_dmat, txq->map, + txq->cur * sizeof (struct iwi_tx_desc), sizeof (struct iwi_tx_desc), BUS_DMASYNC_PREWRITE); - bus_dmamap_sync(sc->sc_dmat, buf->map, 0, MCLBYTES, + bus_dmamap_sync(sc->sc_dmat, data->map, 0, MCLBYTES, BUS_DMASYNC_PREWRITE); - DPRINTFN(5, ("TX!DATA!%u!%u\n", letoh16(desc->len), desc->nseg)); + DPRINTFN(5, ("sending data frame idx=%u len=%u nseg=%u\n", txq->cur, + letoh16(desc->len), data->map->dm_nsegs)); - /* 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); + txq->queued++; + txq->cur = (txq->cur + 1) % IWI_TX_RING_COUNT; + CSR_WRITE_4(sc, txq->csr_widx, txq->cur); return 0; } @@ -1268,7 +1410,7 @@ iwi_start(struct ifnet *ifp) if (m0 == NULL) break; - if (sc->tx_queued >= IWI_TX_RING_SIZE - 8) { + if (sc->txq[0].queued >= IWI_TX_RING_COUNT - 8) { IF_PREPEND(&ifp->if_snd, m0); ifp->if_flags |= IFF_OACTIVE; break; @@ -1414,8 +1556,10 @@ 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); @@ -1434,7 +1578,6 @@ 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 */ @@ -1443,8 +1586,11 @@ iwi_reset(struct iwi_softc *sc) break; DELAY(200); } - if (ntries == 1000) + if (ntries == 1000) { + printf("%s: timeout waiting for clock stabilization\n", + sc->sc_dev.dv_xname); return EIO; + } CSR_WRITE_4(sc, IWI_CSR_RST, CSR_READ_4(sc, IWI_CSR_RST) | IWI_RST_SW_RESET); @@ -1463,27 +1609,10 @@ iwi_reset(struct iwi_softc *sc) } int -iwi_load_ucode(struct iwi_softc *sc, const char *name) +iwi_load_ucode(struct iwi_softc *sc, const char *data, int size) { - 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); + const uint16_t *w; + int ntries, i; CSR_WRITE_4(sc, IWI_CSR_RST, CSR_READ_4(sc, IWI_CSR_RST) | IWI_RST_STOP_MASTER); @@ -1493,15 +1622,17 @@ iwi_load_ucode(struct iwi_softc *sc, const char *name) DELAY(10); } if (ntries == 5) { - printf("%s: timeout waiting for master\n", sc->sc_dev.dv_xname); - error = EIO; - goto fail2; + printf("%s: timeout waiting for master\n", + sc->sc_dev.dv_xname); + return EIO; } 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); @@ -1511,15 +1642,16 @@ iwi_load_ucode(struct iwi_softc *sc, const char *name) 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 = (uint16_t *)uc; size > 0; w++, size -= 2) + for (w = (const uint16_t *)data; 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 a response in the uc queue */ + /* wait until we get an answer */ for (ntries = 0; ntries < 100; ntries++) { if (MEM_READ_1(sc, 0x200000) & 1) break; @@ -1528,27 +1660,24 @@ iwi_load_ucode(struct iwi_softc *sc, const char *name) if (ntries == 100) { printf("%s: timeout waiting for ucode to initialize\n", sc->sc_dev.dv_xname); - error = EIO; - goto fail2; + return EIO; } - /* empty the uc queue or the firmware will not initialize properly */ + /* read the answer or the firmware will not initialize properly */ for (i = 0; i < 7; i++) MEM_READ_4(sc, 0x200004); MEM_WRITE_1(sc, 0x200000, 0x00); -fail2: free(data, M_DEVBUF); -fail1: return error; + return 0; } /* 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 *name) +iwi_load_firmware(struct iwi_softc *sc, const char *data, int size) { - u_char *fw, *data; - size_t size; bus_dmamap_t map; bus_dma_segment_t seg; caddr_t virtaddr; @@ -1556,40 +1685,21 @@ iwi_load_firmware(struct iwi_softc *sc, const char *name) 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 fail2; + goto fail1; } - /* - * 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 fail3; + goto fail2; } error = bus_dmamem_map(sc->sc_dmat, &seg, nsegs, size, &virtaddr, @@ -1597,7 +1707,7 @@ iwi_load_firmware(struct iwi_softc *sc, const char *name) if (error != 0) { printf("%s: could not map firmware DMA memory\n", sc->sc_dev.dv_xname); - goto fail4; + goto fail3; } error = bus_dmamap_load(sc->sc_dmat, map, virtaddr, size, NULL, @@ -1605,11 +1715,11 @@ iwi_load_firmware(struct iwi_softc *sc, const char *name) if (error != 0) { printf("%s: could not load firmware DMA map\n", sc->sc_dev.dv_xname); - goto fail5; + goto fail4; } /* copy firmware image to DMA memory */ - bcopy(fw, virtaddr, size); + bcopy(data, virtaddr, size); /* make sure the adapter will get up-to-date values */ bus_dmamap_sync(sc->sc_dmat, map, 0, size, BUS_DMASYNC_PREWRITE); @@ -1622,7 +1732,7 @@ iwi_load_firmware(struct iwi_softc *sc, const char *name) * indirections. The adapter will read the firmware image through DMA * using information stored in command blocks. */ - src = map->dm_segs->ds_addr; + src = map->dm_segs[0].ds_addr; p = virtaddr; end = p + size; CSR_WRITE_4(sc, IWI_CSR_AUTOINC_ADDR, 0x27000); @@ -1669,7 +1779,7 @@ iwi_load_firmware(struct iwi_softc *sc, const char *name) if (ntries == 400) { printf("%s: timeout processing cb\n", sc->sc_dev.dv_xname); error = EIO; - goto fail6; + goto fail5; } /* we're done with command blocks processing */ @@ -1680,6 +1790,7 @@ iwi_load_firmware(struct iwi_softc *sc, const char *name) /* 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); @@ -1687,16 +1798,14 @@ iwi_load_firmware(struct iwi_softc *sc, const char *name) if ((error = tsleep(sc, 0, "iwiinit", hz)) != 0) { printf("%s: timeout waiting for firmware initialization to " "complete\n", sc->sc_dev.dv_xname); - goto fail6; + goto fail5; } -fail6: bus_dmamap_sync(sc->sc_dmat, map, 0, size, BUS_DMASYNC_POSTWRITE); +fail5: bus_dmamap_sync(sc->sc_dmat, map, 0, size, BUS_DMASYNC_POSTWRITE); bus_dmamap_unload(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); - +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); fail1: return error; } @@ -1722,11 +1831,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_CONFIGURATION, &config, sizeof config, - 0); + error = iwi_cmd(sc, IWI_CMD_SET_CONFIG, &config, sizeof config, 0); if (error != 0) return error; @@ -1910,13 +2019,14 @@ 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_CONFIGURATION, &config, - sizeof config, 1); + error = iwi_cmd(sc, IWI_CMD_SET_CONFIG, &config, sizeof config, + 1); if (error != 0) return error; } @@ -1986,90 +2096,112 @@ iwi_init(struct ifnet *ifp) { struct iwi_softc *sc = ifp->if_softc; struct ieee80211com *ic = &sc->sc_ic; - const char *ucode, *main; + struct iwi_firmware_hdr *hdr; + const char *name, *fw; + u_char *data; + size_t size; int i, error; if ((error = iwi_reset(sc)) != 0) { printf("%s: could not reset adapter\n", sc->sc_dev.dv_xname); - 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; + goto fail1; } switch (sc->sc_ic.ic_opmode) { case IEEE80211_M_STA: case IEEE80211_M_HOSTAP: - ucode = "iwi-ucode-bss"; - main = "iwi-bss"; + name = "iwi-bss"; break; - case IEEE80211_M_IBSS: case IEEE80211_M_AHDEMO: - ucode = "iwi-ucode-ibss"; - main = "iwi-ibss"; + name = "iwi-ibss"; break; - case IEEE80211_M_MONITOR: - ucode = "iwi-ucode-monitor"; - main = "iwi-monitor"; + name = "iwi-monitor"; break; + default: + name = NULL; /* should not get there */ } - if ((error = iwi_load_ucode(sc, ucode)) != 0) { + 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) { printf("%s: could not load microcode\n", sc->sc_dev.dv_xname); - goto fail; + goto fail2; } iwi_stop_master(sc); - 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_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_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); - 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_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_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_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_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); + 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_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_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); - 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); + 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_RX_WRITE_INDEX, sc->rx_cur); + CSR_WRITE_4(sc, IWI_CSR_RX_WIDX, IWI_RX_RING_COUNT - 1); - if ((error = iwi_load_firmware(sc, main)) != 0) { + 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) { printf("%s: could not load main firmware\n", sc->sc_dev.dv_xname); - goto fail; + goto fail2; } + 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 fail; + goto fail1; } if (ic->ic_opmode != IEEE80211_M_MONITOR) @@ -2082,8 +2214,8 @@ iwi_init(struct ifnet *ifp) return 0; -fail: iwi_stop(ifp, 0); - +fail2: free(data, M_DEVBUF); +fail1: iwi_stop(ifp, 0); return error; } @@ -2092,8 +2224,6 @@ 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; @@ -2102,21 +2232,16 @@ 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); - /* - * Release Tx buffers. - */ - for (i = 0; i < IWI_TX_RING_SIZE; i++) { - buf = &sc->tx_buf[i]; + CSR_WRITE_4(sc, IWI_CSR_RST, IWI_RST_SW_RESET); - if (buf->m != NULL) { - bus_dmamap_unload(sc->sc_dmat, buf->map); - m_freem(buf->m); - buf->m = NULL; - } - buf->ni = NULL; - } + /* 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); } struct cfdriver iwi_cd = { |