if_wpi.c revision 173362
1173362Sbenjsc/*- 2173362Sbenjsc * Copyright (c) 2006,2007 3173362Sbenjsc * Damien Bergamini <damien.bergamini@free.fr> 4173362Sbenjsc * Benjamin Close <Benjamin.Close@clearchain.com> 5173362Sbenjsc * 6173362Sbenjsc * Permission to use, copy, modify, and distribute this software for any 7173362Sbenjsc * purpose with or without fee is hereby granted, provided that the above 8173362Sbenjsc * copyright notice and this permission notice appear in all copies. 9173362Sbenjsc * 10173362Sbenjsc * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 11173362Sbenjsc * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 12173362Sbenjsc * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 13173362Sbenjsc * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 14173362Sbenjsc * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 15173362Sbenjsc * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 16173362Sbenjsc * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 17173362Sbenjsc */ 18173362Sbenjsc 19173362Sbenjsc#define VERSION "20071102" 20173362Sbenjsc 21173362Sbenjsc#include <sys/cdefs.h> 22173362Sbenjsc__FBSDID("$FreeBSD: head/sys/dev/wpi/if_wpi.c 173362 2007-11-05 11:47:19Z benjsc $"); 23173362Sbenjsc 24173362Sbenjsc/* 25173362Sbenjsc * Driver for Intel PRO/Wireless 3945ABG 802.11 network adapters. 26173362Sbenjsc * 27173362Sbenjsc * The 3945ABG network adapter doesn't use traditional hardware as 28173362Sbenjsc * many other adaptors do. Instead at run time the eeprom is set into a known 29173362Sbenjsc * state and told to load boot firmware. The boot firmware loads an init and a 30173362Sbenjsc * main binary firmware image into SRAM on the card via DMA. 31173362Sbenjsc * Once the firmware is loaded, the driver/hw then 32173362Sbenjsc * communicate by way of circular dma rings via the the SRAM to the firmware. 33173362Sbenjsc * 34173362Sbenjsc * There is 6 memory rings. 1 command ring, 1 rx data ring & 4 tx data rings. 35173362Sbenjsc * The 4 tx data rings allow for prioritization QoS. 36173362Sbenjsc * 37173362Sbenjsc * The rx data ring consists of 32 dma buffers. Two registers are used to 38173362Sbenjsc * indicate where in the ring the driver and the firmware are up to. The 39173362Sbenjsc * driver sets the initial read index (reg1) and the initial write index (reg2), 40173362Sbenjsc * the firmware updates the read index (reg1) on rx of a packet and fires an 41173362Sbenjsc * interrupt. The driver then processes the buffers starting at reg1 indicating 42173362Sbenjsc * to the firmware which buffers have been accessed by updating reg2. At the 43173362Sbenjsc * same time allocating new memory for the processed buffer. 44173362Sbenjsc * 45173362Sbenjsc * A similar thing happens with the tx rings. The difference is the firmware 46173362Sbenjsc * stop processing buffers once the queue is full and until confirmation 47173362Sbenjsc * of a successful transmition (tx_intr) has occurred. 48173362Sbenjsc * 49173362Sbenjsc * The command ring operates in the same manner as the tx queues. 50173362Sbenjsc * 51173362Sbenjsc * All communication direct to the card (ie eeprom) is classed as Stage1 52173362Sbenjsc * communication 53173362Sbenjsc * 54173362Sbenjsc * All communication via the firmware to the card is classed as State2. 55173362Sbenjsc * The firmware consists of 2 parts. A bootstrap firmware and a runtime 56173362Sbenjsc * firmware. The bootstrap firmware and runtime firmware are loaded 57173362Sbenjsc * from host memory via dma to the card then told to execute. From this point 58173362Sbenjsc * on the majority of communications between the driver and the card goes 59173362Sbenjsc * via the firmware. 60173362Sbenjsc */ 61173362Sbenjsc 62173362Sbenjsc#include <sys/param.h> 63173362Sbenjsc#include <sys/sysctl.h> 64173362Sbenjsc#include <sys/sockio.h> 65173362Sbenjsc#include <sys/mbuf.h> 66173362Sbenjsc#include <sys/kernel.h> 67173362Sbenjsc#include <sys/socket.h> 68173362Sbenjsc#include <sys/systm.h> 69173362Sbenjsc#include <sys/malloc.h> 70173362Sbenjsc#include <sys/queue.h> 71173362Sbenjsc#include <sys/taskqueue.h> 72173362Sbenjsc#include <sys/module.h> 73173362Sbenjsc#include <sys/bus.h> 74173362Sbenjsc#include <sys/endian.h> 75173362Sbenjsc#include <sys/linker.h> 76173362Sbenjsc#include <sys/firmware.h> 77173362Sbenjsc 78173362Sbenjsc#if (__FreeBSD_version > 700000) 79173362Sbenjsc#define WPI_CURRENT 80173362Sbenjsc#endif 81173362Sbenjsc 82173362Sbenjsc#include <machine/bus.h> 83173362Sbenjsc#include <machine/resource.h> 84173362Sbenjsc#ifndef WPI_CURRENT 85173362Sbenjsc#include <machine/clock.h> 86173362Sbenjsc#endif 87173362Sbenjsc#include <sys/rman.h> 88173362Sbenjsc 89173362Sbenjsc#include <dev/pci/pcireg.h> 90173362Sbenjsc#include <dev/pci/pcivar.h> 91173362Sbenjsc 92173362Sbenjsc#include <net/bpf.h> 93173362Sbenjsc#include <net/if.h> 94173362Sbenjsc#include <net/if_arp.h> 95173362Sbenjsc#include <net/ethernet.h> 96173362Sbenjsc#include <net/if_dl.h> 97173362Sbenjsc#include <net/if_media.h> 98173362Sbenjsc#include <net/if_types.h> 99173362Sbenjsc 100173362Sbenjsc#include <net80211/ieee80211_var.h> 101173362Sbenjsc#include <net80211/ieee80211_radiotap.h> 102173362Sbenjsc#include <net80211/ieee80211_regdomain.h> 103173362Sbenjsc 104173362Sbenjsc#include <netinet/in.h> 105173362Sbenjsc#include <netinet/in_systm.h> 106173362Sbenjsc#include <netinet/in_var.h> 107173362Sbenjsc#include <netinet/ip.h> 108173362Sbenjsc#include <netinet/if_ether.h> 109173362Sbenjsc 110173362Sbenjsc#include <dev/wpi/if_wpireg.h> 111173362Sbenjsc#include <dev/wpi/if_wpivar.h> 112173362Sbenjsc 113173362Sbenjsc#define WPI_DEBUG 114173362Sbenjsc 115173362Sbenjsc#ifdef WPI_DEBUG 116173362Sbenjsc#define DPRINTF(x) do { if (wpi_debug != 0) printf x; } while (0) 117173362Sbenjsc#define DPRINTFN(n, x) do { if (wpi_debug & n) printf x; } while (0) 118173362Sbenjsc 119173362Sbenjscenum { 120173362Sbenjsc WPI_DEBUG_UNUSED = 0x00000001, /* Unused */ 121173362Sbenjsc WPI_DEBUG_HW = 0x00000002, /* Stage 1 (eeprom) debugging */ 122173362Sbenjsc WPI_DEBUG_TX = 0x00000004, /* Stage 2 TX intrp debugging*/ 123173362Sbenjsc WPI_DEBUG_RX = 0x00000008, /* Stage 2 RX intrp debugging */ 124173362Sbenjsc WPI_DEBUG_CMD = 0x00000010, /* Stage 2 CMD intrp debugging*/ 125173362Sbenjsc WPI_DEBUG_FIRMWARE = 0x00000020, /* firmware(9) loading debug */ 126173362Sbenjsc WPI_DEBUG_DMA = 0x00000040, /* DMA (de)allocations/syncs */ 127173362Sbenjsc WPI_DEBUG_SCANNING = 0x00000080, /* Stage 2 Scanning debugging */ 128173362Sbenjsc WPI_DEBUG_NOTIFY = 0x00000100, /* State 2 Noftif intr debug */ 129173362Sbenjsc WPI_DEBUG_TEMP = 0x00000200, /* TXPower/Temp Calibration */ 130173362Sbenjsc WPI_DEBUG_OPS = 0x00000400, /* wpi_ops taskq debug */ 131173362Sbenjsc WPI_DEBUG_WATCHDOG = 0x00000800, /* Watch dog debug */ 132173362Sbenjsc WPI_DEBUG_ANY = 0xffffffff 133173362Sbenjsc}; 134173362Sbenjsc 135173362Sbenjscint wpi_debug = WPI_DEBUG_SCANNING | WPI_DEBUG_CMD | WPI_DEBUG_NOTIFY; 136173362SbenjscSYSCTL_INT(_debug, OID_AUTO, wpi, CTLFLAG_RW, &wpi_debug, 0, "wpi debug level"); 137173362Sbenjsc 138173362Sbenjsc#else 139173362Sbenjsc#define DPRINTF(x) 140173362Sbenjsc#define DPRINTFN(n, x) 141173362Sbenjsc#endif 142173362Sbenjsc 143173362Sbenjscstruct wpi_ident { 144173362Sbenjsc uint16_t vendor; 145173362Sbenjsc uint16_t device; 146173362Sbenjsc uint16_t subdevice; 147173362Sbenjsc const char *name; 148173362Sbenjsc}; 149173362Sbenjsc 150173362Sbenjscstatic const struct wpi_ident wpi_ident_table[] = { 151173362Sbenjsc /* The below entries support ABG regardless of the subid */ 152173362Sbenjsc { 0x8086, 0x4222, 0x0, "Intel(R) PRO/Wireless 3945ABG" }, 153173362Sbenjsc { 0x8086, 0x4227, 0x0, "Intel(R) PRO/Wireless 3945ABG" }, 154173362Sbenjsc /* The below entries only support BG */ 155173362Sbenjsc { 0x8086, 0x4222, 0x1005, "Intel(R) PRO/Wireless 3945AB" }, 156173362Sbenjsc { 0x8086, 0x4222, 0x1034, "Intel(R) PRO/Wireless 3945AB" }, 157173362Sbenjsc { 0x8086, 0x4222, 0x1014, "Intel(R) PRO/Wireless 3945AB" }, 158173362Sbenjsc { 0x8086, 0x4222, 0x1044, "Intel(R) PRO/Wireless 3945AB" }, 159173362Sbenjsc { 0, 0, 0, NULL } 160173362Sbenjsc}; 161173362Sbenjsc 162173362Sbenjscstatic int wpi_dma_contig_alloc(struct wpi_softc *, struct wpi_dma_info *, 163173362Sbenjsc void **, bus_size_t, bus_size_t, int); 164173362Sbenjscstatic void wpi_dma_contig_free(struct wpi_dma_info *); 165173362Sbenjscstatic void wpi_dma_map_addr(void *, bus_dma_segment_t *, int, int); 166173362Sbenjscstatic int wpi_alloc_shared(struct wpi_softc *); 167173362Sbenjscstatic void wpi_free_shared(struct wpi_softc *); 168173362Sbenjscstatic struct wpi_rbuf *wpi_alloc_rbuf(struct wpi_softc *); 169173362Sbenjscstatic void wpi_free_rbuf(void *, void *); 170173362Sbenjscstatic int wpi_alloc_rpool(struct wpi_softc *); 171173362Sbenjscstatic void wpi_free_rpool(struct wpi_softc *); 172173362Sbenjscstatic int wpi_alloc_rx_ring(struct wpi_softc *, struct wpi_rx_ring *); 173173362Sbenjscstatic void wpi_reset_rx_ring(struct wpi_softc *, struct wpi_rx_ring *); 174173362Sbenjscstatic void wpi_free_rx_ring(struct wpi_softc *, struct wpi_rx_ring *); 175173362Sbenjscstatic int wpi_alloc_tx_ring(struct wpi_softc *, struct wpi_tx_ring *, 176173362Sbenjsc int, int); 177173362Sbenjscstatic void wpi_reset_tx_ring(struct wpi_softc *, struct wpi_tx_ring *); 178173362Sbenjscstatic void wpi_free_tx_ring(struct wpi_softc *, struct wpi_tx_ring *); 179173362Sbenjscstatic struct ieee80211_node *wpi_node_alloc(struct ieee80211_node_table *); 180173362Sbenjscstatic int wpi_media_change(struct ifnet *); 181173362Sbenjscstatic int wpi_newstate(struct ieee80211com *, enum ieee80211_state, int); 182173362Sbenjscstatic void wpi_mem_lock(struct wpi_softc *); 183173362Sbenjscstatic void wpi_mem_unlock(struct wpi_softc *); 184173362Sbenjscstatic uint32_t wpi_mem_read(struct wpi_softc *, uint16_t); 185173362Sbenjscstatic void wpi_mem_write(struct wpi_softc *, uint16_t, uint32_t); 186173362Sbenjscstatic void wpi_mem_write_region_4(struct wpi_softc *, uint16_t, 187173362Sbenjsc const uint32_t *, int); 188173362Sbenjscstatic uint16_t wpi_read_prom_data(struct wpi_softc *, uint32_t, void *, int); 189173362Sbenjscstatic int wpi_alloc_fwmem(struct wpi_softc *); 190173362Sbenjscstatic void wpi_free_fwmem(struct wpi_softc *); 191173362Sbenjscstatic int wpi_load_firmware(struct wpi_softc *); 192173362Sbenjscstatic void wpi_unload_firmware(struct wpi_softc *); 193173362Sbenjscstatic int wpi_load_microcode(struct wpi_softc *, const uint8_t *, int); 194173362Sbenjscstatic void wpi_rx_intr(struct wpi_softc *, struct wpi_rx_desc *, 195173362Sbenjsc struct wpi_rx_data *); 196173362Sbenjscstatic void wpi_tx_intr(struct wpi_softc *, struct wpi_rx_desc *); 197173362Sbenjscstatic void wpi_cmd_intr(struct wpi_softc *, struct wpi_rx_desc *); 198173362Sbenjscstatic void wpi_notif_intr(struct wpi_softc *); 199173362Sbenjscstatic void wpi_intr(void *); 200173362Sbenjscstatic void wpi_ops(void *, int); 201173362Sbenjscstatic uint8_t wpi_plcp_signal(int); 202173362Sbenjscstatic int wpi_queue_cmd(struct wpi_softc *, int); 203173362Sbenjscstatic void wpi_tick(void *); 204173362Sbenjsc#if 0 205173362Sbenjscstatic void wpi_radio_on(void *, int); 206173362Sbenjscstatic void wpi_radio_off(void *, int); 207173362Sbenjsc#endif 208173362Sbenjscstatic int wpi_tx_data(struct wpi_softc *, struct mbuf *, 209173362Sbenjsc struct ieee80211_node *, int); 210173362Sbenjscstatic void wpi_start(struct ifnet *); 211173362Sbenjscstatic void wpi_scan_start(struct ieee80211com *); 212173362Sbenjscstatic void wpi_scan_end(struct ieee80211com *); 213173362Sbenjscstatic void wpi_set_channel(struct ieee80211com *); 214173362Sbenjscstatic void wpi_scan_curchan(struct ieee80211com *, unsigned long); 215173362Sbenjscstatic void wpi_scan_mindwell(struct ieee80211com *); 216173362Sbenjscstatic void wpi_watchdog(struct ifnet *); 217173362Sbenjscstatic int wpi_ioctl(struct ifnet *, u_long, caddr_t); 218173362Sbenjscstatic void wpi_restart(void *, int); 219173362Sbenjscstatic void wpi_read_eeprom(struct wpi_softc *); 220173362Sbenjscstatic void wpi_read_eeprom_channels(struct wpi_softc *, int); 221173362Sbenjscstatic void wpi_read_eeprom_group(struct wpi_softc *, int); 222173362Sbenjscstatic int wpi_cmd(struct wpi_softc *, int, const void *, int, int); 223173362Sbenjscstatic int wpi_wme_update(struct ieee80211com *); 224173362Sbenjscstatic int wpi_mrr_setup(struct wpi_softc *); 225173362Sbenjscstatic void wpi_set_led(struct wpi_softc *, uint8_t, uint8_t, uint8_t); 226173362Sbenjscstatic void wpi_enable_tsf(struct wpi_softc *, struct ieee80211_node *); 227173362Sbenjsc#if 0 228173362Sbenjscstatic int wpi_setup_beacon(struct wpi_softc *, struct ieee80211_node *); 229173362Sbenjsc#endif 230173362Sbenjscstatic int wpi_auth(struct wpi_softc *); 231173362Sbenjscstatic int wpi_scan(struct wpi_softc *); 232173362Sbenjscstatic int wpi_config(struct wpi_softc *); 233173362Sbenjscstatic void wpi_stop_master(struct wpi_softc *); 234173362Sbenjscstatic int wpi_power_up(struct wpi_softc *); 235173362Sbenjscstatic int wpi_reset(struct wpi_softc *); 236173362Sbenjscstatic void wpi_hw_config(struct wpi_softc *); 237173362Sbenjscstatic void wpi_init(void *); 238173362Sbenjscstatic void wpi_stop(struct wpi_softc *); 239173362Sbenjscstatic void wpi_stop_locked(struct wpi_softc *); 240173362Sbenjscstatic void wpi_iter_func(void *, struct ieee80211_node *); 241173362Sbenjsc 242173362Sbenjscstatic void wpi_newassoc(struct ieee80211_node *, int); 243173362Sbenjscstatic int wpi_set_txpower(struct wpi_softc *, struct ieee80211_channel *, 244173362Sbenjsc int); 245173362Sbenjscstatic void wpi_calib_timeout(void *); 246173362Sbenjscstatic void wpi_power_calibration(struct wpi_softc *, int); 247173362Sbenjscstatic int wpi_get_power_index(struct wpi_softc *, 248173362Sbenjsc struct wpi_power_group *, struct ieee80211_channel *, int); 249173362Sbenjscstatic const char *wpi_cmd_str(int); 250173362Sbenjscstatic int wpi_probe(device_t); 251173362Sbenjscstatic int wpi_attach(device_t); 252173362Sbenjscstatic int wpi_detach(device_t); 253173362Sbenjscstatic int wpi_shutdown(device_t); 254173362Sbenjscstatic int wpi_suspend(device_t); 255173362Sbenjscstatic int wpi_resume(device_t); 256173362Sbenjsc 257173362Sbenjsc 258173362Sbenjscstatic device_method_t wpi_methods[] = { 259173362Sbenjsc /* Device interface */ 260173362Sbenjsc DEVMETHOD(device_probe, wpi_probe), 261173362Sbenjsc DEVMETHOD(device_attach, wpi_attach), 262173362Sbenjsc DEVMETHOD(device_detach, wpi_detach), 263173362Sbenjsc DEVMETHOD(device_shutdown, wpi_shutdown), 264173362Sbenjsc DEVMETHOD(device_suspend, wpi_suspend), 265173362Sbenjsc DEVMETHOD(device_resume, wpi_resume), 266173362Sbenjsc 267173362Sbenjsc { 0, 0 } 268173362Sbenjsc}; 269173362Sbenjsc 270173362Sbenjscstatic driver_t wpi_driver = { 271173362Sbenjsc "wpi", 272173362Sbenjsc wpi_methods, 273173362Sbenjsc sizeof (struct wpi_softc) 274173362Sbenjsc}; 275173362Sbenjsc 276173362Sbenjscstatic devclass_t wpi_devclass; 277173362Sbenjsc 278173362SbenjscDRIVER_MODULE(wpi, pci, wpi_driver, wpi_devclass, 0, 0); 279173362Sbenjsc 280173362Sbenjscstatic const uint8_t wpi_ridx_to_plcp[] = { 281173362Sbenjsc /* OFDM: IEEE Std 802.11a-1999, pp. 14 Table 80 */ 282173362Sbenjsc /* R1-R4 (ral/ural is R4-R1) */ 283173362Sbenjsc 0xd, 0xf, 0x5, 0x7, 0x9, 0xb, 0x1, 0x3, 284173362Sbenjsc /* CCK: device-dependent */ 285173362Sbenjsc 10, 20, 55, 110 286173362Sbenjsc}; 287173362Sbenjscstatic const uint8_t wpi_ridx_to_rate[] = { 288173362Sbenjsc 12, 18, 24, 36, 48, 72, 96, 108, /* OFDM */ 289173362Sbenjsc 2, 4, 11, 22 /*CCK */ 290173362Sbenjsc}; 291173362Sbenjsc 292173362Sbenjsc 293173362Sbenjscstatic int 294173362Sbenjscwpi_probe(device_t dev) 295173362Sbenjsc{ 296173362Sbenjsc const struct wpi_ident *ident; 297173362Sbenjsc 298173362Sbenjsc for (ident = wpi_ident_table; ident->name != NULL; ident++) { 299173362Sbenjsc if (pci_get_vendor(dev) == ident->vendor && 300173362Sbenjsc pci_get_device(dev) == ident->device) { 301173362Sbenjsc device_set_desc(dev, ident->name); 302173362Sbenjsc return 0; 303173362Sbenjsc } 304173362Sbenjsc } 305173362Sbenjsc return ENXIO; 306173362Sbenjsc} 307173362Sbenjsc 308173362Sbenjsc/** 309173362Sbenjsc * Load the firmare image from disk to the allocated dma buffer. 310173362Sbenjsc * we also maintain the reference to the firmware pointer as there 311173362Sbenjsc * is times where we may need to reload the firmware but we are not 312173362Sbenjsc * in a context that can access the filesystem (ie taskq cause by restart) 313173362Sbenjsc * 314173362Sbenjsc * @return 0 on success, an errno on failure 315173362Sbenjsc */ 316173362Sbenjscstatic int 317173362Sbenjscwpi_load_firmware(struct wpi_softc *sc) 318173362Sbenjsc{ 319173362Sbenjsc#ifdef WPI_CURRENT 320173362Sbenjsc const struct firmware *fp ; 321173362Sbenjsc#else 322173362Sbenjsc struct firmware *fp; 323173362Sbenjsc#endif 324173362Sbenjsc struct wpi_dma_info *dma = &sc->fw_dma; 325173362Sbenjsc const struct wpi_firmware_hdr *hdr; 326173362Sbenjsc const uint8_t *itext, *idata, *rtext, *rdata, *btext; 327173362Sbenjsc uint32_t itextsz, idatasz, rtextsz, rdatasz, btextsz; 328173362Sbenjsc int error; 329173362Sbenjsc WPI_LOCK_DECL; 330173362Sbenjsc 331173362Sbenjsc DPRINTFN(WPI_DEBUG_FIRMWARE, 332173362Sbenjsc ("Attempting Loading Firmware from wpi_fw module\n")); 333173362Sbenjsc 334173362Sbenjsc WPI_UNLOCK(sc); 335173362Sbenjsc 336173362Sbenjsc if (sc->fw_fp == NULL && (sc->fw_fp = firmware_get("wpifw")) == NULL) { 337173362Sbenjsc device_printf(sc->sc_dev, 338173362Sbenjsc "could not load firmware image 'wpifw'\n"); 339173362Sbenjsc error = ENOENT; 340173362Sbenjsc WPI_LOCK(sc); 341173362Sbenjsc goto fail; 342173362Sbenjsc } 343173362Sbenjsc 344173362Sbenjsc fp = sc->fw_fp; 345173362Sbenjsc 346173362Sbenjsc WPI_LOCK(sc); 347173362Sbenjsc 348173362Sbenjsc /* Validate the firmware is minimum a particular version */ 349173362Sbenjsc if (fp->version < WPI_FW_MINVERSION) { 350173362Sbenjsc device_printf(sc->sc_dev, 351173362Sbenjsc "firmware version is too old. Need %d, got %d\n", 352173362Sbenjsc WPI_FW_MINVERSION, 353173362Sbenjsc fp->version); 354173362Sbenjsc error = ENXIO; 355173362Sbenjsc goto fail; 356173362Sbenjsc } 357173362Sbenjsc 358173362Sbenjsc if (fp->datasize < sizeof (struct wpi_firmware_hdr)) { 359173362Sbenjsc device_printf(sc->sc_dev, 360173362Sbenjsc "firmware file too short: %zu bytes\n", fp->datasize); 361173362Sbenjsc error = ENXIO; 362173362Sbenjsc goto fail; 363173362Sbenjsc } 364173362Sbenjsc 365173362Sbenjsc hdr = (const struct wpi_firmware_hdr *)fp->data; 366173362Sbenjsc 367173362Sbenjsc /* | RUNTIME FIRMWARE | INIT FIRMWARE | BOOT FW | 368173362Sbenjsc |HDR|<--TEXT-->|<--DATA-->|<--TEXT-->|<--DATA-->|<--TEXT-->| */ 369173362Sbenjsc 370173362Sbenjsc rtextsz = le32toh(hdr->rtextsz); 371173362Sbenjsc rdatasz = le32toh(hdr->rdatasz); 372173362Sbenjsc itextsz = le32toh(hdr->itextsz); 373173362Sbenjsc idatasz = le32toh(hdr->idatasz); 374173362Sbenjsc btextsz = le32toh(hdr->btextsz); 375173362Sbenjsc 376173362Sbenjsc /* check that all firmware segments are present */ 377173362Sbenjsc if (fp->datasize < sizeof (struct wpi_firmware_hdr) + 378173362Sbenjsc rtextsz + rdatasz + itextsz + idatasz + btextsz) { 379173362Sbenjsc device_printf(sc->sc_dev, 380173362Sbenjsc "firmware file too short: %zu bytes\n", fp->datasize); 381173362Sbenjsc error = ENXIO; /* XXX appropriate error code? */ 382173362Sbenjsc goto fail; 383173362Sbenjsc } 384173362Sbenjsc 385173362Sbenjsc /* get pointers to firmware segments */ 386173362Sbenjsc rtext = (const uint8_t *)(hdr + 1); 387173362Sbenjsc rdata = rtext + rtextsz; 388173362Sbenjsc itext = rdata + rdatasz; 389173362Sbenjsc idata = itext + itextsz; 390173362Sbenjsc btext = idata + idatasz; 391173362Sbenjsc 392173362Sbenjsc DPRINTFN(WPI_DEBUG_FIRMWARE, 393173362Sbenjsc ("Firmware Version: Major %d, Minor %d, Driver %d, \n" 394173362Sbenjsc "runtime (text: %u, data: %u) init (text: %u, data %u) boot (text %u)\n", 395173362Sbenjsc (le32toh(hdr->version) & 0xff000000) >> 24, 396173362Sbenjsc (le32toh(hdr->version) & 0x00ff0000) >> 16, 397173362Sbenjsc (le32toh(hdr->version) & 0x0000ffff), 398173362Sbenjsc rtextsz, rdatasz, 399173362Sbenjsc itextsz, idatasz, btextsz)); 400173362Sbenjsc 401173362Sbenjsc DPRINTFN(WPI_DEBUG_FIRMWARE,("rtext 0x%x\n", *(const uint32_t *)rtext)); 402173362Sbenjsc DPRINTFN(WPI_DEBUG_FIRMWARE,("rdata 0x%x\n", *(const uint32_t *)rdata)); 403173362Sbenjsc DPRINTFN(WPI_DEBUG_FIRMWARE,("itext 0x%x\n", *(const uint32_t *)itext)); 404173362Sbenjsc DPRINTFN(WPI_DEBUG_FIRMWARE,("idata 0x%x\n", *(const uint32_t *)idata)); 405173362Sbenjsc DPRINTFN(WPI_DEBUG_FIRMWARE,("btext 0x%x\n", *(const uint32_t *)btext)); 406173362Sbenjsc 407173362Sbenjsc /* sanity checks */ 408173362Sbenjsc if (rtextsz > WPI_FW_MAIN_TEXT_MAXSZ || 409173362Sbenjsc rdatasz > WPI_FW_MAIN_DATA_MAXSZ || 410173362Sbenjsc itextsz > WPI_FW_INIT_TEXT_MAXSZ || 411173362Sbenjsc idatasz > WPI_FW_INIT_DATA_MAXSZ || 412173362Sbenjsc btextsz > WPI_FW_BOOT_TEXT_MAXSZ || 413173362Sbenjsc (btextsz & 3) != 0) { 414173362Sbenjsc device_printf(sc->sc_dev, "firmware invalid\n"); 415173362Sbenjsc error = EINVAL; 416173362Sbenjsc goto fail; 417173362Sbenjsc } 418173362Sbenjsc 419173362Sbenjsc /* copy initialization images into pre-allocated DMA-safe memory */ 420173362Sbenjsc memcpy(dma->vaddr, idata, idatasz); 421173362Sbenjsc memcpy(dma->vaddr + WPI_FW_INIT_DATA_MAXSZ, itext, itextsz); 422173362Sbenjsc 423173362Sbenjsc bus_dmamap_sync(dma->tag, dma->map, BUS_DMASYNC_PREWRITE); 424173362Sbenjsc 425173362Sbenjsc /* tell adapter where to find initialization images */ 426173362Sbenjsc wpi_mem_lock(sc); 427173362Sbenjsc wpi_mem_write(sc, WPI_MEM_DATA_BASE, dma->paddr); 428173362Sbenjsc wpi_mem_write(sc, WPI_MEM_DATA_SIZE, idatasz); 429173362Sbenjsc wpi_mem_write(sc, WPI_MEM_TEXT_BASE, 430173362Sbenjsc dma->paddr + WPI_FW_INIT_DATA_MAXSZ); 431173362Sbenjsc wpi_mem_write(sc, WPI_MEM_TEXT_SIZE, itextsz); 432173362Sbenjsc wpi_mem_unlock(sc); 433173362Sbenjsc 434173362Sbenjsc /* load firmware boot code */ 435173362Sbenjsc if ((error = wpi_load_microcode(sc, btext, btextsz)) != 0) { 436173362Sbenjsc device_printf(sc->sc_dev, "Failed to load microcode\n"); 437173362Sbenjsc goto fail; 438173362Sbenjsc } 439173362Sbenjsc 440173362Sbenjsc /* now press "execute" */ 441173362Sbenjsc WPI_WRITE(sc, WPI_RESET, 0); 442173362Sbenjsc 443173362Sbenjsc /* wait at most one second for the first alive notification */ 444173362Sbenjsc if ((error = msleep(sc, &sc->sc_mtx, PCATCH, "wpiinit", hz)) != 0) { 445173362Sbenjsc device_printf(sc->sc_dev, 446173362Sbenjsc "timeout waiting for adapter to initialize\n"); 447173362Sbenjsc goto fail; 448173362Sbenjsc } 449173362Sbenjsc 450173362Sbenjsc /* copy runtime images into pre-allocated DMA-sage memory */ 451173362Sbenjsc memcpy(dma->vaddr, rdata, rdatasz); 452173362Sbenjsc memcpy(dma->vaddr + WPI_FW_MAIN_DATA_MAXSZ, rtext, rtextsz); 453173362Sbenjsc bus_dmamap_sync(dma->tag, dma->map, BUS_DMASYNC_PREWRITE); 454173362Sbenjsc 455173362Sbenjsc /* tell adapter where to find runtime images */ 456173362Sbenjsc wpi_mem_lock(sc); 457173362Sbenjsc wpi_mem_write(sc, WPI_MEM_DATA_BASE, dma->paddr); 458173362Sbenjsc wpi_mem_write(sc, WPI_MEM_DATA_SIZE, rdatasz); 459173362Sbenjsc wpi_mem_write(sc, WPI_MEM_TEXT_BASE, 460173362Sbenjsc dma->paddr + WPI_FW_MAIN_DATA_MAXSZ); 461173362Sbenjsc wpi_mem_write(sc, WPI_MEM_TEXT_SIZE, WPI_FW_UPDATED | rtextsz); 462173362Sbenjsc wpi_mem_unlock(sc); 463173362Sbenjsc 464173362Sbenjsc /* wait at most one second for the first alive notification */ 465173362Sbenjsc if ((error = msleep(sc, &sc->sc_mtx, PCATCH, "wpiinit", hz)) != 0) { 466173362Sbenjsc device_printf(sc->sc_dev, 467173362Sbenjsc "timeout waiting for adapter to initialize2\n"); 468173362Sbenjsc goto fail; 469173362Sbenjsc } 470173362Sbenjsc 471173362Sbenjsc DPRINTFN(WPI_DEBUG_FIRMWARE, 472173362Sbenjsc ("Firmware loaded to driver successfully\n")); 473173362Sbenjsc return error; 474173362Sbenjscfail: 475173362Sbenjsc wpi_unload_firmware(sc); 476173362Sbenjsc return error; 477173362Sbenjsc} 478173362Sbenjsc 479173362Sbenjsc/** 480173362Sbenjsc * Free the referenced firmware image 481173362Sbenjsc */ 482173362Sbenjscstatic void 483173362Sbenjscwpi_unload_firmware(struct wpi_softc *sc) 484173362Sbenjsc{ 485173362Sbenjsc WPI_LOCK_DECL; 486173362Sbenjsc 487173362Sbenjsc if (sc->fw_fp) { 488173362Sbenjsc WPI_UNLOCK(sc); 489173362Sbenjsc firmware_put(sc->fw_fp, FIRMWARE_UNLOAD); 490173362Sbenjsc WPI_LOCK(sc); 491173362Sbenjsc sc->fw_fp = NULL; 492173362Sbenjsc } 493173362Sbenjsc} 494173362Sbenjsc 495173362Sbenjscstatic int 496173362Sbenjscwpi_attach(device_t dev) 497173362Sbenjsc{ 498173362Sbenjsc struct wpi_softc *sc = device_get_softc(dev); 499173362Sbenjsc struct ifnet *ifp; 500173362Sbenjsc struct ieee80211com *ic = &sc->sc_ic; 501173362Sbenjsc int ac, error, supportsa = 1; 502173362Sbenjsc uint32_t tmp; 503173362Sbenjsc const struct wpi_ident *ident; 504173362Sbenjsc 505173362Sbenjsc sc->sc_dev = dev; 506173362Sbenjsc 507173362Sbenjsc if (bootverbose || wpi_debug) 508173362Sbenjsc device_printf(sc->sc_dev,"Driver Revision %s\n", VERSION); 509173362Sbenjsc 510173362Sbenjsc /* 511173362Sbenjsc * Some card's only support 802.11b/g not a, check to see if 512173362Sbenjsc * this is one such card. A 0x0 in the subdevice table indicates 513173362Sbenjsc * the entire subdevice range is to be ignored. 514173362Sbenjsc */ 515173362Sbenjsc for (ident = wpi_ident_table; ident->name != NULL; ident++) { 516173362Sbenjsc if (ident->subdevice && 517173362Sbenjsc pci_get_subdevice(dev) == ident->subdevice) { 518173362Sbenjsc supportsa = 0; 519173362Sbenjsc break; 520173362Sbenjsc } 521173362Sbenjsc } 522173362Sbenjsc 523173362Sbenjsc#if __FreeBSD_version >= 700000 524173362Sbenjsc /* 525173362Sbenjsc * Create the taskqueues used by the driver. Primarily 526173362Sbenjsc * sc_tq handles most the task 527173362Sbenjsc */ 528173362Sbenjsc sc->sc_tq = taskqueue_create("wpi_taskq", M_NOWAIT | M_ZERO, 529173362Sbenjsc taskqueue_thread_enqueue, &sc->sc_tq); 530173362Sbenjsc taskqueue_start_threads(&sc->sc_tq, 1, PI_NET, "%s taskq", 531173362Sbenjsc device_get_nameunit(dev)); 532173362Sbenjsc 533173362Sbenjsc sc->sc_tq2 = taskqueue_create("wpi_taskq2", M_NOWAIT | M_ZERO, 534173362Sbenjsc taskqueue_thread_enqueue, &sc->sc_tq2); 535173362Sbenjsc taskqueue_start_threads(&sc->sc_tq2, 1, PI_NET, "%s taskq2", 536173362Sbenjsc device_get_nameunit(dev)); 537173362Sbenjsc#else 538173362Sbenjsc#error "Sorry, this driver is not yet ready for FreeBSD < 7.0" 539173362Sbenjsc#endif 540173362Sbenjsc 541173362Sbenjsc /* Create the tasks that can be queued */ 542173362Sbenjsc#if 0 543173362Sbenjsc TASK_INIT(&sc->sc_radioontask, 0, wpi_radio_on, sc); 544173362Sbenjsc TASK_INIT(&sc->sc_radioofftask, 0, wpi_radio_off, sc); 545173362Sbenjsc#endif 546173362Sbenjsc TASK_INIT(&sc->sc_opstask, 0, wpi_ops, sc); 547173362Sbenjsc TASK_INIT(&sc->sc_restarttask, 0, wpi_restart, sc); 548173362Sbenjsc 549173362Sbenjsc WPI_LOCK_INIT(sc); 550173362Sbenjsc WPI_CMD_LOCK_INIT(sc); 551173362Sbenjsc 552173362Sbenjsc callout_init_mtx(&sc->calib_to, &sc->sc_mtx, 0); 553173362Sbenjsc callout_init_mtx(&sc->watchdog_to, &sc->sc_mtx, 0); 554173362Sbenjsc 555173362Sbenjsc if (pci_get_powerstate(dev) != PCI_POWERSTATE_D0) { 556173362Sbenjsc device_printf(dev, "chip is in D%d power mode " 557173362Sbenjsc "-- setting to D0\n", pci_get_powerstate(dev)); 558173362Sbenjsc pci_set_powerstate(dev, PCI_POWERSTATE_D0); 559173362Sbenjsc } 560173362Sbenjsc 561173362Sbenjsc /* disable the retry timeout register */ 562173362Sbenjsc pci_write_config(dev, 0x41, 0, 1); 563173362Sbenjsc 564173362Sbenjsc /* enable bus-mastering */ 565173362Sbenjsc pci_enable_busmaster(dev); 566173362Sbenjsc 567173362Sbenjsc sc->mem_rid = PCIR_BAR(0); 568173362Sbenjsc sc->mem = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &sc->mem_rid, 569173362Sbenjsc RF_ACTIVE); 570173362Sbenjsc if (sc->mem == NULL) { 571173362Sbenjsc device_printf(dev, "could not allocate memory resource\n"); 572173362Sbenjsc error = ENOMEM; 573173362Sbenjsc goto fail; 574173362Sbenjsc } 575173362Sbenjsc 576173362Sbenjsc sc->sc_st = rman_get_bustag(sc->mem); 577173362Sbenjsc sc->sc_sh = rman_get_bushandle(sc->mem); 578173362Sbenjsc 579173362Sbenjsc sc->irq_rid = 0; 580173362Sbenjsc sc->irq = bus_alloc_resource_any(dev, SYS_RES_IRQ, &sc->irq_rid, 581173362Sbenjsc RF_ACTIVE | RF_SHAREABLE); 582173362Sbenjsc if (sc->irq == NULL) { 583173362Sbenjsc device_printf(dev, "could not allocate interrupt resource\n"); 584173362Sbenjsc error = ENOMEM; 585173362Sbenjsc goto fail; 586173362Sbenjsc } 587173362Sbenjsc 588173362Sbenjsc /* 589173362Sbenjsc * Allocate DMA memory for firmware transfers. 590173362Sbenjsc */ 591173362Sbenjsc if ((error = wpi_alloc_fwmem(sc)) != 0) { 592173362Sbenjsc printf(": could not allocate firmware memory\n"); 593173362Sbenjsc error = ENOMEM; 594173362Sbenjsc goto fail; 595173362Sbenjsc } 596173362Sbenjsc 597173362Sbenjsc /* 598173362Sbenjsc * Put adapter into a known state. 599173362Sbenjsc */ 600173362Sbenjsc if ((error = wpi_reset(sc)) != 0) { 601173362Sbenjsc device_printf(dev, "could not reset adapter\n"); 602173362Sbenjsc goto fail; 603173362Sbenjsc } 604173362Sbenjsc 605173362Sbenjsc wpi_mem_lock(sc); 606173362Sbenjsc tmp = wpi_mem_read(sc, WPI_MEM_PCIDEV); 607173362Sbenjsc if (bootverbose || wpi_debug) 608173362Sbenjsc device_printf(sc->sc_dev, "Hardware Revision (0x%X)\n", tmp); 609173362Sbenjsc 610173362Sbenjsc wpi_mem_unlock(sc); 611173362Sbenjsc 612173362Sbenjsc /* Allocate shared page */ 613173362Sbenjsc if ((error = wpi_alloc_shared(sc)) != 0) { 614173362Sbenjsc device_printf(dev, "could not allocate shared page\n"); 615173362Sbenjsc goto fail; 616173362Sbenjsc } 617173362Sbenjsc 618173362Sbenjsc /* 619173362Sbenjsc * Allocate the receive buffer pool. The recieve buffers are 620173362Sbenjsc * WPI_RBUF_SIZE in length (3k) this is bigger than MCLBYTES 621173362Sbenjsc * hence we can't simply use a cluster and used mapped dma memory 622173362Sbenjsc * instead. 623173362Sbenjsc */ 624173362Sbenjsc if ((error = wpi_alloc_rpool(sc)) != 0) { 625173362Sbenjsc device_printf(dev, "could not allocate Rx buffers\n"); 626173362Sbenjsc goto fail; 627173362Sbenjsc } 628173362Sbenjsc 629173362Sbenjsc /* tx data queues - 4 for QoS purposes */ 630173362Sbenjsc for (ac = 0; ac < WME_NUM_AC; ac++) { 631173362Sbenjsc error = wpi_alloc_tx_ring(sc, &sc->txq[ac], WPI_TX_RING_COUNT, ac); 632173362Sbenjsc if (error != 0) { 633173362Sbenjsc device_printf(dev, "could not allocate Tx ring %d\n",ac); 634173362Sbenjsc goto fail; 635173362Sbenjsc } 636173362Sbenjsc } 637173362Sbenjsc 638173362Sbenjsc /* command queue to talk to the card's firmware */ 639173362Sbenjsc error = wpi_alloc_tx_ring(sc, &sc->cmdq, WPI_CMD_RING_COUNT, 4); 640173362Sbenjsc if (error != 0) { 641173362Sbenjsc device_printf(dev, "could not allocate command ring\n"); 642173362Sbenjsc goto fail; 643173362Sbenjsc } 644173362Sbenjsc 645173362Sbenjsc /* receive data queue */ 646173362Sbenjsc error = wpi_alloc_rx_ring(sc, &sc->rxq); 647173362Sbenjsc if (error != 0) { 648173362Sbenjsc device_printf(dev, "could not allocate Rx ring\n"); 649173362Sbenjsc goto fail; 650173362Sbenjsc } 651173362Sbenjsc 652173362Sbenjsc ifp = sc->sc_ifp = if_alloc(IFT_ETHER); 653173362Sbenjsc if (ifp == NULL) { 654173362Sbenjsc device_printf(dev, "can not if_alloc()\n"); 655173362Sbenjsc error = ENOMEM; 656173362Sbenjsc goto fail; 657173362Sbenjsc } 658173362Sbenjsc 659173362Sbenjsc ic->ic_ifp = ifp; 660173362Sbenjsc ic->ic_phytype = IEEE80211_T_OFDM; /* not only, but not used */ 661173362Sbenjsc ic->ic_opmode = IEEE80211_M_STA; /* default to BSS mode */ 662173362Sbenjsc ic->ic_state = IEEE80211_S_INIT; 663173362Sbenjsc 664173362Sbenjsc /* set device capabilities */ 665173362Sbenjsc ic->ic_caps = 666173362Sbenjsc IEEE80211_C_WEP /* s/w WEP */ 667173362Sbenjsc | IEEE80211_C_MONITOR /* monitor mode supported */ 668173362Sbenjsc | IEEE80211_C_TXPMGT /* tx power management */ 669173362Sbenjsc | IEEE80211_C_SHSLOT /* short slot time supported */ 670173362Sbenjsc | IEEE80211_C_SHPREAMBLE /* short preamble supported */ 671173362Sbenjsc | IEEE80211_C_WPA /* 802.11i */ 672173362Sbenjsc/* XXX looks like WME is partly supported? */ 673173362Sbenjsc#if 0 674173362Sbenjsc | IEEE80211_C_IBSS /* IBSS mode support */ 675173362Sbenjsc | IEEE80211_C_BGSCAN /* capable of bg scanning */ 676173362Sbenjsc | IEEE80211_C_WME /* 802.11e */ 677173362Sbenjsc | IEEE80211_C_HOSTAP /* Host access point mode */ 678173362Sbenjsc#endif 679173362Sbenjsc ; 680173362Sbenjsc 681173362Sbenjsc /* 682173362Sbenjsc * Read in the eeprom and also setup the channels for 683173362Sbenjsc * net80211. We don't set the rates as net80211 does this for us 684173362Sbenjsc */ 685173362Sbenjsc wpi_read_eeprom(sc); 686173362Sbenjsc 687173362Sbenjsc if (bootverbose || wpi_debug) { 688173362Sbenjsc device_printf(sc->sc_dev, "Regulatory Domain: %.4s\n", sc->domain); 689173362Sbenjsc device_printf(sc->sc_dev, "Hardware Type: %c\n", 690173362Sbenjsc sc->type > 1 ? 'B': '?'); 691173362Sbenjsc device_printf(sc->sc_dev, "Hardware Revision: %c\n", 692173362Sbenjsc ((le16toh(sc->rev) & 0xf0) == 0xd0) ? 'D': '?'); 693173362Sbenjsc device_printf(sc->sc_dev, "SKU %s support 802.11a\n", 694173362Sbenjsc supportsa ? "does" : "does not"); 695173362Sbenjsc 696173362Sbenjsc /* XXX hw_config uses the PCIDEV for the Hardware rev. Must check 697173362Sbenjsc what sc->rev really represents - benjsc 20070615 */ 698173362Sbenjsc } 699173362Sbenjsc 700173362Sbenjsc if_initname(ifp, device_get_name(dev), device_get_unit(dev)); 701173362Sbenjsc ifp->if_softc = sc; 702173362Sbenjsc ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST; 703173362Sbenjsc ifp->if_init = wpi_init; 704173362Sbenjsc ifp->if_ioctl = wpi_ioctl; 705173362Sbenjsc ifp->if_start = wpi_start; 706173362Sbenjsc IFQ_SET_MAXLEN(&ifp->if_snd, IFQ_MAXLEN); 707173362Sbenjsc ifp->if_snd.ifq_drv_maxlen = IFQ_MAXLEN; 708173362Sbenjsc IFQ_SET_READY(&ifp->if_snd); 709173362Sbenjsc ieee80211_ifattach(ic); 710173362Sbenjsc 711173362Sbenjsc /* override default methods */ 712173362Sbenjsc ic->ic_node_alloc = wpi_node_alloc; 713173362Sbenjsc ic->ic_newassoc = wpi_newassoc; 714173362Sbenjsc ic->ic_wme.wme_update = wpi_wme_update; 715173362Sbenjsc ic->ic_scan_start = wpi_scan_start; 716173362Sbenjsc ic->ic_scan_end = wpi_scan_end; 717173362Sbenjsc ic->ic_set_channel = wpi_set_channel; 718173362Sbenjsc ic->ic_scan_curchan = wpi_scan_curchan; 719173362Sbenjsc ic->ic_scan_mindwell = wpi_scan_mindwell; 720173362Sbenjsc 721173362Sbenjsc /* override state transition machine */ 722173362Sbenjsc sc->sc_newstate = ic->ic_newstate; 723173362Sbenjsc ic->ic_newstate = wpi_newstate; 724173362Sbenjsc ieee80211_media_init(ic, wpi_media_change, ieee80211_media_status); 725173362Sbenjsc 726173362Sbenjsc ieee80211_amrr_init(&sc->amrr, ic, 727173362Sbenjsc IEEE80211_AMRR_MIN_SUCCESS_THRESHOLD, 728173362Sbenjsc IEEE80211_AMRR_MAX_SUCCESS_THRESHOLD); 729173362Sbenjsc 730173362Sbenjsc /* whilst ieee80211_ifattach will listen for ieee80211 frames, 731173362Sbenjsc * we also want to listen for the lower level radio frames 732173362Sbenjsc */ 733173362Sbenjsc bpfattach2(ifp, DLT_IEEE802_11_RADIO, 734173362Sbenjsc sizeof (struct ieee80211_frame) + sizeof (sc->sc_txtap), 735173362Sbenjsc &sc->sc_drvbpf); 736173362Sbenjsc 737173362Sbenjsc sc->sc_rxtap_len = sizeof sc->sc_rxtap; 738173362Sbenjsc sc->sc_rxtap.wr_ihdr.it_len = htole16(sc->sc_rxtap_len); 739173362Sbenjsc sc->sc_rxtap.wr_ihdr.it_present = htole32(WPI_RX_RADIOTAP_PRESENT); 740173362Sbenjsc 741173362Sbenjsc sc->sc_txtap_len = sizeof sc->sc_txtap; 742173362Sbenjsc sc->sc_txtap.wt_ihdr.it_len = htole16(sc->sc_txtap_len); 743173362Sbenjsc sc->sc_txtap.wt_ihdr.it_present = htole32(WPI_TX_RADIOTAP_PRESENT); 744173362Sbenjsc 745173362Sbenjsc /* 746173362Sbenjsc * Hook our interrupt after all initialization is complete. 747173362Sbenjsc */ 748173362Sbenjsc error = bus_setup_intr(dev, sc->irq, INTR_TYPE_NET |INTR_MPSAFE , 749173362Sbenjsc#ifdef WPI_CURRENT 750173362Sbenjsc NULL, 751173362Sbenjsc#endif 752173362Sbenjsc wpi_intr, sc, &sc->sc_ih); 753173362Sbenjsc if (error != 0) { 754173362Sbenjsc device_printf(dev, "could not set up interrupt\n"); 755173362Sbenjsc goto fail; 756173362Sbenjsc } 757173362Sbenjsc 758173362Sbenjsc ieee80211_announce(ic); 759173362Sbenjsc#ifdef XXX_DEBUG 760173362Sbenjsc ieee80211_announce_channels(ic); 761173362Sbenjsc#endif 762173362Sbenjsc 763173362Sbenjsc return 0; 764173362Sbenjsc 765173362Sbenjscfail: wpi_detach(dev); 766173362Sbenjsc return ENXIO; 767173362Sbenjsc} 768173362Sbenjsc 769173362Sbenjscstatic int 770173362Sbenjscwpi_detach(device_t dev) 771173362Sbenjsc{ 772173362Sbenjsc struct wpi_softc *sc = device_get_softc(dev); 773173362Sbenjsc struct ieee80211com *ic = &sc->sc_ic; 774173362Sbenjsc struct ifnet *ifp = ic->ic_ifp; 775173362Sbenjsc int ac; 776173362Sbenjsc WPI_LOCK_DECL; 777173362Sbenjsc 778173362Sbenjsc if (ifp != NULL) { 779173362Sbenjsc wpi_stop(sc); 780173362Sbenjsc callout_drain(&sc->watchdog_to); 781173362Sbenjsc callout_drain(&sc->calib_to); 782173362Sbenjsc bpfdetach(ifp); 783173362Sbenjsc ieee80211_ifdetach(ic); 784173362Sbenjsc } 785173362Sbenjsc 786173362Sbenjsc WPI_LOCK(sc); 787173362Sbenjsc if (sc->txq[0].data_dmat) { 788173362Sbenjsc for (ac = 0; ac < WME_NUM_AC; ac++) 789173362Sbenjsc wpi_free_tx_ring(sc, &sc->txq[ac]); 790173362Sbenjsc 791173362Sbenjsc wpi_free_tx_ring(sc, &sc->cmdq); 792173362Sbenjsc wpi_free_rx_ring(sc, &sc->rxq); 793173362Sbenjsc wpi_free_rpool(sc); 794173362Sbenjsc wpi_free_shared(sc); 795173362Sbenjsc } 796173362Sbenjsc 797173362Sbenjsc if (sc->fw_fp != NULL) { 798173362Sbenjsc wpi_unload_firmware(sc); 799173362Sbenjsc } 800173362Sbenjsc 801173362Sbenjsc if (sc->fw_dma.tag) 802173362Sbenjsc wpi_free_fwmem(sc); 803173362Sbenjsc WPI_UNLOCK(sc); 804173362Sbenjsc 805173362Sbenjsc if (sc->irq != NULL) { 806173362Sbenjsc bus_teardown_intr(dev, sc->irq, sc->sc_ih); 807173362Sbenjsc bus_release_resource(dev, SYS_RES_IRQ, sc->irq_rid, sc->irq); 808173362Sbenjsc } 809173362Sbenjsc 810173362Sbenjsc if (sc->mem != NULL) 811173362Sbenjsc bus_release_resource(dev, SYS_RES_MEMORY, sc->mem_rid, sc->mem); 812173362Sbenjsc 813173362Sbenjsc if (ifp != NULL) 814173362Sbenjsc if_free(ifp); 815173362Sbenjsc 816173362Sbenjsc taskqueue_free(sc->sc_tq); 817173362Sbenjsc taskqueue_free(sc->sc_tq2); 818173362Sbenjsc 819173362Sbenjsc WPI_LOCK_DESTROY(sc); 820173362Sbenjsc WPI_CMD_LOCK_DESTROY(sc); 821173362Sbenjsc 822173362Sbenjsc return 0; 823173362Sbenjsc} 824173362Sbenjsc 825173362Sbenjscstatic void 826173362Sbenjscwpi_dma_map_addr(void *arg, bus_dma_segment_t *segs, int nsegs, int error) 827173362Sbenjsc{ 828173362Sbenjsc if (error != 0) 829173362Sbenjsc return; 830173362Sbenjsc 831173362Sbenjsc KASSERT(nsegs == 1, ("too many DMA segments, %d should be 1", nsegs)); 832173362Sbenjsc 833173362Sbenjsc *(bus_addr_t *)arg = segs[0].ds_addr; 834173362Sbenjsc} 835173362Sbenjsc 836173362Sbenjscstatic int 837173362Sbenjscwpi_dma_contig_alloc(struct wpi_softc *sc, struct wpi_dma_info *dma, 838173362Sbenjsc void **kvap, bus_size_t size, bus_size_t alignment, int flags) 839173362Sbenjsc{ 840173362Sbenjsc int error; 841173362Sbenjsc int count = 0; 842173362Sbenjsc 843173362Sbenjsc DPRINTFN(WPI_DEBUG_DMA, 844173362Sbenjsc ("Size: %zd - alignement %zd\n", size, alignment)); 845173362Sbenjsc 846173362Sbenjsc dma->size = size; 847173362Sbenjsc dma->tag = NULL; 848173362Sbenjsc 849173362Sbenjscagain: 850173362Sbenjsc error = bus_dma_tag_create(bus_get_dma_tag(sc->sc_dev), alignment, 851173362Sbenjsc 0, BUS_SPACE_MAXADDR_32BIT, BUS_SPACE_MAXADDR, 852173362Sbenjsc NULL, NULL, size, 853173362Sbenjsc 1, size, flags, 854173362Sbenjsc NULL, NULL, &dma->tag); 855173362Sbenjsc if (error != 0) { 856173362Sbenjsc device_printf(sc->sc_dev, 857173362Sbenjsc "could not create shared page DMA tag\n"); 858173362Sbenjsc goto fail; 859173362Sbenjsc } 860173362Sbenjsc error = bus_dmamem_alloc(dma->tag, (void **)&dma->vaddr, 861173362Sbenjsc flags | BUS_DMA_ZERO, &dma->map); 862173362Sbenjsc if (error != 0) { 863173362Sbenjsc device_printf(sc->sc_dev, 864173362Sbenjsc "could not allocate shared page DMA memory\n"); 865173362Sbenjsc goto fail; 866173362Sbenjsc } 867173362Sbenjsc 868173362Sbenjsc /** 869173362Sbenjsc * Sadly FreeBSD can't always align on a 16k boundary, hence we give it 870173362Sbenjsc * 10 attempts increasing the size of the allocation by 4k each time. 871173362Sbenjsc * This should eventually align us on a 16k boundary at the cost 872173362Sbenjsc * of chewing up dma memory 873173362Sbenjsc */ 874173362Sbenjsc if ((((uintptr_t)dma->vaddr) & (alignment-1)) && count < 10) { 875173362Sbenjsc DPRINTFN(WPI_DEBUG_DMA, 876173362Sbenjsc ("Memory Unaligned, trying again: %d\n", count++)); 877173362Sbenjsc wpi_dma_contig_free(dma); 878173362Sbenjsc size += 4096; 879173362Sbenjsc goto again; 880173362Sbenjsc } 881173362Sbenjsc 882173362Sbenjsc DPRINTFN(WPI_DEBUG_DMA,("Memory, allocated & %s Aligned!\n", 883173362Sbenjsc count == 10 ? "FAILED" : "")); 884173362Sbenjsc if (count == 10) { 885173362Sbenjsc device_printf(sc->sc_dev, "Unable to align memory\n"); 886173362Sbenjsc error = ENOMEM; 887173362Sbenjsc goto fail; 888173362Sbenjsc } 889173362Sbenjsc 890173362Sbenjsc error = bus_dmamap_load(dma->tag, dma->map, dma->vaddr, 891173362Sbenjsc size, wpi_dma_map_addr, &dma->paddr, flags); 892173362Sbenjsc 893173362Sbenjsc if (error != 0) { 894173362Sbenjsc device_printf(sc->sc_dev, 895173362Sbenjsc "could not load shared page DMA map\n"); 896173362Sbenjsc goto fail; 897173362Sbenjsc } 898173362Sbenjsc 899173362Sbenjsc if (kvap != NULL) 900173362Sbenjsc *kvap = dma->vaddr; 901173362Sbenjsc 902173362Sbenjsc return 0; 903173362Sbenjsc 904173362Sbenjscfail: 905173362Sbenjsc wpi_dma_contig_free(dma); 906173362Sbenjsc return error; 907173362Sbenjsc} 908173362Sbenjsc 909173362Sbenjscstatic void 910173362Sbenjscwpi_dma_contig_free(struct wpi_dma_info *dma) 911173362Sbenjsc{ 912173362Sbenjsc if (dma->tag) { 913173362Sbenjsc if (dma->map != NULL) { 914173362Sbenjsc if (dma->paddr == 0) { 915173362Sbenjsc bus_dmamap_sync(dma->tag, dma->map, 916173362Sbenjsc BUS_DMASYNC_POSTREAD | BUS_DMASYNC_POSTWRITE); 917173362Sbenjsc bus_dmamap_unload(dma->tag, dma->map); 918173362Sbenjsc } 919173362Sbenjsc bus_dmamem_free(dma->tag, &dma->vaddr, dma->map); 920173362Sbenjsc } 921173362Sbenjsc bus_dma_tag_destroy(dma->tag); 922173362Sbenjsc } 923173362Sbenjsc} 924173362Sbenjsc 925173362Sbenjsc/* 926173362Sbenjsc * Allocate a shared page between host and NIC. 927173362Sbenjsc */ 928173362Sbenjscstatic int 929173362Sbenjscwpi_alloc_shared(struct wpi_softc *sc) 930173362Sbenjsc{ 931173362Sbenjsc int error; 932173362Sbenjsc 933173362Sbenjsc error = wpi_dma_contig_alloc(sc, &sc->shared_dma, 934173362Sbenjsc (void **)&sc->shared, sizeof (struct wpi_shared), 935173362Sbenjsc PAGE_SIZE, 936173362Sbenjsc BUS_DMA_NOWAIT); 937173362Sbenjsc 938173362Sbenjsc if (error != 0) { 939173362Sbenjsc device_printf(sc->sc_dev, 940173362Sbenjsc "could not allocate shared area DMA memory\n"); 941173362Sbenjsc } 942173362Sbenjsc 943173362Sbenjsc return error; 944173362Sbenjsc} 945173362Sbenjsc 946173362Sbenjscstatic void 947173362Sbenjscwpi_free_shared(struct wpi_softc *sc) 948173362Sbenjsc{ 949173362Sbenjsc wpi_dma_contig_free(&sc->shared_dma); 950173362Sbenjsc} 951173362Sbenjsc 952173362Sbenjscstruct wpi_rbuf * 953173362Sbenjscwpi_alloc_rbuf(struct wpi_softc *sc) 954173362Sbenjsc{ 955173362Sbenjsc struct wpi_rbuf *rbuf; 956173362Sbenjsc 957173362Sbenjsc rbuf = SLIST_FIRST(&sc->rxq.freelist); 958173362Sbenjsc if (rbuf == NULL) 959173362Sbenjsc return NULL; 960173362Sbenjsc SLIST_REMOVE_HEAD(&sc->rxq.freelist, next); 961173362Sbenjsc return rbuf; 962173362Sbenjsc} 963173362Sbenjsc 964173362Sbenjsc/* 965173362Sbenjsc * This is called automatically by the network stack when the mbuf to which our 966173362Sbenjsc * Rx buffer is attached is freed. 967173362Sbenjsc */ 968173362Sbenjscstatic void 969173362Sbenjscwpi_free_rbuf(void *buf, void *arg) 970173362Sbenjsc{ 971173362Sbenjsc struct wpi_rbuf *rbuf = arg; 972173362Sbenjsc struct wpi_softc *sc = rbuf->sc; 973173362Sbenjsc WPI_LOCK_DECL; 974173362Sbenjsc 975173362Sbenjsc WPI_LOCK(sc); 976173362Sbenjsc 977173362Sbenjsc /* put the buffer back in the free list */ 978173362Sbenjsc SLIST_INSERT_HEAD(&sc->rxq.freelist, rbuf, next); 979173362Sbenjsc 980173362Sbenjsc WPI_UNLOCK(sc); 981173362Sbenjsc} 982173362Sbenjsc 983173362Sbenjscstatic int 984173362Sbenjscwpi_alloc_rpool(struct wpi_softc *sc) 985173362Sbenjsc{ 986173362Sbenjsc struct wpi_rx_ring *ring = &sc->rxq; 987173362Sbenjsc struct wpi_rbuf *rbuf; 988173362Sbenjsc int i, error; 989173362Sbenjsc 990173362Sbenjsc /* allocate a big chunk of DMA'able memory.. */ 991173362Sbenjsc error = wpi_dma_contig_alloc(sc, &ring->buf_dma, NULL, 992173362Sbenjsc WPI_RBUF_COUNT * WPI_RBUF_SIZE, PAGE_SIZE, BUS_DMA_NOWAIT); 993173362Sbenjsc if (error != 0) { 994173362Sbenjsc device_printf(sc->sc_dev, 995173362Sbenjsc "could not allocate Rx buffers DMA memory\n"); 996173362Sbenjsc return error; 997173362Sbenjsc } 998173362Sbenjsc 999173362Sbenjsc /* ..and split it into 3KB chunks */ 1000173362Sbenjsc SLIST_INIT(&ring->freelist); 1001173362Sbenjsc for (i = 0; i < WPI_RBUF_COUNT; i++) { 1002173362Sbenjsc rbuf = &ring->rbuf[i]; 1003173362Sbenjsc 1004173362Sbenjsc rbuf->sc = sc; /* backpointer for callbacks */ 1005173362Sbenjsc rbuf->vaddr = ring->buf_dma.vaddr + i * WPI_RBUF_SIZE; 1006173362Sbenjsc rbuf->paddr = ring->buf_dma.paddr + i * WPI_RBUF_SIZE; 1007173362Sbenjsc 1008173362Sbenjsc SLIST_INSERT_HEAD(&ring->freelist, rbuf, next); 1009173362Sbenjsc } 1010173362Sbenjsc return 0; 1011173362Sbenjsc} 1012173362Sbenjsc 1013173362Sbenjscstatic void 1014173362Sbenjscwpi_free_rpool(struct wpi_softc *sc) 1015173362Sbenjsc{ 1016173362Sbenjsc wpi_dma_contig_free(&sc->rxq.buf_dma); 1017173362Sbenjsc} 1018173362Sbenjsc 1019173362Sbenjscstatic int 1020173362Sbenjscwpi_alloc_rx_ring(struct wpi_softc *sc, struct wpi_rx_ring *ring) 1021173362Sbenjsc{ 1022173362Sbenjsc 1023173362Sbenjsc struct wpi_rx_data *data; 1024173362Sbenjsc struct wpi_rbuf *rbuf; 1025173362Sbenjsc int i, error; 1026173362Sbenjsc 1027173362Sbenjsc ring->cur = 0; 1028173362Sbenjsc 1029173362Sbenjsc error = wpi_dma_contig_alloc(sc, &ring->desc_dma, 1030173362Sbenjsc (void **)&ring->desc, WPI_RX_RING_COUNT * sizeof (uint32_t), 1031173362Sbenjsc WPI_RING_DMA_ALIGN, BUS_DMA_NOWAIT); 1032173362Sbenjsc 1033173362Sbenjsc if (error != 0) { 1034173362Sbenjsc device_printf(sc->sc_dev, 1035173362Sbenjsc "could not allocate rx ring DMA memory\n"); 1036173362Sbenjsc goto fail; 1037173362Sbenjsc } 1038173362Sbenjsc 1039173362Sbenjsc /* 1040173362Sbenjsc * Allocate Rx buffers. 1041173362Sbenjsc */ 1042173362Sbenjsc for (i = 0; i < WPI_RX_RING_COUNT; i++) { 1043173362Sbenjsc data = &ring->data[i]; 1044173362Sbenjsc 1045173362Sbenjsc data->m = m_get(M_DONTWAIT, MT_HEADER); 1046173362Sbenjsc if (data->m == NULL) { 1047173362Sbenjsc device_printf(sc->sc_dev, 1048173362Sbenjsc "could not allocate rx mbuf\n"); 1049173362Sbenjsc error = ENOBUFS; 1050173362Sbenjsc goto fail; 1051173362Sbenjsc } 1052173362Sbenjsc 1053173362Sbenjsc if ((rbuf = wpi_alloc_rbuf(sc)) == NULL) { 1054173362Sbenjsc m_freem(data->m); 1055173362Sbenjsc data->m = NULL; 1056173362Sbenjsc device_printf(sc->sc_dev, 1057173362Sbenjsc "could not allocate rx buffer\n"); 1058173362Sbenjsc error = ENOBUFS; 1059173362Sbenjsc goto fail; 1060173362Sbenjsc } 1061173362Sbenjsc 1062173362Sbenjsc /* attach RxBuffer to mbuf */ 1063173362Sbenjsc MEXTADD(data->m, rbuf->vaddr, WPI_RBUF_SIZE,wpi_free_rbuf, 1064173362Sbenjsc rbuf,0,EXT_NET_DRV); 1065173362Sbenjsc 1066173362Sbenjsc if ((data->m->m_flags & M_EXT) == 0) { 1067173362Sbenjsc m_freem(data->m); 1068173362Sbenjsc data->m = NULL; 1069173362Sbenjsc error = ENOBUFS; 1070173362Sbenjsc goto fail; 1071173362Sbenjsc } 1072173362Sbenjsc ring->desc[i] = htole32(rbuf->paddr); 1073173362Sbenjsc } 1074173362Sbenjsc 1075173362Sbenjsc bus_dmamap_sync(ring->desc_dma.tag, ring->desc_dma.map, 1076173362Sbenjsc BUS_DMASYNC_PREWRITE); 1077173362Sbenjsc 1078173362Sbenjsc return 0; 1079173362Sbenjsc 1080173362Sbenjscfail: 1081173362Sbenjsc wpi_free_rx_ring(sc, ring); 1082173362Sbenjsc return error; 1083173362Sbenjsc} 1084173362Sbenjsc 1085173362Sbenjscstatic void 1086173362Sbenjscwpi_reset_rx_ring(struct wpi_softc *sc, struct wpi_rx_ring *ring) 1087173362Sbenjsc{ 1088173362Sbenjsc int ntries; 1089173362Sbenjsc 1090173362Sbenjsc wpi_mem_lock(sc); 1091173362Sbenjsc 1092173362Sbenjsc WPI_WRITE(sc, WPI_RX_CONFIG, 0); 1093173362Sbenjsc 1094173362Sbenjsc for (ntries = 0; ntries < 100; ntries++) { 1095173362Sbenjsc if (WPI_READ(sc, WPI_RX_STATUS) & WPI_RX_IDLE) 1096173362Sbenjsc break; 1097173362Sbenjsc DELAY(10); 1098173362Sbenjsc } 1099173362Sbenjsc 1100173362Sbenjsc wpi_mem_unlock(sc); 1101173362Sbenjsc 1102173362Sbenjsc#ifdef WPI_DEBUG 1103173362Sbenjsc if (ntries == 100 && wpi_debug > 0) 1104173362Sbenjsc device_printf(sc->sc_dev, "timeout resetting Rx ring\n"); 1105173362Sbenjsc#endif 1106173362Sbenjsc 1107173362Sbenjsc ring->cur = 0; 1108173362Sbenjsc} 1109173362Sbenjsc 1110173362Sbenjscstatic void 1111173362Sbenjscwpi_free_rx_ring(struct wpi_softc *sc, struct wpi_rx_ring *ring) 1112173362Sbenjsc{ 1113173362Sbenjsc int i; 1114173362Sbenjsc 1115173362Sbenjsc wpi_dma_contig_free(&ring->desc_dma); 1116173362Sbenjsc 1117173362Sbenjsc for (i = 0; i < WPI_RX_RING_COUNT; i++) { 1118173362Sbenjsc if (ring->data[i].m != NULL) { 1119173362Sbenjsc m_freem(ring->data[i].m); 1120173362Sbenjsc ring->data[i].m = NULL; 1121173362Sbenjsc } 1122173362Sbenjsc } 1123173362Sbenjsc} 1124173362Sbenjsc 1125173362Sbenjscstatic int 1126173362Sbenjscwpi_alloc_tx_ring(struct wpi_softc *sc, struct wpi_tx_ring *ring, int count, 1127173362Sbenjsc int qid) 1128173362Sbenjsc{ 1129173362Sbenjsc struct wpi_tx_data *data; 1130173362Sbenjsc int i, error; 1131173362Sbenjsc 1132173362Sbenjsc ring->qid = qid; 1133173362Sbenjsc ring->count = count; 1134173362Sbenjsc ring->queued = 0; 1135173362Sbenjsc ring->cur = 0; 1136173362Sbenjsc ring->data = NULL; 1137173362Sbenjsc 1138173362Sbenjsc error = wpi_dma_contig_alloc(sc, &ring->desc_dma, 1139173362Sbenjsc (void **)&ring->desc, count * sizeof (struct wpi_tx_desc), 1140173362Sbenjsc WPI_RING_DMA_ALIGN, BUS_DMA_NOWAIT); 1141173362Sbenjsc 1142173362Sbenjsc if (error != 0) { 1143173362Sbenjsc device_printf(sc->sc_dev, "could not allocate tx dma memory\n"); 1144173362Sbenjsc goto fail; 1145173362Sbenjsc } 1146173362Sbenjsc 1147173362Sbenjsc /* update shared page with ring's base address */ 1148173362Sbenjsc sc->shared->txbase[qid] = htole32(ring->desc_dma.paddr); 1149173362Sbenjsc 1150173362Sbenjsc error = wpi_dma_contig_alloc(sc, &ring->cmd_dma, (void **)&ring->cmd, 1151173362Sbenjsc count * sizeof (struct wpi_tx_cmd), WPI_RING_DMA_ALIGN, 1152173362Sbenjsc BUS_DMA_NOWAIT); 1153173362Sbenjsc 1154173362Sbenjsc if (error != 0) { 1155173362Sbenjsc device_printf(sc->sc_dev, 1156173362Sbenjsc "could not allocate tx command DMA memory\n"); 1157173362Sbenjsc goto fail; 1158173362Sbenjsc } 1159173362Sbenjsc 1160173362Sbenjsc ring->data = malloc(count * sizeof (struct wpi_tx_data), M_DEVBUF, 1161173362Sbenjsc M_NOWAIT | M_ZERO); 1162173362Sbenjsc if (ring->data == NULL) { 1163173362Sbenjsc device_printf(sc->sc_dev, 1164173362Sbenjsc "could not allocate tx data slots\n"); 1165173362Sbenjsc goto fail; 1166173362Sbenjsc } 1167173362Sbenjsc 1168173362Sbenjsc error = bus_dma_tag_create(bus_get_dma_tag(sc->sc_dev), 1, 0, 1169173362Sbenjsc BUS_SPACE_MAXADDR_32BIT, BUS_SPACE_MAXADDR, NULL, NULL, MCLBYTES, 1170173362Sbenjsc WPI_MAX_SCATTER - 1, MCLBYTES, BUS_DMA_NOWAIT, NULL, NULL, 1171173362Sbenjsc &ring->data_dmat); 1172173362Sbenjsc if (error != 0) { 1173173362Sbenjsc device_printf(sc->sc_dev, "could not create data DMA tag\n"); 1174173362Sbenjsc goto fail; 1175173362Sbenjsc } 1176173362Sbenjsc 1177173362Sbenjsc for (i = 0; i < count; i++) { 1178173362Sbenjsc data = &ring->data[i]; 1179173362Sbenjsc 1180173362Sbenjsc error = bus_dmamap_create(ring->data_dmat, 0, &data->map); 1181173362Sbenjsc if (error != 0) { 1182173362Sbenjsc device_printf(sc->sc_dev, 1183173362Sbenjsc "could not create tx buf DMA map\n"); 1184173362Sbenjsc goto fail; 1185173362Sbenjsc } 1186173362Sbenjsc bus_dmamap_sync(ring->data_dmat, data->map, 1187173362Sbenjsc BUS_DMASYNC_PREWRITE); 1188173362Sbenjsc } 1189173362Sbenjsc 1190173362Sbenjsc return 0; 1191173362Sbenjsc 1192173362Sbenjscfail: wpi_free_tx_ring(sc, ring); 1193173362Sbenjsc return error; 1194173362Sbenjsc} 1195173362Sbenjsc 1196173362Sbenjscstatic void 1197173362Sbenjscwpi_reset_tx_ring(struct wpi_softc *sc, struct wpi_tx_ring *ring) 1198173362Sbenjsc{ 1199173362Sbenjsc struct wpi_tx_data *data; 1200173362Sbenjsc int i, ntries; 1201173362Sbenjsc 1202173362Sbenjsc wpi_mem_lock(sc); 1203173362Sbenjsc 1204173362Sbenjsc WPI_WRITE(sc, WPI_TX_CONFIG(ring->qid), 0); 1205173362Sbenjsc for (ntries = 0; ntries < 100; ntries++) { 1206173362Sbenjsc if (WPI_READ(sc, WPI_TX_STATUS) & WPI_TX_IDLE(ring->qid)) 1207173362Sbenjsc break; 1208173362Sbenjsc DELAY(10); 1209173362Sbenjsc } 1210173362Sbenjsc#ifdef WPI_DEBUG 1211173362Sbenjsc if (ntries == 100 && wpi_debug > 0) { 1212173362Sbenjsc device_printf(sc->sc_dev, "timeout resetting Tx ring %d\n", 1213173362Sbenjsc ring->qid); 1214173362Sbenjsc } 1215173362Sbenjsc#endif 1216173362Sbenjsc wpi_mem_unlock(sc); 1217173362Sbenjsc 1218173362Sbenjsc for (i = 0; i < ring->count; i++) { 1219173362Sbenjsc data = &ring->data[i]; 1220173362Sbenjsc 1221173362Sbenjsc if (data->m != NULL) { 1222173362Sbenjsc bus_dmamap_unload(ring->data_dmat, data->map); 1223173362Sbenjsc m_freem(data->m); 1224173362Sbenjsc data->m = NULL; 1225173362Sbenjsc } 1226173362Sbenjsc } 1227173362Sbenjsc 1228173362Sbenjsc ring->queued = 0; 1229173362Sbenjsc ring->cur = 0; 1230173362Sbenjsc} 1231173362Sbenjsc 1232173362Sbenjscstatic void 1233173362Sbenjscwpi_free_tx_ring(struct wpi_softc *sc, struct wpi_tx_ring *ring) 1234173362Sbenjsc{ 1235173362Sbenjsc struct wpi_tx_data *data; 1236173362Sbenjsc int i; 1237173362Sbenjsc 1238173362Sbenjsc wpi_dma_contig_free(&ring->desc_dma); 1239173362Sbenjsc wpi_dma_contig_free(&ring->cmd_dma); 1240173362Sbenjsc 1241173362Sbenjsc if (ring->data != NULL) { 1242173362Sbenjsc for (i = 0; i < ring->count; i++) { 1243173362Sbenjsc data = &ring->data[i]; 1244173362Sbenjsc 1245173362Sbenjsc if (data->m != NULL) { 1246173362Sbenjsc bus_dmamap_sync(ring->data_dmat, data->map, 1247173362Sbenjsc BUS_DMASYNC_POSTWRITE); 1248173362Sbenjsc bus_dmamap_unload(ring->data_dmat, data->map); 1249173362Sbenjsc m_freem(data->m); 1250173362Sbenjsc data->m = NULL; 1251173362Sbenjsc } 1252173362Sbenjsc } 1253173362Sbenjsc free(ring->data, M_DEVBUF); 1254173362Sbenjsc } 1255173362Sbenjsc 1256173362Sbenjsc if (ring->data_dmat != NULL) 1257173362Sbenjsc bus_dma_tag_destroy(ring->data_dmat); 1258173362Sbenjsc} 1259173362Sbenjsc 1260173362Sbenjscstatic int 1261173362Sbenjscwpi_shutdown(device_t dev) 1262173362Sbenjsc{ 1263173362Sbenjsc struct wpi_softc *sc = device_get_softc(dev); 1264173362Sbenjsc WPI_LOCK_DECL; 1265173362Sbenjsc 1266173362Sbenjsc WPI_LOCK(sc); 1267173362Sbenjsc wpi_stop_locked(sc); 1268173362Sbenjsc wpi_unload_firmware(sc); 1269173362Sbenjsc WPI_UNLOCK(sc); 1270173362Sbenjsc 1271173362Sbenjsc return 0; 1272173362Sbenjsc} 1273173362Sbenjsc 1274173362Sbenjscstatic int 1275173362Sbenjscwpi_suspend(device_t dev) 1276173362Sbenjsc{ 1277173362Sbenjsc struct wpi_softc *sc = device_get_softc(dev); 1278173362Sbenjsc 1279173362Sbenjsc wpi_stop(sc); 1280173362Sbenjsc return 0; 1281173362Sbenjsc} 1282173362Sbenjsc 1283173362Sbenjscstatic int 1284173362Sbenjscwpi_resume(device_t dev) 1285173362Sbenjsc{ 1286173362Sbenjsc struct wpi_softc *sc = device_get_softc(dev); 1287173362Sbenjsc struct ifnet *ifp = sc->sc_ic.ic_ifp; 1288173362Sbenjsc 1289173362Sbenjsc pci_write_config(dev, 0x41, 0, 1); 1290173362Sbenjsc 1291173362Sbenjsc if (ifp->if_flags & IFF_UP) { 1292173362Sbenjsc wpi_init(ifp->if_softc); 1293173362Sbenjsc if (ifp->if_drv_flags & IFF_DRV_RUNNING) 1294173362Sbenjsc wpi_start(ifp); 1295173362Sbenjsc } 1296173362Sbenjsc return 0; 1297173362Sbenjsc} 1298173362Sbenjsc 1299173362Sbenjsc/* ARGSUSED */ 1300173362Sbenjscstatic struct ieee80211_node * 1301173362Sbenjscwpi_node_alloc(struct ieee80211_node_table *ic) 1302173362Sbenjsc{ 1303173362Sbenjsc struct wpi_node *wn; 1304173362Sbenjsc 1305173362Sbenjsc wn = malloc(sizeof (struct wpi_node), M_80211_NODE, M_NOWAIT |M_ZERO); 1306173362Sbenjsc 1307173362Sbenjsc return &wn->ni; 1308173362Sbenjsc} 1309173362Sbenjsc 1310173362Sbenjscstatic int 1311173362Sbenjscwpi_media_change(struct ifnet *ifp) 1312173362Sbenjsc{ 1313173362Sbenjsc int error; 1314173362Sbenjsc 1315173362Sbenjsc error = ieee80211_media_change(ifp); 1316173362Sbenjsc if (error != ENETRESET) 1317173362Sbenjsc return error; 1318173362Sbenjsc 1319173362Sbenjsc if ((ifp->if_flags & IFF_UP) && (ifp->if_drv_flags & IFF_DRV_RUNNING)) 1320173362Sbenjsc wpi_init(ifp->if_softc); 1321173362Sbenjsc 1322173362Sbenjsc return 0; 1323173362Sbenjsc} 1324173362Sbenjsc 1325173362Sbenjsc/** 1326173362Sbenjsc * Called by net80211 when ever there is a change to 80211 state machine 1327173362Sbenjsc */ 1328173362Sbenjscstatic int 1329173362Sbenjscwpi_newstate(struct ieee80211com *ic, enum ieee80211_state nstate, int arg) 1330173362Sbenjsc{ 1331173362Sbenjsc struct ifnet *ifp = ic->ic_ifp; 1332173362Sbenjsc struct wpi_softc *sc = ifp->if_softc; 1333173362Sbenjsc struct ieee80211_node *ni; 1334173362Sbenjsc int error; 1335173362Sbenjsc 1336173362Sbenjsc callout_stop(&sc->calib_to); 1337173362Sbenjsc 1338173362Sbenjsc switch (nstate) { 1339173362Sbenjsc case IEEE80211_S_SCAN: 1340173362Sbenjsc DPRINTF(("NEWSTATE:SCAN\n")); 1341173362Sbenjsc /* Scanning is handled in net80211 via the scan_start, 1342173362Sbenjsc * scan_end, scan_curchan functions. Hence all we do when 1343173362Sbenjsc * changing to the SCAN state is update the leds 1344173362Sbenjsc */ 1345173362Sbenjsc 1346173362Sbenjsc /* make the link LED blink while we're scanning */ 1347173362Sbenjsc wpi_set_led(sc, WPI_LED_LINK, 20, 2); 1348173362Sbenjsc break; 1349173362Sbenjsc 1350173362Sbenjsc case IEEE80211_S_ASSOC: 1351173362Sbenjsc DPRINTF(("NEWSTATE:ASSOC\n")); 1352173362Sbenjsc if (ic->ic_state != IEEE80211_S_RUN) 1353173362Sbenjsc break; 1354173362Sbenjsc /* FALLTHROUGH */ 1355173362Sbenjsc 1356173362Sbenjsc case IEEE80211_S_AUTH: 1357173362Sbenjsc DPRINTF(("NEWSTATE:AUTH\n")); 1358173362Sbenjsc sc->flags |= WPI_FLAG_AUTH; 1359173362Sbenjsc sc->config.associd = 0; 1360173362Sbenjsc sc->config.filter &= ~htole32(WPI_FILTER_BSS); 1361173362Sbenjsc wpi_queue_cmd(sc,WPI_AUTH); 1362173362Sbenjsc DPRINTF(("END AUTH\n")); 1363173362Sbenjsc break; 1364173362Sbenjsc 1365173362Sbenjsc case IEEE80211_S_RUN: 1366173362Sbenjsc DPRINTF(("NEWSTATE:RUN\n")); 1367173362Sbenjsc if (ic->ic_opmode == IEEE80211_M_MONITOR) { 1368173362Sbenjsc /* link LED blinks while monitoring */ 1369173362Sbenjsc wpi_set_led(sc, WPI_LED_LINK, 5, 5); 1370173362Sbenjsc break; 1371173362Sbenjsc } 1372173362Sbenjsc 1373173362Sbenjsc#if 0 1374173362Sbenjsc if (ic->ic_opmode != IEEE80211_M_STA) { 1375173362Sbenjsc (void) wpi_auth(sc); /* XXX */ 1376173362Sbenjsc wpi_setup_beacon(sc, ic->ic_bss); 1377173362Sbenjsc } 1378173362Sbenjsc#endif 1379173362Sbenjsc 1380173362Sbenjsc ni = ic->ic_bss; 1381173362Sbenjsc wpi_enable_tsf(sc, ni); 1382173362Sbenjsc 1383173362Sbenjsc /* update adapter's configuration */ 1384173362Sbenjsc sc->config.associd = htole16(ni->ni_associd & ~0xc000); 1385173362Sbenjsc /* short preamble/slot time are negotiated when associating */ 1386173362Sbenjsc sc->config.flags &= ~htole32(WPI_CONFIG_SHPREAMBLE | 1387173362Sbenjsc WPI_CONFIG_SHSLOT); 1388173362Sbenjsc if (ic->ic_flags & IEEE80211_F_SHSLOT) 1389173362Sbenjsc sc->config.flags |= htole32(WPI_CONFIG_SHSLOT); 1390173362Sbenjsc if (ic->ic_flags & IEEE80211_F_SHPREAMBLE) 1391173362Sbenjsc sc->config.flags |= htole32(WPI_CONFIG_SHPREAMBLE); 1392173362Sbenjsc sc->config.filter |= htole32(WPI_FILTER_BSS); 1393173362Sbenjsc#if 0 1394173362Sbenjsc if (ic->ic_opmode != IEEE80211_M_STA) 1395173362Sbenjsc sc->config.filter |= htole32(WPI_FILTER_BEACON); 1396173362Sbenjsc#endif 1397173362Sbenjsc 1398173362Sbenjsc/* XXX put somewhere HC_QOS_SUPPORT_ASSOC + HC_IBSS_START */ 1399173362Sbenjsc 1400173362Sbenjsc DPRINTF(("config chan %d flags %x\n", sc->config.chan, 1401173362Sbenjsc sc->config.flags)); 1402173362Sbenjsc error = wpi_cmd(sc, WPI_CMD_CONFIGURE, &sc->config, 1403173362Sbenjsc sizeof (struct wpi_config), 1); 1404173362Sbenjsc if (error != 0) { 1405173362Sbenjsc device_printf(sc->sc_dev, 1406173362Sbenjsc "could not update configuration\n"); 1407173362Sbenjsc return error; 1408173362Sbenjsc } 1409173362Sbenjsc 1410173362Sbenjsc if ((error = wpi_set_txpower(sc, ic->ic_bss->ni_chan, 1)) != 0) { 1411173362Sbenjsc device_printf(sc->sc_dev, 1412173362Sbenjsc "could set txpower\n"); 1413173362Sbenjsc return error; 1414173362Sbenjsc } 1415173362Sbenjsc 1416173362Sbenjsc if (ic->ic_opmode == IEEE80211_M_STA) { 1417173362Sbenjsc /* fake a join to init the tx rate */ 1418173362Sbenjsc wpi_newassoc(ic->ic_bss, 1); 1419173362Sbenjsc } 1420173362Sbenjsc 1421173362Sbenjsc /* start automatic rate control timer */ 1422173362Sbenjsc callout_reset(&sc->calib_to, hz/2, wpi_calib_timeout, sc); 1423173362Sbenjsc 1424173362Sbenjsc /* link LED always on while associated */ 1425173362Sbenjsc wpi_set_led(sc, WPI_LED_LINK, 0, 1); 1426173362Sbenjsc break; 1427173362Sbenjsc 1428173362Sbenjsc case IEEE80211_S_INIT: 1429173362Sbenjsc DPRINTF(("NEWSTATE:INIT\n")); 1430173362Sbenjsc break; 1431173362Sbenjsc 1432173362Sbenjsc default: 1433173362Sbenjsc break; 1434173362Sbenjsc } 1435173362Sbenjsc 1436173362Sbenjsc return (*sc->sc_newstate)(ic, nstate, arg); 1437173362Sbenjsc} 1438173362Sbenjsc 1439173362Sbenjsc/* 1440173362Sbenjsc * Grab exclusive access to NIC memory. 1441173362Sbenjsc */ 1442173362Sbenjscstatic void 1443173362Sbenjscwpi_mem_lock(struct wpi_softc *sc) 1444173362Sbenjsc{ 1445173362Sbenjsc int ntries; 1446173362Sbenjsc uint32_t tmp; 1447173362Sbenjsc 1448173362Sbenjsc tmp = WPI_READ(sc, WPI_GPIO_CTL); 1449173362Sbenjsc WPI_WRITE(sc, WPI_GPIO_CTL, tmp | WPI_GPIO_MAC); 1450173362Sbenjsc 1451173362Sbenjsc /* spin until we actually get the lock */ 1452173362Sbenjsc for (ntries = 0; ntries < 100; ntries++) { 1453173362Sbenjsc if ((WPI_READ(sc, WPI_GPIO_CTL) & 1454173362Sbenjsc (WPI_GPIO_CLOCK | WPI_GPIO_SLEEP)) == WPI_GPIO_CLOCK) 1455173362Sbenjsc break; 1456173362Sbenjsc DELAY(10); 1457173362Sbenjsc } 1458173362Sbenjsc if (ntries == 100) 1459173362Sbenjsc device_printf(sc->sc_dev, "could not lock memory\n"); 1460173362Sbenjsc} 1461173362Sbenjsc 1462173362Sbenjsc/* 1463173362Sbenjsc * Release lock on NIC memory. 1464173362Sbenjsc */ 1465173362Sbenjscstatic void 1466173362Sbenjscwpi_mem_unlock(struct wpi_softc *sc) 1467173362Sbenjsc{ 1468173362Sbenjsc uint32_t tmp = WPI_READ(sc, WPI_GPIO_CTL); 1469173362Sbenjsc WPI_WRITE(sc, WPI_GPIO_CTL, tmp & ~WPI_GPIO_MAC); 1470173362Sbenjsc} 1471173362Sbenjsc 1472173362Sbenjscstatic uint32_t 1473173362Sbenjscwpi_mem_read(struct wpi_softc *sc, uint16_t addr) 1474173362Sbenjsc{ 1475173362Sbenjsc WPI_WRITE(sc, WPI_READ_MEM_ADDR, WPI_MEM_4 | addr); 1476173362Sbenjsc return WPI_READ(sc, WPI_READ_MEM_DATA); 1477173362Sbenjsc} 1478173362Sbenjsc 1479173362Sbenjscstatic void 1480173362Sbenjscwpi_mem_write(struct wpi_softc *sc, uint16_t addr, uint32_t data) 1481173362Sbenjsc{ 1482173362Sbenjsc WPI_WRITE(sc, WPI_WRITE_MEM_ADDR, WPI_MEM_4 | addr); 1483173362Sbenjsc WPI_WRITE(sc, WPI_WRITE_MEM_DATA, data); 1484173362Sbenjsc} 1485173362Sbenjsc 1486173362Sbenjscstatic void 1487173362Sbenjscwpi_mem_write_region_4(struct wpi_softc *sc, uint16_t addr, 1488173362Sbenjsc const uint32_t *data, int wlen) 1489173362Sbenjsc{ 1490173362Sbenjsc for (; wlen > 0; wlen--, data++, addr+=4) 1491173362Sbenjsc wpi_mem_write(sc, addr, *data); 1492173362Sbenjsc} 1493173362Sbenjsc 1494173362Sbenjsc/* 1495173362Sbenjsc * Read data from the EEPROM. We access EEPROM through the MAC instead of 1496173362Sbenjsc * using the traditional bit-bang method. Data is read up until len bytes have 1497173362Sbenjsc * been obtained. 1498173362Sbenjsc */ 1499173362Sbenjscstatic uint16_t 1500173362Sbenjscwpi_read_prom_data(struct wpi_softc *sc, uint32_t addr, void *data, int len) 1501173362Sbenjsc{ 1502173362Sbenjsc int ntries; 1503173362Sbenjsc uint32_t val; 1504173362Sbenjsc uint8_t *out = data; 1505173362Sbenjsc 1506173362Sbenjsc wpi_mem_lock(sc); 1507173362Sbenjsc 1508173362Sbenjsc for (; len > 0; len -= 2, addr++) { 1509173362Sbenjsc WPI_WRITE(sc, WPI_EEPROM_CTL, addr << 2); 1510173362Sbenjsc 1511173362Sbenjsc for (ntries = 0; ntries < 10; ntries++) { 1512173362Sbenjsc if ((val = WPI_READ(sc, WPI_EEPROM_CTL)) & WPI_EEPROM_READY) 1513173362Sbenjsc break; 1514173362Sbenjsc DELAY(5); 1515173362Sbenjsc } 1516173362Sbenjsc 1517173362Sbenjsc if (ntries == 10) { 1518173362Sbenjsc device_printf(sc->sc_dev, "could not read EEPROM\n"); 1519173362Sbenjsc return ETIMEDOUT; 1520173362Sbenjsc } 1521173362Sbenjsc 1522173362Sbenjsc *out++= val >> 16; 1523173362Sbenjsc if (len > 1) 1524173362Sbenjsc *out ++= val >> 24; 1525173362Sbenjsc } 1526173362Sbenjsc 1527173362Sbenjsc wpi_mem_unlock(sc); 1528173362Sbenjsc 1529173362Sbenjsc return 0; 1530173362Sbenjsc} 1531173362Sbenjsc 1532173362Sbenjsc/* 1533173362Sbenjsc * The firmware text and data segments are transferred to the NIC using DMA. 1534173362Sbenjsc * The driver just copies the firmware into DMA-safe memory and tells the NIC 1535173362Sbenjsc * where to find it. Once the NIC has copied the firmware into its internal 1536173362Sbenjsc * memory, we can free our local copy in the driver. 1537173362Sbenjsc */ 1538173362Sbenjscstatic int 1539173362Sbenjscwpi_load_microcode(struct wpi_softc *sc, const uint8_t *fw, int size) 1540173362Sbenjsc{ 1541173362Sbenjsc int error, ntries; 1542173362Sbenjsc 1543173362Sbenjsc DPRINTFN(WPI_DEBUG_HW,("Loading microcode size 0x%x\n", size)); 1544173362Sbenjsc 1545173362Sbenjsc size /= sizeof(uint32_t); 1546173362Sbenjsc 1547173362Sbenjsc wpi_mem_lock(sc); 1548173362Sbenjsc 1549173362Sbenjsc wpi_mem_write_region_4(sc, WPI_MEM_UCODE_BASE, 1550173362Sbenjsc (const uint32_t *)fw, size); 1551173362Sbenjsc 1552173362Sbenjsc wpi_mem_write(sc, WPI_MEM_UCODE_SRC, 0); 1553173362Sbenjsc wpi_mem_write(sc, WPI_MEM_UCODE_DST, WPI_FW_TEXT); 1554173362Sbenjsc wpi_mem_write(sc, WPI_MEM_UCODE_SIZE, size); 1555173362Sbenjsc 1556173362Sbenjsc /* run microcode */ 1557173362Sbenjsc wpi_mem_write(sc, WPI_MEM_UCODE_CTL, WPI_UC_RUN); 1558173362Sbenjsc 1559173362Sbenjsc /* wait while the adapter is busy copying the firmware */ 1560173362Sbenjsc for (error = 0, ntries = 0; ntries < 1000; ntries++) { 1561173362Sbenjsc uint32_t status = WPI_READ(sc, WPI_TX_STATUS); 1562173362Sbenjsc DPRINTFN(WPI_DEBUG_HW, 1563173362Sbenjsc ("firmware status=0x%x, val=0x%x, result=0x%x\n", status, 1564173362Sbenjsc WPI_TX_IDLE(6), status & WPI_TX_IDLE(6))); 1565173362Sbenjsc if (status & WPI_TX_IDLE(6)) { 1566173362Sbenjsc DPRINTFN(WPI_DEBUG_HW, 1567173362Sbenjsc ("Status Match! - ntries = %d\n", ntries)); 1568173362Sbenjsc break; 1569173362Sbenjsc } 1570173362Sbenjsc DELAY(10); 1571173362Sbenjsc } 1572173362Sbenjsc if (ntries == 1000) { 1573173362Sbenjsc device_printf(sc->sc_dev, "timeout transferring firmware\n"); 1574173362Sbenjsc error = ETIMEDOUT; 1575173362Sbenjsc } 1576173362Sbenjsc 1577173362Sbenjsc /* start the microcode executing */ 1578173362Sbenjsc wpi_mem_write(sc, WPI_MEM_UCODE_CTL, WPI_UC_ENABLE); 1579173362Sbenjsc 1580173362Sbenjsc wpi_mem_unlock(sc); 1581173362Sbenjsc 1582173362Sbenjsc return (error); 1583173362Sbenjsc} 1584173362Sbenjsc 1585173362Sbenjscstatic void 1586173362Sbenjscwpi_rx_intr(struct wpi_softc *sc, struct wpi_rx_desc *desc, 1587173362Sbenjsc struct wpi_rx_data *data) 1588173362Sbenjsc{ 1589173362Sbenjsc struct ieee80211com *ic = &sc->sc_ic; 1590173362Sbenjsc struct ifnet *ifp = ic->ic_ifp; 1591173362Sbenjsc struct wpi_rx_ring *ring = &sc->rxq; 1592173362Sbenjsc struct wpi_rx_stat *stat; 1593173362Sbenjsc struct wpi_rx_head *head; 1594173362Sbenjsc struct wpi_rx_tail *tail; 1595173362Sbenjsc struct wpi_rbuf *rbuf; 1596173362Sbenjsc struct ieee80211_frame *wh; 1597173362Sbenjsc struct ieee80211_node *ni; 1598173362Sbenjsc struct mbuf *m, *mnew; 1599173362Sbenjsc WPI_LOCK_DECL; 1600173362Sbenjsc 1601173362Sbenjsc stat = (struct wpi_rx_stat *)(desc + 1); 1602173362Sbenjsc 1603173362Sbenjsc if (stat->len > WPI_STAT_MAXLEN) { 1604173362Sbenjsc device_printf(sc->sc_dev, "invalid rx statistic header\n"); 1605173362Sbenjsc ifp->if_ierrors++; 1606173362Sbenjsc return; 1607173362Sbenjsc } 1608173362Sbenjsc 1609173362Sbenjsc head = (struct wpi_rx_head *)((caddr_t)(stat + 1) + stat->len); 1610173362Sbenjsc tail = (struct wpi_rx_tail *)((caddr_t)(head + 1) + le16toh(head->len)); 1611173362Sbenjsc 1612173362Sbenjsc DPRINTFN(WPI_DEBUG_RX, ("rx intr: idx=%d len=%d stat len=%d rssi=%d " 1613173362Sbenjsc "rate=%x chan=%d tstamp=%ju\n", ring->cur, le32toh(desc->len), 1614173362Sbenjsc le16toh(head->len), (int8_t)stat->rssi, head->rate, head->chan, 1615173362Sbenjsc (uintmax_t)le64toh(tail->tstamp))); 1616173362Sbenjsc 1617173362Sbenjsc m = data->m; 1618173362Sbenjsc 1619173362Sbenjsc /* finalize mbuf */ 1620173362Sbenjsc m->m_pkthdr.rcvif = ifp; 1621173362Sbenjsc m->m_data = (caddr_t)(head + 1); 1622173362Sbenjsc m->m_pkthdr.len = m->m_len = le16toh(head->len); 1623173362Sbenjsc 1624173362Sbenjsc if ((rbuf = SLIST_FIRST(&sc->rxq.freelist)) != NULL) { 1625173362Sbenjsc mnew = m_gethdr(M_DONTWAIT,MT_DATA); 1626173362Sbenjsc if (mnew == NULL) { 1627173362Sbenjsc ifp->if_ierrors++; 1628173362Sbenjsc return; 1629173362Sbenjsc } 1630173362Sbenjsc 1631173362Sbenjsc /* attach Rx buffer to mbuf */ 1632173362Sbenjsc MEXTADD(mnew,rbuf->vaddr,WPI_RBUF_SIZE, wpi_free_rbuf, rbuf, 0, 1633173362Sbenjsc EXT_NET_DRV); 1634173362Sbenjsc SLIST_REMOVE_HEAD(&sc->rxq.freelist, next); 1635173362Sbenjsc data->m = mnew; 1636173362Sbenjsc 1637173362Sbenjsc /* update Rx descriptor */ 1638173362Sbenjsc ring->desc[ring->cur] = htole32(rbuf->paddr); 1639173362Sbenjsc } else { 1640173362Sbenjsc /* no free rbufs, copy frame */ 1641173362Sbenjsc m = m_dup(m, M_DONTWAIT); 1642173362Sbenjsc if (m == NULL) { 1643173362Sbenjsc /* no free mbufs either, drop frame */ 1644173362Sbenjsc ifp->if_ierrors++; 1645173362Sbenjsc return; 1646173362Sbenjsc } 1647173362Sbenjsc } 1648173362Sbenjsc 1649173362Sbenjsc#ifndef WPI_CURRENT 1650173362Sbenjsc if (sc->sc_drvbpf != NULL) { 1651173362Sbenjsc#else 1652173362Sbenjsc if (bpf_peers_present(sc->sc_drvbpf)) { 1653173362Sbenjsc#endif 1654173362Sbenjsc struct wpi_rx_radiotap_header *tap = &sc->sc_rxtap; 1655173362Sbenjsc 1656173362Sbenjsc tap->wr_flags = 0; 1657173362Sbenjsc tap->wr_chan_freq = 1658173362Sbenjsc htole16(ic->ic_channels[head->chan].ic_freq); 1659173362Sbenjsc tap->wr_chan_flags = 1660173362Sbenjsc htole16(ic->ic_channels[head->chan].ic_flags); 1661173362Sbenjsc tap->wr_dbm_antsignal = (int8_t)(stat->rssi - WPI_RSSI_OFFSET); 1662173362Sbenjsc tap->wr_dbm_antnoise = (int8_t)le16toh(stat->noise); 1663173362Sbenjsc tap->wr_tsft = tail->tstamp; 1664173362Sbenjsc tap->wr_antenna = (le16toh(head->flags) >> 4) & 0xf; 1665173362Sbenjsc switch (head->rate) { 1666173362Sbenjsc /* CCK rates */ 1667173362Sbenjsc case 10: tap->wr_rate = 2; break; 1668173362Sbenjsc case 20: tap->wr_rate = 4; break; 1669173362Sbenjsc case 55: tap->wr_rate = 11; break; 1670173362Sbenjsc case 110: tap->wr_rate = 22; break; 1671173362Sbenjsc /* OFDM rates */ 1672173362Sbenjsc case 0xd: tap->wr_rate = 12; break; 1673173362Sbenjsc case 0xf: tap->wr_rate = 18; break; 1674173362Sbenjsc case 0x5: tap->wr_rate = 24; break; 1675173362Sbenjsc case 0x7: tap->wr_rate = 36; break; 1676173362Sbenjsc case 0x9: tap->wr_rate = 48; break; 1677173362Sbenjsc case 0xb: tap->wr_rate = 72; break; 1678173362Sbenjsc case 0x1: tap->wr_rate = 96; break; 1679173362Sbenjsc case 0x3: tap->wr_rate = 108; break; 1680173362Sbenjsc /* unknown rate: should not happen */ 1681173362Sbenjsc default: tap->wr_rate = 0; 1682173362Sbenjsc } 1683173362Sbenjsc if (le16toh(head->flags) & 0x4) 1684173362Sbenjsc tap->wr_flags |= IEEE80211_RADIOTAP_F_SHORTPRE; 1685173362Sbenjsc 1686173362Sbenjsc bpf_mtap2(sc->sc_drvbpf, tap, sc->sc_rxtap_len, m); 1687173362Sbenjsc } 1688173362Sbenjsc 1689173362Sbenjsc wh = mtod(m, struct ieee80211_frame *); 1690173362Sbenjsc WPI_UNLOCK(sc); 1691173362Sbenjsc 1692173362Sbenjsc /* XXX frame length > sizeof(struct ieee80211_frame_min)? */ 1693173362Sbenjsc /* grab a reference to the source node */ 1694173362Sbenjsc ni = ieee80211_find_rxnode(ic, (struct ieee80211_frame_min *)wh); 1695173362Sbenjsc 1696173362Sbenjsc /* send the frame to the 802.11 layer */ 1697173362Sbenjsc ieee80211_input(ic, m, ni, stat->rssi, 0, 0); 1698173362Sbenjsc 1699173362Sbenjsc /* release node reference */ 1700173362Sbenjsc ieee80211_free_node(ni); 1701173362Sbenjsc WPI_LOCK(sc); 1702173362Sbenjsc} 1703173362Sbenjsc 1704173362Sbenjscstatic void 1705173362Sbenjscwpi_tx_intr(struct wpi_softc *sc, struct wpi_rx_desc *desc) 1706173362Sbenjsc{ 1707173362Sbenjsc struct ifnet *ifp = sc->sc_ic.ic_ifp; 1708173362Sbenjsc struct wpi_tx_ring *ring = &sc->txq[desc->qid & 0x3]; 1709173362Sbenjsc struct wpi_tx_data *txdata = &ring->data[desc->idx]; 1710173362Sbenjsc struct wpi_tx_stat *stat = (struct wpi_tx_stat *)(desc + 1); 1711173362Sbenjsc struct wpi_node *wn = (struct wpi_node *)txdata->ni; 1712173362Sbenjsc 1713173362Sbenjsc DPRINTFN(WPI_DEBUG_TX, ("tx done: qid=%d idx=%d retries=%d nkill=%d " 1714173362Sbenjsc "rate=%x duration=%d status=%x\n", desc->qid, desc->idx, 1715173362Sbenjsc stat->ntries, stat->nkill, stat->rate, le32toh(stat->duration), 1716173362Sbenjsc le32toh(stat->status))); 1717173362Sbenjsc 1718173362Sbenjsc /* 1719173362Sbenjsc * Update rate control statistics for the node. 1720173362Sbenjsc * XXX we should not count mgmt frames since they're always sent at 1721173362Sbenjsc * the lowest available bit-rate. 1722173362Sbenjsc * XXX frames w/o ACK shouldn't be used either 1723173362Sbenjsc */ 1724173362Sbenjsc wn->amn.amn_txcnt++; 1725173362Sbenjsc if (stat->ntries > 0) { 1726173362Sbenjsc DPRINTFN(3, ("%d retries\n", stat->ntries)); 1727173362Sbenjsc wn->amn.amn_retrycnt++; 1728173362Sbenjsc } 1729173362Sbenjsc 1730173362Sbenjsc /* XXX oerrors should only count errors !maxtries */ 1731173362Sbenjsc if ((le32toh(stat->status) & 0xff) != 1) 1732173362Sbenjsc ifp->if_oerrors++; 1733173362Sbenjsc else 1734173362Sbenjsc ifp->if_opackets++; 1735173362Sbenjsc 1736173362Sbenjsc bus_dmamap_sync(ring->data_dmat, txdata->map, BUS_DMASYNC_POSTWRITE); 1737173362Sbenjsc bus_dmamap_unload(ring->data_dmat, txdata->map); 1738173362Sbenjsc /* XXX handle M_TXCB? */ 1739173362Sbenjsc m_freem(txdata->m); 1740173362Sbenjsc txdata->m = NULL; 1741173362Sbenjsc ieee80211_free_node(txdata->ni); 1742173362Sbenjsc txdata->ni = NULL; 1743173362Sbenjsc 1744173362Sbenjsc ring->queued--; 1745173362Sbenjsc 1746173362Sbenjsc sc->sc_tx_timer = 0; 1747173362Sbenjsc sc->watchdog_cnt = 0; 1748173362Sbenjsc callout_stop(&sc->watchdog_to); 1749173362Sbenjsc ifp->if_drv_flags &= ~IFF_DRV_OACTIVE; 1750173362Sbenjsc wpi_start(ifp); 1751173362Sbenjsc} 1752173362Sbenjsc 1753173362Sbenjscstatic void 1754173362Sbenjscwpi_cmd_intr(struct wpi_softc *sc, struct wpi_rx_desc *desc) 1755173362Sbenjsc{ 1756173362Sbenjsc struct wpi_tx_ring *ring = &sc->cmdq; 1757173362Sbenjsc struct wpi_tx_data *data; 1758173362Sbenjsc 1759173362Sbenjsc DPRINTFN(WPI_DEBUG_CMD, ("cmd notification qid=%x idx=%d flags=%x " 1760173362Sbenjsc "type=%s len=%d\n", desc->qid, desc->idx, 1761173362Sbenjsc desc->flags, wpi_cmd_str(desc->type), 1762173362Sbenjsc le32toh(desc->len))); 1763173362Sbenjsc 1764173362Sbenjsc if ((desc->qid & 7) != 4) 1765173362Sbenjsc return; /* not a command ack */ 1766173362Sbenjsc 1767173362Sbenjsc data = &ring->data[desc->idx]; 1768173362Sbenjsc 1769173362Sbenjsc /* if the command was mapped in a mbuf, free it */ 1770173362Sbenjsc if (data->m != NULL) { 1771173362Sbenjsc bus_dmamap_unload(ring->data_dmat, data->map); 1772173362Sbenjsc m_freem(data->m); 1773173362Sbenjsc data->m = NULL; 1774173362Sbenjsc } 1775173362Sbenjsc 1776173362Sbenjsc sc->flags &= ~WPI_FLAG_BUSY; 1777173362Sbenjsc wakeup(&ring->cmd[desc->idx]); 1778173362Sbenjsc} 1779173362Sbenjsc 1780173362Sbenjscstatic void 1781173362Sbenjscwpi_notif_intr(struct wpi_softc *sc) 1782173362Sbenjsc{ 1783173362Sbenjsc struct ieee80211com *ic = &sc->sc_ic; 1784173362Sbenjsc struct wpi_rx_desc *desc; 1785173362Sbenjsc struct wpi_rx_data *data; 1786173362Sbenjsc uint32_t hw; 1787173362Sbenjsc 1788173362Sbenjsc hw = le32toh(sc->shared->next); 1789173362Sbenjsc while (sc->rxq.cur != hw) { 1790173362Sbenjsc data = &sc->rxq.data[sc->rxq.cur]; 1791173362Sbenjsc desc = (void *)data->m->m_ext.ext_buf; 1792173362Sbenjsc 1793173362Sbenjsc DPRINTFN(WPI_DEBUG_NOTIFY, 1794173362Sbenjsc ("notify qid=%x idx=%d flags=%x type=%d len=%d\n", 1795173362Sbenjsc desc->qid, 1796173362Sbenjsc desc->idx, 1797173362Sbenjsc desc->flags, 1798173362Sbenjsc desc->type, 1799173362Sbenjsc le32toh(desc->len))); 1800173362Sbenjsc 1801173362Sbenjsc if (!(desc->qid & 0x80)) /* reply to a command */ 1802173362Sbenjsc wpi_cmd_intr(sc, desc); 1803173362Sbenjsc 1804173362Sbenjsc /* XXX beacon miss handling? */ 1805173362Sbenjsc switch (desc->type) { 1806173362Sbenjsc case WPI_RX_DONE: 1807173362Sbenjsc /* a 802.11 frame was received */ 1808173362Sbenjsc wpi_rx_intr(sc, desc, data); 1809173362Sbenjsc break; 1810173362Sbenjsc 1811173362Sbenjsc case WPI_TX_DONE: 1812173362Sbenjsc /* a 802.11 frame has been transmitted */ 1813173362Sbenjsc wpi_tx_intr(sc, desc); 1814173362Sbenjsc break; 1815173362Sbenjsc 1816173362Sbenjsc case WPI_UC_READY: 1817173362Sbenjsc { 1818173362Sbenjsc struct wpi_ucode_info *uc = 1819173362Sbenjsc (struct wpi_ucode_info *)(desc + 1); 1820173362Sbenjsc 1821173362Sbenjsc /* the microcontroller is ready */ 1822173362Sbenjsc DPRINTF(("microcode alive notification version %x " 1823173362Sbenjsc "alive %x\n", le32toh(uc->version), 1824173362Sbenjsc le32toh(uc->valid))); 1825173362Sbenjsc 1826173362Sbenjsc if (le32toh(uc->valid) != 1) { 1827173362Sbenjsc device_printf(sc->sc_dev, 1828173362Sbenjsc "microcontroller initialization failed\n"); 1829173362Sbenjsc wpi_stop_locked(sc); 1830173362Sbenjsc } 1831173362Sbenjsc break; 1832173362Sbenjsc } 1833173362Sbenjsc case WPI_STATE_CHANGED: 1834173362Sbenjsc { 1835173362Sbenjsc uint32_t *status = (uint32_t *)(desc + 1); 1836173362Sbenjsc 1837173362Sbenjsc /* enabled/disabled notification */ 1838173362Sbenjsc DPRINTF(("state changed to %x\n", le32toh(*status))); 1839173362Sbenjsc 1840173362Sbenjsc if (le32toh(*status) & 1) { 1841173362Sbenjsc device_printf(sc->sc_dev, 1842173362Sbenjsc "Radio transmitter is switched off\n"); 1843173362Sbenjsc sc->flags |= WPI_FLAG_HW_RADIO_OFF; 1844173362Sbenjsc break; 1845173362Sbenjsc } 1846173362Sbenjsc sc->flags &= ~WPI_FLAG_HW_RADIO_OFF; 1847173362Sbenjsc break; 1848173362Sbenjsc } 1849173362Sbenjsc case WPI_START_SCAN: 1850173362Sbenjsc { 1851173362Sbenjsc struct wpi_start_scan *scan = 1852173362Sbenjsc (struct wpi_start_scan *)(desc + 1); 1853173362Sbenjsc 1854173362Sbenjsc DPRINTFN(WPI_DEBUG_SCANNING, 1855173362Sbenjsc ("scanning channel %d status %x\n", 1856173362Sbenjsc scan->chan, le32toh(scan->status))); 1857173362Sbenjsc 1858173362Sbenjsc /* fix current channel */ 1859173362Sbenjsc ic->ic_bss->ni_chan = &ic->ic_channels[scan->chan]; 1860173362Sbenjsc break; 1861173362Sbenjsc } 1862173362Sbenjsc case WPI_STOP_SCAN: 1863173362Sbenjsc { 1864173362Sbenjsc struct wpi_stop_scan *scan = 1865173362Sbenjsc (struct wpi_stop_scan *)(desc + 1); 1866173362Sbenjsc 1867173362Sbenjsc DPRINTFN(WPI_DEBUG_SCANNING, 1868173362Sbenjsc ("scan finished nchan=%d status=%d chan=%d\n", 1869173362Sbenjsc scan->nchan, scan->status, scan->chan)); 1870173362Sbenjsc 1871173362Sbenjsc wpi_queue_cmd(sc, WPI_SCAN_NEXT); 1872173362Sbenjsc break; 1873173362Sbenjsc } 1874173362Sbenjsc } 1875173362Sbenjsc 1876173362Sbenjsc sc->rxq.cur = (sc->rxq.cur + 1) % WPI_RX_RING_COUNT; 1877173362Sbenjsc } 1878173362Sbenjsc 1879173362Sbenjsc /* tell the firmware what we have processed */ 1880173362Sbenjsc hw = (hw == 0) ? WPI_RX_RING_COUNT - 1 : hw - 1; 1881173362Sbenjsc WPI_WRITE(sc, WPI_RX_WIDX, hw & ~7); 1882173362Sbenjsc 1883173362Sbenjsc} 1884173362Sbenjsc 1885173362Sbenjscstatic void 1886173362Sbenjscwpi_intr(void *arg) 1887173362Sbenjsc{ 1888173362Sbenjsc struct wpi_softc *sc = arg; 1889173362Sbenjsc uint32_t r; 1890173362Sbenjsc WPI_LOCK_DECL; 1891173362Sbenjsc 1892173362Sbenjsc WPI_LOCK(sc); 1893173362Sbenjsc 1894173362Sbenjsc r = WPI_READ(sc, WPI_INTR); 1895173362Sbenjsc if (r == 0 || r == 0xffffffff) { 1896173362Sbenjsc WPI_UNLOCK(sc); 1897173362Sbenjsc return; 1898173362Sbenjsc } 1899173362Sbenjsc 1900173362Sbenjsc /* disable interrupts */ 1901173362Sbenjsc WPI_WRITE(sc, WPI_MASK, 0); 1902173362Sbenjsc /* ack interrupts */ 1903173362Sbenjsc WPI_WRITE(sc, WPI_INTR, r); 1904173362Sbenjsc 1905173362Sbenjsc if (r & (WPI_SW_ERROR | WPI_HW_ERROR)) { 1906173362Sbenjsc device_printf(sc->sc_dev, "fatal firmware error\n"); 1907173362Sbenjsc DPRINTFN(6,("(%s)\n", (r & WPI_SW_ERROR) ? "(Software Error)" : 1908173362Sbenjsc "(Hardware Error)")); 1909173362Sbenjsc taskqueue_enqueue(sc->sc_tq2, &sc->sc_restarttask); 1910173362Sbenjsc sc->flags &= ~WPI_FLAG_BUSY; 1911173362Sbenjsc WPI_UNLOCK(sc); 1912173362Sbenjsc return; 1913173362Sbenjsc } 1914173362Sbenjsc 1915173362Sbenjsc if (r & WPI_RX_INTR) 1916173362Sbenjsc wpi_notif_intr(sc); 1917173362Sbenjsc 1918173362Sbenjsc if (r & WPI_ALIVE_INTR) /* firmware initialized */ 1919173362Sbenjsc wakeup(sc); 1920173362Sbenjsc 1921173362Sbenjsc /* re-enable interrupts */ 1922173362Sbenjsc if (sc->sc_ifp->if_flags & IFF_UP) 1923173362Sbenjsc WPI_WRITE(sc, WPI_MASK, WPI_INTR_MASK); 1924173362Sbenjsc 1925173362Sbenjsc WPI_UNLOCK(sc); 1926173362Sbenjsc} 1927173362Sbenjsc 1928173362Sbenjscstatic uint8_t 1929173362Sbenjscwpi_plcp_signal(int rate) 1930173362Sbenjsc{ 1931173362Sbenjsc switch (rate) { 1932173362Sbenjsc /* CCK rates (returned values are device-dependent) */ 1933173362Sbenjsc case 2: return 10; 1934173362Sbenjsc case 4: return 20; 1935173362Sbenjsc case 11: return 55; 1936173362Sbenjsc case 22: return 110; 1937173362Sbenjsc 1938173362Sbenjsc /* OFDM rates (cf IEEE Std 802.11a-1999, pp. 14 Table 80) */ 1939173362Sbenjsc /* R1-R4 (ral/ural is R4-R1) */ 1940173362Sbenjsc case 12: return 0xd; 1941173362Sbenjsc case 18: return 0xf; 1942173362Sbenjsc case 24: return 0x5; 1943173362Sbenjsc case 36: return 0x7; 1944173362Sbenjsc case 48: return 0x9; 1945173362Sbenjsc case 72: return 0xb; 1946173362Sbenjsc case 96: return 0x1; 1947173362Sbenjsc case 108: return 0x3; 1948173362Sbenjsc 1949173362Sbenjsc /* unsupported rates (should not get there) */ 1950173362Sbenjsc default: return 0; 1951173362Sbenjsc } 1952173362Sbenjsc} 1953173362Sbenjsc 1954173362Sbenjsc/* quickly determine if a given rate is CCK or OFDM */ 1955173362Sbenjsc#define WPI_RATE_IS_OFDM(rate) ((rate) >= 12 && (rate) != 22) 1956173362Sbenjsc 1957173362Sbenjsc/* 1958173362Sbenjsc * Construct the data packet for a transmit buffer and acutally put 1959173362Sbenjsc * the buffer onto the transmit ring, kicking the card to process the 1960173362Sbenjsc * the buffer. 1961173362Sbenjsc */ 1962173362Sbenjscstatic int 1963173362Sbenjscwpi_tx_data(struct wpi_softc *sc, struct mbuf *m0, struct ieee80211_node *ni, 1964173362Sbenjsc int ac) 1965173362Sbenjsc{ 1966173362Sbenjsc struct ieee80211com *ic = &sc->sc_ic; 1967173362Sbenjsc struct wpi_tx_ring *ring = &sc->txq[ac]; 1968173362Sbenjsc struct wpi_tx_desc *desc; 1969173362Sbenjsc struct wpi_tx_data *data; 1970173362Sbenjsc struct wpi_tx_cmd *cmd; 1971173362Sbenjsc struct wpi_cmd_data *tx; 1972173362Sbenjsc struct ieee80211_frame *wh; 1973173362Sbenjsc struct ieee80211_key *k; 1974173362Sbenjsc const struct chanAccParams *cap; 1975173362Sbenjsc struct mbuf *mnew; 1976173362Sbenjsc int i, error, nsegs, rate, hdrlen, noack = 0; 1977173362Sbenjsc bus_dma_segment_t segs[WPI_MAX_SCATTER]; 1978173362Sbenjsc 1979173362Sbenjsc desc = &ring->desc[ring->cur]; 1980173362Sbenjsc data = &ring->data[ring->cur]; 1981173362Sbenjsc 1982173362Sbenjsc wh = mtod(m0, struct ieee80211_frame *); 1983173362Sbenjsc 1984173362Sbenjsc if (IEEE80211_QOS_HAS_SEQ(wh)) { 1985173362Sbenjsc hdrlen = sizeof (struct ieee80211_qosframe); 1986173362Sbenjsc cap = &ic->ic_wme.wme_chanParams; 1987173362Sbenjsc noack = cap->cap_wmeParams[ac].wmep_noackPolicy; 1988173362Sbenjsc } else 1989173362Sbenjsc hdrlen = sizeof (struct ieee80211_frame); 1990173362Sbenjsc 1991173362Sbenjsc if (wh->i_fc[1] & IEEE80211_FC1_WEP) { 1992173362Sbenjsc if ((k = ieee80211_crypto_encap(ic, ni, m0)) == NULL) { 1993173362Sbenjsc m_freem(m0); 1994173362Sbenjsc return ENOBUFS; 1995173362Sbenjsc } 1996173362Sbenjsc 1997173362Sbenjsc /* packet header may have moved, reset our local pointer */ 1998173362Sbenjsc wh = mtod(m0, struct ieee80211_frame *); 1999173362Sbenjsc } 2000173362Sbenjsc 2001173362Sbenjsc /* pickup a rate */ 2002173362Sbenjsc if (IEEE80211_IS_MULTICAST(wh->i_addr1)|| 2003173362Sbenjsc ((wh->i_fc[0] & IEEE80211_FC0_TYPE_MASK) == 2004173362Sbenjsc IEEE80211_FC0_TYPE_MGT)) { 2005173362Sbenjsc /* 2006173362Sbenjsc * mgmt/multicast frames are sent at the lowest available 2007173362Sbenjsc * bit-rate 2008173362Sbenjsc */ 2009173362Sbenjsc rate = ni->ni_rates.rs_rates[0]; 2010173362Sbenjsc } else { 2011173362Sbenjsc if (ic->ic_fixed_rate != -1) { 2012173362Sbenjsc rate = ic->ic_sup_rates[ic->ic_curmode]. 2013173362Sbenjsc rs_rates[ic->ic_fixed_rate]; 2014173362Sbenjsc } else 2015173362Sbenjsc rate = ni->ni_rates.rs_rates[ni->ni_txrate]; 2016173362Sbenjsc } 2017173362Sbenjsc rate &= IEEE80211_RATE_VAL; 2018173362Sbenjsc 2019173362Sbenjsc#ifndef WPI_CURRENT 2020173362Sbenjsc if (sc->sc_drvbpf != NULL) { 2021173362Sbenjsc#else 2022173362Sbenjsc if (bpf_peers_present(sc->sc_drvbpf)) { 2023173362Sbenjsc#endif 2024173362Sbenjsc 2025173362Sbenjsc struct wpi_tx_radiotap_header *tap = &sc->sc_txtap; 2026173362Sbenjsc 2027173362Sbenjsc tap->wt_flags = 0; 2028173362Sbenjsc tap->wt_chan_freq = htole16(ni->ni_chan->ic_freq); 2029173362Sbenjsc tap->wt_chan_flags = htole16(ni->ni_chan->ic_flags); 2030173362Sbenjsc tap->wt_rate = rate; 2031173362Sbenjsc tap->wt_hwqueue = ac; 2032173362Sbenjsc if (wh->i_fc[1] & IEEE80211_FC1_WEP) 2033173362Sbenjsc tap->wt_flags |= IEEE80211_RADIOTAP_F_WEP; 2034173362Sbenjsc 2035173362Sbenjsc bpf_mtap2(sc->sc_drvbpf, tap, sc->sc_txtap_len, m0); 2036173362Sbenjsc } 2037173362Sbenjsc 2038173362Sbenjsc cmd = &ring->cmd[ring->cur]; 2039173362Sbenjsc cmd->code = WPI_CMD_TX_DATA; 2040173362Sbenjsc cmd->flags = 0; 2041173362Sbenjsc cmd->qid = ring->qid; 2042173362Sbenjsc cmd->idx = ring->cur; 2043173362Sbenjsc 2044173362Sbenjsc tx = (struct wpi_cmd_data *)cmd->data; 2045173362Sbenjsc tx->flags = 0; 2046173362Sbenjsc 2047173362Sbenjsc if (!noack && !IEEE80211_IS_MULTICAST(wh->i_addr1)) { 2048173362Sbenjsc tx->flags |= htole32(WPI_TX_NEED_ACK); 2049173362Sbenjsc } else if (m0->m_pkthdr.len + IEEE80211_CRC_LEN > ic->ic_rtsthreshold) { 2050173362Sbenjsc tx->flags |= htole32(WPI_TX_NEED_RTS | WPI_TX_FULL_TXOP); 2051173362Sbenjsc } 2052173362Sbenjsc 2053173362Sbenjsc tx->flags |= htole32(WPI_TX_AUTO_SEQ); 2054173362Sbenjsc 2055173362Sbenjsc tx->id = IEEE80211_IS_MULTICAST(wh->i_addr1) ? WPI_ID_BROADCAST : 2056173362Sbenjsc WPI_ID_BSS; 2057173362Sbenjsc 2058173362Sbenjsc if ((wh->i_fc[0] & IEEE80211_FC0_TYPE_MASK) == 2059173362Sbenjsc IEEE80211_FC0_TYPE_MGT) { 2060173362Sbenjsc uint8_t subtype = wh->i_fc[0] & IEEE80211_FC0_SUBTYPE_MASK; 2061173362Sbenjsc /* tell h/w to set timestamp in probe responses */ 2062173362Sbenjsc if (subtype == IEEE80211_FC0_SUBTYPE_PROBE_RESP) 2063173362Sbenjsc tx->flags |= htole32(WPI_TX_INSERT_TSTAMP); 2064173362Sbenjsc 2065173362Sbenjsc if (subtype == IEEE80211_FC0_SUBTYPE_ASSOC_REQ || 2066173362Sbenjsc subtype == IEEE80211_FC0_SUBTYPE_REASSOC_REQ) 2067173362Sbenjsc tx->timeout = htole16(3); 2068173362Sbenjsc else 2069173362Sbenjsc tx->timeout = htole16(2); 2070173362Sbenjsc } else 2071173362Sbenjsc tx->timeout = htole16(0); 2072173362Sbenjsc 2073173362Sbenjsc tx->rate = wpi_plcp_signal(rate); 2074173362Sbenjsc 2075173362Sbenjsc /* be very persistant at sending frames out */ 2076173362Sbenjsc tx->rts_ntries = 7; 2077173362Sbenjsc tx->data_ntries = 15; 2078173362Sbenjsc 2079173362Sbenjsc tx->ofdm_mask = 0xff; 2080173362Sbenjsc tx->cck_mask = 0x0f; 2081173362Sbenjsc tx->lifetime = htole32(WPI_LIFETIME_INFINITE); 2082173362Sbenjsc 2083173362Sbenjsc tx->len = htole16(m0->m_pkthdr.len); 2084173362Sbenjsc 2085173362Sbenjsc /* save and trim IEEE802.11 header */ 2086173362Sbenjsc m_copydata(m0, 0, hdrlen, (caddr_t)&tx->wh); 2087173362Sbenjsc m_adj(m0, hdrlen); 2088173362Sbenjsc 2089173362Sbenjsc error = bus_dmamap_load_mbuf_sg(ring->data_dmat, data->map, m0, segs, 2090173362Sbenjsc &nsegs, BUS_DMA_NOWAIT); 2091173362Sbenjsc if (error != 0 && error != EFBIG) { 2092173362Sbenjsc device_printf(sc->sc_dev, "could not map mbuf (error %d)\n", 2093173362Sbenjsc error); 2094173362Sbenjsc m_freem(m0); 2095173362Sbenjsc return error; 2096173362Sbenjsc } 2097173362Sbenjsc if (error != 0) { 2098173362Sbenjsc /* XXX use ath_defrag */ 2099173362Sbenjsc mnew = m_defrag(m0, M_DONTWAIT); 2100173362Sbenjsc if (mnew == NULL) { 2101173362Sbenjsc device_printf(sc->sc_dev, 2102173362Sbenjsc "could not defragment mbuf\n"); 2103173362Sbenjsc m_freem(m0); 2104173362Sbenjsc return ENOBUFS; 2105173362Sbenjsc } 2106173362Sbenjsc m0 = mnew; 2107173362Sbenjsc 2108173362Sbenjsc error = bus_dmamap_load_mbuf_sg(ring->data_dmat, data->map, 2109173362Sbenjsc m0, segs, &nsegs, BUS_DMA_NOWAIT); 2110173362Sbenjsc if (error != 0) { 2111173362Sbenjsc device_printf(sc->sc_dev, 2112173362Sbenjsc "could not map mbuf (error %d)\n", error); 2113173362Sbenjsc m_freem(m0); 2114173362Sbenjsc return error; 2115173362Sbenjsc } 2116173362Sbenjsc } 2117173362Sbenjsc 2118173362Sbenjsc data->m = m0; 2119173362Sbenjsc data->ni = ni; 2120173362Sbenjsc 2121173362Sbenjsc DPRINTFN(WPI_DEBUG_TX, ("sending data: qid=%d idx=%d len=%d nsegs=%d\n", 2122173362Sbenjsc ring->qid, ring->cur, m0->m_pkthdr.len, nsegs)); 2123173362Sbenjsc 2124173362Sbenjsc /* first scatter/gather segment is used by the tx data command */ 2125173362Sbenjsc desc->flags = htole32(WPI_PAD32(m0->m_pkthdr.len) << 28 | 2126173362Sbenjsc (1 + nsegs) << 24); 2127173362Sbenjsc desc->segs[0].addr = htole32(ring->cmd_dma.paddr + 2128173362Sbenjsc ring->cur * sizeof (struct wpi_tx_cmd)); 2129173362Sbenjsc desc->segs[0].len = htole32(4 + sizeof (struct wpi_cmd_data)); 2130173362Sbenjsc for (i = 1; i <= nsegs; i++) { 2131173362Sbenjsc desc->segs[i].addr = htole32(segs[i - 1].ds_addr); 2132173362Sbenjsc desc->segs[i].len = htole32(segs[i - 1].ds_len); 2133173362Sbenjsc } 2134173362Sbenjsc 2135173362Sbenjsc bus_dmamap_sync(ring->data_dmat, data->map, BUS_DMASYNC_PREWRITE); 2136173362Sbenjsc bus_dmamap_sync(ring->desc_dma.tag, ring->desc_dma.map, 2137173362Sbenjsc BUS_DMASYNC_PREWRITE); 2138173362Sbenjsc 2139173362Sbenjsc ring->queued++; 2140173362Sbenjsc 2141173362Sbenjsc /* kick ring */ 2142173362Sbenjsc ring->cur = (ring->cur + 1) % WPI_TX_RING_COUNT; 2143173362Sbenjsc WPI_WRITE(sc, WPI_TX_WIDX, ring->qid << 8 | ring->cur); 2144173362Sbenjsc 2145173362Sbenjsc return 0; 2146173362Sbenjsc} 2147173362Sbenjsc 2148173362Sbenjsc/** 2149173362Sbenjsc * Process data waiting to be sent on the IFNET output queue 2150173362Sbenjsc */ 2151173362Sbenjscstatic void 2152173362Sbenjscwpi_start(struct ifnet *ifp) 2153173362Sbenjsc{ 2154173362Sbenjsc struct wpi_softc *sc = ifp->if_softc; 2155173362Sbenjsc struct ieee80211com *ic = &sc->sc_ic; 2156173362Sbenjsc struct ieee80211_node *ni; 2157173362Sbenjsc struct ether_header *eh; 2158173362Sbenjsc struct mbuf *m0; 2159173362Sbenjsc int ac; 2160173362Sbenjsc WPI_LOCK_DECL; 2161173362Sbenjsc 2162173362Sbenjsc WPI_LOCK(sc); 2163173362Sbenjsc 2164173362Sbenjsc for (;;) { 2165173362Sbenjsc IF_POLL(&ic->ic_mgtq, m0); 2166173362Sbenjsc if (m0 != NULL) { 2167173362Sbenjsc IF_DEQUEUE(&ic->ic_mgtq, m0); 2168173362Sbenjsc 2169173362Sbenjsc ni = (struct ieee80211_node *)m0->m_pkthdr.rcvif; 2170173362Sbenjsc m0->m_pkthdr.rcvif = NULL; 2171173362Sbenjsc 2172173362Sbenjsc /* management frames go into ring 0 */ 2173173362Sbenjsc if (sc->txq[0].queued > sc->txq[0].count - 8) { 2174173362Sbenjsc ifp->if_oerrors++; 2175173362Sbenjsc continue; 2176173362Sbenjsc } 2177173362Sbenjsc 2178173362Sbenjsc if (wpi_tx_data(sc, m0, ni, 0) != 0) { 2179173362Sbenjsc ifp->if_oerrors++; 2180173362Sbenjsc break; 2181173362Sbenjsc } 2182173362Sbenjsc } else { 2183173362Sbenjsc if (ic->ic_state != IEEE80211_S_RUN) 2184173362Sbenjsc break; 2185173362Sbenjsc 2186173362Sbenjsc IFQ_POLL(&ifp->if_snd, m0); 2187173362Sbenjsc if (m0 == NULL) 2188173362Sbenjsc break; 2189173362Sbenjsc 2190173362Sbenjsc /* 2191173362Sbenjsc * Cancel any background scan. 2192173362Sbenjsc */ 2193173362Sbenjsc if (ic->ic_flags & IEEE80211_F_SCAN) 2194173362Sbenjsc ieee80211_cancel_scan(ic); 2195173362Sbenjsc 2196173362Sbenjsc if (m0->m_len < sizeof (*eh) && 2197173362Sbenjsc (m0 = m_pullup(m0, sizeof (*eh))) != NULL) { 2198173362Sbenjsc ifp->if_oerrors++; 2199173362Sbenjsc continue; 2200173362Sbenjsc } 2201173362Sbenjsc eh = mtod(m0, struct ether_header *); 2202173362Sbenjsc ni = ieee80211_find_txnode(ic, eh->ether_dhost); 2203173362Sbenjsc if (ni == NULL) { 2204173362Sbenjsc m_freem(m0); 2205173362Sbenjsc ifp->if_oerrors++; 2206173362Sbenjsc continue; 2207173362Sbenjsc } 2208173362Sbenjsc 2209173362Sbenjsc /* classify mbuf so we can find which tx ring to use */ 2210173362Sbenjsc if (ieee80211_classify(ic, m0, ni) != 0) { 2211173362Sbenjsc m_freem(m0); 2212173362Sbenjsc ieee80211_free_node(ni); 2213173362Sbenjsc ifp->if_oerrors++; 2214173362Sbenjsc continue; 2215173362Sbenjsc } 2216173362Sbenjsc 2217173362Sbenjsc /* no QoS encapsulation for EAPOL frames */ 2218173362Sbenjsc ac = (eh->ether_type != htons(ETHERTYPE_PAE)) ? 2219173362Sbenjsc M_WME_GETAC(m0) : WME_AC_BE; 2220173362Sbenjsc 2221173362Sbenjsc if (sc->txq[ac].queued > sc->txq[ac].count - 8) { 2222173362Sbenjsc /* there is no place left in this ring */ 2223173362Sbenjsc IFQ_DRV_PREPEND(&ifp->if_snd, m0); 2224173362Sbenjsc ifp->if_drv_flags |= IFF_DRV_OACTIVE; 2225173362Sbenjsc break; 2226173362Sbenjsc } 2227173362Sbenjsc 2228173362Sbenjsc IFQ_DRV_DEQUEUE(&ifp->if_snd, m0); 2229173362Sbenjsc BPF_MTAP(ifp, m0); 2230173362Sbenjsc 2231173362Sbenjsc m0 = ieee80211_encap(ic, m0, ni); 2232173362Sbenjsc if (m0 == NULL) { 2233173362Sbenjsc ieee80211_free_node(ni); 2234173362Sbenjsc ifp->if_oerrors++; 2235173362Sbenjsc continue; 2236173362Sbenjsc } 2237173362Sbenjsc 2238173362Sbenjsc#ifndef WPI_CURRENT 2239173362Sbenjsc if (ic->ic_rawbpf != NULL) 2240173362Sbenjsc#else 2241173362Sbenjsc if (bpf_peers_present(ic->ic_rawbpf)) 2242173362Sbenjsc#endif 2243173362Sbenjsc bpf_mtap(ic->ic_rawbpf, m0); 2244173362Sbenjsc 2245173362Sbenjsc if (wpi_tx_data(sc, m0, ni, ac) != 0) { 2246173362Sbenjsc ieee80211_free_node(ni); 2247173362Sbenjsc ifp->if_oerrors++; 2248173362Sbenjsc break; 2249173362Sbenjsc } 2250173362Sbenjsc } 2251173362Sbenjsc 2252173362Sbenjsc sc->sc_tx_timer = 5; 2253173362Sbenjsc sc->watchdog_cnt = 5; 2254173362Sbenjsc ic->ic_lastdata = ticks; 2255173362Sbenjsc } 2256173362Sbenjsc 2257173362Sbenjsc WPI_UNLOCK(sc); 2258173362Sbenjsc} 2259173362Sbenjsc 2260173362Sbenjscstatic void 2261173362Sbenjscwpi_watchdog(struct ifnet *ifp) 2262173362Sbenjsc{ 2263173362Sbenjsc struct wpi_softc *sc = ifp->if_softc; 2264173362Sbenjsc WPI_LOCK_DECL; 2265173362Sbenjsc 2266173362Sbenjsc WPI_LOCK(sc); 2267173362Sbenjsc 2268173362Sbenjsc DPRINTFN(WPI_DEBUG_WATCHDOG, ("watchdog_cnt: %d\n", sc->watchdog_cnt)); 2269173362Sbenjsc 2270173362Sbenjsc if (sc->watchdog_cnt == 0 || --sc->watchdog_cnt) 2271173362Sbenjsc goto done; 2272173362Sbenjsc 2273173362Sbenjsc if (--sc->sc_tx_timer != 0) { 2274173362Sbenjsc device_printf(sc->sc_dev,"device timeout\n"); 2275173362Sbenjsc ifp->if_oerrors++; 2276173362Sbenjsc taskqueue_enqueue(sc->sc_tq2, &sc->sc_restarttask); 2277173362Sbenjsc } 2278173362Sbenjscdone: 2279173362Sbenjsc WPI_UNLOCK(sc); 2280173362Sbenjsc} 2281173362Sbenjsc 2282173362Sbenjscstatic int 2283173362Sbenjscwpi_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data) 2284173362Sbenjsc{ 2285173362Sbenjsc struct wpi_softc *sc = ifp->if_softc; 2286173362Sbenjsc struct ieee80211com *ic = &sc->sc_ic; 2287173362Sbenjsc int error = 0; 2288173362Sbenjsc WPI_LOCK_DECL; 2289173362Sbenjsc 2290173362Sbenjsc WPI_LOCK(sc); 2291173362Sbenjsc 2292173362Sbenjsc switch (cmd) { 2293173362Sbenjsc case SIOCSIFFLAGS: 2294173362Sbenjsc if ((ifp->if_flags & IFF_UP)) { 2295173362Sbenjsc if (!(ifp->if_drv_flags & IFF_DRV_RUNNING)) 2296173362Sbenjsc wpi_init(sc); 2297173362Sbenjsc } else if (ifp->if_drv_flags & IFF_DRV_RUNNING) 2298173362Sbenjsc wpi_stop_locked(sc); 2299173362Sbenjsc break; 2300173362Sbenjsc default: 2301173362Sbenjsc WPI_UNLOCK(sc); 2302173362Sbenjsc error = ieee80211_ioctl(ic, cmd, data); 2303173362Sbenjsc WPI_LOCK(sc); 2304173362Sbenjsc } 2305173362Sbenjsc 2306173362Sbenjsc if (error == ENETRESET) { 2307173362Sbenjsc if ((ifp->if_flags & IFF_UP) && 2308173362Sbenjsc (ifp->if_drv_flags & IFF_DRV_RUNNING) && 2309173362Sbenjsc ic->ic_roaming != IEEE80211_ROAMING_MANUAL) 2310173362Sbenjsc wpi_init(sc); 2311173362Sbenjsc error = 0; 2312173362Sbenjsc } 2313173362Sbenjsc 2314173362Sbenjsc WPI_UNLOCK(sc); 2315173362Sbenjsc 2316173362Sbenjsc return error; 2317173362Sbenjsc} 2318173362Sbenjsc 2319173362Sbenjsc/* 2320173362Sbenjsc * Extract various information from EEPROM. 2321173362Sbenjsc */ 2322173362Sbenjscstatic void 2323173362Sbenjscwpi_read_eeprom(struct wpi_softc *sc) 2324173362Sbenjsc{ 2325173362Sbenjsc struct ieee80211com *ic = &sc->sc_ic; 2326173362Sbenjsc int i; 2327173362Sbenjsc 2328173362Sbenjsc /* read the hardware capabilities, revision and SKU type */ 2329173362Sbenjsc wpi_read_prom_data(sc, WPI_EEPROM_CAPABILITIES, &sc->cap,1); 2330173362Sbenjsc wpi_read_prom_data(sc, WPI_EEPROM_REVISION, &sc->rev,2); 2331173362Sbenjsc wpi_read_prom_data(sc, WPI_EEPROM_TYPE, &sc->type, 1); 2332173362Sbenjsc 2333173362Sbenjsc /* read the regulatory domain */ 2334173362Sbenjsc wpi_read_prom_data(sc, WPI_EEPROM_DOMAIN, sc->domain, 4); 2335173362Sbenjsc 2336173362Sbenjsc /* read in the hw MAC address */ 2337173362Sbenjsc wpi_read_prom_data(sc, WPI_EEPROM_MAC, ic->ic_myaddr, 6); 2338173362Sbenjsc 2339173362Sbenjsc /* read the list of authorized channels */ 2340173362Sbenjsc for (i = 0; i < WPI_CHAN_BANDS_COUNT; i++) 2341173362Sbenjsc wpi_read_eeprom_channels(sc,i); 2342173362Sbenjsc 2343173362Sbenjsc /* read the power level calibration info for each group */ 2344173362Sbenjsc for (i = 0; i < WPI_POWER_GROUPS_COUNT; i++) 2345173362Sbenjsc wpi_read_eeprom_group(sc,i); 2346173362Sbenjsc} 2347173362Sbenjsc 2348173362Sbenjsc/* 2349173362Sbenjsc * Send a command to the firmware. 2350173362Sbenjsc */ 2351173362Sbenjscstatic int 2352173362Sbenjscwpi_cmd(struct wpi_softc *sc, int code, const void *buf, int size, int async) 2353173362Sbenjsc{ 2354173362Sbenjsc struct wpi_tx_ring *ring = &sc->cmdq; 2355173362Sbenjsc struct wpi_tx_desc *desc; 2356173362Sbenjsc struct wpi_tx_cmd *cmd; 2357173362Sbenjsc 2358173362Sbenjsc#ifdef WPI_DEBUG 2359173362Sbenjsc if (!async) { 2360173362Sbenjsc WPI_LOCK_ASSERT(sc); 2361173362Sbenjsc } 2362173362Sbenjsc#endif 2363173362Sbenjsc 2364173362Sbenjsc DPRINTFN(WPI_DEBUG_CMD,("wpi_cmd %d size %d async %d\n", code, size, 2365173362Sbenjsc async)); 2366173362Sbenjsc 2367173362Sbenjsc if (sc->flags & WPI_FLAG_BUSY) { 2368173362Sbenjsc device_printf(sc->sc_dev, "%s: cmd %d not sent, busy\n", 2369173362Sbenjsc __func__, code); 2370173362Sbenjsc return EAGAIN; 2371173362Sbenjsc } 2372173362Sbenjsc sc->flags|= WPI_FLAG_BUSY; 2373173362Sbenjsc 2374173362Sbenjsc KASSERT(size <= sizeof cmd->data, ("command %d too large: %d bytes", 2375173362Sbenjsc code, size)); 2376173362Sbenjsc 2377173362Sbenjsc desc = &ring->desc[ring->cur]; 2378173362Sbenjsc cmd = &ring->cmd[ring->cur]; 2379173362Sbenjsc 2380173362Sbenjsc cmd->code = code; 2381173362Sbenjsc cmd->flags = 0; 2382173362Sbenjsc cmd->qid = ring->qid; 2383173362Sbenjsc cmd->idx = ring->cur; 2384173362Sbenjsc memcpy(cmd->data, buf, size); 2385173362Sbenjsc 2386173362Sbenjsc desc->flags = htole32(WPI_PAD32(size) << 28 | 1 << 24); 2387173362Sbenjsc desc->segs[0].addr = htole32(ring->cmd_dma.paddr + 2388173362Sbenjsc ring->cur * sizeof (struct wpi_tx_cmd)); 2389173362Sbenjsc desc->segs[0].len = htole32(4 + size); 2390173362Sbenjsc 2391173362Sbenjsc /* kick cmd ring */ 2392173362Sbenjsc ring->cur = (ring->cur + 1) % WPI_CMD_RING_COUNT; 2393173362Sbenjsc WPI_WRITE(sc, WPI_TX_WIDX, ring->qid << 8 | ring->cur); 2394173362Sbenjsc 2395173362Sbenjsc if (async) { 2396173362Sbenjsc sc->flags &= ~ WPI_FLAG_BUSY; 2397173362Sbenjsc return 0; 2398173362Sbenjsc } 2399173362Sbenjsc 2400173362Sbenjsc return msleep(cmd, &sc->sc_mtx, PCATCH, "wpicmd", hz); 2401173362Sbenjsc} 2402173362Sbenjsc 2403173362Sbenjscstatic int 2404173362Sbenjscwpi_wme_update(struct ieee80211com *ic) 2405173362Sbenjsc{ 2406173362Sbenjsc#define WPI_EXP2(v) htole16((1 << (v)) - 1) 2407173362Sbenjsc#define WPI_USEC(v) htole16(IEEE80211_TXOP_TO_US(v)) 2408173362Sbenjsc struct wpi_softc *sc = ic->ic_ifp->if_softc; 2409173362Sbenjsc const struct wmeParams *wmep; 2410173362Sbenjsc struct wpi_wme_setup wme; 2411173362Sbenjsc int ac; 2412173362Sbenjsc 2413173362Sbenjsc /* don't override default WME values if WME is not actually enabled */ 2414173362Sbenjsc if (!(ic->ic_flags & IEEE80211_F_WME)) 2415173362Sbenjsc return 0; 2416173362Sbenjsc 2417173362Sbenjsc wme.flags = 0; 2418173362Sbenjsc for (ac = 0; ac < WME_NUM_AC; ac++) { 2419173362Sbenjsc wmep = &ic->ic_wme.wme_chanParams.cap_wmeParams[ac]; 2420173362Sbenjsc wme.ac[ac].aifsn = wmep->wmep_aifsn; 2421173362Sbenjsc wme.ac[ac].cwmin = WPI_EXP2(wmep->wmep_logcwmin); 2422173362Sbenjsc wme.ac[ac].cwmax = WPI_EXP2(wmep->wmep_logcwmax); 2423173362Sbenjsc wme.ac[ac].txop = WPI_USEC(wmep->wmep_txopLimit); 2424173362Sbenjsc 2425173362Sbenjsc DPRINTF(("setting WME for queue %d aifsn=%d cwmin=%d cwmax=%d " 2426173362Sbenjsc "txop=%d\n", ac, wme.ac[ac].aifsn, wme.ac[ac].cwmin, 2427173362Sbenjsc wme.ac[ac].cwmax, wme.ac[ac].txop)); 2428173362Sbenjsc } 2429173362Sbenjsc 2430173362Sbenjsc return wpi_cmd(sc, WPI_CMD_SET_WME, &wme, sizeof wme, 1); 2431173362Sbenjsc#undef WPI_USEC 2432173362Sbenjsc#undef WPI_EXP2 2433173362Sbenjsc} 2434173362Sbenjsc 2435173362Sbenjsc/* 2436173362Sbenjsc * Configure h/w multi-rate retries. 2437173362Sbenjsc */ 2438173362Sbenjscstatic int 2439173362Sbenjscwpi_mrr_setup(struct wpi_softc *sc) 2440173362Sbenjsc{ 2441173362Sbenjsc struct ieee80211com *ic = &sc->sc_ic; 2442173362Sbenjsc struct wpi_mrr_setup mrr; 2443173362Sbenjsc int i, error; 2444173362Sbenjsc 2445173362Sbenjsc memset(&mrr, 0, sizeof (struct wpi_mrr_setup)); 2446173362Sbenjsc 2447173362Sbenjsc /* CCK rates (not used with 802.11a) */ 2448173362Sbenjsc for (i = WPI_CCK1; i <= WPI_CCK11; i++) { 2449173362Sbenjsc mrr.rates[i].flags = 0; 2450173362Sbenjsc mrr.rates[i].signal = wpi_ridx_to_plcp[i]; 2451173362Sbenjsc /* fallback to the immediate lower CCK rate (if any) */ 2452173362Sbenjsc mrr.rates[i].next = (i == WPI_CCK1) ? WPI_CCK1 : i - 1; 2453173362Sbenjsc /* try one time at this rate before falling back to "next" */ 2454173362Sbenjsc mrr.rates[i].ntries = 1; 2455173362Sbenjsc } 2456173362Sbenjsc 2457173362Sbenjsc /* OFDM rates (not used with 802.11b) */ 2458173362Sbenjsc for (i = WPI_OFDM6; i <= WPI_OFDM54; i++) { 2459173362Sbenjsc mrr.rates[i].flags = 0; 2460173362Sbenjsc mrr.rates[i].signal = wpi_ridx_to_plcp[i]; 2461173362Sbenjsc /* fallback to the immediate lower OFDM rate (if any) */ 2462173362Sbenjsc /* we allow fallback from OFDM/6 to CCK/2 in 11b/g mode */ 2463173362Sbenjsc mrr.rates[i].next = (i == WPI_OFDM6) ? 2464173362Sbenjsc ((ic->ic_curmode == IEEE80211_MODE_11A) ? 2465173362Sbenjsc WPI_OFDM6 : WPI_CCK2) : 2466173362Sbenjsc i - 1; 2467173362Sbenjsc /* try one time at this rate before falling back to "next" */ 2468173362Sbenjsc mrr.rates[i].ntries = 1; 2469173362Sbenjsc } 2470173362Sbenjsc 2471173362Sbenjsc /* setup MRR for control frames */ 2472173362Sbenjsc mrr.which = htole32(WPI_MRR_CTL); 2473173362Sbenjsc error = wpi_cmd(sc, WPI_CMD_MRR_SETUP, &mrr, sizeof mrr, 0); 2474173362Sbenjsc if (error != 0) { 2475173362Sbenjsc device_printf(sc->sc_dev, 2476173362Sbenjsc "could not setup MRR for control frames\n"); 2477173362Sbenjsc return error; 2478173362Sbenjsc } 2479173362Sbenjsc 2480173362Sbenjsc /* setup MRR for data frames */ 2481173362Sbenjsc mrr.which = htole32(WPI_MRR_DATA); 2482173362Sbenjsc error = wpi_cmd(sc, WPI_CMD_MRR_SETUP, &mrr, sizeof mrr, 0); 2483173362Sbenjsc if (error != 0) { 2484173362Sbenjsc device_printf(sc->sc_dev, 2485173362Sbenjsc "could not setup MRR for data frames\n"); 2486173362Sbenjsc return error; 2487173362Sbenjsc } 2488173362Sbenjsc 2489173362Sbenjsc return 0; 2490173362Sbenjsc} 2491173362Sbenjsc 2492173362Sbenjscstatic void 2493173362Sbenjscwpi_set_led(struct wpi_softc *sc, uint8_t which, uint8_t off, uint8_t on) 2494173362Sbenjsc{ 2495173362Sbenjsc struct wpi_cmd_led led; 2496173362Sbenjsc 2497173362Sbenjsc led.which = which; 2498173362Sbenjsc led.unit = htole32(100000); /* on/off in unit of 100ms */ 2499173362Sbenjsc led.off = off; 2500173362Sbenjsc led.on = on; 2501173362Sbenjsc 2502173362Sbenjsc (void)wpi_cmd(sc, WPI_CMD_SET_LED, &led, sizeof led, 1); 2503173362Sbenjsc} 2504173362Sbenjsc 2505173362Sbenjscstatic void 2506173362Sbenjscwpi_enable_tsf(struct wpi_softc *sc, struct ieee80211_node *ni) 2507173362Sbenjsc{ 2508173362Sbenjsc struct wpi_cmd_tsf tsf; 2509173362Sbenjsc uint64_t val, mod; 2510173362Sbenjsc 2511173362Sbenjsc memset(&tsf, 0, sizeof tsf); 2512173362Sbenjsc memcpy(&tsf.tstamp, ni->ni_tstamp.data, 8); 2513173362Sbenjsc tsf.bintval = htole16(ni->ni_intval); 2514173362Sbenjsc tsf.lintval = htole16(10); 2515173362Sbenjsc 2516173362Sbenjsc /* compute remaining time until next beacon */ 2517173362Sbenjsc val = (uint64_t)ni->ni_intval * 1024; /* msec -> usec */ 2518173362Sbenjsc mod = le64toh(tsf.tstamp) % val; 2519173362Sbenjsc tsf.binitval = htole32((uint32_t)(val - mod)); 2520173362Sbenjsc 2521173362Sbenjsc if (wpi_cmd(sc, WPI_CMD_TSF, &tsf, sizeof tsf, 1) != 0) 2522173362Sbenjsc device_printf(sc->sc_dev, "could not enable TSF\n"); 2523173362Sbenjsc} 2524173362Sbenjsc 2525173362Sbenjsc#if 0 2526173362Sbenjsc/* 2527173362Sbenjsc * Build a beacon frame that the firmware will broadcast periodically in 2528173362Sbenjsc * IBSS or HostAP modes. 2529173362Sbenjsc */ 2530173362Sbenjscstatic int 2531173362Sbenjscwpi_setup_beacon(struct wpi_softc *sc, struct ieee80211_node *ni) 2532173362Sbenjsc{ 2533173362Sbenjsc struct ieee80211com *ic = &sc->sc_ic; 2534173362Sbenjsc struct wpi_tx_ring *ring = &sc->cmdq; 2535173362Sbenjsc struct wpi_tx_desc *desc; 2536173362Sbenjsc struct wpi_tx_data *data; 2537173362Sbenjsc struct wpi_tx_cmd *cmd; 2538173362Sbenjsc struct wpi_cmd_beacon *bcn; 2539173362Sbenjsc struct ieee80211_beacon_offsets bo; 2540173362Sbenjsc struct mbuf *m0; 2541173362Sbenjsc bus_addr_t physaddr; 2542173362Sbenjsc int error; 2543173362Sbenjsc 2544173362Sbenjsc desc = &ring->desc[ring->cur]; 2545173362Sbenjsc data = &ring->data[ring->cur]; 2546173362Sbenjsc 2547173362Sbenjsc m0 = ieee80211_beacon_alloc(ic, ni, &bo); 2548173362Sbenjsc if (m0 == NULL) { 2549173362Sbenjsc device_printf(sc->sc_dev, "could not allocate beacon frame\n"); 2550173362Sbenjsc return ENOMEM; 2551173362Sbenjsc } 2552173362Sbenjsc 2553173362Sbenjsc cmd = &ring->cmd[ring->cur]; 2554173362Sbenjsc cmd->code = WPI_CMD_SET_BEACON; 2555173362Sbenjsc cmd->flags = 0; 2556173362Sbenjsc cmd->qid = ring->qid; 2557173362Sbenjsc cmd->idx = ring->cur; 2558173362Sbenjsc 2559173362Sbenjsc bcn = (struct wpi_cmd_beacon *)cmd->data; 2560173362Sbenjsc memset(bcn, 0, sizeof (struct wpi_cmd_beacon)); 2561173362Sbenjsc bcn->id = WPI_ID_BROADCAST; 2562173362Sbenjsc bcn->ofdm_mask = 0xff; 2563173362Sbenjsc bcn->cck_mask = 0x0f; 2564173362Sbenjsc bcn->lifetime = htole32(WPI_LIFETIME_INFINITE); 2565173362Sbenjsc bcn->len = htole16(m0->m_pkthdr.len); 2566173362Sbenjsc bcn->rate = (ic->ic_curmode == IEEE80211_MODE_11A) ? 2567173362Sbenjsc wpi_plcp_signal(12) : wpi_plcp_signal(2); 2568173362Sbenjsc bcn->flags = htole32(WPI_TX_AUTO_SEQ | WPI_TX_INSERT_TSTAMP); 2569173362Sbenjsc 2570173362Sbenjsc /* save and trim IEEE802.11 header */ 2571173362Sbenjsc m_copydata(m0, 0, sizeof (struct ieee80211_frame), (caddr_t)&bcn->wh); 2572173362Sbenjsc m_adj(m0, sizeof (struct ieee80211_frame)); 2573173362Sbenjsc 2574173362Sbenjsc /* assume beacon frame is contiguous */ 2575173362Sbenjsc error = bus_dmamap_load(ring->data_dmat, data->map, mtod(m0, void *), 2576173362Sbenjsc m0->m_pkthdr.len, wpi_dma_map_addr, &physaddr, 0); 2577173362Sbenjsc if (error != 0) { 2578173362Sbenjsc device_printf(sc->sc_dev, "could not map beacon\n"); 2579173362Sbenjsc m_freem(m0); 2580173362Sbenjsc return error; 2581173362Sbenjsc } 2582173362Sbenjsc 2583173362Sbenjsc data->m = m0; 2584173362Sbenjsc 2585173362Sbenjsc /* first scatter/gather segment is used by the beacon command */ 2586173362Sbenjsc desc->flags = htole32(WPI_PAD32(m0->m_pkthdr.len) << 28 | 2 << 24); 2587173362Sbenjsc desc->segs[0].addr = htole32(ring->cmd_dma.paddr + 2588173362Sbenjsc ring->cur * sizeof (struct wpi_tx_cmd)); 2589173362Sbenjsc desc->segs[0].len = htole32(4 + sizeof (struct wpi_cmd_beacon)); 2590173362Sbenjsc desc->segs[1].addr = htole32(physaddr); 2591173362Sbenjsc desc->segs[1].len = htole32(m0->m_pkthdr.len); 2592173362Sbenjsc 2593173362Sbenjsc /* kick cmd ring */ 2594173362Sbenjsc ring->cur = (ring->cur + 1) % WPI_CMD_RING_COUNT; 2595173362Sbenjsc WPI_WRITE(sc, WPI_TX_WIDX, ring->qid << 8 | ring->cur); 2596173362Sbenjsc 2597173362Sbenjsc return 0; 2598173362Sbenjsc} 2599173362Sbenjsc#endif 2600173362Sbenjsc 2601173362Sbenjscstatic int 2602173362Sbenjscwpi_auth(struct wpi_softc *sc) 2603173362Sbenjsc{ 2604173362Sbenjsc struct ieee80211com *ic = &sc->sc_ic; 2605173362Sbenjsc struct ieee80211_node *ni = ic->ic_bss; 2606173362Sbenjsc struct wpi_node_info node; 2607173362Sbenjsc int error; 2608173362Sbenjsc 2609173362Sbenjsc /* update adapter's configuration */ 2610173362Sbenjsc IEEE80211_ADDR_COPY(sc->config.bssid, ni->ni_bssid); 2611173362Sbenjsc sc->config.chan = ieee80211_chan2ieee(ic, ni->ni_chan); 2612173362Sbenjsc if (IEEE80211_IS_CHAN_2GHZ(ni->ni_chan)) { 2613173362Sbenjsc sc->config.flags |= htole32(WPI_CONFIG_AUTO | 2614173362Sbenjsc WPI_CONFIG_24GHZ); 2615173362Sbenjsc } 2616173362Sbenjsc switch (ic->ic_curmode) { 2617173362Sbenjsc case IEEE80211_MODE_11A: 2618173362Sbenjsc sc->config.cck_mask = 0; 2619173362Sbenjsc sc->config.ofdm_mask = 0x15; 2620173362Sbenjsc break; 2621173362Sbenjsc case IEEE80211_MODE_11B: 2622173362Sbenjsc sc->config.cck_mask = 0x03; 2623173362Sbenjsc sc->config.ofdm_mask = 0; 2624173362Sbenjsc break; 2625173362Sbenjsc default: /* assume 802.11b/g */ 2626173362Sbenjsc sc->config.cck_mask = 0x0f; 2627173362Sbenjsc sc->config.ofdm_mask = 0x15; 2628173362Sbenjsc } 2629173362Sbenjsc 2630173362Sbenjsc DPRINTF(("config chan %d flags %x cck %x ofdm %x\n", sc->config.chan, 2631173362Sbenjsc sc->config.flags, sc->config.cck_mask, sc->config.ofdm_mask)); 2632173362Sbenjsc error = wpi_cmd(sc, WPI_CMD_CONFIGURE, &sc->config, 2633173362Sbenjsc sizeof (struct wpi_config), 1); 2634173362Sbenjsc if (error != 0) { 2635173362Sbenjsc device_printf(sc->sc_dev, "could not configure\n"); 2636173362Sbenjsc return error; 2637173362Sbenjsc } 2638173362Sbenjsc 2639173362Sbenjsc /* configuration has changed, set Tx power accordingly */ 2640173362Sbenjsc if ((error = wpi_set_txpower(sc, ni->ni_chan, 1)) != 0) { 2641173362Sbenjsc device_printf(sc->sc_dev, "could not set Tx power\n"); 2642173362Sbenjsc return error; 2643173362Sbenjsc } 2644173362Sbenjsc 2645173362Sbenjsc /* add default node */ 2646173362Sbenjsc memset(&node, 0, sizeof node); 2647173362Sbenjsc IEEE80211_ADDR_COPY(node.bssid, ni->ni_bssid); 2648173362Sbenjsc node.id = WPI_ID_BSS; 2649173362Sbenjsc node.rate = (ic->ic_curmode == IEEE80211_MODE_11A) ? 2650173362Sbenjsc wpi_plcp_signal(12) : wpi_plcp_signal(2); 2651173362Sbenjsc node.action = htole32(WPI_ACTION_SET_RATE); 2652173362Sbenjsc node.antenna = WPI_ANTENNA_BOTH; 2653173362Sbenjsc error = wpi_cmd(sc, WPI_CMD_ADD_NODE, &node, sizeof node, 1); 2654173362Sbenjsc if (error != 0) { 2655173362Sbenjsc device_printf(sc->sc_dev, "could not add BSS node\n"); 2656173362Sbenjsc return error; 2657173362Sbenjsc } 2658173362Sbenjsc 2659173362Sbenjsc sc->flags &= ~WPI_FLAG_AUTH; 2660173362Sbenjsc 2661173362Sbenjsc return 0; 2662173362Sbenjsc} 2663173362Sbenjsc 2664173362Sbenjsc/* 2665173362Sbenjsc * Send a scan request to the firmware. Since this command is huge, we map it 2666173362Sbenjsc * into a mbufcluster instead of using the pre-allocated set of commands. Note, 2667173362Sbenjsc * much of this code is similar to that in wpi_cmd but because we must manually 2668173362Sbenjsc * construct the probe & channels, we duplicate what's needed here. XXX In the 2669173362Sbenjsc * future, this function should be modified to use wpi_cmd to help cleanup the 2670173362Sbenjsc * code base. 2671173362Sbenjsc */ 2672173362Sbenjscstatic int 2673173362Sbenjscwpi_scan(struct wpi_softc *sc) 2674173362Sbenjsc{ 2675173362Sbenjsc struct ieee80211com *ic = &sc->sc_ic; 2676173362Sbenjsc struct wpi_tx_ring *ring = &sc->cmdq; 2677173362Sbenjsc struct wpi_tx_desc *desc; 2678173362Sbenjsc struct wpi_tx_data *data; 2679173362Sbenjsc struct wpi_tx_cmd *cmd; 2680173362Sbenjsc struct wpi_scan_hdr *hdr; 2681173362Sbenjsc struct wpi_scan_chan *chan; 2682173362Sbenjsc struct ieee80211_frame *wh; 2683173362Sbenjsc struct ieee80211_rateset *rs; 2684173362Sbenjsc struct ieee80211_channel *c; 2685173362Sbenjsc enum ieee80211_phymode mode; 2686173362Sbenjsc uint8_t *frm; 2687173362Sbenjsc int nrates, pktlen, error; 2688173362Sbenjsc bus_addr_t physaddr; 2689173362Sbenjsc struct ifnet *ifp = ic->ic_ifp; 2690173362Sbenjsc 2691173362Sbenjsc desc = &ring->desc[ring->cur]; 2692173362Sbenjsc data = &ring->data[ring->cur]; 2693173362Sbenjsc 2694173362Sbenjsc data->m = m_getcl(M_DONTWAIT, MT_DATA, M_PKTHDR); 2695173362Sbenjsc if (data->m == NULL) { 2696173362Sbenjsc device_printf(sc->sc_dev, 2697173362Sbenjsc "could not allocate mbuf for scan command\n"); 2698173362Sbenjsc return ENOMEM; 2699173362Sbenjsc } 2700173362Sbenjsc 2701173362Sbenjsc cmd = mtod(data->m, struct wpi_tx_cmd *); 2702173362Sbenjsc cmd->code = WPI_CMD_SCAN; 2703173362Sbenjsc cmd->flags = 0; 2704173362Sbenjsc cmd->qid = ring->qid; 2705173362Sbenjsc cmd->idx = ring->cur; 2706173362Sbenjsc 2707173362Sbenjsc hdr = (struct wpi_scan_hdr *)cmd->data; 2708173362Sbenjsc memset(hdr, 0, sizeof(struct wpi_scan_hdr)); 2709173362Sbenjsc 2710173362Sbenjsc /* 2711173362Sbenjsc * Move to the next channel if no packets are received within 5 msecs 2712173362Sbenjsc * after sending the probe request (this helps to reduce the duration 2713173362Sbenjsc * of active scans). 2714173362Sbenjsc */ 2715173362Sbenjsc hdr->quiet = htole16(5); 2716173362Sbenjsc hdr->threshold = htole16(1); 2717173362Sbenjsc 2718173362Sbenjsc if (IEEE80211_IS_CHAN_A(ic->ic_curchan)) { 2719173362Sbenjsc /* send probe requests at 6Mbps */ 2720173362Sbenjsc hdr->tx.rate = wpi_ridx_to_plcp[WPI_OFDM6]; 2721173362Sbenjsc 2722173362Sbenjsc /* Enable crc checking */ 2723173362Sbenjsc hdr->promotion = htole16(1); 2724173362Sbenjsc } else { 2725173362Sbenjsc hdr->flags = htole32(WPI_CONFIG_24GHZ | WPI_CONFIG_AUTO); 2726173362Sbenjsc /* send probe requests at 1Mbps */ 2727173362Sbenjsc hdr->tx.rate = wpi_ridx_to_plcp[WPI_CCK1]; 2728173362Sbenjsc } 2729173362Sbenjsc hdr->tx.id = WPI_ID_BROADCAST; 2730173362Sbenjsc hdr->tx.lifetime = htole32(WPI_LIFETIME_INFINITE); 2731173362Sbenjsc hdr->tx.flags = htole32(WPI_TX_AUTO_SEQ); 2732173362Sbenjsc 2733173362Sbenjsc /*XXX Need to cater for multiple essids */ 2734173362Sbenjsc memset(&hdr->scan_essids[0], 0, 4 * sizeof(hdr->scan_essids[0])); 2735173362Sbenjsc hdr->scan_essids[0].id = IEEE80211_ELEMID_SSID; 2736173362Sbenjsc hdr->scan_essids[0].esslen = ic->ic_des_ssid[0].len; 2737173362Sbenjsc memcpy(hdr->scan_essids[0].essid, ic->ic_des_ssid[0].ssid, 2738173362Sbenjsc ic->ic_des_ssid[0].len); 2739173362Sbenjsc 2740173362Sbenjsc if (wpi_debug & WPI_DEBUG_SCANNING) { 2741173362Sbenjsc printf("Scanning Essid: "); 2742173362Sbenjsc ieee80211_print_essid(ic->ic_des_ssid[0].ssid, 2743173362Sbenjsc ic->ic_des_ssid[0].len); 2744173362Sbenjsc printf("\n"); 2745173362Sbenjsc } 2746173362Sbenjsc 2747173362Sbenjsc /* 2748173362Sbenjsc * Build a probe request frame. Most of the following code is a 2749173362Sbenjsc * copy & paste of what is done in net80211. 2750173362Sbenjsc */ 2751173362Sbenjsc wh = (struct ieee80211_frame *)&hdr->scan_essids[4]; 2752173362Sbenjsc wh->i_fc[0] = IEEE80211_FC0_VERSION_0 | IEEE80211_FC0_TYPE_MGT | 2753173362Sbenjsc IEEE80211_FC0_SUBTYPE_PROBE_REQ; 2754173362Sbenjsc wh->i_fc[1] = IEEE80211_FC1_DIR_NODS; 2755173362Sbenjsc IEEE80211_ADDR_COPY(wh->i_addr1, ifp->if_broadcastaddr); 2756173362Sbenjsc IEEE80211_ADDR_COPY(wh->i_addr2, ic->ic_myaddr); 2757173362Sbenjsc IEEE80211_ADDR_COPY(wh->i_addr3, ifp->if_broadcastaddr); 2758173362Sbenjsc *(u_int16_t *)&wh->i_dur[0] = 0; /* filled by h/w */ 2759173362Sbenjsc *(u_int16_t *)&wh->i_seq[0] = 0; /* filled by h/w */ 2760173362Sbenjsc 2761173362Sbenjsc frm = (uint8_t *)(wh + 1); 2762173362Sbenjsc 2763173362Sbenjsc /* add essid IE, the hardware will fill this in for us */ 2764173362Sbenjsc *frm++ = IEEE80211_ELEMID_SSID; 2765173362Sbenjsc *frm++ = 0; 2766173362Sbenjsc 2767173362Sbenjsc mode = ieee80211_chan2mode(ic->ic_curchan); 2768173362Sbenjsc rs = &ic->ic_sup_rates[mode]; 2769173362Sbenjsc 2770173362Sbenjsc /* add supported rates IE */ 2771173362Sbenjsc *frm++ = IEEE80211_ELEMID_RATES; 2772173362Sbenjsc nrates = rs->rs_nrates; 2773173362Sbenjsc if (nrates > IEEE80211_RATE_SIZE) 2774173362Sbenjsc nrates = IEEE80211_RATE_SIZE; 2775173362Sbenjsc *frm++ = nrates; 2776173362Sbenjsc memcpy(frm, rs->rs_rates, nrates); 2777173362Sbenjsc frm += nrates; 2778173362Sbenjsc 2779173362Sbenjsc /* add supported xrates IE */ 2780173362Sbenjsc if (rs->rs_nrates > IEEE80211_RATE_SIZE) { 2781173362Sbenjsc nrates = rs->rs_nrates - IEEE80211_RATE_SIZE; 2782173362Sbenjsc *frm++ = IEEE80211_ELEMID_XRATES; 2783173362Sbenjsc *frm++ = nrates; 2784173362Sbenjsc memcpy(frm, rs->rs_rates + IEEE80211_RATE_SIZE, nrates); 2785173362Sbenjsc frm += nrates; 2786173362Sbenjsc } 2787173362Sbenjsc 2788173362Sbenjsc /* setup length of probe request */ 2789173362Sbenjsc hdr->tx.len = htole16(frm - (uint8_t *)wh); 2790173362Sbenjsc 2791173362Sbenjsc /* 2792173362Sbenjsc * Construct information about the channel that we 2793173362Sbenjsc * want to scan. The firmware expects this to be directly 2794173362Sbenjsc * after the scan probe request 2795173362Sbenjsc */ 2796173362Sbenjsc c = ic->ic_curchan; 2797173362Sbenjsc chan = (struct wpi_scan_chan *)frm; 2798173362Sbenjsc chan->chan = ieee80211_chan2ieee(ic, c); 2799173362Sbenjsc chan->flags = 0; 2800173362Sbenjsc if (!(c->ic_flags & IEEE80211_CHAN_PASSIVE)) { 2801173362Sbenjsc chan->flags |= WPI_CHAN_ACTIVE; 2802173362Sbenjsc if (ic->ic_des_ssid[0].len != 0) 2803173362Sbenjsc chan->flags |= WPI_CHAN_DIRECT; 2804173362Sbenjsc } 2805173362Sbenjsc chan->gain_dsp = 0x6e; /* Default level */ 2806173362Sbenjsc if (IEEE80211_IS_CHAN_5GHZ(c)) { 2807173362Sbenjsc chan->active = htole16(10); 2808173362Sbenjsc chan->passive = htole16(sc->maxdwell); 2809173362Sbenjsc chan->gain_radio = 0x3b; 2810173362Sbenjsc } else { 2811173362Sbenjsc chan->active = htole16(20); 2812173362Sbenjsc chan->passive = htole16(sc->maxdwell); 2813173362Sbenjsc chan->gain_radio = 0x28; 2814173362Sbenjsc } 2815173362Sbenjsc 2816173362Sbenjsc DPRINTFN(WPI_DEBUG_SCANNING, 2817173362Sbenjsc ("Scanning %u Passive: %d\n", 2818173362Sbenjsc chan->chan, 2819173362Sbenjsc c->ic_flags & IEEE80211_CHAN_PASSIVE)); 2820173362Sbenjsc 2821173362Sbenjsc hdr->nchan++; 2822173362Sbenjsc chan++; 2823173362Sbenjsc 2824173362Sbenjsc frm += sizeof (struct wpi_scan_chan); 2825173362Sbenjsc#if 0 2826173362Sbenjsc // XXX All Channels.... 2827173362Sbenjsc for (c = &ic->ic_channels[1]; 2828173362Sbenjsc c <= &ic->ic_channels[IEEE80211_CHAN_MAX]; c++) { 2829173362Sbenjsc if ((c->ic_flags & ic->ic_curchan->ic_flags) != ic->ic_curchan->ic_flags) 2830173362Sbenjsc continue; 2831173362Sbenjsc 2832173362Sbenjsc chan->chan = ieee80211_chan2ieee(ic, c); 2833173362Sbenjsc chan->flags = 0; 2834173362Sbenjsc if (!(c->ic_flags & IEEE80211_CHAN_PASSIVE)) { 2835173362Sbenjsc chan->flags |= WPI_CHAN_ACTIVE; 2836173362Sbenjsc if (ic->ic_des_ssid[0].len != 0) 2837173362Sbenjsc chan->flags |= WPI_CHAN_DIRECT; 2838173362Sbenjsc } 2839173362Sbenjsc chan->gain_dsp = 0x6e; /* Default level */ 2840173362Sbenjsc if (IEEE80211_IS_CHAN_5GHZ(c)) { 2841173362Sbenjsc chan->active = htole16(10); 2842173362Sbenjsc chan->passive = htole16(110); 2843173362Sbenjsc chan->gain_radio = 0x3b; 2844173362Sbenjsc } else { 2845173362Sbenjsc chan->active = htole16(20); 2846173362Sbenjsc chan->passive = htole16(120); 2847173362Sbenjsc chan->gain_radio = 0x28; 2848173362Sbenjsc } 2849173362Sbenjsc 2850173362Sbenjsc DPRINTFN(WPI_DEBUG_SCANNING, 2851173362Sbenjsc ("Scanning %u Passive: %d\n", 2852173362Sbenjsc chan->chan, 2853173362Sbenjsc c->ic_flags & IEEE80211_CHAN_PASSIVE)); 2854173362Sbenjsc 2855173362Sbenjsc hdr->nchan++; 2856173362Sbenjsc chan++; 2857173362Sbenjsc 2858173362Sbenjsc frm += sizeof (struct wpi_scan_chan); 2859173362Sbenjsc } 2860173362Sbenjsc#endif 2861173362Sbenjsc 2862173362Sbenjsc hdr->len = htole16(frm - (uint8_t *)hdr); 2863173362Sbenjsc pktlen = frm - (uint8_t *)cmd; 2864173362Sbenjsc 2865173362Sbenjsc error = bus_dmamap_load(ring->data_dmat, data->map, cmd, pktlen, 2866173362Sbenjsc wpi_dma_map_addr, &physaddr, BUS_DMA_NOWAIT); 2867173362Sbenjsc if (error != 0) { 2868173362Sbenjsc device_printf(sc->sc_dev, "could not map scan command\n"); 2869173362Sbenjsc m_freem(data->m); 2870173362Sbenjsc data->m = NULL; 2871173362Sbenjsc return error; 2872173362Sbenjsc } 2873173362Sbenjsc 2874173362Sbenjsc desc->flags = htole32(WPI_PAD32(pktlen) << 28 | 1 << 24); 2875173362Sbenjsc desc->segs[0].addr = htole32(physaddr); 2876173362Sbenjsc desc->segs[0].len = htole32(pktlen); 2877173362Sbenjsc 2878173362Sbenjsc bus_dmamap_sync(ring->desc_dma.tag, ring->desc_dma.map, 2879173362Sbenjsc BUS_DMASYNC_PREWRITE); 2880173362Sbenjsc bus_dmamap_sync(ring->data_dmat, data->map, BUS_DMASYNC_PREWRITE); 2881173362Sbenjsc 2882173362Sbenjsc /* kick cmd ring */ 2883173362Sbenjsc ring->cur = (ring->cur + 1) % WPI_CMD_RING_COUNT; 2884173362Sbenjsc WPI_WRITE(sc, WPI_TX_WIDX, ring->qid << 8 | ring->cur); 2885173362Sbenjsc 2886173362Sbenjsc return 0; /* will be notified async. of failure/success */ 2887173362Sbenjsc} 2888173362Sbenjsc 2889173362Sbenjsc/** 2890173362Sbenjsc * Configure the card to listen to a particular channel, this transisions the 2891173362Sbenjsc * card in to being able to receive frames from remote devices. 2892173362Sbenjsc */ 2893173362Sbenjscstatic int 2894173362Sbenjscwpi_config(struct wpi_softc *sc) 2895173362Sbenjsc{ 2896173362Sbenjsc struct ieee80211com *ic = &sc->sc_ic; 2897173362Sbenjsc struct ifnet *ifp = ic->ic_ifp; 2898173362Sbenjsc struct wpi_power power; 2899173362Sbenjsc struct wpi_bluetooth bluetooth; 2900173362Sbenjsc struct wpi_node_info node; 2901173362Sbenjsc int error; 2902173362Sbenjsc 2903173362Sbenjsc /* set power mode */ 2904173362Sbenjsc memset(&power, 0, sizeof power); 2905173362Sbenjsc power.flags = htole32(WPI_POWER_CAM|0x8); 2906173362Sbenjsc error = wpi_cmd(sc, WPI_CMD_SET_POWER_MODE, &power, sizeof power, 0); 2907173362Sbenjsc if (error != 0) { 2908173362Sbenjsc device_printf(sc->sc_dev, "could not set power mode\n"); 2909173362Sbenjsc return error; 2910173362Sbenjsc } 2911173362Sbenjsc 2912173362Sbenjsc /* configure bluetooth coexistence */ 2913173362Sbenjsc memset(&bluetooth, 0, sizeof bluetooth); 2914173362Sbenjsc bluetooth.flags = 3; 2915173362Sbenjsc bluetooth.lead = 0xaa; 2916173362Sbenjsc bluetooth.kill = 1; 2917173362Sbenjsc error = wpi_cmd(sc, WPI_CMD_BLUETOOTH, &bluetooth, sizeof bluetooth, 2918173362Sbenjsc 0); 2919173362Sbenjsc if (error != 0) { 2920173362Sbenjsc device_printf(sc->sc_dev, 2921173362Sbenjsc "could not configure bluetooth coexistence\n"); 2922173362Sbenjsc return error; 2923173362Sbenjsc } 2924173362Sbenjsc 2925173362Sbenjsc /* configure adapter */ 2926173362Sbenjsc memset(&sc->config, 0, sizeof (struct wpi_config)); 2927173362Sbenjsc IEEE80211_ADDR_COPY(sc->config.myaddr, ic->ic_myaddr); 2928173362Sbenjsc /*set default channel*/ 2929173362Sbenjsc sc->config.chan = htole16(ieee80211_chan2ieee(ic, ic->ic_curchan)); 2930173362Sbenjsc sc->config.flags = htole32(WPI_CONFIG_TSF); 2931173362Sbenjsc if (IEEE80211_IS_CHAN_2GHZ(ic->ic_curchan)) { 2932173362Sbenjsc sc->config.flags |= htole32(WPI_CONFIG_AUTO | 2933173362Sbenjsc WPI_CONFIG_24GHZ); 2934173362Sbenjsc } 2935173362Sbenjsc sc->config.filter = 0; 2936173362Sbenjsc switch (ic->ic_opmode) { 2937173362Sbenjsc case IEEE80211_M_STA: 2938173362Sbenjsc case IEEE80211_M_WDS: /* No know setup, use STA for now */ 2939173362Sbenjsc sc->config.mode = WPI_MODE_STA; 2940173362Sbenjsc sc->config.filter |= htole32(WPI_FILTER_MULTICAST); 2941173362Sbenjsc break; 2942173362Sbenjsc case IEEE80211_M_IBSS: 2943173362Sbenjsc case IEEE80211_M_AHDEMO: 2944173362Sbenjsc sc->config.mode = WPI_MODE_IBSS; 2945173362Sbenjsc sc->config.filter |= htole32(WPI_FILTER_BEACON | 2946173362Sbenjsc WPI_FILTER_MULTICAST); 2947173362Sbenjsc break; 2948173362Sbenjsc case IEEE80211_M_HOSTAP: 2949173362Sbenjsc sc->config.mode = WPI_MODE_HOSTAP; 2950173362Sbenjsc break; 2951173362Sbenjsc case IEEE80211_M_MONITOR: 2952173362Sbenjsc sc->config.mode = WPI_MODE_MONITOR; 2953173362Sbenjsc sc->config.filter |= htole32(WPI_FILTER_MULTICAST | 2954173362Sbenjsc WPI_FILTER_CTL | WPI_FILTER_PROMISC); 2955173362Sbenjsc break; 2956173362Sbenjsc } 2957173362Sbenjsc sc->config.cck_mask = 0x0f; /* not yet negotiated */ 2958173362Sbenjsc sc->config.ofdm_mask = 0xff; /* not yet negotiated */ 2959173362Sbenjsc error = wpi_cmd(sc, WPI_CMD_CONFIGURE, &sc->config, 2960173362Sbenjsc sizeof (struct wpi_config), 0); 2961173362Sbenjsc if (error != 0) { 2962173362Sbenjsc device_printf(sc->sc_dev, "configure command failed\n"); 2963173362Sbenjsc return error; 2964173362Sbenjsc } 2965173362Sbenjsc 2966173362Sbenjsc /* configuration has changed, set Tx power accordingly */ 2967173362Sbenjsc if ((error = wpi_set_txpower(sc, ic->ic_curchan,0)) != 0) { 2968173362Sbenjsc device_printf(sc->sc_dev, "could not set Tx power\n"); 2969173362Sbenjsc return error; 2970173362Sbenjsc } 2971173362Sbenjsc 2972173362Sbenjsc /* add broadcast node */ 2973173362Sbenjsc memset(&node, 0, sizeof node); 2974173362Sbenjsc IEEE80211_ADDR_COPY(node.bssid, ifp->if_broadcastaddr); 2975173362Sbenjsc node.id = WPI_ID_BROADCAST; 2976173362Sbenjsc node.rate = wpi_plcp_signal(2); 2977173362Sbenjsc error = wpi_cmd(sc, WPI_CMD_ADD_NODE, &node, sizeof node, 0); 2978173362Sbenjsc if (error != 0) { 2979173362Sbenjsc device_printf(sc->sc_dev, "could not add broadcast node\n"); 2980173362Sbenjsc return error; 2981173362Sbenjsc } 2982173362Sbenjsc 2983173362Sbenjsc /* Setup rate scalling */ 2984173362Sbenjsc error = wpi_mrr_setup(sc); 2985173362Sbenjsc if (error != 0) { 2986173362Sbenjsc device_printf(sc->sc_dev, "could not setup MRR\n"); 2987173362Sbenjsc return error; 2988173362Sbenjsc } 2989173362Sbenjsc 2990173362Sbenjsc return 0; 2991173362Sbenjsc} 2992173362Sbenjsc 2993173362Sbenjscstatic void 2994173362Sbenjscwpi_stop_master(struct wpi_softc *sc) 2995173362Sbenjsc{ 2996173362Sbenjsc uint32_t tmp; 2997173362Sbenjsc int ntries; 2998173362Sbenjsc 2999173362Sbenjsc DPRINTFN(WPI_DEBUG_HW,("Disabling Firmware execution\n")); 3000173362Sbenjsc 3001173362Sbenjsc tmp = WPI_READ(sc, WPI_RESET); 3002173362Sbenjsc WPI_WRITE(sc, WPI_RESET, tmp | WPI_STOP_MASTER | WPI_NEVO_RESET); 3003173362Sbenjsc 3004173362Sbenjsc tmp = WPI_READ(sc, WPI_GPIO_CTL); 3005173362Sbenjsc if ((tmp & WPI_GPIO_PWR_STATUS) == WPI_GPIO_PWR_SLEEP) 3006173362Sbenjsc return; /* already asleep */ 3007173362Sbenjsc 3008173362Sbenjsc for (ntries = 0; ntries < 100; ntries++) { 3009173362Sbenjsc if (WPI_READ(sc, WPI_RESET) & WPI_MASTER_DISABLED) 3010173362Sbenjsc break; 3011173362Sbenjsc DELAY(10); 3012173362Sbenjsc } 3013173362Sbenjsc if (ntries == 100) { 3014173362Sbenjsc device_printf(sc->sc_dev, "timeout waiting for master\n"); 3015173362Sbenjsc } 3016173362Sbenjsc} 3017173362Sbenjsc 3018173362Sbenjscstatic int 3019173362Sbenjscwpi_power_up(struct wpi_softc *sc) 3020173362Sbenjsc{ 3021173362Sbenjsc uint32_t tmp; 3022173362Sbenjsc int ntries; 3023173362Sbenjsc 3024173362Sbenjsc wpi_mem_lock(sc); 3025173362Sbenjsc tmp = wpi_mem_read(sc, WPI_MEM_POWER); 3026173362Sbenjsc wpi_mem_write(sc, WPI_MEM_POWER, tmp & ~0x03000000); 3027173362Sbenjsc wpi_mem_unlock(sc); 3028173362Sbenjsc 3029173362Sbenjsc for (ntries = 0; ntries < 5000; ntries++) { 3030173362Sbenjsc if (WPI_READ(sc, WPI_GPIO_STATUS) & WPI_POWERED) 3031173362Sbenjsc break; 3032173362Sbenjsc DELAY(10); 3033173362Sbenjsc } 3034173362Sbenjsc if (ntries == 5000) { 3035173362Sbenjsc device_printf(sc->sc_dev, 3036173362Sbenjsc "timeout waiting for NIC to power up\n"); 3037173362Sbenjsc return ETIMEDOUT; 3038173362Sbenjsc } 3039173362Sbenjsc return 0; 3040173362Sbenjsc} 3041173362Sbenjsc 3042173362Sbenjscstatic int 3043173362Sbenjscwpi_reset(struct wpi_softc *sc) 3044173362Sbenjsc{ 3045173362Sbenjsc uint32_t tmp; 3046173362Sbenjsc int ntries; 3047173362Sbenjsc 3048173362Sbenjsc DPRINTFN(WPI_DEBUG_HW, 3049173362Sbenjsc ("Resetting the card - clearing any uploaded firmware\n")); 3050173362Sbenjsc 3051173362Sbenjsc /* clear any pending interrupts */ 3052173362Sbenjsc WPI_WRITE(sc, WPI_INTR, 0xffffffff); 3053173362Sbenjsc 3054173362Sbenjsc tmp = WPI_READ(sc, WPI_PLL_CTL); 3055173362Sbenjsc WPI_WRITE(sc, WPI_PLL_CTL, tmp | WPI_PLL_INIT); 3056173362Sbenjsc 3057173362Sbenjsc tmp = WPI_READ(sc, WPI_CHICKEN); 3058173362Sbenjsc WPI_WRITE(sc, WPI_CHICKEN, tmp | WPI_CHICKEN_RXNOLOS); 3059173362Sbenjsc 3060173362Sbenjsc tmp = WPI_READ(sc, WPI_GPIO_CTL); 3061173362Sbenjsc WPI_WRITE(sc, WPI_GPIO_CTL, tmp | WPI_GPIO_INIT); 3062173362Sbenjsc 3063173362Sbenjsc /* wait for clock stabilization */ 3064173362Sbenjsc for (ntries = 0; ntries < 25000; ntries++) { 3065173362Sbenjsc if (WPI_READ(sc, WPI_GPIO_CTL) & WPI_GPIO_CLOCK) 3066173362Sbenjsc break; 3067173362Sbenjsc DELAY(10); 3068173362Sbenjsc } 3069173362Sbenjsc if (ntries == 25000) { 3070173362Sbenjsc device_printf(sc->sc_dev, 3071173362Sbenjsc "timeout waiting for clock stabilization\n"); 3072173362Sbenjsc return ETIMEDOUT; 3073173362Sbenjsc } 3074173362Sbenjsc 3075173362Sbenjsc /* initialize EEPROM */ 3076173362Sbenjsc tmp = WPI_READ(sc, WPI_EEPROM_STATUS); 3077173362Sbenjsc 3078173362Sbenjsc if ((tmp & WPI_EEPROM_VERSION) == 0) { 3079173362Sbenjsc device_printf(sc->sc_dev, "EEPROM not found\n"); 3080173362Sbenjsc return EIO; 3081173362Sbenjsc } 3082173362Sbenjsc WPI_WRITE(sc, WPI_EEPROM_STATUS, tmp & ~WPI_EEPROM_LOCKED); 3083173362Sbenjsc 3084173362Sbenjsc return 0; 3085173362Sbenjsc} 3086173362Sbenjsc 3087173362Sbenjscstatic void 3088173362Sbenjscwpi_hw_config(struct wpi_softc *sc) 3089173362Sbenjsc{ 3090173362Sbenjsc uint32_t rev, hw; 3091173362Sbenjsc 3092173362Sbenjsc /* voodoo from the Linux "driver".. */ 3093173362Sbenjsc hw = WPI_READ(sc, WPI_HWCONFIG); 3094173362Sbenjsc 3095173362Sbenjsc rev = pci_read_config(sc->sc_dev, PCIR_REVID, 1); 3096173362Sbenjsc if ((rev & 0xc0) == 0x40) 3097173362Sbenjsc hw |= WPI_HW_ALM_MB; 3098173362Sbenjsc else if (!(rev & 0x80)) 3099173362Sbenjsc hw |= WPI_HW_ALM_MM; 3100173362Sbenjsc 3101173362Sbenjsc if (sc->cap == 0x80) 3102173362Sbenjsc hw |= WPI_HW_SKU_MRC; 3103173362Sbenjsc 3104173362Sbenjsc hw &= ~WPI_HW_REV_D; 3105173362Sbenjsc if ((le16toh(sc->rev) & 0xf0) == 0xd0) 3106173362Sbenjsc hw |= WPI_HW_REV_D; 3107173362Sbenjsc 3108173362Sbenjsc if (sc->type > 1) 3109173362Sbenjsc hw |= WPI_HW_TYPE_B; 3110173362Sbenjsc 3111173362Sbenjsc WPI_WRITE(sc, WPI_HWCONFIG, hw); 3112173362Sbenjsc} 3113173362Sbenjsc 3114173362Sbenjscstatic void 3115173362Sbenjscwpi_init(void *arg) 3116173362Sbenjsc{ 3117173362Sbenjsc struct wpi_softc *sc = arg; 3118173362Sbenjsc struct ieee80211com *ic = &sc->sc_ic; 3119173362Sbenjsc struct ifnet *ifp = ic->ic_ifp; 3120173362Sbenjsc uint32_t tmp; 3121173362Sbenjsc int ntries, error, qid; 3122173362Sbenjsc WPI_LOCK_DECL; 3123173362Sbenjsc 3124173362Sbenjsc WPI_LOCK(sc); 3125173362Sbenjsc 3126173362Sbenjsc wpi_stop_locked(sc); 3127173362Sbenjsc (void)wpi_reset(sc); 3128173362Sbenjsc 3129173362Sbenjsc wpi_mem_lock(sc); 3130173362Sbenjsc wpi_mem_write(sc, WPI_MEM_CLOCK1, 0xa00); 3131173362Sbenjsc DELAY(20); 3132173362Sbenjsc tmp = wpi_mem_read(sc, WPI_MEM_PCIDEV); 3133173362Sbenjsc wpi_mem_write(sc, WPI_MEM_PCIDEV, tmp | 0x800); 3134173362Sbenjsc wpi_mem_unlock(sc); 3135173362Sbenjsc 3136173362Sbenjsc (void)wpi_power_up(sc); 3137173362Sbenjsc wpi_hw_config(sc); 3138173362Sbenjsc 3139173362Sbenjsc /* init Rx ring */ 3140173362Sbenjsc wpi_mem_lock(sc); 3141173362Sbenjsc WPI_WRITE(sc, WPI_RX_BASE, sc->rxq.desc_dma.paddr); 3142173362Sbenjsc WPI_WRITE(sc, WPI_RX_RIDX_PTR, sc->shared_dma.paddr + 3143173362Sbenjsc offsetof(struct wpi_shared, next)); 3144173362Sbenjsc WPI_WRITE(sc, WPI_RX_WIDX, (WPI_RX_RING_COUNT - 1) & ~7); 3145173362Sbenjsc WPI_WRITE(sc, WPI_RX_CONFIG, 0xa9601010); 3146173362Sbenjsc wpi_mem_unlock(sc); 3147173362Sbenjsc 3148173362Sbenjsc /* init Tx rings */ 3149173362Sbenjsc wpi_mem_lock(sc); 3150173362Sbenjsc wpi_mem_write(sc, WPI_MEM_MODE, 2); /* bypass mode */ 3151173362Sbenjsc wpi_mem_write(sc, WPI_MEM_RA, 1); /* enable RA0 */ 3152173362Sbenjsc wpi_mem_write(sc, WPI_MEM_TXCFG, 0x3f); /* enable all 6 Tx rings */ 3153173362Sbenjsc wpi_mem_write(sc, WPI_MEM_BYPASS1, 0x10000); 3154173362Sbenjsc wpi_mem_write(sc, WPI_MEM_BYPASS2, 0x30002); 3155173362Sbenjsc wpi_mem_write(sc, WPI_MEM_MAGIC4, 4); 3156173362Sbenjsc wpi_mem_write(sc, WPI_MEM_MAGIC5, 5); 3157173362Sbenjsc 3158173362Sbenjsc WPI_WRITE(sc, WPI_TX_BASE_PTR, sc->shared_dma.paddr); 3159173362Sbenjsc WPI_WRITE(sc, WPI_MSG_CONFIG, 0xffff05a5); 3160173362Sbenjsc 3161173362Sbenjsc for (qid = 0; qid < 6; qid++) { 3162173362Sbenjsc WPI_WRITE(sc, WPI_TX_CTL(qid), 0); 3163173362Sbenjsc WPI_WRITE(sc, WPI_TX_BASE(qid), 0); 3164173362Sbenjsc WPI_WRITE(sc, WPI_TX_CONFIG(qid), 0x80200008); 3165173362Sbenjsc } 3166173362Sbenjsc wpi_mem_unlock(sc); 3167173362Sbenjsc 3168173362Sbenjsc /* clear "radio off" and "disable command" bits (reversed logic) */ 3169173362Sbenjsc WPI_WRITE(sc, WPI_UCODE_CLR, WPI_RADIO_OFF); 3170173362Sbenjsc WPI_WRITE(sc, WPI_UCODE_CLR, WPI_DISABLE_CMD); 3171173362Sbenjsc sc->flags &= ~WPI_FLAG_HW_RADIO_OFF; 3172173362Sbenjsc 3173173362Sbenjsc /* clear any pending interrupts */ 3174173362Sbenjsc WPI_WRITE(sc, WPI_INTR, 0xffffffff); 3175173362Sbenjsc 3176173362Sbenjsc /* enable interrupts */ 3177173362Sbenjsc WPI_WRITE(sc, WPI_MASK, WPI_INTR_MASK); 3178173362Sbenjsc 3179173362Sbenjsc WPI_WRITE(sc, WPI_UCODE_CLR, WPI_RADIO_OFF); 3180173362Sbenjsc WPI_WRITE(sc, WPI_UCODE_CLR, WPI_RADIO_OFF); 3181173362Sbenjsc 3182173362Sbenjsc if ((error = wpi_load_firmware(sc)) != 0) { 3183173362Sbenjsc device_printf(sc->sc_dev, 3184173362Sbenjsc "A problem occurred loading the firmware to the driver\n"); 3185173362Sbenjsc return; 3186173362Sbenjsc } 3187173362Sbenjsc 3188173362Sbenjsc /* At this point the firmware is up and running. If the hardware 3189173362Sbenjsc * RF switch is turned off thermal calibration will fail, though 3190173362Sbenjsc * the card is still happy to continue to accept commands, catch 3191173362Sbenjsc * this case and record the hw is disabled. 3192173362Sbenjsc */ 3193173362Sbenjsc wpi_mem_lock(sc); 3194173362Sbenjsc tmp = wpi_mem_read(sc, WPI_MEM_HW_RADIO_OFF); 3195173362Sbenjsc wpi_mem_unlock(sc); 3196173362Sbenjsc 3197173362Sbenjsc if (!(tmp & 0x1)) { 3198173362Sbenjsc sc->flags |= WPI_FLAG_HW_RADIO_OFF; 3199173362Sbenjsc ifp->if_drv_flags &= ~IFF_DRV_OACTIVE; 3200173362Sbenjsc ifp->if_drv_flags |= IFF_DRV_RUNNING; 3201173362Sbenjsc device_printf(sc->sc_dev,"Radio Transmitter is switched off\n"); 3202173362Sbenjsc return; 3203173362Sbenjsc } 3204173362Sbenjsc 3205173362Sbenjsc /* wait for thermal sensors to calibrate */ 3206173362Sbenjsc for (ntries = 0; ntries < 1000; ntries++) { 3207173362Sbenjsc if ((sc->temp = (int)WPI_READ(sc, WPI_TEMPERATURE)) != 0) 3208173362Sbenjsc break; 3209173362Sbenjsc DELAY(10); 3210173362Sbenjsc } 3211173362Sbenjsc 3212173362Sbenjsc if (ntries == 1000) { 3213173362Sbenjsc device_printf(sc->sc_dev, 3214173362Sbenjsc "timeout waiting for thermal sensors calibration\n"); 3215173362Sbenjsc error = ETIMEDOUT; 3216173362Sbenjsc return; 3217173362Sbenjsc } 3218173362Sbenjsc DPRINTFN(WPI_DEBUG_TEMP,("temperature %d\n", sc->temp)); 3219173362Sbenjsc 3220173362Sbenjsc ifp->if_drv_flags &= ~IFF_DRV_OACTIVE; 3221173362Sbenjsc ifp->if_drv_flags |= IFF_DRV_RUNNING; 3222173362Sbenjsc callout_reset(&sc->watchdog_to, hz, wpi_tick, sc); 3223173362Sbenjsc WPI_UNLOCK(sc); 3224173362Sbenjsc 3225173362Sbenjsc if (ic->ic_opmode == IEEE80211_M_MONITOR) 3226173362Sbenjsc ieee80211_new_state(ic, IEEE80211_S_RUN, -1); 3227173362Sbenjsc else if (ic->ic_roaming != IEEE80211_ROAMING_MANUAL) 3228173362Sbenjsc ieee80211_new_state(ic, IEEE80211_S_SCAN, -1); 3229173362Sbenjsc} 3230173362Sbenjsc 3231173362Sbenjscstatic void 3232173362Sbenjscwpi_stop(struct wpi_softc *sc) 3233173362Sbenjsc{ 3234173362Sbenjsc WPI_LOCK_DECL; 3235173362Sbenjsc 3236173362Sbenjsc WPI_LOCK(sc); 3237173362Sbenjsc wpi_stop_locked(sc); 3238173362Sbenjsc WPI_UNLOCK(sc); 3239173362Sbenjsc 3240173362Sbenjsc} 3241173362Sbenjscstatic void 3242173362Sbenjscwpi_stop_locked(struct wpi_softc *sc) 3243173362Sbenjsc 3244173362Sbenjsc{ 3245173362Sbenjsc struct ieee80211com *ic = &sc->sc_ic; 3246173362Sbenjsc struct ifnet *ifp = ic->ic_ifp; 3247173362Sbenjsc uint32_t tmp; 3248173362Sbenjsc int ac; 3249173362Sbenjsc 3250173362Sbenjsc sc->watchdog_cnt = sc->sc_tx_timer = 0; 3251173362Sbenjsc ifp->if_drv_flags &= ~(IFF_DRV_RUNNING | IFF_DRV_OACTIVE); 3252173362Sbenjsc 3253173362Sbenjsc /* disable interrupts */ 3254173362Sbenjsc WPI_WRITE(sc, WPI_MASK, 0); 3255173362Sbenjsc WPI_WRITE(sc, WPI_INTR, WPI_INTR_MASK); 3256173362Sbenjsc WPI_WRITE(sc, WPI_INTR_STATUS, 0xff); 3257173362Sbenjsc WPI_WRITE(sc, WPI_INTR_STATUS, 0x00070000); 3258173362Sbenjsc 3259173362Sbenjsc /* Clear any commands left in the command buffer */ 3260173362Sbenjsc memset(sc->sc_cmd, 0, sizeof(sc->sc_cmd)); 3261173362Sbenjsc 3262173362Sbenjsc wpi_mem_lock(sc); 3263173362Sbenjsc wpi_mem_write(sc, WPI_MEM_MODE, 0); 3264173362Sbenjsc wpi_mem_unlock(sc); 3265173362Sbenjsc 3266173362Sbenjsc /* reset all Tx rings */ 3267173362Sbenjsc for (ac = 0; ac < 4; ac++) 3268173362Sbenjsc wpi_reset_tx_ring(sc, &sc->txq[ac]); 3269173362Sbenjsc wpi_reset_tx_ring(sc, &sc->cmdq); 3270173362Sbenjsc 3271173362Sbenjsc /* reset Rx ring */ 3272173362Sbenjsc wpi_reset_rx_ring(sc, &sc->rxq); 3273173362Sbenjsc 3274173362Sbenjsc wpi_mem_lock(sc); 3275173362Sbenjsc wpi_mem_write(sc, WPI_MEM_CLOCK2, 0x200); 3276173362Sbenjsc wpi_mem_unlock(sc); 3277173362Sbenjsc 3278173362Sbenjsc DELAY(5); 3279173362Sbenjsc 3280173362Sbenjsc wpi_stop_master(sc); 3281173362Sbenjsc 3282173362Sbenjsc tmp = WPI_READ(sc, WPI_RESET); 3283173362Sbenjsc WPI_WRITE(sc, WPI_RESET, tmp | WPI_SW_RESET); 3284173362Sbenjsc sc->flags &= ~WPI_FLAG_BUSY; 3285173362Sbenjsc 3286173362Sbenjsc ieee80211_new_state(ic, IEEE80211_S_INIT, -1); 3287173362Sbenjsc} 3288173362Sbenjsc 3289173362Sbenjscstatic void 3290173362Sbenjscwpi_iter_func(void *arg, struct ieee80211_node *ni) 3291173362Sbenjsc{ 3292173362Sbenjsc struct wpi_softc *sc = arg; 3293173362Sbenjsc struct wpi_node *wn = (struct wpi_node *)ni; 3294173362Sbenjsc 3295173362Sbenjsc ieee80211_amrr_choose(&sc->amrr, ni, &wn->amn); 3296173362Sbenjsc} 3297173362Sbenjsc 3298173362Sbenjscstatic void 3299173362Sbenjscwpi_newassoc(struct ieee80211_node *ni, int isnew) 3300173362Sbenjsc{ 3301173362Sbenjsc struct wpi_softc *sc = ni->ni_ic->ic_ifp->if_softc; 3302173362Sbenjsc int i; 3303173362Sbenjsc 3304173362Sbenjsc ieee80211_amrr_node_init(&sc->amrr, &((struct wpi_node *)ni)->amn); 3305173362Sbenjsc 3306173362Sbenjsc for (i = ni->ni_rates.rs_nrates - 1; 3307173362Sbenjsc i > 0 && (ni->ni_rates.rs_rates[i] & IEEE80211_RATE_VAL) > 72; 3308173362Sbenjsc i--); 3309173362Sbenjsc ni->ni_txrate = i; 3310173362Sbenjsc} 3311173362Sbenjsc 3312173362Sbenjscstatic void 3313173362Sbenjscwpi_calib_timeout(void *arg) 3314173362Sbenjsc{ 3315173362Sbenjsc struct wpi_softc *sc = arg; 3316173362Sbenjsc struct ieee80211com *ic = &sc->sc_ic; 3317173362Sbenjsc int temp; 3318173362Sbenjsc WPI_LOCK_DECL; 3319173362Sbenjsc 3320173362Sbenjsc /* automatic rate control triggered every 500ms */ 3321173362Sbenjsc if (ic->ic_fixed_rate == IEEE80211_FIXED_RATE_NONE) { 3322173362Sbenjsc WPI_LOCK(sc); 3323173362Sbenjsc if (ic->ic_opmode == IEEE80211_M_STA) 3324173362Sbenjsc wpi_iter_func(sc, ic->ic_bss); 3325173362Sbenjsc else 3326173362Sbenjsc ieee80211_iterate_nodes(&ic->ic_sta, wpi_iter_func, sc); 3327173362Sbenjsc WPI_UNLOCK(sc); 3328173362Sbenjsc } 3329173362Sbenjsc 3330173362Sbenjsc /* update sensor data */ 3331173362Sbenjsc temp = (int)WPI_READ(sc, WPI_TEMPERATURE); 3332173362Sbenjsc DPRINTFN(WPI_DEBUG_TEMP,("Temp in calibration is: %d\n", temp)); 3333173362Sbenjsc#if 0 3334173362Sbenjsc //XXX Used by OpenBSD Sensor Framework 3335173362Sbenjsc sc->sensor.value = temp + 260; 3336173362Sbenjsc#endif 3337173362Sbenjsc 3338173362Sbenjsc /* automatic power calibration every 60s */ 3339173362Sbenjsc if (++sc->calib_cnt >= 120) { 3340173362Sbenjsc wpi_power_calibration(sc, temp); 3341173362Sbenjsc sc->calib_cnt = 0; 3342173362Sbenjsc } 3343173362Sbenjsc 3344173362Sbenjsc callout_reset(&sc->calib_to, hz/2, wpi_calib_timeout, sc); 3345173362Sbenjsc} 3346173362Sbenjsc 3347173362Sbenjsc/* 3348173362Sbenjsc * This function is called periodically (every 60 seconds) to adjust output 3349173362Sbenjsc * power to temperature changes. 3350173362Sbenjsc */ 3351173362Sbenjscstatic void 3352173362Sbenjscwpi_power_calibration(struct wpi_softc *sc, int temp) 3353173362Sbenjsc{ 3354173362Sbenjsc /* sanity-check read value */ 3355173362Sbenjsc if (temp < -260 || temp > 25) { 3356173362Sbenjsc /* this can't be correct, ignore */ 3357173362Sbenjsc DPRINTFN(WPI_DEBUG_TEMP, 3358173362Sbenjsc ("out-of-range temperature reported: %d\n", temp)); 3359173362Sbenjsc return; 3360173362Sbenjsc } 3361173362Sbenjsc 3362173362Sbenjsc DPRINTFN(WPI_DEBUG_TEMP,("temperature %d->%d\n", sc->temp, temp)); 3363173362Sbenjsc 3364173362Sbenjsc /* adjust Tx power if need be */ 3365173362Sbenjsc if (abs(temp - sc->temp) <= 6) 3366173362Sbenjsc return; 3367173362Sbenjsc 3368173362Sbenjsc sc->temp = temp; 3369173362Sbenjsc 3370173362Sbenjsc if (wpi_set_txpower(sc, sc->sc_ic.ic_bss->ni_chan,1) != 0) { 3371173362Sbenjsc /* just warn, too bad for the automatic calibration... */ 3372173362Sbenjsc device_printf(sc->sc_dev,"could not adjust Tx power\n"); 3373173362Sbenjsc } 3374173362Sbenjsc} 3375173362Sbenjsc 3376173362Sbenjsc/** 3377173362Sbenjsc * Read the eeprom to find out what channels are valid for the given 3378173362Sbenjsc * band and update net80211 with what we find. 3379173362Sbenjsc */ 3380173362Sbenjscstatic void 3381173362Sbenjscwpi_read_eeprom_channels(struct wpi_softc *sc, int n) 3382173362Sbenjsc{ 3383173362Sbenjsc struct ieee80211com *ic = &sc->sc_ic; 3384173362Sbenjsc const struct wpi_chan_band *band = &wpi_bands[n]; 3385173362Sbenjsc struct wpi_eeprom_chan channels[WPI_MAX_CHAN_PER_BAND]; 3386173362Sbenjsc int chan, i, offset, passive; 3387173362Sbenjsc 3388173362Sbenjsc wpi_read_prom_data(sc, band->addr, channels, 3389173362Sbenjsc band->nchan * sizeof (struct wpi_eeprom_chan)); 3390173362Sbenjsc 3391173362Sbenjsc for (i = 0; i < band->nchan; i++) { 3392173362Sbenjsc if (!(channels[i].flags & WPI_EEPROM_CHAN_VALID)) { 3393173362Sbenjsc DPRINTFN(WPI_DEBUG_HW, 3394173362Sbenjsc ("Channel Not Valid: %d, band %d\n", 3395173362Sbenjsc band->chan[i],n)); 3396173362Sbenjsc continue; 3397173362Sbenjsc } 3398173362Sbenjsc 3399173362Sbenjsc passive = 0; 3400173362Sbenjsc chan = band->chan[i]; 3401173362Sbenjsc offset = ic->ic_nchans; 3402173362Sbenjsc 3403173362Sbenjsc /* is active scan allowed on this channel? */ 3404173362Sbenjsc if (!(channels[i].flags & WPI_EEPROM_CHAN_ACTIVE)) { 3405173362Sbenjsc passive = IEEE80211_CHAN_PASSIVE; 3406173362Sbenjsc } 3407173362Sbenjsc 3408173362Sbenjsc if (n == 0) { /* 2GHz band */ 3409173362Sbenjsc ic->ic_channels[offset].ic_ieee = chan; 3410173362Sbenjsc ic->ic_channels[offset].ic_freq = 3411173362Sbenjsc ieee80211_ieee2mhz(chan, IEEE80211_CHAN_2GHZ); 3412173362Sbenjsc ic->ic_channels[offset].ic_flags = IEEE80211_CHAN_B | passive; 3413173362Sbenjsc offset++; 3414173362Sbenjsc ic->ic_channels[offset].ic_ieee = chan; 3415173362Sbenjsc ic->ic_channels[offset].ic_freq = 3416173362Sbenjsc ieee80211_ieee2mhz(chan, IEEE80211_CHAN_2GHZ); 3417173362Sbenjsc ic->ic_channels[offset].ic_flags = IEEE80211_CHAN_G | passive; 3418173362Sbenjsc offset++; 3419173362Sbenjsc 3420173362Sbenjsc } else { /* 5GHz band */ 3421173362Sbenjsc /* 3422173362Sbenjsc * Some 3945ABG adapters support channels 7, 8, 11 3423173362Sbenjsc * and 12 in the 2GHz *and* 5GHz bands. 3424173362Sbenjsc * Because of limitations in our net80211(9) stack, 3425173362Sbenjsc * we can't support these channels in 5GHz band. 3426173362Sbenjsc * XXX not true; just need to map to proper frequency 3427173362Sbenjsc */ 3428173362Sbenjsc if (chan <= 14) 3429173362Sbenjsc continue; 3430173362Sbenjsc 3431173362Sbenjsc ic->ic_channels[offset].ic_ieee = chan; 3432173362Sbenjsc ic->ic_channels[offset].ic_freq = 3433173362Sbenjsc ieee80211_ieee2mhz(chan, IEEE80211_CHAN_5GHZ); 3434173362Sbenjsc ic->ic_channels[offset].ic_flags = IEEE80211_CHAN_A | passive; 3435173362Sbenjsc offset++; 3436173362Sbenjsc } 3437173362Sbenjsc 3438173362Sbenjsc /* save maximum allowed power for this channel */ 3439173362Sbenjsc sc->maxpwr[chan] = channels[i].maxpwr; 3440173362Sbenjsc 3441173362Sbenjsc ic->ic_nchans = offset; 3442173362Sbenjsc 3443173362Sbenjsc#if 0 3444173362Sbenjsc // XXX We can probably use this an get rid of maxpwr - ben 20070617 3445173362Sbenjsc ic->ic_channels[chan].ic_maxpower = channels[i].maxpwr; 3446173362Sbenjsc //ic->ic_channels[chan].ic_minpower... 3447173362Sbenjsc //ic->ic_channels[chan].ic_maxregtxpower... 3448173362Sbenjsc#endif 3449173362Sbenjsc 3450173362Sbenjsc DPRINTF(("adding chan %d flags=0x%x maxpwr=%d, offset %d\n", 3451173362Sbenjsc chan, channels[i].flags, sc->maxpwr[chan], offset)); 3452173362Sbenjsc } 3453173362Sbenjsc} 3454173362Sbenjsc 3455173362Sbenjscstatic void 3456173362Sbenjscwpi_read_eeprom_group(struct wpi_softc *sc, int n) 3457173362Sbenjsc{ 3458173362Sbenjsc struct wpi_power_group *group = &sc->groups[n]; 3459173362Sbenjsc struct wpi_eeprom_group rgroup; 3460173362Sbenjsc int i; 3461173362Sbenjsc 3462173362Sbenjsc wpi_read_prom_data(sc, WPI_EEPROM_POWER_GRP + n * 32, &rgroup, 3463173362Sbenjsc sizeof rgroup); 3464173362Sbenjsc 3465173362Sbenjsc /* save power group information */ 3466173362Sbenjsc group->chan = rgroup.chan; 3467173362Sbenjsc group->maxpwr = rgroup.maxpwr; 3468173362Sbenjsc /* temperature at which the samples were taken */ 3469173362Sbenjsc group->temp = (int16_t)le16toh(rgroup.temp); 3470173362Sbenjsc 3471173362Sbenjsc DPRINTF(("power group %d: chan=%d maxpwr=%d temp=%d\n", n, 3472173362Sbenjsc group->chan, group->maxpwr, group->temp)); 3473173362Sbenjsc 3474173362Sbenjsc for (i = 0; i < WPI_SAMPLES_COUNT; i++) { 3475173362Sbenjsc group->samples[i].index = rgroup.samples[i].index; 3476173362Sbenjsc group->samples[i].power = rgroup.samples[i].power; 3477173362Sbenjsc 3478173362Sbenjsc DPRINTF(("\tsample %d: index=%d power=%d\n", i, 3479173362Sbenjsc group->samples[i].index, group->samples[i].power)); 3480173362Sbenjsc } 3481173362Sbenjsc} 3482173362Sbenjsc 3483173362Sbenjsc/* 3484173362Sbenjsc * Update Tx power to match what is defined for channel `c'. 3485173362Sbenjsc */ 3486173362Sbenjscstatic int 3487173362Sbenjscwpi_set_txpower(struct wpi_softc *sc, struct ieee80211_channel *c, int async) 3488173362Sbenjsc{ 3489173362Sbenjsc struct ieee80211com *ic = &sc->sc_ic; 3490173362Sbenjsc struct wpi_power_group *group; 3491173362Sbenjsc struct wpi_cmd_txpower txpower; 3492173362Sbenjsc u_int chan; 3493173362Sbenjsc int i; 3494173362Sbenjsc 3495173362Sbenjsc /* get channel number */ 3496173362Sbenjsc chan = ieee80211_chan2ieee(ic, c); 3497173362Sbenjsc 3498173362Sbenjsc /* find the power group to which this channel belongs */ 3499173362Sbenjsc if (IEEE80211_IS_CHAN_5GHZ(c)) { 3500173362Sbenjsc for (group = &sc->groups[1]; group < &sc->groups[4]; group++) 3501173362Sbenjsc if (chan <= group->chan) 3502173362Sbenjsc break; 3503173362Sbenjsc } else 3504173362Sbenjsc group = &sc->groups[0]; 3505173362Sbenjsc 3506173362Sbenjsc memset(&txpower, 0, sizeof txpower); 3507173362Sbenjsc txpower.band = IEEE80211_IS_CHAN_5GHZ(c) ? 0 : 1; 3508173362Sbenjsc txpower.channel = htole16(chan); 3509173362Sbenjsc 3510173362Sbenjsc /* set Tx power for all OFDM and CCK rates */ 3511173362Sbenjsc for (i = 0; i <= 11 ; i++) { 3512173362Sbenjsc /* retrieve Tx power for this channel/rate combination */ 3513173362Sbenjsc int idx = wpi_get_power_index(sc, group, c, 3514173362Sbenjsc wpi_ridx_to_rate[i]); 3515173362Sbenjsc 3516173362Sbenjsc txpower.rates[i].rate = wpi_ridx_to_plcp[i]; 3517173362Sbenjsc 3518173362Sbenjsc if (IEEE80211_IS_CHAN_5GHZ(c)) { 3519173362Sbenjsc txpower.rates[i].gain_radio = wpi_rf_gain_5ghz[idx]; 3520173362Sbenjsc txpower.rates[i].gain_dsp = wpi_dsp_gain_5ghz[idx]; 3521173362Sbenjsc } else { 3522173362Sbenjsc txpower.rates[i].gain_radio = wpi_rf_gain_2ghz[idx]; 3523173362Sbenjsc txpower.rates[i].gain_dsp = wpi_dsp_gain_2ghz[idx]; 3524173362Sbenjsc } 3525173362Sbenjsc DPRINTFN(WPI_DEBUG_TEMP,("chan %d/rate %d: power index %d\n", 3526173362Sbenjsc chan, wpi_ridx_to_rate[i], idx)); 3527173362Sbenjsc } 3528173362Sbenjsc 3529173362Sbenjsc return wpi_cmd(sc, WPI_CMD_TXPOWER, &txpower, sizeof txpower, async); 3530173362Sbenjsc} 3531173362Sbenjsc 3532173362Sbenjsc/* 3533173362Sbenjsc * Determine Tx power index for a given channel/rate combination. 3534173362Sbenjsc * This takes into account the regulatory information from EEPROM and the 3535173362Sbenjsc * current temperature. 3536173362Sbenjsc */ 3537173362Sbenjscstatic int 3538173362Sbenjscwpi_get_power_index(struct wpi_softc *sc, struct wpi_power_group *group, 3539173362Sbenjsc struct ieee80211_channel *c, int rate) 3540173362Sbenjsc{ 3541173362Sbenjsc/* fixed-point arithmetic division using a n-bit fractional part */ 3542173362Sbenjsc#define fdivround(a, b, n) \ 3543173362Sbenjsc ((((1 << n) * (a)) / (b) + (1 << n) / 2) / (1 << n)) 3544173362Sbenjsc 3545173362Sbenjsc/* linear interpolation */ 3546173362Sbenjsc#define interpolate(x, x1, y1, x2, y2, n) \ 3547173362Sbenjsc ((y1) + fdivround(((x) - (x1)) * ((y2) - (y1)), (x2) - (x1), n)) 3548173362Sbenjsc 3549173362Sbenjsc struct ieee80211com *ic = &sc->sc_ic; 3550173362Sbenjsc struct wpi_power_sample *sample; 3551173362Sbenjsc int pwr, idx; 3552173362Sbenjsc u_int chan; 3553173362Sbenjsc 3554173362Sbenjsc /* get channel number */ 3555173362Sbenjsc chan = ieee80211_chan2ieee(ic, c); 3556173362Sbenjsc 3557173362Sbenjsc /* default power is group's maximum power - 3dB */ 3558173362Sbenjsc pwr = group->maxpwr / 2; 3559173362Sbenjsc 3560173362Sbenjsc /* decrease power for highest OFDM rates to reduce distortion */ 3561173362Sbenjsc switch (rate) { 3562173362Sbenjsc case 72: /* 36Mb/s */ 3563173362Sbenjsc pwr -= IEEE80211_IS_CHAN_2GHZ(c) ? 0 : 5; 3564173362Sbenjsc break; 3565173362Sbenjsc case 96: /* 48Mb/s */ 3566173362Sbenjsc pwr -= IEEE80211_IS_CHAN_2GHZ(c) ? 7 : 10; 3567173362Sbenjsc break; 3568173362Sbenjsc case 108: /* 54Mb/s */ 3569173362Sbenjsc pwr -= IEEE80211_IS_CHAN_2GHZ(c) ? 9 : 12; 3570173362Sbenjsc break; 3571173362Sbenjsc } 3572173362Sbenjsc 3573173362Sbenjsc /* never exceed channel's maximum allowed Tx power */ 3574173362Sbenjsc pwr = min(pwr, sc->maxpwr[chan]); 3575173362Sbenjsc 3576173362Sbenjsc /* retrieve power index into gain tables from samples */ 3577173362Sbenjsc for (sample = group->samples; sample < &group->samples[3]; sample++) 3578173362Sbenjsc if (pwr > sample[1].power) 3579173362Sbenjsc break; 3580173362Sbenjsc /* fixed-point linear interpolation using a 19-bit fractional part */ 3581173362Sbenjsc idx = interpolate(pwr, sample[0].power, sample[0].index, 3582173362Sbenjsc sample[1].power, sample[1].index, 19); 3583173362Sbenjsc 3584173362Sbenjsc /* 3585173362Sbenjsc * Adjust power index based on current temperature 3586173362Sbenjsc * - if colder than factory-calibrated: decreate output power 3587173362Sbenjsc * - if warmer than factory-calibrated: increase output power 3588173362Sbenjsc */ 3589173362Sbenjsc idx -= (sc->temp - group->temp) * 11 / 100; 3590173362Sbenjsc 3591173362Sbenjsc /* decrease power for CCK rates (-5dB) */ 3592173362Sbenjsc if (!WPI_RATE_IS_OFDM(rate)) 3593173362Sbenjsc idx += 10; 3594173362Sbenjsc 3595173362Sbenjsc /* keep power index in a valid range */ 3596173362Sbenjsc if (idx < 0) 3597173362Sbenjsc return 0; 3598173362Sbenjsc if (idx > WPI_MAX_PWR_INDEX) 3599173362Sbenjsc return WPI_MAX_PWR_INDEX; 3600173362Sbenjsc return idx; 3601173362Sbenjsc 3602173362Sbenjsc#undef interpolate 3603173362Sbenjsc#undef fdivround 3604173362Sbenjsc} 3605173362Sbenjsc 3606173362Sbenjsc#if 0 3607173362Sbenjscstatic void 3608173362Sbenjscwpi_radio_on(void *arg, int pending) 3609173362Sbenjsc{ 3610173362Sbenjsc struct wpi_softc *sc = arg; 3611173362Sbenjsc 3612173362Sbenjsc device_printf(sc->sc_dev, "radio turned on\n"); 3613173362Sbenjsc} 3614173362Sbenjsc 3615173362Sbenjscstatic void 3616173362Sbenjscwpi_radio_off(void *arg, int pending) 3617173362Sbenjsc{ 3618173362Sbenjsc struct wpi_softc *sc = arg; 3619173362Sbenjsc 3620173362Sbenjsc device_printf(sc->sc_dev, "radio turned off\n"); 3621173362Sbenjsc} 3622173362Sbenjsc#endif 3623173362Sbenjsc 3624173362Sbenjsc/** 3625173362Sbenjsc * Called by net80211 framework to indicate that a scan 3626173362Sbenjsc * is starting. This function doesn't actually do the scan, 3627173362Sbenjsc * wpi_scan_curchan starts things off. This function is more 3628173362Sbenjsc * of an early warning from the framework we should get ready 3629173362Sbenjsc * for the scan. 3630173362Sbenjsc */ 3631173362Sbenjscstatic void 3632173362Sbenjscwpi_scan_start(struct ieee80211com *ic) 3633173362Sbenjsc{ 3634173362Sbenjsc struct ifnet *ifp = ic->ic_ifp; 3635173362Sbenjsc struct wpi_softc *sc = ifp->if_softc; 3636173362Sbenjsc 3637173362Sbenjsc wpi_queue_cmd(sc, WPI_SCAN_START); 3638173362Sbenjsc} 3639173362Sbenjsc 3640173362Sbenjsc/** 3641173362Sbenjsc * Called by the net80211 framework, indicates that the 3642173362Sbenjsc * scan has ended. If there is a scan in progress on the card 3643173362Sbenjsc * then it should be aborted. 3644173362Sbenjsc */ 3645173362Sbenjscstatic void 3646173362Sbenjscwpi_scan_end(struct ieee80211com *ic) 3647173362Sbenjsc{ 3648173362Sbenjsc struct ifnet *ifp = ic->ic_ifp; 3649173362Sbenjsc struct wpi_softc *sc = ifp->if_softc; 3650173362Sbenjsc 3651173362Sbenjsc wpi_queue_cmd(sc, WPI_SCAN_STOP); 3652173362Sbenjsc} 3653173362Sbenjsc 3654173362Sbenjsc/** 3655173362Sbenjsc * Called by the net80211 framework to indicate to the driver 3656173362Sbenjsc * that the channel should be changed 3657173362Sbenjsc */ 3658173362Sbenjscstatic void 3659173362Sbenjscwpi_set_channel(struct ieee80211com *ic) 3660173362Sbenjsc{ 3661173362Sbenjsc struct ifnet *ifp = ic->ic_ifp; 3662173362Sbenjsc struct wpi_softc *sc = ifp->if_softc; 3663173362Sbenjsc 3664173362Sbenjsc wpi_queue_cmd(sc, WPI_SET_CHAN); 3665173362Sbenjsc} 3666173362Sbenjsc 3667173362Sbenjsc/** 3668173362Sbenjsc * Called by net80211 to indicate that we need to scan the current 3669173362Sbenjsc * channel. The channel is previously be set via the wpi_set_channel 3670173362Sbenjsc * callback. 3671173362Sbenjsc */ 3672173362Sbenjscstatic void 3673173362Sbenjscwpi_scan_curchan(struct ieee80211com *ic, unsigned long maxdwell) 3674173362Sbenjsc{ 3675173362Sbenjsc struct ifnet *ifp = ic->ic_ifp; 3676173362Sbenjsc struct wpi_softc *sc = ifp->if_softc; 3677173362Sbenjsc 3678173362Sbenjsc sc->maxdwell = maxdwell; 3679173362Sbenjsc 3680173362Sbenjsc wpi_queue_cmd(sc, WPI_SCAN_CURCHAN); 3681173362Sbenjsc} 3682173362Sbenjsc 3683173362Sbenjsc/** 3684173362Sbenjsc * Called by the net80211 framework to indicate 3685173362Sbenjsc * the minimum dwell time has been met, terminate the scan. 3686173362Sbenjsc * We don't actually terminate the scan as the firmware will notify 3687173362Sbenjsc * us when it's finished and we have no way to interrupt it. 3688173362Sbenjsc */ 3689173362Sbenjscstatic void 3690173362Sbenjscwpi_scan_mindwell(struct ieee80211com *ic) 3691173362Sbenjsc{ 3692173362Sbenjsc /* NB: don't try to abort scan; wait for firmware to finish */ 3693173362Sbenjsc} 3694173362Sbenjsc 3695173362Sbenjsc/** 3696173362Sbenjsc * The ops function is called to perform some actual work. 3697173362Sbenjsc * because we can't sleep from any of the ic callbacks, we queue an 3698173362Sbenjsc * op task with wpi_queue_cmd and have the taskqueue process that task. 3699173362Sbenjsc * The task that gets cued is a op task, which ends up calling this function. 3700173362Sbenjsc */ 3701173362Sbenjscstatic void 3702173362Sbenjscwpi_ops(void *arg, int pending) 3703173362Sbenjsc{ 3704173362Sbenjsc struct wpi_softc *sc = arg; 3705173362Sbenjsc struct ieee80211com *ic = &sc->sc_ic; 3706173362Sbenjsc WPI_LOCK_DECL; 3707173362Sbenjsc int cmd; 3708173362Sbenjsc 3709173362Sbenjscagain: 3710173362Sbenjsc WPI_CMD_LOCK(sc); 3711173362Sbenjsc cmd = sc->sc_cmd[sc->sc_cmd_cur]; 3712173362Sbenjsc 3713173362Sbenjsc if (cmd == 0) { 3714173362Sbenjsc /* No more commands to process */ 3715173362Sbenjsc WPI_CMD_UNLOCK(sc); 3716173362Sbenjsc return; 3717173362Sbenjsc } 3718173362Sbenjsc sc->sc_cmd[sc->sc_cmd_cur] = 0; /* free the slot */ 3719173362Sbenjsc sc->sc_cmd_cur = (sc->sc_cmd_cur + 1) % WPI_CMD_MAXOPS; 3720173362Sbenjsc WPI_CMD_UNLOCK(sc); 3721173362Sbenjsc WPI_LOCK(sc); 3722173362Sbenjsc 3723173362Sbenjsc if (!(sc->sc_ifp->if_drv_flags & IFF_DRV_RUNNING)) { 3724173362Sbenjsc WPI_UNLOCK(sc); 3725173362Sbenjsc return; 3726173362Sbenjsc } 3727173362Sbenjsc 3728173362Sbenjsc { 3729173362Sbenjsc const char *name[]={"SCAN_START", "SCAN_CURCHAN",0,"STOP",0,0,0,"CHAN", 3730173362Sbenjsc 0,0,0,0,0,0,"AUTH",0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,"NEXT"}; 3731173362Sbenjsc DPRINTFN(WPI_DEBUG_OPS,("wpi_ops: command: %d %s\n", cmd, name[cmd-1])); 3732173362Sbenjsc } 3733173362Sbenjsc 3734173362Sbenjsc switch (cmd) { 3735173362Sbenjsc case WPI_SCAN_START: 3736173362Sbenjsc if (sc->flags & WPI_FLAG_HW_RADIO_OFF) { 3737173362Sbenjsc DPRINTF(("HERER\n")); 3738173362Sbenjsc ieee80211_cancel_scan(ic); 3739173362Sbenjsc } else 3740173362Sbenjsc sc->flags |= WPI_FLAG_SCANNING; 3741173362Sbenjsc break; 3742173362Sbenjsc 3743173362Sbenjsc case WPI_SCAN_STOP: 3744173362Sbenjsc sc->flags &= ~WPI_FLAG_SCANNING; 3745173362Sbenjsc break; 3746173362Sbenjsc 3747173362Sbenjsc case WPI_SCAN_NEXT: 3748173362Sbenjsc DPRINTF(("NEXT\n")); 3749173362Sbenjsc WPI_UNLOCK(sc); 3750173362Sbenjsc ieee80211_scan_next(ic); 3751173362Sbenjsc WPI_LOCK(sc); 3752173362Sbenjsc break; 3753173362Sbenjsc 3754173362Sbenjsc case WPI_SCAN_CURCHAN: 3755173362Sbenjsc if (wpi_scan(sc)) 3756173362Sbenjsc ieee80211_cancel_scan(ic); 3757173362Sbenjsc break; 3758173362Sbenjsc 3759173362Sbenjsc case WPI_SET_CHAN: 3760173362Sbenjsc if (sc->flags&WPI_FLAG_AUTH) { 3761173362Sbenjsc DPRINTF(("Authenticating, not changing channel\n")); 3762173362Sbenjsc break; 3763173362Sbenjsc } 3764173362Sbenjsc if (wpi_config(sc)) { 3765173362Sbenjsc DPRINTF(("Scan cancelled\n")); 3766173362Sbenjsc WPI_UNLOCK(sc); 3767173362Sbenjsc ieee80211_cancel_scan(ic); 3768173362Sbenjsc WPI_LOCK(sc); 3769173362Sbenjsc sc->flags &= ~WPI_FLAG_SCANNING; 3770173362Sbenjsc wpi_restart(sc,0); 3771173362Sbenjsc WPI_UNLOCK(sc); 3772173362Sbenjsc return; 3773173362Sbenjsc } 3774173362Sbenjsc break; 3775173362Sbenjsc 3776173362Sbenjsc case WPI_AUTH: 3777173362Sbenjsc if (wpi_auth(sc) != 0) { 3778173362Sbenjsc device_printf(sc->sc_dev, 3779173362Sbenjsc "could not send authentication request\n"); 3780173362Sbenjsc wpi_stop_locked(sc); 3781173362Sbenjsc WPI_UNLOCK(sc); 3782173362Sbenjsc return; 3783173362Sbenjsc } 3784173362Sbenjsc WPI_UNLOCK(sc); 3785173362Sbenjsc ieee80211_node_authorize(ic->ic_bss); 3786173362Sbenjsc ieee80211_new_state(ic, IEEE80211_S_ASSOC, -1); 3787173362Sbenjsc WPI_LOCK(sc); 3788173362Sbenjsc break; 3789173362Sbenjsc } 3790173362Sbenjsc WPI_UNLOCK(sc); 3791173362Sbenjsc 3792173362Sbenjsc /* Take another pass */ 3793173362Sbenjsc goto again; 3794173362Sbenjsc} 3795173362Sbenjsc 3796173362Sbenjsc/** 3797173362Sbenjsc * queue a command for later execution in a different thread. 3798173362Sbenjsc * This is needed as the net80211 callbacks do not allow 3799173362Sbenjsc * sleeping, since we need to sleep to confirm commands have 3800173362Sbenjsc * been processed by the firmware, we must defer execution to 3801173362Sbenjsc * a sleep enabled thread. 3802173362Sbenjsc */ 3803173362Sbenjscstatic int 3804173362Sbenjscwpi_queue_cmd(struct wpi_softc *sc, int cmd) 3805173362Sbenjsc{ 3806173362Sbenjsc WPI_CMD_LOCK(sc); 3807173362Sbenjsc 3808173362Sbenjsc if (sc->sc_cmd[sc->sc_cmd_next] != 0) { 3809173362Sbenjsc WPI_CMD_UNLOCK(sc); 3810173362Sbenjsc DPRINTF(("%s: command %d dropped\n", __func__, cmd)); 3811173362Sbenjsc return (EBUSY); 3812173362Sbenjsc } 3813173362Sbenjsc 3814173362Sbenjsc sc->sc_cmd[sc->sc_cmd_next] = cmd; 3815173362Sbenjsc sc->sc_cmd_next = (sc->sc_cmd_next + 1) % WPI_CMD_MAXOPS; 3816173362Sbenjsc 3817173362Sbenjsc taskqueue_enqueue(sc->sc_tq, &sc->sc_opstask); 3818173362Sbenjsc 3819173362Sbenjsc WPI_CMD_UNLOCK(sc); 3820173362Sbenjsc 3821173362Sbenjsc return 0; 3822173362Sbenjsc} 3823173362Sbenjsc 3824173362Sbenjscstatic void 3825173362Sbenjscwpi_restart(void * arg, int pending) 3826173362Sbenjsc{ 3827173362Sbenjsc#if 0 3828173362Sbenjsc struct wpi_softc *sc = arg; 3829173362Sbenjsc struct ieee80211com *ic = &sc->sc_ic; 3830173362Sbenjsc WPI_LOCK_DECL; 3831173362Sbenjsc 3832173362Sbenjsc DPRINTF(("Device failed, restarting device\n")); 3833173362Sbenjsc WPI_LOCK(sc); 3834173362Sbenjsc wpi_stop(sc); 3835173362Sbenjsc wpi_init(sc); 3836173362Sbenjsc WPI_UNLOCK(sc); 3837173362Sbenjsc ieee80211_new_state(ic, IEEE80211_S_SCAN, -1); 3838173362Sbenjsc#endif 3839173362Sbenjsc} 3840173362Sbenjsc 3841173362Sbenjsc/* 3842173362Sbenjsc * Allocate DMA-safe memory for firmware transfer. 3843173362Sbenjsc */ 3844173362Sbenjscstatic int 3845173362Sbenjscwpi_alloc_fwmem(struct wpi_softc *sc) 3846173362Sbenjsc{ 3847173362Sbenjsc /* allocate enough contiguous space to store text and data */ 3848173362Sbenjsc return wpi_dma_contig_alloc(sc, &sc->fw_dma, NULL, 3849173362Sbenjsc WPI_FW_MAIN_TEXT_MAXSZ + WPI_FW_MAIN_DATA_MAXSZ, 1, 3850173362Sbenjsc BUS_DMA_NOWAIT); 3851173362Sbenjsc} 3852173362Sbenjsc 3853173362Sbenjscstatic void 3854173362Sbenjscwpi_free_fwmem(struct wpi_softc *sc) 3855173362Sbenjsc{ 3856173362Sbenjsc wpi_dma_contig_free(&sc->fw_dma); 3857173362Sbenjsc} 3858173362Sbenjsc 3859173362Sbenjsc/** 3860173362Sbenjsc * Called every second, wpi_tick used by the watch dog timer 3861173362Sbenjsc * to check that the card is still alive 3862173362Sbenjsc */ 3863173362Sbenjscstatic void 3864173362Sbenjscwpi_tick(void *arg) 3865173362Sbenjsc{ 3866173362Sbenjsc struct wpi_softc *sc = arg; 3867173362Sbenjsc 3868173362Sbenjsc DPRINTFN(WPI_DEBUG_WATCHDOG,("Watchdog: tick\n")); 3869173362Sbenjsc 3870173362Sbenjsc wpi_watchdog(sc->sc_ifp); 3871173362Sbenjsc callout_reset(&sc->watchdog_to, hz, wpi_tick, sc); 3872173362Sbenjsc} 3873173362Sbenjsc 3874173362Sbenjsc#ifdef WPI_DEBUG 3875173362Sbenjscstatic const char *wpi_cmd_str(int cmd) 3876173362Sbenjsc{ 3877173362Sbenjsc switch(cmd) { 3878173362Sbenjsc case WPI_DISABLE_CMD: return "WPI_DISABLE_CMD"; 3879173362Sbenjsc case WPI_CMD_CONFIGURE: return "WPI_CMD_CONFIGURE"; 3880173362Sbenjsc case WPI_CMD_ASSOCIATE: return "WPI_CMD_ASSOCIATE"; 3881173362Sbenjsc case WPI_CMD_SET_WME: return "WPI_CMD_SET_WME"; 3882173362Sbenjsc case WPI_CMD_TSF: return "WPI_CMD_TSF"; 3883173362Sbenjsc case WPI_CMD_ADD_NODE: return "WPI_CMD_ADD_NODE"; 3884173362Sbenjsc case WPI_CMD_TX_DATA: return "WPI_CMD_TX_DATA"; 3885173362Sbenjsc case WPI_CMD_MRR_SETUP: return "WPI_CMD_MRR_SETUP"; 3886173362Sbenjsc case WPI_CMD_SET_LED: return "WPI_CMD_SET_LED"; 3887173362Sbenjsc case WPI_CMD_SET_POWER_MODE: return "WPI_CMD_SET_POWER_MODE"; 3888173362Sbenjsc case WPI_CMD_SCAN: return "WPI_CMD_SCAN"; 3889173362Sbenjsc case WPI_CMD_SET_BEACON:return "WPI_CMD_SET_BEACON"; 3890173362Sbenjsc case WPI_CMD_TXPOWER: return "WPI_CMD_TXPOWER"; 3891173362Sbenjsc case WPI_CMD_BLUETOOTH: return "WPI_CMD_BLUETOOTH"; 3892173362Sbenjsc 3893173362Sbenjsc default: 3894173362Sbenjsc KASSERT(1, ("Unknown Command: %d\n", cmd)); 3895173362Sbenjsc return "UNKNOWN CMD"; // Make the compiler happy 3896173362Sbenjsc } 3897173362Sbenjsc} 3898173362Sbenjsc#endif 3899173362Sbenjsc 3900173362SbenjscMODULE_DEPEND(wpi, pci, 1, 1, 1); 3901173362SbenjscMODULE_DEPEND(wpi, wlan, 1, 1, 1); 3902173362SbenjscMODULE_DEPEND(wpi, firmware, 1, 1, 1); 3903173362SbenjscMODULE_DEPEND(wpi, wlan_amrr, 1, 1, 1); 3904