summaryrefslogtreecommitdiff
path: root/sys/dev
diff options
context:
space:
mode:
authorDamien Bergamini <damien@cvs.openbsd.org>2007-06-05 19:49:41 +0000
committerDamien Bergamini <damien@cvs.openbsd.org>2007-06-05 19:49:41 +0000
commit7987ac2d6221b197fb87ff8d60173b9843b4c856 (patch)
treee8317730d3228a7288ad129b986a06c6757a3c40 /sys/dev
parent30c408d46337ee2569d1a697b68b5fd4816f706c (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.c979
-rw-r--r--sys/dev/pci/if_wpireg.h261
-rw-r--r--sys/dev/pci/if_wpivar.h38
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;