diff options
author | Damien Bergamini <damien@cvs.openbsd.org> | 2007-06-05 19:49:41 +0000 |
---|---|---|
committer | Damien Bergamini <damien@cvs.openbsd.org> | 2007-06-05 19:49:41 +0000 |
commit | 7987ac2d6221b197fb87ff8d60173b9843b4c856 (patch) | |
tree | e8317730d3228a7288ad129b986a06c6757a3c40 /sys/dev | |
parent | 30c408d46337ee2569d1a697b68b5fd4816f706c (diff) |
Major wpi(4) update:
1/ Update the driver to use the new firmware images from Intel (2.14.3.)
2/ Read the list of supported channels from the EEPROM instead of having
it hard-coded in the driver.
3/ Limit output power to what is specified in EEPROM.
4/ Decrease output power for highest OFDM rates to reduce distortion.
5/ Automatically adjust output power to temperature changes for increased
throughput and range.
6/ Attach the adapter's onboard thermal sensor to the sensor framework.
7/ Replace 'magic' fields in structures with their correct definitions.
NOTE1: you must upgrade your wpi-firmware package to rev 2.14.3 or the
driver will stop working.
NOTE2: if you are using a channel not allowed by the regulatory domain
of your adapter, you will no longer be able to associate.
Diffstat (limited to 'sys/dev')
-rw-r--r-- | sys/dev/pci/if_wpi.c | 979 | ||||
-rw-r--r-- | sys/dev/pci/if_wpireg.h | 261 | ||||
-rw-r--r-- | sys/dev/pci/if_wpivar.h | 38 |
3 files changed, 856 insertions, 422 deletions
diff --git a/sys/dev/pci/if_wpi.c b/sys/dev/pci/if_wpi.c index 9eba593dccc..68fd4aa0b2e 100644 --- a/sys/dev/pci/if_wpi.c +++ b/sys/dev/pci/if_wpi.c @@ -1,7 +1,7 @@ -/* $OpenBSD: if_wpi.c,v 1.38 2007/01/03 18:19:06 claudio Exp $ */ +/* $OpenBSD: if_wpi.c,v 1.39 2007/06/05 19:49:40 damien Exp $ */ /*- - * Copyright (c) 2006 + * Copyright (c) 2006, 2007 * Damien Bergamini <damien.bergamini@free.fr> * * Permission to use, copy, modify, and distribute this software for any @@ -33,6 +33,7 @@ #include <sys/malloc.h> #include <sys/conf.h> #include <sys/device.h> +#include <sys/sensors.h> #include <machine/bus.h> #include <machine/endian.h> @@ -69,11 +70,6 @@ const struct pci_matchid wpi_devices[] = { { PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_PRO_WL_3945ABG_2 } }; -static const uint8_t wpi_ridx_to_plcp[] = { - 0xd, 0xf, 0x5, 0x7, 0x9, 0xb, 0x1, 0x3, /* OFDM R1-R4 */ - 10, 20, 55, 110 /* CCK */ -}; - int wpi_match(struct device *, void *, void *); void wpi_attach(struct device *, struct device *, void *); void wpi_power(int, void *); @@ -82,6 +78,8 @@ int wpi_dma_contig_alloc(bus_dma_tag_t, struct wpi_dma_info *, 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 *); @@ -94,20 +92,21 @@ int wpi_alloc_tx_ring(struct wpi_softc *, struct wpi_tx_ring *, void wpi_reset_tx_ring(struct wpi_softc *, struct wpi_tx_ring *); void wpi_free_tx_ring(struct wpi_softc *, struct wpi_tx_ring *); struct ieee80211_node *wpi_node_alloc(struct ieee80211com *); +void wpi_newassoc(struct ieee80211com *, struct ieee80211_node *, + int); int wpi_media_change(struct ifnet *); int wpi_newstate(struct ieee80211com *, enum ieee80211_state, int); void wpi_mem_lock(struct wpi_softc *); void wpi_mem_unlock(struct wpi_softc *); uint32_t wpi_mem_read(struct wpi_softc *, uint16_t); void wpi_mem_write(struct wpi_softc *, uint16_t, uint32_t); -void wpi_mem_write_region_4(struct wpi_softc *, uint16_t, - const uint32_t *, int); -uint16_t wpi_read_prom_word(struct wpi_softc *, uint32_t); -int wpi_load_microcode(struct wpi_softc *, const char *, int); -int wpi_load_firmware_block(struct wpi_softc *, uint32_t, - bus_dma_segment_t *); -int wpi_load_firmware(struct wpi_softc *, uint32_t, const char *, +int wpi_read_prom_data(struct wpi_softc *, uint32_t, void *, int); +int wpi_load_segment(struct wpi_softc *, uint32_t, const uint8_t *, int); +int wpi_load_firmware(struct wpi_softc *); +void wpi_calib_timeout(void *); +void wpi_iter_func(void *, struct ieee80211_node *); +void wpi_power_calibration(struct wpi_softc *, int); void wpi_rx_intr(struct wpi_softc *, struct wpi_rx_desc *, struct wpi_rx_data *); void wpi_tx_intr(struct wpi_softc *, struct wpi_rx_desc *); @@ -115,6 +114,8 @@ void wpi_cmd_intr(struct wpi_softc *, struct wpi_rx_desc *); void wpi_notif_intr(struct wpi_softc *); int wpi_intr(void *); void wpi_read_eeprom(struct wpi_softc *); +void wpi_read_eeprom_channels(struct wpi_softc *, int); +void wpi_read_eeprom_group(struct wpi_softc *, int); uint8_t wpi_plcp_signal(int); int wpi_tx_data(struct wpi_softc *, struct mbuf *, struct ieee80211_node *, int); @@ -125,6 +126,10 @@ int wpi_cmd(struct wpi_softc *, int, const void *, int, int); int wpi_mrr_setup(struct wpi_softc *); void wpi_set_led(struct wpi_softc *, uint8_t, uint8_t, uint8_t); void wpi_enable_tsf(struct wpi_softc *, struct ieee80211_node *); +int wpi_set_txpower(struct wpi_softc *, + struct ieee80211_channel *); +int wpi_get_power_index(struct wpi_softc *, + struct wpi_power_group *, struct ieee80211_channel *, int); int wpi_setup_beacon(struct wpi_softc *, struct ieee80211_node *); int wpi_auth(struct wpi_softc *); int wpi_scan(struct wpi_softc *, uint16_t); @@ -135,10 +140,6 @@ int wpi_reset(struct wpi_softc *); void wpi_hw_config(struct wpi_softc *); int wpi_init(struct ifnet *); void wpi_stop(struct ifnet *, int); -void wpi_iter_func(void *, struct ieee80211_node *); -void wpi_amrr_timeout(void *); -void wpi_newassoc(struct ieee80211com *, struct ieee80211_node *, - int); #ifdef WPI_DEBUG #define DPRINTF(x) do { if (wpi_debug > 0) printf x; } while (0) @@ -175,7 +176,7 @@ wpi_attach(struct device *parent, struct device *self, void *aux) bus_space_handle_t memh; pci_intr_handle_t ih; pcireg_t data; - int i, ac, error; + int ac, error; sc->sc_pct = pa->pa_pc; sc->sc_pcitag = pa->pa_tag; @@ -223,16 +224,24 @@ wpi_attach(struct device *parent, struct device *self, void *aux) } /* + * Allocate DMA memory for firmware transfers. + */ + if ((error = wpi_alloc_fwmem(sc)) != 0) { + printf(": could not allocate firmware memory\n"); + return; + } + + /* * Allocate shared page and Tx/Rx rings. */ if ((error = wpi_alloc_shared(sc)) != 0) { printf(": could not allocate shared area\n"); - return; + goto fail1; } if ((error = wpi_alloc_rpool(sc)) != 0) { printf(": could not allocate Rx buffers\n"); - goto fail1; + goto fail2; } for (ac = 0; ac < 4; ac++) { @@ -240,26 +249,26 @@ wpi_attach(struct device *parent, struct device *self, void *aux) ac); if (error != 0) { printf(": could not allocate Tx ring %d\n", ac); - goto fail2; + goto fail3; } } error = wpi_alloc_tx_ring(sc, &sc->cmdq, WPI_CMD_RING_COUNT, 4); if (error != 0) { printf(": could not allocate command ring\n"); - goto fail2; + goto fail3; } error = wpi_alloc_tx_ring(sc, &sc->svcq, WPI_SVC_RING_COUNT, 5); if (error != 0) { printf(": could not allocate service ring\n"); - goto fail3; + goto fail4; } error = wpi_alloc_rx_ring(sc, &sc->rxq); if (error != 0) { printf(": could not allocate Rx ring\n"); - goto fail4; + goto fail5; } ic->ic_phytype = IEEE80211_T_OFDM; /* not only, but not used */ @@ -274,42 +283,15 @@ wpi_attach(struct device *parent, struct device *self, void *aux) IEEE80211_C_SHSLOT | /* short slot time supported */ IEEE80211_C_SHPREAMBLE; /* short preamble supported */ + /* read supported channels and MAC address from EEPROM */ wpi_read_eeprom(sc); printf(", address %s\n", ether_sprintf(ic->ic_myaddr)); - /* set supported .11a rates */ + /* set supported .11a, .11b and .11g rates */ ic->ic_sup_rates[IEEE80211_MODE_11A] = ieee80211_std_rateset_11a; - - /* set supported .11a channels */ - for (i = 36; i <= 64; i += 4) { - ic->ic_channels[i].ic_freq = - ieee80211_ieee2mhz(i, IEEE80211_CHAN_5GHZ); - ic->ic_channels[i].ic_flags = IEEE80211_CHAN_A; - } - for (i = 100; i <= 140; i += 4) { - ic->ic_channels[i].ic_freq = - ieee80211_ieee2mhz(i, IEEE80211_CHAN_5GHZ); - ic->ic_channels[i].ic_flags = IEEE80211_CHAN_A; - } - for (i = 149; i <= 165; i += 4) { - ic->ic_channels[i].ic_freq = - ieee80211_ieee2mhz(i, IEEE80211_CHAN_5GHZ); - ic->ic_channels[i].ic_flags = IEEE80211_CHAN_A; - } - - /* set supported .11b and .11g rates */ ic->ic_sup_rates[IEEE80211_MODE_11B] = ieee80211_std_rateset_11b; ic->ic_sup_rates[IEEE80211_MODE_11G] = ieee80211_std_rateset_11g; - /* set supported .11b and .11g channels (1 through 14) */ - for (i = 1; i <= 14; i++) { - ic->ic_channels[i].ic_freq = - ieee80211_ieee2mhz(i, IEEE80211_CHAN_2GHZ); - ic->ic_channels[i].ic_flags = - IEEE80211_CHAN_CCK | IEEE80211_CHAN_OFDM | - IEEE80211_CHAN_DYN | IEEE80211_CHAN_2GHZ; - } - /* IBSS channel undefined for now */ ic->ic_ibss_chan = &ic->ic_channels[0]; @@ -320,7 +302,7 @@ wpi_attach(struct device *parent, struct device *self, void *aux) ifp->if_start = wpi_start; ifp->if_watchdog = wpi_watchdog; IFQ_SET_READY(&ifp->if_snd); - bcopy(sc->sc_dev.dv_xname, ifp->if_xname, IFNAMSIZ); + memcpy(ifp->if_xname, sc->sc_dev.dv_xname, IFNAMSIZ); if_attach(ifp); ieee80211_ifattach(ifp); @@ -334,7 +316,21 @@ wpi_attach(struct device *parent, struct device *self, void *aux) sc->amrr.amrr_min_success_threshold = 1; sc->amrr.amrr_max_success_threshold = 15; - timeout_set(&sc->amrr_ch, wpi_amrr_timeout, sc); + + /* register thermal sensor with the sensor framework */ + strlcpy(sc->sensordev.xname, sc->sc_dev.dv_xname, + sizeof sc->sensordev.xname); + strlcpy(sc->sensor.desc, "temperature 0..285", + sizeof sc->sensor.desc); + sc->sensor.type = SENSOR_INTEGER; /* not in muK! */ + sc->sensor.status = SENSOR_S_OK; + /* temperature invalid until interface is up */ + sc->sensor.value = 0; + sc->sensor.flags = SENSOR_FINVALID; + sensordev_install(&sc->sensordev); + sensor_attach(&sc->sensordev, &sc->sensor); + + timeout_set(&sc->calib_to, wpi_calib_timeout, sc); sc->powerhook = powerhook_establish(wpi_power, sc); @@ -353,12 +349,14 @@ wpi_attach(struct device *parent, struct device *self, void *aux) return; -fail4: wpi_free_tx_ring(sc, &sc->svcq); -fail3: wpi_free_tx_ring(sc, &sc->cmdq); -fail2: while (--ac >= 0) + /* free allocated memory if something failed during attachment */ +fail5: wpi_free_tx_ring(sc, &sc->svcq); +fail4: wpi_free_tx_ring(sc, &sc->cmdq); +fail3: while (--ac >= 0) wpi_free_tx_ring(sc, &sc->txq[ac]); wpi_free_rpool(sc); -fail1: wpi_free_shared(sc); +fail2: wpi_free_shared(sc); +fail1: wpi_free_fwmem(sc); } void @@ -413,7 +411,7 @@ wpi_dma_contig_alloc(bus_dma_tag_t tag, struct wpi_dma_info *dma, void **kvap, if (error != 0) goto fail; - bzero(dma->vaddr, size); + memset(dma->vaddr, 0, size); dma->paddr = dma->map->dm_segs[0].ds_addr; if (kvap != NULL) @@ -446,17 +444,10 @@ wpi_dma_contig_free(struct wpi_dma_info *dma) int wpi_alloc_shared(struct wpi_softc *sc) { - int error; - /* must be aligned on a 4K-page boundary */ - error = wpi_dma_contig_alloc(sc->sc_dmat, &sc->shared_dma, + return wpi_dma_contig_alloc(sc->sc_dmat, &sc->shared_dma, (void **)&sc->shared, sizeof (struct wpi_shared), PAGE_SIZE, BUS_DMA_NOWAIT); - if (error != 0) { - printf("%s: could not allocate shared area DMA memory\n", - sc->sc_dev.dv_xname); - } - return error; } void @@ -465,6 +456,24 @@ wpi_free_shared(struct wpi_softc *sc) wpi_dma_contig_free(&sc->shared_dma); } +/* + * Allocate DMA-safe memory for firmware transfer. + */ +int +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_MAIN_TEXT_MAXSZ + WPI_FW_MAIN_DATA_MAXSZ, 0, + BUS_DMA_NOWAIT); +} + +void +wpi_free_fwmem(struct wpi_softc *sc) +{ + wpi_dma_contig_free(&sc->fw_dma); +} + struct wpi_rbuf * wpi_alloc_rbuf(struct wpi_softc *sc) { @@ -653,7 +662,7 @@ wpi_alloc_tx_ring(struct wpi_softc *sc, struct wpi_tx_ring *ring, int count, goto fail; } - bzero(ring->data, count * sizeof (struct wpi_tx_data)); + memset(ring->data, 0, count * sizeof (struct wpi_tx_data)); for (i = 0; i < count; i++) { struct wpi_tx_data *data = &ring->data[i]; @@ -737,10 +746,25 @@ wpi_node_alloc(struct ieee80211com *ic) wn = malloc(sizeof (struct wpi_node), M_DEVBUF, M_NOWAIT); if (wn != NULL) - bzero(wn, sizeof (struct wpi_node)); + memset(wn, 0, sizeof (struct wpi_node)); return (struct ieee80211_node *)wn; } +void +wpi_newassoc(struct ieee80211com *ic, struct ieee80211_node *ni, int isnew) +{ + struct wpi_softc *sc = ic->ic_if.if_softc; + int i; + + ieee80211_amrr_node_init(&sc->amrr, &((struct wpi_node *)ni)->amn); + + /* set rate to some reasonable initial value */ + for (i = ni->ni_rates.rs_nrates - 1; + i > 0 && (ni->ni_rates.rs_rates[i] & IEEE80211_RATE_VAL) > 72; + i--); + ni->ni_txrate = i; +} + int wpi_media_change(struct ifnet *ifp) { @@ -761,9 +785,10 @@ wpi_newstate(struct ieee80211com *ic, enum ieee80211_state nstate, int arg) { struct ifnet *ifp = &ic->ic_if; struct wpi_softc *sc = ifp->if_softc; + struct ieee80211_node *ni; int error; - timeout_del(&sc->amrr_ch); + timeout_del(&sc->calib_to); switch (nstate) { case IEEE80211_S_SCAN: @@ -784,7 +809,7 @@ wpi_newstate(struct ieee80211com *ic, enum ieee80211_state nstate, int arg) /* FALLTHROUGH */ case IEEE80211_S_AUTH: /* reset state to handle reassociations correctly */ - sc->config.state = 0; + sc->config.associd = 0; sc->config.filter &= ~htole32(WPI_FILTER_BSS); if ((error = wpi_auth(sc)) != 0) { @@ -800,11 +825,12 @@ wpi_newstate(struct ieee80211com *ic, enum ieee80211_state nstate, int arg) wpi_set_led(sc, WPI_LED_LINK, 5, 5); break; } + ni = ic->ic_bss; - wpi_enable_tsf(sc, ic->ic_bss); + wpi_enable_tsf(sc, ni); /* update adapter's configuration */ - sc->config.state = htole16(WPI_STATE_ASSOCIATED); + sc->config.associd = htole16(ni->ni_associd & ~0xc000); /* short preamble/slot time are negotiated when associating */ sc->config.flags &= ~htole32(WPI_CONFIG_SHPREAMBLE | WPI_CONFIG_SHSLOT); @@ -824,14 +850,21 @@ wpi_newstate(struct ieee80211com *ic, enum ieee80211_state nstate, int arg) return error; } + /* configuration has changed, set Tx power accordingly */ + if ((error = wpi_set_txpower(sc, ni->ni_chan)) != 0) { + printf("%s: could not set Tx power\n", + sc->sc_dev.dv_xname); + return error; + } + if (ic->ic_opmode == IEEE80211_M_STA) { /* fake a join to init the tx rate */ - wpi_newassoc(ic, ic->ic_bss, 1); + wpi_newassoc(ic, ni, 1); } - /* start automatic rate control timer */ - if (ic->ic_fixed_rate == -1) - timeout_add(&sc->amrr_ch, hz / 2); + /* start periodic calibration timer */ + sc->calib_cnt = 0; + timeout_add(&sc->calib_to, hz / 2); /* link LED always on while associated */ wpi_set_led(sc, WPI_LED_LINK, 0, 1); @@ -891,93 +924,68 @@ wpi_mem_write(struct wpi_softc *sc, uint16_t addr, uint32_t data) WPI_WRITE(sc, WPI_WRITE_MEM_DATA, data); } -void -wpi_mem_write_region_4(struct wpi_softc *sc, uint16_t addr, - const uint32_t *data, int wlen) -{ - for (; wlen > 0; wlen--, data++, addr += 4) - wpi_mem_write(sc, addr, *data); -} - /* - * Read 16 bits from the EEPROM. We access EEPROM through the MAC instead of - * using the traditional bit-bang method. + * Read `len' bytes from the EEPROM. We access the EEPROM through the MAC + * instead of using the traditional bit-bang method. */ -uint16_t -wpi_read_prom_word(struct wpi_softc *sc, uint32_t addr) +int +wpi_read_prom_data(struct wpi_softc *sc, uint32_t addr, void *data, int len) { - int ntries; + uint8_t *out = data; uint32_t val; - - WPI_WRITE(sc, WPI_EEPROM_CTL, addr << 2); + int ntries; wpi_mem_lock(sc); - for (ntries = 0; ntries < 10; ntries++) { - if ((val = WPI_READ(sc, WPI_EEPROM_CTL)) & WPI_EEPROM_READY) - break; - DELAY(10); - } - wpi_mem_unlock(sc); + for (; len > 0; len -= 2, addr++) { + WPI_WRITE(sc, WPI_EEPROM_CTL, addr << 2); - if (ntries == 10) { - printf("%s: could not read EEPROM\n", sc->sc_dev.dv_xname); - return 0xdead; + for (ntries = 0; ntries < 10; ntries++) { + if ((val = WPI_READ(sc, WPI_EEPROM_CTL)) & + WPI_EEPROM_READY) + break; + DELAY(5); + } + if (ntries == 10) { + printf("%s: could not read EEPROM\n", + sc->sc_dev.dv_xname); + return ETIMEDOUT; + } + *out++ = val >> 16; + if (len > 1) + *out++ = val >> 24; } - return val >> 16; -} - -/* - * The firmware boot code is small and is intended to be copied directly into - * the NIC internal memory. - */ -int -wpi_load_microcode(struct wpi_softc *sc, const char *ucode, int size) -{ - /* check that microcode size is a multiple of 4 */ - if (size & 3) - return EINVAL; - - size /= sizeof (uint32_t); - - wpi_mem_lock(sc); - - /* copy microcode image into NIC memory */ - wpi_mem_write_region_4(sc, WPI_MEM_UCODE_BASE, (const uint32_t *)ucode, - size); - - wpi_mem_write(sc, WPI_MEM_UCODE_SRC, 0); - wpi_mem_write(sc, WPI_MEM_UCODE_DST, WPI_FW_TEXT); - wpi_mem_write(sc, WPI_MEM_UCODE_SIZE, size); - - /* run microcode */ - wpi_mem_write(sc, WPI_MEM_UCODE_CTL, WPI_UC_RUN); - wpi_mem_unlock(sc); return 0; } int -wpi_load_firmware_block(struct wpi_softc *sc, uint32_t target, - bus_dma_segment_t *seg) +wpi_load_segment(struct wpi_softc *sc, uint32_t target, const uint8_t *data, + int len) { + struct wpi_dma_info *dma = &sc->fw_dma; struct wpi_tx_desc desc; int ntries, error = 0; - DPRINTFN(2, ("loading firmware block target=%x addr=%x len=%d\n", - target, seg->ds_addr, seg->ds_len)); + DPRINTFN(2, ("loading firmware segment target=%x len=%d\n", target, + len)); - bzero(&desc, sizeof desc); - desc.flags = htole32(WPI_PAD32(seg->ds_len) << 28 | 1 << 24); - desc.segs[0].addr = htole32(seg->ds_addr); - desc.segs[0].len = htole32(seg->ds_len); + /* copy data to pre-allocated DMA-safe memory */ + memcpy(dma->vaddr, data, len); + bus_dmamap_sync(dma->tag, dma->map, 0, len, BUS_DMASYNC_PREWRITE); - /* tell adapter where to copy firmware block in its internal memory */ + /* setup Tx descriptor */ + memset(&desc, 0, sizeof desc); + desc.flags = htole32(WPI_PAD32(len) << 28 | 1 << 24); + desc.segs[0].addr = htole32(dma->paddr); + desc.segs[0].len = htole32(len); + + /* tell adapter where to copy data in its internal memory */ WPI_WRITE(sc, WPI_FW_TARGET, target); WPI_WRITE(sc, WPI_TX_CONFIG(6), 0); - /* copy firmware block descriptor into NIC memory */ + /* copy Tx descriptor into NIC memory */ WPI_WRITE_REGION_4(sc, WPI_TX_DESC(6), (uint32_t *)&desc, sizeof desc / sizeof (uint32_t)); @@ -985,14 +993,14 @@ wpi_load_firmware_block(struct wpi_softc *sc, uint32_t target, WPI_WRITE(sc, WPI_TX_STATE(6), 0x4001); WPI_WRITE(sc, WPI_TX_CONFIG(6), 0x80000001); - /* wait while the adapter is busy copying the firmware block */ + /* wait while the adapter transfers the block */ for (ntries = 0; ntries < 100; ntries++) { if (WPI_READ(sc, WPI_TX_STATUS) & WPI_TX_IDLE(6)) break; DELAY(1000); } if (ntries == 100) { - printf("%s: timeout transferring firmware block\n", + printf("%s: timeout transferring firmware segment\n", sc->sc_dev.dv_xname); error = ETIMEDOUT; } @@ -1002,60 +1010,194 @@ wpi_load_firmware_block(struct wpi_softc *sc, uint32_t target, return error; } -/* - * The firmware text and data segments are transferred to the NIC using DMA. - * The driver just DMA-maps the firmware and tells the NIC where to find it. - * Once the NIC has copied the firmware into its internal memory, we can free - * our local copy in the driver. - */ int -wpi_load_firmware(struct wpi_softc *sc, uint32_t target, const char *fw, - int size) +wpi_load_firmware(struct wpi_softc *sc) { - bus_dmamap_t map; - int i, nsegs, error; - - nsegs = 1 + ((size + PAGE_SIZE - 1) / PAGE_SIZE); + struct wpi_dma_info *dma = &sc->fw_dma; + const struct wpi_firmware_hdr *hdr; + const uint8_t *boot_text, *boot_data, *main_text, *main_data; + uint32_t main_textsz, main_datasz, boot_textsz, boot_datasz; + u_char *fw; + size_t size; + uint32_t tmp; + int error; - error = bus_dmamap_create(sc->sc_dmat, size, nsegs, WPI_MAX_SEG_LEN, - 0, BUS_DMA_NOWAIT, &map); - if (error != 0) { - printf("%s: could not create firmware DMA map (error=%d)\n", - sc->sc_dev.dv_xname, error); + /* load firmware image from disk */ + if ((error = loadfirmware("wpi-ucode", &fw, &size)) != 0) { + printf("%s: could not read firmware file\n", + sc->sc_dev.dv_xname); goto fail1; } - /* XXX: we're discarding a const qualifier here! */ - error = bus_dmamap_load(sc->sc_dmat, map, (void *)fw, size, NULL, - BUS_DMA_NOWAIT | BUS_DMA_WRITE); + /* extract firmware header information */ + if (size < sizeof (struct wpi_firmware_hdr)) { + printf("%s: truncated firmware header: %d bytes\n", + sc->sc_dev.dv_xname, size); + error = EINVAL; + goto fail2; + } + hdr = (const struct wpi_firmware_hdr *)fw; + main_textsz = letoh32(hdr->main_textsz); + main_datasz = letoh32(hdr->main_datasz); + boot_textsz = letoh32(hdr->boot_textsz); + boot_datasz = letoh32(hdr->boot_datasz); + + /* sanity-check firmware header */ + if (main_textsz > WPI_FW_MAIN_TEXT_MAXSZ) { + printf("%s: main .text segment too large: %u bytes\n", + sc->sc_dev.dv_xname, main_textsz); + error = EINVAL; + goto fail2; + } + if (main_datasz > WPI_FW_MAIN_DATA_MAXSZ) { + printf("%s: main .data segment too large: %u bytes\n", + sc->sc_dev.dv_xname, main_datasz); + error = EINVAL; + goto fail2; + } + if (boot_textsz > WPI_FW_BOOT_TEXT_MAXSZ) { + printf("%s: boot .text segment too large: %u bytes\n", + sc->sc_dev.dv_xname, boot_textsz); + error = EINVAL; + goto fail2; + } + if (boot_datasz > WPI_FW_BOOT_DATA_MAXSZ) { + printf("%s: boot .data segment too large: %u bytes\n", + sc->sc_dev.dv_xname, boot_datasz); + error = EINVAL; + goto fail2; + } + + /* check that all firmware segments are present */ + if (size < sizeof (struct wpi_firmware_hdr) + main_textsz + + main_datasz + boot_textsz + boot_datasz) { + printf("%s: firmware file too short: %d bytes\n", + sc->sc_dev.dv_xname, size); + error = EINVAL; + goto fail2; + } + + /* get pointers to firmware segments */ + main_text = (const uint8_t *)(hdr + 1); + main_data = main_text + main_textsz; + boot_text = main_data + main_datasz; + boot_data = boot_text + boot_textsz; + + /* load firmware boot .data segment into NIC */ + error = wpi_load_segment(sc, WPI_FW_DATA, boot_data, boot_datasz); if (error != 0) { - printf("%s: could not load firmware DMA map (error=%d)\n", - sc->sc_dev.dv_xname, error); + printf("%s: could not load firmware boot .data segment\n", + sc->sc_dev.dv_xname); goto fail2; } - DPRINTF(("load firmware target=%x size=%d nsegs=%d\n", target, size, - map->dm_nsegs)); + /* load firmware boot .text segment into NIC */ + error = wpi_load_segment(sc, WPI_FW_TEXT, boot_text, boot_textsz); + if (error != 0) { + printf("%s: could not load firmware boot .text segment\n", + sc->sc_dev.dv_xname); + goto fail2; + } - /* make sure the adapter will get up-to-date values */ - bus_dmamap_sync(sc->sc_dmat, map, 0, size, BUS_DMASYNC_PREWRITE); + /* copy firmware runtime into pre-allocated DMA-safe memory */ + memcpy(dma->vaddr, main_text, main_textsz); + memcpy(dma->vaddr + main_textsz, main_data, main_datasz); + bus_dmamap_sync(dma->tag, dma->map, 0, main_textsz + main_datasz, + BUS_DMASYNC_PREWRITE); + /* tell adapter where to find firmware runtime */ wpi_mem_lock(sc); - for (i = 0; i < map->dm_nsegs; i++) { - error = wpi_load_firmware_block(sc, target, &map->dm_segs[i]); - if (error != 0) - break; - target += map->dm_segs[i].ds_len; - } + wpi_mem_write(sc, WPI_MEM_MAIN_TEXT_BASE, dma->paddr); + wpi_mem_write(sc, WPI_MEM_MAIN_TEXT_SIZE, main_textsz); + wpi_mem_write(sc, WPI_MEM_MAIN_DATA_BASE, dma->paddr + main_textsz); + wpi_mem_write(sc, WPI_MEM_MAIN_DATA_SIZE, main_datasz); wpi_mem_unlock(sc); - bus_dmamap_sync(sc->sc_dmat, map, 0, size, BUS_DMASYNC_POSTWRITE); - bus_dmamap_unload(sc->sc_dmat, map); -fail2: bus_dmamap_destroy(sc->sc_dmat, map); + /* now press "execute" ;-) */ + tmp = WPI_READ(sc, WPI_RESET); + tmp &= ~(WPI_MASTER_DISABLED | WPI_STOP_MASTER | WPI_NEVO_RESET); + WPI_WRITE(sc, WPI_RESET, tmp); + + /* ..and wait at most one second for adapter to initialize */ + if ((error = tsleep(sc, PCATCH, "wpiinit", hz)) != 0) { + /* this isn't what was supposed to happen.. */ + printf("%s: timeout waiting for adapter to initialize\n", + sc->sc_dev.dv_xname); + } + +fail2: free(fw, M_DEVBUF); fail1: return error; } void +wpi_calib_timeout(void *arg) +{ + struct wpi_softc *sc = arg; + struct ieee80211com *ic = &sc->sc_ic; + int temp, s; + + /* automatic rate control triggered every 500ms */ + if (ic->ic_fixed_rate == -1) { + s = splnet(); + if (ic->ic_opmode == IEEE80211_M_STA) + wpi_iter_func(sc, ic->ic_bss); + else + ieee80211_iterate_nodes(ic, wpi_iter_func, sc); + splx(s); + } + + /* update sensor data */ + temp = (int)WPI_READ(sc, WPI_TEMPERATURE); + sc->sensor.value = temp + 260; + + /* automatic power calibration every 60s */ + if (++sc->calib_cnt >= 120) { + wpi_power_calibration(sc, temp); + sc->calib_cnt = 0; + } + + timeout_add(&sc->calib_to, hz / 2); +} + +void +wpi_iter_func(void *arg, struct ieee80211_node *ni) +{ + struct wpi_softc *sc = arg; + struct wpi_node *wn = (struct wpi_node *)ni; + + ieee80211_amrr_choose(&sc->amrr, ni, &wn->amn); +} + +/* + * This function is called periodically (every 60 seconds) to adjust output + * power to temperature changes. + */ +void +wpi_power_calibration(struct wpi_softc *sc, int temp) +{ + /* sanity-check read value */ + if (temp < -260 || temp > 25) { + /* this can't be correct, ignore */ + DPRINTF(("out-of-range temperature reported: %d\n", temp)); + return; + } + + DPRINTF(("temperature %d->%d\n", sc->temp, temp)); + + /* adjust Tx power if need be */ + if (abs(temp - sc->temp) <= 6) + return; + + sc->temp = temp; + + if (wpi_set_txpower(sc, sc->sc_ic.ic_bss->ni_chan) != 0) { + /* just warn, too bad for the automatic calibration... */ + printf("%s: could not adjust Tx power\n", + sc->sc_dev.dv_xname); + } +} + +void wpi_rx_intr(struct wpi_softc *sc, struct wpi_rx_desc *desc, struct wpi_rx_data *data) { @@ -1488,6 +1630,7 @@ wpi_tx_data(struct wpi_softc *sc, struct mbuf *m0, struct ieee80211_node *ni, cmd->idx = ring->cur; tx = (struct wpi_cmd_data *)cmd->data; + /* no need to zero tx, all fields are reinitialized here */ tx->flags = 0; if (!IEEE80211_IS_MULTICAST(wh->i_addr1)) { @@ -1541,7 +1684,7 @@ wpi_tx_data(struct wpi_softc *sc, struct mbuf *m0, struct ieee80211_node *ni, tx->ofdm_mask = 0xff; tx->cck_mask = 0x0f; - tx->lifetime = htole32(0xffffffff); + tx->lifetime = htole32(WPI_LIFETIME_INFINITE); tx->len = htole16(m0->m_pkthdr.len); @@ -1765,33 +1908,109 @@ wpi_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data) return error; } -/* - * Extract various information from EEPROM. - */ void wpi_read_eeprom(struct wpi_softc *sc) { struct ieee80211com *ic = &sc->sc_ic; - uint16_t val; int i; + wpi_read_prom_data(sc, WPI_EEPROM_CAPABILITIES, &sc->cap, 1); + wpi_read_prom_data(sc, WPI_EEPROM_REVISION, &sc->rev, 2); + wpi_read_prom_data(sc, WPI_EEPROM_TYPE, &sc->type, 1); + + DPRINTF(("cap=%x rev=%x type=%x\n", sc->cap, letoh16(sc->rev), + sc->type)); + /* read MAC address */ - val = wpi_read_prom_word(sc, WPI_EEPROM_MAC + 0); - ic->ic_myaddr[0] = val & 0xff; - ic->ic_myaddr[1] = val >> 8; - val = wpi_read_prom_word(sc, WPI_EEPROM_MAC + 1); - ic->ic_myaddr[2] = val & 0xff; - ic->ic_myaddr[3] = val >> 8; - val = wpi_read_prom_word(sc, WPI_EEPROM_MAC + 2); - ic->ic_myaddr[4] = val & 0xff; - ic->ic_myaddr[5] = val >> 8; - - /* read power settings for 2.4GHz channels */ - for (i = 0; i < 14; i++) { - sc->pwr1[i] = wpi_read_prom_word(sc, WPI_EEPROM_PWR1 + i); - sc->pwr2[i] = wpi_read_prom_word(sc, WPI_EEPROM_PWR2 + i); - DPRINTFN(2, ("channel %d pwr1 0x%04x pwr2 0x%04x\n", i + 1, - sc->pwr1[i], sc->pwr2[i])); + wpi_read_prom_data(sc, WPI_EEPROM_MAC, ic->ic_myaddr, 6); + + /* read the list of authorized channels */ + for (i = 0; i < WPI_CHAN_BANDS_COUNT; i++) + wpi_read_eeprom_channels(sc, i); + + /* read the list of power groups */ + for (i = 0; i < WPI_POWER_GROUPS_COUNT; i++) + wpi_read_eeprom_group(sc, i); +} + +void +wpi_read_eeprom_channels(struct wpi_softc *sc, int n) +{ + struct ieee80211com *ic = &sc->sc_ic; + const struct wpi_chan_band *band = &wpi_bands[n]; + struct wpi_eeprom_chan channels[WPI_MAX_CHAN_PER_BAND]; + int chan, i; + + wpi_read_prom_data(sc, band->addr, channels, + band->nchan * sizeof (struct wpi_eeprom_chan)); + + for (i = 0; i < band->nchan; i++) { + if (!(channels[i].flags & WPI_EEPROM_CHAN_VALID)) + continue; + + chan = band->chan[i]; + + if (n == 0) { /* 2GHz band */ + ic->ic_channels[chan].ic_freq = + ieee80211_ieee2mhz(chan, IEEE80211_CHAN_2GHZ); + ic->ic_channels[chan].ic_flags = + IEEE80211_CHAN_CCK | IEEE80211_CHAN_OFDM | + IEEE80211_CHAN_DYN | IEEE80211_CHAN_2GHZ; + + } else { /* 5GHz band */ + /* + * Some 3945abg adapters support channels 7, 8, 11 + * and 12 in the 2GHz *and* 5GHz bands. + * Because of limitations in our net80211(9) stack, + * we can't support these channels in 5GHz band. + */ + if (chan <= 14) + continue; + + ic->ic_channels[chan].ic_freq = + ieee80211_ieee2mhz(chan, IEEE80211_CHAN_5GHZ); + ic->ic_channels[chan].ic_flags = IEEE80211_CHAN_A; + } + + /* is active scan allowed on this channel? */ + if (!(channels[i].flags & WPI_EEPROM_CHAN_ACTIVE)) { + ic->ic_channels[chan].ic_flags |= + IEEE80211_CHAN_PASSIVE; + } + + /* save maximum allowed power for this channel */ + sc->maxpwr[chan] = channels[i].maxpwr; + + DPRINTF(("adding chan %d flags=0x%x maxpwr=%d\n", + chan, channels[i].flags, sc->maxpwr[chan])); + } +} + +void +wpi_read_eeprom_group(struct wpi_softc *sc, int n) +{ + struct wpi_power_group *group = &sc->groups[n]; + struct wpi_eeprom_group rgroup; + int i; + + wpi_read_prom_data(sc, WPI_EEPROM_POWER_GRP + n * 32, &rgroup, + sizeof rgroup); + + /* save power group information */ + group->chan = rgroup.chan; + group->maxpwr = rgroup.maxpwr; + /* temperature at which the samples were taken */ + group->temp = (int16_t)letoh16(rgroup.temp); + + DPRINTF(("power group %d: chan=%d maxpwr=%d temp=%d\n", n, + group->chan, group->maxpwr, group->temp)); + + for (i = 0; i < WPI_SAMPLES_COUNT; i++) { + group->samples[i].index = rgroup.samples[i].index; + group->samples[i].power = rgroup.samples[i].power; + + DPRINTF(("\tsample %d: index=%d power=%d\n", i, + group->samples[i].index, group->samples[i].power)); } } @@ -1814,7 +2033,7 @@ wpi_cmd(struct wpi_softc *sc, int code, const void *buf, int size, int async) cmd->flags = 0; cmd->qid = ring->qid; cmd->idx = ring->cur; - bcopy(buf, cmd->data, size); + memcpy(cmd->data, buf, size); desc->flags = htole32(WPI_PAD32(size) << 28 | 1 << 24); desc->segs[0].addr = htole32(ring->cmd_dma.paddr + @@ -1864,7 +2083,7 @@ wpi_mrr_setup(struct wpi_softc *sc) /* setup MRR for control frames */ mrr.which = htole32(WPI_MRR_CTL); - error = wpi_cmd(sc, WPI_CMD_MRR_SETUP, &mrr, sizeof mrr, 1); + error = wpi_cmd(sc, WPI_CMD_MRR_SETUP, &mrr, sizeof mrr, 0); if (error != 0) { printf("%s: could not setup MRR for control frames\n", sc->sc_dev.dv_xname); @@ -1873,7 +2092,7 @@ wpi_mrr_setup(struct wpi_softc *sc) /* setup MRR for data frames */ mrr.which = htole32(WPI_MRR_DATA); - error = wpi_cmd(sc, WPI_CMD_MRR_SETUP, &mrr, sizeof mrr, 1); + error = wpi_cmd(sc, WPI_CMD_MRR_SETUP, &mrr, sizeof mrr, 0); if (error != 0) { printf("%s: could not setup MRR for data frames\n", sc->sc_dev.dv_xname); @@ -1902,8 +2121,8 @@ wpi_enable_tsf(struct wpi_softc *sc, struct ieee80211_node *ni) struct wpi_cmd_tsf tsf; uint64_t val, mod; - bzero(&tsf, sizeof tsf); - bcopy(ni->ni_tstamp, &tsf.tstamp, sizeof (uint64_t)); + memset(&tsf, 0, sizeof tsf); + memcpy(&tsf.tstamp, ni->ni_tstamp, sizeof (uint64_t)); tsf.bintval = htole16(ni->ni_intval); tsf.lintval = htole16(10); @@ -1920,6 +2139,125 @@ wpi_enable_tsf(struct wpi_softc *sc, struct ieee80211_node *ni) } /* + * Update Tx power to match what is defined for channel `c'. + */ +int +wpi_set_txpower(struct wpi_softc *sc, struct ieee80211_channel *c) +{ + struct ieee80211com *ic = &sc->sc_ic; + struct wpi_power_group *group; + struct wpi_cmd_txpower txpower; + u_int chan; + int i; + + /* get channel number */ + chan = ieee80211_chan2ieee(ic, c); + + /* find the power group to which this channel belongs */ + if (IEEE80211_IS_CHAN_5GHZ(c)) { + for (group = &sc->groups[1]; group < &sc->groups[4]; group++) + if (chan <= group->chan) + break; + } else + group = &sc->groups[0]; + + memset(&txpower, 0, sizeof txpower); + txpower.band = IEEE80211_IS_CHAN_5GHZ(c) ? 0 : 1; + txpower.chan = htole16(chan); + + /* set Tx power for all OFDM and CCK rates */ + for (i = 0; i <= 11 ; i++) { + /* retrieve Tx power for this channel/rate combination */ + int idx = wpi_get_power_index(sc, group, c, + wpi_ridx_to_rate[i]); + + txpower.rates[i].plcp = wpi_ridx_to_plcp[i]; + + if (IEEE80211_IS_CHAN_5GHZ(c)) { + txpower.rates[i].rf_gain = wpi_rf_gain_5ghz[idx]; + txpower.rates[i].dsp_gain = wpi_dsp_gain_5ghz[idx]; + } else { + txpower.rates[i].rf_gain = wpi_rf_gain_2ghz[idx]; + txpower.rates[i].dsp_gain = wpi_dsp_gain_2ghz[idx]; + } + DPRINTF(("chan %d/rate %d: power index %d\n", chan, + wpi_ridx_to_rate[i], idx)); + } + + return wpi_cmd(sc, WPI_CMD_TXPOWER, &txpower, sizeof txpower, 1); +} + +/* + * Determine Tx power index for a given channel/rate combination. + * This takes into account the regulatory information from EEPROM and the + * current temperature. + */ +int +wpi_get_power_index(struct wpi_softc *sc, struct wpi_power_group *group, + struct ieee80211_channel *c, int rate) +{ +/* fixed-point arithmetic division using a n-bit fractional part */ +#define fdivround(a, b, n) \ + ((((1 << n) * (a)) / (b) + (1 << n) / 2) / (1 << n)) + +/* linear interpolation */ +#define interpolate(x, x1, y1, x2, y2, n) \ + ((y1) + fdivround(((x) - (x1)) * ((y2) - (y1)), (x2) - (x1), n)) + + struct ieee80211com *ic = &sc->sc_ic; + struct wpi_power_sample *sample; + int pwr, idx; + u_int chan; + + /* get channel number */ + chan = ieee80211_chan2ieee(ic, c); + + /* default power is group's maximum power - 3dB */ + pwr = group->maxpwr / 2; + + /* decrease power for highest OFDM rates to reduce distortion */ + switch (rate) { + case 72: /* 36Mb/s */ + pwr -= IEEE80211_IS_CHAN_2GHZ(c) ? 0 : 5; + break; + case 96: /* 48Mb/s */ + pwr -= IEEE80211_IS_CHAN_2GHZ(c) ? 7 : 10; + break; + case 108: /* 54Mb/s */ + pwr -= IEEE80211_IS_CHAN_2GHZ(c) ? 9 : 12; + break; + } + + /* never exceed channel's maximum allowed Tx power */ + pwr = min(pwr, sc->maxpwr[chan]); + + /* retrieve power index into gain tables from samples */ + for (sample = group->samples; sample < &group->samples[3]; sample++) + if (pwr > sample[1].power) + break; + /* fixed-point linear interpolation using a 19-bit fractional part */ + idx = interpolate(pwr, sample[0].power, sample[0].index, + sample[1].power, sample[1].index, 19); + + /* adjust power index based on current temperature */ + idx -= (sc->temp - group->temp) * 11 / 100; + + /* decrease power for CCK rates (-5dB) */ + if (!WPI_RATE_IS_OFDM(rate)) + idx += 10; + + /* keep power index in a valid range */ + if (idx < 0) + return 0; + if (idx > WPI_MAX_PWR_INDEX) + return WPI_MAX_PWR_INDEX; + return idx; + +#undef interpolate +#undef fdiv +} + +/* * Build a beacon frame that the firmware will broadcast periodically in * IBSS or HostAP modes. */ @@ -1952,11 +2290,11 @@ wpi_setup_beacon(struct wpi_softc *sc, struct ieee80211_node *ni) cmd->idx = ring->cur; bcn = (struct wpi_cmd_beacon *)cmd->data; - bzero(bcn, sizeof (struct wpi_cmd_beacon)); + memset(bcn, 0, sizeof (struct wpi_cmd_beacon)); bcn->id = WPI_ID_BROADCAST; bcn->ofdm_mask = 0xff; bcn->cck_mask = 0x0f; - bcn->lifetime = htole32(0xffffffff); + bcn->lifetime = htole32(WPI_LIFETIME_INFINITE); bcn->len = htole16(m0->m_pkthdr.len); bcn->rate = (ic->ic_curmode == IEEE80211_MODE_11A) ? wpi_plcp_signal(12) : wpi_plcp_signal(2); @@ -2003,7 +2341,6 @@ wpi_auth(struct wpi_softc *sc) /* update adapter's configuration */ IEEE80211_ADDR_COPY(sc->config.bssid, ni->ni_bssid); sc->config.chan = ieee80211_chan2ieee(ic, ni->ni_chan); - sc->config.flags = htole32(WPI_CONFIG_TSF); if (IEEE80211_IS_CHAN_2GHZ(ni->ni_chan)) { sc->config.flags |= htole32(WPI_CONFIG_AUTO | WPI_CONFIG_24GHZ); @@ -2034,24 +2371,26 @@ wpi_auth(struct wpi_softc *sc) return error; } + /* configuration has changed, set Tx power accordingly */ + if ((error = wpi_set_txpower(sc, ni->ni_chan)) != 0) { + printf("%s: could not set Tx power\n", sc->sc_dev.dv_xname); + return error; + } + /* add default node */ - bzero(&node, sizeof node); + memset(&node, 0, sizeof node); IEEE80211_ADDR_COPY(node.bssid, ni->ni_bssid); node.id = WPI_ID_BSS; node.rate = (ic->ic_curmode == IEEE80211_MODE_11A) ? wpi_plcp_signal(12) : wpi_plcp_signal(2); + node.action = htole32(WPI_ACTION_SET_RATE); + node.antenna = WPI_ANTENNA_BOTH; error = wpi_cmd(sc, WPI_CMD_ADD_NODE, &node, sizeof node, 1); if (error != 0) { printf("%s: could not add BSS node\n", sc->sc_dev.dv_xname); return error; } - error = wpi_mrr_setup(sc); - if (error != 0) { - printf("%s: could not setup MRR\n", sc->sc_dev.dv_xname); - return error; - } - return 0; } @@ -2101,18 +2440,20 @@ wpi_scan(struct wpi_softc *sc, uint16_t flags) cmd->idx = ring->cur; hdr = (struct wpi_scan_hdr *)cmd->data; - bzero(hdr, sizeof (struct wpi_scan_hdr)); - hdr->first = 1; + memset(hdr, 0, sizeof (struct wpi_scan_hdr)); + hdr->txflags = htole32(WPI_TX_AUTO_SEQ); + hdr->id = WPI_ID_BROADCAST; + hdr->lifetime = htole32(WPI_LIFETIME_INFINITE); /* * Move to the next channel if no packets are received within 5 msecs * after sending the probe request (this helps to reduce the duration * of active scans). */ hdr->quiet = htole16(5); /* timeout in milliseconds */ - hdr->threshold = htole16(1); /* min # of packets */ + hdr->plcp_threshold = htole16(1); /* min # of packets */ if (flags & IEEE80211_CHAN_A) { - hdr->band = htole16(WPI_SCAN_5GHZ); + hdr->crc_threshold = htole16(1); /* send probe requests at 6Mbps */ hdr->rate = wpi_plcp_signal(12); } else { @@ -2120,12 +2461,11 @@ wpi_scan(struct wpi_softc *sc, uint16_t flags) /* send probe requests at 1Mbps */ hdr->rate = wpi_plcp_signal(2); } - hdr->id = WPI_ID_BROADCAST; - hdr->mask = htole32(0xffffffff); - hdr->magic1 = htole32(1 << 13); - hdr->esslen = ic->ic_des_esslen; - bcopy(ic->ic_des_essid, hdr->essid, ic->ic_des_esslen); + /* for directed scans, firmware inserts the essid IE itself */ + hdr->essid[0].id = IEEE80211_ELEMID_SSID; + hdr->essid[0].len = ic->ic_des_esslen; + memcpy(hdr->essid[0].data, ic->ic_des_essid, ic->ic_des_esslen); /* * Build a probe request frame. Most of the following code is a @@ -2143,8 +2483,9 @@ wpi_scan(struct wpi_softc *sc, uint16_t flags) frm = (uint8_t *)(wh + 1); - /* add essid IE */ - frm = ieee80211_add_ssid(frm, ic->ic_des_essid, ic->ic_des_esslen); + /* add empty essid IE (firmware generates it for directed scans) */ + *frm++ = IEEE80211_ELEMID_SSID; + *frm++ = 0; mode = ieee80211_chan2mode(ic, ic->ic_ibss_chan); rs = &ic->ic_sup_rates[mode]; @@ -2156,7 +2497,7 @@ wpi_scan(struct wpi_softc *sc, uint16_t flags) frm = ieee80211_add_xrates(frm, rs); /* setup length of probe request */ - hdr->length = htole16(frm - (uint8_t *)wh); + hdr->paylen = htole16(frm - (uint8_t *)wh); chan = (struct wpi_scan_chan *)frm; for (c = &ic->ic_channels[1]; @@ -2165,14 +2506,20 @@ wpi_scan(struct wpi_softc *sc, uint16_t flags) continue; chan->chan = ieee80211_chan2ieee(ic, c); - chan->flags = (c->ic_flags & IEEE80211_CHAN_PASSIVE) ? - 0 : WPI_CHAN_ACTIVE; - chan->magic = htole16(0x62ab); + chan->flags = 0; + if (!(c->ic_flags & IEEE80211_CHAN_PASSIVE)) { + chan->flags |= WPI_CHAN_ACTIVE; + if (ic->ic_des_esslen != 0) + chan->flags |= WPI_CHAN_DIRECT; + } + chan->dsp_gain = 0x6e; if (IEEE80211_IS_CHAN_5GHZ(c)) { - chan->active = htole16(10); + chan->rf_gain = 0x3b; + chan->active = htole16(10); chan->passive = htole16(110); } else { - chan->active = htole16(20); + chan->rf_gain = 0x28; + chan->active = htole16(20); chan->passive = htole16(120); } hdr->nchan++; @@ -2181,8 +2528,8 @@ wpi_scan(struct wpi_softc *sc, uint16_t flags) frm += sizeof (struct wpi_scan_chan); } - hdr->len = hdr->nchan * sizeof (struct wpi_scan_chan); - pktlen = frm - mtod(data->m, uint8_t *); + hdr->len = htole16(frm - (uint8_t *)hdr); + pktlen = frm - (uint8_t *)cmd; error = bus_dmamap_load(sc->sc_dmat, data->map, cmd, pktlen, NULL, BUS_DMA_NOWAIT); @@ -2210,25 +2557,14 @@ wpi_config(struct wpi_softc *sc) { struct ieee80211com *ic = &sc->sc_ic; struct ifnet *ifp = &ic->ic_if; - struct wpi_txpower txpower; struct wpi_power power; struct wpi_bluetooth bluetooth; struct wpi_node_info node; int error; - /* set Tx power for 2.4GHz channels (values read from EEPROM) */ - bzero(&txpower, sizeof txpower); - bcopy(sc->pwr1, txpower.pwr1, 14 * sizeof (uint16_t)); - bcopy(sc->pwr2, txpower.pwr2, 14 * sizeof (uint16_t)); - error = wpi_cmd(sc, WPI_CMD_TXPOWER, &txpower, sizeof txpower, 0); - if (error != 0) { - printf("%s: could not set txpower\n", sc->sc_dev.dv_xname); - return error; - } - /* set power mode */ - bzero(&power, sizeof power); - power.flags = htole32(0x8); /* XXX */ + memset(&power, 0, sizeof power); + power.flags = htole32(WPI_POWER_CAM | 0x8); error = wpi_cmd(sc, WPI_CMD_SET_POWER_MODE, &power, sizeof power, 0); if (error != 0) { printf("%s: could not set power mode\n", sc->sc_dev.dv_xname); @@ -2236,7 +2572,7 @@ wpi_config(struct wpi_softc *sc) } /* configure bluetooth coexistence */ - bzero(&bluetooth, sizeof bluetooth); + memset(&bluetooth, 0, sizeof bluetooth); bluetooth.flags = 3; bluetooth.lead = 0xaa; bluetooth.kill = 1; @@ -2249,7 +2585,7 @@ wpi_config(struct wpi_softc *sc) } /* configure adapter */ - bzero(&sc->config, sizeof (struct wpi_config)); + memset(&sc->config, 0, sizeof (struct wpi_config)); IEEE80211_ADDR_COPY(ic->ic_myaddr, LLADDR(ifp->if_sadl)); IEEE80211_ADDR_COPY(sc->config.myaddr, ic->ic_myaddr); /* set default channel */ @@ -2287,11 +2623,19 @@ wpi_config(struct wpi_softc *sc) return error; } + /* configuration has changed, set Tx power accordingly */ + if ((error = wpi_set_txpower(sc, ic->ic_ibss_chan)) != 0) { + printf("%s: could not set Tx power\n", sc->sc_dev.dv_xname); + return error; + } + /* add broadcast node */ - bzero(&node, sizeof node); + memset(&node, 0, sizeof node); IEEE80211_ADDR_COPY(node.bssid, etherbroadcastaddr); node.id = WPI_ID_BROADCAST; node.rate = wpi_plcp_signal(2); + node.action = htole32(WPI_ACTION_SET_RATE); + node.antenna = WPI_ANTENNA_BOTH; error = wpi_cmd(sc, WPI_CMD_ADD_NODE, &node, sizeof node, 0); if (error != 0) { printf("%s: could not add broadcast node\n", @@ -2299,6 +2643,11 @@ wpi_config(struct wpi_softc *sc) return error; } + if ((error = wpi_mrr_setup(sc)) != 0) { + printf("%s: could not setup MRR\n", sc->sc_dev.dv_xname); + return error; + } + return 0; } @@ -2394,10 +2743,9 @@ wpi_reset(struct wpi_softc *sc) void wpi_hw_config(struct wpi_softc *sc) { - uint16_t val; uint32_t rev, hw; - /* voodoo from the Linux "driver".. */ + /* voodoo from the reference driver */ hw = WPI_READ(sc, WPI_HWCONFIG); rev = pci_conf_read(sc->sc_pct, sc->sc_pcitag, PCI_CLASS_REG); @@ -2407,17 +2755,14 @@ wpi_hw_config(struct wpi_softc *sc) else if (!(rev & 0x80)) hw |= WPI_HW_ALM_MM; - val = wpi_read_prom_word(sc, WPI_EEPROM_CAPABILITIES); - if ((val & 0xff) == 0x80) + if (sc->cap == 0x80) hw |= WPI_HW_SKU_MRC; - val = wpi_read_prom_word(sc, WPI_EEPROM_REVISION); hw &= ~WPI_HW_REV_D; - if ((val & 0xf0) == 0xd0) + if ((letoh16(sc->rev) & 0xf0) == 0xd0) hw |= WPI_HW_REV_D; - val = wpi_read_prom_word(sc, WPI_EEPROM_TYPE); - if ((val & 0xff) > 1) + if (sc->type > 1) hw |= WPI_HW_TYPE_B; DPRINTF(("setting h/w config %x\n", hw)); @@ -2429,10 +2774,6 @@ wpi_init(struct ifnet *ifp) { struct wpi_softc *sc = ifp->if_softc; struct ieee80211com *ic = &sc->sc_ic; - const struct wpi_firmware_hdr *hdr; - const char *boot, *text, *data; - u_char *fw; - size_t size; uint32_t tmp; int qid, ntries, error; @@ -2486,72 +2827,18 @@ wpi_init(struct ifnet *ifp) /* enable interrupts */ WPI_WRITE(sc, WPI_MASK, WPI_INTR_MASK); - if ((error = loadfirmware("wpi-ucode", &fw, &size)) != 0) { - printf("%s: could not read firmware file\n", - sc->sc_dev.dv_xname); - goto fail1; - } - - if (size < sizeof (struct wpi_firmware_hdr)) { - printf("%s: firmware file too short: %d bytes\n", - sc->sc_dev.dv_xname, size); - error = EINVAL; - goto fail2; - } - - hdr = (const struct wpi_firmware_hdr *)fw; - if (size < sizeof (struct wpi_firmware_hdr) + letoh32(hdr->textsz) + - letoh32(hdr->datasz) + letoh32(hdr->bootsz)) { - printf("%s: firmware file too short: %d bytes\n", - sc->sc_dev.dv_xname, size); - error = EINVAL; - goto fail2; - } - - /* firmware image layout: |HDR|<--TEXT-->|<--DATA-->|<--BOOT-->| */ - text = (const char *)(hdr + 1); - data = text + letoh32(hdr->textsz); - boot = data + letoh32(hdr->datasz); - - /* load firmware boot code into NIC */ - error = wpi_load_microcode(sc, boot, letoh32(hdr->bootsz)); - if (error != 0) { - printf("%s: could not load microcode\n", sc->sc_dev.dv_xname); - goto fail2; - } - - /* load firmware .text segment into NIC */ - error = wpi_load_firmware(sc, WPI_FW_TEXT, text, letoh32(hdr->textsz)); - if (error != 0) { - printf("%s: could not load firmware\n", sc->sc_dev.dv_xname); - goto fail2; - } + /* not sure why/if this is necessary... */ + WPI_WRITE(sc, WPI_UCODE_CLR, WPI_RADIO_OFF); + WPI_WRITE(sc, WPI_UCODE_CLR, WPI_RADIO_OFF); - /* load firmware .data segment into NIC */ - error = wpi_load_firmware(sc, WPI_FW_DATA, data, letoh32(hdr->datasz)); - if (error != 0) { + if ((error = wpi_load_firmware(sc)) != 0) { printf("%s: could not load firmware\n", sc->sc_dev.dv_xname); - goto fail2; - } - - free(fw, M_DEVBUF); - - /* now press "execute" ;-) */ - tmp = WPI_READ(sc, WPI_RESET); - tmp &= ~(WPI_MASTER_DISABLED | WPI_STOP_MASTER | WPI_NEVO_RESET); - WPI_WRITE(sc, WPI_RESET, tmp); - - /* ..and wait at most one second for adapter to initialize */ - if ((error = tsleep(sc, PCATCH, "wpiinit", hz)) != 0) { - /* this isn't what was supposed to happen.. */ - printf("%s: timeout waiting for adapter to initialize\n", - sc->sc_dev.dv_xname); goto fail1; } /* wait for thermal sensors to calibrate */ for (ntries = 0; ntries < 1000; ntries++) { - if (WPI_READ(sc, WPI_TEMPERATURE) != 0) + if ((sc->temp = (int)WPI_READ(sc, WPI_TEMPERATURE)) != 0) break; DELAY(10); } @@ -2561,7 +2848,9 @@ wpi_init(struct ifnet *ifp) error = ETIMEDOUT; goto fail1; } - DPRINTF(("temperature %d\n", (int)WPI_READ(sc, WPI_TEMPERATURE))); + DPRINTF(("temperature %d\n", sc->temp)); + sc->sensor.value = sc->temp + 260; + sc->sensor.flags &= ~SENSOR_FINVALID; if ((error = wpi_config(sc)) != 0) { printf("%s: could not configure device\n", @@ -2579,7 +2868,6 @@ wpi_init(struct ifnet *ifp) return 0; -fail2: free(fw, M_DEVBUF); fail1: wpi_stop(ifp, 1); return error; } @@ -2616,6 +2904,10 @@ wpi_stop(struct ifnet *ifp, int disable) /* reset Rx ring */ wpi_reset_rx_ring(sc, &sc->rxq); + /* temperature is no longer valid */ + sc->sensor.value = 0; + sc->sensor.flags |= SENSOR_FINVALID; + wpi_mem_lock(sc); wpi_mem_write(sc, WPI_MEM_CLOCK2, 0x200); wpi_mem_unlock(sc); @@ -2628,47 +2920,6 @@ wpi_stop(struct ifnet *ifp, int disable) WPI_WRITE(sc, WPI_RESET, tmp | WPI_SW_RESET); } -void -wpi_iter_func(void *arg, struct ieee80211_node *ni) -{ - struct wpi_softc *sc = arg; - struct wpi_node *wn = (struct wpi_node *)ni; - - ieee80211_amrr_choose(&sc->amrr, ni, &wn->amn); -} - -void -wpi_amrr_timeout(void *arg) -{ - struct wpi_softc *sc = arg; - struct ieee80211com *ic = &sc->sc_ic; - int s; - - s = splnet(); - if (ic->ic_opmode == IEEE80211_M_STA) - wpi_iter_func(sc, ic->ic_bss); - else - ieee80211_iterate_nodes(ic, wpi_iter_func, sc); - splx(s); - - timeout_add(&sc->amrr_ch, hz / 2); -} - -void -wpi_newassoc(struct ieee80211com *ic, struct ieee80211_node *ni, int isnew) -{ - struct wpi_softc *sc = ic->ic_if.if_softc; - int i; - - ieee80211_amrr_node_init(&sc->amrr, &((struct wpi_node *)ni)->amn); - - /* set rate to some reasonable initial value */ - for (i = ni->ni_rates.rs_nrates - 1; - i > 0 && (ni->ni_rates.rs_rates[i] & IEEE80211_RATE_VAL) > 72; - i--); - ni->ni_txrate = i; -} - struct cfdriver wpi_cd = { NULL, "wpi", DV_IFNET }; diff --git a/sys/dev/pci/if_wpireg.h b/sys/dev/pci/if_wpireg.h index 8c285e47623..ea98be3e76a 100644 --- a/sys/dev/pci/if_wpireg.h +++ b/sys/dev/pci/if_wpireg.h @@ -1,7 +1,7 @@ -/* $OpenBSD: if_wpireg.h,v 1.12 2006/11/13 20:06:38 damien Exp $ */ +/* $OpenBSD: if_wpireg.h,v 1.13 2007/06/05 19:49:40 damien Exp $ */ /*- - * Copyright (c) 2006 + * Copyright (c) 2006, 2007 * Damien Bergamini <damien.bergamini@free.fr> * * Permission to use, copy, modify, and distribute this software for any @@ -23,7 +23,7 @@ #define WPI_RX_RING_COUNT 64 /* - * Rings must be aligned on a four 4K-pages boundary. + * Rings must be aligned on a 16K boundary. * I had a hard time figuring this out. */ #define WPI_RING_DMA_ALIGN 0x4000 @@ -31,7 +31,7 @@ /* maximum scatter/gather */ #define WPI_MAX_SCATTER 4 -/* maximum Rx buffer size */ +/* maximum Rx buffer size (larger than MCLBYTES) */ #define WPI_RBUF_SIZE (3 * 1024) /* XXX 3000 but must be aligned! */ /* @@ -93,6 +93,11 @@ #define WPI_MEM_UCODE_SIZE 0x340c #define WPI_MEM_UCODE_BASE 0x3800 +#define WPI_MEM_MAIN_TEXT_BASE 0x3490 +#define WPI_MEM_MAIN_TEXT_SIZE 0x3494 +#define WPI_MEM_MAIN_DATA_BASE 0x3498 +#define WPI_MEM_MAIN_DATA_SIZE 0x349c + /* possible flags for register WPI_HWCONFIG */ #define WPI_HW_ALM_MB (1 << 8) @@ -250,8 +255,8 @@ struct wpi_tx_cmd { #define WPI_CMD_SET_POWER_MODE 119 #define WPI_CMD_SCAN 128 #define WPI_CMD_SET_BEACON 145 +#define WPI_CMD_TXPOWER 151 #define WPI_CMD_BLUETOOTH 155 -#define WPI_CMD_TXPOWER 176 uint8_t flags; uint8_t idx; @@ -275,9 +280,7 @@ struct wpi_config { uint8_t reserved4[3]; uint8_t ofdm_mask; uint8_t cck_mask; - uint16_t state; -#define WPI_STATE_ASSOCIATED 4 - + uint16_t associd; uint32_t flags; #define WPI_CONFIG_24GHZ (1 << 0) #define WPI_CONFIG_CCK (1 << 1) @@ -331,7 +334,7 @@ struct wpi_node_info { #define WPI_ID_BSS 0 #define WPI_ID_BROADCAST 24 - uint8_t sta_mask; + uint8_t flags; uint16_t reserved3; uint16_t key_flags; uint8_t tkip; @@ -339,11 +342,17 @@ struct wpi_node_info { uint16_t ttak[5]; uint16_t reserved5; uint8_t key[IEEE80211_KEYBUF_SIZE]; - uint32_t flags; + uint32_t action; +#define WPI_ACTION_SET_RATE 4 + uint32_t mask; uint16_t tid; uint8_t rate; - uint8_t reserved6; + uint8_t antenna; +#define WPI_ANTENNA_A (1 << 6) +#define WPI_ANTENNA_B (1 << 7) +#define WPI_ANTENNA_BOTH (WPI_ANTENNA_A | WPI_ANTENNA_B) + uint8_t add_imm; uint8_t del_imm; uint16_t add_imm_start; @@ -358,6 +367,7 @@ struct wpi_cmd_data { #define WPI_TX_NEED_CTS (1 << 2) #define WPI_TX_NEED_ACK (1 << 3) #define WPI_TX_FULL_TXOP (1 << 7) +#define WPI_TX_BT_DISABLE (1 << 12) /* bluetooth coexistence */ #define WPI_TX_AUTO_SEQ (1 << 13) #define WPI_TX_INSERT_TSTAMP (1 << 16) @@ -369,6 +379,8 @@ struct wpi_cmd_data { uint8_t tkip[IEEE80211_WEP_MICLEN]; uint32_t fnext; uint32_t lifetime; +#define WPI_LIFETIME_INFINITE 0xffffffff + uint8_t ofdm_mask; uint8_t cck_mask; uint8_t rts_ntries; @@ -431,37 +443,53 @@ struct wpi_cmd_led { /* structure for WPI_CMD_SET_POWER_MODE */ struct wpi_power { uint32_t flags; +#define WPI_POWER_CAM 0 /* constantly awake mode */ + uint32_t rx_timeout; uint32_t tx_timeout; uint32_t sleep[5]; } __packed; -/* structure for command WPI_CMD_SCAN */ +/* structures for command WPI_CMD_SCAN */ +struct wpi_scan_essid { + uint8_t id; + uint8_t len; + uint8_t data[IEEE80211_NWID_LEN]; +} __packed; + struct wpi_scan_hdr { - uint8_t len; - uint8_t first; + uint16_t len; uint8_t reserved1; uint8_t nchan; uint16_t quiet; - uint16_t threshold; - uint16_t band; -#define WPI_SCAN_5GHZ 1 - - uint16_t reserved2[5]; + uint16_t plcp_threshold; + uint16_t crc_threshold; + uint16_t reserved2; + uint32_t max_svc; /* background scans */ + uint32_t pause_svc; /* background scans */ uint32_t flags; uint32_t filter; - uint16_t length; - uint16_t reserved4; - uint32_t magic1; + + /* wpi_cmd_data structure */ + uint16_t paylen; + uint16_t lnext; + uint32_t txflags; uint8_t rate; uint8_t id; - uint16_t reserved5; - uint32_t reserved6[7]; - uint32_t mask; - uint32_t reserved7[2]; - uint8_t reserved8; - uint8_t esslen; - uint8_t essid[134]; + uint8_t tid; + uint8_t security; + uint8_t key[IEEE80211_KEYBUF_SIZE]; + uint8_t tkip[IEEE80211_WEP_MICLEN]; + uint32_t fnext; + uint32_t lifetime; + uint8_t ofdm_mask; + uint8_t cck_mask; + uint8_t rts_ntries; + uint8_t data_ntries; + uint16_t timeout; + uint16_t txop; + + struct wpi_scan_essid essid[4]; /* followed by probe request body */ /* followed by nchan x wpi_scan_chan */ @@ -469,14 +497,32 @@ struct wpi_scan_hdr { struct wpi_scan_chan { uint8_t flags; -#define WPI_CHAN_ACTIVE 3 +#define WPI_CHAN_ACTIVE (1 << 0) +#define WPI_CHAN_DIRECT (1 << 1) uint8_t chan; - uint16_t magic; /* XXX */ + uint8_t rf_gain; + uint8_t dsp_gain; uint16_t active; /* msecs */ uint16_t passive; /* msecs */ } __packed; +/* structure for WPI_CMD_TXPOWER */ +struct wpi_cmd_txpower { + uint8_t band; +#define WPI_BAND_5GHZ 0 +#define WPI_BAND_2GHZ 1 + + uint8_t reserved; + uint16_t chan; + struct { + uint8_t plcp; + uint8_t rf_gain; + uint8_t dsp_gain; + uint8_t reserved; + } __packed rates[WPI_CCK11 + 1]; +} __packed; + /* structure for WPI_CMD_BLUETOOTH */ struct wpi_bluetooth { uint8_t flags; @@ -487,23 +533,6 @@ struct wpi_bluetooth { uint32_t cts; } __packed; -/* structure for command WPI_CMD_TXPOWER */ -struct wpi_txpower { - uint32_t reserved1; - uint16_t pwr1[14]; - uint32_t reserved2[2]; - uint16_t pwr2[14]; - uint32_t reserved3[2]; -} __packed; - - -/* firmware image header */ -struct wpi_firmware_hdr { - uint32_t version; - uint32_t textsz; - uint32_t datasz; - uint32_t bootsz; -} __packed; /* structure for WPI_UC_READY notification */ struct wpi_ucode_info { @@ -537,12 +566,144 @@ struct wpi_stop_scan { uint64_t tsf; } __packed; + +/* firmware image header */ +struct wpi_firmware_hdr { + uint32_t version; + uint32_t main_textsz; + uint32_t main_datasz; + uint32_t boot_textsz; + uint32_t boot_datasz; +} __packed; + +#define WPI_FW_MAIN_TEXT_MAXSZ (80 * 1024) +#define WPI_FW_MAIN_DATA_MAXSZ (32 * 1024) +#define WPI_FW_BOOT_TEXT_MAXSZ (80 * 1024) +#define WPI_FW_BOOT_DATA_MAXSZ (32 * 1024) + +/* + * Offsets into EEPROM. + */ #define WPI_EEPROM_MAC 0x015 #define WPI_EEPROM_REVISION 0x035 #define WPI_EEPROM_CAPABILITIES 0x045 #define WPI_EEPROM_TYPE 0x04a -#define WPI_EEPROM_PWR1 0x1ae -#define WPI_EEPROM_PWR2 0x1bc +#define WPI_EEPROM_BAND1 0x063 +#define WPI_EEPROM_BAND2 0x072 +#define WPI_EEPROM_BAND3 0x080 +#define WPI_EEPROM_BAND4 0x08d +#define WPI_EEPROM_BAND5 0x099 +#define WPI_EEPROM_POWER_GRP 0x100 + +struct wpi_eeprom_chan { + uint8_t flags; +#define WPI_EEPROM_CHAN_VALID (1 << 0) +#define WPI_EEPROM_CHAN_IBSS (1 << 1) +#define WPI_EEPROM_CHAN_ACTIVE (1 << 3) +#define WPI_EEPROM_CHAN_RADAR (1 << 4) + + int8_t maxpwr; +} __packed; + +struct wpi_eeprom_sample { + uint8_t index; + int8_t power; + uint16_t volt; +} __packed; + +#define WPI_POWER_GROUPS_COUNT 5 +struct wpi_eeprom_group { + struct wpi_eeprom_sample samples[5]; + int32_t coef[5]; + int32_t corr[5]; + int8_t maxpwr; + uint8_t chan; + int16_t temp; +} __packed; + +#define WPI_CHAN_BANDS_COUNT 5 +#define WPI_MAX_CHAN_PER_BAND 14 +static const struct wpi_chan_band { + uint32_t addr; /* offset in EEPROM */ + uint8_t nchan; + uint8_t chan[WPI_MAX_CHAN_PER_BAND]; +} wpi_bands[5] = { + { WPI_EEPROM_BAND1, 14, + { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14 } }, + { WPI_EEPROM_BAND2, 13, + { 183, 184, 185, 187, 188, 189, 192, 196, 7, 8, 11, 12, 16 } }, + { WPI_EEPROM_BAND3, 12, + { 34, 36, 38, 40, 42, 44, 46, 48, 52, 56, 60, 64 } }, + { WPI_EEPROM_BAND4, 11, + { 100, 104, 108, 112, 116, 120, 124, 128, 132, 136, 140 } }, + { WPI_EEPROM_BAND5, 6, + { 145, 149, 153, 157, 161, 165 } } +}; + +/* convert rate index (device view) into rate in 500Kbps unit */ +static const uint8_t wpi_ridx_to_rate[] = { + 12, 18, 24, 36, 48, 72, 96, 108, /* OFDM */ + 2, 4, 11, 22 /* CCK */ +}; + +/* convert rate index (device view) into PLCP code */ +static const uint8_t wpi_ridx_to_plcp[] = { + 0xd, 0xf, 0x5, 0x7, 0x9, 0xb, 0x1, 0x3, /* OFDM R1-R4 */ + 10, 20, 55, 110 /* CCK */ +}; + +#define WPI_MAX_PWR_INDEX 77 +/* + * RF Tx gain values from highest to lowest power (values obtained from + * the reference driver.) + */ +static const uint8_t wpi_rf_gain_2ghz[WPI_MAX_PWR_INDEX + 1] = { + 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xbb, 0xbb, 0xbb, + 0xbb, 0xf3, 0xf3, 0xf3, 0xf3, 0xf3, 0xd3, 0xd3, 0xb3, 0xb3, 0xb3, + 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x73, 0xeb, 0xeb, 0xeb, + 0xcb, 0xcb, 0xcb, 0xcb, 0xcb, 0xcb, 0xcb, 0xab, 0xab, 0xab, 0x8b, + 0xe3, 0xe3, 0xe3, 0xe3, 0xe3, 0xe3, 0xc3, 0xc3, 0xc3, 0xc3, 0xa3, + 0xa3, 0xa3, 0xa3, 0x83, 0x83, 0x83, 0x83, 0x63, 0x63, 0x63, 0x63, + 0x43, 0x43, 0x43, 0x43, 0x23, 0x23, 0x23, 0x23, 0x03, 0x03, 0x03, + 0x03 +}; + +static const uint8_t wpi_rf_gain_5ghz[WPI_MAX_PWR_INDEX + 1] = { + 0xfb, 0xfb, 0xfb, 0xdb, 0xdb, 0xbb, 0xbb, 0x9b, 0x9b, 0x7b, 0x7b, + 0x7b, 0x7b, 0x5b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x1b, 0x1b, + 0x1b, 0x73, 0x73, 0x73, 0x53, 0x53, 0x53, 0x53, 0x53, 0x33, 0x33, + 0x33, 0x33, 0x13, 0x13, 0x13, 0x13, 0x13, 0xab, 0xab, 0xab, 0x8b, + 0x8b, 0x8b, 0x8b, 0x6b, 0x6b, 0x6b, 0x6b, 0x4b, 0x4b, 0x4b, 0x4b, + 0x2b, 0x2b, 0x2b, 0x2b, 0x0b, 0x0b, 0x0b, 0x0b, 0x83, 0x83, 0x63, + 0x63, 0x63, 0x63, 0x43, 0x43, 0x43, 0x43, 0x23, 0x23, 0x23, 0x23, + 0x03 +}; + +/* + * DSP pre-DAC gain values from highest to lowest power (values obtained + * from the reference driver.) + */ +static const uint8_t wpi_dsp_gain_2ghz[WPI_MAX_PWR_INDEX + 1] = { + 0x7f, 0x7f, 0x7f, 0x7f, 0x7d, 0x6e, 0x69, 0x62, 0x7d, 0x73, 0x6c, + 0x63, 0x77, 0x6f, 0x69, 0x61, 0x5c, 0x6a, 0x64, 0x78, 0x71, 0x6b, + 0x7d, 0x77, 0x70, 0x6a, 0x65, 0x61, 0x5b, 0x6b, 0x79, 0x73, 0x6d, + 0x7f, 0x79, 0x73, 0x6c, 0x66, 0x60, 0x5c, 0x6e, 0x68, 0x62, 0x74, + 0x7d, 0x77, 0x71, 0x6b, 0x65, 0x60, 0x71, 0x6a, 0x66, 0x5f, 0x71, + 0x6a, 0x66, 0x5f, 0x71, 0x6a, 0x66, 0x5f, 0x71, 0x6a, 0x66, 0x5f, + 0x71, 0x6a, 0x66, 0x5f, 0x71, 0x6a, 0x66, 0x5f, 0x71, 0x6a, 0x66, + 0x5f +}; + +static const uint8_t wpi_dsp_gain_5ghz[WPI_MAX_PWR_INDEX + 1] = { + 0x7f, 0x78, 0x72, 0x77, 0x65, 0x71, 0x66, 0x72, 0x67, 0x75, 0x6b, + 0x63, 0x5c, 0x6c, 0x7d, 0x76, 0x6d, 0x66, 0x60, 0x5a, 0x68, 0x62, + 0x5c, 0x76, 0x6f, 0x68, 0x7e, 0x79, 0x71, 0x69, 0x63, 0x76, 0x6f, + 0x68, 0x62, 0x74, 0x6d, 0x66, 0x62, 0x5d, 0x71, 0x6b, 0x63, 0x78, + 0x71, 0x6b, 0x63, 0x78, 0x71, 0x6b, 0x63, 0x78, 0x71, 0x6b, 0x63, + 0x78, 0x71, 0x6b, 0x63, 0x78, 0x71, 0x6b, 0x63, 0x6b, 0x63, 0x78, + 0x71, 0x6b, 0x63, 0x78, 0x71, 0x6b, 0x63, 0x78, 0x71, 0x6b, 0x63, + 0x78 +}; #define WPI_READ(sc, reg) \ bus_space_read_4((sc)->sc_st, (sc)->sc_sh, (reg)) diff --git a/sys/dev/pci/if_wpivar.h b/sys/dev/pci/if_wpivar.h index abfff1336f4..4ee209cb70d 100644 --- a/sys/dev/pci/if_wpivar.h +++ b/sys/dev/pci/if_wpivar.h @@ -1,7 +1,7 @@ -/* $OpenBSD: if_wpivar.h,v 1.10 2006/10/23 18:16:56 damien Exp $ */ +/* $OpenBSD: if_wpivar.h,v 1.11 2007/06/05 19:49:40 damien Exp $ */ /*- - * Copyright (c) 2006 + * Copyright (c) 2006, 2007 * Damien Bergamini <damien.bergamini@free.fr> * * Permission to use, copy, modify, and distribute this software for any @@ -110,6 +110,19 @@ struct wpi_node { struct ieee80211_amrr_node amn; }; +struct wpi_power_sample { + uint8_t index; + int8_t power; +}; + +struct wpi_power_group { +#define WPI_SAMPLES_COUNT 5 + struct wpi_power_sample samples[WPI_SAMPLES_COUNT]; + uint8_t chan; + int8_t maxpwr; + int16_t temp; +}; + struct wpi_softc { struct device sc_dev; @@ -118,15 +131,16 @@ struct wpi_softc { enum ieee80211_state, int); struct ieee80211_amrr amrr; - uint32_t flags; -#define WPI_FLAG_FW_INITED (1 << 0) - bus_dma_tag_t sc_dmat; /* shared area */ struct wpi_dma_info shared_dma; struct wpi_shared *shared; + /* firmware DMA transfer */ + struct wpi_dma_info fw_dma; + + /* rings */ struct wpi_tx_ring txq[4]; struct wpi_tx_ring cmdq; struct wpi_tx_ring svcq; @@ -139,11 +153,19 @@ struct wpi_softc { pcitag_t sc_pcitag; bus_size_t sc_sz; - struct timeout amrr_ch; + struct ksensordev sensordev; + struct ksensor sensor; + struct timeout calib_to; + int calib_cnt; struct wpi_config config; - uint16_t pwr1[14]; - uint16_t pwr2[14]; + int temp; + + uint8_t cap; + uint16_t rev; + uint8_t type; + struct wpi_power_group groups[WPI_POWER_GROUPS_COUNT]; + int8_t maxpwr[IEEE80211_CHAN_MAX]; int sc_tx_timer; void *powerhook; |