if_wpi.c revision 280057
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#include <sys/cdefs.h> 20173362Sbenjsc__FBSDID("$FreeBSD: head/sys/dev/wpi/if_wpi.c 280057 2015-03-15 20:18:09Z adrian $"); 21173362Sbenjsc 22173362Sbenjsc/* 23173362Sbenjsc * Driver for Intel PRO/Wireless 3945ABG 802.11 network adapters. 24173362Sbenjsc * 25173362Sbenjsc * The 3945ABG network adapter doesn't use traditional hardware as 26173362Sbenjsc * many other adaptors do. Instead at run time the eeprom is set into a known 27173362Sbenjsc * state and told to load boot firmware. The boot firmware loads an init and a 28173362Sbenjsc * main binary firmware image into SRAM on the card via DMA. 29173362Sbenjsc * Once the firmware is loaded, the driver/hw then 30218909Sbrucec * communicate by way of circular dma rings via the SRAM to the firmware. 31173362Sbenjsc * 32173362Sbenjsc * There is 6 memory rings. 1 command ring, 1 rx data ring & 4 tx data rings. 33173362Sbenjsc * The 4 tx data rings allow for prioritization QoS. 34173362Sbenjsc * 35173362Sbenjsc * The rx data ring consists of 32 dma buffers. Two registers are used to 36173362Sbenjsc * indicate where in the ring the driver and the firmware are up to. The 37173362Sbenjsc * driver sets the initial read index (reg1) and the initial write index (reg2), 38173362Sbenjsc * the firmware updates the read index (reg1) on rx of a packet and fires an 39173362Sbenjsc * interrupt. The driver then processes the buffers starting at reg1 indicating 40173362Sbenjsc * to the firmware which buffers have been accessed by updating reg2. At the 41173362Sbenjsc * same time allocating new memory for the processed buffer. 42173362Sbenjsc * 43173362Sbenjsc * A similar thing happens with the tx rings. The difference is the firmware 44173362Sbenjsc * stop processing buffers once the queue is full and until confirmation 45278764Sadrian * of a successful transmition (tx_done) has occurred. 46173362Sbenjsc * 47173362Sbenjsc * The command ring operates in the same manner as the tx queues. 48173362Sbenjsc * 49173362Sbenjsc * All communication direct to the card (ie eeprom) is classed as Stage1 50173362Sbenjsc * communication 51173362Sbenjsc * 52173362Sbenjsc * All communication via the firmware to the card is classed as State2. 53173362Sbenjsc * The firmware consists of 2 parts. A bootstrap firmware and a runtime 54173362Sbenjsc * firmware. The bootstrap firmware and runtime firmware are loaded 55173362Sbenjsc * from host memory via dma to the card then told to execute. From this point 56173362Sbenjsc * on the majority of communications between the driver and the card goes 57173362Sbenjsc * via the firmware. 58173362Sbenjsc */ 59173362Sbenjsc 60236381Sadrian#include "opt_wlan.h" 61278366Sadrian#include "opt_wpi.h" 62236381Sadrian 63173362Sbenjsc#include <sys/param.h> 64173362Sbenjsc#include <sys/sysctl.h> 65173362Sbenjsc#include <sys/sockio.h> 66173362Sbenjsc#include <sys/mbuf.h> 67173362Sbenjsc#include <sys/kernel.h> 68173362Sbenjsc#include <sys/socket.h> 69173362Sbenjsc#include <sys/systm.h> 70173362Sbenjsc#include <sys/malloc.h> 71173362Sbenjsc#include <sys/queue.h> 72173362Sbenjsc#include <sys/taskqueue.h> 73173362Sbenjsc#include <sys/module.h> 74173362Sbenjsc#include <sys/bus.h> 75173362Sbenjsc#include <sys/endian.h> 76173362Sbenjsc#include <sys/linker.h> 77173362Sbenjsc#include <sys/firmware.h> 78173362Sbenjsc 79173362Sbenjsc#include <machine/bus.h> 80173362Sbenjsc#include <machine/resource.h> 81173362Sbenjsc#include <sys/rman.h> 82173362Sbenjsc 83173362Sbenjsc#include <dev/pci/pcireg.h> 84173362Sbenjsc#include <dev/pci/pcivar.h> 85173362Sbenjsc 86173362Sbenjsc#include <net/bpf.h> 87173362Sbenjsc#include <net/if.h> 88257176Sglebius#include <net/if_var.h> 89173362Sbenjsc#include <net/if_arp.h> 90173362Sbenjsc#include <net/ethernet.h> 91173362Sbenjsc#include <net/if_dl.h> 92173362Sbenjsc#include <net/if_media.h> 93173362Sbenjsc#include <net/if_types.h> 94173362Sbenjsc 95278366Sadrian#include <netinet/in.h> 96278366Sadrian#include <netinet/in_systm.h> 97278366Sadrian#include <netinet/in_var.h> 98278366Sadrian#include <netinet/if_ether.h> 99278366Sadrian#include <netinet/ip.h> 100278366Sadrian 101173362Sbenjsc#include <net80211/ieee80211_var.h> 102173362Sbenjsc#include <net80211/ieee80211_radiotap.h> 103173362Sbenjsc#include <net80211/ieee80211_regdomain.h> 104206358Srpaulo#include <net80211/ieee80211_ratectl.h> 105173362Sbenjsc 106173362Sbenjsc#include <dev/wpi/if_wpireg.h> 107173362Sbenjsc#include <dev/wpi/if_wpivar.h> 108278366Sadrian#include <dev/wpi/if_wpi_debug.h> 109173362Sbenjsc 110173362Sbenjscstruct wpi_ident { 111173362Sbenjsc uint16_t vendor; 112173362Sbenjsc uint16_t device; 113173362Sbenjsc uint16_t subdevice; 114173362Sbenjsc const char *name; 115173362Sbenjsc}; 116173362Sbenjsc 117173362Sbenjscstatic const struct wpi_ident wpi_ident_table[] = { 118173362Sbenjsc /* The below entries support ABG regardless of the subid */ 119173362Sbenjsc { 0x8086, 0x4222, 0x0, "Intel(R) PRO/Wireless 3945ABG" }, 120173362Sbenjsc { 0x8086, 0x4227, 0x0, "Intel(R) PRO/Wireless 3945ABG" }, 121173362Sbenjsc /* The below entries only support BG */ 122182127Sbenjsc { 0x8086, 0x4222, 0x1005, "Intel(R) PRO/Wireless 3945BG" }, 123182127Sbenjsc { 0x8086, 0x4222, 0x1034, "Intel(R) PRO/Wireless 3945BG" }, 124182127Sbenjsc { 0x8086, 0x4227, 0x1014, "Intel(R) PRO/Wireless 3945BG" }, 125182127Sbenjsc { 0x8086, 0x4222, 0x1044, "Intel(R) PRO/Wireless 3945BG" }, 126173362Sbenjsc { 0, 0, 0, NULL } 127173362Sbenjsc}; 128173362Sbenjsc 129278366Sadrianstatic int wpi_probe(device_t); 130278366Sadrianstatic int wpi_attach(device_t); 131278366Sadrianstatic void wpi_radiotap_attach(struct wpi_softc *); 132278366Sadrianstatic void wpi_sysctlattach(struct wpi_softc *); 133178354Ssamstatic struct ieee80211vap *wpi_vap_create(struct ieee80211com *, 134228621Sbschmidt const char [IFNAMSIZ], int, enum ieee80211_opmode, int, 135228621Sbschmidt const uint8_t [IEEE80211_ADDR_LEN], 136228621Sbschmidt const uint8_t [IEEE80211_ADDR_LEN]); 137178354Ssamstatic void wpi_vap_delete(struct ieee80211vap *); 138278366Sadrianstatic int wpi_detach(device_t); 139278366Sadrianstatic int wpi_shutdown(device_t); 140278366Sadrianstatic int wpi_suspend(device_t); 141278366Sadrianstatic int wpi_resume(device_t); 142278366Sadrianstatic int wpi_nic_lock(struct wpi_softc *); 143278366Sadrianstatic int wpi_read_prom_data(struct wpi_softc *, uint32_t, void *, int); 144278366Sadrianstatic void wpi_dma_map_addr(void *, bus_dma_segment_t *, int, int); 145173362Sbenjscstatic int wpi_dma_contig_alloc(struct wpi_softc *, struct wpi_dma_info *, 146278366Sadrian void **, bus_size_t, bus_size_t); 147173362Sbenjscstatic void wpi_dma_contig_free(struct wpi_dma_info *); 148173362Sbenjscstatic int wpi_alloc_shared(struct wpi_softc *); 149173362Sbenjscstatic void wpi_free_shared(struct wpi_softc *); 150278366Sadrianstatic int wpi_alloc_fwmem(struct wpi_softc *); 151278366Sadrianstatic void wpi_free_fwmem(struct wpi_softc *); 152278366Sadrianstatic int wpi_alloc_rx_ring(struct wpi_softc *); 153278366Sadrianstatic void wpi_update_rx_ring(struct wpi_softc *); 154278366Sadrianstatic void wpi_reset_rx_ring(struct wpi_softc *); 155278366Sadrianstatic void wpi_free_rx_ring(struct wpi_softc *); 156173362Sbenjscstatic int wpi_alloc_tx_ring(struct wpi_softc *, struct wpi_tx_ring *, 157278366Sadrian int); 158278366Sadrianstatic void wpi_update_tx_ring(struct wpi_softc *, struct wpi_tx_ring *); 159173362Sbenjscstatic void wpi_reset_tx_ring(struct wpi_softc *, struct wpi_tx_ring *); 160173362Sbenjscstatic void wpi_free_tx_ring(struct wpi_softc *, struct wpi_tx_ring *); 161278366Sadrianstatic int wpi_read_eeprom(struct wpi_softc *, 162278366Sadrian uint8_t macaddr[IEEE80211_ADDR_LEN]); 163278366Sadrianstatic uint32_t wpi_eeprom_channel_flags(struct wpi_eeprom_chan *); 164278366Sadrianstatic void wpi_read_eeprom_band(struct wpi_softc *, int); 165278366Sadrianstatic int wpi_read_eeprom_channels(struct wpi_softc *, int); 166278366Sadrianstatic struct wpi_eeprom_chan *wpi_find_eeprom_channel(struct wpi_softc *, 167278366Sadrian struct ieee80211_channel *); 168278366Sadrianstatic int wpi_setregdomain(struct ieee80211com *, 169278366Sadrian struct ieee80211_regdomain *, int, 170278366Sadrian struct ieee80211_channel[]); 171278366Sadrianstatic int wpi_read_eeprom_group(struct wpi_softc *, int); 172278366Sadrianstatic void wpi_node_free(struct ieee80211_node *); 173278366Sadrianstatic struct ieee80211_node *wpi_node_alloc(struct ieee80211vap *, 174278366Sadrian const uint8_t mac[IEEE80211_ADDR_LEN]); 175178354Ssamstatic int wpi_newstate(struct ieee80211vap *, enum ieee80211_state, int); 176278366Sadrianstatic void wpi_calib_timeout(void *); 177278366Sadrianstatic void wpi_rx_done(struct wpi_softc *, struct wpi_rx_desc *, 178173362Sbenjsc struct wpi_rx_data *); 179278366Sadrianstatic void wpi_rx_statistics(struct wpi_softc *, struct wpi_rx_desc *, 180278366Sadrian struct wpi_rx_data *); 181278366Sadrianstatic void wpi_tx_done(struct wpi_softc *, struct wpi_rx_desc *); 182278366Sadrianstatic void wpi_cmd_done(struct wpi_softc *, struct wpi_rx_desc *); 183173362Sbenjscstatic void wpi_notif_intr(struct wpi_softc *); 184278366Sadrianstatic void wpi_wakeup_intr(struct wpi_softc *); 185278366Sadrianstatic void wpi_fatal_intr(struct wpi_softc *); 186173362Sbenjscstatic void wpi_intr(void *); 187278366Sadrianstatic int wpi_cmd2(struct wpi_softc *, struct wpi_buf *); 188173362Sbenjscstatic int wpi_tx_data(struct wpi_softc *, struct mbuf *, 189278366Sadrian struct ieee80211_node *); 190278366Sadrianstatic int wpi_tx_data_raw(struct wpi_softc *, struct mbuf *, 191278366Sadrian struct ieee80211_node *, 192278366Sadrian const struct ieee80211_bpf_params *); 193278366Sadrianstatic int wpi_raw_xmit(struct ieee80211_node *, struct mbuf *, 194278366Sadrian const struct ieee80211_bpf_params *); 195173362Sbenjscstatic void wpi_start(struct ifnet *); 196178354Ssamstatic void wpi_start_locked(struct ifnet *); 197278366Sadrianstatic void wpi_watchdog_rfkill(void *); 198278366Sadrianstatic void wpi_watchdog(void *); 199173362Sbenjscstatic int wpi_ioctl(struct ifnet *, u_long, caddr_t); 200278366Sadrianstatic int wpi_cmd(struct wpi_softc *, int, const void *, size_t, int); 201173362Sbenjscstatic int wpi_mrr_setup(struct wpi_softc *); 202278366Sadrianstatic int wpi_add_node(struct wpi_softc *, struct ieee80211_node *); 203278366Sadrianstatic int wpi_add_broadcast_node(struct wpi_softc *, int); 204278366Sadrianstatic int wpi_add_ibss_node(struct wpi_softc *, struct ieee80211_node *); 205278366Sadrianstatic void wpi_del_node(struct wpi_softc *, struct ieee80211_node *); 206278366Sadrianstatic int wpi_updateedca(struct ieee80211com *); 207278366Sadrianstatic void wpi_set_promisc(struct wpi_softc *); 208278366Sadrianstatic void wpi_update_promisc(struct ifnet *); 209278366Sadrianstatic void wpi_update_mcast(struct ifnet *); 210173362Sbenjscstatic void wpi_set_led(struct wpi_softc *, uint8_t, uint8_t, uint8_t); 211278366Sadrianstatic int wpi_set_timing(struct wpi_softc *, struct ieee80211_node *); 212278366Sadrianstatic void wpi_power_calibration(struct wpi_softc *); 213278366Sadrianstatic int wpi_set_txpower(struct wpi_softc *, int); 214278366Sadrianstatic int wpi_get_power_index(struct wpi_softc *, 215278366Sadrian struct wpi_power_group *, struct ieee80211_channel *, int); 216278366Sadrianstatic int wpi_set_pslevel(struct wpi_softc *, uint8_t, int, int); 217278366Sadrianstatic int wpi_send_btcoex(struct wpi_softc *); 218278366Sadrianstatic int wpi_send_rxon(struct wpi_softc *, int, int); 219278366Sadrianstatic int wpi_config(struct wpi_softc *); 220278366Sadrianstatic uint16_t wpi_get_active_dwell_time(struct wpi_softc *, 221278366Sadrian struct ieee80211_channel *, uint8_t); 222278366Sadrianstatic uint16_t wpi_limit_dwell(struct wpi_softc *, uint16_t); 223278366Sadrianstatic uint16_t wpi_get_passive_dwell_time(struct wpi_softc *, 224278366Sadrian struct ieee80211_channel *); 225278366Sadrianstatic int wpi_scan(struct wpi_softc *, struct ieee80211_channel *); 226278366Sadrianstatic int wpi_auth(struct wpi_softc *, struct ieee80211vap *); 227278366Sadrianstatic void wpi_update_beacon(struct ieee80211vap *, int); 228173362Sbenjscstatic int wpi_setup_beacon(struct wpi_softc *, struct ieee80211_node *); 229178354Ssamstatic int wpi_run(struct wpi_softc *, struct ieee80211vap *); 230278366Sadrianstatic int wpi_key_alloc(struct ieee80211vap *, struct ieee80211_key *, 231278366Sadrian ieee80211_keyix *, ieee80211_keyix *); 232278366Sadrianstatic int wpi_key_set(struct ieee80211vap *, 233278366Sadrian const struct ieee80211_key *, 234278366Sadrian const uint8_t mac[IEEE80211_ADDR_LEN]); 235278366Sadrianstatic int wpi_key_delete(struct ieee80211vap *, 236278366Sadrian const struct ieee80211_key *); 237278366Sadrianstatic int wpi_post_alive(struct wpi_softc *); 238278366Sadrianstatic int wpi_load_bootcode(struct wpi_softc *, const uint8_t *, int); 239278366Sadrianstatic int wpi_load_firmware(struct wpi_softc *); 240278366Sadrianstatic int wpi_read_firmware(struct wpi_softc *); 241278366Sadrianstatic void wpi_unload_firmware(struct wpi_softc *); 242278366Sadrianstatic int wpi_clock_wait(struct wpi_softc *); 243278366Sadrianstatic int wpi_apm_init(struct wpi_softc *); 244278366Sadrianstatic void wpi_apm_stop_master(struct wpi_softc *); 245278366Sadrianstatic void wpi_apm_stop(struct wpi_softc *); 246278366Sadrianstatic void wpi_nic_config(struct wpi_softc *); 247278366Sadrianstatic int wpi_hw_init(struct wpi_softc *); 248278366Sadrianstatic void wpi_hw_stop(struct wpi_softc *); 249278366Sadrianstatic void wpi_radio_on(void *, int); 250278366Sadrianstatic void wpi_radio_off(void *, int); 251278366Sadrianstatic void wpi_init_locked(struct wpi_softc *); 252173362Sbenjscstatic void wpi_init(void *); 253278366Sadrianstatic void wpi_stop_locked(struct wpi_softc *); 254173362Sbenjscstatic void wpi_stop(struct wpi_softc *); 255278366Sadrianstatic void wpi_scan_start(struct ieee80211com *); 256278366Sadrianstatic void wpi_scan_end(struct ieee80211com *); 257278366Sadrianstatic void wpi_set_channel(struct ieee80211com *); 258278366Sadrianstatic void wpi_scan_curchan(struct ieee80211_scan_state *, unsigned long); 259278366Sadrianstatic void wpi_scan_mindwell(struct ieee80211_scan_state *); 260278366Sadrianstatic void wpi_hw_reset(void *, int); 261173362Sbenjsc 262173362Sbenjscstatic device_method_t wpi_methods[] = { 263173362Sbenjsc /* Device interface */ 264173362Sbenjsc DEVMETHOD(device_probe, wpi_probe), 265173362Sbenjsc DEVMETHOD(device_attach, wpi_attach), 266173362Sbenjsc DEVMETHOD(device_detach, wpi_detach), 267173362Sbenjsc DEVMETHOD(device_shutdown, wpi_shutdown), 268173362Sbenjsc DEVMETHOD(device_suspend, wpi_suspend), 269173362Sbenjsc DEVMETHOD(device_resume, wpi_resume), 270173362Sbenjsc 271260064Smarius DEVMETHOD_END 272173362Sbenjsc}; 273173362Sbenjsc 274173362Sbenjscstatic driver_t wpi_driver = { 275173362Sbenjsc "wpi", 276173362Sbenjsc wpi_methods, 277173362Sbenjsc sizeof (struct wpi_softc) 278173362Sbenjsc}; 279173362Sbenjscstatic devclass_t wpi_devclass; 280173362Sbenjsc 281260064SmariusDRIVER_MODULE(wpi, pci, wpi_driver, wpi_devclass, NULL, NULL); 282173362Sbenjsc 283222543SbschmidtMODULE_VERSION(wpi, 1); 284222543Sbschmidt 285278366SadrianMODULE_DEPEND(wpi, pci, 1, 1, 1); 286278366SadrianMODULE_DEPEND(wpi, wlan, 1, 1, 1); 287278366SadrianMODULE_DEPEND(wpi, firmware, 1, 1, 1); 288260064Smarius 289173362Sbenjscstatic int 290173362Sbenjscwpi_probe(device_t dev) 291173362Sbenjsc{ 292173362Sbenjsc const struct wpi_ident *ident; 293173362Sbenjsc 294173362Sbenjsc for (ident = wpi_ident_table; ident->name != NULL; ident++) { 295173362Sbenjsc if (pci_get_vendor(dev) == ident->vendor && 296173362Sbenjsc pci_get_device(dev) == ident->device) { 297173362Sbenjsc device_set_desc(dev, ident->name); 298260064Smarius return (BUS_PROBE_DEFAULT); 299173362Sbenjsc } 300173362Sbenjsc } 301173362Sbenjsc return ENXIO; 302173362Sbenjsc} 303173362Sbenjsc 304173362Sbenjscstatic int 305173362Sbenjscwpi_attach(device_t dev) 306173362Sbenjsc{ 307278366Sadrian struct wpi_softc *sc = (struct wpi_softc *)device_get_softc(dev); 308278366Sadrian struct ieee80211com *ic; 309173362Sbenjsc struct ifnet *ifp; 310278366Sadrian int i, error, rid, supportsa = 1; 311173362Sbenjsc const struct wpi_ident *ident; 312190526Ssam uint8_t macaddr[IEEE80211_ADDR_LEN]; 313173362Sbenjsc 314173362Sbenjsc sc->sc_dev = dev; 315173362Sbenjsc 316278366Sadrian#ifdef WPI_DEBUG 317278366Sadrian error = resource_int_value(device_get_name(sc->sc_dev), 318278366Sadrian device_get_unit(sc->sc_dev), "debug", &(sc->sc_debug)); 319278366Sadrian if (error != 0) 320278366Sadrian sc->sc_debug = 0; 321278366Sadrian#else 322278366Sadrian sc->sc_debug = 0; 323278366Sadrian#endif 324173362Sbenjsc 325278366Sadrian DPRINTF(sc, WPI_DEBUG_TRACE, TRACE_STR_BEGIN, __func__); 326278366Sadrian 327173362Sbenjsc /* 328278366Sadrian * Get the offset of the PCI Express Capability Structure in PCI 329278366Sadrian * Configuration Space. 330278366Sadrian */ 331278366Sadrian error = pci_find_cap(dev, PCIY_EXPRESS, &sc->sc_cap_off); 332278366Sadrian if (error != 0) { 333278366Sadrian device_printf(dev, "PCIe capability structure not found!\n"); 334278366Sadrian return error; 335278366Sadrian } 336278366Sadrian 337278366Sadrian /* 338173362Sbenjsc * Some card's only support 802.11b/g not a, check to see if 339173362Sbenjsc * this is one such card. A 0x0 in the subdevice table indicates 340173362Sbenjsc * the entire subdevice range is to be ignored. 341173362Sbenjsc */ 342173362Sbenjsc for (ident = wpi_ident_table; ident->name != NULL; ident++) { 343173362Sbenjsc if (ident->subdevice && 344173362Sbenjsc pci_get_subdevice(dev) == ident->subdevice) { 345173362Sbenjsc supportsa = 0; 346173362Sbenjsc break; 347173362Sbenjsc } 348173362Sbenjsc } 349173362Sbenjsc 350278366Sadrian /* Clear device-specific "PCI retry timeout" register (41h). */ 351173362Sbenjsc pci_write_config(dev, 0x41, 0, 1); 352173362Sbenjsc 353278366Sadrian /* Enable bus-mastering. */ 354173362Sbenjsc pci_enable_busmaster(dev); 355173362Sbenjsc 356260064Smarius rid = PCIR_BAR(0); 357260064Smarius sc->mem = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &rid, 358173362Sbenjsc RF_ACTIVE); 359173362Sbenjsc if (sc->mem == NULL) { 360278366Sadrian device_printf(dev, "can't map mem space\n"); 361173362Sbenjsc error = ENOMEM; 362278366Sadrian return error; 363173362Sbenjsc } 364173362Sbenjsc sc->sc_st = rman_get_bustag(sc->mem); 365173362Sbenjsc sc->sc_sh = rman_get_bushandle(sc->mem); 366173362Sbenjsc 367278366Sadrian i = 1; 368260064Smarius rid = 0; 369278366Sadrian if (pci_alloc_msi(dev, &i) == 0) 370278366Sadrian rid = 1; 371278366Sadrian /* Install interrupt handler. */ 372278366Sadrian sc->irq = bus_alloc_resource_any(dev, SYS_RES_IRQ, &rid, RF_ACTIVE | 373278366Sadrian (rid != 0 ? 0 : RF_SHAREABLE)); 374173362Sbenjsc if (sc->irq == NULL) { 375278366Sadrian device_printf(dev, "can't map interrupt\n"); 376173362Sbenjsc error = ENOMEM; 377173362Sbenjsc goto fail; 378173362Sbenjsc } 379173362Sbenjsc 380278366Sadrian WPI_LOCK_INIT(sc); 381278366Sadrian 382278366Sadrian sc->sc_unr = new_unrhdr(WPI_ID_IBSS_MIN, WPI_ID_IBSS_MAX, &sc->sc_mtx); 383278366Sadrian 384278366Sadrian /* Allocate DMA memory for firmware transfers. */ 385173362Sbenjsc if ((error = wpi_alloc_fwmem(sc)) != 0) { 386278366Sadrian device_printf(dev, 387278366Sadrian "could not allocate memory for firmware, error %d\n", 388278366Sadrian error); 389173362Sbenjsc goto fail; 390173362Sbenjsc } 391173362Sbenjsc 392278366Sadrian /* Allocate shared page. */ 393173362Sbenjsc if ((error = wpi_alloc_shared(sc)) != 0) { 394173362Sbenjsc device_printf(dev, "could not allocate shared page\n"); 395173362Sbenjsc goto fail; 396173362Sbenjsc } 397173362Sbenjsc 398278366Sadrian /* Allocate TX rings - 4 for QoS purposes, 1 for commands. */ 399278366Sadrian for (i = 0; i < WPI_NTXQUEUES; i++) { 400278366Sadrian if ((error = wpi_alloc_tx_ring(sc, &sc->txq[i], i)) != 0) { 401278366Sadrian device_printf(dev, 402278366Sadrian "could not allocate TX ring %d, error %d\n", i, 403278366Sadrian error); 404278366Sadrian goto fail; 405173362Sbenjsc } 406173362Sbenjsc } 407173362Sbenjsc 408278366Sadrian /* Allocate RX ring. */ 409278366Sadrian if ((error = wpi_alloc_rx_ring(sc)) != 0) { 410278366Sadrian device_printf(dev, "could not allocate RX ring, error %d\n", 411278366Sadrian error); 412173362Sbenjsc goto fail; 413173362Sbenjsc } 414173362Sbenjsc 415278366Sadrian /* Clear pending interrupts. */ 416278366Sadrian WPI_WRITE(sc, WPI_INT, 0xffffffff); 417173362Sbenjsc 418178354Ssam ifp = sc->sc_ifp = if_alloc(IFT_IEEE80211); 419173362Sbenjsc if (ifp == NULL) { 420278366Sadrian device_printf(dev, "can not allocate ifnet structure\n"); 421173362Sbenjsc goto fail; 422173362Sbenjsc } 423278366Sadrian 424178354Ssam ic = ifp->if_l2com; 425173362Sbenjsc ic->ic_ifp = ifp; 426178354Ssam ic->ic_phytype = IEEE80211_T_OFDM; /* not only, but not used */ 427178354Ssam ic->ic_opmode = IEEE80211_M_STA; /* default to BSS mode */ 428173362Sbenjsc 429278366Sadrian /* Set device capabilities. */ 430173362Sbenjsc ic->ic_caps = 431178957Ssam IEEE80211_C_STA /* station mode supported */ 432278366Sadrian | IEEE80211_C_IBSS /* IBSS mode supported */ 433178957Ssam | IEEE80211_C_MONITOR /* monitor mode supported */ 434278366Sadrian | IEEE80211_C_AHDEMO /* adhoc demo mode */ 435278366Sadrian | IEEE80211_C_BGSCAN /* capable of bg scanning */ 436173362Sbenjsc | IEEE80211_C_TXPMGT /* tx power management */ 437173362Sbenjsc | IEEE80211_C_SHSLOT /* short slot time supported */ 438278366Sadrian | IEEE80211_C_WPA /* 802.11i */ 439173362Sbenjsc | IEEE80211_C_SHPREAMBLE /* short preamble supported */ 440173362Sbenjsc#if 0 441173362Sbenjsc | IEEE80211_C_HOSTAP /* Host access point mode */ 442173362Sbenjsc#endif 443278366Sadrian | IEEE80211_C_WME /* 802.11e */ 444278366Sadrian | IEEE80211_C_PMGT /* Station-side power mgmt */ 445173362Sbenjsc ; 446173362Sbenjsc 447278366Sadrian ic->ic_cryptocaps = 448278366Sadrian IEEE80211_CRYPTO_AES_CCM; 449278366Sadrian 450173362Sbenjsc /* 451173362Sbenjsc * Read in the eeprom and also setup the channels for 452173362Sbenjsc * net80211. We don't set the rates as net80211 does this for us 453173362Sbenjsc */ 454278366Sadrian if ((error = wpi_read_eeprom(sc, macaddr)) != 0) { 455278366Sadrian device_printf(dev, "could not read EEPROM, error %d\n", 456278366Sadrian error); 457278366Sadrian goto fail; 458278366Sadrian } 459173362Sbenjsc 460278366Sadrian#ifdef WPI_DEBUG 461278366Sadrian if (bootverbose) { 462173362Sbenjsc device_printf(sc->sc_dev, "Regulatory Domain: %.4s\n", sc->domain); 463173362Sbenjsc device_printf(sc->sc_dev, "Hardware Type: %c\n", 464173362Sbenjsc sc->type > 1 ? 'B': '?'); 465173362Sbenjsc device_printf(sc->sc_dev, "Hardware Revision: %c\n", 466173362Sbenjsc ((le16toh(sc->rev) & 0xf0) == 0xd0) ? 'D': '?'); 467173362Sbenjsc device_printf(sc->sc_dev, "SKU %s support 802.11a\n", 468173362Sbenjsc supportsa ? "does" : "does not"); 469173362Sbenjsc 470173362Sbenjsc /* XXX hw_config uses the PCIDEV for the Hardware rev. Must check 471173362Sbenjsc what sc->rev really represents - benjsc 20070615 */ 472173362Sbenjsc } 473278366Sadrian#endif 474173362Sbenjsc 475173362Sbenjsc if_initname(ifp, device_get_name(dev), device_get_unit(dev)); 476173362Sbenjsc ifp->if_softc = sc; 477173362Sbenjsc ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST; 478173362Sbenjsc ifp->if_init = wpi_init; 479173362Sbenjsc ifp->if_ioctl = wpi_ioctl; 480173362Sbenjsc ifp->if_start = wpi_start; 481207554Ssobomax IFQ_SET_MAXLEN(&ifp->if_snd, ifqmaxlen); 482207554Ssobomax ifp->if_snd.ifq_drv_maxlen = ifqmaxlen; 483173362Sbenjsc IFQ_SET_READY(&ifp->if_snd); 484178354Ssam 485190526Ssam ieee80211_ifattach(ic, macaddr); 486278366Sadrian ic->ic_vap_create = wpi_vap_create; 487278366Sadrian ic->ic_vap_delete = wpi_vap_delete; 488178354Ssam ic->ic_raw_xmit = wpi_raw_xmit; 489278366Sadrian ic->ic_node_alloc = wpi_node_alloc; 490278366Sadrian sc->sc_node_free = ic->ic_node_free; 491278366Sadrian ic->ic_node_free = wpi_node_free; 492278366Sadrian ic->ic_wme.wme_update = wpi_updateedca; 493278366Sadrian ic->ic_update_promisc = wpi_update_promisc; 494278366Sadrian ic->ic_update_mcast = wpi_update_mcast; 495173362Sbenjsc ic->ic_scan_start = wpi_scan_start; 496173362Sbenjsc ic->ic_scan_end = wpi_scan_end; 497173362Sbenjsc ic->ic_set_channel = wpi_set_channel; 498278366Sadrian sc->sc_scan_curchan = ic->ic_scan_curchan; 499173362Sbenjsc ic->ic_scan_curchan = wpi_scan_curchan; 500173362Sbenjsc ic->ic_scan_mindwell = wpi_scan_mindwell; 501278366Sadrian ic->ic_setregdomain = wpi_setregdomain; 502173362Sbenjsc 503278366Sadrian wpi_radiotap_attach(sc); 504173362Sbenjsc 505278366Sadrian callout_init_mtx(&sc->calib_to, &sc->sc_mtx, 0); 506278366Sadrian callout_init_mtx(&sc->watchdog_to, &sc->sc_mtx, 0); 507278366Sadrian callout_init_mtx(&sc->watchdog_rfkill, &sc->sc_mtx, 0); 508278366Sadrian TASK_INIT(&sc->sc_reinittask, 0, wpi_hw_reset, sc); 509278366Sadrian TASK_INIT(&sc->sc_radiooff_task, 0, wpi_radio_off, sc); 510278366Sadrian TASK_INIT(&sc->sc_radioon_task, 0, wpi_radio_on, sc); 511173362Sbenjsc 512278366Sadrian wpi_sysctlattach(sc); 513278366Sadrian 514173362Sbenjsc /* 515173362Sbenjsc * Hook our interrupt after all initialization is complete. 516173362Sbenjsc */ 517278366Sadrian error = bus_setup_intr(dev, sc->irq, INTR_TYPE_NET | INTR_MPSAFE, 518177043Sthompsa NULL, wpi_intr, sc, &sc->sc_ih); 519173362Sbenjsc if (error != 0) { 520278366Sadrian device_printf(dev, "can't establish interrupt, error %d\n", 521278366Sadrian error); 522173362Sbenjsc goto fail; 523173362Sbenjsc } 524173362Sbenjsc 525177043Sthompsa if (bootverbose) 526177043Sthompsa ieee80211_announce(ic); 527278366Sadrian 528278366Sadrian#ifdef WPI_DEBUG 529278366Sadrian if (sc->sc_debug & WPI_DEBUG_HW) 530278366Sadrian ieee80211_announce_channels(ic); 531173362Sbenjsc#endif 532278366Sadrian 533278366Sadrian DPRINTF(sc, WPI_DEBUG_TRACE, TRACE_STR_END, __func__); 534173362Sbenjsc return 0; 535173362Sbenjsc 536173362Sbenjscfail: wpi_detach(dev); 537278366Sadrian DPRINTF(sc, WPI_DEBUG_TRACE, TRACE_STR_END_ERR, __func__); 538278366Sadrian return error; 539173362Sbenjsc} 540173362Sbenjsc 541278366Sadrian/* 542278366Sadrian * Attach the interface to 802.11 radiotap. 543278366Sadrian */ 544278366Sadrianstatic void 545278366Sadrianwpi_radiotap_attach(struct wpi_softc *sc) 546278366Sadrian{ 547278366Sadrian struct ifnet *ifp = sc->sc_ifp; 548278366Sadrian struct ieee80211com *ic = ifp->if_l2com; 549278366Sadrian DPRINTF(sc, WPI_DEBUG_TRACE, TRACE_STR_BEGIN, __func__); 550278366Sadrian ieee80211_radiotap_attach(ic, 551278366Sadrian &sc->sc_txtap.wt_ihdr, sizeof(sc->sc_txtap), 552278366Sadrian WPI_TX_RADIOTAP_PRESENT, 553278366Sadrian &sc->sc_rxtap.wr_ihdr, sizeof(sc->sc_rxtap), 554278366Sadrian WPI_RX_RADIOTAP_PRESENT); 555278366Sadrian DPRINTF(sc, WPI_DEBUG_TRACE, TRACE_STR_END, __func__); 556278366Sadrian} 557278366Sadrian 558278366Sadrianstatic void 559278366Sadrianwpi_sysctlattach(struct wpi_softc *sc) 560278366Sadrian{ 561278366Sadrian#ifdef WPI_DEBUG 562278366Sadrian struct sysctl_ctx_list *ctx = device_get_sysctl_ctx(sc->sc_dev); 563278366Sadrian struct sysctl_oid *tree = device_get_sysctl_tree(sc->sc_dev); 564278366Sadrian 565278366Sadrian SYSCTL_ADD_INT(ctx, SYSCTL_CHILDREN(tree), OID_AUTO, 566278366Sadrian "debug", CTLFLAG_RW, &sc->sc_debug, sc->sc_debug, 567278366Sadrian "control debugging printfs"); 568278366Sadrian#endif 569278366Sadrian} 570278366Sadrian 571278366Sadrianstatic struct ieee80211vap * 572278366Sadrianwpi_vap_create(struct ieee80211com *ic, const char name[IFNAMSIZ], int unit, 573278366Sadrian enum ieee80211_opmode opmode, int flags, 574278366Sadrian const uint8_t bssid[IEEE80211_ADDR_LEN], 575278366Sadrian const uint8_t mac[IEEE80211_ADDR_LEN]) 576278366Sadrian{ 577278366Sadrian struct wpi_vap *wvp; 578278366Sadrian struct wpi_buf *bcn; 579278366Sadrian struct ieee80211vap *vap; 580278366Sadrian 581278366Sadrian if (!TAILQ_EMPTY(&ic->ic_vaps)) /* only one at a time */ 582278366Sadrian return NULL; 583278366Sadrian 584278366Sadrian wvp = (struct wpi_vap *) malloc(sizeof(struct wpi_vap), 585278366Sadrian M_80211_VAP, M_NOWAIT | M_ZERO); 586278366Sadrian if (wvp == NULL) 587278366Sadrian return NULL; 588278366Sadrian vap = &wvp->vap; 589278366Sadrian ieee80211_vap_setup(ic, vap, name, unit, opmode, flags, bssid, mac); 590278366Sadrian 591278366Sadrian bcn = &wvp->wv_bcbuf; 592278366Sadrian bcn->data = NULL; 593278366Sadrian 594278366Sadrian /* Override with driver methods. */ 595278366Sadrian wvp->newstate = vap->iv_newstate; 596278366Sadrian vap->iv_key_alloc = wpi_key_alloc; 597278366Sadrian vap->iv_key_set = wpi_key_set; 598278366Sadrian vap->iv_key_delete = wpi_key_delete; 599278366Sadrian vap->iv_newstate = wpi_newstate; 600278366Sadrian vap->iv_update_beacon = wpi_update_beacon; 601278366Sadrian 602278366Sadrian ieee80211_ratectl_init(vap); 603278366Sadrian /* Complete setup. */ 604278366Sadrian ieee80211_vap_attach(vap, ieee80211_media_change, ieee80211_media_status); 605278366Sadrian ic->ic_opmode = opmode; 606278366Sadrian return vap; 607278366Sadrian} 608278366Sadrian 609278366Sadrianstatic void 610278366Sadrianwpi_vap_delete(struct ieee80211vap *vap) 611278366Sadrian{ 612278366Sadrian struct wpi_vap *wvp = WPI_VAP(vap); 613278366Sadrian struct wpi_buf *bcn = &wvp->wv_bcbuf; 614278366Sadrian 615278366Sadrian ieee80211_ratectl_deinit(vap); 616278366Sadrian ieee80211_vap_detach(vap); 617278366Sadrian 618278366Sadrian if (bcn->data != NULL) 619278366Sadrian free(bcn->data, M_DEVBUF); 620278366Sadrian free(wvp, M_80211_VAP); 621278366Sadrian} 622278366Sadrian 623173362Sbenjscstatic int 624173362Sbenjscwpi_detach(device_t dev) 625173362Sbenjsc{ 626173362Sbenjsc struct wpi_softc *sc = device_get_softc(dev); 627178354Ssam struct ifnet *ifp = sc->sc_ifp; 628200530Sgavin struct ieee80211com *ic; 629278366Sadrian int qid; 630173362Sbenjsc 631278366Sadrian DPRINTF(sc, WPI_DEBUG_TRACE, TRACE_STR_BEGIN, __func__); 632260064Smarius 633200530Sgavin if (ifp != NULL) { 634200530Sgavin ic = ifp->if_l2com; 635191746Sthompsa 636278366Sadrian ieee80211_draintask(ic, &sc->sc_reinittask); 637278366Sadrian ieee80211_draintask(ic, &sc->sc_radiooff_task); 638280052Sadrian ieee80211_draintask(ic, &sc->sc_radioon_task); 639278366Sadrian 640173362Sbenjsc wpi_stop(sc); 641278366Sadrian 642173362Sbenjsc callout_drain(&sc->watchdog_to); 643278366Sadrian callout_drain(&sc->watchdog_rfkill); 644173362Sbenjsc callout_drain(&sc->calib_to); 645173362Sbenjsc ieee80211_ifdetach(ic); 646173362Sbenjsc } 647173362Sbenjsc 648278366Sadrian /* Uninstall interrupt handler. */ 649278366Sadrian if (sc->irq != NULL) { 650278366Sadrian bus_teardown_intr(dev, sc->irq, sc->sc_ih); 651278366Sadrian bus_release_resource(dev, SYS_RES_IRQ, rman_get_rid(sc->irq), 652278366Sadrian sc->irq); 653278366Sadrian pci_release_msi(dev); 654278366Sadrian } 655278366Sadrian 656173362Sbenjsc if (sc->txq[0].data_dmat) { 657278366Sadrian /* Free DMA resources. */ 658278366Sadrian for (qid = 0; qid < WPI_NTXQUEUES; qid++) 659278366Sadrian wpi_free_tx_ring(sc, &sc->txq[qid]); 660173362Sbenjsc 661278366Sadrian wpi_free_rx_ring(sc); 662173362Sbenjsc wpi_free_shared(sc); 663173362Sbenjsc } 664173362Sbenjsc 665173362Sbenjsc if (sc->fw_dma.tag) 666173362Sbenjsc wpi_free_fwmem(sc); 667278366Sadrian 668173362Sbenjsc if (sc->mem != NULL) 669260064Smarius bus_release_resource(dev, SYS_RES_MEMORY, 670260064Smarius rman_get_rid(sc->mem), sc->mem); 671173362Sbenjsc 672173362Sbenjsc if (ifp != NULL) 673173362Sbenjsc if_free(ifp); 674173362Sbenjsc 675278366Sadrian delete_unrhdr(sc->sc_unr); 676278366Sadrian 677278366Sadrian DPRINTF(sc, WPI_DEBUG_TRACE, TRACE_STR_END, __func__); 678173362Sbenjsc WPI_LOCK_DESTROY(sc); 679278366Sadrian return 0; 680278366Sadrian} 681173362Sbenjsc 682278366Sadrianstatic int 683278366Sadrianwpi_shutdown(device_t dev) 684278366Sadrian{ 685278366Sadrian struct wpi_softc *sc = device_get_softc(dev); 686278366Sadrian 687278366Sadrian wpi_stop(sc); 688173362Sbenjsc return 0; 689173362Sbenjsc} 690173362Sbenjsc 691278366Sadrianstatic int 692278366Sadrianwpi_suspend(device_t dev) 693178354Ssam{ 694278366Sadrian struct wpi_softc *sc = device_get_softc(dev); 695278366Sadrian struct ieee80211com *ic = sc->sc_ifp->if_l2com; 696178354Ssam 697278366Sadrian ieee80211_suspend_all(ic); 698278366Sadrian return 0; 699278366Sadrian} 700178354Ssam 701278366Sadrianstatic int 702278366Sadrianwpi_resume(device_t dev) 703278366Sadrian{ 704278366Sadrian struct wpi_softc *sc = device_get_softc(dev); 705278366Sadrian struct ieee80211com *ic = sc->sc_ifp->if_l2com; 706278366Sadrian 707278366Sadrian /* Clear device-specific "PCI retry timeout" register (41h). */ 708278366Sadrian pci_write_config(dev, 0x41, 0, 1); 709278366Sadrian 710278366Sadrian ieee80211_resume_all(ic); 711278366Sadrian return 0; 712178354Ssam} 713178354Ssam 714278366Sadrian/* 715278366Sadrian * Grab exclusive access to NIC memory. 716278366Sadrian */ 717278366Sadrianstatic int 718278366Sadrianwpi_nic_lock(struct wpi_softc *sc) 719178354Ssam{ 720278366Sadrian int ntries; 721178354Ssam 722278366Sadrian /* Request exclusive access to NIC. */ 723278366Sadrian WPI_SETBITS(sc, WPI_GP_CNTRL, WPI_GP_CNTRL_MAC_ACCESS_REQ); 724278366Sadrian 725278366Sadrian /* Spin until we actually get the lock. */ 726278366Sadrian for (ntries = 0; ntries < 1000; ntries++) { 727278366Sadrian if ((WPI_READ(sc, WPI_GP_CNTRL) & 728278366Sadrian (WPI_GP_CNTRL_MAC_ACCESS_ENA | WPI_GP_CNTRL_SLEEP)) == 729278366Sadrian WPI_GP_CNTRL_MAC_ACCESS_ENA) 730278366Sadrian return 0; 731278366Sadrian DELAY(10); 732278366Sadrian } 733278366Sadrian 734278366Sadrian device_printf(sc->sc_dev, "could not lock memory\n"); 735278366Sadrian 736278366Sadrian return ETIMEDOUT; 737178354Ssam} 738178354Ssam 739278366Sadrian/* 740278366Sadrian * Release lock on NIC memory. 741278366Sadrian */ 742278366Sadrianstatic __inline void 743278366Sadrianwpi_nic_unlock(struct wpi_softc *sc) 744278366Sadrian{ 745278366Sadrian WPI_CLRBITS(sc, WPI_GP_CNTRL, WPI_GP_CNTRL_MAC_ACCESS_REQ); 746278366Sadrian} 747278366Sadrian 748278366Sadrianstatic __inline uint32_t 749278366Sadrianwpi_prph_read(struct wpi_softc *sc, uint32_t addr) 750278366Sadrian{ 751278366Sadrian WPI_WRITE(sc, WPI_PRPH_RADDR, WPI_PRPH_DWORD | addr); 752278366Sadrian WPI_BARRIER_READ_WRITE(sc); 753278366Sadrian return WPI_READ(sc, WPI_PRPH_RDATA); 754278366Sadrian} 755278366Sadrian 756278366Sadrianstatic __inline void 757278366Sadrianwpi_prph_write(struct wpi_softc *sc, uint32_t addr, uint32_t data) 758278366Sadrian{ 759278366Sadrian WPI_WRITE(sc, WPI_PRPH_WADDR, WPI_PRPH_DWORD | addr); 760278366Sadrian WPI_BARRIER_WRITE(sc); 761278366Sadrian WPI_WRITE(sc, WPI_PRPH_WDATA, data); 762278366Sadrian} 763278366Sadrian 764278366Sadrianstatic __inline void 765278366Sadrianwpi_prph_setbits(struct wpi_softc *sc, uint32_t addr, uint32_t mask) 766278366Sadrian{ 767278366Sadrian wpi_prph_write(sc, addr, wpi_prph_read(sc, addr) | mask); 768278366Sadrian} 769278366Sadrian 770278366Sadrianstatic __inline void 771278366Sadrianwpi_prph_clrbits(struct wpi_softc *sc, uint32_t addr, uint32_t mask) 772278366Sadrian{ 773278366Sadrian wpi_prph_write(sc, addr, wpi_prph_read(sc, addr) & ~mask); 774278366Sadrian} 775278366Sadrian 776278366Sadrianstatic __inline void 777278366Sadrianwpi_prph_write_region_4(struct wpi_softc *sc, uint32_t addr, 778278366Sadrian const uint32_t *data, int count) 779278366Sadrian{ 780278366Sadrian for (; count > 0; count--, data++, addr += 4) 781278366Sadrian wpi_prph_write(sc, addr, *data); 782278366Sadrian} 783278366Sadrian 784278366Sadrianstatic __inline uint32_t 785278366Sadrianwpi_mem_read(struct wpi_softc *sc, uint32_t addr) 786278366Sadrian{ 787278366Sadrian WPI_WRITE(sc, WPI_MEM_RADDR, addr); 788278366Sadrian WPI_BARRIER_READ_WRITE(sc); 789278366Sadrian return WPI_READ(sc, WPI_MEM_RDATA); 790278366Sadrian} 791278366Sadrian 792278366Sadrianstatic __inline void 793278366Sadrianwpi_mem_read_region_4(struct wpi_softc *sc, uint32_t addr, uint32_t *data, 794278366Sadrian int count) 795278366Sadrian{ 796278366Sadrian for (; count > 0; count--, addr += 4) 797278366Sadrian *data++ = wpi_mem_read(sc, addr); 798278366Sadrian} 799278366Sadrian 800278366Sadrianstatic int 801278366Sadrianwpi_read_prom_data(struct wpi_softc *sc, uint32_t addr, void *data, int count) 802278366Sadrian{ 803278366Sadrian uint8_t *out = data; 804278366Sadrian uint32_t val; 805278366Sadrian int error, ntries; 806278366Sadrian 807278366Sadrian DPRINTF(sc, WPI_DEBUG_TRACE, TRACE_STR_BEGIN, __func__); 808278366Sadrian 809278366Sadrian if ((error = wpi_nic_lock(sc)) != 0) 810278366Sadrian return error; 811278366Sadrian 812278366Sadrian for (; count > 0; count -= 2, addr++) { 813278366Sadrian WPI_WRITE(sc, WPI_EEPROM, addr << 2); 814278366Sadrian for (ntries = 0; ntries < 10; ntries++) { 815278366Sadrian val = WPI_READ(sc, WPI_EEPROM); 816278366Sadrian if (val & WPI_EEPROM_READ_VALID) 817278366Sadrian break; 818278366Sadrian DELAY(5); 819278366Sadrian } 820278366Sadrian if (ntries == 10) { 821278366Sadrian device_printf(sc->sc_dev, 822278366Sadrian "timeout reading ROM at 0x%x\n", addr); 823278366Sadrian return ETIMEDOUT; 824278366Sadrian } 825278366Sadrian *out++= val >> 16; 826278366Sadrian if (count > 1) 827278366Sadrian *out ++= val >> 24; 828278366Sadrian } 829278366Sadrian 830278366Sadrian wpi_nic_unlock(sc); 831278366Sadrian 832278366Sadrian DPRINTF(sc, WPI_DEBUG_TRACE, TRACE_STR_END, __func__); 833278366Sadrian 834278366Sadrian return 0; 835278366Sadrian} 836278366Sadrian 837178354Ssamstatic void 838173362Sbenjscwpi_dma_map_addr(void *arg, bus_dma_segment_t *segs, int nsegs, int error) 839173362Sbenjsc{ 840173362Sbenjsc if (error != 0) 841173362Sbenjsc return; 842173362Sbenjsc KASSERT(nsegs == 1, ("too many DMA segments, %d should be 1", nsegs)); 843173362Sbenjsc *(bus_addr_t *)arg = segs[0].ds_addr; 844173362Sbenjsc} 845173362Sbenjsc 846177043Sthompsa/* 847177043Sthompsa * Allocates a contiguous block of dma memory of the requested size and 848278366Sadrian * alignment. 849177043Sthompsa */ 850173362Sbenjscstatic int 851173362Sbenjscwpi_dma_contig_alloc(struct wpi_softc *sc, struct wpi_dma_info *dma, 852278366Sadrian void **kvap, bus_size_t size, bus_size_t alignment) 853173362Sbenjsc{ 854173362Sbenjsc int error; 855173362Sbenjsc 856278366Sadrian dma->tag = NULL; 857173362Sbenjsc dma->size = size; 858173362Sbenjsc 859278366Sadrian error = bus_dma_tag_create(bus_get_dma_tag(sc->sc_dev), alignment, 860278366Sadrian 0, BUS_SPACE_MAXADDR_32BIT, BUS_SPACE_MAXADDR, NULL, NULL, size, 861278366Sadrian 1, size, BUS_DMA_NOWAIT, NULL, NULL, &dma->tag); 862278366Sadrian if (error != 0) 863173362Sbenjsc goto fail; 864278366Sadrian 865278366Sadrian error = bus_dmamem_alloc(dma->tag, (void **)&dma->vaddr, 866278366Sadrian BUS_DMA_NOWAIT | BUS_DMA_ZERO | BUS_DMA_COHERENT, &dma->map); 867278366Sadrian if (error != 0) 868173362Sbenjsc goto fail; 869173362Sbenjsc 870278366Sadrian error = bus_dmamap_load(dma->tag, dma->map, dma->vaddr, size, 871278366Sadrian wpi_dma_map_addr, &dma->paddr, BUS_DMA_NOWAIT); 872278366Sadrian if (error != 0) 873278366Sadrian goto fail; 874177043Sthompsa 875278366Sadrian bus_dmamap_sync(dma->tag, dma->map, BUS_DMASYNC_PREWRITE); 876177043Sthompsa 877173362Sbenjsc if (kvap != NULL) 878173362Sbenjsc *kvap = dma->vaddr; 879173362Sbenjsc 880173362Sbenjsc return 0; 881173362Sbenjsc 882278366Sadrianfail: wpi_dma_contig_free(dma); 883173362Sbenjsc return error; 884173362Sbenjsc} 885173362Sbenjsc 886173362Sbenjscstatic void 887173362Sbenjscwpi_dma_contig_free(struct wpi_dma_info *dma) 888173362Sbenjsc{ 889278366Sadrian if (dma->vaddr != NULL) { 890278366Sadrian bus_dmamap_sync(dma->tag, dma->map, 891278366Sadrian BUS_DMASYNC_POSTREAD | BUS_DMASYNC_POSTWRITE); 892278366Sadrian bus_dmamap_unload(dma->tag, dma->map); 893278366Sadrian bus_dmamem_free(dma->tag, dma->vaddr, dma->map); 894278366Sadrian dma->vaddr = NULL; 895278366Sadrian } 896278366Sadrian if (dma->tag != NULL) { 897173362Sbenjsc bus_dma_tag_destroy(dma->tag); 898278366Sadrian dma->tag = NULL; 899173362Sbenjsc } 900173362Sbenjsc} 901173362Sbenjsc 902173362Sbenjsc/* 903173362Sbenjsc * Allocate a shared page between host and NIC. 904173362Sbenjsc */ 905173362Sbenjscstatic int 906173362Sbenjscwpi_alloc_shared(struct wpi_softc *sc) 907173362Sbenjsc{ 908278366Sadrian /* Shared buffer must be aligned on a 4KB boundary. */ 909278366Sadrian return wpi_dma_contig_alloc(sc, &sc->shared_dma, 910278366Sadrian (void **)&sc->shared, sizeof (struct wpi_shared), 4096); 911173362Sbenjsc} 912173362Sbenjsc 913173362Sbenjscstatic void 914173362Sbenjscwpi_free_shared(struct wpi_softc *sc) 915173362Sbenjsc{ 916173362Sbenjsc wpi_dma_contig_free(&sc->shared_dma); 917173362Sbenjsc} 918173362Sbenjsc 919278366Sadrian/* 920278366Sadrian * Allocate DMA-safe memory for firmware transfer. 921278366Sadrian */ 922173362Sbenjscstatic int 923278366Sadrianwpi_alloc_fwmem(struct wpi_softc *sc) 924173362Sbenjsc{ 925278366Sadrian /* Must be aligned on a 16-byte boundary. */ 926278366Sadrian return wpi_dma_contig_alloc(sc, &sc->fw_dma, NULL, 927278366Sadrian WPI_FW_TEXT_MAXSZ + WPI_FW_DATA_MAXSZ, 16); 928278366Sadrian} 929173362Sbenjsc 930278366Sadrianstatic void 931278366Sadrianwpi_free_fwmem(struct wpi_softc *sc) 932278366Sadrian{ 933278366Sadrian wpi_dma_contig_free(&sc->fw_dma); 934278366Sadrian} 935278366Sadrian 936278366Sadrianstatic int 937278366Sadrianwpi_alloc_rx_ring(struct wpi_softc *sc) 938278366Sadrian{ 939278366Sadrian struct wpi_rx_ring *ring = &sc->rxq; 940278366Sadrian bus_size_t size; 941173362Sbenjsc int i, error; 942173362Sbenjsc 943173362Sbenjsc ring->cur = 0; 944278366Sadrian ring->update = 0; 945173362Sbenjsc 946278366Sadrian DPRINTF(sc, WPI_DEBUG_TRACE, TRACE_STR_BEGIN, __func__); 947278366Sadrian 948278366Sadrian /* Allocate RX descriptors (16KB aligned.) */ 949278366Sadrian size = WPI_RX_RING_COUNT * sizeof (uint32_t); 950173362Sbenjsc error = wpi_dma_contig_alloc(sc, &ring->desc_dma, 951278366Sadrian (void **)&ring->desc, size, WPI_RING_DMA_ALIGN); 952173362Sbenjsc if (error != 0) { 953177043Sthompsa device_printf(sc->sc_dev, 954278366Sadrian "%s: could not allocate RX ring DMA memory, error %d\n", 955177043Sthompsa __func__, error); 956177043Sthompsa goto fail; 957173362Sbenjsc } 958173362Sbenjsc 959278366Sadrian /* Create RX buffer DMA tag. */ 960177043Sthompsa error = bus_dma_tag_create(bus_get_dma_tag(sc->sc_dev), 1, 0, 961278366Sadrian BUS_SPACE_MAXADDR_32BIT, BUS_SPACE_MAXADDR, NULL, NULL, 962278366Sadrian MJUMPAGESIZE, 1, MJUMPAGESIZE, BUS_DMA_NOWAIT, NULL, NULL, 963278366Sadrian &ring->data_dmat); 964177043Sthompsa if (error != 0) { 965177043Sthompsa device_printf(sc->sc_dev, 966278366Sadrian "%s: could not create RX buf DMA tag, error %d\n", 967177043Sthompsa __func__, error); 968177043Sthompsa goto fail; 969177043Sthompsa } 970177043Sthompsa 971173362Sbenjsc /* 972278366Sadrian * Allocate and map RX buffers. 973173362Sbenjsc */ 974173362Sbenjsc for (i = 0; i < WPI_RX_RING_COUNT; i++) { 975177043Sthompsa struct wpi_rx_data *data = &ring->data[i]; 976177043Sthompsa bus_addr_t paddr; 977173362Sbenjsc 978177043Sthompsa error = bus_dmamap_create(ring->data_dmat, 0, &data->map); 979177043Sthompsa if (error != 0) { 980173362Sbenjsc device_printf(sc->sc_dev, 981278366Sadrian "%s: could not create RX buf DMA map, error %d\n", 982177043Sthompsa __func__, error); 983173362Sbenjsc goto fail; 984173362Sbenjsc } 985278366Sadrian 986278366Sadrian data->m = m_getjcl(M_NOWAIT, MT_DATA, M_PKTHDR, MJUMPAGESIZE); 987278366Sadrian if (data->m == NULL) { 988173362Sbenjsc device_printf(sc->sc_dev, 989278366Sadrian "%s: could not allocate RX mbuf\n", __func__); 990278366Sadrian error = ENOBUFS; 991173362Sbenjsc goto fail; 992173362Sbenjsc } 993278366Sadrian 994177043Sthompsa error = bus_dmamap_load(ring->data_dmat, data->map, 995278366Sadrian mtod(data->m, void *), MJUMPAGESIZE, wpi_dma_map_addr, 996278366Sadrian &paddr, BUS_DMA_NOWAIT); 997177043Sthompsa if (error != 0 && error != EFBIG) { 998177043Sthompsa device_printf(sc->sc_dev, 999278366Sadrian "%s: can't map mbuf (error %d)\n", __func__, 1000278366Sadrian error); 1001173362Sbenjsc goto fail; 1002173362Sbenjsc } 1003177043Sthompsa 1004278366Sadrian /* Set physical address of RX buffer. */ 1005177043Sthompsa ring->desc[i] = htole32(paddr); 1006173362Sbenjsc } 1007278366Sadrian 1008173362Sbenjsc bus_dmamap_sync(ring->desc_dma.tag, ring->desc_dma.map, 1009173362Sbenjsc BUS_DMASYNC_PREWRITE); 1010278366Sadrian 1011278366Sadrian DPRINTF(sc, WPI_DEBUG_TRACE, TRACE_STR_END, __func__); 1012278366Sadrian 1013173362Sbenjsc return 0; 1014278366Sadrian 1015278366Sadrianfail: wpi_free_rx_ring(sc); 1016278366Sadrian 1017278366Sadrian DPRINTF(sc, WPI_DEBUG_TRACE, TRACE_STR_END_ERR, __func__); 1018278366Sadrian 1019173362Sbenjsc return error; 1020173362Sbenjsc} 1021173362Sbenjsc 1022173362Sbenjscstatic void 1023278366Sadrianwpi_update_rx_ring(struct wpi_softc *sc) 1024173362Sbenjsc{ 1025278366Sadrian struct wpi_rx_ring *ring = &sc->rxq; 1026173362Sbenjsc 1027280056Sadrian if (ring->update != 0) { 1028280056Sadrian /* Wait for INT_WAKEUP event. */ 1029280056Sadrian return; 1030280056Sadrian } 1031280056Sadrian 1032278366Sadrian if (WPI_READ(sc, WPI_UCODE_GP1) & WPI_UCODE_GP1_MAC_SLEEP) { 1033278366Sadrian DPRINTF(sc, WPI_DEBUG_PWRSAVE, "%s: wakeup request\n", 1034278366Sadrian __func__); 1035173362Sbenjsc 1036278366Sadrian WPI_SETBITS(sc, WPI_GP_CNTRL, WPI_GP_CNTRL_MAC_ACCESS_REQ); 1037278366Sadrian ring->update = 1; 1038278366Sadrian } else 1039278366Sadrian WPI_WRITE(sc, WPI_FH_RX_WPTR, ring->cur & ~7); 1040278366Sadrian} 1041173362Sbenjsc 1042278366Sadrianstatic void 1043278366Sadrianwpi_reset_rx_ring(struct wpi_softc *sc) 1044278366Sadrian{ 1045278366Sadrian struct wpi_rx_ring *ring = &sc->rxq; 1046278366Sadrian int ntries; 1047173362Sbenjsc 1048278366Sadrian DPRINTF(sc, WPI_DEBUG_TRACE, TRACE_STR_DOING, __func__); 1049173362Sbenjsc 1050278366Sadrian if (wpi_nic_lock(sc) == 0) { 1051278366Sadrian WPI_WRITE(sc, WPI_FH_RX_CONFIG, 0); 1052278366Sadrian for (ntries = 0; ntries < 1000; ntries++) { 1053278366Sadrian if (WPI_READ(sc, WPI_FH_RX_STATUS) & 1054278366Sadrian WPI_FH_RX_STATUS_IDLE) 1055278366Sadrian break; 1056278366Sadrian DELAY(10); 1057278366Sadrian } 1058173362Sbenjsc#ifdef WPI_DEBUG 1059278366Sadrian if (ntries == 1000) { 1060278366Sadrian device_printf(sc->sc_dev, 1061278366Sadrian "timeout resetting Rx ring\n"); 1062278366Sadrian } 1063173362Sbenjsc#endif 1064278366Sadrian wpi_nic_unlock(sc); 1065278366Sadrian } 1066173362Sbenjsc 1067173362Sbenjsc ring->cur = 0; 1068278366Sadrian ring->update = 0; 1069173362Sbenjsc} 1070173362Sbenjsc 1071173362Sbenjscstatic void 1072278366Sadrianwpi_free_rx_ring(struct wpi_softc *sc) 1073173362Sbenjsc{ 1074278366Sadrian struct wpi_rx_ring *ring = &sc->rxq; 1075173362Sbenjsc int i; 1076173362Sbenjsc 1077278366Sadrian DPRINTF(sc, WPI_DEBUG_TRACE, TRACE_STR_DOING, __func__); 1078278366Sadrian 1079173362Sbenjsc wpi_dma_contig_free(&ring->desc_dma); 1080173362Sbenjsc 1081216824Sbschmidt for (i = 0; i < WPI_RX_RING_COUNT; i++) { 1082216824Sbschmidt struct wpi_rx_data *data = &ring->data[i]; 1083216824Sbschmidt 1084216824Sbschmidt if (data->m != NULL) { 1085216824Sbschmidt bus_dmamap_sync(ring->data_dmat, data->map, 1086216824Sbschmidt BUS_DMASYNC_POSTREAD); 1087216824Sbschmidt bus_dmamap_unload(ring->data_dmat, data->map); 1088216824Sbschmidt m_freem(data->m); 1089278366Sadrian data->m = NULL; 1090216824Sbschmidt } 1091216824Sbschmidt if (data->map != NULL) 1092216824Sbschmidt bus_dmamap_destroy(ring->data_dmat, data->map); 1093216824Sbschmidt } 1094278366Sadrian if (ring->data_dmat != NULL) { 1095278366Sadrian bus_dma_tag_destroy(ring->data_dmat); 1096278366Sadrian ring->data_dmat = NULL; 1097278366Sadrian } 1098173362Sbenjsc} 1099173362Sbenjsc 1100173362Sbenjscstatic int 1101278366Sadrianwpi_alloc_tx_ring(struct wpi_softc *sc, struct wpi_tx_ring *ring, int qid) 1102173362Sbenjsc{ 1103278366Sadrian bus_addr_t paddr; 1104278366Sadrian bus_size_t size; 1105173362Sbenjsc int i, error; 1106173362Sbenjsc 1107173362Sbenjsc ring->qid = qid; 1108173362Sbenjsc ring->queued = 0; 1109173362Sbenjsc ring->cur = 0; 1110278366Sadrian ring->update = 0; 1111173362Sbenjsc 1112278366Sadrian DPRINTF(sc, WPI_DEBUG_TRACE, TRACE_STR_BEGIN, __func__); 1113173362Sbenjsc 1114278366Sadrian /* Allocate TX descriptors (16KB aligned.) */ 1115278366Sadrian size = WPI_TX_RING_COUNT * sizeof (struct wpi_tx_desc); 1116278366Sadrian error = wpi_dma_contig_alloc(sc, &ring->desc_dma, (void **)&ring->desc, 1117278366Sadrian size, WPI_RING_DMA_ALIGN); 1118173362Sbenjsc if (error != 0) { 1119278366Sadrian device_printf(sc->sc_dev, 1120278366Sadrian "%s: could not allocate TX ring DMA memory, error %d\n", 1121278366Sadrian __func__, error); 1122278366Sadrian goto fail; 1123173362Sbenjsc } 1124173362Sbenjsc 1125278366Sadrian /* Update shared area with ring physical address. */ 1126173362Sbenjsc sc->shared->txbase[qid] = htole32(ring->desc_dma.paddr); 1127278366Sadrian bus_dmamap_sync(sc->shared_dma.tag, sc->shared_dma.map, 1128278366Sadrian BUS_DMASYNC_PREWRITE); 1129173362Sbenjsc 1130278366Sadrian /* 1131278366Sadrian * We only use rings 0 through 4 (4 EDCA + cmd) so there is no need 1132278366Sadrian * to allocate commands space for other rings. 1133278366Sadrian * XXX Do we really need to allocate descriptors for other rings? 1134278366Sadrian */ 1135278366Sadrian if (qid > 4) 1136278366Sadrian return 0; 1137278366Sadrian 1138278366Sadrian size = WPI_TX_RING_COUNT * sizeof (struct wpi_tx_cmd); 1139173362Sbenjsc error = wpi_dma_contig_alloc(sc, &ring->cmd_dma, (void **)&ring->cmd, 1140278366Sadrian size, 4); 1141173362Sbenjsc if (error != 0) { 1142173362Sbenjsc device_printf(sc->sc_dev, 1143278366Sadrian "%s: could not allocate TX cmd DMA memory, error %d\n", 1144278366Sadrian __func__, error); 1145173362Sbenjsc goto fail; 1146173362Sbenjsc } 1147173362Sbenjsc 1148173362Sbenjsc error = bus_dma_tag_create(bus_get_dma_tag(sc->sc_dev), 1, 0, 1149173362Sbenjsc BUS_SPACE_MAXADDR_32BIT, BUS_SPACE_MAXADDR, NULL, NULL, MCLBYTES, 1150173362Sbenjsc WPI_MAX_SCATTER - 1, MCLBYTES, BUS_DMA_NOWAIT, NULL, NULL, 1151173362Sbenjsc &ring->data_dmat); 1152173362Sbenjsc if (error != 0) { 1153278366Sadrian device_printf(sc->sc_dev, 1154278366Sadrian "%s: could not create TX buf DMA tag, error %d\n", 1155278366Sadrian __func__, error); 1156173362Sbenjsc goto fail; 1157173362Sbenjsc } 1158173362Sbenjsc 1159278366Sadrian paddr = ring->cmd_dma.paddr; 1160278366Sadrian for (i = 0; i < WPI_TX_RING_COUNT; i++) { 1161278366Sadrian struct wpi_tx_data *data = &ring->data[i]; 1162173362Sbenjsc 1163278366Sadrian data->cmd_paddr = paddr; 1164278366Sadrian paddr += sizeof (struct wpi_tx_cmd); 1165278366Sadrian 1166173362Sbenjsc error = bus_dmamap_create(ring->data_dmat, 0, &data->map); 1167173362Sbenjsc if (error != 0) { 1168173362Sbenjsc device_printf(sc->sc_dev, 1169278366Sadrian "%s: could not create TX buf DMA map, error %d\n", 1170278366Sadrian __func__, error); 1171173362Sbenjsc goto fail; 1172173362Sbenjsc } 1173173362Sbenjsc } 1174173362Sbenjsc 1175278366Sadrian DPRINTF(sc, WPI_DEBUG_TRACE, TRACE_STR_END, __func__); 1176278366Sadrian 1177173362Sbenjsc return 0; 1178173362Sbenjsc 1179278366Sadrianfail: wpi_free_tx_ring(sc, ring); 1180278366Sadrian DPRINTF(sc, WPI_DEBUG_TRACE, TRACE_STR_END_ERR, __func__); 1181173362Sbenjsc return error; 1182173362Sbenjsc} 1183173362Sbenjsc 1184173362Sbenjscstatic void 1185278366Sadrianwpi_update_tx_ring(struct wpi_softc *sc, struct wpi_tx_ring *ring) 1186278366Sadrian{ 1187280056Sadrian if (ring->update != 0) { 1188280056Sadrian /* Wait for INT_WAKEUP event. */ 1189280056Sadrian return; 1190280056Sadrian } 1191280056Sadrian 1192278366Sadrian if (WPI_READ(sc, WPI_UCODE_GP1) & WPI_UCODE_GP1_MAC_SLEEP) { 1193278366Sadrian DPRINTF(sc, WPI_DEBUG_PWRSAVE, "%s (%d): requesting wakeup\n", 1194278366Sadrian __func__, ring->qid); 1195278366Sadrian 1196278366Sadrian WPI_SETBITS(sc, WPI_GP_CNTRL, WPI_GP_CNTRL_MAC_ACCESS_REQ); 1197278366Sadrian ring->update = 1; 1198278366Sadrian } else 1199278366Sadrian WPI_WRITE(sc, WPI_HBUS_TARG_WRPTR, ring->qid << 8 | ring->cur); 1200278366Sadrian} 1201278366Sadrian 1202278366Sadrianstatic void 1203173362Sbenjscwpi_reset_tx_ring(struct wpi_softc *sc, struct wpi_tx_ring *ring) 1204173362Sbenjsc{ 1205278366Sadrian int i; 1206173362Sbenjsc 1207278366Sadrian DPRINTF(sc, WPI_DEBUG_TRACE, TRACE_STR_DOING, __func__); 1208173362Sbenjsc 1209278366Sadrian for (i = 0; i < WPI_TX_RING_COUNT; i++) { 1210278366Sadrian struct wpi_tx_data *data = &ring->data[i]; 1211173362Sbenjsc 1212173362Sbenjsc if (data->m != NULL) { 1213278366Sadrian bus_dmamap_sync(ring->data_dmat, data->map, 1214278366Sadrian BUS_DMASYNC_POSTWRITE); 1215173362Sbenjsc bus_dmamap_unload(ring->data_dmat, data->map); 1216173362Sbenjsc m_freem(data->m); 1217173362Sbenjsc data->m = NULL; 1218173362Sbenjsc } 1219173362Sbenjsc } 1220278366Sadrian /* Clear TX descriptors. */ 1221278366Sadrian memset(ring->desc, 0, ring->desc_dma.size); 1222278366Sadrian bus_dmamap_sync(ring->desc_dma.tag, ring->desc_dma.map, 1223278366Sadrian BUS_DMASYNC_PREWRITE); 1224278366Sadrian sc->qfullmsk &= ~(1 << ring->qid); 1225173362Sbenjsc ring->queued = 0; 1226173362Sbenjsc ring->cur = 0; 1227278366Sadrian ring->update = 0; 1228173362Sbenjsc} 1229173362Sbenjsc 1230173362Sbenjscstatic void 1231173362Sbenjscwpi_free_tx_ring(struct wpi_softc *sc, struct wpi_tx_ring *ring) 1232173362Sbenjsc{ 1233173362Sbenjsc int i; 1234173362Sbenjsc 1235278366Sadrian DPRINTF(sc, WPI_DEBUG_TRACE, TRACE_STR_DOING, __func__); 1236278366Sadrian 1237173362Sbenjsc wpi_dma_contig_free(&ring->desc_dma); 1238173362Sbenjsc wpi_dma_contig_free(&ring->cmd_dma); 1239173362Sbenjsc 1240278366Sadrian for (i = 0; i < WPI_TX_RING_COUNT; i++) { 1241278366Sadrian struct wpi_tx_data *data = &ring->data[i]; 1242173362Sbenjsc 1243278366Sadrian if (data->m != NULL) { 1244278366Sadrian bus_dmamap_sync(ring->data_dmat, data->map, 1245278366Sadrian BUS_DMASYNC_POSTWRITE); 1246278366Sadrian bus_dmamap_unload(ring->data_dmat, data->map); 1247278366Sadrian m_freem(data->m); 1248173362Sbenjsc } 1249278366Sadrian if (data->map != NULL) 1250278366Sadrian bus_dmamap_destroy(ring->data_dmat, data->map); 1251173362Sbenjsc } 1252278366Sadrian if (ring->data_dmat != NULL) { 1253173362Sbenjsc bus_dma_tag_destroy(ring->data_dmat); 1254278366Sadrian ring->data_dmat = NULL; 1255278366Sadrian } 1256173362Sbenjsc} 1257173362Sbenjsc 1258278366Sadrian/* 1259278366Sadrian * Extract various information from EEPROM. 1260278366Sadrian */ 1261173362Sbenjscstatic int 1262278366Sadrianwpi_read_eeprom(struct wpi_softc *sc, uint8_t macaddr[IEEE80211_ADDR_LEN]) 1263173362Sbenjsc{ 1264278366Sadrian#define WPI_CHK(res) do { \ 1265278366Sadrian if ((error = res) != 0) \ 1266278366Sadrian goto fail; \ 1267278366Sadrian} while (0) 1268278366Sadrian int error, i; 1269173362Sbenjsc 1270278366Sadrian DPRINTF(sc, WPI_DEBUG_TRACE, TRACE_STR_BEGIN, __func__); 1271173362Sbenjsc 1272278366Sadrian /* Adapter has to be powered on for EEPROM access to work. */ 1273278366Sadrian if ((error = wpi_apm_init(sc)) != 0) { 1274278366Sadrian device_printf(sc->sc_dev, 1275278366Sadrian "%s: could not power ON adapter, error %d\n", __func__, 1276278366Sadrian error); 1277278366Sadrian return error; 1278278366Sadrian } 1279278366Sadrian 1280278366Sadrian if ((WPI_READ(sc, WPI_EEPROM_GP) & 0x6) == 0) { 1281278366Sadrian device_printf(sc->sc_dev, "bad EEPROM signature\n"); 1282278366Sadrian error = EIO; 1283278366Sadrian goto fail; 1284278366Sadrian } 1285278366Sadrian /* Clear HW ownership of EEPROM. */ 1286278366Sadrian WPI_CLRBITS(sc, WPI_EEPROM_GP, WPI_EEPROM_GP_IF_OWNER); 1287278366Sadrian 1288278366Sadrian /* Read the hardware capabilities, revision and SKU type. */ 1289278366Sadrian WPI_CHK(wpi_read_prom_data(sc, WPI_EEPROM_SKU_CAP, &sc->cap, 1290278366Sadrian sizeof(sc->cap))); 1291278366Sadrian WPI_CHK(wpi_read_prom_data(sc, WPI_EEPROM_REVISION, &sc->rev, 1292278366Sadrian sizeof(sc->rev))); 1293278366Sadrian WPI_CHK(wpi_read_prom_data(sc, WPI_EEPROM_TYPE, &sc->type, 1294278366Sadrian sizeof(sc->type))); 1295278366Sadrian 1296278366Sadrian DPRINTF(sc, WPI_DEBUG_EEPROM, "cap=%x rev=%x type=%x\n", sc->cap, le16toh(sc->rev), 1297278366Sadrian sc->type); 1298278366Sadrian 1299278366Sadrian /* Read the regulatory domain (4 ASCII characters.) */ 1300278366Sadrian WPI_CHK(wpi_read_prom_data(sc, WPI_EEPROM_DOMAIN, sc->domain, 1301278366Sadrian sizeof(sc->domain))); 1302278366Sadrian 1303278366Sadrian /* Read MAC address. */ 1304278366Sadrian WPI_CHK(wpi_read_prom_data(sc, WPI_EEPROM_MAC, macaddr, 1305278366Sadrian IEEE80211_ADDR_LEN)); 1306278366Sadrian 1307278366Sadrian /* Read the list of authorized channels. */ 1308278366Sadrian for (i = 0; i < WPI_CHAN_BANDS_COUNT; i++) 1309278366Sadrian WPI_CHK(wpi_read_eeprom_channels(sc, i)); 1310278366Sadrian 1311278366Sadrian /* Read the list of TX power groups. */ 1312278366Sadrian for (i = 0; i < WPI_POWER_GROUPS_COUNT; i++) 1313278366Sadrian WPI_CHK(wpi_read_eeprom_group(sc, i)); 1314278366Sadrian 1315278366Sadrianfail: wpi_apm_stop(sc); /* Power OFF adapter. */ 1316278366Sadrian 1317278366Sadrian DPRINTF(sc, WPI_DEBUG_TRACE, error ? TRACE_STR_END_ERR : TRACE_STR_END, 1318278366Sadrian __func__); 1319278366Sadrian 1320278366Sadrian return error; 1321278366Sadrian#undef WPI_CHK 1322278366Sadrian} 1323278366Sadrian 1324278366Sadrian/* 1325278366Sadrian * Translate EEPROM flags to net80211. 1326278366Sadrian */ 1327278366Sadrianstatic uint32_t 1328278366Sadrianwpi_eeprom_channel_flags(struct wpi_eeprom_chan *channel) 1329278366Sadrian{ 1330278366Sadrian uint32_t nflags; 1331278366Sadrian 1332278366Sadrian nflags = 0; 1333278366Sadrian if ((channel->flags & WPI_EEPROM_CHAN_ACTIVE) == 0) 1334278366Sadrian nflags |= IEEE80211_CHAN_PASSIVE; 1335278366Sadrian if ((channel->flags & WPI_EEPROM_CHAN_IBSS) == 0) 1336278366Sadrian nflags |= IEEE80211_CHAN_NOADHOC; 1337278366Sadrian if (channel->flags & WPI_EEPROM_CHAN_RADAR) { 1338278366Sadrian nflags |= IEEE80211_CHAN_DFS; 1339278366Sadrian /* XXX apparently IBSS may still be marked */ 1340278366Sadrian nflags |= IEEE80211_CHAN_NOADHOC; 1341278366Sadrian } 1342278366Sadrian 1343278366Sadrian return nflags; 1344278366Sadrian} 1345278366Sadrian 1346278366Sadrianstatic void 1347278366Sadrianwpi_read_eeprom_band(struct wpi_softc *sc, int n) 1348278366Sadrian{ 1349278366Sadrian struct ifnet *ifp = sc->sc_ifp; 1350278366Sadrian struct ieee80211com *ic = ifp->if_l2com; 1351278366Sadrian struct wpi_eeprom_chan *channels = sc->eeprom_channels[n]; 1352278366Sadrian const struct wpi_chan_band *band = &wpi_bands[n]; 1353278366Sadrian struct ieee80211_channel *c; 1354278366Sadrian uint8_t chan; 1355278366Sadrian int i, nflags; 1356278366Sadrian 1357278366Sadrian for (i = 0; i < band->nchan; i++) { 1358278366Sadrian if (!(channels[i].flags & WPI_EEPROM_CHAN_VALID)) { 1359278366Sadrian DPRINTF(sc, WPI_DEBUG_HW, 1360278366Sadrian "Channel Not Valid: %d, band %d\n", 1361278366Sadrian band->chan[i],n); 1362278366Sadrian continue; 1363278366Sadrian } 1364278366Sadrian 1365278366Sadrian chan = band->chan[i]; 1366278366Sadrian nflags = wpi_eeprom_channel_flags(&channels[i]); 1367278366Sadrian 1368278366Sadrian c = &ic->ic_channels[ic->ic_nchans++]; 1369278366Sadrian c->ic_ieee = chan; 1370278366Sadrian c->ic_maxregpower = channels[i].maxpwr; 1371278366Sadrian c->ic_maxpower = 2*c->ic_maxregpower; 1372278366Sadrian 1373278366Sadrian if (n == 0) { /* 2GHz band */ 1374278366Sadrian c->ic_freq = ieee80211_ieee2mhz(chan, IEEE80211_CHAN_G); 1375278366Sadrian /* G =>'s B is supported */ 1376278366Sadrian c->ic_flags = IEEE80211_CHAN_B | nflags; 1377278366Sadrian c = &ic->ic_channels[ic->ic_nchans++]; 1378278366Sadrian c[0] = c[-1]; 1379278366Sadrian c->ic_flags = IEEE80211_CHAN_G | nflags; 1380278366Sadrian } else { /* 5GHz band */ 1381278366Sadrian c->ic_freq = ieee80211_ieee2mhz(chan, IEEE80211_CHAN_A); 1382278366Sadrian c->ic_flags = IEEE80211_CHAN_A | nflags; 1383278366Sadrian } 1384278366Sadrian 1385278366Sadrian /* Save maximum allowed TX power for this channel. */ 1386278366Sadrian sc->maxpwr[chan] = channels[i].maxpwr; 1387278366Sadrian 1388278366Sadrian DPRINTF(sc, WPI_DEBUG_EEPROM, 1389278366Sadrian "adding chan %d (%dMHz) flags=0x%x maxpwr=%d passive=%d," 1390278366Sadrian " offset %d\n", chan, c->ic_freq, 1391278366Sadrian channels[i].flags, sc->maxpwr[chan], 1392278764Sadrian IEEE80211_IS_CHAN_PASSIVE(c), ic->ic_nchans); 1393278366Sadrian } 1394278366Sadrian} 1395278366Sadrian 1396278366Sadrian/** 1397278366Sadrian * Read the eeprom to find out what channels are valid for the given 1398278366Sadrian * band and update net80211 with what we find. 1399278366Sadrian */ 1400278366Sadrianstatic int 1401278366Sadrianwpi_read_eeprom_channels(struct wpi_softc *sc, int n) 1402278366Sadrian{ 1403278366Sadrian struct ifnet *ifp = sc->sc_ifp; 1404278366Sadrian struct ieee80211com *ic = ifp->if_l2com; 1405278366Sadrian const struct wpi_chan_band *band = &wpi_bands[n]; 1406278366Sadrian int error; 1407278366Sadrian 1408278366Sadrian DPRINTF(sc, WPI_DEBUG_TRACE, TRACE_STR_BEGIN, __func__); 1409278366Sadrian 1410278366Sadrian error = wpi_read_prom_data(sc, band->addr, &sc->eeprom_channels[n], 1411278366Sadrian band->nchan * sizeof (struct wpi_eeprom_chan)); 1412278366Sadrian if (error != 0) { 1413278366Sadrian DPRINTF(sc, WPI_DEBUG_TRACE, TRACE_STR_END_ERR, __func__); 1414278366Sadrian return error; 1415278366Sadrian } 1416278366Sadrian 1417278366Sadrian wpi_read_eeprom_band(sc, n); 1418278366Sadrian 1419278366Sadrian ieee80211_sort_channels(ic->ic_channels, ic->ic_nchans); 1420278366Sadrian 1421278366Sadrian DPRINTF(sc, WPI_DEBUG_TRACE, TRACE_STR_END, __func__); 1422278366Sadrian 1423173362Sbenjsc return 0; 1424173362Sbenjsc} 1425173362Sbenjsc 1426278366Sadrianstatic struct wpi_eeprom_chan * 1427278366Sadrianwpi_find_eeprom_channel(struct wpi_softc *sc, struct ieee80211_channel *c) 1428278366Sadrian{ 1429278366Sadrian int i, j; 1430278366Sadrian 1431278366Sadrian for (j = 0; j < WPI_CHAN_BANDS_COUNT; j++) 1432278366Sadrian for (i = 0; i < wpi_bands[j].nchan; i++) 1433278366Sadrian if (wpi_bands[j].chan[i] == c->ic_ieee) 1434278366Sadrian return &sc->eeprom_channels[j][i]; 1435278366Sadrian 1436278366Sadrian return NULL; 1437278366Sadrian} 1438278366Sadrian 1439278366Sadrian/* 1440278366Sadrian * Enforce flags read from EEPROM. 1441278366Sadrian */ 1442173362Sbenjscstatic int 1443278366Sadrianwpi_setregdomain(struct ieee80211com *ic, struct ieee80211_regdomain *rd, 1444278366Sadrian int nchan, struct ieee80211_channel chans[]) 1445173362Sbenjsc{ 1446278366Sadrian struct ifnet *ifp = ic->ic_ifp; 1447278366Sadrian struct wpi_softc *sc = ifp->if_softc; 1448278366Sadrian int i; 1449173362Sbenjsc 1450278366Sadrian for (i = 0; i < nchan; i++) { 1451278366Sadrian struct ieee80211_channel *c = &chans[i]; 1452278366Sadrian struct wpi_eeprom_chan *channel; 1453278366Sadrian 1454278366Sadrian channel = wpi_find_eeprom_channel(sc, c); 1455278366Sadrian if (channel == NULL) { 1456278366Sadrian if_printf(ic->ic_ifp, 1457278366Sadrian "%s: invalid channel %u freq %u/0x%x\n", 1458278366Sadrian __func__, c->ic_ieee, c->ic_freq, c->ic_flags); 1459278366Sadrian return EINVAL; 1460278366Sadrian } 1461278366Sadrian c->ic_flags |= wpi_eeprom_channel_flags(channel); 1462278366Sadrian } 1463278366Sadrian 1464173362Sbenjsc return 0; 1465173362Sbenjsc} 1466173362Sbenjsc 1467173362Sbenjscstatic int 1468278366Sadrianwpi_read_eeprom_group(struct wpi_softc *sc, int n) 1469173362Sbenjsc{ 1470278366Sadrian struct wpi_power_group *group = &sc->groups[n]; 1471278366Sadrian struct wpi_eeprom_group rgroup; 1472278366Sadrian int i, error; 1473173362Sbenjsc 1474278366Sadrian DPRINTF(sc, WPI_DEBUG_TRACE, TRACE_STR_BEGIN, __func__); 1475173362Sbenjsc 1476278366Sadrian if ((error = wpi_read_prom_data(sc, WPI_EEPROM_POWER_GRP + n * 32, 1477278366Sadrian &rgroup, sizeof rgroup)) != 0) { 1478278366Sadrian DPRINTF(sc, WPI_DEBUG_TRACE, TRACE_STR_END_ERR, __func__); 1479278366Sadrian return error; 1480278366Sadrian } 1481278366Sadrian 1482278366Sadrian /* Save TX power group information. */ 1483278366Sadrian group->chan = rgroup.chan; 1484278366Sadrian group->maxpwr = rgroup.maxpwr; 1485278366Sadrian /* Retrieve temperature at which the samples were taken. */ 1486278366Sadrian group->temp = (int16_t)le16toh(rgroup.temp); 1487278366Sadrian 1488278366Sadrian DPRINTF(sc, WPI_DEBUG_EEPROM, 1489278366Sadrian "power group %d: chan=%d maxpwr=%d temp=%d\n", n, group->chan, 1490278366Sadrian group->maxpwr, group->temp); 1491278366Sadrian 1492278366Sadrian for (i = 0; i < WPI_SAMPLES_COUNT; i++) { 1493278366Sadrian group->samples[i].index = rgroup.samples[i].index; 1494278366Sadrian group->samples[i].power = rgroup.samples[i].power; 1495278366Sadrian 1496278366Sadrian DPRINTF(sc, WPI_DEBUG_EEPROM, 1497278366Sadrian "\tsample %d: index=%d power=%d\n", i, 1498278366Sadrian group->samples[i].index, group->samples[i].power); 1499278366Sadrian } 1500278366Sadrian 1501278366Sadrian DPRINTF(sc, WPI_DEBUG_TRACE, TRACE_STR_END, __func__); 1502278366Sadrian 1503173362Sbenjsc return 0; 1504173362Sbenjsc} 1505173362Sbenjsc 1506278366Sadrianstatic struct ieee80211_node * 1507278366Sadrianwpi_node_alloc(struct ieee80211vap *vap, const uint8_t mac[IEEE80211_ADDR_LEN]) 1508278366Sadrian{ 1509278366Sadrian struct wpi_node *wn; 1510278366Sadrian 1511278366Sadrian wn = malloc(sizeof (struct wpi_node), M_80211_NODE, 1512278366Sadrian M_NOWAIT | M_ZERO); 1513278366Sadrian 1514278366Sadrian if (wn == NULL) 1515278366Sadrian return NULL; 1516278366Sadrian 1517278366Sadrian wn->id = WPI_ID_UNDEFINED; 1518278366Sadrian 1519278366Sadrian return &wn->ni; 1520278366Sadrian} 1521278366Sadrian 1522278366Sadrianstatic void 1523278366Sadrianwpi_node_free(struct ieee80211_node *ni) 1524278366Sadrian{ 1525278366Sadrian struct ieee80211com *ic = ni->ni_ic; 1526278366Sadrian struct wpi_softc *sc = ic->ic_ifp->if_softc; 1527278366Sadrian struct wpi_node *wn = (struct wpi_node *)ni; 1528278366Sadrian 1529278366Sadrian if (wn->id >= WPI_ID_IBSS_MIN && wn->id <= WPI_ID_IBSS_MAX) { 1530278366Sadrian free_unr(sc->sc_unr, wn->id); 1531278366Sadrian 1532278366Sadrian WPI_LOCK(sc); 1533278366Sadrian if (sc->rxon.filter & htole32(WPI_FILTER_BSS)) 1534278366Sadrian wpi_del_node(sc, ni); 1535278366Sadrian WPI_UNLOCK(sc); 1536278366Sadrian } 1537278366Sadrian 1538278366Sadrian sc->sc_node_free(ni); 1539278366Sadrian} 1540278366Sadrian 1541173362Sbenjsc/** 1542173362Sbenjsc * Called by net80211 when ever there is a change to 80211 state machine 1543173362Sbenjsc */ 1544173362Sbenjscstatic int 1545178354Ssamwpi_newstate(struct ieee80211vap *vap, enum ieee80211_state nstate, int arg) 1546173362Sbenjsc{ 1547178354Ssam struct wpi_vap *wvp = WPI_VAP(vap); 1548178354Ssam struct ieee80211com *ic = vap->iv_ic; 1549173362Sbenjsc struct ifnet *ifp = ic->ic_ifp; 1550173362Sbenjsc struct wpi_softc *sc = ifp->if_softc; 1551278366Sadrian int error = 0; 1552173362Sbenjsc 1553278366Sadrian DPRINTF(sc, WPI_DEBUG_TRACE, TRACE_STR_BEGIN, __func__); 1554278366Sadrian 1555278366Sadrian DPRINTF(sc, WPI_DEBUG_STATE, "%s: %s -> %s\n", __func__, 1556178354Ssam ieee80211_state_name[vap->iv_state], 1557278366Sadrian ieee80211_state_name[nstate]); 1558173362Sbenjsc 1559191746Sthompsa IEEE80211_UNLOCK(ic); 1560191746Sthompsa WPI_LOCK(sc); 1561278366Sadrian switch (nstate) { 1562278366Sadrian case IEEE80211_S_SCAN: 1563278366Sadrian if ((vap->iv_opmode == IEEE80211_M_IBSS || 1564278366Sadrian vap->iv_opmode == IEEE80211_M_AHDEMO) && 1565278366Sadrian (sc->rxon.filter & htole32(WPI_FILTER_BSS))) { 1566278366Sadrian sc->rxon.filter &= ~htole32(WPI_FILTER_BSS); 1567278366Sadrian if ((error = wpi_send_rxon(sc, 0, 1)) != 0) { 1568278366Sadrian device_printf(sc->sc_dev, 1569278366Sadrian "%s: could not send RXON\n", __func__); 1570278366Sadrian } 1571216238Sbschmidt } 1572278366Sadrian break; 1573278366Sadrian 1574278366Sadrian case IEEE80211_S_ASSOC: 1575278366Sadrian if (vap->iv_state != IEEE80211_S_RUN) 1576278366Sadrian break; 1577278366Sadrian /* FALLTHROUGH */ 1578278366Sadrian case IEEE80211_S_AUTH: 1579216238Sbschmidt /* 1580216238Sbschmidt * The node must be registered in the firmware before auth. 1581216238Sbschmidt * Also the associd must be cleared on RUN -> ASSOC 1582216238Sbschmidt * transitions. 1583216238Sbschmidt */ 1584278366Sadrian if ((error = wpi_auth(sc, vap)) != 0) { 1585191746Sthompsa device_printf(sc->sc_dev, 1586278366Sadrian "%s: could not move to AUTH state, error %d\n", 1587191746Sthompsa __func__, error); 1588191746Sthompsa } 1589278366Sadrian break; 1590278366Sadrian 1591278366Sadrian case IEEE80211_S_RUN: 1592278366Sadrian /* 1593278366Sadrian * RUN -> RUN transition; Just restart the timers. 1594278366Sadrian */ 1595278366Sadrian if (vap->iv_state == IEEE80211_S_RUN) { 1596278366Sadrian wpi_calib_timeout(sc); 1597278366Sadrian break; 1598278366Sadrian } 1599278366Sadrian 1600278366Sadrian /* 1601278366Sadrian * !RUN -> RUN requires setting the association id 1602278366Sadrian * which is done with a firmware cmd. We also defer 1603278366Sadrian * starting the timers until that work is done. 1604278366Sadrian */ 1605278366Sadrian if ((error = wpi_run(sc, vap)) != 0) { 1606191746Sthompsa device_printf(sc->sc_dev, 1607278366Sadrian "%s: could not move to RUN state\n", __func__); 1608191746Sthompsa } 1609278366Sadrian break; 1610278366Sadrian 1611278366Sadrian default: 1612278366Sadrian break; 1613178354Ssam } 1614191746Sthompsa WPI_UNLOCK(sc); 1615191746Sthompsa IEEE80211_LOCK(ic); 1616278366Sadrian if (error != 0) { 1617278366Sadrian DPRINTF(sc, WPI_DEBUG_TRACE, TRACE_STR_END_ERR, __func__); 1618278366Sadrian return error; 1619278366Sadrian } 1620173362Sbenjsc 1621278366Sadrian DPRINTF(sc, WPI_DEBUG_TRACE, TRACE_STR_END, __func__); 1622173362Sbenjsc 1623278366Sadrian return wvp->newstate(vap, nstate, arg); 1624173362Sbenjsc} 1625173362Sbenjsc 1626173362Sbenjscstatic void 1627278366Sadrianwpi_calib_timeout(void *arg) 1628173362Sbenjsc{ 1629278366Sadrian struct wpi_softc *sc = arg; 1630278366Sadrian struct ifnet *ifp = sc->sc_ifp; 1631278366Sadrian struct ieee80211com *ic = ifp->if_l2com; 1632278366Sadrian struct ieee80211vap *vap = TAILQ_FIRST(&ic->ic_vaps); 1633173362Sbenjsc 1634278366Sadrian if (vap->iv_state != IEEE80211_S_RUN) 1635278366Sadrian return; 1636173362Sbenjsc 1637278366Sadrian wpi_power_calibration(sc); 1638173362Sbenjsc 1639278366Sadrian callout_reset(&sc->calib_to, 60*hz, wpi_calib_timeout, sc); 1640173362Sbenjsc} 1641173362Sbenjsc 1642278366Sadrianstatic __inline uint8_t 1643278366Sadrianrate2plcp(const uint8_t rate) 1644173362Sbenjsc{ 1645278366Sadrian switch (rate) { 1646278366Sadrian case 12: return 0xd; 1647278366Sadrian case 18: return 0xf; 1648278366Sadrian case 24: return 0x5; 1649278366Sadrian case 36: return 0x7; 1650278366Sadrian case 48: return 0x9; 1651278366Sadrian case 72: return 0xb; 1652278366Sadrian case 96: return 0x1; 1653278366Sadrian case 108: return 0x3; 1654278366Sadrian case 2: return 10; 1655278366Sadrian case 4: return 20; 1656278366Sadrian case 11: return 55; 1657278366Sadrian case 22: return 110; 1658278366Sadrian default: return 0; 1659173362Sbenjsc } 1660173362Sbenjsc} 1661173362Sbenjsc 1662278366Sadrianstatic __inline uint8_t 1663278366Sadrianplcp2rate(const uint8_t plcp) 1664173362Sbenjsc{ 1665278366Sadrian switch (plcp) { 1666278366Sadrian case 0xd: return 12; 1667278366Sadrian case 0xf: return 18; 1668278366Sadrian case 0x5: return 24; 1669278366Sadrian case 0x7: return 36; 1670278366Sadrian case 0x9: return 48; 1671278366Sadrian case 0xb: return 72; 1672278366Sadrian case 0x1: return 96; 1673278366Sadrian case 0x3: return 108; 1674278366Sadrian case 10: return 2; 1675278366Sadrian case 20: return 4; 1676278366Sadrian case 55: return 11; 1677278366Sadrian case 110: return 22; 1678278366Sadrian default: return 0; 1679173362Sbenjsc } 1680278366Sadrian} 1681173362Sbenjsc 1682278366Sadrian/* Quickly determine if a given rate is CCK or OFDM. */ 1683278366Sadrian#define WPI_RATE_IS_OFDM(rate) ((rate) >= 12 && (rate) != 22) 1684173362Sbenjsc 1685173362Sbenjscstatic void 1686278366Sadrianwpi_rx_done(struct wpi_softc *sc, struct wpi_rx_desc *desc, 1687278366Sadrian struct wpi_rx_data *data) 1688173362Sbenjsc{ 1689178354Ssam struct ifnet *ifp = sc->sc_ifp; 1690278366Sadrian const struct ieee80211_cipher *cip = NULL; 1691178354Ssam struct ieee80211com *ic = ifp->if_l2com; 1692173362Sbenjsc struct wpi_rx_ring *ring = &sc->rxq; 1693173362Sbenjsc struct wpi_rx_stat *stat; 1694173362Sbenjsc struct wpi_rx_head *head; 1695173362Sbenjsc struct wpi_rx_tail *tail; 1696278366Sadrian struct ieee80211_frame *wh; 1697173362Sbenjsc struct ieee80211_node *ni; 1698278366Sadrian struct mbuf *m, *m1; 1699177043Sthompsa bus_addr_t paddr; 1700278366Sadrian uint32_t flags; 1701278366Sadrian uint16_t len; 1702177043Sthompsa int error; 1703173362Sbenjsc 1704173362Sbenjsc stat = (struct wpi_rx_stat *)(desc + 1); 1705173362Sbenjsc 1706173362Sbenjsc if (stat->len > WPI_STAT_MAXLEN) { 1707278366Sadrian device_printf(sc->sc_dev, "invalid RX statistic header\n"); 1708278764Sadrian goto fail1; 1709173362Sbenjsc } 1710173362Sbenjsc 1711216824Sbschmidt bus_dmamap_sync(ring->data_dmat, data->map, BUS_DMASYNC_POSTREAD); 1712173362Sbenjsc head = (struct wpi_rx_head *)((caddr_t)(stat + 1) + stat->len); 1713278366Sadrian len = le16toh(head->len); 1714278366Sadrian tail = (struct wpi_rx_tail *)((caddr_t)(head + 1) + len); 1715278366Sadrian flags = le32toh(tail->flags); 1716173362Sbenjsc 1717278366Sadrian DPRINTF(sc, WPI_DEBUG_RECV, "%s: idx %d len %d stat len %u rssi %d" 1718278366Sadrian " rate %x chan %d tstamp %ju\n", __func__, ring->cur, 1719278366Sadrian le32toh(desc->len), len, (int8_t)stat->rssi, 1720278366Sadrian head->plcp, head->chan, (uintmax_t)le64toh(tail->tstamp)); 1721173362Sbenjsc 1722278366Sadrian /* Discard frames with a bad FCS early. */ 1723278366Sadrian if ((flags & WPI_RX_NOERROR) != WPI_RX_NOERROR) { 1724278366Sadrian DPRINTF(sc, WPI_DEBUG_RECV, "%s: RX flags error %x\n", 1725278366Sadrian __func__, flags); 1726278764Sadrian goto fail1; 1727190458Sjmallett } 1728278366Sadrian /* Discard frames that are too short. */ 1729278366Sadrian if (len < sizeof (*wh)) { 1730278366Sadrian DPRINTF(sc, WPI_DEBUG_RECV, "%s: frame too short: %d\n", 1731278366Sadrian __func__, len); 1732278764Sadrian goto fail1; 1733190458Sjmallett } 1734190458Sjmallett 1735278366Sadrian m1 = m_getjcl(M_NOWAIT, MT_DATA, M_PKTHDR, MJUMPAGESIZE); 1736278366Sadrian if (m1 == NULL) { 1737278366Sadrian DPRINTF(sc, WPI_DEBUG_ANY, "%s: no mbuf to restock ring\n", 1738278366Sadrian __func__); 1739278764Sadrian goto fail1; 1740177043Sthompsa } 1741216824Sbschmidt bus_dmamap_unload(ring->data_dmat, data->map); 1742216824Sbschmidt 1743278366Sadrian error = bus_dmamap_load(ring->data_dmat, data->map, mtod(m1, void *), 1744278366Sadrian MJUMPAGESIZE, wpi_dma_map_addr, &paddr, BUS_DMA_NOWAIT); 1745177043Sthompsa if (error != 0 && error != EFBIG) { 1746177043Sthompsa device_printf(sc->sc_dev, 1747177043Sthompsa "%s: bus_dmamap_load failed, error %d\n", __func__, error); 1748278366Sadrian m_freem(m1); 1749278366Sadrian 1750278366Sadrian /* Try to reload the old mbuf. */ 1751278366Sadrian error = bus_dmamap_load(ring->data_dmat, data->map, 1752278366Sadrian mtod(data->m, void *), MJUMPAGESIZE, wpi_dma_map_addr, 1753278366Sadrian &paddr, BUS_DMA_NOWAIT); 1754278366Sadrian if (error != 0 && error != EFBIG) { 1755278366Sadrian panic("%s: could not load old RX mbuf", __func__); 1756278366Sadrian } 1757278366Sadrian /* Physical address may have changed. */ 1758278366Sadrian ring->desc[ring->cur] = htole32(paddr); 1759278366Sadrian bus_dmamap_sync(ring->data_dmat, ring->desc_dma.map, 1760278366Sadrian BUS_DMASYNC_PREWRITE); 1761278764Sadrian goto fail1; 1762177043Sthompsa } 1763177043Sthompsa 1764173362Sbenjsc m = data->m; 1765278366Sadrian data->m = m1; 1766278366Sadrian /* Update RX descriptor. */ 1767278366Sadrian ring->desc[ring->cur] = htole32(paddr); 1768278366Sadrian bus_dmamap_sync(ring->desc_dma.tag, ring->desc_dma.map, 1769278366Sadrian BUS_DMASYNC_PREWRITE); 1770278366Sadrian 1771278366Sadrian /* Finalize mbuf. */ 1772173362Sbenjsc m->m_pkthdr.rcvif = ifp; 1773173362Sbenjsc m->m_data = (caddr_t)(head + 1); 1774278366Sadrian m->m_pkthdr.len = m->m_len = len; 1775173362Sbenjsc 1776278366Sadrian /* Grab a reference to the source node. */ 1777278366Sadrian wh = mtod(m, struct ieee80211_frame *); 1778278366Sadrian ni = ieee80211_find_rxnode(ic, (struct ieee80211_frame_min *)wh); 1779173362Sbenjsc 1780278366Sadrian if (ni != NULL) 1781278366Sadrian cip = ni->ni_ucastkey.wk_cipher; 1782278366Sadrian if ((wh->i_fc[1] & IEEE80211_FC1_PROTECTED) && 1783278366Sadrian !IEEE80211_IS_MULTICAST(wh->i_addr1) && 1784278366Sadrian cip != NULL && cip->ic_cipher == IEEE80211_CIPHER_AES_CCM) { 1785278764Sadrian if ((flags & WPI_RX_CIPHER_MASK) != WPI_RX_CIPHER_CCMP) 1786278764Sadrian goto fail2; 1787278764Sadrian 1788278366Sadrian /* Check whether decryption was successful or not. */ 1789278366Sadrian if ((flags & WPI_RX_DECRYPT_MASK) != WPI_RX_DECRYPT_OK) { 1790278366Sadrian DPRINTF(sc, WPI_DEBUG_RECV, 1791278366Sadrian "CCMP decryption failed 0x%x\n", flags); 1792278764Sadrian goto fail2; 1793278366Sadrian } 1794278366Sadrian m->m_flags |= M_WEP; 1795278366Sadrian } 1796278366Sadrian 1797192468Ssam if (ieee80211_radiotap_active(ic)) { 1798173362Sbenjsc struct wpi_rx_radiotap_header *tap = &sc->sc_rxtap; 1799173362Sbenjsc 1800173362Sbenjsc tap->wr_flags = 0; 1801278366Sadrian if (head->flags & htole16(WPI_STAT_FLAG_SHPREAMBLE)) 1802278366Sadrian tap->wr_flags |= IEEE80211_RADIOTAP_F_SHORTPRE; 1803173362Sbenjsc tap->wr_dbm_antsignal = (int8_t)(stat->rssi - WPI_RSSI_OFFSET); 1804173362Sbenjsc tap->wr_dbm_antnoise = (int8_t)le16toh(stat->noise); 1805173362Sbenjsc tap->wr_tsft = tail->tstamp; 1806173362Sbenjsc tap->wr_antenna = (le16toh(head->flags) >> 4) & 0xf; 1807278366Sadrian tap->wr_rate = plcp2rate(head->plcp); 1808173362Sbenjsc } 1809173362Sbenjsc 1810173362Sbenjsc WPI_UNLOCK(sc); 1811173362Sbenjsc 1812278366Sadrian /* Send the frame to the 802.11 layer. */ 1813178354Ssam if (ni != NULL) { 1814278366Sadrian (void)ieee80211_input(ni, m, stat->rssi, -WPI_RSSI_OFFSET); 1815278366Sadrian /* Node is no longer needed. */ 1816178354Ssam ieee80211_free_node(ni); 1817178354Ssam } else 1818278366Sadrian (void)ieee80211_input_all(ic, m, stat->rssi, -WPI_RSSI_OFFSET); 1819173362Sbenjsc 1820173362Sbenjsc WPI_LOCK(sc); 1821278764Sadrian 1822278764Sadrian return; 1823278764Sadrian 1824278764Sadrianfail2: ieee80211_free_node(ni); 1825278764Sadrian m_freem(m); 1826278764Sadrian 1827278764Sadrianfail1: if_inc_counter(ifp, IFCOUNTER_IERRORS, 1); 1828173362Sbenjsc} 1829173362Sbenjsc 1830173362Sbenjscstatic void 1831278366Sadrianwpi_rx_statistics(struct wpi_softc *sc, struct wpi_rx_desc *desc, 1832278366Sadrian struct wpi_rx_data *data) 1833173362Sbenjsc{ 1834278366Sadrian /* Ignore */ 1835278366Sadrian} 1836278366Sadrian 1837278366Sadrianstatic void 1838278366Sadrianwpi_tx_done(struct wpi_softc *sc, struct wpi_rx_desc *desc) 1839278366Sadrian{ 1840178354Ssam struct ifnet *ifp = sc->sc_ifp; 1841173362Sbenjsc struct wpi_tx_ring *ring = &sc->txq[desc->qid & 0x3]; 1842278366Sadrian struct wpi_tx_data *data = &ring->data[desc->idx]; 1843173362Sbenjsc struct wpi_tx_stat *stat = (struct wpi_tx_stat *)(desc + 1); 1844278366Sadrian struct mbuf *m; 1845278366Sadrian struct ieee80211_node *ni; 1846278366Sadrian struct ieee80211vap *vap; 1847280054Sadrian int ackfailcnt = stat->ackfailcnt / 2; /* wpi_mrr_setup() */ 1848278366Sadrian int status = le32toh(stat->status); 1849173362Sbenjsc 1850278366Sadrian KASSERT(data->ni != NULL, ("no node")); 1851173362Sbenjsc 1852278366Sadrian DPRINTF(sc, WPI_DEBUG_TRACE, TRACE_STR_BEGIN, __func__); 1853278366Sadrian 1854278366Sadrian DPRINTF(sc, WPI_DEBUG_XMIT, "%s: " 1855278366Sadrian "qid %d idx %d retries %d btkillcnt %d rate %x duration %d " 1856278764Sadrian "status %x\n", __func__, desc->qid, desc->idx, ackfailcnt, 1857278366Sadrian stat->btkillcnt, stat->rate, le32toh(stat->duration), status); 1858278366Sadrian 1859278366Sadrian /* Unmap and free mbuf. */ 1860278366Sadrian bus_dmamap_sync(ring->data_dmat, data->map, BUS_DMASYNC_POSTWRITE); 1861278366Sadrian bus_dmamap_unload(ring->data_dmat, data->map); 1862278366Sadrian m = data->m, data->m = NULL; 1863278366Sadrian ni = data->ni, data->ni = NULL; 1864278366Sadrian vap = ni->ni_vap; 1865278366Sadrian 1866173362Sbenjsc /* 1867173362Sbenjsc * Update rate control statistics for the node. 1868173362Sbenjsc */ 1869278366Sadrian WPI_UNLOCK(sc); 1870278366Sadrian if ((status & 0xff) != 1) { 1871271849Sglebius if_inc_counter(ifp, IFCOUNTER_OERRORS, 1); 1872278366Sadrian ieee80211_ratectl_tx_complete(vap, ni, 1873278764Sadrian IEEE80211_RATECTL_TX_FAILURE, &ackfailcnt, NULL); 1874278366Sadrian } else { 1875271849Sglebius if_inc_counter(ifp, IFCOUNTER_OPACKETS, 1); 1876278366Sadrian ieee80211_ratectl_tx_complete(vap, ni, 1877278764Sadrian IEEE80211_RATECTL_TX_SUCCESS, &ackfailcnt, NULL); 1878278366Sadrian } 1879173362Sbenjsc 1880278366Sadrian ieee80211_tx_complete(ni, m, (status & 0xff) != 1); 1881278366Sadrian WPI_LOCK(sc); 1882173362Sbenjsc 1883278366Sadrian sc->sc_tx_timer = 0; 1884278366Sadrian if (--ring->queued < WPI_TX_RING_LOMARK) { 1885278366Sadrian sc->qfullmsk &= ~(1 << ring->qid); 1886278366Sadrian if (sc->qfullmsk == 0 && 1887278366Sadrian (ifp->if_drv_flags & IFF_DRV_OACTIVE)) { 1888278366Sadrian ifp->if_drv_flags &= ~IFF_DRV_OACTIVE; 1889278366Sadrian wpi_start_locked(ifp); 1890278366Sadrian } 1891278366Sadrian } 1892173362Sbenjsc 1893278366Sadrian DPRINTF(sc, WPI_DEBUG_TRACE, TRACE_STR_END, __func__); 1894173362Sbenjsc} 1895173362Sbenjsc 1896278366Sadrian/* 1897278366Sadrian * Process a "command done" firmware notification. This is where we wakeup 1898278366Sadrian * processes waiting for a synchronous command completion. 1899278366Sadrian */ 1900173362Sbenjscstatic void 1901278366Sadrianwpi_cmd_done(struct wpi_softc *sc, struct wpi_rx_desc *desc) 1902173362Sbenjsc{ 1903278366Sadrian struct wpi_tx_ring *ring = &sc->txq[4]; 1904173362Sbenjsc struct wpi_tx_data *data; 1905173362Sbenjsc 1906278366Sadrian DPRINTF(sc, WPI_DEBUG_CMD, "cmd notification qid=%x idx=%d flags=%x " 1907278366Sadrian "type=%s len=%d\n", desc->qid, desc->idx, 1908278366Sadrian desc->flags, wpi_cmd_str(desc->type), 1909278366Sadrian le32toh(desc->len)); 1910173362Sbenjsc 1911173362Sbenjsc if ((desc->qid & 7) != 4) 1912278366Sadrian return; /* Not a command ack. */ 1913173362Sbenjsc 1914173362Sbenjsc data = &ring->data[desc->idx]; 1915173362Sbenjsc 1916278366Sadrian /* If the command was mapped in an mbuf, free it. */ 1917173362Sbenjsc if (data->m != NULL) { 1918278366Sadrian bus_dmamap_sync(ring->data_dmat, data->map, 1919278366Sadrian BUS_DMASYNC_POSTWRITE); 1920173362Sbenjsc bus_dmamap_unload(ring->data_dmat, data->map); 1921173362Sbenjsc m_freem(data->m); 1922173362Sbenjsc data->m = NULL; 1923173362Sbenjsc } 1924173362Sbenjsc 1925173362Sbenjsc sc->flags &= ~WPI_FLAG_BUSY; 1926173362Sbenjsc wakeup(&ring->cmd[desc->idx]); 1927173362Sbenjsc} 1928173362Sbenjsc 1929173362Sbenjscstatic void 1930173362Sbenjscwpi_notif_intr(struct wpi_softc *sc) 1931173362Sbenjsc{ 1932178354Ssam struct ifnet *ifp = sc->sc_ifp; 1933178354Ssam struct ieee80211com *ic = ifp->if_l2com; 1934278366Sadrian struct ieee80211vap *vap = TAILQ_FIRST(&ic->ic_vaps); 1935278366Sadrian int hw; 1936173362Sbenjsc 1937216523Sbschmidt bus_dmamap_sync(sc->shared_dma.tag, sc->shared_dma.map, 1938216523Sbschmidt BUS_DMASYNC_POSTREAD); 1939216523Sbschmidt 1940173362Sbenjsc hw = le32toh(sc->shared->next); 1941278366Sadrian hw = (hw == 0) ? WPI_RX_RING_COUNT - 1 : hw - 1; 1942216523Sbschmidt 1943278764Sadrian while (sc->rxq.cur != hw) { 1944278366Sadrian sc->rxq.cur = (sc->rxq.cur + 1) % WPI_RX_RING_COUNT; 1945278366Sadrian 1946278366Sadrian struct wpi_rx_data *data = &sc->rxq.data[sc->rxq.cur]; 1947278366Sadrian struct wpi_rx_desc *desc; 1948278366Sadrian 1949216523Sbschmidt bus_dmamap_sync(sc->rxq.data_dmat, data->map, 1950216523Sbschmidt BUS_DMASYNC_POSTREAD); 1951278366Sadrian desc = mtod(data->m, struct wpi_rx_desc *); 1952173362Sbenjsc 1953278366Sadrian DPRINTF(sc, WPI_DEBUG_NOTIFY, 1954278366Sadrian "%s: cur=%d; qid %x idx %d flags %x type %d(%s) len %d\n", 1955278366Sadrian __func__, sc->rxq.cur, desc->qid, desc->idx, desc->flags, 1956278366Sadrian desc->type, wpi_cmd_str(desc->type), le32toh(desc->len)); 1957173362Sbenjsc 1958278366Sadrian if (!(desc->qid & 0x80)) /* Reply to a command. */ 1959278366Sadrian wpi_cmd_done(sc, desc); 1960173362Sbenjsc 1961173362Sbenjsc switch (desc->type) { 1962173362Sbenjsc case WPI_RX_DONE: 1963278366Sadrian /* An 802.11 frame has been received. */ 1964278366Sadrian wpi_rx_done(sc, desc, data); 1965280055Sadrian 1966280055Sadrian if ((ifp->if_drv_flags & IFF_DRV_RUNNING) == 0) { 1967280055Sadrian /* wpi_stop() was called. */ 1968280055Sadrian return; 1969280055Sadrian } 1970280055Sadrian 1971173362Sbenjsc break; 1972173362Sbenjsc 1973173362Sbenjsc case WPI_TX_DONE: 1974278366Sadrian /* An 802.11 frame has been transmitted. */ 1975278366Sadrian wpi_tx_done(sc, desc); 1976173362Sbenjsc break; 1977173362Sbenjsc 1978278366Sadrian case WPI_RX_STATISTICS: 1979278366Sadrian case WPI_BEACON_STATISTICS: 1980278366Sadrian wpi_rx_statistics(sc, desc, data); 1981278366Sadrian break; 1982278366Sadrian 1983278366Sadrian case WPI_BEACON_MISSED: 1984278366Sadrian { 1985278366Sadrian struct wpi_beacon_missed *miss = 1986278366Sadrian (struct wpi_beacon_missed *)(desc + 1); 1987278366Sadrian int misses; 1988278366Sadrian 1989278366Sadrian bus_dmamap_sync(sc->rxq.data_dmat, data->map, 1990278366Sadrian BUS_DMASYNC_POSTREAD); 1991278366Sadrian misses = le32toh(miss->consecutive); 1992278366Sadrian 1993278366Sadrian DPRINTF(sc, WPI_DEBUG_STATE, 1994278366Sadrian "%s: beacons missed %d/%d\n", __func__, misses, 1995278366Sadrian le32toh(miss->total)); 1996278366Sadrian 1997278366Sadrian if (vap->iv_state == IEEE80211_S_RUN && 1998280051Sadrian (ic->ic_flags & IEEE80211_F_SCAN) == 0) { 1999278366Sadrian if (misses >= vap->iv_bmissthreshold) { 2000278366Sadrian WPI_UNLOCK(sc); 2001278366Sadrian ieee80211_beacon_miss(ic); 2002278366Sadrian WPI_LOCK(sc); 2003278366Sadrian } 2004278366Sadrian } 2005278366Sadrian break; 2006278366Sadrian } 2007173362Sbenjsc case WPI_UC_READY: 2008173362Sbenjsc { 2009173362Sbenjsc struct wpi_ucode_info *uc = 2010278366Sadrian (struct wpi_ucode_info *)(desc + 1); 2011173362Sbenjsc 2012278366Sadrian /* The microcontroller is ready. */ 2013278366Sadrian bus_dmamap_sync(sc->rxq.data_dmat, data->map, 2014278366Sadrian BUS_DMASYNC_POSTREAD); 2015278366Sadrian DPRINTF(sc, WPI_DEBUG_RESET, 2016278366Sadrian "microcode alive notification version=%d.%d " 2017278366Sadrian "subtype=%x alive=%x\n", uc->major, uc->minor, 2018278366Sadrian uc->subtype, le32toh(uc->valid)); 2019173362Sbenjsc 2020173362Sbenjsc if (le32toh(uc->valid) != 1) { 2021173362Sbenjsc device_printf(sc->sc_dev, 2022173362Sbenjsc "microcontroller initialization failed\n"); 2023173362Sbenjsc wpi_stop_locked(sc); 2024173362Sbenjsc } 2025278366Sadrian /* Save the address of the error log in SRAM. */ 2026278366Sadrian sc->errptr = le32toh(uc->errptr); 2027173362Sbenjsc break; 2028173362Sbenjsc } 2029173362Sbenjsc case WPI_STATE_CHANGED: 2030173362Sbenjsc { 2031278366Sadrian bus_dmamap_sync(sc->rxq.data_dmat, data->map, 2032278366Sadrian BUS_DMASYNC_POSTREAD); 2033278366Sadrian 2034173362Sbenjsc uint32_t *status = (uint32_t *)(desc + 1); 2035278764Sadrian 2036278366Sadrian DPRINTF(sc, WPI_DEBUG_STATE, "state changed to %x\n", 2037278366Sadrian le32toh(*status)); 2038278764Sadrian 2039173362Sbenjsc if (le32toh(*status) & 1) { 2040278366Sadrian ieee80211_runtask(ic, &sc->sc_radiooff_task); 2041278366Sadrian return; 2042173362Sbenjsc } 2043173362Sbenjsc break; 2044173362Sbenjsc } 2045173362Sbenjsc case WPI_START_SCAN: 2046173362Sbenjsc { 2047278366Sadrian bus_dmamap_sync(sc->rxq.data_dmat, data->map, 2048278366Sadrian BUS_DMASYNC_POSTREAD); 2049179957Sthompsa#ifdef WPI_DEBUG 2050173362Sbenjsc struct wpi_start_scan *scan = 2051278366Sadrian (struct wpi_start_scan *)(desc + 1); 2052278366Sadrian DPRINTF(sc, WPI_DEBUG_SCAN, 2053278366Sadrian "%s: scanning channel %d status %x\n", 2054278366Sadrian __func__, scan->chan, le32toh(scan->status)); 2055179957Sthompsa#endif 2056173362Sbenjsc break; 2057173362Sbenjsc } 2058173362Sbenjsc case WPI_STOP_SCAN: 2059173362Sbenjsc { 2060278366Sadrian bus_dmamap_sync(sc->rxq.data_dmat, data->map, 2061278366Sadrian BUS_DMASYNC_POSTREAD); 2062179957Sthompsa#ifdef WPI_DEBUG 2063173362Sbenjsc struct wpi_stop_scan *scan = 2064278366Sadrian (struct wpi_stop_scan *)(desc + 1); 2065278366Sadrian DPRINTF(sc, WPI_DEBUG_SCAN, 2066278366Sadrian "scan finished nchan=%d status=%d chan=%d\n", 2067278366Sadrian scan->nchan, scan->status, scan->chan); 2068179957Sthompsa#endif 2069177043Sthompsa sc->sc_scan_timer = 0; 2070278366Sadrian WPI_UNLOCK(sc); 2071178354Ssam ieee80211_scan_next(vap); 2072278366Sadrian WPI_LOCK(sc); 2073173362Sbenjsc break; 2074173362Sbenjsc } 2075278366Sadrian } 2076278764Sadrian } 2077173976Sbenjsc 2078278366Sadrian /* Tell the firmware what we have processed. */ 2079278366Sadrian wpi_update_rx_ring(sc); 2080278366Sadrian} 2081278366Sadrian 2082278366Sadrian/* 2083278366Sadrian * Process an INT_WAKEUP interrupt raised when the microcontroller wakes up 2084278366Sadrian * from power-down sleep mode. 2085278366Sadrian */ 2086278366Sadrianstatic void 2087278366Sadrianwpi_wakeup_intr(struct wpi_softc *sc) 2088278366Sadrian{ 2089278366Sadrian int qid; 2090278366Sadrian 2091278366Sadrian DPRINTF(sc, WPI_DEBUG_PWRSAVE, 2092278366Sadrian "%s: ucode wakeup from power-down sleep\n", __func__); 2093278366Sadrian 2094278366Sadrian /* Wakeup RX and TX rings. */ 2095278366Sadrian if (sc->rxq.update) { 2096278764Sadrian sc->rxq.update = 0; 2097278366Sadrian wpi_update_rx_ring(sc); 2098278366Sadrian } 2099278366Sadrian for (qid = 0; qid < WPI_NTXQUEUES; qid++) { 2100278366Sadrian struct wpi_tx_ring *ring = &sc->txq[qid]; 2101278366Sadrian 2102278366Sadrian if (ring->update) { 2103278764Sadrian ring->update = 0; 2104278366Sadrian wpi_update_tx_ring(sc, ring); 2105173362Sbenjsc } 2106278366Sadrian } 2107173362Sbenjsc 2108278366Sadrian WPI_CLRBITS(sc, WPI_GP_CNTRL, WPI_GP_CNTRL_MAC_ACCESS_REQ); 2109278366Sadrian} 2110278366Sadrian 2111278366Sadrian/* 2112278366Sadrian * Dump the error log of the firmware when a firmware panic occurs. Although 2113278366Sadrian * we can't debug the firmware because it is neither open source nor free, it 2114278366Sadrian * can help us to identify certain classes of problems. 2115278366Sadrian */ 2116278366Sadrianstatic void 2117278366Sadrianwpi_fatal_intr(struct wpi_softc *sc) 2118278366Sadrian{ 2119278366Sadrian struct wpi_fw_dump dump; 2120278366Sadrian uint32_t i, offset, count; 2121278366Sadrian const uint32_t size_errmsg = 2122278366Sadrian (sizeof (wpi_fw_errmsg) / sizeof ((wpi_fw_errmsg)[0])); 2123278366Sadrian 2124278366Sadrian /* Check that the error log address is valid. */ 2125278366Sadrian if (sc->errptr < WPI_FW_DATA_BASE || 2126278366Sadrian sc->errptr + sizeof (dump) > 2127278366Sadrian WPI_FW_DATA_BASE + WPI_FW_DATA_MAXSZ) { 2128278366Sadrian printf("%s: bad firmware error log address 0x%08x\n", __func__, 2129278366Sadrian sc->errptr); 2130278366Sadrian return; 2131278366Sadrian } 2132278366Sadrian if (wpi_nic_lock(sc) != 0) { 2133278366Sadrian printf("%s: could not read firmware error log\n", __func__); 2134278366Sadrian return; 2135278366Sadrian } 2136278366Sadrian /* Read number of entries in the log. */ 2137278366Sadrian count = wpi_mem_read(sc, sc->errptr); 2138278366Sadrian if (count == 0 || count * sizeof (dump) > WPI_FW_DATA_MAXSZ) { 2139278366Sadrian printf("%s: invalid count field (count = %u)\n", __func__, 2140278366Sadrian count); 2141278366Sadrian wpi_nic_unlock(sc); 2142278366Sadrian return; 2143173362Sbenjsc } 2144278366Sadrian /* Skip "count" field. */ 2145278366Sadrian offset = sc->errptr + sizeof (uint32_t); 2146278366Sadrian printf("firmware error log (count = %u):\n", count); 2147278366Sadrian for (i = 0; i < count; i++) { 2148278366Sadrian wpi_mem_read_region_4(sc, offset, (uint32_t *)&dump, 2149278366Sadrian sizeof (dump) / sizeof (uint32_t)); 2150173362Sbenjsc 2151278366Sadrian printf(" error type = \"%s\" (0x%08X)\n", 2152278366Sadrian (dump.desc < size_errmsg) ? 2153278366Sadrian wpi_fw_errmsg[dump.desc] : "UNKNOWN", 2154278366Sadrian dump.desc); 2155278366Sadrian printf(" error data = 0x%08X\n", 2156278366Sadrian dump.data); 2157278366Sadrian printf(" branch link = 0x%08X%08X\n", 2158278366Sadrian dump.blink[0], dump.blink[1]); 2159278366Sadrian printf(" interrupt link = 0x%08X%08X\n", 2160278366Sadrian dump.ilink[0], dump.ilink[1]); 2161278366Sadrian printf(" time = %u\n", dump.time); 2162278366Sadrian 2163278366Sadrian offset += sizeof (dump); 2164278366Sadrian } 2165278366Sadrian wpi_nic_unlock(sc); 2166278366Sadrian /* Dump driver status (TX and RX rings) while we're here. */ 2167278366Sadrian printf("driver status:\n"); 2168278366Sadrian for (i = 0; i < WPI_NTXQUEUES; i++) { 2169278366Sadrian struct wpi_tx_ring *ring = &sc->txq[i]; 2170278366Sadrian printf(" tx ring %2d: qid=%-2d cur=%-3d queued=%-3d\n", 2171278366Sadrian i, ring->qid, ring->cur, ring->queued); 2172278366Sadrian } 2173278366Sadrian printf(" rx ring: cur=%d\n", sc->rxq.cur); 2174173362Sbenjsc} 2175173362Sbenjsc 2176173362Sbenjscstatic void 2177173362Sbenjscwpi_intr(void *arg) 2178173362Sbenjsc{ 2179173362Sbenjsc struct wpi_softc *sc = arg; 2180278366Sadrian struct ifnet *ifp = sc->sc_ifp; 2181278366Sadrian uint32_t r1, r2; 2182173362Sbenjsc 2183173362Sbenjsc WPI_LOCK(sc); 2184173362Sbenjsc 2185278366Sadrian /* Disable interrupts. */ 2186278366Sadrian WPI_WRITE(sc, WPI_INT_MASK, 0); 2187278366Sadrian 2188278366Sadrian r1 = WPI_READ(sc, WPI_INT); 2189278366Sadrian 2190278366Sadrian if (r1 == 0xffffffff || (r1 & 0xfffffff0) == 0xa5a5a5a0) { 2191173362Sbenjsc WPI_UNLOCK(sc); 2192278366Sadrian return; /* Hardware gone! */ 2193173362Sbenjsc } 2194173362Sbenjsc 2195278366Sadrian r2 = WPI_READ(sc, WPI_FH_INT); 2196173362Sbenjsc 2197278366Sadrian DPRINTF(sc, WPI_DEBUG_INTR, "%s: reg1=0x%08x reg2=0x%08x\n", __func__, 2198278366Sadrian r1, r2); 2199278366Sadrian 2200278366Sadrian if (r1 == 0 && r2 == 0) 2201278366Sadrian goto done; /* Interrupt not for us. */ 2202278366Sadrian 2203278366Sadrian /* Acknowledge interrupts. */ 2204278366Sadrian WPI_WRITE(sc, WPI_INT, r1); 2205278366Sadrian WPI_WRITE(sc, WPI_FH_INT, r2); 2206278366Sadrian 2207278366Sadrian if (r1 & (WPI_INT_SW_ERR | WPI_INT_HW_ERR)) { 2208191746Sthompsa struct ieee80211com *ic = ifp->if_l2com; 2209191746Sthompsa 2210173362Sbenjsc device_printf(sc->sc_dev, "fatal firmware error\n"); 2211278366Sadrian wpi_fatal_intr(sc); 2212278366Sadrian DPRINTF(sc, WPI_DEBUG_HW, 2213278366Sadrian "(%s)\n", (r1 & WPI_INT_SW_ERR) ? "(Software Error)" : 2214278366Sadrian "(Hardware Error)"); 2215278366Sadrian ieee80211_runtask(ic, &sc->sc_reinittask); 2216173362Sbenjsc sc->flags &= ~WPI_FLAG_BUSY; 2217173362Sbenjsc WPI_UNLOCK(sc); 2218173362Sbenjsc return; 2219173362Sbenjsc } 2220173362Sbenjsc 2221278366Sadrian if ((r1 & (WPI_INT_FH_RX | WPI_INT_SW_RX)) || 2222278366Sadrian (r2 & WPI_FH_INT_RX)) 2223173362Sbenjsc wpi_notif_intr(sc); 2224173362Sbenjsc 2225278366Sadrian if (r1 & WPI_INT_ALIVE) 2226278366Sadrian wakeup(sc); /* Firmware is alive. */ 2227173362Sbenjsc 2228278366Sadrian if (r1 & WPI_INT_WAKEUP) 2229278366Sadrian wpi_wakeup_intr(sc); 2230173362Sbenjsc 2231278366Sadriandone: 2232278366Sadrian /* Re-enable interrupts. */ 2233278366Sadrian if (ifp->if_flags & IFF_UP) 2234278366Sadrian WPI_WRITE(sc, WPI_INT_MASK, WPI_INT_MASK_DEF); 2235278366Sadrian 2236173362Sbenjsc WPI_UNLOCK(sc); 2237173362Sbenjsc} 2238173362Sbenjsc 2239278366Sadrianstatic int 2240278366Sadrianwpi_cmd2(struct wpi_softc *sc, struct wpi_buf *buf) 2241173362Sbenjsc{ 2242278366Sadrian struct ieee80211_frame *wh; 2243278366Sadrian struct wpi_tx_cmd *cmd; 2244278366Sadrian struct wpi_tx_data *data; 2245278366Sadrian struct wpi_tx_desc *desc; 2246278366Sadrian struct wpi_tx_ring *ring; 2247278366Sadrian struct mbuf *m1; 2248278366Sadrian bus_dma_segment_t *seg, segs[WPI_MAX_SCATTER]; 2249279763Sadrian int error, i, hdrlen, nsegs, totlen, pad; 2250173362Sbenjsc 2251278366Sadrian WPI_LOCK_ASSERT(sc); 2252173362Sbenjsc 2253278366Sadrian DPRINTF(sc, WPI_DEBUG_TRACE, TRACE_STR_BEGIN, __func__); 2254278366Sadrian 2255278366Sadrian wh = mtod(buf->m, struct ieee80211_frame *); 2256279763Sadrian hdrlen = ieee80211_anyhdrsize(wh); 2257278366Sadrian totlen = buf->m->m_pkthdr.len; 2258278366Sadrian 2259279763Sadrian if (hdrlen & 3) { 2260279763Sadrian /* First segment length must be a multiple of 4. */ 2261279763Sadrian pad = 4 - (hdrlen & 3); 2262279763Sadrian } else 2263279763Sadrian pad = 0; 2264279763Sadrian 2265278366Sadrian ring = &sc->txq[buf->ac]; 2266278366Sadrian desc = &ring->desc[ring->cur]; 2267278366Sadrian data = &ring->data[ring->cur]; 2268278366Sadrian 2269278366Sadrian /* Prepare TX firmware command. */ 2270278366Sadrian cmd = &ring->cmd[ring->cur]; 2271278366Sadrian cmd->code = buf->code; 2272278366Sadrian cmd->flags = 0; 2273278366Sadrian cmd->qid = ring->qid; 2274278366Sadrian cmd->idx = ring->cur; 2275278366Sadrian 2276278366Sadrian memcpy(cmd->data, buf->data, buf->size); 2277278366Sadrian 2278278366Sadrian /* Save and trim IEEE802.11 header. */ 2279279763Sadrian memcpy((uint8_t *)(cmd->data + buf->size), wh, hdrlen); 2280279763Sadrian m_adj(buf->m, hdrlen); 2281278366Sadrian 2282278366Sadrian error = bus_dmamap_load_mbuf_sg(ring->data_dmat, data->map, buf->m, 2283278366Sadrian segs, &nsegs, BUS_DMA_NOWAIT); 2284278366Sadrian if (error != 0 && error != EFBIG) { 2285278366Sadrian device_printf(sc->sc_dev, 2286278366Sadrian "%s: can't map mbuf (error %d)\n", __func__, error); 2287278366Sadrian m_freem(buf->m); 2288278366Sadrian return error; 2289173362Sbenjsc } 2290278366Sadrian if (error != 0) { 2291278366Sadrian /* Too many DMA segments, linearize mbuf. */ 2292280050Sadrian m1 = m_collapse(buf->m, M_NOWAIT, WPI_MAX_SCATTER - 1); 2293278366Sadrian if (m1 == NULL) { 2294278366Sadrian device_printf(sc->sc_dev, 2295278366Sadrian "%s: could not defrag mbuf\n", __func__); 2296278366Sadrian m_freem(buf->m); 2297278366Sadrian return ENOBUFS; 2298278366Sadrian } 2299278366Sadrian buf->m = m1; 2300278366Sadrian 2301278366Sadrian error = bus_dmamap_load_mbuf_sg(ring->data_dmat, data->map, 2302278366Sadrian buf->m, segs, &nsegs, BUS_DMA_NOWAIT); 2303278366Sadrian if (error != 0) { 2304278366Sadrian device_printf(sc->sc_dev, 2305278366Sadrian "%s: can't map mbuf (error %d)\n", __func__, error); 2306278366Sadrian m_freem(buf->m); 2307278366Sadrian return error; 2308278366Sadrian } 2309278366Sadrian } 2310278366Sadrian 2311280050Sadrian KASSERT(nsegs < WPI_MAX_SCATTER, 2312280050Sadrian ("too many DMA segments, nsegs (%d) should be less than %d", 2313280050Sadrian nsegs, WPI_MAX_SCATTER)); 2314280050Sadrian 2315278366Sadrian data->m = buf->m; 2316278366Sadrian data->ni = buf->ni; 2317278366Sadrian 2318278366Sadrian DPRINTF(sc, WPI_DEBUG_XMIT, "%s: qid %d idx %d len %d nsegs %d\n", 2319278366Sadrian __func__, ring->qid, ring->cur, totlen, nsegs); 2320278366Sadrian 2321278366Sadrian /* Fill TX descriptor. */ 2322279763Sadrian desc->nsegs = WPI_PAD32(totlen + pad) << 4 | (1 + nsegs); 2323278366Sadrian /* First DMA segment is used by the TX command. */ 2324278366Sadrian desc->segs[0].addr = htole32(data->cmd_paddr); 2325279763Sadrian desc->segs[0].len = htole32(4 + buf->size + hdrlen + pad); 2326278366Sadrian /* Other DMA segments are for data payload. */ 2327278366Sadrian seg = &segs[0]; 2328278366Sadrian for (i = 1; i <= nsegs; i++) { 2329278366Sadrian desc->segs[i].addr = htole32(seg->ds_addr); 2330278366Sadrian desc->segs[i].len = htole32(seg->ds_len); 2331278366Sadrian seg++; 2332278366Sadrian } 2333278366Sadrian 2334278366Sadrian bus_dmamap_sync(ring->data_dmat, data->map, BUS_DMASYNC_PREWRITE); 2335278366Sadrian bus_dmamap_sync(ring->data_dmat, ring->cmd_dma.map, 2336278366Sadrian BUS_DMASYNC_PREWRITE); 2337278366Sadrian bus_dmamap_sync(ring->desc_dma.tag, ring->desc_dma.map, 2338278366Sadrian BUS_DMASYNC_PREWRITE); 2339278366Sadrian 2340278366Sadrian /* Kick TX ring. */ 2341278366Sadrian ring->cur = (ring->cur + 1) % WPI_TX_RING_COUNT; 2342278366Sadrian wpi_update_tx_ring(sc, ring); 2343278366Sadrian 2344278366Sadrian /* Mark TX ring as full if we reach a certain threshold. */ 2345278366Sadrian if (++ring->queued > WPI_TX_RING_HIMARK) 2346278366Sadrian sc->qfullmsk |= 1 << ring->qid; 2347278366Sadrian 2348278366Sadrian DPRINTF(sc, WPI_DEBUG_TRACE, TRACE_STR_END, __func__); 2349278366Sadrian 2350278366Sadrian return 0; 2351173362Sbenjsc} 2352173362Sbenjsc 2353173362Sbenjsc/* 2354278366Sadrian * Construct the data packet for a transmit buffer. 2355173362Sbenjsc */ 2356173362Sbenjscstatic int 2357278366Sadrianwpi_tx_data(struct wpi_softc *sc, struct mbuf *m, struct ieee80211_node *ni) 2358173362Sbenjsc{ 2359278366Sadrian const struct ieee80211_txparam *tp; 2360178354Ssam struct ieee80211vap *vap = ni->ni_vap; 2361278366Sadrian struct ieee80211com *ic = ni->ni_ic; 2362278366Sadrian struct wpi_node *wn = (void *)ni; 2363278366Sadrian struct ieee80211_channel *chan; 2364173362Sbenjsc struct ieee80211_frame *wh; 2365278366Sadrian struct ieee80211_key *k = NULL; 2366278366Sadrian struct wpi_cmd_data tx; 2367278366Sadrian struct wpi_buf tx_data; 2368278366Sadrian uint32_t flags; 2369278366Sadrian uint16_t qos; 2370278366Sadrian uint8_t tid, type; 2371279763Sadrian int ac, error, rate, ismcast, totlen; 2372173362Sbenjsc 2373278366Sadrian wh = mtod(m, struct ieee80211_frame *); 2374278366Sadrian type = wh->i_fc[0] & IEEE80211_FC0_TYPE_MASK; 2375278366Sadrian ismcast = IEEE80211_IS_MULTICAST(wh->i_addr1); 2376173362Sbenjsc 2377278366Sadrian /* Select EDCA Access Category and TX ring for this frame. */ 2378278366Sadrian if (IEEE80211_QOS_HAS_SEQ(wh)) { 2379278366Sadrian qos = ((const struct ieee80211_qosframe *)wh)->i_qos[0]; 2380278366Sadrian tid = qos & IEEE80211_QOS_TID; 2381278366Sadrian } else { 2382278366Sadrian qos = 0; 2383278366Sadrian tid = 0; 2384278366Sadrian } 2385278366Sadrian ac = M_WME_GETAC(m); 2386173362Sbenjsc 2387278366Sadrian chan = (ni->ni_chan != IEEE80211_CHAN_ANYC) ? 2388278366Sadrian ni->ni_chan : ic->ic_curchan; 2389278366Sadrian tp = &vap->iv_txparms[ieee80211_chan2mode(chan)]; 2390173362Sbenjsc 2391278366Sadrian /* Choose a TX rate index. */ 2392278366Sadrian if (type == IEEE80211_FC0_TYPE_MGT) 2393278366Sadrian rate = tp->mgmtrate; 2394278366Sadrian else if (ismcast) 2395278366Sadrian rate = tp->mcastrate; 2396278366Sadrian else if (tp->ucastrate != IEEE80211_FIXED_RATE_NONE) 2397278366Sadrian rate = tp->ucastrate; 2398278366Sadrian else if (m->m_flags & M_EAPOL) 2399278366Sadrian rate = tp->mgmtrate; 2400278366Sadrian else { 2401278366Sadrian /* XXX pass pktlen */ 2402278366Sadrian (void) ieee80211_ratectl_rate(ni, NULL, 0); 2403278366Sadrian rate = ni->ni_txrate; 2404278366Sadrian } 2405278366Sadrian 2406278366Sadrian /* Encrypt the frame if need be. */ 2407260444Skevlo if (wh->i_fc[1] & IEEE80211_FC1_PROTECTED) { 2408278366Sadrian /* Retrieve key for TX. */ 2409278366Sadrian k = ieee80211_crypto_encap(ni, m); 2410177043Sthompsa if (k == NULL) { 2411278366Sadrian error = ENOBUFS; 2412278366Sadrian goto fail; 2413173362Sbenjsc } 2414278366Sadrian /* 802.11 header may have moved. */ 2415278366Sadrian wh = mtod(m, struct ieee80211_frame *); 2416173362Sbenjsc } 2417279763Sadrian totlen = m->m_pkthdr.len; 2418173362Sbenjsc 2419278366Sadrian if (ieee80211_radiotap_active_vap(vap)) { 2420278366Sadrian struct wpi_tx_radiotap_header *tap = &sc->sc_txtap; 2421173362Sbenjsc 2422279763Sadrian tap->wt_flags = 0; 2423278366Sadrian tap->wt_rate = rate; 2424278366Sadrian if (k != NULL) 2425278366Sadrian tap->wt_flags |= IEEE80211_RADIOTAP_F_WEP; 2426173362Sbenjsc 2427278366Sadrian ieee80211_radiotap_tx(vap, m); 2428278366Sadrian } 2429278366Sadrian 2430278366Sadrian flags = 0; 2431177119Ssam if (!ismcast) { 2432278366Sadrian /* Unicast frame, check if an ACK is expected. */ 2433278366Sadrian if (!qos || (qos & IEEE80211_QOS_ACKPOLICY) != 2434278366Sadrian IEEE80211_QOS_ACKPOLICY_NOACK) 2435278366Sadrian flags |= WPI_TX_NEED_ACK; 2436278366Sadrian } 2437278366Sadrian 2438278764Sadrian if (wh->i_fc[1] & IEEE80211_FC1_MORE_FRAG) 2439278764Sadrian flags |= WPI_TX_MORE_FRAG; /* Cannot happen yet. */ 2440278764Sadrian 2441278366Sadrian /* Check if frame must be protected using RTS/CTS or CTS-to-self. */ 2442278366Sadrian if (!ismcast) { 2443278366Sadrian /* NB: Group frames are sent using CCK in 802.11b/g. */ 2444278366Sadrian if (totlen + IEEE80211_CRC_LEN > vap->iv_rtsthreshold) { 2445278366Sadrian flags |= WPI_TX_NEED_RTS; 2446278366Sadrian } else if ((ic->ic_flags & IEEE80211_F_USEPROT) && 2447278366Sadrian WPI_RATE_IS_OFDM(rate)) { 2448278366Sadrian if (ic->ic_protmode == IEEE80211_PROT_CTSONLY) 2449278366Sadrian flags |= WPI_TX_NEED_CTS; 2450278366Sadrian else if (ic->ic_protmode == IEEE80211_PROT_RTSCTS) 2451278366Sadrian flags |= WPI_TX_NEED_RTS; 2452177043Sthompsa } 2453278366Sadrian 2454278366Sadrian if (flags & (WPI_TX_NEED_RTS | WPI_TX_NEED_CTS)) 2455278366Sadrian flags |= WPI_TX_FULL_TXOP; 2456173362Sbenjsc } 2457278366Sadrian 2458278366Sadrian memset(&tx, 0, sizeof (struct wpi_cmd_data)); 2459278366Sadrian if (type == IEEE80211_FC0_TYPE_MGT) { 2460173362Sbenjsc uint8_t subtype = wh->i_fc[0] & IEEE80211_FC0_SUBTYPE_MASK; 2461278366Sadrian 2462278366Sadrian /* Tell HW to set timestamp in probe responses. */ 2463173362Sbenjsc if (subtype == IEEE80211_FC0_SUBTYPE_PROBE_RESP) 2464278366Sadrian flags |= WPI_TX_INSERT_TSTAMP; 2465173362Sbenjsc if (subtype == IEEE80211_FC0_SUBTYPE_ASSOC_REQ || 2466177043Sthompsa subtype == IEEE80211_FC0_SUBTYPE_REASSOC_REQ) 2467278366Sadrian tx.timeout = htole16(3); 2468173362Sbenjsc else 2469278366Sadrian tx.timeout = htole16(2); 2470177043Sthompsa } 2471173362Sbenjsc 2472278366Sadrian if (ismcast || type != IEEE80211_FC0_TYPE_DATA) 2473278366Sadrian tx.id = WPI_ID_BROADCAST; 2474278366Sadrian else { 2475278366Sadrian if (wn->id == WPI_ID_UNDEFINED && 2476278366Sadrian (vap->iv_opmode == IEEE80211_M_IBSS || 2477278366Sadrian vap->iv_opmode == IEEE80211_M_AHDEMO)) { 2478278366Sadrian error = wpi_add_ibss_node(sc, ni); 2479278366Sadrian if (error != 0) { 2480278366Sadrian device_printf(sc->sc_dev, 2481278366Sadrian "%s: could not add IBSS node, error %d\n", 2482278366Sadrian __func__, error); 2483278366Sadrian goto fail; 2484278366Sadrian } 2485278366Sadrian } 2486173362Sbenjsc 2487278366Sadrian if (wn->id == WPI_ID_UNDEFINED) { 2488278366Sadrian device_printf(sc->sc_dev, 2489278366Sadrian "%s: undefined node id\n", __func__); 2490278366Sadrian error = EINVAL; 2491278366Sadrian goto fail; 2492278366Sadrian } 2493278366Sadrian 2494278366Sadrian tx.id = wn->id; 2495278366Sadrian } 2496278366Sadrian 2497278366Sadrian if (type != IEEE80211_FC0_TYPE_MGT) 2498278366Sadrian tx.data_ntries = tp->maxretry; 2499278366Sadrian 2500278366Sadrian tx.len = htole16(totlen); 2501278366Sadrian tx.flags = htole32(flags); 2502278366Sadrian tx.plcp = rate2plcp(rate); 2503278366Sadrian tx.tid = tid; 2504278366Sadrian tx.lifetime = htole32(WPI_LIFETIME_INFINITE); 2505278366Sadrian tx.ofdm_mask = 0xff; 2506278366Sadrian tx.cck_mask = 0x0f; 2507278366Sadrian tx.rts_ntries = 7; 2508278366Sadrian 2509278366Sadrian if (k != NULL && k->wk_cipher->ic_cipher == IEEE80211_CIPHER_AES_CCM) { 2510278366Sadrian if (!(k->wk_flags & IEEE80211_KEY_SWCRYPT)) { 2511278366Sadrian tx.security = WPI_CIPHER_CCMP; 2512278366Sadrian memcpy(tx.key, k->wk_key, k->wk_keylen); 2513278366Sadrian } 2514278366Sadrian } 2515278366Sadrian 2516278366Sadrian tx_data.data = &tx; 2517278366Sadrian tx_data.ni = ni; 2518278366Sadrian tx_data.m = m; 2519278366Sadrian tx_data.size = sizeof(tx); 2520278366Sadrian tx_data.code = WPI_CMD_TX_DATA; 2521278366Sadrian tx_data.ac = ac; 2522278366Sadrian 2523278366Sadrian return wpi_cmd2(sc, &tx_data); 2524278366Sadrian 2525278366Sadrianfail: m_freem(m); 2526278366Sadrian return error; 2527278366Sadrian} 2528278366Sadrian 2529278366Sadrianstatic int 2530278366Sadrianwpi_tx_data_raw(struct wpi_softc *sc, struct mbuf *m, struct ieee80211_node *ni, 2531278366Sadrian const struct ieee80211_bpf_params *params) 2532278366Sadrian{ 2533278366Sadrian struct ieee80211vap *vap = ni->ni_vap; 2534278366Sadrian struct ieee80211_frame *wh; 2535278366Sadrian struct wpi_cmd_data tx; 2536278366Sadrian struct wpi_buf tx_data; 2537278366Sadrian uint32_t flags; 2538278366Sadrian uint8_t type; 2539279763Sadrian int ac, rate, totlen; 2540278366Sadrian 2541278366Sadrian wh = mtod(m, struct ieee80211_frame *); 2542278366Sadrian type = wh->i_fc[0] & IEEE80211_FC0_TYPE_MASK; 2543279763Sadrian totlen = m->m_pkthdr.len; 2544278366Sadrian 2545278366Sadrian ac = params->ibp_pri & 3; 2546278366Sadrian 2547278366Sadrian /* Choose a TX rate index. */ 2548278366Sadrian rate = params->ibp_rate0; 2549278366Sadrian 2550278366Sadrian flags = 0; 2551278366Sadrian if ((params->ibp_flags & IEEE80211_BPF_NOACK) == 0) 2552278366Sadrian flags |= WPI_TX_NEED_ACK; 2553278366Sadrian if (params->ibp_flags & IEEE80211_BPF_RTS) 2554278366Sadrian flags |= WPI_TX_NEED_RTS; 2555278366Sadrian if (params->ibp_flags & IEEE80211_BPF_CTS) 2556278366Sadrian flags |= WPI_TX_NEED_CTS; 2557278366Sadrian if (flags & (WPI_TX_NEED_RTS | WPI_TX_NEED_CTS)) 2558278366Sadrian flags |= WPI_TX_FULL_TXOP; 2559278366Sadrian 2560192468Ssam if (ieee80211_radiotap_active_vap(vap)) { 2561177043Sthompsa struct wpi_tx_radiotap_header *tap = &sc->sc_txtap; 2562278366Sadrian 2563177043Sthompsa tap->wt_flags = 0; 2564177043Sthompsa tap->wt_rate = rate; 2565178354Ssam 2566278366Sadrian ieee80211_radiotap_tx(vap, m); 2567177043Sthompsa } 2568173362Sbenjsc 2569278366Sadrian memset(&tx, 0, sizeof (struct wpi_cmd_data)); 2570278366Sadrian if (type == IEEE80211_FC0_TYPE_MGT) { 2571278366Sadrian uint8_t subtype = wh->i_fc[0] & IEEE80211_FC0_SUBTYPE_MASK; 2572173362Sbenjsc 2573278366Sadrian /* Tell HW to set timestamp in probe responses. */ 2574278366Sadrian if (subtype == IEEE80211_FC0_SUBTYPE_PROBE_RESP) 2575278366Sadrian flags |= WPI_TX_INSERT_TSTAMP; 2576278366Sadrian if (subtype == IEEE80211_FC0_SUBTYPE_ASSOC_REQ || 2577278366Sadrian subtype == IEEE80211_FC0_SUBTYPE_REASSOC_REQ) 2578278366Sadrian tx.timeout = htole16(3); 2579278366Sadrian else 2580278366Sadrian tx.timeout = htole16(2); 2581173362Sbenjsc } 2582173362Sbenjsc 2583278366Sadrian tx.len = htole16(totlen); 2584278366Sadrian tx.flags = htole32(flags); 2585278366Sadrian tx.plcp = rate2plcp(rate); 2586278366Sadrian tx.id = WPI_ID_BROADCAST; 2587278366Sadrian tx.lifetime = htole32(WPI_LIFETIME_INFINITE); 2588278366Sadrian tx.rts_ntries = params->ibp_try1; 2589278366Sadrian tx.data_ntries = params->ibp_try0; 2590278366Sadrian 2591278366Sadrian tx_data.data = &tx; 2592278366Sadrian tx_data.ni = ni; 2593278366Sadrian tx_data.m = m; 2594278366Sadrian tx_data.size = sizeof(tx); 2595278366Sadrian tx_data.code = WPI_CMD_TX_DATA; 2596278366Sadrian tx_data.ac = ac; 2597278366Sadrian 2598278366Sadrian return wpi_cmd2(sc, &tx_data); 2599278366Sadrian} 2600278366Sadrian 2601278366Sadrianstatic int 2602278366Sadrianwpi_raw_xmit(struct ieee80211_node *ni, struct mbuf *m, 2603278366Sadrian const struct ieee80211_bpf_params *params) 2604278366Sadrian{ 2605278366Sadrian struct ieee80211com *ic = ni->ni_ic; 2606278366Sadrian struct ifnet *ifp = ic->ic_ifp; 2607278366Sadrian struct wpi_softc *sc = ifp->if_softc; 2608278366Sadrian int error = 0; 2609278366Sadrian 2610278366Sadrian DPRINTF(sc, WPI_DEBUG_TRACE, TRACE_STR_BEGIN, __func__); 2611278366Sadrian 2612278366Sadrian if ((ifp->if_drv_flags & IFF_DRV_RUNNING) == 0) { 2613278366Sadrian ieee80211_free_node(ni); 2614278366Sadrian m_freem(m); 2615278366Sadrian return ENETDOWN; 2616173362Sbenjsc } 2617173362Sbenjsc 2618278366Sadrian WPI_LOCK(sc); 2619278366Sadrian if (params == NULL) { 2620278366Sadrian /* 2621278366Sadrian * Legacy path; interpret frame contents to decide 2622278366Sadrian * precisely how to send the frame. 2623278366Sadrian */ 2624278366Sadrian error = wpi_tx_data(sc, m, ni); 2625278366Sadrian } else { 2626278366Sadrian /* 2627278366Sadrian * Caller supplied explicit parameters to use in 2628278366Sadrian * sending the frame. 2629278366Sadrian */ 2630278366Sadrian error = wpi_tx_data_raw(sc, m, ni, params); 2631278366Sadrian } 2632278366Sadrian WPI_UNLOCK(sc); 2633173362Sbenjsc 2634278366Sadrian if (error != 0) { 2635278366Sadrian /* NB: m is reclaimed on tx failure */ 2636278366Sadrian ieee80211_free_node(ni); 2637278366Sadrian if_inc_counter(ifp, IFCOUNTER_OERRORS, 1); 2638173362Sbenjsc 2639278366Sadrian DPRINTF(sc, WPI_DEBUG_TRACE, TRACE_STR_END_ERR, __func__); 2640278366Sadrian 2641278366Sadrian return error; 2642173362Sbenjsc } 2643173362Sbenjsc 2644278366Sadrian sc->sc_tx_timer = 5; 2645173362Sbenjsc 2646278366Sadrian DPRINTF(sc, WPI_DEBUG_TRACE, TRACE_STR_END, __func__); 2647173362Sbenjsc 2648173362Sbenjsc return 0; 2649173362Sbenjsc} 2650173362Sbenjsc 2651173362Sbenjsc/** 2652173362Sbenjsc * Process data waiting to be sent on the IFNET output queue 2653173362Sbenjsc */ 2654173362Sbenjscstatic void 2655173362Sbenjscwpi_start(struct ifnet *ifp) 2656173362Sbenjsc{ 2657173362Sbenjsc struct wpi_softc *sc = ifp->if_softc; 2658178354Ssam 2659178354Ssam WPI_LOCK(sc); 2660178354Ssam wpi_start_locked(ifp); 2661178354Ssam WPI_UNLOCK(sc); 2662178354Ssam} 2663178354Ssam 2664178354Ssamstatic void 2665178354Ssamwpi_start_locked(struct ifnet *ifp) 2666178354Ssam{ 2667178354Ssam struct wpi_softc *sc = ifp->if_softc; 2668173362Sbenjsc struct ieee80211_node *ni; 2669178354Ssam struct mbuf *m; 2670173362Sbenjsc 2671178354Ssam WPI_LOCK_ASSERT(sc); 2672178354Ssam 2673278366Sadrian DPRINTF(sc, WPI_DEBUG_XMIT, "%s: called\n", __func__); 2674278366Sadrian 2675278366Sadrian if ((ifp->if_drv_flags & IFF_DRV_RUNNING) == 0 || 2676278366Sadrian (ifp->if_drv_flags & IFF_DRV_OACTIVE)) 2677177043Sthompsa return; 2678173362Sbenjsc 2679173362Sbenjsc for (;;) { 2680278366Sadrian if (sc->qfullmsk != 0) { 2681278366Sadrian ifp->if_drv_flags |= IFF_DRV_OACTIVE; 2682278366Sadrian break; 2683278366Sadrian } 2684190458Sjmallett IFQ_DRV_DEQUEUE(&ifp->if_snd, m); 2685178354Ssam if (m == NULL) 2686178354Ssam break; 2687278366Sadrian ni = (struct ieee80211_node *)m->m_pkthdr.rcvif; 2688278366Sadrian if (wpi_tx_data(sc, m, ni) != 0) { 2689278366Sadrian WPI_UNLOCK(sc); 2690178354Ssam ieee80211_free_node(ni); 2691278366Sadrian WPI_LOCK(sc); 2692271849Sglebius if_inc_counter(ifp, IFCOUNTER_OERRORS, 1); 2693278366Sadrian } else 2694278366Sadrian sc->sc_tx_timer = 5; 2695178354Ssam } 2696278366Sadrian 2697278366Sadrian DPRINTF(sc, WPI_DEBUG_XMIT, "%s: done\n", __func__); 2698178354Ssam} 2699173362Sbenjsc 2700278366Sadrianstatic void 2701278366Sadrianwpi_watchdog_rfkill(void *arg) 2702178354Ssam{ 2703278366Sadrian struct wpi_softc *sc = arg; 2704278366Sadrian struct ifnet *ifp = sc->sc_ifp; 2705278366Sadrian struct ieee80211com *ic = ifp->if_l2com; 2706173362Sbenjsc 2707278366Sadrian DPRINTF(sc, WPI_DEBUG_WATCHDOG, "RFkill Watchdog: tick\n"); 2708278366Sadrian 2709278366Sadrian /* No need to lock firmware memory. */ 2710278366Sadrian if ((wpi_prph_read(sc, WPI_APMG_RFKILL) & 0x1) == 0) { 2711278366Sadrian /* Radio kill switch is still off. */ 2712278366Sadrian callout_reset(&sc->watchdog_rfkill, hz, wpi_watchdog_rfkill, 2713278366Sadrian sc); 2714278366Sadrian } else 2715278366Sadrian ieee80211_runtask(ic, &sc->sc_radioon_task); 2716278366Sadrian} 2717278366Sadrian 2718278366Sadrian/** 2719278366Sadrian * Called every second, wpi_watchdog used by the watch dog timer 2720278366Sadrian * to check that the card is still alive 2721278366Sadrian */ 2722278366Sadrianstatic void 2723278366Sadrianwpi_watchdog(void *arg) 2724278366Sadrian{ 2725278366Sadrian struct wpi_softc *sc = arg; 2726278366Sadrian struct ifnet *ifp = sc->sc_ifp; 2727278366Sadrian struct ieee80211com *ic = ifp->if_l2com; 2728278366Sadrian 2729278366Sadrian DPRINTF(sc, WPI_DEBUG_WATCHDOG, "Watchdog: tick\n"); 2730278366Sadrian 2731278366Sadrian if (sc->sc_tx_timer > 0) { 2732278366Sadrian if (--sc->sc_tx_timer == 0) { 2733278366Sadrian if_printf(ifp, "device timeout\n"); 2734278366Sadrian if_inc_counter(ifp, IFCOUNTER_OERRORS, 1); 2735278366Sadrian ieee80211_runtask(ic, &sc->sc_reinittask); 2736278366Sadrian } 2737178354Ssam } 2738173362Sbenjsc 2739278366Sadrian if (sc->sc_scan_timer > 0) { 2740278366Sadrian struct ieee80211vap *vap = TAILQ_FIRST(&ic->ic_vaps); 2741278366Sadrian if (--sc->sc_scan_timer == 0 && vap != NULL) { 2742278366Sadrian if_printf(ifp, "scan timeout\n"); 2743278366Sadrian ieee80211_cancel_scan(vap); 2744278366Sadrian ieee80211_runtask(ic, &sc->sc_reinittask); 2745278366Sadrian } 2746178354Ssam } 2747173362Sbenjsc 2748278366Sadrian if (ifp->if_drv_flags & IFF_DRV_RUNNING) 2749278366Sadrian callout_reset(&sc->watchdog_to, hz, wpi_watchdog, sc); 2750173362Sbenjsc} 2751173362Sbenjsc 2752173362Sbenjscstatic int 2753173362Sbenjscwpi_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data) 2754173362Sbenjsc{ 2755173362Sbenjsc struct wpi_softc *sc = ifp->if_softc; 2756178354Ssam struct ieee80211com *ic = ifp->if_l2com; 2757278366Sadrian struct ieee80211vap *vap = TAILQ_FIRST(&ic->ic_vaps); 2758178354Ssam struct ifreq *ifr = (struct ifreq *) data; 2759278366Sadrian int error = 0, startall = 0, stop = 0; 2760173362Sbenjsc 2761173362Sbenjsc switch (cmd) { 2762278366Sadrian case SIOCGIFADDR: 2763278366Sadrian error = ether_ioctl(ifp, cmd, data); 2764278366Sadrian break; 2765173362Sbenjsc case SIOCSIFFLAGS: 2766178704Sthompsa WPI_LOCK(sc); 2767278366Sadrian if (ifp->if_flags & IFF_UP) { 2768178354Ssam if (!(ifp->if_drv_flags & IFF_DRV_RUNNING)) { 2769278366Sadrian wpi_init_locked(sc); 2770278366Sadrian if (WPI_READ(sc, WPI_GP_CNTRL) & 2771278366Sadrian WPI_GP_CNTRL_RFKILL) 2772278366Sadrian startall = 1; 2773278366Sadrian else 2774278366Sadrian stop = 1; 2775178354Ssam } 2776278366Sadrian } else if (ifp->if_drv_flags & IFF_DRV_RUNNING) 2777173362Sbenjsc wpi_stop_locked(sc); 2778178704Sthompsa WPI_UNLOCK(sc); 2779178704Sthompsa if (startall) 2780178704Sthompsa ieee80211_start_all(ic); 2781278366Sadrian else if (vap != NULL && stop) 2782278366Sadrian ieee80211_stop(vap); 2783173362Sbenjsc break; 2784178354Ssam case SIOCGIFMEDIA: 2785178354Ssam error = ifmedia_ioctl(ifp, ifr, &ic->ic_media, cmd); 2786178354Ssam break; 2787178704Sthompsa default: 2788178704Sthompsa error = EINVAL; 2789178704Sthompsa break; 2790173362Sbenjsc } 2791173362Sbenjsc return error; 2792173362Sbenjsc} 2793173362Sbenjsc 2794173362Sbenjsc/* 2795173362Sbenjsc * Send a command to the firmware. 2796173362Sbenjsc */ 2797173362Sbenjscstatic int 2798278366Sadrianwpi_cmd(struct wpi_softc *sc, int code, const void *buf, size_t size, 2799278366Sadrian int async) 2800173362Sbenjsc{ 2801278366Sadrian struct wpi_tx_ring *ring = &sc->txq[4]; 2802173362Sbenjsc struct wpi_tx_desc *desc; 2803278366Sadrian struct wpi_tx_data *data; 2804173362Sbenjsc struct wpi_tx_cmd *cmd; 2805278366Sadrian struct mbuf *m; 2806278366Sadrian bus_addr_t paddr; 2807278366Sadrian int totlen, error; 2808173362Sbenjsc 2809278366Sadrian DPRINTF(sc, WPI_DEBUG_TRACE, TRACE_STR_BEGIN, __func__); 2810278366Sadrian 2811278366Sadrian if (async == 0) 2812173362Sbenjsc WPI_LOCK_ASSERT(sc); 2813173362Sbenjsc 2814278366Sadrian DPRINTF(sc, WPI_DEBUG_CMD, "wpi_cmd %s size %zu async %d\n", 2815278366Sadrian wpi_cmd_str(code), size, async); 2816173362Sbenjsc 2817173362Sbenjsc if (sc->flags & WPI_FLAG_BUSY) { 2818173362Sbenjsc device_printf(sc->sc_dev, "%s: cmd %d not sent, busy\n", 2819173362Sbenjsc __func__, code); 2820173362Sbenjsc return EAGAIN; 2821173362Sbenjsc } 2822278366Sadrian sc->flags |= WPI_FLAG_BUSY; 2823173362Sbenjsc 2824173362Sbenjsc desc = &ring->desc[ring->cur]; 2825278366Sadrian data = &ring->data[ring->cur]; 2826278366Sadrian totlen = 4 + size; 2827173362Sbenjsc 2828278366Sadrian if (size > sizeof cmd->data) { 2829278366Sadrian /* Command is too large to fit in a descriptor. */ 2830278366Sadrian if (totlen > MCLBYTES) 2831278366Sadrian return EINVAL; 2832278366Sadrian m = m_getjcl(M_NOWAIT, MT_DATA, M_PKTHDR, MJUMPAGESIZE); 2833278366Sadrian if (m == NULL) 2834278366Sadrian return ENOMEM; 2835278366Sadrian cmd = mtod(m, struct wpi_tx_cmd *); 2836278366Sadrian error = bus_dmamap_load(ring->data_dmat, data->map, cmd, 2837278366Sadrian totlen, wpi_dma_map_addr, &paddr, BUS_DMA_NOWAIT); 2838278366Sadrian if (error != 0) { 2839278366Sadrian m_freem(m); 2840278366Sadrian return error; 2841278366Sadrian } 2842278366Sadrian data->m = m; 2843278366Sadrian } else { 2844278366Sadrian cmd = &ring->cmd[ring->cur]; 2845278366Sadrian paddr = data->cmd_paddr; 2846278366Sadrian } 2847278366Sadrian 2848173362Sbenjsc cmd->code = code; 2849173362Sbenjsc cmd->flags = 0; 2850173362Sbenjsc cmd->qid = ring->qid; 2851173362Sbenjsc cmd->idx = ring->cur; 2852173362Sbenjsc memcpy(cmd->data, buf, size); 2853173362Sbenjsc 2854278366Sadrian desc->nsegs = 1 + (WPI_PAD32(size) << 4); 2855278366Sadrian desc->segs[0].addr = htole32(paddr); 2856278366Sadrian desc->segs[0].len = htole32(totlen); 2857173362Sbenjsc 2858278366Sadrian if (size > sizeof cmd->data) { 2859278366Sadrian bus_dmamap_sync(ring->data_dmat, data->map, 2860278366Sadrian BUS_DMASYNC_PREWRITE); 2861278366Sadrian } else { 2862278366Sadrian bus_dmamap_sync(ring->data_dmat, ring->cmd_dma.map, 2863278366Sadrian BUS_DMASYNC_PREWRITE); 2864278366Sadrian } 2865278366Sadrian bus_dmamap_sync(ring->desc_dma.tag, ring->desc_dma.map, 2866278366Sadrian BUS_DMASYNC_PREWRITE); 2867173362Sbenjsc 2868278366Sadrian /* Kick command ring. */ 2869278366Sadrian ring->cur = (ring->cur + 1) % WPI_TX_RING_COUNT; 2870278366Sadrian wpi_update_tx_ring(sc, ring); 2871278366Sadrian 2872278366Sadrian DPRINTF(sc, WPI_DEBUG_TRACE, TRACE_STR_END, __func__); 2873278366Sadrian 2874173362Sbenjsc if (async) { 2875278366Sadrian sc->flags &= ~WPI_FLAG_BUSY; 2876173362Sbenjsc return 0; 2877173362Sbenjsc } 2878173362Sbenjsc 2879173362Sbenjsc return msleep(cmd, &sc->sc_mtx, PCATCH, "wpicmd", hz); 2880173362Sbenjsc} 2881173362Sbenjsc 2882173362Sbenjsc/* 2883278366Sadrian * Configure HW multi-rate retries. 2884173362Sbenjsc */ 2885173362Sbenjscstatic int 2886173362Sbenjscwpi_mrr_setup(struct wpi_softc *sc) 2887173362Sbenjsc{ 2888178354Ssam struct ifnet *ifp = sc->sc_ifp; 2889178354Ssam struct ieee80211com *ic = ifp->if_l2com; 2890173362Sbenjsc struct wpi_mrr_setup mrr; 2891173362Sbenjsc int i, error; 2892173362Sbenjsc 2893278366Sadrian /* CCK rates (not used with 802.11a). */ 2894278366Sadrian for (i = WPI_RIDX_CCK1; i <= WPI_RIDX_CCK11; i++) { 2895173362Sbenjsc mrr.rates[i].flags = 0; 2896278366Sadrian mrr.rates[i].plcp = wpi_ridx_to_plcp[i]; 2897278366Sadrian /* Fallback to the immediate lower CCK rate (if any.) */ 2898278366Sadrian mrr.rates[i].next = 2899278366Sadrian (i == WPI_RIDX_CCK1) ? WPI_RIDX_CCK1 : i - 1; 2900278366Sadrian /* Try one time at this rate before falling back to "next". */ 2901173362Sbenjsc mrr.rates[i].ntries = 1; 2902173362Sbenjsc } 2903278366Sadrian /* OFDM rates (not used with 802.11b). */ 2904278366Sadrian for (i = WPI_RIDX_OFDM6; i <= WPI_RIDX_OFDM54; i++) { 2905173362Sbenjsc mrr.rates[i].flags = 0; 2906278366Sadrian mrr.rates[i].plcp = wpi_ridx_to_plcp[i]; 2907278366Sadrian /* Fallback to the immediate lower rate (if any.) */ 2908278366Sadrian /* We allow fallback from OFDM/6 to CCK/2 in 11b/g mode. */ 2909278366Sadrian mrr.rates[i].next = (i == WPI_RIDX_OFDM6) ? 2910173362Sbenjsc ((ic->ic_curmode == IEEE80211_MODE_11A) ? 2911278366Sadrian WPI_RIDX_OFDM6 : WPI_RIDX_CCK2) : 2912173362Sbenjsc i - 1; 2913278366Sadrian /* Try one time at this rate before falling back to "next". */ 2914173362Sbenjsc mrr.rates[i].ntries = 1; 2915173362Sbenjsc } 2916278366Sadrian /* Setup MRR for control frames. */ 2917278366Sadrian mrr.which = htole32(WPI_MRR_CTL); 2918173362Sbenjsc error = wpi_cmd(sc, WPI_CMD_MRR_SETUP, &mrr, sizeof mrr, 0); 2919173362Sbenjsc if (error != 0) { 2920173362Sbenjsc device_printf(sc->sc_dev, 2921173362Sbenjsc "could not setup MRR for control frames\n"); 2922173362Sbenjsc return error; 2923173362Sbenjsc } 2924278366Sadrian /* Setup MRR for data frames. */ 2925278366Sadrian mrr.which = htole32(WPI_MRR_DATA); 2926173362Sbenjsc error = wpi_cmd(sc, WPI_CMD_MRR_SETUP, &mrr, sizeof mrr, 0); 2927173362Sbenjsc if (error != 0) { 2928173362Sbenjsc device_printf(sc->sc_dev, 2929173362Sbenjsc "could not setup MRR for data frames\n"); 2930173362Sbenjsc return error; 2931173362Sbenjsc } 2932173362Sbenjsc return 0; 2933173362Sbenjsc} 2934173362Sbenjsc 2935278366Sadrianstatic int 2936278366Sadrianwpi_add_node(struct wpi_softc *sc, struct ieee80211_node *ni) 2937278366Sadrian{ 2938278366Sadrian struct ieee80211com *ic = ni->ni_ic; 2939278366Sadrian struct wpi_node *wn = (void *)ni; 2940278366Sadrian struct wpi_node_info node; 2941278366Sadrian 2942278366Sadrian DPRINTF(sc, WPI_DEBUG_TRACE, TRACE_STR_DOING, __func__); 2943278366Sadrian 2944278366Sadrian if (wn->id == WPI_ID_UNDEFINED) 2945278366Sadrian return EINVAL; 2946278366Sadrian 2947278366Sadrian memset(&node, 0, sizeof node); 2948279762Sadrian IEEE80211_ADDR_COPY(node.macaddr, ni->ni_macaddr); 2949278366Sadrian node.id = wn->id; 2950278366Sadrian node.plcp = (ic->ic_curmode == IEEE80211_MODE_11A) ? 2951278366Sadrian wpi_ridx_to_plcp[WPI_RIDX_OFDM6] : wpi_ridx_to_plcp[WPI_RIDX_CCK1]; 2952278366Sadrian node.action = htole32(WPI_ACTION_SET_RATE); 2953278366Sadrian node.antenna = WPI_ANTENNA_BOTH; 2954278366Sadrian 2955278366Sadrian return wpi_cmd(sc, WPI_CMD_ADD_NODE, &node, sizeof node, 1); 2956278366Sadrian} 2957278366Sadrian 2958278366Sadrian/* 2959278366Sadrian * Broadcast node is used to send group-addressed and management frames. 2960278366Sadrian */ 2961278366Sadrianstatic int 2962278366Sadrianwpi_add_broadcast_node(struct wpi_softc *sc, int async) 2963278366Sadrian{ 2964278366Sadrian struct ifnet *ifp = sc->sc_ifp; 2965278366Sadrian struct ieee80211com *ic = ifp->if_l2com; 2966278366Sadrian struct wpi_node_info node; 2967278366Sadrian 2968278366Sadrian DPRINTF(sc, WPI_DEBUG_TRACE, TRACE_STR_DOING, __func__); 2969278366Sadrian 2970278366Sadrian memset(&node, 0, sizeof node); 2971278366Sadrian IEEE80211_ADDR_COPY(node.macaddr, ifp->if_broadcastaddr); 2972278366Sadrian node.id = WPI_ID_BROADCAST; 2973278366Sadrian node.plcp = (ic->ic_curmode == IEEE80211_MODE_11A) ? 2974278366Sadrian wpi_ridx_to_plcp[WPI_RIDX_OFDM6] : wpi_ridx_to_plcp[WPI_RIDX_CCK1]; 2975278366Sadrian node.action = htole32(WPI_ACTION_SET_RATE); 2976278366Sadrian node.antenna = WPI_ANTENNA_BOTH; 2977278366Sadrian 2978278366Sadrian return wpi_cmd(sc, WPI_CMD_ADD_NODE, &node, sizeof node, async); 2979278366Sadrian} 2980278366Sadrian 2981278366Sadrianstatic int 2982278366Sadrianwpi_add_ibss_node(struct wpi_softc *sc, struct ieee80211_node *ni) 2983278366Sadrian{ 2984278366Sadrian struct wpi_node *wn = (void *)ni; 2985278366Sadrian 2986278366Sadrian DPRINTF(sc, WPI_DEBUG_TRACE, TRACE_STR_DOING, __func__); 2987278366Sadrian 2988278366Sadrian if (wn->id != WPI_ID_UNDEFINED) 2989278366Sadrian return EINVAL; 2990278366Sadrian 2991278366Sadrian wn->id = alloc_unrl(sc->sc_unr); 2992278366Sadrian 2993278366Sadrian if (wn->id == (uint8_t)-1) 2994278366Sadrian return ENOBUFS; 2995278366Sadrian 2996278366Sadrian return wpi_add_node(sc, ni); 2997278366Sadrian} 2998278366Sadrian 2999173362Sbenjscstatic void 3000278366Sadrianwpi_del_node(struct wpi_softc *sc, struct ieee80211_node *ni) 3001278366Sadrian{ 3002278366Sadrian struct wpi_node *wn = (void *)ni; 3003278366Sadrian struct wpi_cmd_del_node node; 3004278366Sadrian int error; 3005278366Sadrian 3006278366Sadrian DPRINTF(sc, WPI_DEBUG_TRACE, TRACE_STR_DOING, __func__); 3007278366Sadrian 3008278366Sadrian if (wn->id == WPI_ID_UNDEFINED) { 3009278366Sadrian device_printf(sc->sc_dev, "%s: undefined node id passed\n", 3010278366Sadrian __func__); 3011278366Sadrian return; 3012278366Sadrian } 3013278366Sadrian 3014278366Sadrian memset(&node, 0, sizeof node); 3015279762Sadrian IEEE80211_ADDR_COPY(node.macaddr, ni->ni_macaddr); 3016278366Sadrian node.count = 1; 3017278366Sadrian 3018278366Sadrian error = wpi_cmd(sc, WPI_CMD_DEL_NODE, &node, sizeof node, 1); 3019278366Sadrian if (error != 0) { 3020278366Sadrian device_printf(sc->sc_dev, 3021278366Sadrian "%s: could not delete node %u, error %d\n", __func__, 3022278366Sadrian wn->id, error); 3023278366Sadrian } 3024278366Sadrian} 3025278366Sadrian 3026278366Sadrianstatic int 3027278366Sadrianwpi_updateedca(struct ieee80211com *ic) 3028278366Sadrian{ 3029278366Sadrian#define WPI_EXP2(x) ((1 << (x)) - 1) /* CWmin = 2^ECWmin - 1 */ 3030278366Sadrian struct wpi_softc *sc = ic->ic_ifp->if_softc; 3031278366Sadrian struct wpi_edca_params cmd; 3032278366Sadrian int aci, error; 3033278366Sadrian 3034278366Sadrian DPRINTF(sc, WPI_DEBUG_TRACE, TRACE_STR_BEGIN, __func__); 3035278366Sadrian 3036278366Sadrian memset(&cmd, 0, sizeof cmd); 3037278366Sadrian cmd.flags = htole32(WPI_EDCA_UPDATE); 3038278366Sadrian for (aci = 0; aci < WME_NUM_AC; aci++) { 3039278366Sadrian const struct wmeParams *ac = 3040278366Sadrian &ic->ic_wme.wme_chanParams.cap_wmeParams[aci]; 3041278366Sadrian cmd.ac[aci].aifsn = ac->wmep_aifsn; 3042278366Sadrian cmd.ac[aci].cwmin = htole16(WPI_EXP2(ac->wmep_logcwmin)); 3043278366Sadrian cmd.ac[aci].cwmax = htole16(WPI_EXP2(ac->wmep_logcwmax)); 3044278366Sadrian cmd.ac[aci].txoplimit = 3045278366Sadrian htole16(IEEE80211_TXOP_TO_US(ac->wmep_txopLimit)); 3046278366Sadrian 3047278366Sadrian DPRINTF(sc, WPI_DEBUG_EDCA, 3048278366Sadrian "setting WME for queue %d aifsn=%d cwmin=%d cwmax=%d " 3049278366Sadrian "txoplimit=%d\n", aci, cmd.ac[aci].aifsn, 3050278366Sadrian cmd.ac[aci].cwmin, cmd.ac[aci].cwmax, 3051278366Sadrian cmd.ac[aci].txoplimit); 3052278366Sadrian } 3053278366Sadrian IEEE80211_UNLOCK(ic); 3054278366Sadrian WPI_LOCK(sc); 3055278366Sadrian error = wpi_cmd(sc, WPI_CMD_EDCA_PARAMS, &cmd, sizeof cmd, 1); 3056278366Sadrian WPI_UNLOCK(sc); 3057278366Sadrian IEEE80211_LOCK(ic); 3058278366Sadrian 3059278366Sadrian DPRINTF(sc, WPI_DEBUG_TRACE, TRACE_STR_END, __func__); 3060278366Sadrian 3061278366Sadrian return error; 3062278366Sadrian#undef WPI_EXP2 3063278366Sadrian} 3064278366Sadrian 3065278366Sadrianstatic void 3066278366Sadrianwpi_set_promisc(struct wpi_softc *sc) 3067278366Sadrian{ 3068278366Sadrian struct ifnet *ifp = sc->sc_ifp; 3069278366Sadrian uint32_t promisc_filter; 3070278366Sadrian 3071278366Sadrian promisc_filter = WPI_FILTER_PROMISC | WPI_FILTER_CTL; 3072278366Sadrian 3073278366Sadrian if (ifp->if_flags & IFF_PROMISC) 3074278366Sadrian sc->rxon.filter |= htole32(promisc_filter); 3075278366Sadrian else 3076278366Sadrian sc->rxon.filter &= ~htole32(promisc_filter); 3077278366Sadrian} 3078278366Sadrian 3079278366Sadrianstatic void 3080278366Sadrianwpi_update_promisc(struct ifnet *ifp) 3081278366Sadrian{ 3082278366Sadrian struct wpi_softc *sc = ifp->if_softc; 3083278366Sadrian 3084278366Sadrian wpi_set_promisc(sc); 3085278366Sadrian 3086278366Sadrian WPI_LOCK(sc); 3087278366Sadrian if (wpi_send_rxon(sc, 1, 1) != 0) { 3088278366Sadrian device_printf(sc->sc_dev, "%s: could not send RXON\n", 3089278366Sadrian __func__); 3090278366Sadrian } 3091278366Sadrian WPI_UNLOCK(sc); 3092278366Sadrian} 3093278366Sadrian 3094278366Sadrianstatic void 3095278366Sadrianwpi_update_mcast(struct ifnet *ifp) 3096278366Sadrian{ 3097278366Sadrian /* Ignore */ 3098278366Sadrian} 3099278366Sadrian 3100278366Sadrianstatic void 3101173362Sbenjscwpi_set_led(struct wpi_softc *sc, uint8_t which, uint8_t off, uint8_t on) 3102173362Sbenjsc{ 3103173362Sbenjsc struct wpi_cmd_led led; 3104173362Sbenjsc 3105278366Sadrian DPRINTF(sc, WPI_DEBUG_TRACE, TRACE_STR_DOING, __func__); 3106278366Sadrian 3107173362Sbenjsc led.which = which; 3108173362Sbenjsc led.unit = htole32(100000); /* on/off in unit of 100ms */ 3109173362Sbenjsc led.off = off; 3110173362Sbenjsc led.on = on; 3111173362Sbenjsc (void)wpi_cmd(sc, WPI_CMD_SET_LED, &led, sizeof led, 1); 3112173362Sbenjsc} 3113173362Sbenjsc 3114278366Sadrianstatic int 3115278366Sadrianwpi_set_timing(struct wpi_softc *sc, struct ieee80211_node *ni) 3116173362Sbenjsc{ 3117278366Sadrian struct wpi_cmd_timing cmd; 3118173362Sbenjsc uint64_t val, mod; 3119173362Sbenjsc 3120278366Sadrian DPRINTF(sc, WPI_DEBUG_TRACE, TRACE_STR_DOING, __func__); 3121173362Sbenjsc 3122278366Sadrian memset(&cmd, 0, sizeof cmd); 3123278366Sadrian memcpy(&cmd.tstamp, ni->ni_tstamp.data, sizeof (uint64_t)); 3124278366Sadrian cmd.bintval = htole16(ni->ni_intval); 3125278366Sadrian cmd.lintval = htole16(10); 3126173362Sbenjsc 3127278366Sadrian /* Compute remaining time until next beacon. */ 3128278366Sadrian val = (uint64_t)ni->ni_intval * IEEE80211_DUR_TU; 3129278366Sadrian mod = le64toh(cmd.tstamp) % val; 3130278366Sadrian cmd.binitval = htole32((uint32_t)(val - mod)); 3131278366Sadrian 3132278366Sadrian DPRINTF(sc, WPI_DEBUG_RESET, "timing bintval=%u tstamp=%ju, init=%u\n", 3133278366Sadrian ni->ni_intval, le64toh(cmd.tstamp), (uint32_t)(val - mod)); 3134278366Sadrian 3135278366Sadrian return wpi_cmd(sc, WPI_CMD_TIMING, &cmd, sizeof cmd, 1); 3136173362Sbenjsc} 3137173362Sbenjsc 3138173362Sbenjsc/* 3139278366Sadrian * This function is called periodically (every 60 seconds) to adjust output 3140278366Sadrian * power to temperature changes. 3141173362Sbenjsc */ 3142278366Sadrianstatic void 3143278366Sadrianwpi_power_calibration(struct wpi_softc *sc) 3144278366Sadrian{ 3145278366Sadrian int temp; 3146278366Sadrian 3147278366Sadrian DPRINTF(sc, WPI_DEBUG_TRACE, TRACE_STR_DOING, __func__); 3148278366Sadrian 3149278366Sadrian /* Update sensor data. */ 3150278366Sadrian temp = (int)WPI_READ(sc, WPI_UCODE_GP2); 3151278366Sadrian DPRINTF(sc, WPI_DEBUG_TEMP, "Temp in calibration is: %d\n", temp); 3152278366Sadrian 3153278366Sadrian /* Sanity-check read value. */ 3154278366Sadrian if (temp < -260 || temp > 25) { 3155278366Sadrian /* This can't be correct, ignore. */ 3156278366Sadrian DPRINTF(sc, WPI_DEBUG_TEMP, 3157278366Sadrian "out-of-range temperature reported: %d\n", temp); 3158278366Sadrian return; 3159278366Sadrian } 3160278366Sadrian 3161278366Sadrian DPRINTF(sc, WPI_DEBUG_TEMP, "temperature %d->%d\n", sc->temp, temp); 3162278366Sadrian 3163278366Sadrian /* Adjust Tx power if need be. */ 3164278366Sadrian if (abs(temp - sc->temp) <= 6) 3165278366Sadrian return; 3166278366Sadrian 3167278366Sadrian sc->temp = temp; 3168278366Sadrian 3169278366Sadrian if (wpi_set_txpower(sc, 1) != 0) { 3170278366Sadrian /* just warn, too bad for the automatic calibration... */ 3171278366Sadrian device_printf(sc->sc_dev,"could not adjust Tx power\n"); 3172278366Sadrian } 3173278366Sadrian} 3174278366Sadrian 3175278366Sadrian/* 3176278366Sadrian * Set TX power for current channel. 3177278366Sadrian */ 3178173362Sbenjscstatic int 3179278366Sadrianwpi_set_txpower(struct wpi_softc *sc, int async) 3180173362Sbenjsc{ 3181178354Ssam struct ifnet *ifp = sc->sc_ifp; 3182178354Ssam struct ieee80211com *ic = ifp->if_l2com; 3183278366Sadrian struct ieee80211_channel *ch; 3184278366Sadrian struct wpi_power_group *group; 3185278366Sadrian struct wpi_cmd_txpower cmd; 3186278366Sadrian uint8_t chan; 3187278366Sadrian int idx, i; 3188173362Sbenjsc 3189278366Sadrian /* Retrieve current channel from last RXON. */ 3190278366Sadrian chan = sc->rxon.chan; 3191278366Sadrian ch = &ic->ic_channels[chan]; 3192173362Sbenjsc 3193278366Sadrian /* Find the TX power group to which this channel belongs. */ 3194278366Sadrian if (IEEE80211_IS_CHAN_5GHZ(ch)) { 3195278366Sadrian for (group = &sc->groups[1]; group < &sc->groups[4]; group++) 3196278366Sadrian if (chan <= group->chan) 3197278366Sadrian break; 3198278366Sadrian } else 3199278366Sadrian group = &sc->groups[0]; 3200278366Sadrian 3201278366Sadrian memset(&cmd, 0, sizeof cmd); 3202278366Sadrian cmd.band = IEEE80211_IS_CHAN_5GHZ(ch) ? 0 : 1; 3203278366Sadrian cmd.chan = htole16(chan); 3204278366Sadrian 3205278366Sadrian /* Set TX power for all OFDM and CCK rates. */ 3206278366Sadrian for (i = 0; i <= WPI_RIDX_MAX ; i++) { 3207278366Sadrian /* Retrieve TX power for this channel/rate. */ 3208278366Sadrian idx = wpi_get_power_index(sc, group, ch, i); 3209278366Sadrian 3210278366Sadrian cmd.rates[i].plcp = wpi_ridx_to_plcp[i]; 3211278366Sadrian 3212278366Sadrian if (IEEE80211_IS_CHAN_5GHZ(ch)) { 3213278366Sadrian cmd.rates[i].rf_gain = wpi_rf_gain_5ghz[idx]; 3214278366Sadrian cmd.rates[i].dsp_gain = wpi_dsp_gain_5ghz[idx]; 3215278366Sadrian } else { 3216278366Sadrian cmd.rates[i].rf_gain = wpi_rf_gain_2ghz[idx]; 3217278366Sadrian cmd.rates[i].dsp_gain = wpi_dsp_gain_2ghz[idx]; 3218278366Sadrian } 3219278366Sadrian DPRINTF(sc, WPI_DEBUG_TEMP, 3220278366Sadrian "chan %d/ridx %d: power index %d\n", chan, i, idx); 3221173362Sbenjsc } 3222173362Sbenjsc 3223278366Sadrian return wpi_cmd(sc, WPI_CMD_TXPOWER, &cmd, sizeof cmd, async); 3224278366Sadrian} 3225173362Sbenjsc 3226278366Sadrian/* 3227278366Sadrian * Determine Tx power index for a given channel/rate combination. 3228278366Sadrian * This takes into account the regulatory information from EEPROM and the 3229278366Sadrian * current temperature. 3230278366Sadrian */ 3231278366Sadrianstatic int 3232278366Sadrianwpi_get_power_index(struct wpi_softc *sc, struct wpi_power_group *group, 3233278366Sadrian struct ieee80211_channel *c, int ridx) 3234278366Sadrian{ 3235278366Sadrian/* Fixed-point arithmetic division using a n-bit fractional part. */ 3236278366Sadrian#define fdivround(a, b, n) \ 3237278366Sadrian ((((1 << n) * (a)) / (b) + (1 << n) / 2) / (1 << n)) 3238173362Sbenjsc 3239278366Sadrian/* Linear interpolation. */ 3240278366Sadrian#define interpolate(x, x1, y1, x2, y2, n) \ 3241278366Sadrian ((y1) + fdivround(((x) - (x1)) * ((y2) - (y1)), (x2) - (x1), n)) 3242173362Sbenjsc 3243278366Sadrian struct ifnet *ifp = sc->sc_ifp; 3244278366Sadrian struct ieee80211com *ic = ifp->if_l2com; 3245278366Sadrian struct wpi_power_sample *sample; 3246278366Sadrian int pwr, idx; 3247278366Sadrian u_int chan; 3248278366Sadrian 3249278366Sadrian /* Get channel number. */ 3250278366Sadrian chan = ieee80211_chan2ieee(ic, c); 3251278366Sadrian 3252278366Sadrian /* Default TX power is group maximum TX power minus 3dB. */ 3253278366Sadrian pwr = group->maxpwr / 2; 3254278366Sadrian 3255278366Sadrian /* Decrease TX power for highest OFDM rates to reduce distortion. */ 3256278366Sadrian switch (ridx) { 3257278366Sadrian case WPI_RIDX_OFDM36: 3258278366Sadrian pwr -= IEEE80211_IS_CHAN_2GHZ(c) ? 0 : 5; 3259278366Sadrian break; 3260278366Sadrian case WPI_RIDX_OFDM48: 3261278366Sadrian pwr -= IEEE80211_IS_CHAN_2GHZ(c) ? 7 : 10; 3262278366Sadrian break; 3263278366Sadrian case WPI_RIDX_OFDM54: 3264278366Sadrian pwr -= IEEE80211_IS_CHAN_2GHZ(c) ? 9 : 12; 3265278366Sadrian break; 3266173362Sbenjsc } 3267173362Sbenjsc 3268278366Sadrian /* Never exceed the channel maximum allowed TX power. */ 3269278366Sadrian pwr = min(pwr, sc->maxpwr[chan]); 3270173362Sbenjsc 3271278366Sadrian /* Retrieve TX power index into gain tables from samples. */ 3272278366Sadrian for (sample = group->samples; sample < &group->samples[3]; sample++) 3273278366Sadrian if (pwr > sample[1].power) 3274278366Sadrian break; 3275278366Sadrian /* Fixed-point linear interpolation using a 19-bit fractional part. */ 3276278366Sadrian idx = interpolate(pwr, sample[0].power, sample[0].index, 3277278366Sadrian sample[1].power, sample[1].index, 19); 3278173362Sbenjsc 3279278366Sadrian /*- 3280278366Sadrian * Adjust power index based on current temperature: 3281278366Sadrian * - if cooler than factory-calibrated: decrease output power 3282278366Sadrian * - if warmer than factory-calibrated: increase output power 3283278366Sadrian */ 3284278366Sadrian idx -= (sc->temp - group->temp) * 11 / 100; 3285173362Sbenjsc 3286278366Sadrian /* Decrease TX power for CCK rates (-5dB). */ 3287278366Sadrian if (ridx >= WPI_RIDX_CCK1) 3288278366Sadrian idx += 10; 3289278366Sadrian 3290278366Sadrian /* Make sure idx stays in a valid range. */ 3291278366Sadrian if (idx < 0) 3292278366Sadrian return 0; 3293278366Sadrian if (idx > WPI_MAX_PWR_INDEX) 3294278366Sadrian return WPI_MAX_PWR_INDEX; 3295278366Sadrian return idx; 3296278366Sadrian 3297278366Sadrian#undef interpolate 3298278366Sadrian#undef fdivround 3299173362Sbenjsc} 3300173362Sbenjsc 3301278366Sadrian/* 3302278366Sadrian * Set STA mode power saving level (between 0 and 5). 3303278366Sadrian * Level 0 is CAM (Continuously Aware Mode), 5 is for maximum power saving. 3304278366Sadrian */ 3305173362Sbenjscstatic int 3306278366Sadrianwpi_set_pslevel(struct wpi_softc *sc, uint8_t dtim, int level, int async) 3307173362Sbenjsc{ 3308278366Sadrian struct wpi_pmgt_cmd cmd; 3309278366Sadrian const struct wpi_pmgt *pmgt; 3310278366Sadrian uint32_t max, skip_dtim; 3311278366Sadrian uint32_t reg; 3312278366Sadrian int i; 3313278366Sadrian 3314278366Sadrian DPRINTF(sc, WPI_DEBUG_PWRSAVE, 3315278366Sadrian "%s: dtim=%d, level=%d, async=%d\n", 3316278366Sadrian __func__, dtim, level, async); 3317278366Sadrian 3318278366Sadrian /* Select which PS parameters to use. */ 3319278366Sadrian if (dtim <= 10) 3320278366Sadrian pmgt = &wpi_pmgt[0][level]; 3321278366Sadrian else 3322278366Sadrian pmgt = &wpi_pmgt[1][level]; 3323278366Sadrian 3324278366Sadrian memset(&cmd, 0, sizeof cmd); 3325278366Sadrian if (level != 0) /* not CAM */ 3326278366Sadrian cmd.flags |= htole16(WPI_PS_ALLOW_SLEEP); 3327278366Sadrian /* Retrieve PCIe Active State Power Management (ASPM). */ 3328278366Sadrian reg = pci_read_config(sc->sc_dev, sc->sc_cap_off + 0x10, 1); 3329278366Sadrian if (!(reg & 0x1)) /* L0s Entry disabled. */ 3330278366Sadrian cmd.flags |= htole16(WPI_PS_PCI_PMGT); 3331278366Sadrian 3332278366Sadrian cmd.rxtimeout = htole32(pmgt->rxtimeout * IEEE80211_DUR_TU); 3333278366Sadrian cmd.txtimeout = htole32(pmgt->txtimeout * IEEE80211_DUR_TU); 3334278366Sadrian 3335278366Sadrian if (dtim == 0) { 3336278366Sadrian dtim = 1; 3337278366Sadrian skip_dtim = 0; 3338278366Sadrian } else 3339278366Sadrian skip_dtim = pmgt->skip_dtim; 3340278366Sadrian 3341278366Sadrian if (skip_dtim != 0) { 3342278366Sadrian cmd.flags |= htole16(WPI_PS_SLEEP_OVER_DTIM); 3343278366Sadrian max = pmgt->intval[4]; 3344278366Sadrian if (max == (uint32_t)-1) 3345278366Sadrian max = dtim * (skip_dtim + 1); 3346278366Sadrian else if (max > dtim) 3347278366Sadrian max = (max / dtim) * dtim; 3348278366Sadrian } else 3349278366Sadrian max = dtim; 3350278366Sadrian 3351278366Sadrian for (i = 0; i < 5; i++) 3352278366Sadrian cmd.intval[i] = htole32(MIN(max, pmgt->intval[i])); 3353278366Sadrian 3354278366Sadrian return wpi_cmd(sc, WPI_CMD_SET_POWER_MODE, &cmd, sizeof cmd, async); 3355278366Sadrian} 3356278366Sadrian 3357278366Sadrianstatic int 3358278366Sadrianwpi_send_btcoex(struct wpi_softc *sc) 3359278366Sadrian{ 3360278366Sadrian struct wpi_bluetooth cmd; 3361278366Sadrian 3362278366Sadrian memset(&cmd, 0, sizeof cmd); 3363278366Sadrian cmd.flags = WPI_BT_COEX_MODE_4WIRE; 3364278366Sadrian cmd.lead_time = WPI_BT_LEAD_TIME_DEF; 3365278366Sadrian cmd.max_kill = WPI_BT_MAX_KILL_DEF; 3366278366Sadrian DPRINTF(sc, WPI_DEBUG_RESET, "%s: configuring bluetooth coexistence\n", 3367278366Sadrian __func__); 3368278366Sadrian return wpi_cmd(sc, WPI_CMD_BT_COEX, &cmd, sizeof(cmd), 0); 3369278366Sadrian} 3370278366Sadrian 3371278366Sadrianstatic int 3372278366Sadrianwpi_send_rxon(struct wpi_softc *sc, int assoc, int async) 3373278366Sadrian{ 3374173362Sbenjsc int error; 3375173362Sbenjsc 3376278366Sadrian if (assoc && (sc->rxon.filter & htole32(WPI_FILTER_BSS))) { 3377278366Sadrian struct wpi_assoc rxon_assoc; 3378177043Sthompsa 3379278366Sadrian rxon_assoc.flags = sc->rxon.flags; 3380278366Sadrian rxon_assoc.filter = sc->rxon.filter; 3381278366Sadrian rxon_assoc.ofdm_mask = sc->rxon.ofdm_mask; 3382278366Sadrian rxon_assoc.cck_mask = sc->rxon.cck_mask; 3383278366Sadrian rxon_assoc.reserved = 0; 3384278366Sadrian 3385278366Sadrian error = wpi_cmd(sc, WPI_CMD_RXON_ASSOC, &rxon_assoc, 3386278366Sadrian sizeof (struct wpi_assoc), async); 3387216522Sbschmidt } else { 3388278366Sadrian error = wpi_cmd(sc, WPI_CMD_RXON, &sc->rxon, 3389278366Sadrian sizeof (struct wpi_rxon), async); 3390173362Sbenjsc } 3391173362Sbenjsc if (error != 0) { 3392278366Sadrian device_printf(sc->sc_dev, "RXON command failed, error %d\n", 3393278366Sadrian error); 3394173362Sbenjsc return error; 3395173362Sbenjsc } 3396173362Sbenjsc 3397278366Sadrian /* Configuration has changed, set Tx power accordingly. */ 3398278366Sadrian if ((error = wpi_set_txpower(sc, async)) != 0) { 3399278366Sadrian device_printf(sc->sc_dev, 3400278366Sadrian "%s: could not set TX power, error %d\n", __func__, error); 3401173362Sbenjsc return error; 3402173362Sbenjsc } 3403173362Sbenjsc 3404278366Sadrian if (!(sc->rxon.filter & htole32(WPI_FILTER_BSS))) { 3405278366Sadrian /* Add broadcast node. */ 3406278366Sadrian error = wpi_add_broadcast_node(sc, async); 3407278366Sadrian if (error != 0) { 3408278366Sadrian device_printf(sc->sc_dev, 3409278366Sadrian "could not add broadcast node, error %d\n", error); 3410278366Sadrian return error; 3411278366Sadrian } 3412278366Sadrian } 3413177043Sthompsa 3414278366Sadrian return 0; 3415177043Sthompsa} 3416177043Sthompsa 3417278366Sadrian/** 3418278366Sadrian * Configure the card to listen to a particular channel, this transisions the 3419278366Sadrian * card in to being able to receive frames from remote devices. 3420278366Sadrian */ 3421177043Sthompsastatic int 3422278366Sadrianwpi_config(struct wpi_softc *sc) 3423177043Sthompsa{ 3424278366Sadrian struct ifnet *ifp = sc->sc_ifp; 3425278366Sadrian struct ieee80211com *ic = ifp->if_l2com; 3426279762Sadrian struct ieee80211vap *vap = TAILQ_FIRST(&ic->ic_vaps); 3427278366Sadrian uint32_t flags; 3428177043Sthompsa int error; 3429177043Sthompsa 3430278366Sadrian DPRINTF(sc, WPI_DEBUG_TRACE, TRACE_STR_BEGIN, __func__); 3431278366Sadrian 3432278366Sadrian /* Set power saving level to CAM during initialization. */ 3433278366Sadrian if ((error = wpi_set_pslevel(sc, 0, 0, 0)) != 0) { 3434278366Sadrian device_printf(sc->sc_dev, 3435278366Sadrian "%s: could not set power saving level\n", __func__); 3436278366Sadrian return error; 3437178354Ssam } 3438178354Ssam 3439278366Sadrian /* Configure bluetooth coexistence. */ 3440278366Sadrian if ((error = wpi_send_btcoex(sc)) != 0) { 3441278366Sadrian device_printf(sc->sc_dev, 3442278366Sadrian "could not configure bluetooth coexistence\n"); 3443278366Sadrian return error; 3444278366Sadrian } 3445177043Sthompsa 3446278366Sadrian /* Configure adapter. */ 3447278366Sadrian memset(&sc->rxon, 0, sizeof (struct wpi_rxon)); 3448279762Sadrian IEEE80211_ADDR_COPY(sc->rxon.myaddr, vap->iv_myaddr); 3449177043Sthompsa 3450278366Sadrian /* Set default channel. */ 3451278366Sadrian sc->rxon.chan = ieee80211_chan2ieee(ic, ic->ic_curchan); 3452278366Sadrian sc->rxon.flags = htole32(WPI_RXON_TSF | WPI_RXON_CTS_TO_SELF); 3453278366Sadrian if (IEEE80211_IS_CHAN_2GHZ(ic->ic_curchan)) 3454278366Sadrian sc->rxon.flags |= htole32(WPI_RXON_AUTO | WPI_RXON_24GHZ); 3455177043Sthompsa 3456278764Sadrian sc->rxon.filter = WPI_FILTER_MULTICAST; 3457278366Sadrian switch (ic->ic_opmode) { 3458278366Sadrian case IEEE80211_M_STA: 3459278366Sadrian sc->rxon.mode = WPI_MODE_STA; 3460278366Sadrian break; 3461278366Sadrian case IEEE80211_M_IBSS: 3462278366Sadrian sc->rxon.mode = WPI_MODE_IBSS; 3463278764Sadrian sc->rxon.filter |= WPI_FILTER_BEACON; 3464278366Sadrian break; 3465278366Sadrian /* XXX workaround for passive channels selection */ 3466278366Sadrian case IEEE80211_M_AHDEMO: 3467278366Sadrian case IEEE80211_M_HOSTAP: 3468278366Sadrian sc->rxon.mode = WPI_MODE_HOSTAP; 3469278366Sadrian break; 3470278366Sadrian case IEEE80211_M_MONITOR: 3471278366Sadrian sc->rxon.mode = WPI_MODE_MONITOR; 3472278366Sadrian break; 3473278366Sadrian default: 3474278366Sadrian device_printf(sc->sc_dev, "unknown opmode %d\n", ic->ic_opmode); 3475278366Sadrian return EINVAL; 3476278366Sadrian } 3477278764Sadrian sc->rxon.filter = htole32(sc->rxon.filter); 3478278366Sadrian wpi_set_promisc(sc); 3479278366Sadrian sc->rxon.cck_mask = 0x0f; /* not yet negotiated */ 3480278366Sadrian sc->rxon.ofdm_mask = 0xff; /* not yet negotiated */ 3481278366Sadrian 3482278366Sadrian if ((error = wpi_send_rxon(sc, 0, 0)) != 0) { 3483278366Sadrian device_printf(sc->sc_dev, "%s: could not send RXON\n", 3484278366Sadrian __func__); 3485173362Sbenjsc return error; 3486173362Sbenjsc } 3487173362Sbenjsc 3488278366Sadrian /* Setup rate scalling. */ 3489278366Sadrian if ((error = wpi_mrr_setup(sc)) != 0) { 3490278366Sadrian device_printf(sc->sc_dev, "could not setup MRR, error %d\n", 3491278366Sadrian error); 3492278366Sadrian return error; 3493278366Sadrian } 3494278366Sadrian 3495278366Sadrian /* Disable beacon notifications (unused). */ 3496278366Sadrian flags = WPI_STATISTICS_BEACON_DISABLE; 3497278366Sadrian error = wpi_cmd(sc, WPI_CMD_GET_STATISTICS, &flags, sizeof flags, 1); 3498177043Sthompsa if (error != 0) { 3499278366Sadrian device_printf(sc->sc_dev, 3500278366Sadrian "could not disable beacon statistics, error %d\n", error); 3501177043Sthompsa return error; 3502177043Sthompsa } 3503173362Sbenjsc 3504278366Sadrian DPRINTF(sc, WPI_DEBUG_TRACE, TRACE_STR_END, __func__); 3505177043Sthompsa 3506278366Sadrian return 0; 3507278366Sadrian} 3508177043Sthompsa 3509278366Sadrianstatic uint16_t 3510278366Sadrianwpi_get_active_dwell_time(struct wpi_softc *sc, 3511278366Sadrian struct ieee80211_channel *c, uint8_t n_probes) 3512278366Sadrian{ 3513278366Sadrian /* No channel? Default to 2GHz settings. */ 3514278366Sadrian if (c == NULL || IEEE80211_IS_CHAN_2GHZ(c)) { 3515278366Sadrian return (WPI_ACTIVE_DWELL_TIME_2GHZ + 3516278366Sadrian WPI_ACTIVE_DWELL_FACTOR_2GHZ * (n_probes + 1)); 3517278366Sadrian } 3518278366Sadrian 3519278366Sadrian /* 5GHz dwell time. */ 3520278366Sadrian return (WPI_ACTIVE_DWELL_TIME_5GHZ + 3521278366Sadrian WPI_ACTIVE_DWELL_FACTOR_5GHZ * (n_probes + 1)); 3522173362Sbenjsc} 3523173362Sbenjsc 3524173362Sbenjsc/* 3525278366Sadrian * Limit the total dwell time to 85% of the beacon interval. 3526278366Sadrian * 3527278366Sadrian * Returns the dwell time in milliseconds. 3528173362Sbenjsc */ 3529278366Sadrianstatic uint16_t 3530278366Sadrianwpi_limit_dwell(struct wpi_softc *sc, uint16_t dwell_time) 3531278366Sadrian{ 3532278366Sadrian struct ieee80211com *ic = sc->sc_ifp->if_l2com; 3533278366Sadrian struct ieee80211vap *vap = NULL; 3534278366Sadrian int bintval = 0; 3535278366Sadrian 3536278366Sadrian /* bintval is in TU (1.024mS) */ 3537278366Sadrian if (! TAILQ_EMPTY(&ic->ic_vaps)) { 3538278366Sadrian vap = TAILQ_FIRST(&ic->ic_vaps); 3539278366Sadrian bintval = vap->iv_bss->ni_intval; 3540278366Sadrian } 3541278366Sadrian 3542278366Sadrian /* 3543278366Sadrian * If it's non-zero, we should calculate the minimum of 3544278366Sadrian * it and the DWELL_BASE. 3545278366Sadrian * 3546278366Sadrian * XXX Yes, the math should take into account that bintval 3547278366Sadrian * is 1.024mS, not 1mS.. 3548278366Sadrian */ 3549278366Sadrian if (bintval > 0) { 3550278366Sadrian DPRINTF(sc, WPI_DEBUG_SCAN, "%s: bintval=%d\n", __func__, 3551278366Sadrian bintval); 3552278366Sadrian return (MIN(WPI_PASSIVE_DWELL_BASE, ((bintval * 85) / 100))); 3553278366Sadrian } 3554278366Sadrian 3555278366Sadrian /* No association context? Default. */ 3556278366Sadrian return (WPI_PASSIVE_DWELL_BASE); 3557278366Sadrian} 3558278366Sadrian 3559278366Sadrianstatic uint16_t 3560278366Sadrianwpi_get_passive_dwell_time(struct wpi_softc *sc, struct ieee80211_channel *c) 3561278366Sadrian{ 3562278366Sadrian uint16_t passive; 3563278366Sadrian 3564278366Sadrian if (c == NULL || IEEE80211_IS_CHAN_2GHZ(c)) 3565278366Sadrian passive = WPI_PASSIVE_DWELL_BASE + WPI_PASSIVE_DWELL_TIME_2GHZ; 3566278366Sadrian else 3567278366Sadrian passive = WPI_PASSIVE_DWELL_BASE + WPI_PASSIVE_DWELL_TIME_5GHZ; 3568278366Sadrian 3569278366Sadrian /* Clamp to the beacon interval if we're associated. */ 3570278366Sadrian return (wpi_limit_dwell(sc, passive)); 3571278366Sadrian} 3572278366Sadrian 3573278366Sadrian/* 3574278366Sadrian * Send a scan request to the firmware. 3575278366Sadrian */ 3576173362Sbenjscstatic int 3577278366Sadrianwpi_scan(struct wpi_softc *sc, struct ieee80211_channel *c) 3578173362Sbenjsc{ 3579178354Ssam struct ifnet *ifp = sc->sc_ifp; 3580178354Ssam struct ieee80211com *ic = ifp->if_l2com; 3581177043Sthompsa struct ieee80211_scan_state *ss = ic->ic_scan; 3582279762Sadrian struct ieee80211vap *vap = ss->ss_vap; 3583173362Sbenjsc struct wpi_scan_hdr *hdr; 3584278366Sadrian struct wpi_cmd_data *tx; 3585278366Sadrian struct wpi_scan_essid *essids; 3586173362Sbenjsc struct wpi_scan_chan *chan; 3587173362Sbenjsc struct ieee80211_frame *wh; 3588173362Sbenjsc struct ieee80211_rateset *rs; 3589278366Sadrian uint16_t dwell_active, dwell_passive; 3590278366Sadrian uint8_t *buf, *frm; 3591278366Sadrian int buflen, error, i, nssid; 3592173362Sbenjsc 3593278366Sadrian DPRINTF(sc, WPI_DEBUG_TRACE, TRACE_STR_BEGIN, __func__); 3594173362Sbenjsc 3595278366Sadrian /* 3596278366Sadrian * We are absolutely not allowed to send a scan command when another 3597278366Sadrian * scan command is pending. 3598278366Sadrian */ 3599278366Sadrian if (sc->sc_scan_timer) { 3600278366Sadrian device_printf(sc->sc_dev, "%s: called whilst scanning!\n", 3601278366Sadrian __func__); 3602278366Sadrian return (EAGAIN); 3603278366Sadrian } 3604278366Sadrian 3605278366Sadrian buf = malloc(WPI_SCAN_MAXSZ, M_DEVBUF, M_NOWAIT | M_ZERO); 3606278366Sadrian if (buf == NULL) { 3607173362Sbenjsc device_printf(sc->sc_dev, 3608278366Sadrian "%s: could not allocate buffer for scan command\n", 3609278366Sadrian __func__); 3610173362Sbenjsc return ENOMEM; 3611173362Sbenjsc } 3612278366Sadrian hdr = (struct wpi_scan_hdr *)buf; 3613173362Sbenjsc 3614173362Sbenjsc /* 3615278366Sadrian * Move to the next channel if no packets are received within 10 msecs 3616278366Sadrian * after sending the probe request. 3617173362Sbenjsc */ 3618278366Sadrian hdr->quiet_time = htole16(10); /* timeout in milliseconds */ 3619278366Sadrian hdr->quiet_threshold = htole16(1); /* min # of packets */ 3620278366Sadrian /* 3621278366Sadrian * Max needs to be greater than active and passive and quiet! 3622278366Sadrian * It's also in microseconds! 3623278366Sadrian */ 3624278366Sadrian hdr->max_svc = htole32(250 * IEEE80211_DUR_TU); 3625278366Sadrian hdr->pause_svc = htole32((4 << 24) | 3626278366Sadrian (100 * IEEE80211_DUR_TU)); /* Hardcode for now */ 3627278366Sadrian hdr->filter = htole32(WPI_FILTER_MULTICAST | WPI_FILTER_BEACON); 3628173362Sbenjsc 3629278366Sadrian tx = (struct wpi_cmd_data *)(hdr + 1); 3630278366Sadrian tx->flags = htole32(WPI_TX_AUTO_SEQ); 3631278366Sadrian tx->id = WPI_ID_BROADCAST; 3632278366Sadrian tx->lifetime = htole32(WPI_LIFETIME_INFINITE); 3633173362Sbenjsc 3634278366Sadrian if (IEEE80211_IS_CHAN_5GHZ(c)) { 3635278366Sadrian /* Send probe requests at 6Mbps. */ 3636278366Sadrian tx->plcp = wpi_ridx_to_plcp[WPI_RIDX_OFDM6]; 3637278366Sadrian rs = &ic->ic_sup_rates[IEEE80211_MODE_11A]; 3638173362Sbenjsc } else { 3639278366Sadrian hdr->flags = htole32(WPI_RXON_24GHZ | WPI_RXON_AUTO); 3640278366Sadrian /* Send probe requests at 1Mbps. */ 3641278366Sadrian tx->plcp = wpi_ridx_to_plcp[WPI_RIDX_CCK1]; 3642278366Sadrian rs = &ic->ic_sup_rates[IEEE80211_MODE_11G]; 3643173362Sbenjsc } 3644173362Sbenjsc 3645278366Sadrian essids = (struct wpi_scan_essid *)(tx + 1); 3646177043Sthompsa nssid = MIN(ss->ss_nssid, WPI_SCAN_MAX_ESSIDS); 3647178354Ssam for (i = 0; i < nssid; i++) { 3648278366Sadrian essids[i].id = IEEE80211_ELEMID_SSID; 3649278366Sadrian essids[i].len = MIN(ss->ss_ssid[i].len, IEEE80211_NWID_LEN); 3650278366Sadrian memcpy(essids[i].data, ss->ss_ssid[i].ssid, essids[i].len); 3651179957Sthompsa#ifdef WPI_DEBUG 3652278366Sadrian if (sc->sc_debug & WPI_DEBUG_SCAN) { 3653177043Sthompsa printf("Scanning Essid: "); 3654278366Sadrian ieee80211_print_essid(essids[i].data, essids[i].len); 3655177043Sthompsa printf("\n"); 3656177043Sthompsa } 3657179957Sthompsa#endif 3658173362Sbenjsc } 3659173362Sbenjsc 3660173362Sbenjsc /* 3661173362Sbenjsc * Build a probe request frame. Most of the following code is a 3662173362Sbenjsc * copy & paste of what is done in net80211. 3663173362Sbenjsc */ 3664278366Sadrian wh = (struct ieee80211_frame *)(essids + WPI_SCAN_MAX_ESSIDS); 3665173362Sbenjsc wh->i_fc[0] = IEEE80211_FC0_VERSION_0 | IEEE80211_FC0_TYPE_MGT | 3666173362Sbenjsc IEEE80211_FC0_SUBTYPE_PROBE_REQ; 3667173362Sbenjsc wh->i_fc[1] = IEEE80211_FC1_DIR_NODS; 3668173362Sbenjsc IEEE80211_ADDR_COPY(wh->i_addr1, ifp->if_broadcastaddr); 3669279762Sadrian IEEE80211_ADDR_COPY(wh->i_addr2, vap->iv_myaddr); 3670173362Sbenjsc IEEE80211_ADDR_COPY(wh->i_addr3, ifp->if_broadcastaddr); 3671278366Sadrian *(uint16_t *)&wh->i_dur[0] = 0; /* filled by h/w */ 3672278366Sadrian *(uint16_t *)&wh->i_seq[0] = 0; /* filled by h/w */ 3673173362Sbenjsc 3674173362Sbenjsc frm = (uint8_t *)(wh + 1); 3675275966Sadrian frm = ieee80211_add_ssid(frm, NULL, 0); 3676275966Sadrian frm = ieee80211_add_rates(frm, rs); 3677278366Sadrian if (rs->rs_nrates > IEEE80211_RATE_SIZE) 3678278366Sadrian frm = ieee80211_add_xrates(frm, rs); 3679173362Sbenjsc 3680278366Sadrian /* Set length of probe request. */ 3681278366Sadrian tx->len = htole16(frm - (uint8_t *)wh); 3682173362Sbenjsc 3683173362Sbenjsc /* 3684173362Sbenjsc * Construct information about the channel that we 3685173362Sbenjsc * want to scan. The firmware expects this to be directly 3686173362Sbenjsc * after the scan probe request 3687173362Sbenjsc */ 3688173362Sbenjsc chan = (struct wpi_scan_chan *)frm; 3689278366Sadrian chan->chan = htole16(ieee80211_chan2ieee(ic, c)); 3690173362Sbenjsc chan->flags = 0; 3691278366Sadrian if (nssid) { 3692278366Sadrian hdr->crc_threshold = WPI_SCAN_CRC_TH_DEFAULT; 3693278366Sadrian chan->flags |= WPI_CHAN_NPBREQS(nssid); 3694278366Sadrian } else 3695278366Sadrian hdr->crc_threshold = WPI_SCAN_CRC_TH_NEVER; 3696278366Sadrian 3697278764Sadrian if (!IEEE80211_IS_CHAN_PASSIVE(c)) 3698173362Sbenjsc chan->flags |= WPI_CHAN_ACTIVE; 3699173362Sbenjsc 3700278366Sadrian /* 3701278366Sadrian * Calculate the active/passive dwell times. 3702278366Sadrian */ 3703173362Sbenjsc 3704278366Sadrian dwell_active = wpi_get_active_dwell_time(sc, c, nssid); 3705278366Sadrian dwell_passive = wpi_get_passive_dwell_time(sc, c); 3706278366Sadrian 3707278366Sadrian /* Make sure they're valid. */ 3708278366Sadrian if (dwell_passive <= dwell_active) 3709278366Sadrian dwell_passive = dwell_active + 1; 3710278366Sadrian 3711278366Sadrian chan->active = htole16(dwell_active); 3712278366Sadrian chan->passive = htole16(dwell_passive); 3713278366Sadrian 3714278366Sadrian chan->dsp_gain = 0x6e; /* Default level */ 3715278366Sadrian 3716278366Sadrian if (IEEE80211_IS_CHAN_5GHZ(c)) 3717278366Sadrian chan->rf_gain = 0x3b; 3718278366Sadrian else 3719278366Sadrian chan->rf_gain = 0x28; 3720278366Sadrian 3721278366Sadrian DPRINTF(sc, WPI_DEBUG_SCAN, "Scanning %u Passive: %d\n", 3722278764Sadrian chan->chan, IEEE80211_IS_CHAN_PASSIVE(c)); 3723278366Sadrian 3724173362Sbenjsc hdr->nchan++; 3725173362Sbenjsc chan++; 3726173362Sbenjsc 3727278366Sadrian buflen = (uint8_t *)chan - buf; 3728278366Sadrian hdr->len = htole16(buflen); 3729173362Sbenjsc 3730278366Sadrian DPRINTF(sc, WPI_DEBUG_CMD, "sending scan command nchan=%d\n", 3731278366Sadrian hdr->nchan); 3732278366Sadrian error = wpi_cmd(sc, WPI_CMD_SCAN, buf, buflen, 1); 3733278366Sadrian free(buf, M_DEVBUF); 3734173362Sbenjsc 3735278366Sadrian sc->sc_scan_timer = 5; 3736173362Sbenjsc 3737278366Sadrian DPRINTF(sc, WPI_DEBUG_TRACE, TRACE_STR_END, __func__); 3738173362Sbenjsc 3739278366Sadrian return error; 3740278366Sadrian} 3741173362Sbenjsc 3742278366Sadrianstatic int 3743278366Sadrianwpi_auth(struct wpi_softc *sc, struct ieee80211vap *vap) 3744278366Sadrian{ 3745278366Sadrian struct ieee80211com *ic = vap->iv_ic; 3746278366Sadrian struct ieee80211_node *ni = vap->iv_bss; 3747278366Sadrian int error; 3748173362Sbenjsc 3749278366Sadrian DPRINTF(sc, WPI_DEBUG_TRACE, TRACE_STR_BEGIN, __func__); 3750278366Sadrian 3751278366Sadrian /* Update adapter configuration. */ 3752278366Sadrian sc->rxon.associd = 0; 3753278366Sadrian sc->rxon.filter &= ~htole32(WPI_FILTER_BSS); 3754278366Sadrian IEEE80211_ADDR_COPY(sc->rxon.bssid, ni->ni_bssid); 3755278366Sadrian sc->rxon.chan = ieee80211_chan2ieee(ic, ni->ni_chan); 3756278366Sadrian sc->rxon.flags = htole32(WPI_RXON_TSF | WPI_RXON_CTS_TO_SELF); 3757278366Sadrian if (IEEE80211_IS_CHAN_2GHZ(ni->ni_chan)) 3758278366Sadrian sc->rxon.flags |= htole32(WPI_RXON_AUTO | WPI_RXON_24GHZ); 3759278366Sadrian if (ic->ic_flags & IEEE80211_F_SHSLOT) 3760278366Sadrian sc->rxon.flags |= htole32(WPI_RXON_SHSLOT); 3761278366Sadrian if (ic->ic_flags & IEEE80211_F_SHPREAMBLE) 3762278366Sadrian sc->rxon.flags |= htole32(WPI_RXON_SHPREAMBLE); 3763278366Sadrian if (IEEE80211_IS_CHAN_A(ni->ni_chan)) { 3764278366Sadrian sc->rxon.cck_mask = 0; 3765278366Sadrian sc->rxon.ofdm_mask = 0x15; 3766278366Sadrian } else if (IEEE80211_IS_CHAN_B(ni->ni_chan)) { 3767278366Sadrian sc->rxon.cck_mask = 0x03; 3768278366Sadrian sc->rxon.ofdm_mask = 0; 3769278366Sadrian } else { 3770278366Sadrian /* Assume 802.11b/g. */ 3771278366Sadrian sc->rxon.cck_mask = 0x0f; 3772278366Sadrian sc->rxon.ofdm_mask = 0x15; 3773173362Sbenjsc } 3774173362Sbenjsc 3775278366Sadrian DPRINTF(sc, WPI_DEBUG_STATE, "rxon chan %d flags %x cck %x ofdm %x\n", 3776278366Sadrian sc->rxon.chan, sc->rxon.flags, sc->rxon.cck_mask, 3777278366Sadrian sc->rxon.ofdm_mask); 3778173362Sbenjsc 3779278366Sadrian if ((error = wpi_send_rxon(sc, 0, 1)) != 0) { 3780278366Sadrian device_printf(sc->sc_dev, "%s: could not send RXON\n", 3781278366Sadrian __func__); 3782278366Sadrian } 3783173362Sbenjsc 3784278366Sadrian DPRINTF(sc, WPI_DEBUG_TRACE, TRACE_STR_END, __func__); 3785173362Sbenjsc 3786278366Sadrian return error; 3787173362Sbenjsc} 3788173362Sbenjsc 3789173362Sbenjscstatic int 3790278366Sadrianwpi_setup_beacon(struct wpi_softc *sc, struct ieee80211_node *ni) 3791173362Sbenjsc{ 3792178354Ssam struct ifnet *ifp = sc->sc_ifp; 3793178354Ssam struct ieee80211com *ic = ifp->if_l2com; 3794278366Sadrian struct ieee80211vap *vap = ni->ni_vap; 3795278366Sadrian struct wpi_vap *wvp = WPI_VAP(vap); 3796278366Sadrian struct wpi_buf *bcn = &wvp->wv_bcbuf; 3797278366Sadrian struct ieee80211_beacon_offsets bo; 3798278366Sadrian struct wpi_cmd_beacon *cmd; 3799278366Sadrian struct mbuf *m; 3800278366Sadrian int totlen; 3801173362Sbenjsc 3802278366Sadrian DPRINTF(sc, WPI_DEBUG_TRACE, TRACE_STR_DOING, __func__); 3803278366Sadrian 3804278366Sadrian if (ni->ni_chan == IEEE80211_CHAN_ANYC) 3805278366Sadrian return EINVAL; 3806278366Sadrian 3807278366Sadrian m = ieee80211_beacon_alloc(ni, &bo); 3808278366Sadrian if (m == NULL) { 3809278366Sadrian device_printf(sc->sc_dev, 3810278366Sadrian "%s: could not allocate beacon frame\n", __func__); 3811278366Sadrian return ENOMEM; 3812173362Sbenjsc } 3813278366Sadrian totlen = m->m_pkthdr.len; 3814173362Sbenjsc 3815278366Sadrian if (bcn->data == NULL) { 3816278366Sadrian cmd = malloc(sizeof(struct wpi_cmd_beacon), M_DEVBUF, 3817278366Sadrian M_NOWAIT | M_ZERO); 3818278366Sadrian 3819278366Sadrian if (cmd == NULL) { 3820278366Sadrian device_printf(sc->sc_dev, 3821278366Sadrian "could not allocate buffer for beacon command\n"); 3822278366Sadrian m_freem(m); 3823278366Sadrian return ENOMEM; 3824278366Sadrian } 3825278366Sadrian 3826278366Sadrian cmd->id = WPI_ID_BROADCAST; 3827278366Sadrian cmd->ofdm_mask = 0xff; 3828278366Sadrian cmd->cck_mask = 0x0f; 3829278366Sadrian cmd->lifetime = htole32(WPI_LIFETIME_INFINITE); 3830278366Sadrian cmd->flags = htole32(WPI_TX_AUTO_SEQ | WPI_TX_INSERT_TSTAMP); 3831278366Sadrian 3832278366Sadrian bcn->data = cmd; 3833278366Sadrian bcn->ni = NULL; 3834278366Sadrian bcn->code = WPI_CMD_SET_BEACON; 3835278366Sadrian bcn->ac = 4; 3836278366Sadrian bcn->size = sizeof(struct wpi_cmd_beacon); 3837278366Sadrian } else 3838278366Sadrian cmd = bcn->data; 3839278366Sadrian 3840278366Sadrian cmd->len = htole16(totlen); 3841278366Sadrian cmd->plcp = (ic->ic_curmode == IEEE80211_MODE_11A) ? 3842278366Sadrian wpi_ridx_to_plcp[WPI_RIDX_OFDM6] : wpi_ridx_to_plcp[WPI_RIDX_CCK1]; 3843278366Sadrian 3844278366Sadrian /* NB: m will be freed in wpi_cmd_done() */ 3845278366Sadrian bcn->m = m; 3846278366Sadrian 3847278366Sadrian return wpi_cmd2(sc, bcn); 3848278366Sadrian} 3849278366Sadrian 3850278366Sadrianstatic void 3851278366Sadrianwpi_update_beacon(struct ieee80211vap *vap, int item) 3852278366Sadrian{ 3853280057Sadrian struct wpi_softc *sc = vap->iv_ic->ic_ifp->if_softc; 3854278366Sadrian struct ieee80211_node *ni = vap->iv_bss; 3855278366Sadrian int error; 3856278366Sadrian 3857278764Sadrian WPI_LOCK(sc); 3858278366Sadrian if ((error = wpi_setup_beacon(sc, ni)) != 0) { 3859173362Sbenjsc device_printf(sc->sc_dev, 3860278366Sadrian "%s: could not update beacon frame, error %d", __func__, 3861278366Sadrian error); 3862173362Sbenjsc } 3863278764Sadrian WPI_UNLOCK(sc); 3864278366Sadrian} 3865173362Sbenjsc 3866278366Sadrianstatic int 3867278366Sadrianwpi_run(struct wpi_softc *sc, struct ieee80211vap *vap) 3868278366Sadrian{ 3869278366Sadrian struct ieee80211com *ic = vap->iv_ic; 3870278366Sadrian struct ieee80211_node *ni = vap->iv_bss; 3871278366Sadrian int error; 3872278366Sadrian 3873278366Sadrian DPRINTF(sc, WPI_DEBUG_TRACE, TRACE_STR_BEGIN, __func__); 3874278366Sadrian 3875278366Sadrian if (vap->iv_opmode == IEEE80211_M_MONITOR) { 3876278366Sadrian /* Link LED blinks while monitoring. */ 3877278366Sadrian wpi_set_led(sc, WPI_LED_LINK, 5, 5); 3878278366Sadrian return 0; 3879173362Sbenjsc } 3880278366Sadrian 3881278366Sadrian /* XXX kernel panic workaround */ 3882278366Sadrian if (ni->ni_chan == IEEE80211_CHAN_ANYC) { 3883278366Sadrian device_printf(sc->sc_dev, "%s: incomplete configuration\n", 3884278366Sadrian __func__); 3885195562Srpaulo return EINVAL; 3886173362Sbenjsc } 3887278366Sadrian 3888278366Sadrian if ((error = wpi_set_timing(sc, ni)) != 0) { 3889278366Sadrian device_printf(sc->sc_dev, 3890278366Sadrian "%s: could not set timing, error %d\n", __func__, error); 3891173362Sbenjsc return error; 3892173362Sbenjsc } 3893173362Sbenjsc 3894278366Sadrian /* Update adapter configuration. */ 3895278366Sadrian IEEE80211_ADDR_COPY(sc->rxon.bssid, ni->ni_bssid); 3896278366Sadrian sc->rxon.associd = htole16(IEEE80211_NODE_AID(ni)); 3897278366Sadrian sc->rxon.chan = ieee80211_chan2ieee(ic, ni->ni_chan); 3898278366Sadrian sc->rxon.flags = htole32(WPI_RXON_TSF | WPI_RXON_CTS_TO_SELF); 3899278366Sadrian if (IEEE80211_IS_CHAN_2GHZ(ni->ni_chan)) 3900278366Sadrian sc->rxon.flags |= htole32(WPI_RXON_AUTO | WPI_RXON_24GHZ); 3901278366Sadrian /* Short preamble and slot time are negotiated when associating. */ 3902278366Sadrian sc->rxon.flags &= ~htole32(WPI_RXON_SHPREAMBLE | WPI_RXON_SHSLOT); 3903278366Sadrian if (ic->ic_flags & IEEE80211_F_SHSLOT) 3904278366Sadrian sc->rxon.flags |= htole32(WPI_RXON_SHSLOT); 3905278366Sadrian if (ic->ic_flags & IEEE80211_F_SHPREAMBLE) 3906278366Sadrian sc->rxon.flags |= htole32(WPI_RXON_SHPREAMBLE); 3907278366Sadrian if (IEEE80211_IS_CHAN_A(ni->ni_chan)) { 3908278366Sadrian sc->rxon.cck_mask = 0; 3909278366Sadrian sc->rxon.ofdm_mask = 0x15; 3910278366Sadrian } else if (IEEE80211_IS_CHAN_B(ni->ni_chan)) { 3911278366Sadrian sc->rxon.cck_mask = 0x03; 3912278366Sadrian sc->rxon.ofdm_mask = 0; 3913278366Sadrian } else { 3914278366Sadrian /* Assume 802.11b/g. */ 3915278366Sadrian sc->rxon.cck_mask = 0x0f; 3916278366Sadrian sc->rxon.ofdm_mask = 0x15; 3917173362Sbenjsc } 3918278366Sadrian sc->rxon.filter |= htole32(WPI_FILTER_BSS); 3919173362Sbenjsc 3920278366Sadrian /* XXX put somewhere HC_QOS_SUPPORT_ASSOC + HC_IBSS_START */ 3921278366Sadrian 3922278366Sadrian DPRINTF(sc, WPI_DEBUG_STATE, "rxon chan %d flags %x\n", 3923278366Sadrian sc->rxon.chan, sc->rxon.flags); 3924278366Sadrian 3925278366Sadrian if ((error = wpi_send_rxon(sc, 0, 1)) != 0) { 3926278366Sadrian device_printf(sc->sc_dev, "%s: could not send RXON\n", 3927278366Sadrian __func__); 3928173362Sbenjsc return error; 3929173362Sbenjsc } 3930173362Sbenjsc 3931278366Sadrian if (vap->iv_opmode == IEEE80211_M_IBSS) { 3932278366Sadrian if ((error = wpi_setup_beacon(sc, ni)) != 0) { 3933278366Sadrian device_printf(sc->sc_dev, 3934278366Sadrian "%s: could not setup beacon, error %d\n", __func__, 3935278366Sadrian error); 3936278366Sadrian return error; 3937278366Sadrian } 3938173362Sbenjsc } 3939173362Sbenjsc 3940278366Sadrian if (vap->iv_opmode == IEEE80211_M_STA) { 3941278366Sadrian /* Add BSS node. */ 3942278366Sadrian ((struct wpi_node *)ni)->id = WPI_ID_BSS; 3943278366Sadrian if ((error = wpi_add_node(sc, ni)) != 0) { 3944278366Sadrian device_printf(sc->sc_dev, 3945278366Sadrian "%s: could not add BSS node, error %d\n", __func__, 3946278366Sadrian error); 3947278366Sadrian return error; 3948278366Sadrian } 3949278366Sadrian } 3950173362Sbenjsc 3951278366Sadrian /* Link LED always on while associated. */ 3952278366Sadrian wpi_set_led(sc, WPI_LED_LINK, 0, 1); 3953173362Sbenjsc 3954278366Sadrian /* Start periodic calibration timer. */ 3955278366Sadrian callout_reset(&sc->calib_to, 60*hz, wpi_calib_timeout, sc); 3956173362Sbenjsc 3957278366Sadrian /* Enable power-saving mode if requested by user. */ 3958278366Sadrian if (vap->iv_flags & IEEE80211_F_PMGTON) 3959278366Sadrian (void)wpi_set_pslevel(sc, 0, 3, 1); 3960278764Sadrian else 3961278764Sadrian (void)wpi_set_pslevel(sc, 0, 0, 1); 3962173362Sbenjsc 3963278366Sadrian DPRINTF(sc, WPI_DEBUG_TRACE, TRACE_STR_END, __func__); 3964173362Sbenjsc 3965278366Sadrian return 0; 3966173362Sbenjsc} 3967173362Sbenjsc 3968173362Sbenjscstatic int 3969278366Sadrianwpi_key_alloc(struct ieee80211vap *vap, struct ieee80211_key *k, 3970278366Sadrian ieee80211_keyix *keyix, ieee80211_keyix *rxkeyix) 3971173362Sbenjsc{ 3972280057Sadrian struct wpi_softc *sc = vap->iv_ic->ic_ifp->if_softc; 3973173362Sbenjsc 3974278366Sadrian if (!(&vap->iv_nw_keys[0] <= k && 3975278366Sadrian k < &vap->iv_nw_keys[IEEE80211_WEP_NKID])) { 3976278366Sadrian if (k->wk_flags & IEEE80211_KEY_GROUP) { 3977278366Sadrian /* should not happen */ 3978278366Sadrian DPRINTF(sc, WPI_DEBUG_KEY, "%s: bogus group key\n", 3979278366Sadrian __func__); 3980278366Sadrian return 0; 3981278366Sadrian } 3982278366Sadrian *keyix = 0; /* NB: use key index 0 for ucast key */ 3983278366Sadrian } else { 3984278366Sadrian *keyix = *rxkeyix = k - vap->iv_nw_keys; 3985173362Sbenjsc 3986278366Sadrian if (k->wk_cipher->ic_cipher == IEEE80211_CIPHER_AES_CCM) 3987278366Sadrian k->wk_flags |= IEEE80211_KEY_SWCRYPT; 3988173362Sbenjsc } 3989278366Sadrian return 1; 3990173362Sbenjsc} 3991173362Sbenjsc 3992173362Sbenjscstatic int 3993278366Sadrianwpi_key_set(struct ieee80211vap *vap, const struct ieee80211_key *k, 3994278366Sadrian const uint8_t mac[IEEE80211_ADDR_LEN]) 3995173362Sbenjsc{ 3996278366Sadrian const struct ieee80211_cipher *cip = k->wk_cipher; 3997278366Sadrian struct ieee80211com *ic = vap->iv_ic; 3998278366Sadrian struct ieee80211_node *ni = vap->iv_bss; 3999278366Sadrian struct wpi_softc *sc = ic->ic_ifp->if_softc; 4000278366Sadrian struct wpi_node *wn = (void *)ni; 4001278366Sadrian struct wpi_node_info node; 4002278366Sadrian uint16_t kflags; 4003278366Sadrian int error; 4004173362Sbenjsc 4005278366Sadrian DPRINTF(sc, WPI_DEBUG_TRACE, TRACE_STR_DOING, __func__); 4006173362Sbenjsc 4007278366Sadrian switch (cip->ic_cipher) { 4008278366Sadrian case IEEE80211_CIPHER_AES_CCM: 4009278366Sadrian if (k->wk_flags & IEEE80211_KEY_GROUP) 4010278366Sadrian return 1; 4011173362Sbenjsc 4012278366Sadrian kflags = WPI_KFLAG_CCMP; 4013278366Sadrian break; 4014278366Sadrian default: 4015278366Sadrian /* null_key_set() */ 4016278366Sadrian return 1; 4017278366Sadrian } 4018173362Sbenjsc 4019278366Sadrian if (wn->id == WPI_ID_UNDEFINED) 4020278366Sadrian return 0; 4021173362Sbenjsc 4022278366Sadrian kflags |= WPI_KFLAG_KID(k->wk_keyix); 4023278366Sadrian if (k->wk_flags & IEEE80211_KEY_GROUP) 4024278366Sadrian kflags |= WPI_KFLAG_MULTICAST; 4025173362Sbenjsc 4026278366Sadrian memset(&node, 0, sizeof node); 4027278366Sadrian node.id = wn->id; 4028278366Sadrian node.control = WPI_NODE_UPDATE; 4029278366Sadrian node.flags = WPI_FLAG_KEY_SET; 4030278366Sadrian node.kflags = htole16(kflags); 4031278366Sadrian memcpy(node.key, k->wk_key, k->wk_keylen); 4032173362Sbenjsc 4033278366Sadrian DPRINTF(sc, WPI_DEBUG_KEY, "set key id=%d for node %d\n", k->wk_keyix, 4034278366Sadrian node.id); 4035173362Sbenjsc 4036278366Sadrian error = wpi_cmd(sc, WPI_CMD_ADD_NODE, &node, sizeof node, 1); 4037278366Sadrian if (error != 0) { 4038278366Sadrian device_printf(sc->sc_dev, "can't update node info, error %d\n", 4039278366Sadrian error); 4040278366Sadrian return 0; 4041173362Sbenjsc } 4042173362Sbenjsc 4043278366Sadrian return 1; 4044173362Sbenjsc} 4045173362Sbenjsc 4046278366Sadrianstatic int 4047278366Sadrianwpi_key_delete(struct ieee80211vap *vap, const struct ieee80211_key *k) 4048173362Sbenjsc{ 4049278366Sadrian const struct ieee80211_cipher *cip = k->wk_cipher; 4050278366Sadrian struct ieee80211com *ic = vap->iv_ic; 4051278366Sadrian struct ieee80211_node *ni = vap->iv_bss; 4052278366Sadrian struct wpi_softc *sc = ic->ic_ifp->if_softc; 4053278366Sadrian struct wpi_node *wn = (void *)ni; 4054278366Sadrian struct wpi_node_info node; 4055173362Sbenjsc 4056278366Sadrian DPRINTF(sc, WPI_DEBUG_TRACE, TRACE_STR_DOING, __func__); 4057173362Sbenjsc 4058278366Sadrian switch (cip->ic_cipher) { 4059278366Sadrian case IEEE80211_CIPHER_AES_CCM: 4060278366Sadrian break; 4061278366Sadrian default: 4062278366Sadrian /* null_key_delete() */ 4063278366Sadrian return 1; 4064278366Sadrian } 4065173362Sbenjsc 4066278366Sadrian if (vap->iv_state != IEEE80211_S_RUN || 4067278366Sadrian (k->wk_flags & IEEE80211_KEY_GROUP)) 4068278366Sadrian return 1; /* Nothing to do. */ 4069173362Sbenjsc 4070278366Sadrian memset(&node, 0, sizeof node); 4071278366Sadrian node.id = wn->id; 4072278366Sadrian node.control = WPI_NODE_UPDATE; 4073278366Sadrian node.flags = WPI_FLAG_KEY_SET; 4074173362Sbenjsc 4075278366Sadrian DPRINTF(sc, WPI_DEBUG_KEY, "delete keys for node %d\n", node.id); 4076278366Sadrian (void)wpi_cmd(sc, WPI_CMD_ADD_NODE, &node, sizeof node, 1); 4077173362Sbenjsc 4078278366Sadrian return 1; 4079173362Sbenjsc} 4080173362Sbenjsc 4081278366Sadrian/* 4082278366Sadrian * This function is called after the runtime firmware notifies us of its 4083278366Sadrian * readiness (called in a process context). 4084278366Sadrian */ 4085278366Sadrianstatic int 4086278366Sadrianwpi_post_alive(struct wpi_softc *sc) 4087177043Sthompsa{ 4088278366Sadrian int ntries, error; 4089177043Sthompsa 4090278366Sadrian /* Check (again) that the radio is not disabled. */ 4091278366Sadrian if ((error = wpi_nic_lock(sc)) != 0) 4092278366Sadrian return error; 4093177043Sthompsa 4094278366Sadrian DPRINTF(sc, WPI_DEBUG_TRACE, TRACE_STR_DOING, __func__); 4095278366Sadrian 4096278366Sadrian /* NB: Runtime firmware must be up and running. */ 4097278366Sadrian if (!(wpi_prph_read(sc, WPI_APMG_RFKILL) & 1)) { 4098278366Sadrian device_printf(sc->sc_dev, 4099278366Sadrian "RF switch: radio disabled (%s)\n", __func__); 4100278366Sadrian wpi_nic_unlock(sc); 4101278366Sadrian return EPERM; /* :-) */ 4102278366Sadrian } 4103278366Sadrian wpi_nic_unlock(sc); 4104278366Sadrian 4105278366Sadrian /* Wait for thermal sensor to calibrate. */ 4106177043Sthompsa for (ntries = 0; ntries < 1000; ntries++) { 4107278366Sadrian if ((sc->temp = (int)WPI_READ(sc, WPI_UCODE_GP2)) != 0) 4108177043Sthompsa break; 4109177043Sthompsa DELAY(10); 4110177043Sthompsa } 4111177043Sthompsa 4112177043Sthompsa if (ntries == 1000) { 4113177043Sthompsa device_printf(sc->sc_dev, 4114278366Sadrian "timeout waiting for thermal sensor calibration\n"); 4115278366Sadrian return ETIMEDOUT; 4116278366Sadrian } 4117177043Sthompsa 4118278366Sadrian DPRINTF(sc, WPI_DEBUG_TEMP, "temperature %d\n", sc->temp); 4119278366Sadrian return 0; 4120278366Sadrian} 4121177043Sthompsa 4122278366Sadrian/* 4123278366Sadrian * The firmware boot code is small and is intended to be copied directly into 4124278366Sadrian * the NIC internal memory (no DMA transfer). 4125278366Sadrian */ 4126278366Sadrianstatic int 4127278366Sadrianwpi_load_bootcode(struct wpi_softc *sc, const uint8_t *ucode, int size) 4128278366Sadrian{ 4129278366Sadrian int error, ntries; 4130177043Sthompsa 4131278366Sadrian DPRINTF(sc, WPI_DEBUG_HW, "Loading microcode size 0x%x\n", size); 4132278366Sadrian 4133278366Sadrian size /= sizeof (uint32_t); 4134278366Sadrian 4135278366Sadrian if ((error = wpi_nic_lock(sc)) != 0) 4136278366Sadrian return error; 4137278366Sadrian 4138278366Sadrian /* Copy microcode image into NIC memory. */ 4139278366Sadrian wpi_prph_write_region_4(sc, WPI_BSM_SRAM_BASE, 4140278366Sadrian (const uint32_t *)ucode, size); 4141278366Sadrian 4142278366Sadrian wpi_prph_write(sc, WPI_BSM_WR_MEM_SRC, 0); 4143278366Sadrian wpi_prph_write(sc, WPI_BSM_WR_MEM_DST, WPI_FW_TEXT_BASE); 4144278366Sadrian wpi_prph_write(sc, WPI_BSM_WR_DWCOUNT, size); 4145278366Sadrian 4146278366Sadrian /* Start boot load now. */ 4147278366Sadrian wpi_prph_write(sc, WPI_BSM_WR_CTRL, WPI_BSM_WR_CTRL_START); 4148278366Sadrian 4149278366Sadrian /* Wait for transfer to complete. */ 4150278366Sadrian for (ntries = 0; ntries < 1000; ntries++) { 4151278366Sadrian uint32_t status = WPI_READ(sc, WPI_FH_TX_STATUS); 4152278366Sadrian DPRINTF(sc, WPI_DEBUG_HW, 4153278366Sadrian "firmware status=0x%x, val=0x%x, result=0x%x\n", status, 4154278366Sadrian WPI_FH_TX_STATUS_IDLE(6), 4155278366Sadrian status & WPI_FH_TX_STATUS_IDLE(6)); 4156278366Sadrian if (status & WPI_FH_TX_STATUS_IDLE(6)) { 4157278366Sadrian DPRINTF(sc, WPI_DEBUG_HW, 4158278366Sadrian "Status Match! - ntries = %d\n", ntries); 4159278366Sadrian break; 4160178354Ssam } 4161278366Sadrian DELAY(10); 4162177043Sthompsa } 4163278366Sadrian if (ntries == 1000) { 4164278366Sadrian device_printf(sc->sc_dev, "%s: could not load boot firmware\n", 4165278366Sadrian __func__); 4166278366Sadrian wpi_nic_unlock(sc); 4167278366Sadrian return ETIMEDOUT; 4168278366Sadrian } 4169177043Sthompsa 4170278366Sadrian /* Enable boot after power up. */ 4171278366Sadrian wpi_prph_write(sc, WPI_BSM_WR_CTRL, WPI_BSM_WR_CTRL_START_EN); 4172278366Sadrian 4173278366Sadrian wpi_nic_unlock(sc); 4174278366Sadrian return 0; 4175177043Sthompsa} 4176177043Sthompsa 4177278366Sadrianstatic int 4178278366Sadrianwpi_load_firmware(struct wpi_softc *sc) 4179177043Sthompsa{ 4180278366Sadrian struct wpi_fw_info *fw = &sc->fw; 4181278366Sadrian struct wpi_dma_info *dma = &sc->fw_dma; 4182278366Sadrian int error; 4183173362Sbenjsc 4184278366Sadrian DPRINTF(sc, WPI_DEBUG_TRACE, TRACE_STR_DOING, __func__); 4185173362Sbenjsc 4186278366Sadrian /* Copy initialization sections into pre-allocated DMA-safe memory. */ 4187278366Sadrian memcpy(dma->vaddr, fw->init.data, fw->init.datasz); 4188278366Sadrian bus_dmamap_sync(dma->tag, dma->map, BUS_DMASYNC_PREWRITE); 4189278366Sadrian memcpy(dma->vaddr + WPI_FW_DATA_MAXSZ, fw->init.text, fw->init.textsz); 4190278366Sadrian bus_dmamap_sync(dma->tag, dma->map, BUS_DMASYNC_PREWRITE); 4191173362Sbenjsc 4192278366Sadrian /* Tell adapter where to find initialization sections. */ 4193278366Sadrian if ((error = wpi_nic_lock(sc)) != 0) 4194278366Sadrian return error; 4195278366Sadrian wpi_prph_write(sc, WPI_BSM_DRAM_DATA_ADDR, dma->paddr); 4196278366Sadrian wpi_prph_write(sc, WPI_BSM_DRAM_DATA_SIZE, fw->init.datasz); 4197278366Sadrian wpi_prph_write(sc, WPI_BSM_DRAM_TEXT_ADDR, 4198278366Sadrian dma->paddr + WPI_FW_DATA_MAXSZ); 4199278366Sadrian wpi_prph_write(sc, WPI_BSM_DRAM_TEXT_SIZE, fw->init.textsz); 4200278366Sadrian wpi_nic_unlock(sc); 4201173362Sbenjsc 4202278366Sadrian /* Load firmware boot code. */ 4203278366Sadrian error = wpi_load_bootcode(sc, fw->boot.text, fw->boot.textsz); 4204278366Sadrian if (error != 0) { 4205278366Sadrian device_printf(sc->sc_dev, "%s: could not load boot firmware\n", 4206278366Sadrian __func__); 4207278366Sadrian return error; 4208278366Sadrian } 4209173362Sbenjsc 4210278366Sadrian /* Now press "execute". */ 4211278366Sadrian WPI_WRITE(sc, WPI_RESET, 0); 4212173362Sbenjsc 4213278366Sadrian /* Wait at most one second for first alive notification. */ 4214278366Sadrian if ((error = msleep(sc, &sc->sc_mtx, PCATCH, "wpiinit", hz)) != 0) { 4215278366Sadrian device_printf(sc->sc_dev, 4216278366Sadrian "%s: timeout waiting for adapter to initialize, error %d\n", 4217278366Sadrian __func__, error); 4218278366Sadrian return error; 4219173362Sbenjsc } 4220173362Sbenjsc 4221278366Sadrian /* Copy runtime sections into pre-allocated DMA-safe memory. */ 4222278366Sadrian memcpy(dma->vaddr, fw->main.data, fw->main.datasz); 4223278366Sadrian bus_dmamap_sync(dma->tag, dma->map, BUS_DMASYNC_PREWRITE); 4224278366Sadrian memcpy(dma->vaddr + WPI_FW_DATA_MAXSZ, fw->main.text, fw->main.textsz); 4225278366Sadrian bus_dmamap_sync(dma->tag, dma->map, BUS_DMASYNC_PREWRITE); 4226173362Sbenjsc 4227278366Sadrian /* Tell adapter where to find runtime sections. */ 4228278366Sadrian if ((error = wpi_nic_lock(sc)) != 0) 4229278366Sadrian return error; 4230278366Sadrian wpi_prph_write(sc, WPI_BSM_DRAM_DATA_ADDR, dma->paddr); 4231278366Sadrian wpi_prph_write(sc, WPI_BSM_DRAM_DATA_SIZE, fw->main.datasz); 4232278366Sadrian wpi_prph_write(sc, WPI_BSM_DRAM_TEXT_ADDR, 4233278366Sadrian dma->paddr + WPI_FW_DATA_MAXSZ); 4234278366Sadrian wpi_prph_write(sc, WPI_BSM_DRAM_TEXT_SIZE, 4235278366Sadrian WPI_FW_UPDATED | fw->main.textsz); 4236278366Sadrian wpi_nic_unlock(sc); 4237173362Sbenjsc 4238278366Sadrian return 0; 4239278366Sadrian} 4240173362Sbenjsc 4241278366Sadrianstatic int 4242278366Sadrianwpi_read_firmware(struct wpi_softc *sc) 4243278366Sadrian{ 4244278366Sadrian const struct firmware *fp; 4245278366Sadrian struct wpi_fw_info *fw = &sc->fw; 4246278366Sadrian const struct wpi_firmware_hdr *hdr; 4247278366Sadrian int error; 4248173362Sbenjsc 4249278366Sadrian DPRINTF(sc, WPI_DEBUG_TRACE, TRACE_STR_DOING, __func__); 4250278366Sadrian 4251278366Sadrian DPRINTF(sc, WPI_DEBUG_FIRMWARE, 4252278366Sadrian "Attempting Loading Firmware from %s module\n", WPI_FW_NAME); 4253278366Sadrian 4254278366Sadrian WPI_UNLOCK(sc); 4255278366Sadrian fp = firmware_get(WPI_FW_NAME); 4256278366Sadrian WPI_LOCK(sc); 4257278366Sadrian 4258278366Sadrian if (fp == NULL) { 4259278366Sadrian device_printf(sc->sc_dev, 4260278366Sadrian "could not load firmware image '%s'\n", WPI_FW_NAME); 4261278366Sadrian return EINVAL; 4262173362Sbenjsc } 4263173362Sbenjsc 4264278366Sadrian sc->fw_fp = fp; 4265173362Sbenjsc 4266278366Sadrian if (fp->datasize < sizeof (struct wpi_firmware_hdr)) { 4267278366Sadrian device_printf(sc->sc_dev, 4268278366Sadrian "firmware file too short: %zu bytes\n", fp->datasize); 4269278366Sadrian error = EINVAL; 4270278366Sadrian goto fail; 4271173362Sbenjsc } 4272173362Sbenjsc 4273278366Sadrian fw->size = fp->datasize; 4274278366Sadrian fw->data = (const uint8_t *)fp->data; 4275278366Sadrian 4276278366Sadrian /* Extract firmware header information. */ 4277278366Sadrian hdr = (const struct wpi_firmware_hdr *)fw->data; 4278278366Sadrian 4279278366Sadrian /* | RUNTIME FIRMWARE | INIT FIRMWARE | BOOT FW | 4280278366Sadrian |HDR|<--TEXT-->|<--DATA-->|<--TEXT-->|<--DATA-->|<--TEXT-->| */ 4281278366Sadrian 4282278366Sadrian fw->main.textsz = le32toh(hdr->rtextsz); 4283278366Sadrian fw->main.datasz = le32toh(hdr->rdatasz); 4284278366Sadrian fw->init.textsz = le32toh(hdr->itextsz); 4285278366Sadrian fw->init.datasz = le32toh(hdr->idatasz); 4286278366Sadrian fw->boot.textsz = le32toh(hdr->btextsz); 4287278366Sadrian fw->boot.datasz = 0; 4288278366Sadrian 4289278366Sadrian /* Sanity-check firmware header. */ 4290278366Sadrian if (fw->main.textsz > WPI_FW_TEXT_MAXSZ || 4291278366Sadrian fw->main.datasz > WPI_FW_DATA_MAXSZ || 4292278366Sadrian fw->init.textsz > WPI_FW_TEXT_MAXSZ || 4293278366Sadrian fw->init.datasz > WPI_FW_DATA_MAXSZ || 4294278366Sadrian fw->boot.textsz > WPI_FW_BOOT_TEXT_MAXSZ || 4295278366Sadrian (fw->boot.textsz & 3) != 0) { 4296278366Sadrian device_printf(sc->sc_dev, "invalid firmware header\n"); 4297278366Sadrian error = EINVAL; 4298278366Sadrian goto fail; 4299173362Sbenjsc } 4300173362Sbenjsc 4301278366Sadrian /* Check that all firmware sections fit. */ 4302278366Sadrian if (fw->size < sizeof (*hdr) + fw->main.textsz + fw->main.datasz + 4303278366Sadrian fw->init.textsz + fw->init.datasz + fw->boot.textsz) { 4304173362Sbenjsc device_printf(sc->sc_dev, 4305278366Sadrian "firmware file too short: %zu bytes\n", fw->size); 4306278366Sadrian error = EINVAL; 4307278366Sadrian goto fail; 4308173362Sbenjsc } 4309173362Sbenjsc 4310278366Sadrian /* Get pointers to firmware sections. */ 4311278366Sadrian fw->main.text = (const uint8_t *)(hdr + 1); 4312278366Sadrian fw->main.data = fw->main.text + fw->main.textsz; 4313278366Sadrian fw->init.text = fw->main.data + fw->main.datasz; 4314278366Sadrian fw->init.data = fw->init.text + fw->init.textsz; 4315278366Sadrian fw->boot.text = fw->init.data + fw->init.datasz; 4316177043Sthompsa 4317278366Sadrian DPRINTF(sc, WPI_DEBUG_FIRMWARE, 4318278366Sadrian "Firmware Version: Major %d, Minor %d, Driver %d, \n" 4319278366Sadrian "runtime (text: %u, data: %u) init (text: %u, data %u) boot (text %u)\n", 4320278366Sadrian hdr->major, hdr->minor, le32toh(hdr->driver), 4321278366Sadrian fw->main.textsz, fw->main.datasz, 4322278366Sadrian fw->init.textsz, fw->init.datasz, fw->boot.textsz); 4323278366Sadrian 4324278366Sadrian DPRINTF(sc, WPI_DEBUG_FIRMWARE, "fw->main.text %p\n", fw->main.text); 4325278366Sadrian DPRINTF(sc, WPI_DEBUG_FIRMWARE, "fw->main.data %p\n", fw->main.data); 4326278366Sadrian DPRINTF(sc, WPI_DEBUG_FIRMWARE, "fw->init.text %p\n", fw->init.text); 4327278366Sadrian DPRINTF(sc, WPI_DEBUG_FIRMWARE, "fw->init.data %p\n", fw->init.data); 4328278366Sadrian DPRINTF(sc, WPI_DEBUG_FIRMWARE, "fw->boot.text %p\n", fw->boot.text); 4329278366Sadrian 4330278366Sadrian return 0; 4331278366Sadrian 4332278366Sadrianfail: wpi_unload_firmware(sc); 4333278366Sadrian return error; 4334173362Sbenjsc} 4335173362Sbenjsc 4336278366Sadrian/** 4337278366Sadrian * Free the referenced firmware image 4338278366Sadrian */ 4339173362Sbenjscstatic void 4340278366Sadrianwpi_unload_firmware(struct wpi_softc *sc) 4341173362Sbenjsc{ 4342278366Sadrian if (sc->fw_fp != NULL) { 4343278366Sadrian firmware_put(sc->fw_fp, FIRMWARE_UNLOAD); 4344278366Sadrian sc->fw_fp = NULL; 4345278366Sadrian } 4346278366Sadrian} 4347173362Sbenjsc 4348278366Sadrianstatic int 4349278366Sadrianwpi_clock_wait(struct wpi_softc *sc) 4350278366Sadrian{ 4351278366Sadrian int ntries; 4352173362Sbenjsc 4353278366Sadrian /* Set "initialization complete" bit. */ 4354278366Sadrian WPI_SETBITS(sc, WPI_GP_CNTRL, WPI_GP_CNTRL_INIT_DONE); 4355278366Sadrian 4356278366Sadrian /* Wait for clock stabilization. */ 4357278366Sadrian for (ntries = 0; ntries < 2500; ntries++) { 4358278366Sadrian if (WPI_READ(sc, WPI_GP_CNTRL) & WPI_GP_CNTRL_MAC_CLOCK_READY) 4359278366Sadrian return 0; 4360278366Sadrian DELAY(100); 4361278366Sadrian } 4362278366Sadrian device_printf(sc->sc_dev, 4363278366Sadrian "%s: timeout waiting for clock stabilization\n", __func__); 4364278366Sadrian 4365278366Sadrian return ETIMEDOUT; 4366173362Sbenjsc} 4367178354Ssam 4368278366Sadrianstatic int 4369278366Sadrianwpi_apm_init(struct wpi_softc *sc) 4370173362Sbenjsc{ 4371278366Sadrian uint32_t reg; 4372278366Sadrian int error; 4373173362Sbenjsc 4374278366Sadrian DPRINTF(sc, WPI_DEBUG_TRACE, TRACE_STR_DOING, __func__); 4375173362Sbenjsc 4376278366Sadrian /* Disable L0s exit timer (NMI bug workaround). */ 4377278366Sadrian WPI_SETBITS(sc, WPI_GIO_CHICKEN, WPI_GIO_CHICKEN_DIS_L0S_TIMER); 4378278366Sadrian /* Don't wait for ICH L0s (ICH bug workaround). */ 4379278366Sadrian WPI_SETBITS(sc, WPI_GIO_CHICKEN, WPI_GIO_CHICKEN_L1A_NO_L0S_RX); 4380173362Sbenjsc 4381278366Sadrian /* Set FH wait threshold to max (HW bug under stress workaround). */ 4382278366Sadrian WPI_SETBITS(sc, WPI_DBG_HPET_MEM, 0xffff0000); 4383173362Sbenjsc 4384278366Sadrian /* Retrieve PCIe Active State Power Management (ASPM). */ 4385278366Sadrian reg = pci_read_config(sc->sc_dev, sc->sc_cap_off + 0x10, 1); 4386278366Sadrian /* Workaround for HW instability in PCIe L0->L0s->L1 transition. */ 4387278366Sadrian if (reg & 0x02) /* L1 Entry enabled. */ 4388278366Sadrian WPI_SETBITS(sc, WPI_GIO, WPI_GIO_L0S_ENA); 4389278366Sadrian else 4390278366Sadrian WPI_CLRBITS(sc, WPI_GIO, WPI_GIO_L0S_ENA); 4391173362Sbenjsc 4392278366Sadrian WPI_SETBITS(sc, WPI_ANA_PLL, WPI_ANA_PLL_INIT); 4393173362Sbenjsc 4394278366Sadrian /* Wait for clock stabilization before accessing prph. */ 4395278366Sadrian if ((error = wpi_clock_wait(sc)) != 0) 4396278366Sadrian return error; 4397173362Sbenjsc 4398278366Sadrian if ((error = wpi_nic_lock(sc)) != 0) 4399278366Sadrian return error; 4400278366Sadrian /* Enable DMA and BSM (Bootstrap State Machine). */ 4401278366Sadrian wpi_prph_write(sc, WPI_APMG_CLK_EN, 4402278366Sadrian WPI_APMG_CLK_CTRL_DMA_CLK_RQT | WPI_APMG_CLK_CTRL_BSM_CLK_RQT); 4403278366Sadrian DELAY(20); 4404278366Sadrian /* Disable L1-Active. */ 4405278366Sadrian wpi_prph_setbits(sc, WPI_APMG_PCI_STT, WPI_APMG_PCI_STT_L1A_DIS); 4406278764Sadrian /* ??? */ 4407278764Sadrian wpi_prph_clrbits(sc, WPI_APMG_PS, 0x00000E00); 4408278366Sadrian wpi_nic_unlock(sc); 4409173362Sbenjsc 4410278366Sadrian return 0; 4411278366Sadrian} 4412173362Sbenjsc 4413278366Sadrianstatic void 4414278366Sadrianwpi_apm_stop_master(struct wpi_softc *sc) 4415278366Sadrian{ 4416278366Sadrian int ntries; 4417278366Sadrian 4418278366Sadrian /* Stop busmaster DMA activity. */ 4419278366Sadrian WPI_SETBITS(sc, WPI_RESET, WPI_RESET_STOP_MASTER); 4420278366Sadrian 4421278366Sadrian if ((WPI_READ(sc, WPI_GP_CNTRL) & WPI_GP_CNTRL_PS_MASK) == 4422278366Sadrian WPI_GP_CNTRL_MAC_PS) 4423278366Sadrian return; /* Already asleep. */ 4424278366Sadrian 4425278366Sadrian for (ntries = 0; ntries < 100; ntries++) { 4426278366Sadrian if (WPI_READ(sc, WPI_RESET) & WPI_RESET_MASTER_DISABLED) 4427278366Sadrian return; 4428278366Sadrian DELAY(10); 4429278366Sadrian } 4430278366Sadrian device_printf(sc->sc_dev, "%s: timeout waiting for master\n", __func__); 4431173362Sbenjsc} 4432173362Sbenjsc 4433173362Sbenjscstatic void 4434278366Sadrianwpi_apm_stop(struct wpi_softc *sc) 4435173362Sbenjsc{ 4436278366Sadrian wpi_apm_stop_master(sc); 4437278366Sadrian 4438278366Sadrian /* Reset the entire device. */ 4439278366Sadrian WPI_SETBITS(sc, WPI_RESET, WPI_RESET_SW); 4440278366Sadrian DELAY(10); 4441278366Sadrian /* Clear "initialization complete" bit. */ 4442278366Sadrian WPI_CLRBITS(sc, WPI_GP_CNTRL, WPI_GP_CNTRL_INIT_DONE); 4443173362Sbenjsc} 4444173362Sbenjsc 4445173362Sbenjscstatic void 4446278366Sadrianwpi_nic_config(struct wpi_softc *sc) 4447173362Sbenjsc{ 4448278366Sadrian uint32_t rev; 4449173362Sbenjsc 4450278366Sadrian DPRINTF(sc, WPI_DEBUG_TRACE, TRACE_STR_DOING, __func__); 4451177043Sthompsa 4452278366Sadrian /* voodoo from the Linux "driver".. */ 4453278366Sadrian rev = pci_read_config(sc->sc_dev, PCIR_REVID, 1); 4454278366Sadrian if ((rev & 0xc0) == 0x40) 4455278366Sadrian WPI_SETBITS(sc, WPI_HW_IF_CONFIG, WPI_HW_IF_CONFIG_ALM_MB); 4456278366Sadrian else if (!(rev & 0x80)) 4457278366Sadrian WPI_SETBITS(sc, WPI_HW_IF_CONFIG, WPI_HW_IF_CONFIG_ALM_MM); 4458173362Sbenjsc 4459278366Sadrian if (sc->cap == 0x80) 4460278366Sadrian WPI_SETBITS(sc, WPI_HW_IF_CONFIG, WPI_HW_IF_CONFIG_SKU_MRC); 4461173362Sbenjsc 4462278366Sadrian if ((le16toh(sc->rev) & 0xf0) == 0xd0) 4463278366Sadrian WPI_SETBITS(sc, WPI_HW_IF_CONFIG, WPI_HW_IF_CONFIG_REV_D); 4464278366Sadrian else 4465278366Sadrian WPI_CLRBITS(sc, WPI_HW_IF_CONFIG, WPI_HW_IF_CONFIG_REV_D); 4466278366Sadrian 4467278366Sadrian if (sc->type > 1) 4468278366Sadrian WPI_SETBITS(sc, WPI_HW_IF_CONFIG, WPI_HW_IF_CONFIG_TYPE_B); 4469173362Sbenjsc} 4470173362Sbenjsc 4471278366Sadrianstatic int 4472278366Sadrianwpi_hw_init(struct wpi_softc *sc) 4473173362Sbenjsc{ 4474278366Sadrian int chnl, ntries, error; 4475178354Ssam 4476278366Sadrian DPRINTF(sc, WPI_DEBUG_TRACE, TRACE_STR_BEGIN, __func__); 4477278366Sadrian 4478278366Sadrian /* Clear pending interrupts. */ 4479278366Sadrian WPI_WRITE(sc, WPI_INT, 0xffffffff); 4480278366Sadrian 4481278366Sadrian if ((error = wpi_apm_init(sc)) != 0) { 4482278366Sadrian device_printf(sc->sc_dev, 4483278366Sadrian "%s: could not power ON adapter, error %d\n", __func__, 4484278366Sadrian error); 4485278366Sadrian return error; 4486173362Sbenjsc } 4487173362Sbenjsc 4488278366Sadrian /* Select VMAIN power source. */ 4489278366Sadrian if ((error = wpi_nic_lock(sc)) != 0) 4490278366Sadrian return error; 4491278366Sadrian wpi_prph_clrbits(sc, WPI_APMG_PS, WPI_APMG_PS_PWR_SRC_MASK); 4492278366Sadrian wpi_nic_unlock(sc); 4493278366Sadrian /* Spin until VMAIN gets selected. */ 4494278366Sadrian for (ntries = 0; ntries < 5000; ntries++) { 4495278366Sadrian if (WPI_READ(sc, WPI_GPIO_IN) & WPI_GPIO_IN_VMAIN) 4496278366Sadrian break; 4497278366Sadrian DELAY(10); 4498278366Sadrian } 4499278366Sadrian if (ntries == 5000) { 4500278366Sadrian device_printf(sc->sc_dev, "timeout selecting power source\n"); 4501278366Sadrian return ETIMEDOUT; 4502278366Sadrian } 4503173362Sbenjsc 4504278366Sadrian /* Perform adapter initialization. */ 4505278366Sadrian wpi_nic_config(sc); 4506173362Sbenjsc 4507278366Sadrian /* Initialize RX ring. */ 4508278366Sadrian if ((error = wpi_nic_lock(sc)) != 0) 4509278366Sadrian return error; 4510278366Sadrian /* Set physical address of RX ring. */ 4511278366Sadrian WPI_WRITE(sc, WPI_FH_RX_BASE, sc->rxq.desc_dma.paddr); 4512278366Sadrian /* Set physical address of RX read pointer. */ 4513278366Sadrian WPI_WRITE(sc, WPI_FH_RX_RPTR_ADDR, sc->shared_dma.paddr + 4514278366Sadrian offsetof(struct wpi_shared, next)); 4515278366Sadrian WPI_WRITE(sc, WPI_FH_RX_WPTR, 0); 4516278366Sadrian /* Enable RX. */ 4517278366Sadrian WPI_WRITE(sc, WPI_FH_RX_CONFIG, 4518278366Sadrian WPI_FH_RX_CONFIG_DMA_ENA | 4519278366Sadrian WPI_FH_RX_CONFIG_RDRBD_ENA | 4520278366Sadrian WPI_FH_RX_CONFIG_WRSTATUS_ENA | 4521278366Sadrian WPI_FH_RX_CONFIG_MAXFRAG | 4522278366Sadrian WPI_FH_RX_CONFIG_NRBD(WPI_RX_RING_COUNT_LOG) | 4523278366Sadrian WPI_FH_RX_CONFIG_IRQ_DST_HOST | 4524278366Sadrian WPI_FH_RX_CONFIG_IRQ_TIMEOUT(1)); 4525278366Sadrian (void)WPI_READ(sc, WPI_FH_RSSR_TBL); /* barrier */ 4526278366Sadrian wpi_nic_unlock(sc); 4527278366Sadrian WPI_WRITE(sc, WPI_FH_RX_WPTR, (WPI_RX_RING_COUNT - 1) & ~7); 4528173362Sbenjsc 4529278366Sadrian /* Initialize TX rings. */ 4530278366Sadrian if ((error = wpi_nic_lock(sc)) != 0) 4531278366Sadrian return error; 4532278366Sadrian wpi_prph_write(sc, WPI_ALM_SCHED_MODE, 2); /* bypass mode */ 4533278366Sadrian wpi_prph_write(sc, WPI_ALM_SCHED_ARASTAT, 1); /* enable RA0 */ 4534278366Sadrian /* Enable all 6 TX rings. */ 4535278366Sadrian wpi_prph_write(sc, WPI_ALM_SCHED_TXFACT, 0x3f); 4536278366Sadrian wpi_prph_write(sc, WPI_ALM_SCHED_SBYPASS_MODE1, 0x10000); 4537278366Sadrian wpi_prph_write(sc, WPI_ALM_SCHED_SBYPASS_MODE2, 0x30002); 4538278366Sadrian wpi_prph_write(sc, WPI_ALM_SCHED_TXF4MF, 4); 4539278366Sadrian wpi_prph_write(sc, WPI_ALM_SCHED_TXF5MF, 5); 4540278366Sadrian /* Set physical address of TX rings. */ 4541278366Sadrian WPI_WRITE(sc, WPI_FH_TX_BASE, sc->shared_dma.paddr); 4542278366Sadrian WPI_WRITE(sc, WPI_FH_MSG_CONFIG, 0xffff05a5); 4543278366Sadrian 4544278366Sadrian /* Enable all DMA channels. */ 4545278366Sadrian for (chnl = 0; chnl < WPI_NDMACHNLS; chnl++) { 4546278366Sadrian WPI_WRITE(sc, WPI_FH_CBBC_CTRL(chnl), 0); 4547278366Sadrian WPI_WRITE(sc, WPI_FH_CBBC_BASE(chnl), 0); 4548278366Sadrian WPI_WRITE(sc, WPI_FH_TX_CONFIG(chnl), 0x80200008); 4549173362Sbenjsc } 4550278366Sadrian wpi_nic_unlock(sc); 4551278366Sadrian (void)WPI_READ(sc, WPI_FH_TX_BASE); /* barrier */ 4552278366Sadrian 4553278366Sadrian /* Clear "radio off" and "commands blocked" bits. */ 4554278366Sadrian WPI_WRITE(sc, WPI_UCODE_GP1_CLR, WPI_UCODE_GP1_RFKILL); 4555278366Sadrian WPI_WRITE(sc, WPI_UCODE_GP1_CLR, WPI_UCODE_GP1_CMD_BLOCKED); 4556278366Sadrian 4557278366Sadrian /* Clear pending interrupts. */ 4558278366Sadrian WPI_WRITE(sc, WPI_INT, 0xffffffff); 4559278366Sadrian /* Enable interrupts. */ 4560278366Sadrian WPI_WRITE(sc, WPI_INT_MASK, WPI_INT_MASK_DEF); 4561278366Sadrian 4562278366Sadrian /* _Really_ make sure "radio off" bit is cleared! */ 4563278366Sadrian WPI_WRITE(sc, WPI_UCODE_GP1_CLR, WPI_UCODE_GP1_RFKILL); 4564278366Sadrian WPI_WRITE(sc, WPI_UCODE_GP1_CLR, WPI_UCODE_GP1_RFKILL); 4565278366Sadrian 4566278366Sadrian if ((error = wpi_load_firmware(sc)) != 0) { 4567278366Sadrian device_printf(sc->sc_dev, 4568278366Sadrian "%s: could not load firmware, error %d\n", __func__, 4569278366Sadrian error); 4570278366Sadrian return error; 4571278366Sadrian } 4572278366Sadrian /* Wait at most one second for firmware alive notification. */ 4573278366Sadrian if ((error = msleep(sc, &sc->sc_mtx, PCATCH, "wpiinit", hz)) != 0) { 4574278366Sadrian device_printf(sc->sc_dev, 4575278366Sadrian "%s: timeout waiting for adapter to initialize, error %d\n", 4576278366Sadrian __func__, error); 4577278366Sadrian return error; 4578278366Sadrian } 4579278366Sadrian 4580278366Sadrian DPRINTF(sc, WPI_DEBUG_TRACE, TRACE_STR_END, __func__); 4581278366Sadrian 4582278366Sadrian /* Do post-firmware initialization. */ 4583278366Sadrian return wpi_post_alive(sc); 4584173362Sbenjsc} 4585173362Sbenjsc 4586173362Sbenjscstatic void 4587278366Sadrianwpi_hw_stop(struct wpi_softc *sc) 4588173362Sbenjsc{ 4589278366Sadrian int chnl, qid, ntries; 4590173362Sbenjsc 4591278366Sadrian DPRINTF(sc, WPI_DEBUG_TRACE, TRACE_STR_DOING, __func__); 4592173362Sbenjsc 4593278366Sadrian if (WPI_READ(sc, WPI_UCODE_GP1) & WPI_UCODE_GP1_MAC_SLEEP) 4594278366Sadrian wpi_nic_lock(sc); 4595173362Sbenjsc 4596278366Sadrian WPI_WRITE(sc, WPI_RESET, WPI_RESET_NEVO); 4597173362Sbenjsc 4598278366Sadrian /* Disable interrupts. */ 4599278366Sadrian WPI_WRITE(sc, WPI_INT_MASK, 0); 4600278366Sadrian WPI_WRITE(sc, WPI_INT, 0xffffffff); 4601278366Sadrian WPI_WRITE(sc, WPI_FH_INT, 0xffffffff); 4602173362Sbenjsc 4603278366Sadrian /* Make sure we no longer hold the NIC lock. */ 4604278366Sadrian wpi_nic_unlock(sc); 4605173362Sbenjsc 4606278366Sadrian if (wpi_nic_lock(sc) == 0) { 4607278366Sadrian /* Stop TX scheduler. */ 4608278366Sadrian wpi_prph_write(sc, WPI_ALM_SCHED_MODE, 0); 4609278366Sadrian wpi_prph_write(sc, WPI_ALM_SCHED_TXFACT, 0); 4610179957Sthompsa 4611278366Sadrian /* Stop all DMA channels. */ 4612278366Sadrian for (chnl = 0; chnl < WPI_NDMACHNLS; chnl++) { 4613278366Sadrian WPI_WRITE(sc, WPI_FH_TX_CONFIG(chnl), 0); 4614278366Sadrian for (ntries = 0; ntries < 200; ntries++) { 4615278366Sadrian if (WPI_READ(sc, WPI_FH_TX_STATUS) & 4616278366Sadrian WPI_FH_TX_STATUS_IDLE(chnl)) 4617278366Sadrian break; 4618278366Sadrian DELAY(10); 4619278366Sadrian } 4620173362Sbenjsc } 4621278366Sadrian wpi_nic_unlock(sc); 4622278366Sadrian } 4623173362Sbenjsc 4624278366Sadrian /* Stop RX ring. */ 4625278366Sadrian wpi_reset_rx_ring(sc); 4626173362Sbenjsc 4627278366Sadrian /* Reset all TX rings. */ 4628278366Sadrian for (qid = 0; qid < WPI_NTXQUEUES; qid++) 4629278366Sadrian wpi_reset_tx_ring(sc, &sc->txq[qid]); 4630173362Sbenjsc 4631278366Sadrian if (wpi_nic_lock(sc) == 0) { 4632278366Sadrian wpi_prph_write(sc, WPI_APMG_CLK_DIS, 4633278366Sadrian WPI_APMG_CLK_CTRL_DMA_CLK_RQT); 4634278366Sadrian wpi_nic_unlock(sc); 4635173362Sbenjsc } 4636278366Sadrian DELAY(5); 4637278366Sadrian /* Power OFF adapter. */ 4638278366Sadrian wpi_apm_stop(sc); 4639173362Sbenjsc} 4640173362Sbenjsc 4641173362Sbenjscstatic void 4642278366Sadrianwpi_radio_on(void *arg0, int pending) 4643173362Sbenjsc{ 4644278366Sadrian struct wpi_softc *sc = arg0; 4645278366Sadrian struct ifnet *ifp = sc->sc_ifp; 4646278366Sadrian struct ieee80211com *ic = ifp->if_l2com; 4647278366Sadrian struct ieee80211vap *vap = TAILQ_FIRST(&ic->ic_vaps); 4648173362Sbenjsc 4649278366Sadrian device_printf(sc->sc_dev, "RF switch: radio enabled\n"); 4650173362Sbenjsc 4651278366Sadrian if (vap != NULL) { 4652278366Sadrian wpi_init(sc); 4653278366Sadrian ieee80211_init(vap); 4654278366Sadrian } 4655173362Sbenjsc 4656278366Sadrian if (WPI_READ(sc, WPI_GP_CNTRL) & WPI_GP_CNTRL_RFKILL) { 4657278366Sadrian WPI_LOCK(sc); 4658278366Sadrian callout_stop(&sc->watchdog_rfkill); 4659278366Sadrian WPI_UNLOCK(sc); 4660173362Sbenjsc } 4661173362Sbenjsc} 4662173362Sbenjsc 4663278366Sadrianstatic void 4664278366Sadrianwpi_radio_off(void *arg0, int pending) 4665173362Sbenjsc{ 4666278366Sadrian struct wpi_softc *sc = arg0; 4667178354Ssam struct ifnet *ifp = sc->sc_ifp; 4668178354Ssam struct ieee80211com *ic = ifp->if_l2com; 4669278366Sadrian struct ieee80211vap *vap = TAILQ_FIRST(&ic->ic_vaps); 4670173362Sbenjsc 4671278366Sadrian device_printf(sc->sc_dev, "RF switch: radio disabled\n"); 4672173362Sbenjsc 4673278366Sadrian wpi_stop(sc); 4674278366Sadrian if (vap != NULL) 4675278366Sadrian ieee80211_stop(vap); 4676173362Sbenjsc 4677280053Sadrian WPI_LOCK(sc); 4678278366Sadrian callout_reset(&sc->watchdog_rfkill, hz, wpi_watchdog_rfkill, sc); 4679280053Sadrian WPI_UNLOCK(sc); 4680278366Sadrian} 4681173362Sbenjsc 4682278366Sadrianstatic void 4683278366Sadrianwpi_init_locked(struct wpi_softc *sc) 4684278366Sadrian{ 4685278366Sadrian struct ifnet *ifp = sc->sc_ifp; 4686278366Sadrian int error; 4687173362Sbenjsc 4688278366Sadrian DPRINTF(sc, WPI_DEBUG_TRACE, TRACE_STR_BEGIN, __func__); 4689173362Sbenjsc 4690278366Sadrian WPI_LOCK_ASSERT(sc); 4691278366Sadrian 4692278366Sadrian /* Check that the radio is not disabled by hardware switch. */ 4693278366Sadrian if (!(WPI_READ(sc, WPI_GP_CNTRL) & WPI_GP_CNTRL_RFKILL)) { 4694278366Sadrian device_printf(sc->sc_dev, 4695278366Sadrian "RF switch: radio disabled (%s)\n", __func__); 4696278366Sadrian callout_reset(&sc->watchdog_rfkill, hz, wpi_watchdog_rfkill, 4697278366Sadrian sc); 4698278366Sadrian return; 4699173362Sbenjsc } 4700173362Sbenjsc 4701278366Sadrian /* Read firmware images from the filesystem. */ 4702278366Sadrian if ((error = wpi_read_firmware(sc)) != 0) { 4703278366Sadrian device_printf(sc->sc_dev, 4704278366Sadrian "%s: could not read firmware, error %d\n", __func__, 4705278366Sadrian error); 4706278366Sadrian goto fail; 4707278366Sadrian } 4708173362Sbenjsc 4709278366Sadrian /* Initialize hardware and upload firmware. */ 4710278366Sadrian error = wpi_hw_init(sc); 4711278366Sadrian wpi_unload_firmware(sc); 4712278366Sadrian if (error != 0) { 4713278366Sadrian device_printf(sc->sc_dev, 4714278366Sadrian "%s: could not initialize hardware, error %d\n", __func__, 4715278366Sadrian error); 4716278366Sadrian goto fail; 4717278366Sadrian } 4718173362Sbenjsc 4719278366Sadrian /* Configure adapter now that it is ready. */ 4720278366Sadrian if ((error = wpi_config(sc)) != 0) { 4721278366Sadrian device_printf(sc->sc_dev, 4722278366Sadrian "%s: could not configure device, error %d\n", __func__, 4723278366Sadrian error); 4724278366Sadrian goto fail; 4725278366Sadrian } 4726173362Sbenjsc 4727278366Sadrian ifp->if_drv_flags &= ~IFF_DRV_OACTIVE; 4728278366Sadrian ifp->if_drv_flags |= IFF_DRV_RUNNING; 4729173362Sbenjsc 4730278366Sadrian callout_reset(&sc->watchdog_to, hz, wpi_watchdog, sc); 4731173362Sbenjsc 4732278366Sadrian DPRINTF(sc, WPI_DEBUG_TRACE, TRACE_STR_END, __func__); 4733173362Sbenjsc 4734278366Sadrian return; 4735173362Sbenjsc 4736278366Sadrianfail: wpi_stop_locked(sc); 4737278366Sadrian DPRINTF(sc, WPI_DEBUG_TRACE, TRACE_STR_END_ERR, __func__); 4738278366Sadrian} 4739173362Sbenjsc 4740278366Sadrianstatic void 4741278366Sadrianwpi_init(void *arg) 4742278366Sadrian{ 4743278366Sadrian struct wpi_softc *sc = arg; 4744278366Sadrian struct ifnet *ifp = sc->sc_ifp; 4745278366Sadrian struct ieee80211com *ic = ifp->if_l2com; 4746173362Sbenjsc 4747278366Sadrian WPI_LOCK(sc); 4748278366Sadrian wpi_init_locked(sc); 4749278366Sadrian WPI_UNLOCK(sc); 4750173362Sbenjsc 4751278366Sadrian if (ifp->if_drv_flags & IFF_DRV_RUNNING) 4752278366Sadrian ieee80211_start_all(ic); 4753278366Sadrian} 4754173362Sbenjsc 4755278366Sadrianstatic void 4756278366Sadrianwpi_stop_locked(struct wpi_softc *sc) 4757278366Sadrian{ 4758278366Sadrian struct ifnet *ifp = sc->sc_ifp; 4759173362Sbenjsc 4760278366Sadrian WPI_LOCK_ASSERT(sc); 4761278366Sadrian 4762278366Sadrian sc->sc_scan_timer = 0; 4763278366Sadrian sc->sc_tx_timer = 0; 4764278366Sadrian callout_stop(&sc->watchdog_to); 4765278366Sadrian callout_stop(&sc->calib_to); 4766278366Sadrian ifp->if_drv_flags &= ~(IFF_DRV_RUNNING | IFF_DRV_OACTIVE); 4767278366Sadrian 4768278366Sadrian /* Power OFF hardware. */ 4769278366Sadrian wpi_hw_stop(sc); 4770173362Sbenjsc} 4771173362Sbenjsc 4772278366Sadrianstatic void 4773278366Sadrianwpi_stop(struct wpi_softc *sc) 4774278366Sadrian{ 4775278366Sadrian WPI_LOCK(sc); 4776278366Sadrian wpi_stop_locked(sc); 4777278366Sadrian WPI_UNLOCK(sc); 4778278366Sadrian} 4779278366Sadrian 4780278366Sadrian/* 4781278366Sadrian * Callback from net80211 to start a scan. 4782173362Sbenjsc */ 4783173362Sbenjscstatic void 4784173362Sbenjscwpi_scan_start(struct ieee80211com *ic) 4785173362Sbenjsc{ 4786173362Sbenjsc struct ifnet *ifp = ic->ic_ifp; 4787173362Sbenjsc struct wpi_softc *sc = ifp->if_softc; 4788173362Sbenjsc 4789191746Sthompsa WPI_LOCK(sc); 4790191746Sthompsa wpi_set_led(sc, WPI_LED_LINK, 20, 2); 4791191746Sthompsa WPI_UNLOCK(sc); 4792173362Sbenjsc} 4793173362Sbenjsc 4794278366Sadrian/* 4795278366Sadrian * Callback from net80211 to terminate a scan. 4796173362Sbenjsc */ 4797173362Sbenjscstatic void 4798173362Sbenjscwpi_scan_end(struct ieee80211com *ic) 4799173362Sbenjsc{ 4800278366Sadrian struct ifnet *ifp = ic->ic_ifp; 4801278366Sadrian struct wpi_softc *sc = ifp->if_softc; 4802278366Sadrian struct ieee80211vap *vap = TAILQ_FIRST(&ic->ic_vaps); 4803278366Sadrian 4804278366Sadrian if (vap->iv_state == IEEE80211_S_RUN) { 4805278366Sadrian WPI_LOCK(sc); 4806278366Sadrian wpi_set_led(sc, WPI_LED_LINK, 0, 1); 4807278366Sadrian WPI_UNLOCK(sc); 4808278366Sadrian } 4809173362Sbenjsc} 4810173362Sbenjsc 4811173362Sbenjsc/** 4812173362Sbenjsc * Called by the net80211 framework to indicate to the driver 4813173362Sbenjsc * that the channel should be changed 4814173362Sbenjsc */ 4815173362Sbenjscstatic void 4816173362Sbenjscwpi_set_channel(struct ieee80211com *ic) 4817173362Sbenjsc{ 4818278366Sadrian const struct ieee80211_channel *c = ic->ic_curchan; 4819173362Sbenjsc struct ifnet *ifp = ic->ic_ifp; 4820173362Sbenjsc struct wpi_softc *sc = ifp->if_softc; 4821191746Sthompsa int error; 4822173362Sbenjsc 4823278366Sadrian DPRINTF(sc, WPI_DEBUG_TRACE, TRACE_STR_DOING, __func__); 4824278366Sadrian 4825278366Sadrian WPI_LOCK(sc); 4826278366Sadrian sc->sc_rxtap.wr_chan_freq = htole16(c->ic_freq); 4827278366Sadrian sc->sc_rxtap.wr_chan_flags = htole16(c->ic_flags); 4828278366Sadrian sc->sc_txtap.wt_chan_freq = htole16(c->ic_freq); 4829278366Sadrian sc->sc_txtap.wt_chan_flags = htole16(c->ic_flags); 4830278366Sadrian 4831177043Sthompsa /* 4832177043Sthompsa * Only need to set the channel in Monitor mode. AP scanning and auth 4833177043Sthompsa * are already taken care of by their respective firmware commands. 4834177043Sthompsa */ 4835191746Sthompsa if (ic->ic_opmode == IEEE80211_M_MONITOR) { 4836278366Sadrian sc->rxon.chan = ieee80211_chan2ieee(ic, c); 4837278366Sadrian if (IEEE80211_IS_CHAN_2GHZ(c)) { 4838278366Sadrian sc->rxon.flags |= htole32(WPI_RXON_AUTO | 4839278366Sadrian WPI_RXON_24GHZ); 4840278366Sadrian } else { 4841278366Sadrian sc->rxon.flags &= ~htole32(WPI_RXON_AUTO | 4842278366Sadrian WPI_RXON_24GHZ); 4843278366Sadrian } 4844278366Sadrian if ((error = wpi_send_rxon(sc, 0, 0)) != 0) 4845191746Sthompsa device_printf(sc->sc_dev, 4846278366Sadrian "%s: error %d settting channel\n", __func__, 4847278366Sadrian error); 4848191746Sthompsa } 4849278366Sadrian WPI_UNLOCK(sc); 4850173362Sbenjsc} 4851173362Sbenjsc 4852173362Sbenjsc/** 4853173362Sbenjsc * Called by net80211 to indicate that we need to scan the current 4854173362Sbenjsc * channel. The channel is previously be set via the wpi_set_channel 4855173362Sbenjsc * callback. 4856173362Sbenjsc */ 4857173362Sbenjscstatic void 4858178354Ssamwpi_scan_curchan(struct ieee80211_scan_state *ss, unsigned long maxdwell) 4859173362Sbenjsc{ 4860178354Ssam struct ieee80211vap *vap = ss->ss_vap; 4861278366Sadrian struct ieee80211com *ic = vap->iv_ic; 4862278366Sadrian struct ifnet *ifp = ic->ic_ifp; 4863173362Sbenjsc struct wpi_softc *sc = ifp->if_softc; 4864278366Sadrian int error; 4865173362Sbenjsc 4866278366Sadrian if (sc->rxon.chan != ieee80211_chan2ieee(ic, ic->ic_curchan)) { 4867278366Sadrian WPI_LOCK(sc); 4868278366Sadrian error = wpi_scan(sc, ic->ic_curchan); 4869278366Sadrian WPI_UNLOCK(sc); 4870278366Sadrian if (error != 0) 4871278366Sadrian ieee80211_cancel_scan(vap); 4872278366Sadrian } else { 4873278366Sadrian /* Send probe request when associated. */ 4874278366Sadrian sc->sc_scan_curchan(ss, maxdwell); 4875278366Sadrian } 4876173362Sbenjsc} 4877173362Sbenjsc 4878173362Sbenjsc/** 4879173362Sbenjsc * Called by the net80211 framework to indicate 4880173362Sbenjsc * the minimum dwell time has been met, terminate the scan. 4881173362Sbenjsc * We don't actually terminate the scan as the firmware will notify 4882173362Sbenjsc * us when it's finished and we have no way to interrupt it. 4883173362Sbenjsc */ 4884173362Sbenjscstatic void 4885178354Ssamwpi_scan_mindwell(struct ieee80211_scan_state *ss) 4886173362Sbenjsc{ 4887173362Sbenjsc /* NB: don't try to abort scan; wait for firmware to finish */ 4888173362Sbenjsc} 4889173362Sbenjsc 4890173362Sbenjscstatic void 4891278366Sadrianwpi_hw_reset(void *arg, int pending) 4892173362Sbenjsc{ 4893191746Sthompsa struct wpi_softc *sc = arg; 4894177043Sthompsa struct ifnet *ifp = sc->sc_ifp; 4895191746Sthompsa struct ieee80211com *ic = ifp->if_l2com; 4896278366Sadrian struct ieee80211vap *vap = TAILQ_FIRST(&ic->ic_vaps); 4897173362Sbenjsc 4898278366Sadrian DPRINTF(sc, WPI_DEBUG_TRACE, TRACE_STR_DOING, __func__); 4899173362Sbenjsc 4900278366Sadrian wpi_stop(sc); 4901278366Sadrian if (vap != NULL) 4902278366Sadrian ieee80211_stop(vap); 4903278366Sadrian wpi_init(sc); 4904278366Sadrian if (vap != NULL) 4905278366Sadrian ieee80211_init(vap); 4906173362Sbenjsc} 4907