if_iwi.c revision 150341
1145247Sdamien/* $FreeBSD: head/sys/dev/iwi/if_iwi.c 150341 2005-09-19 18:59:04Z damien $ */ 2145247Sdamien 3145247Sdamien/*- 4145247Sdamien * Copyright (c) 2004, 2005 5145247Sdamien * Damien Bergamini <damien.bergamini@free.fr>. All rights reserved. 6145247Sdamien * 7145247Sdamien * Redistribution and use in source and binary forms, with or without 8145247Sdamien * modification, are permitted provided that the following conditions 9145247Sdamien * are met: 10145247Sdamien * 1. Redistributions of source code must retain the above copyright 11145247Sdamien * notice unmodified, this list of conditions, and the following 12145247Sdamien * disclaimer. 13145247Sdamien * 2. Redistributions in binary form must reproduce the above copyright 14145247Sdamien * notice, this list of conditions and the following disclaimer in the 15145247Sdamien * documentation and/or other materials provided with the distribution. 16145247Sdamien * 17145247Sdamien * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 18145247Sdamien * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 19145247Sdamien * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 20145247Sdamien * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 21145247Sdamien * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 22145247Sdamien * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 23145247Sdamien * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 24145247Sdamien * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 25145247Sdamien * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 26145247Sdamien * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 27145247Sdamien * SUCH DAMAGE. 28145247Sdamien */ 29145247Sdamien 30145247Sdamien#include <sys/cdefs.h> 31145247Sdamien__FBSDID("$FreeBSD: head/sys/dev/iwi/if_iwi.c 150341 2005-09-19 18:59:04Z damien $"); 32145247Sdamien 33145247Sdamien/*- 34145247Sdamien * Intel(R) PRO/Wireless 2200BG/2225BG/2915ABG driver 35145247Sdamien * http://www.intel.com/network/connectivity/products/wireless/prowireless_mobile.htm 36145247Sdamien */ 37145247Sdamien 38145247Sdamien#include <sys/param.h> 39145247Sdamien#include <sys/sysctl.h> 40145247Sdamien#include <sys/sockio.h> 41145247Sdamien#include <sys/mbuf.h> 42145247Sdamien#include <sys/kernel.h> 43145247Sdamien#include <sys/socket.h> 44145247Sdamien#include <sys/systm.h> 45145247Sdamien#include <sys/malloc.h> 46145247Sdamien#include <sys/module.h> 47145247Sdamien#include <sys/bus.h> 48145247Sdamien#include <sys/endian.h> 49145247Sdamien 50145247Sdamien#include <machine/bus.h> 51145247Sdamien#include <machine/resource.h> 52145247Sdamien#include <machine/clock.h> 53145247Sdamien#include <sys/rman.h> 54145247Sdamien 55145247Sdamien#include <dev/pci/pcireg.h> 56145247Sdamien#include <dev/pci/pcivar.h> 57145247Sdamien 58145247Sdamien#include <net/bpf.h> 59145247Sdamien#include <net/if.h> 60145247Sdamien#include <net/if_arp.h> 61145247Sdamien#include <net/ethernet.h> 62145247Sdamien#include <net/if_dl.h> 63145247Sdamien#include <net/if_media.h> 64145247Sdamien#include <net/if_types.h> 65145247Sdamien 66145247Sdamien#include <net80211/ieee80211_var.h> 67145247Sdamien#include <net80211/ieee80211_radiotap.h> 68145247Sdamien 69145247Sdamien#include <netinet/in.h> 70145247Sdamien#include <netinet/in_systm.h> 71145247Sdamien#include <netinet/in_var.h> 72145247Sdamien#include <netinet/ip.h> 73145247Sdamien#include <netinet/if_ether.h> 74145247Sdamien 75145247Sdamien#include <dev/iwi/if_iwireg.h> 76145247Sdamien#include <dev/iwi/if_iwivar.h> 77145247Sdamien 78145247Sdamien#ifdef IWI_DEBUG 79145247Sdamien#define DPRINTF(x) do { if (iwi_debug > 0) printf x; } while (0) 80145247Sdamien#define DPRINTFN(n, x) do { if (iwi_debug >= (n)) printf x; } while (0) 81145247Sdamienint iwi_debug = 0; 82145247SdamienSYSCTL_INT(_debug, OID_AUTO, iwi, CTLFLAG_RW, &iwi_debug, 0, "iwi debug level"); 83145247Sdamien#else 84145247Sdamien#define DPRINTF(x) 85145247Sdamien#define DPRINTFN(n, x) 86145247Sdamien#endif 87145247Sdamien 88145247SdamienMODULE_DEPEND(iwi, pci, 1, 1, 1); 89145247SdamienMODULE_DEPEND(iwi, wlan, 1, 1, 1); 90145247Sdamien 91145247Sdamienstruct iwi_ident { 92145247Sdamien uint16_t vendor; 93145247Sdamien uint16_t device; 94145247Sdamien const char *name; 95145247Sdamien}; 96145247Sdamien 97145247Sdamienstatic const struct iwi_ident iwi_ident_table[] = { 98145247Sdamien { 0x8086, 0x4220, "Intel(R) PRO/Wireless 2200BG" }, 99145247Sdamien { 0x8086, 0x4221, "Intel(R) PRO/Wireless 2225BG" }, 100145247Sdamien { 0x8086, 0x4223, "Intel(R) PRO/Wireless 2915ABG" }, 101145247Sdamien { 0x8086, 0x4224, "Intel(R) PRO/Wireless 2915ABG" }, 102145247Sdamien 103145247Sdamien { 0, 0, NULL } 104145247Sdamien}; 105145247Sdamien 106145247Sdamienstatic void iwi_dma_map_addr(void *, bus_dma_segment_t *, int, int); 107145247Sdamienstatic int iwi_alloc_cmd_ring(struct iwi_softc *, struct iwi_cmd_ring *, 108145247Sdamien int); 109145247Sdamienstatic void iwi_reset_cmd_ring(struct iwi_softc *, struct iwi_cmd_ring *); 110145247Sdamienstatic void iwi_free_cmd_ring(struct iwi_softc *, struct iwi_cmd_ring *); 111145247Sdamienstatic int iwi_alloc_tx_ring(struct iwi_softc *, struct iwi_tx_ring *, 112149338Sdamien int, bus_addr_t, bus_addr_t); 113145247Sdamienstatic void iwi_reset_tx_ring(struct iwi_softc *, struct iwi_tx_ring *); 114145247Sdamienstatic void iwi_free_tx_ring(struct iwi_softc *, struct iwi_tx_ring *); 115145247Sdamienstatic int iwi_alloc_rx_ring(struct iwi_softc *, struct iwi_rx_ring *, 116145247Sdamien int); 117145247Sdamienstatic void iwi_reset_rx_ring(struct iwi_softc *, struct iwi_rx_ring *); 118145247Sdamienstatic void iwi_free_rx_ring(struct iwi_softc *, struct iwi_rx_ring *); 119150341Sdamienstatic struct ieee80211_node *iwi_node_alloc(struct ieee80211_node_table *); 120150341Sdamienstatic void iwi_node_free(struct ieee80211_node *); 121145247Sdamienstatic int iwi_media_change(struct ifnet *); 122145247Sdamienstatic void iwi_media_status(struct ifnet *, struct ifmediareq *); 123145247Sdamienstatic int iwi_newstate(struct ieee80211com *, enum ieee80211_state, int); 124149338Sdamienstatic int iwi_wme_update(struct ieee80211com *); 125145247Sdamienstatic uint16_t iwi_read_prom_word(struct iwi_softc *, uint8_t); 126145247Sdamienstatic void iwi_fix_channel(struct ieee80211com *, struct mbuf *); 127145247Sdamienstatic void iwi_frame_intr(struct iwi_softc *, struct iwi_rx_data *, int, 128145247Sdamien struct iwi_frame *); 129145247Sdamienstatic void iwi_notification_intr(struct iwi_softc *, struct iwi_notif *); 130145247Sdamienstatic void iwi_rx_intr(struct iwi_softc *); 131149338Sdamienstatic void iwi_tx_intr(struct iwi_softc *, struct iwi_tx_ring *); 132145247Sdamienstatic void iwi_intr(void *); 133145247Sdamienstatic int iwi_cmd(struct iwi_softc *, uint8_t, void *, uint8_t, int); 134150341Sdamienstatic void iwi_write_ibssnode(struct iwi_softc *, const struct iwi_node *); 135145247Sdamienstatic int iwi_tx_start(struct ifnet *, struct mbuf *, 136150245Sdamien struct ieee80211_node *, int); 137145247Sdamienstatic void iwi_start(struct ifnet *); 138145247Sdamienstatic void iwi_watchdog(struct ifnet *); 139145247Sdamienstatic int iwi_ioctl(struct ifnet *, u_long, caddr_t); 140145247Sdamienstatic void iwi_stop_master(struct iwi_softc *); 141145247Sdamienstatic int iwi_reset(struct iwi_softc *); 142145247Sdamienstatic int iwi_load_ucode(struct iwi_softc *, void *, int); 143145247Sdamienstatic int iwi_load_firmware(struct iwi_softc *, void *, int); 144145247Sdamienstatic int iwi_cache_firmware(struct iwi_softc *, void *); 145145247Sdamienstatic void iwi_free_firmware(struct iwi_softc *); 146145247Sdamienstatic int iwi_config(struct iwi_softc *); 147146500Sdamienstatic int iwi_set_chan(struct iwi_softc *, struct ieee80211_channel *); 148145247Sdamienstatic int iwi_scan(struct iwi_softc *); 149145247Sdamienstatic int iwi_auth_and_assoc(struct iwi_softc *); 150145247Sdamienstatic void iwi_init(void *); 151145247Sdamienstatic void iwi_stop(void *); 152145247Sdamienstatic int iwi_sysctl_stats(SYSCTL_HANDLER_ARGS); 153145247Sdamienstatic int iwi_sysctl_radio(SYSCTL_HANDLER_ARGS); 154145247Sdamien 155145247Sdamienstatic int iwi_probe(device_t); 156145247Sdamienstatic int iwi_attach(device_t); 157145247Sdamienstatic int iwi_detach(device_t); 158145247Sdamienstatic int iwi_shutdown(device_t); 159145247Sdamienstatic int iwi_suspend(device_t); 160145247Sdamienstatic int iwi_resume(device_t); 161145247Sdamien 162145247Sdamienstatic device_method_t iwi_methods[] = { 163145247Sdamien /* Device interface */ 164145247Sdamien DEVMETHOD(device_probe, iwi_probe), 165145247Sdamien DEVMETHOD(device_attach, iwi_attach), 166145247Sdamien DEVMETHOD(device_detach, iwi_detach), 167145247Sdamien DEVMETHOD(device_shutdown, iwi_shutdown), 168145247Sdamien DEVMETHOD(device_suspend, iwi_suspend), 169145247Sdamien DEVMETHOD(device_resume, iwi_resume), 170145247Sdamien 171145247Sdamien { 0, 0 } 172145247Sdamien}; 173145247Sdamien 174145247Sdamienstatic driver_t iwi_driver = { 175145247Sdamien "iwi", 176145247Sdamien iwi_methods, 177145247Sdamien sizeof (struct iwi_softc) 178145247Sdamien}; 179145247Sdamien 180145247Sdamienstatic devclass_t iwi_devclass; 181145247Sdamien 182145247SdamienDRIVER_MODULE(iwi, pci, iwi_driver, iwi_devclass, 0, 0); 183145247Sdamien 184145247Sdamien/* 185145247Sdamien * Supported rates for 802.11a/b/g modes (in 500Kbps unit). 186145247Sdamien */ 187145247Sdamienstatic const struct ieee80211_rateset iwi_rateset_11a = 188145247Sdamien { 8, { 12, 18, 24, 36, 48, 72, 96, 108 } }; 189145247Sdamien 190145247Sdamienstatic const struct ieee80211_rateset iwi_rateset_11b = 191145247Sdamien { 4, { 2, 4, 11, 22 } }; 192145247Sdamien 193145247Sdamienstatic const struct ieee80211_rateset iwi_rateset_11g = 194145247Sdamien { 12, { 2, 4, 11, 22, 12, 18, 24, 36, 48, 72, 96, 108 } }; 195145247Sdamien 196145247Sdamienstatic __inline uint8_t 197145247SdamienMEM_READ_1(struct iwi_softc *sc, uint32_t addr) 198145247Sdamien{ 199145247Sdamien CSR_WRITE_4(sc, IWI_CSR_INDIRECT_ADDR, addr); 200145247Sdamien return CSR_READ_1(sc, IWI_CSR_INDIRECT_DATA); 201145247Sdamien} 202145247Sdamien 203145247Sdamienstatic __inline uint32_t 204145247SdamienMEM_READ_4(struct iwi_softc *sc, uint32_t addr) 205145247Sdamien{ 206145247Sdamien CSR_WRITE_4(sc, IWI_CSR_INDIRECT_ADDR, addr); 207145247Sdamien return CSR_READ_4(sc, IWI_CSR_INDIRECT_DATA); 208145247Sdamien} 209145247Sdamien 210145247Sdamienstatic int 211145247Sdamieniwi_probe(device_t dev) 212145247Sdamien{ 213145247Sdamien const struct iwi_ident *ident; 214145247Sdamien 215145247Sdamien for (ident = iwi_ident_table; ident->name != NULL; ident++) { 216145247Sdamien if (pci_get_vendor(dev) == ident->vendor && 217145247Sdamien pci_get_device(dev) == ident->device) { 218145247Sdamien device_set_desc(dev, ident->name); 219145247Sdamien return 0; 220145247Sdamien } 221145247Sdamien } 222145247Sdamien return ENXIO; 223145247Sdamien} 224145247Sdamien 225145247Sdamien/* Base Address Register */ 226145247Sdamien#define IWI_PCI_BAR0 0x10 227145247Sdamien 228145247Sdamienstatic int 229145247Sdamieniwi_attach(device_t dev) 230145247Sdamien{ 231145247Sdamien struct iwi_softc *sc = device_get_softc(dev); 232147256Sbrooks struct ifnet *ifp; 233145247Sdamien struct ieee80211com *ic = &sc->sc_ic; 234145247Sdamien uint16_t val; 235145247Sdamien int error, i; 236145247Sdamien 237145247Sdamien sc->sc_dev = dev; 238145247Sdamien 239145247Sdamien mtx_init(&sc->sc_mtx, device_get_nameunit(dev), MTX_NETWORK_LOCK, 240145247Sdamien MTX_DEF | MTX_RECURSE); 241145247Sdamien 242150341Sdamien sc->sc_unr = new_unrhdr(0, IWI_MAX_IBSSNODE, &sc->sc_mtx); 243150341Sdamien 244145247Sdamien if (pci_get_powerstate(dev) != PCI_POWERSTATE_D0) { 245145247Sdamien device_printf(dev, "chip is in D%d power mode " 246145247Sdamien "-- setting to D0\n", pci_get_powerstate(dev)); 247145247Sdamien pci_set_powerstate(dev, PCI_POWERSTATE_D0); 248145247Sdamien } 249145247Sdamien 250146500Sdamien pci_write_config(dev, 0x41, 0, 1); 251146500Sdamien 252145247Sdamien /* enable bus-mastering */ 253145247Sdamien pci_enable_busmaster(dev); 254145247Sdamien 255145247Sdamien sc->mem_rid = IWI_PCI_BAR0; 256145247Sdamien sc->mem = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &sc->mem_rid, 257145247Sdamien RF_ACTIVE); 258145247Sdamien if (sc->mem == NULL) { 259145247Sdamien device_printf(dev, "could not allocate memory resource\n"); 260145247Sdamien goto fail; 261145247Sdamien } 262145247Sdamien 263145247Sdamien sc->sc_st = rman_get_bustag(sc->mem); 264145247Sdamien sc->sc_sh = rman_get_bushandle(sc->mem); 265145247Sdamien 266145247Sdamien sc->irq_rid = 0; 267145247Sdamien sc->irq = bus_alloc_resource_any(dev, SYS_RES_IRQ, &sc->irq_rid, 268145247Sdamien RF_ACTIVE | RF_SHAREABLE); 269145247Sdamien if (sc->irq == NULL) { 270145247Sdamien device_printf(dev, "could not allocate interrupt resource\n"); 271145247Sdamien goto fail; 272145247Sdamien } 273145247Sdamien 274145247Sdamien if (iwi_reset(sc) != 0) { 275145247Sdamien device_printf(dev, "could not reset adapter\n"); 276145247Sdamien goto fail; 277145247Sdamien } 278145247Sdamien 279145247Sdamien /* 280145247Sdamien * Allocate rings. 281145247Sdamien */ 282145247Sdamien if (iwi_alloc_cmd_ring(sc, &sc->cmdq, IWI_CMD_RING_COUNT) != 0) { 283145247Sdamien device_printf(dev, "could not allocate Cmd ring\n"); 284145247Sdamien goto fail; 285145247Sdamien } 286145247Sdamien 287149338Sdamien error = iwi_alloc_tx_ring(sc, &sc->txq[0], IWI_TX_RING_COUNT, 288149338Sdamien IWI_CSR_TX1_RIDX, IWI_CSR_TX1_WIDX); 289149338Sdamien if (error != 0) { 290149338Sdamien device_printf(dev, "could not allocate Tx ring 1\n"); 291145247Sdamien goto fail; 292145247Sdamien } 293145247Sdamien 294149338Sdamien error = iwi_alloc_tx_ring(sc, &sc->txq[1], IWI_TX_RING_COUNT, 295149338Sdamien IWI_CSR_TX2_RIDX, IWI_CSR_TX2_WIDX); 296149338Sdamien if (error != 0) { 297149338Sdamien device_printf(dev, "could not allocate Tx ring 2\n"); 298149338Sdamien goto fail; 299149338Sdamien } 300149338Sdamien 301149338Sdamien error = iwi_alloc_tx_ring(sc, &sc->txq[2], IWI_TX_RING_COUNT, 302149338Sdamien IWI_CSR_TX3_RIDX, IWI_CSR_TX3_WIDX); 303149338Sdamien if (error != 0) { 304149338Sdamien device_printf(dev, "could not allocate Tx ring 3\n"); 305149338Sdamien goto fail; 306149338Sdamien } 307149338Sdamien 308149338Sdamien error = iwi_alloc_tx_ring(sc, &sc->txq[3], IWI_TX_RING_COUNT, 309149338Sdamien IWI_CSR_TX4_RIDX, IWI_CSR_TX4_WIDX); 310149338Sdamien if (error != 0) { 311149338Sdamien device_printf(dev, "could not allocate Tx ring 4\n"); 312149338Sdamien goto fail; 313149338Sdamien } 314149338Sdamien 315145247Sdamien if (iwi_alloc_rx_ring(sc, &sc->rxq, IWI_RX_RING_COUNT) != 0) { 316145247Sdamien device_printf(dev, "could not allocate Rx ring\n"); 317145247Sdamien goto fail; 318145247Sdamien } 319145247Sdamien 320147256Sbrooks ifp = sc->sc_ifp = if_alloc(IFT_ETHER); 321147256Sbrooks if (ifp == NULL) { 322147256Sbrooks device_printf(dev, "can not if_alloc()\n"); 323147256Sbrooks goto fail; 324147256Sbrooks } 325145247Sdamien ifp->if_softc = sc; 326145247Sdamien if_initname(ifp, device_get_name(dev), device_get_unit(dev)); 327145247Sdamien ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST; 328145247Sdamien ifp->if_init = iwi_init; 329145247Sdamien ifp->if_ioctl = iwi_ioctl; 330145247Sdamien ifp->if_start = iwi_start; 331145247Sdamien ifp->if_watchdog = iwi_watchdog; 332145247Sdamien IFQ_SET_MAXLEN(&ifp->if_snd, IFQ_MAXLEN); 333145247Sdamien ifp->if_snd.ifq_drv_maxlen = IFQ_MAXLEN; 334145247Sdamien IFQ_SET_READY(&ifp->if_snd); 335145247Sdamien 336145247Sdamien ic->ic_ifp = ifp; 337149338Sdamien ic->ic_wme.wme_update = iwi_wme_update; 338145247Sdamien ic->ic_phytype = IEEE80211_T_OFDM; /* not only, but not used */ 339145247Sdamien ic->ic_opmode = IEEE80211_M_STA; /* default to BSS mode */ 340145247Sdamien ic->ic_state = IEEE80211_S_INIT; 341145247Sdamien 342145247Sdamien /* set device capabilities */ 343149338Sdamien ic->ic_caps = 344150245Sdamien IEEE80211_C_IBSS | /* IBSS mode supported */ 345149338Sdamien IEEE80211_C_MONITOR | /* monitor mode supported */ 346149338Sdamien IEEE80211_C_TXPMGT | /* tx power management */ 347149338Sdamien IEEE80211_C_SHPREAMBLE | /* short preamble supported */ 348149338Sdamien IEEE80211_C_WPA | /* 802.11i */ 349149338Sdamien IEEE80211_C_WME; /* 802.11e */ 350145247Sdamien 351145247Sdamien /* read MAC address from EEPROM */ 352145247Sdamien val = iwi_read_prom_word(sc, IWI_EEPROM_MAC + 0); 353145247Sdamien ic->ic_myaddr[0] = val >> 8; 354145247Sdamien ic->ic_myaddr[1] = val & 0xff; 355145247Sdamien val = iwi_read_prom_word(sc, IWI_EEPROM_MAC + 1); 356145247Sdamien ic->ic_myaddr[2] = val >> 8; 357145247Sdamien ic->ic_myaddr[3] = val & 0xff; 358145247Sdamien val = iwi_read_prom_word(sc, IWI_EEPROM_MAC + 2); 359145247Sdamien ic->ic_myaddr[4] = val >> 8; 360145247Sdamien ic->ic_myaddr[5] = val & 0xff; 361145247Sdamien 362146500Sdamien#if 0 363145247Sdamien if (pci_get_device(dev) >= 0x4223) { 364145247Sdamien /* set supported .11a rates (2915ABG only) */ 365145247Sdamien ic->ic_sup_rates[IEEE80211_MODE_11A] = iwi_rateset_11a; 366145247Sdamien 367145247Sdamien /* set supported .11a channels */ 368145247Sdamien for (i = 36; i <= 64; i += 4) { 369145247Sdamien ic->ic_channels[i].ic_freq = 370145247Sdamien ieee80211_ieee2mhz(i, IEEE80211_CHAN_5GHZ); 371145247Sdamien ic->ic_channels[i].ic_flags = IEEE80211_CHAN_A; 372145247Sdamien } 373145247Sdamien for (i = 149; i <= 165; i += 4) { 374145247Sdamien ic->ic_channels[i].ic_freq = 375145247Sdamien ieee80211_ieee2mhz(i, IEEE80211_CHAN_5GHZ); 376145247Sdamien ic->ic_channels[i].ic_flags = IEEE80211_CHAN_A; 377145247Sdamien } 378145247Sdamien } 379146500Sdamien#endif 380145247Sdamien 381145247Sdamien /* set supported .11b and .11g rates */ 382145247Sdamien ic->ic_sup_rates[IEEE80211_MODE_11B] = iwi_rateset_11b; 383145247Sdamien ic->ic_sup_rates[IEEE80211_MODE_11G] = iwi_rateset_11g; 384145247Sdamien 385145247Sdamien /* set supported .11b and .11g channels (1 through 14) */ 386145247Sdamien for (i = 1; i <= 14; i++) { 387145247Sdamien ic->ic_channels[i].ic_freq = 388145247Sdamien ieee80211_ieee2mhz(i, IEEE80211_CHAN_2GHZ); 389145247Sdamien ic->ic_channels[i].ic_flags = 390145247Sdamien IEEE80211_CHAN_CCK | IEEE80211_CHAN_OFDM | 391145247Sdamien IEEE80211_CHAN_DYN | IEEE80211_CHAN_2GHZ; 392145247Sdamien } 393145247Sdamien 394145247Sdamien ieee80211_ifattach(ic); 395150341Sdamien /* override default methods */ 396150341Sdamien ic->ic_node_alloc = iwi_node_alloc; 397150341Sdamien sc->sc_node_free = ic->ic_node_free; 398150341Sdamien ic->ic_node_free = iwi_node_free; 399145247Sdamien /* override state transition machine */ 400145247Sdamien sc->sc_newstate = ic->ic_newstate; 401145247Sdamien ic->ic_newstate = iwi_newstate; 402145247Sdamien ieee80211_media_init(ic, iwi_media_change, iwi_media_status); 403145247Sdamien 404145247Sdamien bpfattach2(ifp, DLT_IEEE802_11_RADIO, 405145247Sdamien sizeof (struct ieee80211_frame) + 64, &sc->sc_drvbpf); 406145247Sdamien 407145247Sdamien sc->sc_rxtap_len = sizeof sc->sc_rxtapu; 408145247Sdamien sc->sc_rxtap.wr_ihdr.it_len = htole16(sc->sc_rxtap_len); 409145247Sdamien sc->sc_rxtap.wr_ihdr.it_present = htole32(IWI_RX_RADIOTAP_PRESENT); 410145247Sdamien 411145247Sdamien sc->sc_txtap_len = sizeof sc->sc_txtapu; 412145247Sdamien sc->sc_txtap.wt_ihdr.it_len = htole16(sc->sc_txtap_len); 413145247Sdamien sc->sc_txtap.wt_ihdr.it_present = htole32(IWI_TX_RADIOTAP_PRESENT); 414145247Sdamien 415145247Sdamien /* 416145247Sdamien * Add a few sysctl knobs. 417145247Sdamien */ 418145247Sdamien sc->dwelltime = 100; 419145247Sdamien sc->bluetooth = 1; 420146500Sdamien sc->antenna = 0; 421145247Sdamien 422145247Sdamien SYSCTL_ADD_PROC(device_get_sysctl_ctx(dev), 423145247Sdamien SYSCTL_CHILDREN(device_get_sysctl_tree(dev)), OID_AUTO, "radio", 424145247Sdamien CTLTYPE_INT | CTLFLAG_RD, sc, 0, iwi_sysctl_radio, "I", 425145247Sdamien "radio transmitter switch state (0=off, 1=on)"); 426145247Sdamien 427145247Sdamien SYSCTL_ADD_PROC(device_get_sysctl_ctx(dev), 428145247Sdamien SYSCTL_CHILDREN(device_get_sysctl_tree(dev)), OID_AUTO, "stats", 429145247Sdamien CTLTYPE_OPAQUE | CTLFLAG_RD, sc, 0, iwi_sysctl_stats, "S", 430145247Sdamien "statistics"); 431145247Sdamien 432145247Sdamien SYSCTL_ADD_INT(device_get_sysctl_ctx(dev), 433145247Sdamien SYSCTL_CHILDREN(device_get_sysctl_tree(dev)), OID_AUTO, "dwell", 434145247Sdamien CTLFLAG_RW, &sc->dwelltime, 0, 435145247Sdamien "channel dwell time (ms) for AP/station scanning"); 436145247Sdamien 437145247Sdamien SYSCTL_ADD_INT(device_get_sysctl_ctx(dev), 438145247Sdamien SYSCTL_CHILDREN(device_get_sysctl_tree(dev)), OID_AUTO, "bluetooth", 439145247Sdamien CTLFLAG_RW, &sc->bluetooth, 0, "bluetooth coexistence"); 440145247Sdamien 441146500Sdamien SYSCTL_ADD_INT(device_get_sysctl_ctx(dev), 442146500Sdamien SYSCTL_CHILDREN(device_get_sysctl_tree(dev)), OID_AUTO, "antenna", 443146500Sdamien CTLFLAG_RW, &sc->antenna, 0, "antenna (0=auto)"); 444146500Sdamien 445145247Sdamien /* 446145247Sdamien * Hook our interrupt after all initialization is complete. 447145247Sdamien */ 448145247Sdamien error = bus_setup_intr(dev, sc->irq, INTR_TYPE_NET | INTR_MPSAFE, 449145247Sdamien iwi_intr, sc, &sc->sc_ih); 450145247Sdamien if (error != 0) { 451145247Sdamien device_printf(dev, "could not set up interrupt\n"); 452145247Sdamien goto fail; 453145247Sdamien } 454145247Sdamien 455145247Sdamien if (bootverbose) 456145247Sdamien ieee80211_announce(ic); 457145247Sdamien 458145247Sdamien return 0; 459145247Sdamien 460145247Sdamienfail: iwi_detach(dev); 461145247Sdamien return ENXIO; 462145247Sdamien} 463145247Sdamien 464145247Sdamienstatic int 465145247Sdamieniwi_detach(device_t dev) 466145247Sdamien{ 467145247Sdamien struct iwi_softc *sc = device_get_softc(dev); 468145247Sdamien struct ieee80211com *ic = &sc->sc_ic; 469145247Sdamien struct ifnet *ifp = ic->ic_ifp; 470145247Sdamien 471145247Sdamien iwi_stop(sc); 472145247Sdamien 473145247Sdamien iwi_free_firmware(sc); 474145247Sdamien 475150245Sdamien if (ifp != NULL) { 476147256Sbrooks bpfdetach(ifp); 477150245Sdamien ieee80211_ifdetach(ic); 478150245Sdamien } 479145247Sdamien 480145247Sdamien iwi_free_cmd_ring(sc, &sc->cmdq); 481149338Sdamien iwi_free_tx_ring(sc, &sc->txq[0]); 482149338Sdamien iwi_free_tx_ring(sc, &sc->txq[1]); 483149338Sdamien iwi_free_tx_ring(sc, &sc->txq[2]); 484149338Sdamien iwi_free_tx_ring(sc, &sc->txq[3]); 485145247Sdamien iwi_free_rx_ring(sc, &sc->rxq); 486145247Sdamien 487145247Sdamien if (sc->irq != NULL) { 488145247Sdamien bus_teardown_intr(dev, sc->irq, sc->sc_ih); 489145247Sdamien bus_release_resource(dev, SYS_RES_IRQ, sc->irq_rid, sc->irq); 490145247Sdamien } 491145247Sdamien 492145247Sdamien if (sc->mem != NULL) 493145247Sdamien bus_release_resource(dev, SYS_RES_MEMORY, sc->mem_rid, sc->mem); 494145247Sdamien 495150306Simp if (ifp != NULL) 496150306Simp if_free(ifp); 497150330Sdamien 498150341Sdamien if (sc->sc_unr != NULL) 499150341Sdamien delete_unrhdr(sc->sc_unr); 500150341Sdamien 501145247Sdamien mtx_destroy(&sc->sc_mtx); 502145247Sdamien 503145247Sdamien return 0; 504145247Sdamien} 505145247Sdamien 506145247Sdamienstatic void 507145247Sdamieniwi_dma_map_addr(void *arg, bus_dma_segment_t *segs, int nseg, int error) 508145247Sdamien{ 509145247Sdamien if (error != 0) 510145247Sdamien return; 511145247Sdamien 512145247Sdamien KASSERT(nseg == 1, ("too many DMA segments, %d should be 1", nseg)); 513145247Sdamien 514145247Sdamien *(bus_addr_t *)arg = segs[0].ds_addr; 515145247Sdamien} 516145247Sdamien 517145247Sdamienstatic int 518145247Sdamieniwi_alloc_cmd_ring(struct iwi_softc *sc, struct iwi_cmd_ring *ring, int count) 519145247Sdamien{ 520145247Sdamien int error; 521145247Sdamien 522145247Sdamien ring->count = count; 523145247Sdamien ring->queued = 0; 524145247Sdamien ring->cur = ring->next = 0; 525145247Sdamien 526145247Sdamien error = bus_dma_tag_create(NULL, 4, 0, BUS_SPACE_MAXADDR_32BIT, 527145247Sdamien BUS_SPACE_MAXADDR, NULL, NULL, count * IWI_CMD_DESC_SIZE, 1, 528145247Sdamien count * IWI_CMD_DESC_SIZE, 0, NULL, NULL, &ring->desc_dmat); 529145247Sdamien if (error != 0) { 530145247Sdamien device_printf(sc->sc_dev, "could not create desc DMA tag\n"); 531145247Sdamien goto fail; 532145247Sdamien } 533145247Sdamien 534145247Sdamien error = bus_dmamem_alloc(ring->desc_dmat, (void **)&ring->desc, 535145247Sdamien BUS_DMA_NOWAIT | BUS_DMA_ZERO, &ring->desc_map); 536145247Sdamien if (error != 0) { 537145247Sdamien device_printf(sc->sc_dev, "could not allocate DMA memory\n"); 538145247Sdamien goto fail; 539145247Sdamien } 540145247Sdamien 541145247Sdamien error = bus_dmamap_load(ring->desc_dmat, ring->desc_map, ring->desc, 542145247Sdamien count * IWI_CMD_DESC_SIZE, iwi_dma_map_addr, &ring->physaddr, 0); 543145247Sdamien if (error != 0) { 544145247Sdamien device_printf(sc->sc_dev, "could not load desc DMA map\n"); 545145247Sdamien goto fail; 546145247Sdamien } 547145247Sdamien 548145247Sdamien return 0; 549145247Sdamien 550145247Sdamienfail: iwi_free_cmd_ring(sc, ring); 551145247Sdamien return error; 552145247Sdamien} 553145247Sdamien 554145247Sdamienstatic void 555145247Sdamieniwi_reset_cmd_ring(struct iwi_softc *sc, struct iwi_cmd_ring *ring) 556145247Sdamien{ 557145247Sdamien ring->queued = 0; 558145247Sdamien ring->cur = ring->next = 0; 559145247Sdamien} 560145247Sdamien 561145247Sdamienstatic void 562145247Sdamieniwi_free_cmd_ring(struct iwi_softc *sc, struct iwi_cmd_ring *ring) 563145247Sdamien{ 564145247Sdamien if (ring->desc != NULL) { 565145247Sdamien bus_dmamap_sync(ring->desc_dmat, ring->desc_map, 566145247Sdamien BUS_DMASYNC_POSTWRITE); 567145247Sdamien bus_dmamap_unload(ring->desc_dmat, ring->desc_map); 568145247Sdamien bus_dmamem_free(ring->desc_dmat, ring->desc, ring->desc_map); 569145247Sdamien } 570145247Sdamien 571145247Sdamien if (ring->desc_dmat != NULL) 572145247Sdamien bus_dma_tag_destroy(ring->desc_dmat); 573145247Sdamien} 574145247Sdamien 575145247Sdamienstatic int 576149338Sdamieniwi_alloc_tx_ring(struct iwi_softc *sc, struct iwi_tx_ring *ring, int count, 577149338Sdamien bus_addr_t csr_ridx, bus_addr_t csr_widx) 578145247Sdamien{ 579145247Sdamien int i, error; 580145247Sdamien 581145247Sdamien ring->count = count; 582145247Sdamien ring->queued = 0; 583145247Sdamien ring->cur = ring->next = 0; 584149338Sdamien ring->csr_ridx = csr_ridx; 585149338Sdamien ring->csr_widx = csr_widx; 586145247Sdamien 587145247Sdamien error = bus_dma_tag_create(NULL, 4, 0, BUS_SPACE_MAXADDR_32BIT, 588145247Sdamien BUS_SPACE_MAXADDR, NULL, NULL, count * IWI_TX_DESC_SIZE, 1, 589145247Sdamien count * IWI_TX_DESC_SIZE, 0, NULL, NULL, &ring->desc_dmat); 590145247Sdamien if (error != 0) { 591145247Sdamien device_printf(sc->sc_dev, "could not create desc DMA tag\n"); 592145247Sdamien goto fail; 593145247Sdamien } 594145247Sdamien 595145247Sdamien error = bus_dmamem_alloc(ring->desc_dmat, (void **)&ring->desc, 596145247Sdamien BUS_DMA_NOWAIT | BUS_DMA_ZERO, &ring->desc_map); 597145247Sdamien if (error != 0) { 598145247Sdamien device_printf(sc->sc_dev, "could not allocate DMA memory\n"); 599145247Sdamien goto fail; 600145247Sdamien } 601145247Sdamien 602145247Sdamien error = bus_dmamap_load(ring->desc_dmat, ring->desc_map, ring->desc, 603145247Sdamien count * IWI_TX_DESC_SIZE, iwi_dma_map_addr, &ring->physaddr, 0); 604145247Sdamien if (error != 0) { 605145247Sdamien device_printf(sc->sc_dev, "could not load desc DMA map\n"); 606145247Sdamien goto fail; 607145247Sdamien } 608145247Sdamien 609145247Sdamien ring->data = malloc(count * sizeof (struct iwi_tx_data), M_DEVBUF, 610145247Sdamien M_NOWAIT | M_ZERO); 611145247Sdamien if (ring->data == NULL) { 612145247Sdamien device_printf(sc->sc_dev, "could not allocate soft data\n"); 613145247Sdamien error = ENOMEM; 614145247Sdamien goto fail; 615145247Sdamien } 616145247Sdamien 617145247Sdamien error = bus_dma_tag_create(NULL, 1, 0, BUS_SPACE_MAXADDR_32BIT, 618145247Sdamien BUS_SPACE_MAXADDR, NULL, NULL, MCLBYTES, 1, MCLBYTES, 0, NULL, 619145247Sdamien NULL, &ring->data_dmat); 620145247Sdamien if (error != 0) { 621145247Sdamien device_printf(sc->sc_dev, "could not create data DMA tag\n"); 622145247Sdamien goto fail; 623145247Sdamien } 624145247Sdamien 625145247Sdamien for (i = 0; i < count; i++) { 626145247Sdamien error = bus_dmamap_create(ring->data_dmat, 0, 627145247Sdamien &ring->data[i].map); 628145247Sdamien if (error != 0) { 629145247Sdamien device_printf(sc->sc_dev, "could not create DMA map\n"); 630145247Sdamien goto fail; 631145247Sdamien } 632145247Sdamien } 633145247Sdamien 634145247Sdamien return 0; 635145247Sdamien 636145247Sdamienfail: iwi_free_tx_ring(sc, ring); 637145247Sdamien return error; 638145247Sdamien} 639145247Sdamien 640145247Sdamienstatic void 641145247Sdamieniwi_reset_tx_ring(struct iwi_softc *sc, struct iwi_tx_ring *ring) 642145247Sdamien{ 643145247Sdamien struct iwi_tx_data *data; 644145247Sdamien int i; 645145247Sdamien 646145247Sdamien for (i = 0; i < ring->count; i++) { 647145247Sdamien data = &ring->data[i]; 648145247Sdamien 649145247Sdamien if (data->m != NULL) { 650145247Sdamien bus_dmamap_sync(ring->data_dmat, data->map, 651145247Sdamien BUS_DMASYNC_POSTWRITE); 652145247Sdamien bus_dmamap_unload(ring->data_dmat, data->map); 653145247Sdamien m_freem(data->m); 654145247Sdamien data->m = NULL; 655145247Sdamien } 656145247Sdamien 657145247Sdamien if (data->ni != NULL) { 658145247Sdamien ieee80211_free_node(data->ni); 659145247Sdamien data->ni = NULL; 660145247Sdamien } 661145247Sdamien } 662145247Sdamien 663145247Sdamien ring->queued = 0; 664145247Sdamien ring->cur = ring->next = 0; 665145247Sdamien} 666145247Sdamien 667145247Sdamienstatic void 668145247Sdamieniwi_free_tx_ring(struct iwi_softc *sc, struct iwi_tx_ring *ring) 669145247Sdamien{ 670145247Sdamien struct iwi_tx_data *data; 671145247Sdamien int i; 672145247Sdamien 673145247Sdamien if (ring->desc != NULL) { 674145247Sdamien bus_dmamap_sync(ring->desc_dmat, ring->desc_map, 675145247Sdamien BUS_DMASYNC_POSTWRITE); 676145247Sdamien bus_dmamap_unload(ring->desc_dmat, ring->desc_map); 677145247Sdamien bus_dmamem_free(ring->desc_dmat, ring->desc, ring->desc_map); 678145247Sdamien } 679145247Sdamien 680145247Sdamien if (ring->desc_dmat != NULL) 681145247Sdamien bus_dma_tag_destroy(ring->desc_dmat); 682145247Sdamien 683145247Sdamien if (ring->data != NULL) { 684145247Sdamien for (i = 0; i < ring->count; i++) { 685145247Sdamien data = &ring->data[i]; 686145247Sdamien 687145247Sdamien if (data->m != NULL) { 688145247Sdamien bus_dmamap_sync(ring->data_dmat, data->map, 689145247Sdamien BUS_DMASYNC_POSTWRITE); 690145247Sdamien bus_dmamap_unload(ring->data_dmat, data->map); 691145247Sdamien m_freem(data->m); 692145247Sdamien } 693145247Sdamien 694145247Sdamien if (data->ni != NULL) 695145247Sdamien ieee80211_free_node(data->ni); 696145247Sdamien 697145247Sdamien if (data->map != NULL) 698145247Sdamien bus_dmamap_destroy(ring->data_dmat, data->map); 699145247Sdamien } 700145247Sdamien 701145247Sdamien free(ring->data, M_DEVBUF); 702145247Sdamien } 703145247Sdamien 704145247Sdamien if (ring->data_dmat != NULL) 705145247Sdamien bus_dma_tag_destroy(ring->data_dmat); 706145247Sdamien} 707145247Sdamien 708145247Sdamienstatic int 709145247Sdamieniwi_alloc_rx_ring(struct iwi_softc *sc, struct iwi_rx_ring *ring, int count) 710145247Sdamien{ 711145247Sdamien struct iwi_rx_data *data; 712145247Sdamien int i, error; 713145247Sdamien 714145247Sdamien ring->count = count; 715145247Sdamien ring->cur = 0; 716145247Sdamien 717145247Sdamien ring->data = malloc(count * sizeof (struct iwi_rx_data), M_DEVBUF, 718145247Sdamien M_NOWAIT | M_ZERO); 719145247Sdamien if (ring->data == NULL) { 720145247Sdamien device_printf(sc->sc_dev, "could not allocate soft data\n"); 721145247Sdamien error = ENOMEM; 722145247Sdamien goto fail; 723145247Sdamien } 724145247Sdamien 725145247Sdamien error = bus_dma_tag_create(NULL, 1, 0, BUS_SPACE_MAXADDR_32BIT, 726145247Sdamien BUS_SPACE_MAXADDR, NULL, NULL, MCLBYTES, 1, MCLBYTES, 0, NULL, 727145247Sdamien NULL, &ring->data_dmat); 728145247Sdamien if (error != 0) { 729145247Sdamien device_printf(sc->sc_dev, "could not create data DMA tag\n"); 730145247Sdamien goto fail; 731145247Sdamien } 732145247Sdamien 733145247Sdamien for (i = 0; i < count; i++) { 734145247Sdamien data = &ring->data[i]; 735145247Sdamien 736145247Sdamien error = bus_dmamap_create(ring->data_dmat, 0, &data->map); 737145247Sdamien if (error != 0) { 738145247Sdamien device_printf(sc->sc_dev, "could not create DMA map\n"); 739145247Sdamien goto fail; 740145247Sdamien } 741145247Sdamien 742145247Sdamien data->m = m_getcl(M_DONTWAIT, MT_DATA, M_PKTHDR); 743145247Sdamien if (data->m == NULL) { 744145247Sdamien device_printf(sc->sc_dev, 745145247Sdamien "could not allocate rx mbuf\n"); 746145247Sdamien error = ENOMEM; 747145247Sdamien goto fail; 748145247Sdamien } 749145247Sdamien 750145247Sdamien error = bus_dmamap_load(ring->data_dmat, data->map, 751145247Sdamien mtod(data->m, void *), MCLBYTES, iwi_dma_map_addr, 752145247Sdamien &data->physaddr, 0); 753145247Sdamien if (error != 0) { 754145247Sdamien device_printf(sc->sc_dev, 755145247Sdamien "could not load rx buf DMA map"); 756145247Sdamien goto fail; 757145247Sdamien } 758145247Sdamien 759145247Sdamien data->reg = IWI_CSR_RX_BASE + i * 4; 760145247Sdamien } 761145247Sdamien 762145247Sdamien return 0; 763145247Sdamien 764145247Sdamienfail: iwi_free_rx_ring(sc, ring); 765145247Sdamien return error; 766145247Sdamien} 767145247Sdamien 768145247Sdamienstatic void 769145247Sdamieniwi_reset_rx_ring(struct iwi_softc *sc, struct iwi_rx_ring *ring) 770145247Sdamien{ 771145247Sdamien ring->cur = 0; 772145247Sdamien} 773145247Sdamien 774145247Sdamienstatic void 775145247Sdamieniwi_free_rx_ring(struct iwi_softc *sc, struct iwi_rx_ring *ring) 776145247Sdamien{ 777145247Sdamien struct iwi_rx_data *data; 778145247Sdamien int i; 779145247Sdamien 780145247Sdamien if (ring->data != NULL) { 781145247Sdamien for (i = 0; i < ring->count; i++) { 782145247Sdamien data = &ring->data[i]; 783145247Sdamien 784145247Sdamien if (data->m != NULL) { 785145247Sdamien bus_dmamap_sync(ring->data_dmat, data->map, 786145247Sdamien BUS_DMASYNC_POSTREAD); 787145247Sdamien bus_dmamap_unload(ring->data_dmat, data->map); 788145247Sdamien m_freem(data->m); 789145247Sdamien } 790145247Sdamien 791145247Sdamien if (data->map != NULL) 792145247Sdamien bus_dmamap_destroy(ring->data_dmat, data->map); 793145247Sdamien } 794145247Sdamien 795145247Sdamien free(ring->data, M_DEVBUF); 796145247Sdamien } 797145247Sdamien 798145247Sdamien if (ring->data_dmat != NULL) 799145247Sdamien bus_dma_tag_destroy(ring->data_dmat); 800145247Sdamien} 801145247Sdamien 802145247Sdamienstatic int 803145247Sdamieniwi_shutdown(device_t dev) 804145247Sdamien{ 805145247Sdamien struct iwi_softc *sc = device_get_softc(dev); 806145247Sdamien 807145247Sdamien iwi_stop(sc); 808145247Sdamien 809145247Sdamien return 0; 810145247Sdamien} 811145247Sdamien 812145247Sdamienstatic int 813145247Sdamieniwi_suspend(device_t dev) 814145247Sdamien{ 815145247Sdamien struct iwi_softc *sc = device_get_softc(dev); 816145247Sdamien 817145247Sdamien iwi_stop(sc); 818145247Sdamien 819145247Sdamien return 0; 820145247Sdamien} 821145247Sdamien 822145247Sdamienstatic int 823145247Sdamieniwi_resume(device_t dev) 824145247Sdamien{ 825145247Sdamien struct iwi_softc *sc = device_get_softc(dev); 826145247Sdamien struct ifnet *ifp = sc->sc_ic.ic_ifp; 827145247Sdamien 828145247Sdamien IWI_LOCK(sc); 829145247Sdamien 830146500Sdamien pci_write_config(dev, 0x41, 0, 1); 831146500Sdamien 832145247Sdamien if (ifp->if_flags & IFF_UP) { 833145247Sdamien ifp->if_init(ifp->if_softc); 834148887Srwatson if (ifp->if_drv_flags & IFF_DRV_RUNNING) 835145247Sdamien ifp->if_start(ifp); 836145247Sdamien } 837145247Sdamien 838145247Sdamien IWI_UNLOCK(sc); 839145247Sdamien 840145247Sdamien return 0; 841145247Sdamien} 842145247Sdamien 843150341Sdamienstatic struct ieee80211_node * 844150341Sdamieniwi_node_alloc(struct ieee80211_node_table *nt) 845150341Sdamien{ 846150341Sdamien struct iwi_node *in; 847150341Sdamien 848150341Sdamien in = malloc(sizeof (struct iwi_node), M_80211_NODE, M_NOWAIT | M_ZERO); 849150341Sdamien if (in == NULL) 850150341Sdamien return NULL; 851150341Sdamien 852150341Sdamien in->in_station = -1; 853150341Sdamien 854150341Sdamien return &in->in_node; 855150341Sdamien} 856150341Sdamien 857150341Sdamienstatic void 858150341Sdamieniwi_node_free(struct ieee80211_node *ni) 859150341Sdamien{ 860150341Sdamien struct ieee80211com *ic = ni->ni_ic; 861150341Sdamien struct iwi_softc *sc = ic->ic_ifp->if_softc; 862150341Sdamien struct iwi_node *in = (struct iwi_node *)ni; 863150341Sdamien 864150341Sdamien if (in->in_station != -1) 865150341Sdamien free_unr(sc->sc_unr, in->in_station); 866150341Sdamien 867150341Sdamien sc->sc_node_free(ni); 868150341Sdamien} 869150341Sdamien 870145247Sdamienstatic int 871145247Sdamieniwi_media_change(struct ifnet *ifp) 872145247Sdamien{ 873145247Sdamien struct iwi_softc *sc = ifp->if_softc; 874145247Sdamien int error; 875145247Sdamien 876145247Sdamien IWI_LOCK(sc); 877145247Sdamien 878145247Sdamien error = ieee80211_media_change(ifp); 879145247Sdamien if (error != ENETRESET) { 880145247Sdamien IWI_UNLOCK(sc); 881145247Sdamien return error; 882145247Sdamien } 883145247Sdamien 884148887Srwatson if ((ifp->if_flags & IFF_UP) && (ifp->if_drv_flags & IFF_DRV_RUNNING)) 885145247Sdamien iwi_init(sc); 886145247Sdamien 887145247Sdamien IWI_UNLOCK(sc); 888145247Sdamien 889145247Sdamien return 0; 890145247Sdamien} 891145247Sdamien 892145247Sdamien/* 893150341Sdamien * The firmware automatically adapts the transmit speed. We report its current 894150341Sdamien * value here. 895145247Sdamien */ 896145247Sdamienstatic void 897145247Sdamieniwi_media_status(struct ifnet *ifp, struct ifmediareq *imr) 898145247Sdamien{ 899145247Sdamien struct iwi_softc *sc = ifp->if_softc; 900145247Sdamien struct ieee80211com *ic = &sc->sc_ic; 901145247Sdamien#define N(a) (sizeof (a) / sizeof (a[0])) 902145247Sdamien static const struct { 903145247Sdamien uint32_t val; 904145247Sdamien int rate; 905145247Sdamien } rates[] = { 906145247Sdamien { IWI_RATE_DS1, 2 }, 907145247Sdamien { IWI_RATE_DS2, 4 }, 908145247Sdamien { IWI_RATE_DS5, 11 }, 909145247Sdamien { IWI_RATE_DS11, 22 }, 910145247Sdamien { IWI_RATE_OFDM6, 12 }, 911145247Sdamien { IWI_RATE_OFDM9, 18 }, 912145247Sdamien { IWI_RATE_OFDM12, 24 }, 913145247Sdamien { IWI_RATE_OFDM18, 36 }, 914145247Sdamien { IWI_RATE_OFDM24, 48 }, 915145247Sdamien { IWI_RATE_OFDM36, 72 }, 916145247Sdamien { IWI_RATE_OFDM48, 96 }, 917145247Sdamien { IWI_RATE_OFDM54, 108 }, 918145247Sdamien }; 919145247Sdamien uint32_t val; 920145247Sdamien int rate, i; 921145247Sdamien 922145247Sdamien imr->ifm_status = IFM_AVALID; 923145247Sdamien imr->ifm_active = IFM_IEEE80211; 924145247Sdamien if (ic->ic_state == IEEE80211_S_RUN) 925145247Sdamien imr->ifm_status |= IFM_ACTIVE; 926145247Sdamien 927145247Sdamien /* read current transmission rate from adapter */ 928145247Sdamien val = CSR_READ_4(sc, IWI_CSR_CURRENT_TX_RATE); 929145247Sdamien 930145247Sdamien /* convert rate to 802.11 rate */ 931145247Sdamien for (i = 0; i < N(rates) && rates[i].val != val; i++); 932145247Sdamien rate = (i < N(rates)) ? rates[i].rate : 0; 933145247Sdamien 934145247Sdamien imr->ifm_active |= ieee80211_rate2media(ic, rate, ic->ic_curmode); 935145247Sdamien switch (ic->ic_opmode) { 936145247Sdamien case IEEE80211_M_STA: 937145247Sdamien break; 938145247Sdamien 939145247Sdamien case IEEE80211_M_IBSS: 940145247Sdamien imr->ifm_active |= IFM_IEEE80211_ADHOC; 941145247Sdamien break; 942145247Sdamien 943145247Sdamien case IEEE80211_M_MONITOR: 944145247Sdamien imr->ifm_active |= IFM_IEEE80211_MONITOR; 945145247Sdamien break; 946145247Sdamien 947145247Sdamien case IEEE80211_M_AHDEMO: 948145247Sdamien case IEEE80211_M_HOSTAP: 949145247Sdamien /* should not get there */ 950145247Sdamien break; 951145247Sdamien } 952145247Sdamien#undef N 953145247Sdamien} 954145247Sdamien 955145247Sdamienstatic int 956145247Sdamieniwi_newstate(struct ieee80211com *ic, enum ieee80211_state nstate, int arg) 957145247Sdamien{ 958145247Sdamien struct ifnet *ifp = ic->ic_ifp; 959145247Sdamien struct iwi_softc *sc = ifp->if_softc; 960145247Sdamien 961145247Sdamien switch (nstate) { 962145247Sdamien case IEEE80211_S_SCAN: 963146500Sdamien if (sc->flags & IWI_FLAG_SCANNING) 964146500Sdamien break; 965146500Sdamien 966146500Sdamien ieee80211_node_table_reset(&ic->ic_scan); 967146500Sdamien ic->ic_flags |= IEEE80211_F_SCAN | IEEE80211_F_ASCAN; 968146500Sdamien sc->flags |= IWI_FLAG_SCANNING; 969145247Sdamien iwi_scan(sc); 970145247Sdamien break; 971145247Sdamien 972145247Sdamien case IEEE80211_S_AUTH: 973145247Sdamien iwi_auth_and_assoc(sc); 974145247Sdamien break; 975145247Sdamien 976145247Sdamien case IEEE80211_S_RUN: 977145247Sdamien if (ic->ic_opmode == IEEE80211_M_IBSS) 978145247Sdamien ieee80211_new_state(ic, IEEE80211_S_AUTH, -1); 979146500Sdamien else if (ic->ic_opmode == IEEE80211_M_MONITOR) 980146500Sdamien iwi_set_chan(sc, ic->ic_ibss_chan); 981146500Sdamien 982146500Sdamien return sc->sc_newstate(ic, nstate, 983146500Sdamien IEEE80211_FC0_SUBTYPE_ASSOC_RESP); 984146500Sdamien 985146500Sdamien case IEEE80211_S_ASSOC: 986145247Sdamien break; 987145247Sdamien 988145247Sdamien case IEEE80211_S_INIT: 989146500Sdamien sc->flags &= ~IWI_FLAG_SCANNING; 990145247Sdamien break; 991145247Sdamien } 992145247Sdamien 993145247Sdamien ic->ic_state = nstate; 994145247Sdamien return 0; 995145247Sdamien} 996145247Sdamien 997149346Sdamien/* 998149346Sdamien * WME parameters coming from IEEE 802.11e specification. These values are 999149346Sdamien * already declared in ieee80211_proto.c, but they are static so they can't 1000149346Sdamien * be reused here. 1001149346Sdamien */ 1002149346Sdamienstatic const struct wmeParams iwi_wme_cck_params[WME_NUM_AC] = { 1003149346Sdamien { 0, 3, 5, 7, 0 }, /* WME_AC_BE */ 1004149346Sdamien { 0, 3, 5, 10, 0 }, /* WME_AC_BK */ 1005149346Sdamien { 0, 2, 4, 5, 188 }, /* WME_AC_VI */ 1006149346Sdamien { 0, 2, 3, 4, 102 } /* WME_AC_VO */ 1007149346Sdamien}; 1008149346Sdamien 1009149346Sdamienstatic const struct wmeParams iwi_wme_ofdm_params[WME_NUM_AC] = { 1010149346Sdamien { 0, 3, 4, 6, 0 }, /* WME_AC_BE */ 1011149346Sdamien { 0, 3, 4, 10, 0 }, /* WME_AC_BK */ 1012149346Sdamien { 0, 2, 3, 4, 94 }, /* WME_AC_VI */ 1013149346Sdamien { 0, 2, 2, 3, 47 } /* WME_AC_VO */ 1014149346Sdamien}; 1015149346Sdamien 1016149338Sdamienstatic int 1017149338Sdamieniwi_wme_update(struct ieee80211com *ic) 1018149338Sdamien{ 1019149346Sdamien#define IWI_EXP2(v) htole16((1 << (v)) - 1) 1020149346Sdamien#define IWI_USEC(v) htole16(IEEE80211_TXOP_TO_US(v)) 1021149346Sdamien struct iwi_softc *sc = ic->ic_ifp->if_softc; 1022149346Sdamien struct iwi_wme_params wme[3]; 1023149346Sdamien const struct wmeParams *wmep; 1024149346Sdamien int ac; 1025149338Sdamien 1026149346Sdamien /* 1027149346Sdamien * We shall not override firmware default WME values if WME is not 1028149346Sdamien * actually enabled. 1029149346Sdamien */ 1030149346Sdamien if (!(ic->ic_flags & IEEE80211_F_WME)) 1031149346Sdamien return 0; 1032149346Sdamien 1033149346Sdamien for (ac = 0; ac < WME_NUM_AC; ac++) { 1034149346Sdamien /* set WME values for current operating mode */ 1035149346Sdamien wmep = &ic->ic_wme.wme_chanParams.cap_wmeParams[ac]; 1036149346Sdamien wme[0].aifsn[ac] = wmep->wmep_aifsn; 1037149346Sdamien wme[0].cwmin[ac] = IWI_EXP2(wmep->wmep_logcwmin); 1038149346Sdamien wme[0].cwmax[ac] = IWI_EXP2(wmep->wmep_logcwmax); 1039149346Sdamien wme[0].burst[ac] = IWI_USEC(wmep->wmep_txopLimit); 1040149346Sdamien wme[0].acm[ac] = wmep->wmep_acm; 1041149346Sdamien 1042149346Sdamien /* set WME values for CCK modulation */ 1043149346Sdamien wmep = &iwi_wme_cck_params[ac]; 1044149346Sdamien wme[1].aifsn[ac] = wmep->wmep_aifsn; 1045149346Sdamien wme[1].cwmin[ac] = IWI_EXP2(wmep->wmep_logcwmin); 1046149346Sdamien wme[1].cwmax[ac] = IWI_EXP2(wmep->wmep_logcwmax); 1047149346Sdamien wme[1].burst[ac] = IWI_USEC(wmep->wmep_txopLimit); 1048149346Sdamien wme[1].acm[ac] = wmep->wmep_acm; 1049149346Sdamien 1050149346Sdamien /* set WME values for OFDM modulation */ 1051149346Sdamien wmep = &iwi_wme_ofdm_params[ac]; 1052149346Sdamien wme[2].aifsn[ac] = wmep->wmep_aifsn; 1053149346Sdamien wme[2].cwmin[ac] = IWI_EXP2(wmep->wmep_logcwmin); 1054149346Sdamien wme[2].cwmax[ac] = IWI_EXP2(wmep->wmep_logcwmax); 1055149346Sdamien wme[2].burst[ac] = IWI_USEC(wmep->wmep_txopLimit); 1056149346Sdamien wme[2].acm[ac] = wmep->wmep_acm; 1057149346Sdamien } 1058149346Sdamien 1059149346Sdamien DPRINTF(("Setting WME parameters\n")); 1060149346Sdamien return iwi_cmd(sc, IWI_CMD_SET_WME_PARAMS, wme, sizeof wme, 1); 1061149346Sdamien#undef IWI_USEC 1062149346Sdamien#undef IWI_EXP2 1063149338Sdamien} 1064149338Sdamien 1065145247Sdamien/* 1066145247Sdamien * Read 16 bits at address 'addr' from the serial EEPROM. 1067145247Sdamien */ 1068145247Sdamienstatic uint16_t 1069145247Sdamieniwi_read_prom_word(struct iwi_softc *sc, uint8_t addr) 1070145247Sdamien{ 1071145247Sdamien uint32_t tmp; 1072145247Sdamien uint16_t val; 1073145247Sdamien int n; 1074145247Sdamien 1075145247Sdamien /* clock C once before the first command */ 1076145247Sdamien IWI_EEPROM_CTL(sc, 0); 1077145247Sdamien IWI_EEPROM_CTL(sc, IWI_EEPROM_S); 1078145247Sdamien IWI_EEPROM_CTL(sc, IWI_EEPROM_S | IWI_EEPROM_C); 1079145247Sdamien IWI_EEPROM_CTL(sc, IWI_EEPROM_S); 1080145247Sdamien 1081145247Sdamien /* write start bit (1) */ 1082145247Sdamien IWI_EEPROM_CTL(sc, IWI_EEPROM_S | IWI_EEPROM_D); 1083145247Sdamien IWI_EEPROM_CTL(sc, IWI_EEPROM_S | IWI_EEPROM_D | IWI_EEPROM_C); 1084145247Sdamien 1085145247Sdamien /* write READ opcode (10) */ 1086145247Sdamien IWI_EEPROM_CTL(sc, IWI_EEPROM_S | IWI_EEPROM_D); 1087145247Sdamien IWI_EEPROM_CTL(sc, IWI_EEPROM_S | IWI_EEPROM_D | IWI_EEPROM_C); 1088145247Sdamien IWI_EEPROM_CTL(sc, IWI_EEPROM_S); 1089145247Sdamien IWI_EEPROM_CTL(sc, IWI_EEPROM_S | IWI_EEPROM_C); 1090145247Sdamien 1091145247Sdamien /* write address A7-A0 */ 1092145247Sdamien for (n = 7; n >= 0; n--) { 1093145247Sdamien IWI_EEPROM_CTL(sc, IWI_EEPROM_S | 1094145247Sdamien (((addr >> n) & 1) << IWI_EEPROM_SHIFT_D)); 1095145247Sdamien IWI_EEPROM_CTL(sc, IWI_EEPROM_S | 1096145247Sdamien (((addr >> n) & 1) << IWI_EEPROM_SHIFT_D) | IWI_EEPROM_C); 1097145247Sdamien } 1098145247Sdamien 1099145247Sdamien IWI_EEPROM_CTL(sc, IWI_EEPROM_S); 1100145247Sdamien 1101145247Sdamien /* read data Q15-Q0 */ 1102145247Sdamien val = 0; 1103145247Sdamien for (n = 15; n >= 0; n--) { 1104145247Sdamien IWI_EEPROM_CTL(sc, IWI_EEPROM_S | IWI_EEPROM_C); 1105145247Sdamien IWI_EEPROM_CTL(sc, IWI_EEPROM_S); 1106145247Sdamien tmp = MEM_READ_4(sc, IWI_MEM_EEPROM_CTL); 1107145247Sdamien val |= ((tmp & IWI_EEPROM_Q) >> IWI_EEPROM_SHIFT_Q) << n; 1108145247Sdamien } 1109145247Sdamien 1110145247Sdamien IWI_EEPROM_CTL(sc, 0); 1111145247Sdamien 1112145247Sdamien /* clear Chip Select and clock C */ 1113145247Sdamien IWI_EEPROM_CTL(sc, IWI_EEPROM_S); 1114145247Sdamien IWI_EEPROM_CTL(sc, 0); 1115145247Sdamien IWI_EEPROM_CTL(sc, IWI_EEPROM_C); 1116145247Sdamien 1117145247Sdamien return be16toh(val); 1118145247Sdamien} 1119145247Sdamien 1120145247Sdamien/* 1121145247Sdamien * XXX: Hack to set the current channel to the value advertised in beacons or 1122145247Sdamien * probe responses. Only used during AP detection. 1123145247Sdamien */ 1124145247Sdamienstatic void 1125145247Sdamieniwi_fix_channel(struct ieee80211com *ic, struct mbuf *m) 1126145247Sdamien{ 1127145247Sdamien struct ieee80211_frame *wh; 1128145247Sdamien uint8_t subtype; 1129145247Sdamien uint8_t *frm, *efrm; 1130145247Sdamien 1131145247Sdamien wh = mtod(m, struct ieee80211_frame *); 1132145247Sdamien 1133145247Sdamien if ((wh->i_fc[0] & IEEE80211_FC0_TYPE_MASK) != IEEE80211_FC0_TYPE_MGT) 1134145247Sdamien return; 1135145247Sdamien 1136145247Sdamien subtype = wh->i_fc[0] & IEEE80211_FC0_SUBTYPE_MASK; 1137145247Sdamien 1138145247Sdamien if (subtype != IEEE80211_FC0_SUBTYPE_BEACON && 1139145247Sdamien subtype != IEEE80211_FC0_SUBTYPE_PROBE_RESP) 1140145247Sdamien return; 1141145247Sdamien 1142145247Sdamien frm = (uint8_t *)(wh + 1); 1143145247Sdamien efrm = mtod(m, uint8_t *) + m->m_len; 1144145247Sdamien 1145145247Sdamien frm += 12; /* skip tstamp, bintval and capinfo fields */ 1146145247Sdamien while (frm < efrm) { 1147145247Sdamien if (*frm == IEEE80211_ELEMID_DSPARMS) 1148145247Sdamien#if IEEE80211_CHAN_MAX < 255 1149145247Sdamien if (frm[2] <= IEEE80211_CHAN_MAX) 1150145247Sdamien#endif 1151149186Sjhb ic->ic_curchan = &ic->ic_channels[frm[2]]; 1152145247Sdamien 1153145247Sdamien frm += frm[1] + 2; 1154145247Sdamien } 1155145247Sdamien} 1156145247Sdamien 1157145247Sdamienstatic void 1158145247Sdamieniwi_frame_intr(struct iwi_softc *sc, struct iwi_rx_data *data, int i, 1159145247Sdamien struct iwi_frame *frame) 1160145247Sdamien{ 1161145247Sdamien struct ieee80211com *ic = &sc->sc_ic; 1162145247Sdamien struct ifnet *ifp = ic->ic_ifp; 1163145247Sdamien struct mbuf *m; 1164145247Sdamien struct ieee80211_frame *wh; 1165145247Sdamien struct ieee80211_node *ni; 1166145247Sdamien int error; 1167145247Sdamien 1168145247Sdamien DPRINTFN(5, ("received frame len=%u chan=%u rssi=%u\n", 1169145247Sdamien le16toh(frame->len), frame->chan, frame->rssi_dbm)); 1170145247Sdamien 1171146500Sdamien if (le16toh(frame->len) < sizeof (struct ieee80211_frame)) 1172146500Sdamien return; 1173146500Sdamien 1174145247Sdamien bus_dmamap_unload(sc->rxq.data_dmat, data->map); 1175145247Sdamien 1176145247Sdamien /* finalize mbuf */ 1177145247Sdamien m = data->m; 1178145247Sdamien m->m_pkthdr.rcvif = ifp; 1179145247Sdamien m->m_pkthdr.len = m->m_len = sizeof (struct iwi_hdr) + 1180145247Sdamien sizeof (struct iwi_frame) + le16toh(frame->len); 1181145247Sdamien 1182145247Sdamien m_adj(m, sizeof (struct iwi_hdr) + sizeof (struct iwi_frame)); 1183145247Sdamien 1184145247Sdamien if (ic->ic_state == IEEE80211_S_SCAN) 1185145247Sdamien iwi_fix_channel(ic, m); 1186145247Sdamien 1187145247Sdamien if (sc->sc_drvbpf != NULL) { 1188145247Sdamien struct iwi_rx_radiotap_header *tap = &sc->sc_rxtap; 1189145247Sdamien 1190145247Sdamien tap->wr_flags = 0; 1191145247Sdamien tap->wr_rate = frame->rate; 1192145247Sdamien tap->wr_chan_freq = 1193145247Sdamien htole16(ic->ic_channels[frame->chan].ic_freq); 1194145247Sdamien tap->wr_chan_flags = 1195145247Sdamien htole16(ic->ic_channels[frame->chan].ic_flags); 1196145247Sdamien tap->wr_antsignal = frame->signal; 1197145247Sdamien tap->wr_antenna = frame->antenna; 1198145247Sdamien 1199145247Sdamien bpf_mtap2(sc->sc_drvbpf, tap, sc->sc_rxtap_len, m); 1200145247Sdamien } 1201145247Sdamien 1202145247Sdamien wh = mtod(m, struct ieee80211_frame *); 1203145247Sdamien ni = ieee80211_find_rxnode(ic, (struct ieee80211_frame_min *)wh); 1204145247Sdamien 1205145247Sdamien /* send the frame to the 802.11 layer */ 1206146500Sdamien ieee80211_input(ic, m, ni, frame->rssi_dbm, 0); 1207145247Sdamien 1208145247Sdamien /* node is no longer needed */ 1209145247Sdamien ieee80211_free_node(ni); 1210145247Sdamien 1211145247Sdamien data->m = m_getcl(M_DONTWAIT, MT_DATA, M_PKTHDR); 1212145247Sdamien if (data->m == NULL) { 1213145247Sdamien device_printf(sc->sc_dev, "could not allocate rx mbuf\n"); 1214145247Sdamien return; 1215145247Sdamien } 1216145247Sdamien 1217145247Sdamien error = bus_dmamap_load(sc->rxq.data_dmat, data->map, 1218145247Sdamien mtod(data->m, void *), MCLBYTES, iwi_dma_map_addr, &data->physaddr, 1219145247Sdamien 0); 1220145247Sdamien if (error != 0) { 1221145247Sdamien device_printf(sc->sc_dev, "could not load rx buf DMA map\n"); 1222145247Sdamien m_freem(data->m); 1223145247Sdamien data->m = NULL; 1224145247Sdamien return; 1225145247Sdamien } 1226145247Sdamien 1227145247Sdamien CSR_WRITE_4(sc, data->reg, data->physaddr); 1228145247Sdamien} 1229145247Sdamien 1230145247Sdamienstatic void 1231145247Sdamieniwi_notification_intr(struct iwi_softc *sc, struct iwi_notif *notif) 1232145247Sdamien{ 1233145247Sdamien struct ieee80211com *ic = &sc->sc_ic; 1234145247Sdamien struct iwi_notif_scan_channel *chan; 1235145247Sdamien struct iwi_notif_scan_complete *scan; 1236145247Sdamien struct iwi_notif_authentication *auth; 1237145247Sdamien struct iwi_notif_association *assoc; 1238145247Sdamien 1239145247Sdamien switch (notif->type) { 1240145247Sdamien case IWI_NOTIF_TYPE_SCAN_CHANNEL: 1241145247Sdamien chan = (struct iwi_notif_scan_channel *)(notif + 1); 1242145247Sdamien 1243145247Sdamien DPRINTFN(2, ("Scanning channel (%u)\n", chan->nchan)); 1244145247Sdamien break; 1245145247Sdamien 1246145247Sdamien case IWI_NOTIF_TYPE_SCAN_COMPLETE: 1247145247Sdamien scan = (struct iwi_notif_scan_complete *)(notif + 1); 1248145247Sdamien 1249145247Sdamien DPRINTFN(2, ("Scan completed (%u, %u)\n", scan->nchan, 1250145247Sdamien scan->status)); 1251145247Sdamien 1252146500Sdamien /* monitor mode uses scan to set the channel ... */ 1253146500Sdamien if (ic->ic_opmode != IEEE80211_M_MONITOR) { 1254146500Sdamien sc->flags &= ~IWI_FLAG_SCANNING; 1255146500Sdamien ieee80211_end_scan(ic); 1256146500Sdamien } else 1257146500Sdamien iwi_set_chan(sc, ic->ic_ibss_chan); 1258145247Sdamien break; 1259145247Sdamien 1260145247Sdamien case IWI_NOTIF_TYPE_AUTHENTICATION: 1261145247Sdamien auth = (struct iwi_notif_authentication *)(notif + 1); 1262145247Sdamien 1263145247Sdamien DPRINTFN(2, ("Authentication (%u)\n", auth->state)); 1264145247Sdamien 1265145247Sdamien switch (auth->state) { 1266145247Sdamien case IWI_AUTHENTICATED: 1267148302Ssam ieee80211_node_authorize(ic->ic_bss); 1268145247Sdamien ieee80211_new_state(ic, IEEE80211_S_ASSOC, -1); 1269145247Sdamien break; 1270145247Sdamien 1271145247Sdamien case IWI_DEAUTHENTICATED: 1272145247Sdamien break; 1273145247Sdamien 1274145247Sdamien default: 1275145247Sdamien device_printf(sc->sc_dev, 1276145247Sdamien "unknown authentication state %u\n", auth->state); 1277145247Sdamien } 1278145247Sdamien break; 1279145247Sdamien 1280145247Sdamien case IWI_NOTIF_TYPE_ASSOCIATION: 1281145247Sdamien assoc = (struct iwi_notif_association *)(notif + 1); 1282145247Sdamien 1283145247Sdamien DPRINTFN(2, ("Association (%u, %u)\n", assoc->state, 1284145247Sdamien assoc->status)); 1285145247Sdamien 1286145247Sdamien switch (assoc->state) { 1287145247Sdamien case IWI_AUTHENTICATED: 1288145247Sdamien /* re-association, do nothing */ 1289145247Sdamien break; 1290145247Sdamien 1291145247Sdamien case IWI_ASSOCIATED: 1292145247Sdamien ieee80211_new_state(ic, IEEE80211_S_RUN, -1); 1293145247Sdamien break; 1294145247Sdamien 1295145247Sdamien case IWI_DEASSOCIATED: 1296145247Sdamien ieee80211_begin_scan(ic, 1); 1297145247Sdamien break; 1298145247Sdamien 1299145247Sdamien default: 1300145247Sdamien device_printf(sc->sc_dev, 1301145247Sdamien "unknown association state %u\n", assoc->state); 1302145247Sdamien } 1303145247Sdamien break; 1304145247Sdamien 1305145247Sdamien case IWI_NOTIF_TYPE_CALIBRATION: 1306145247Sdamien case IWI_NOTIF_TYPE_BEACON: 1307145247Sdamien case IWI_NOTIF_TYPE_NOISE: 1308145247Sdamien DPRINTFN(5, ("Notification (%u)\n", notif->type)); 1309145247Sdamien break; 1310145247Sdamien 1311145247Sdamien default: 1312145247Sdamien device_printf(sc->sc_dev, "unknown notification type %u\n", 1313145247Sdamien notif->type); 1314145247Sdamien } 1315145247Sdamien} 1316145247Sdamien 1317145247Sdamienstatic void 1318145247Sdamieniwi_rx_intr(struct iwi_softc *sc) 1319145247Sdamien{ 1320145247Sdamien struct iwi_rx_data *data; 1321145247Sdamien struct iwi_hdr *hdr; 1322145247Sdamien uint32_t hw; 1323145247Sdamien 1324145247Sdamien hw = CSR_READ_4(sc, IWI_CSR_RX_RIDX); 1325145247Sdamien 1326145247Sdamien for (; sc->rxq.cur != hw;) { 1327145247Sdamien data = &sc->rxq.data[sc->rxq.cur]; 1328145247Sdamien 1329145247Sdamien bus_dmamap_sync(sc->rxq.data_dmat, data->map, 1330145247Sdamien BUS_DMASYNC_POSTREAD); 1331145247Sdamien 1332145247Sdamien hdr = mtod(data->m, struct iwi_hdr *); 1333145247Sdamien 1334145247Sdamien switch (hdr->type) { 1335145247Sdamien case IWI_HDR_TYPE_FRAME: 1336145247Sdamien iwi_frame_intr(sc, data, sc->rxq.cur, 1337145247Sdamien (struct iwi_frame *)(hdr + 1)); 1338145247Sdamien break; 1339145247Sdamien 1340145247Sdamien case IWI_HDR_TYPE_NOTIF: 1341145247Sdamien iwi_notification_intr(sc, 1342145247Sdamien (struct iwi_notif *)(hdr + 1)); 1343145247Sdamien break; 1344145247Sdamien 1345145247Sdamien default: 1346145247Sdamien device_printf(sc->sc_dev, "unknown hdr type %u\n", 1347145247Sdamien hdr->type); 1348145247Sdamien } 1349145247Sdamien 1350145247Sdamien DPRINTFN(15, ("rx done idx=%u\n", sc->rxq.cur)); 1351145247Sdamien 1352145247Sdamien sc->rxq.cur = (sc->rxq.cur + 1) % IWI_RX_RING_COUNT; 1353145247Sdamien } 1354145247Sdamien 1355145247Sdamien /* tell the firmware what we have processed */ 1356145247Sdamien hw = (hw == 0) ? IWI_RX_RING_COUNT - 1 : hw - 1; 1357145247Sdamien CSR_WRITE_4(sc, IWI_CSR_RX_WIDX, hw); 1358145247Sdamien} 1359145247Sdamien 1360145247Sdamienstatic void 1361149338Sdamieniwi_tx_intr(struct iwi_softc *sc, struct iwi_tx_ring *txq) 1362145247Sdamien{ 1363145247Sdamien struct ieee80211com *ic = &sc->sc_ic; 1364145247Sdamien struct ifnet *ifp = ic->ic_ifp; 1365145247Sdamien struct iwi_tx_data *data; 1366145247Sdamien uint32_t hw; 1367145247Sdamien 1368149338Sdamien hw = CSR_READ_4(sc, txq->csr_ridx); 1369145247Sdamien 1370149338Sdamien for (; txq->next != hw;) { 1371149338Sdamien data = &txq->data[txq->next]; 1372145247Sdamien 1373149338Sdamien bus_dmamap_sync(txq->data_dmat, data->map, 1374145247Sdamien BUS_DMASYNC_POSTWRITE); 1375149338Sdamien bus_dmamap_unload(txq->data_dmat, data->map); 1376145247Sdamien m_freem(data->m); 1377145247Sdamien data->m = NULL; 1378145247Sdamien ieee80211_free_node(data->ni); 1379145247Sdamien data->ni = NULL; 1380145247Sdamien 1381149338Sdamien DPRINTFN(15, ("tx done idx=%u\n", txq->next)); 1382145247Sdamien 1383145247Sdamien ifp->if_opackets++; 1384145247Sdamien 1385149338Sdamien txq->queued--; 1386149338Sdamien txq->next = (txq->next + 1) % IWI_TX_RING_COUNT; 1387145247Sdamien } 1388145247Sdamien 1389145247Sdamien sc->sc_tx_timer = 0; 1390148887Srwatson ifp->if_drv_flags &= ~IFF_DRV_OACTIVE; 1391145247Sdamien iwi_start(ifp); 1392145247Sdamien} 1393145247Sdamien 1394145247Sdamienstatic void 1395145247Sdamieniwi_intr(void *arg) 1396145247Sdamien{ 1397145247Sdamien struct iwi_softc *sc = arg; 1398145247Sdamien uint32_t r; 1399145247Sdamien 1400145247Sdamien IWI_LOCK(sc); 1401145247Sdamien 1402145247Sdamien if ((r = CSR_READ_4(sc, IWI_CSR_INTR)) == 0 || r == 0xffffffff) { 1403145247Sdamien IWI_UNLOCK(sc); 1404145247Sdamien return; 1405145247Sdamien } 1406145247Sdamien 1407145247Sdamien /* disable interrupts */ 1408145247Sdamien CSR_WRITE_4(sc, IWI_CSR_INTR_MASK, 0); 1409145247Sdamien 1410145247Sdamien if (r & (IWI_INTR_FATAL_ERROR | IWI_INTR_PARITY_ERROR)) { 1411145247Sdamien device_printf(sc->sc_dev, "fatal error\n"); 1412145247Sdamien sc->sc_ic.ic_ifp->if_flags &= ~IFF_UP; 1413145247Sdamien iwi_stop(sc); 1414145247Sdamien } 1415145247Sdamien 1416145247Sdamien if (r & IWI_INTR_FW_INITED) { 1417145247Sdamien if (!(r & (IWI_INTR_FATAL_ERROR | IWI_INTR_PARITY_ERROR))) 1418145247Sdamien wakeup(sc); 1419145247Sdamien } 1420145247Sdamien 1421145247Sdamien if (r & IWI_INTR_RADIO_OFF) { 1422145247Sdamien DPRINTF(("radio transmitter turned off\n")); 1423145247Sdamien sc->sc_ic.ic_ifp->if_flags &= ~IFF_UP; 1424145247Sdamien iwi_stop(sc); 1425145247Sdamien } 1426145247Sdamien 1427145247Sdamien if (r & IWI_INTR_CMD_DONE) 1428145247Sdamien wakeup(sc); 1429145247Sdamien 1430145247Sdamien if (r & IWI_INTR_TX1_DONE) 1431149338Sdamien iwi_tx_intr(sc, &sc->txq[0]); 1432145247Sdamien 1433149338Sdamien if (r & IWI_INTR_TX2_DONE) 1434149338Sdamien iwi_tx_intr(sc, &sc->txq[1]); 1435149338Sdamien 1436149338Sdamien if (r & IWI_INTR_TX3_DONE) 1437149338Sdamien iwi_tx_intr(sc, &sc->txq[2]); 1438149338Sdamien 1439149338Sdamien if (r & IWI_INTR_TX4_DONE) 1440149338Sdamien iwi_tx_intr(sc, &sc->txq[3]); 1441149338Sdamien 1442149338Sdamien if (r & IWI_INTR_RX_DONE) 1443149338Sdamien iwi_rx_intr(sc); 1444149338Sdamien 1445145247Sdamien /* acknowledge interrupts */ 1446145247Sdamien CSR_WRITE_4(sc, IWI_CSR_INTR, r); 1447145247Sdamien 1448145247Sdamien /* re-enable interrupts */ 1449145247Sdamien CSR_WRITE_4(sc, IWI_CSR_INTR_MASK, IWI_INTR_MASK); 1450145247Sdamien 1451145247Sdamien IWI_UNLOCK(sc); 1452145247Sdamien} 1453145247Sdamien 1454145247Sdamienstatic int 1455145247Sdamieniwi_cmd(struct iwi_softc *sc, uint8_t type, void *data, uint8_t len, int async) 1456145247Sdamien{ 1457145247Sdamien struct iwi_cmd_desc *desc; 1458145247Sdamien 1459145247Sdamien desc = &sc->cmdq.desc[sc->cmdq.cur]; 1460145247Sdamien 1461145247Sdamien desc->hdr.type = IWI_HDR_TYPE_COMMAND; 1462145247Sdamien desc->hdr.flags = IWI_HDR_FLAG_IRQ; 1463145247Sdamien desc->type = type; 1464145247Sdamien desc->len = len; 1465145247Sdamien memcpy(desc->data, data, len); 1466145247Sdamien 1467145247Sdamien bus_dmamap_sync(sc->cmdq.desc_dmat, sc->cmdq.desc_map, 1468145247Sdamien BUS_DMASYNC_PREWRITE); 1469145247Sdamien 1470145247Sdamien DPRINTFN(2, ("sending command idx=%u type=%u len=%u\n", sc->cmdq.cur, 1471145247Sdamien type, len)); 1472145247Sdamien 1473145247Sdamien sc->cmdq.cur = (sc->cmdq.cur + 1) % IWI_CMD_RING_COUNT; 1474145247Sdamien CSR_WRITE_4(sc, IWI_CSR_CMD_WIDX, sc->cmdq.cur); 1475145247Sdamien 1476145247Sdamien return async ? 0 : msleep(sc, &sc->sc_mtx, 0, "iwicmd", hz); 1477145247Sdamien} 1478145247Sdamien 1479150341Sdamienstatic void 1480150341Sdamieniwi_write_ibssnode(struct iwi_softc *sc, const struct iwi_node *in) 1481150341Sdamien{ 1482150341Sdamien struct iwi_ibssnode node; 1483150341Sdamien 1484150341Sdamien /* write node information into NIC memory */ 1485150341Sdamien memset(&node, 0, sizeof node); 1486150341Sdamien IEEE80211_ADDR_COPY(node.bssid, in->in_node.ni_macaddr); 1487150341Sdamien 1488150341Sdamien CSR_WRITE_REGION_1(sc, 1489150341Sdamien IWI_CSR_NODE_BASE + in->in_station * sizeof node, 1490150341Sdamien (uint8_t *)&node, sizeof node); 1491150341Sdamien} 1492150341Sdamien 1493145247Sdamienstatic int 1494150245Sdamieniwi_tx_start(struct ifnet *ifp, struct mbuf *m0, struct ieee80211_node *ni, 1495150245Sdamien int ac) 1496145247Sdamien{ 1497145247Sdamien struct iwi_softc *sc = ifp->if_softc; 1498145247Sdamien struct ieee80211com *ic = &sc->sc_ic; 1499150341Sdamien struct iwi_node *in = (struct iwi_node *)ni; 1500149338Sdamien struct ieee80211_frame *wh; 1501146500Sdamien struct ieee80211_key *k; 1502149338Sdamien const struct chanAccParams *cap; 1503150245Sdamien struct iwi_tx_ring *txq = &sc->txq[ac]; 1504145247Sdamien struct iwi_tx_data *data; 1505145247Sdamien struct iwi_tx_desc *desc; 1506145247Sdamien struct mbuf *mnew; 1507145247Sdamien bus_dma_segment_t segs[IWI_MAX_NSEG]; 1508150341Sdamien int error, nsegs, hdrlen, i, noack = 0; 1509145247Sdamien 1510149338Sdamien wh = mtod(m0, struct ieee80211_frame *); 1511149338Sdamien 1512149338Sdamien if (wh->i_fc[0] & IEEE80211_FC0_SUBTYPE_QOS) { 1513149338Sdamien hdrlen = sizeof (struct ieee80211_qosframe); 1514149338Sdamien cap = &ic->ic_wme.wme_chanParams; 1515149338Sdamien noack = cap->cap_wmeParams[ac].wmep_noackPolicy; 1516150245Sdamien } else 1517149338Sdamien hdrlen = sizeof (struct ieee80211_frame); 1518149338Sdamien 1519150341Sdamien /* 1520150341Sdamien * This is only used in IBSS mode where the firmware expect an index 1521150341Sdamien * in a h/w table instead of a destination address. 1522150341Sdamien */ 1523150341Sdamien if (ic->ic_opmode == IEEE80211_M_IBSS && in->in_station == -1) { 1524150341Sdamien in->in_station = alloc_unr(sc->sc_unr); 1525150341Sdamien if (in->in_station == -1) { /* h/w table is full */ 1526150245Sdamien m_freem(m0); 1527150245Sdamien ieee80211_free_node(ni); 1528150245Sdamien ifp->if_oerrors++; 1529150245Sdamien return 0; 1530150245Sdamien } 1531150341Sdamien iwi_write_ibssnode(sc, in); 1532149338Sdamien } 1533149338Sdamien 1534149338Sdamien if (wh->i_fc[1] & IEEE80211_FC1_WEP) { 1535146500Sdamien k = ieee80211_crypto_encap(ic, ni, m0); 1536147806Ssam if (k == NULL) { 1537147806Ssam m_freem(m0); 1538146500Sdamien return ENOBUFS; 1539147806Ssam } 1540149338Sdamien 1541149338Sdamien /* packet header may have moved, reset our local pointer */ 1542149338Sdamien wh = mtod(m0, struct ieee80211_frame *); 1543146500Sdamien } 1544146500Sdamien 1545145247Sdamien if (sc->sc_drvbpf != NULL) { 1546145247Sdamien struct iwi_tx_radiotap_header *tap = &sc->sc_txtap; 1547145247Sdamien 1548145247Sdamien tap->wt_flags = 0; 1549146500Sdamien tap->wt_chan_freq = htole16(ic->ic_ibss_chan->ic_freq); 1550146500Sdamien tap->wt_chan_flags = htole16(ic->ic_ibss_chan->ic_flags); 1551145247Sdamien 1552145247Sdamien bpf_mtap2(sc->sc_drvbpf, tap, sc->sc_txtap_len, m0); 1553145247Sdamien } 1554145247Sdamien 1555149338Sdamien data = &txq->data[txq->cur]; 1556149338Sdamien desc = &txq->desc[txq->cur]; 1557145247Sdamien 1558149338Sdamien /* save and trim IEEE802.11 header */ 1559149338Sdamien m_copydata(m0, 0, hdrlen, (caddr_t)&desc->wh); 1560149338Sdamien m_adj(m0, hdrlen); 1561145247Sdamien 1562149338Sdamien error = bus_dmamap_load_mbuf_sg(txq->data_dmat, data->map, m0, segs, 1563145247Sdamien &nsegs, 0); 1564145247Sdamien if (error != 0 && error != EFBIG) { 1565145247Sdamien device_printf(sc->sc_dev, "could not map mbuf (error %d)\n", 1566145247Sdamien error); 1567145247Sdamien m_freem(m0); 1568145247Sdamien return error; 1569145247Sdamien } 1570145247Sdamien if (error != 0) { 1571145247Sdamien mnew = m_defrag(m0, M_DONTWAIT); 1572145247Sdamien if (mnew == NULL) { 1573145247Sdamien device_printf(sc->sc_dev, 1574145247Sdamien "could not defragment mbuf\n"); 1575145247Sdamien m_freem(m0); 1576145247Sdamien return ENOBUFS; 1577145247Sdamien } 1578145247Sdamien m0 = mnew; 1579145247Sdamien 1580149338Sdamien error = bus_dmamap_load_mbuf_sg(txq->data_dmat, data->map, 1581145247Sdamien m0, segs, &nsegs, 0); 1582145247Sdamien if (error != 0) { 1583145247Sdamien device_printf(sc->sc_dev, 1584145247Sdamien "could not map mbuf (error %d)\n", error); 1585145247Sdamien m_freem(m0); 1586145247Sdamien return error; 1587145247Sdamien } 1588145247Sdamien } 1589145247Sdamien 1590145247Sdamien data->m = m0; 1591145247Sdamien data->ni = ni; 1592145247Sdamien 1593145247Sdamien desc->hdr.type = IWI_HDR_TYPE_DATA; 1594145247Sdamien desc->hdr.flags = IWI_HDR_FLAG_IRQ; 1595150341Sdamien desc->station = 1596150341Sdamien (ic->ic_opmode == IEEE80211_M_IBSS) ? in->in_station : 0; 1597145247Sdamien desc->cmd = IWI_DATA_CMD_TX; 1598145247Sdamien desc->len = htole16(m0->m_pkthdr.len); 1599145247Sdamien desc->flags = 0; 1600149338Sdamien desc->xflags = 0; 1601145247Sdamien 1602149338Sdamien if (!noack && !IEEE80211_IS_MULTICAST(desc->wh.i_addr1)) 1603145247Sdamien desc->flags |= IWI_DATA_FLAG_NEED_ACK; 1604145247Sdamien 1605146500Sdamien#if 0 1606145247Sdamien if (ic->ic_flags & IEEE80211_F_PRIVACY) { 1607149338Sdamien desc->wh.i_fc[1] |= IEEE80211_FC1_WEP; 1608145247Sdamien desc->wep_txkey = ic->ic_crypto.cs_def_txkey; 1609145247Sdamien } else 1610146500Sdamien#endif 1611145247Sdamien desc->flags |= IWI_DATA_FLAG_NO_WEP; 1612145247Sdamien 1613145247Sdamien if (ic->ic_flags & IEEE80211_F_SHPREAMBLE) 1614145247Sdamien desc->flags |= IWI_DATA_FLAG_SHPREAMBLE; 1615145247Sdamien 1616149338Sdamien if (desc->wh.i_fc[0] & IEEE80211_FC0_SUBTYPE_QOS) 1617149338Sdamien desc->xflags |= IWI_DATA_XFLAG_QOS; 1618149338Sdamien 1619145247Sdamien desc->nseg = htole32(nsegs); 1620145247Sdamien for (i = 0; i < nsegs; i++) { 1621145247Sdamien desc->seg_addr[i] = htole32(segs[i].ds_addr); 1622145247Sdamien desc->seg_len[i] = htole32(segs[i].ds_len); 1623145247Sdamien } 1624145247Sdamien 1625149338Sdamien bus_dmamap_sync(txq->data_dmat, data->map, BUS_DMASYNC_PREWRITE); 1626149338Sdamien bus_dmamap_sync(txq->desc_dmat, txq->desc_map, BUS_DMASYNC_PREWRITE); 1627145247Sdamien 1628149338Sdamien DPRINTFN(5, ("sending data frame txq=%u idx=%u len=%u nseg=%u\n", 1629149338Sdamien ac, txq->cur, desc->len, desc->nseg)); 1630145247Sdamien 1631149338Sdamien txq->queued++; 1632149338Sdamien txq->cur = (txq->cur + 1) % IWI_TX_RING_COUNT; 1633149338Sdamien CSR_WRITE_4(sc, txq->csr_widx, txq->cur); 1634145247Sdamien 1635145247Sdamien return 0; 1636145247Sdamien} 1637145247Sdamien 1638145247Sdamienstatic void 1639145247Sdamieniwi_start(struct ifnet *ifp) 1640145247Sdamien{ 1641145247Sdamien struct iwi_softc *sc = ifp->if_softc; 1642145247Sdamien struct ieee80211com *ic = &sc->sc_ic; 1643145247Sdamien struct mbuf *m0; 1644145247Sdamien struct ether_header *eh; 1645145247Sdamien struct ieee80211_node *ni; 1646150245Sdamien int ac; 1647145247Sdamien 1648145247Sdamien IWI_LOCK(sc); 1649145247Sdamien 1650145247Sdamien if (ic->ic_state != IEEE80211_S_RUN) { 1651145247Sdamien IWI_UNLOCK(sc); 1652145247Sdamien return; 1653145247Sdamien } 1654145247Sdamien 1655145247Sdamien for (;;) { 1656145247Sdamien IFQ_DRV_DEQUEUE(&ifp->if_snd, m0); 1657145247Sdamien if (m0 == NULL) 1658145247Sdamien break; 1659145247Sdamien 1660145247Sdamien if (m0->m_len < sizeof (struct ether_header) && 1661150245Sdamien (m0 = m_pullup(m0, sizeof (struct ether_header))) == NULL) { 1662150245Sdamien ifp->if_oerrors++; 1663145247Sdamien continue; 1664150245Sdamien } 1665145247Sdamien eh = mtod(m0, struct ether_header *); 1666145247Sdamien ni = ieee80211_find_txnode(ic, eh->ether_dhost); 1667145247Sdamien if (ni == NULL) { 1668145247Sdamien m_freem(m0); 1669150245Sdamien ifp->if_oerrors++; 1670145247Sdamien continue; 1671145247Sdamien } 1672150245Sdamien 1673150245Sdamien /* classify mbuf so we can find which tx ring to use */ 1674149338Sdamien if (ieee80211_classify(ic, m0, ni) != 0) { 1675149338Sdamien m_freem(m0); 1676150245Sdamien ieee80211_free_node(ni); 1677150245Sdamien ifp->if_oerrors++; 1678149338Sdamien continue; 1679149338Sdamien } 1680150245Sdamien 1681150245Sdamien /* no QoS encapsulation for EAPOL frames */ 1682150245Sdamien ac = (eh->ether_type != htons(ETHERTYPE_PAE)) ? 1683150245Sdamien M_WME_GETAC(m0) : WME_AC_BE; 1684150245Sdamien 1685150245Sdamien if (sc->txq[ac].queued > IWI_TX_RING_COUNT - 8) { 1686150245Sdamien /* there is no place left in this ring */ 1687150245Sdamien IFQ_DRV_PREPEND(&ifp->if_snd, m0); 1688150245Sdamien ifp->if_drv_flags |= IFF_DRV_OACTIVE; 1689150245Sdamien break; 1690150245Sdamien } 1691150245Sdamien 1692145247Sdamien BPF_MTAP(ifp, m0); 1693145247Sdamien 1694145247Sdamien m0 = ieee80211_encap(ic, m0, ni); 1695147834Ssam if (m0 == NULL) { 1696147834Ssam ieee80211_free_node(ni); 1697150245Sdamien ifp->if_oerrors++; 1698145247Sdamien continue; 1699147834Ssam } 1700145247Sdamien 1701145247Sdamien if (ic->ic_rawbpf != NULL) 1702145247Sdamien bpf_mtap(ic->ic_rawbpf, m0); 1703145247Sdamien 1704150245Sdamien if (iwi_tx_start(ifp, m0, ni, ac) != 0) { 1705145247Sdamien ieee80211_free_node(ni); 1706145247Sdamien ifp->if_oerrors++; 1707145247Sdamien break; 1708145247Sdamien } 1709145247Sdamien 1710145247Sdamien sc->sc_tx_timer = 5; 1711145247Sdamien ifp->if_timer = 1; 1712145247Sdamien } 1713145247Sdamien 1714145247Sdamien IWI_UNLOCK(sc); 1715145247Sdamien} 1716145247Sdamien 1717145247Sdamienstatic void 1718145247Sdamieniwi_watchdog(struct ifnet *ifp) 1719145247Sdamien{ 1720145247Sdamien struct iwi_softc *sc = ifp->if_softc; 1721145247Sdamien struct ieee80211com *ic = &sc->sc_ic; 1722145247Sdamien 1723145247Sdamien IWI_LOCK(sc); 1724145247Sdamien 1725145247Sdamien ifp->if_timer = 0; 1726145247Sdamien 1727145247Sdamien if (sc->sc_tx_timer > 0) { 1728145247Sdamien if (--sc->sc_tx_timer == 0) { 1729145247Sdamien if_printf(ifp, "device timeout\n"); 1730145247Sdamien ifp->if_oerrors++; 1731145247Sdamien ifp->if_flags &= ~IFF_UP; 1732145247Sdamien iwi_stop(sc); 1733145247Sdamien IWI_UNLOCK(sc); 1734145247Sdamien return; 1735145247Sdamien } 1736145247Sdamien ifp->if_timer = 1; 1737145247Sdamien } 1738145247Sdamien 1739145247Sdamien ieee80211_watchdog(ic); 1740145247Sdamien 1741145247Sdamien IWI_UNLOCK(sc); 1742145247Sdamien} 1743145247Sdamien 1744145247Sdamienstatic int 1745145247Sdamieniwi_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data) 1746145247Sdamien{ 1747145247Sdamien struct iwi_softc *sc = ifp->if_softc; 1748145247Sdamien struct ieee80211com *ic = &sc->sc_ic; 1749145247Sdamien struct ifreq *ifr; 1750145247Sdamien int error = 0; 1751145247Sdamien 1752145247Sdamien IWI_LOCK(sc); 1753145247Sdamien 1754145247Sdamien switch (cmd) { 1755145247Sdamien case SIOCSIFFLAGS: 1756145247Sdamien if (ifp->if_flags & IFF_UP) { 1757148887Srwatson if (!(ifp->if_drv_flags & IFF_DRV_RUNNING)) 1758145247Sdamien iwi_init(sc); 1759145247Sdamien } else { 1760148887Srwatson if (ifp->if_drv_flags & IFF_DRV_RUNNING) 1761145247Sdamien iwi_stop(sc); 1762145247Sdamien } 1763145247Sdamien break; 1764145247Sdamien 1765145247Sdamien case SIOCSLOADFW: 1766145247Sdamien /* only super-user can do that! */ 1767145247Sdamien if ((error = suser(curthread)) != 0) 1768145247Sdamien break; 1769145247Sdamien 1770145247Sdamien ifr = (struct ifreq *)data; 1771145247Sdamien error = iwi_cache_firmware(sc, ifr->ifr_data); 1772145247Sdamien break; 1773145247Sdamien 1774145247Sdamien case SIOCSKILLFW: 1775145247Sdamien /* only super-user can do that! */ 1776145247Sdamien if ((error = suser(curthread)) != 0) 1777145247Sdamien break; 1778145247Sdamien 1779145247Sdamien ifp->if_flags &= ~IFF_UP; 1780145247Sdamien iwi_stop(sc); 1781145247Sdamien iwi_free_firmware(sc); 1782145247Sdamien break; 1783145247Sdamien 1784145247Sdamien default: 1785145247Sdamien error = ieee80211_ioctl(ic, cmd, data); 1786145247Sdamien } 1787145247Sdamien 1788145247Sdamien if (error == ENETRESET) { 1789148887Srwatson if ((ifp->if_flags & IFF_UP) && 1790149333Sdamien (ifp->if_drv_flags & IFF_DRV_RUNNING) && 1791149333Sdamien (ic->ic_roaming != IEEE80211_ROAMING_MANUAL)) 1792145247Sdamien iwi_init(sc); 1793145247Sdamien error = 0; 1794145247Sdamien } 1795145247Sdamien 1796145247Sdamien IWI_UNLOCK(sc); 1797145247Sdamien 1798145247Sdamien return error; 1799145247Sdamien} 1800145247Sdamien 1801145247Sdamienstatic void 1802145247Sdamieniwi_stop_master(struct iwi_softc *sc) 1803145247Sdamien{ 1804145247Sdamien uint32_t tmp; 1805145247Sdamien int ntries; 1806145247Sdamien 1807145247Sdamien /* disable interrupts */ 1808145247Sdamien CSR_WRITE_4(sc, IWI_CSR_INTR_MASK, 0); 1809145247Sdamien 1810145247Sdamien CSR_WRITE_4(sc, IWI_CSR_RST, IWI_RST_STOP_MASTER); 1811145247Sdamien for (ntries = 0; ntries < 5; ntries++) { 1812145247Sdamien if (CSR_READ_4(sc, IWI_CSR_RST) & IWI_RST_MASTER_DISABLED) 1813145247Sdamien break; 1814145247Sdamien DELAY(10); 1815145247Sdamien } 1816145247Sdamien if (ntries == 5) 1817145247Sdamien device_printf(sc->sc_dev, "timeout waiting for master\n"); 1818145247Sdamien 1819145247Sdamien tmp = CSR_READ_4(sc, IWI_CSR_RST); 1820145247Sdamien CSR_WRITE_4(sc, IWI_CSR_RST, tmp | IWI_RST_PRINCETON_RESET); 1821145247Sdamien 1822145247Sdamien sc->flags &= ~IWI_FLAG_FW_INITED; 1823145247Sdamien} 1824145247Sdamien 1825145247Sdamienstatic int 1826145247Sdamieniwi_reset(struct iwi_softc *sc) 1827145247Sdamien{ 1828145247Sdamien uint32_t tmp; 1829145247Sdamien int i, ntries; 1830145247Sdamien 1831145247Sdamien iwi_stop_master(sc); 1832145247Sdamien 1833145247Sdamien tmp = CSR_READ_4(sc, IWI_CSR_CTL); 1834145247Sdamien CSR_WRITE_4(sc, IWI_CSR_CTL, tmp | IWI_CTL_INIT); 1835145247Sdamien 1836145247Sdamien CSR_WRITE_4(sc, IWI_CSR_READ_INT, IWI_READ_INT_INIT_HOST); 1837145247Sdamien 1838145247Sdamien /* wait for clock stabilization */ 1839145247Sdamien for (ntries = 0; ntries < 1000; ntries++) { 1840145247Sdamien if (CSR_READ_4(sc, IWI_CSR_CTL) & IWI_CTL_CLOCK_READY) 1841145247Sdamien break; 1842145247Sdamien DELAY(200); 1843145247Sdamien } 1844145247Sdamien if (ntries == 1000) { 1845145247Sdamien device_printf(sc->sc_dev, 1846145247Sdamien "timeout waiting for clock stabilization\n"); 1847145247Sdamien return EIO; 1848145247Sdamien } 1849145247Sdamien 1850145247Sdamien tmp = CSR_READ_4(sc, IWI_CSR_RST); 1851145247Sdamien CSR_WRITE_4(sc, IWI_CSR_RST, tmp | IWI_RST_SOFT_RESET); 1852145247Sdamien 1853145247Sdamien DELAY(10); 1854145247Sdamien 1855145247Sdamien tmp = CSR_READ_4(sc, IWI_CSR_CTL); 1856145247Sdamien CSR_WRITE_4(sc, IWI_CSR_CTL, tmp | IWI_CTL_INIT); 1857145247Sdamien 1858145247Sdamien /* clear NIC memory */ 1859145247Sdamien CSR_WRITE_4(sc, IWI_CSR_AUTOINC_ADDR, 0); 1860145247Sdamien for (i = 0; i < 0xc000; i++) 1861145247Sdamien CSR_WRITE_4(sc, IWI_CSR_AUTOINC_DATA, 0); 1862145247Sdamien 1863145247Sdamien return 0; 1864145247Sdamien} 1865145247Sdamien 1866145247Sdamienstatic int 1867145247Sdamieniwi_load_ucode(struct iwi_softc *sc, void *uc, int size) 1868145247Sdamien{ 1869145247Sdamien uint32_t tmp; 1870145247Sdamien uint16_t *w; 1871145247Sdamien int ntries, i; 1872145247Sdamien 1873145247Sdamien CSR_WRITE_4(sc, IWI_CSR_RST, CSR_READ_4(sc, IWI_CSR_RST) | 1874145247Sdamien IWI_RST_STOP_MASTER); 1875145247Sdamien for (ntries = 0; ntries < 5; ntries++) { 1876145247Sdamien if (CSR_READ_4(sc, IWI_CSR_RST) & IWI_RST_MASTER_DISABLED) 1877145247Sdamien break; 1878145247Sdamien DELAY(10); 1879145247Sdamien } 1880145247Sdamien if (ntries == 5) { 1881145247Sdamien device_printf(sc->sc_dev, "timeout waiting for master\n"); 1882145247Sdamien return EIO; 1883145247Sdamien } 1884145247Sdamien 1885145247Sdamien MEM_WRITE_4(sc, 0x3000e0, 0x80000000); 1886145247Sdamien DELAY(5000); 1887145247Sdamien 1888145247Sdamien tmp = CSR_READ_4(sc, IWI_CSR_RST); 1889145247Sdamien tmp &= ~IWI_RST_PRINCETON_RESET; 1890145247Sdamien CSR_WRITE_4(sc, IWI_CSR_RST, tmp); 1891145247Sdamien 1892145247Sdamien DELAY(5000); 1893145247Sdamien MEM_WRITE_4(sc, 0x3000e0, 0); 1894145247Sdamien DELAY(1000); 1895145247Sdamien MEM_WRITE_4(sc, 0x300004, 1); 1896145247Sdamien DELAY(1000); 1897145247Sdamien MEM_WRITE_4(sc, 0x300004, 0); 1898145247Sdamien DELAY(1000); 1899145247Sdamien MEM_WRITE_1(sc, 0x200000, 0x00); 1900145247Sdamien MEM_WRITE_1(sc, 0x200000, 0x40); 1901145247Sdamien DELAY(1000); 1902145247Sdamien 1903145247Sdamien /* write microcode into adapter memory */ 1904145247Sdamien for (w = uc; size > 0; w++, size -= 2) 1905145247Sdamien MEM_WRITE_2(sc, 0x200010, *w); 1906145247Sdamien 1907145247Sdamien MEM_WRITE_1(sc, 0x200000, 0x00); 1908145247Sdamien MEM_WRITE_1(sc, 0x200000, 0x80); 1909145247Sdamien 1910145247Sdamien /* wait until we get an answer */ 1911145247Sdamien for (ntries = 0; ntries < 100; ntries++) { 1912145247Sdamien if (MEM_READ_1(sc, 0x200000) & 1) 1913145247Sdamien break; 1914145247Sdamien DELAY(100); 1915145247Sdamien } 1916145247Sdamien if (ntries == 100) { 1917145247Sdamien device_printf(sc->sc_dev, 1918145247Sdamien "timeout waiting for ucode to initialize\n"); 1919145247Sdamien return EIO; 1920145247Sdamien } 1921145247Sdamien 1922145247Sdamien /* read the answer or the firmware will not initialize properly */ 1923145247Sdamien for (i = 0; i < 7; i++) 1924145247Sdamien MEM_READ_4(sc, 0x200004); 1925145247Sdamien 1926145247Sdamien MEM_WRITE_1(sc, 0x200000, 0x00); 1927145247Sdamien 1928145247Sdamien return 0; 1929145247Sdamien} 1930145247Sdamien 1931145247Sdamien/* macro to handle unaligned little endian data in firmware image */ 1932145247Sdamien#define GETLE32(p) ((p)[0] | (p)[1] << 8 | (p)[2] << 16 | (p)[3] << 24) 1933145247Sdamien 1934145247Sdamienstatic int 1935145247Sdamieniwi_load_firmware(struct iwi_softc *sc, void *fw, int size) 1936145247Sdamien{ 1937145247Sdamien bus_dma_tag_t dmat; 1938145247Sdamien bus_dmamap_t map; 1939145247Sdamien bus_addr_t physaddr; 1940145247Sdamien void *virtaddr; 1941145247Sdamien u_char *p, *end; 1942145247Sdamien uint32_t sentinel, ctl, src, dst, sum, len, mlen, tmp; 1943145247Sdamien int ntries, error = 0; 1944145247Sdamien 1945145247Sdamien /* allocate DMA memory for mapping firmware image */ 1946145247Sdamien error = bus_dma_tag_create(NULL, 4, 0, BUS_SPACE_MAXADDR_32BIT, 1947145247Sdamien BUS_SPACE_MAXADDR, NULL, NULL, size, 1, size, 0, NULL, NULL, &dmat); 1948145247Sdamien if (error != 0) { 1949145247Sdamien device_printf(sc->sc_dev, 1950145247Sdamien "could not create firmware DMA tag\n"); 1951145247Sdamien goto fail1; 1952145247Sdamien } 1953145247Sdamien 1954145247Sdamien error = bus_dmamem_alloc(dmat, &virtaddr, BUS_DMA_NOWAIT, &map); 1955145247Sdamien if (error != 0) { 1956145247Sdamien device_printf(sc->sc_dev, 1957145247Sdamien "could not allocate firmware DMA memory\n"); 1958145247Sdamien goto fail2; 1959145247Sdamien } 1960145247Sdamien 1961145247Sdamien error = bus_dmamap_load(dmat, map, virtaddr, size, iwi_dma_map_addr, 1962145247Sdamien &physaddr, 0); 1963145247Sdamien if (error != 0) { 1964145247Sdamien device_printf(sc->sc_dev, "could not load firmware DMA map\n"); 1965145247Sdamien goto fail3; 1966145247Sdamien } 1967145247Sdamien 1968145247Sdamien /* copy firmware image to DMA memory */ 1969145247Sdamien memcpy(virtaddr, fw, size); 1970145247Sdamien 1971145247Sdamien /* make sure the adapter will get up-to-date values */ 1972145247Sdamien bus_dmamap_sync(dmat, map, BUS_DMASYNC_PREWRITE); 1973145247Sdamien 1974145247Sdamien /* tell the adapter where the command blocks are stored */ 1975145247Sdamien MEM_WRITE_4(sc, 0x3000a0, 0x27000); 1976145247Sdamien 1977145247Sdamien /* 1978145247Sdamien * Store command blocks into adapter's internal memory using register 1979145247Sdamien * indirections. The adapter will read the firmware image through DMA 1980145247Sdamien * using information stored in command blocks. 1981145247Sdamien */ 1982145247Sdamien src = physaddr; 1983145247Sdamien p = virtaddr; 1984145247Sdamien end = p + size; 1985145247Sdamien CSR_WRITE_4(sc, IWI_CSR_AUTOINC_ADDR, 0x27000); 1986145247Sdamien 1987145247Sdamien while (p < end) { 1988145247Sdamien dst = GETLE32(p); p += 4; src += 4; 1989145247Sdamien len = GETLE32(p); p += 4; src += 4; 1990145247Sdamien p += len; 1991145247Sdamien 1992145247Sdamien while (len > 0) { 1993145247Sdamien mlen = min(len, IWI_CB_MAXDATALEN); 1994145247Sdamien 1995145247Sdamien ctl = IWI_CB_DEFAULT_CTL | mlen; 1996145247Sdamien sum = ctl ^ src ^ dst; 1997145247Sdamien 1998145247Sdamien /* write a command block */ 1999145247Sdamien CSR_WRITE_4(sc, IWI_CSR_AUTOINC_DATA, ctl); 2000145247Sdamien CSR_WRITE_4(sc, IWI_CSR_AUTOINC_DATA, src); 2001145247Sdamien CSR_WRITE_4(sc, IWI_CSR_AUTOINC_DATA, dst); 2002145247Sdamien CSR_WRITE_4(sc, IWI_CSR_AUTOINC_DATA, sum); 2003145247Sdamien 2004145247Sdamien src += mlen; 2005145247Sdamien dst += mlen; 2006145247Sdamien len -= mlen; 2007145247Sdamien } 2008145247Sdamien } 2009145247Sdamien 2010145247Sdamien /* write a fictive final command block (sentinel) */ 2011145247Sdamien sentinel = CSR_READ_4(sc, IWI_CSR_AUTOINC_ADDR); 2012145247Sdamien CSR_WRITE_4(sc, IWI_CSR_AUTOINC_DATA, 0); 2013145247Sdamien 2014145247Sdamien tmp = CSR_READ_4(sc, IWI_CSR_RST); 2015145247Sdamien tmp &= ~(IWI_RST_MASTER_DISABLED | IWI_RST_STOP_MASTER); 2016145247Sdamien CSR_WRITE_4(sc, IWI_CSR_RST, tmp); 2017145247Sdamien 2018145247Sdamien /* tell the adapter to start processing command blocks */ 2019145247Sdamien MEM_WRITE_4(sc, 0x3000a4, 0x540100); 2020145247Sdamien 2021145247Sdamien /* wait until the adapter reach the sentinel */ 2022145247Sdamien for (ntries = 0; ntries < 400; ntries++) { 2023145247Sdamien if (MEM_READ_4(sc, 0x3000d0) >= sentinel) 2024145247Sdamien break; 2025145247Sdamien DELAY(100); 2026145247Sdamien } 2027145247Sdamien if (ntries == 400) { 2028145247Sdamien device_printf(sc->sc_dev, 2029145247Sdamien "timeout processing command blocks\n"); 2030145247Sdamien error = EIO; 2031145247Sdamien goto fail4; 2032145247Sdamien } 2033145247Sdamien 2034145247Sdamien /* we're done with command blocks processing */ 2035145247Sdamien MEM_WRITE_4(sc, 0x3000a4, 0x540c00); 2036145247Sdamien 2037145247Sdamien /* allow interrupts so we know when the firmware is inited */ 2038145247Sdamien CSR_WRITE_4(sc, IWI_CSR_INTR_MASK, IWI_INTR_MASK); 2039145247Sdamien 2040145247Sdamien /* tell the adapter to initialize the firmware */ 2041145247Sdamien CSR_WRITE_4(sc, IWI_CSR_RST, 0); 2042145247Sdamien 2043145247Sdamien tmp = CSR_READ_4(sc, IWI_CSR_CTL); 2044145247Sdamien CSR_WRITE_4(sc, IWI_CSR_CTL, tmp | IWI_CTL_ALLOW_STANDBY); 2045145247Sdamien 2046145247Sdamien /* wait at most one second for firmware initialization to complete */ 2047145247Sdamien if ((error = msleep(sc, &sc->sc_mtx, 0, "iwiinit", hz)) != 0) { 2048145247Sdamien device_printf(sc->sc_dev, "timeout waiting for firmware " 2049145247Sdamien "initialization to complete\n"); 2050145247Sdamien goto fail4; 2051145247Sdamien } 2052145247Sdamien 2053145247Sdamienfail4: bus_dmamap_sync(dmat, map, BUS_DMASYNC_POSTWRITE); 2054145247Sdamien bus_dmamap_unload(dmat, map); 2055145247Sdamienfail3: bus_dmamem_free(dmat, virtaddr, map); 2056145247Sdamienfail2: bus_dma_tag_destroy(dmat); 2057145247Sdamienfail1: 2058145247Sdamien return error; 2059145247Sdamien} 2060145247Sdamien 2061145247Sdamien/* 2062145247Sdamien * Store firmware into kernel memory so we can download it when we need to, 2063145247Sdamien * e.g when the adapter wakes up from suspend mode. 2064145247Sdamien */ 2065145247Sdamienstatic int 2066145247Sdamieniwi_cache_firmware(struct iwi_softc *sc, void *data) 2067145247Sdamien{ 2068145247Sdamien struct iwi_firmware *kfw = &sc->fw; 2069145247Sdamien struct iwi_firmware ufw; 2070145247Sdamien int error; 2071145247Sdamien 2072145247Sdamien iwi_free_firmware(sc); 2073145247Sdamien 2074145247Sdamien IWI_UNLOCK(sc); 2075145247Sdamien 2076145247Sdamien if ((error = copyin(data, &ufw, sizeof ufw)) != 0) 2077145247Sdamien goto fail1; 2078145247Sdamien 2079145247Sdamien kfw->boot_size = ufw.boot_size; 2080145247Sdamien kfw->ucode_size = ufw.ucode_size; 2081145247Sdamien kfw->main_size = ufw.main_size; 2082145247Sdamien 2083145247Sdamien kfw->boot = malloc(kfw->boot_size, M_DEVBUF, M_NOWAIT); 2084145247Sdamien if (kfw->boot == NULL) { 2085145247Sdamien error = ENOMEM; 2086145247Sdamien goto fail1; 2087145247Sdamien } 2088145247Sdamien 2089145247Sdamien kfw->ucode = malloc(kfw->ucode_size, M_DEVBUF, M_NOWAIT); 2090145247Sdamien if (kfw->ucode == NULL) { 2091145247Sdamien error = ENOMEM; 2092145247Sdamien goto fail2; 2093145247Sdamien } 2094145247Sdamien 2095145247Sdamien kfw->main = malloc(kfw->main_size, M_DEVBUF, M_NOWAIT); 2096145247Sdamien if (kfw->main == NULL) { 2097145247Sdamien error = ENOMEM; 2098145247Sdamien goto fail3; 2099145247Sdamien } 2100145247Sdamien 2101145247Sdamien if ((error = copyin(ufw.boot, kfw->boot, kfw->boot_size)) != 0) 2102145247Sdamien goto fail4; 2103145247Sdamien 2104145247Sdamien if ((error = copyin(ufw.ucode, kfw->ucode, kfw->ucode_size)) != 0) 2105145247Sdamien goto fail4; 2106145247Sdamien 2107145247Sdamien if ((error = copyin(ufw.main, kfw->main, kfw->main_size)) != 0) 2108145247Sdamien goto fail4; 2109145247Sdamien 2110145247Sdamien DPRINTF(("Firmware cached: boot %u, ucode %u, main %u\n", 2111145247Sdamien kfw->boot_size, kfw->ucode_size, kfw->main_size)); 2112145247Sdamien 2113145247Sdamien IWI_LOCK(sc); 2114145247Sdamien 2115145247Sdamien sc->flags |= IWI_FLAG_FW_CACHED; 2116145247Sdamien 2117145247Sdamien return 0; 2118145247Sdamien 2119145247Sdamienfail4: free(kfw->boot, M_DEVBUF); 2120145247Sdamienfail3: free(kfw->ucode, M_DEVBUF); 2121145247Sdamienfail2: free(kfw->main, M_DEVBUF); 2122145247Sdamienfail1: IWI_LOCK(sc); 2123145247Sdamien 2124145247Sdamien return error; 2125145247Sdamien} 2126145247Sdamien 2127145247Sdamienstatic void 2128145247Sdamieniwi_free_firmware(struct iwi_softc *sc) 2129145247Sdamien{ 2130145247Sdamien if (!(sc->flags & IWI_FLAG_FW_CACHED)) 2131145247Sdamien return; 2132145247Sdamien 2133145247Sdamien free(sc->fw.boot, M_DEVBUF); 2134145247Sdamien free(sc->fw.ucode, M_DEVBUF); 2135145247Sdamien free(sc->fw.main, M_DEVBUF); 2136145247Sdamien 2137145247Sdamien sc->flags &= ~IWI_FLAG_FW_CACHED; 2138145247Sdamien} 2139145247Sdamien 2140145247Sdamienstatic int 2141145247Sdamieniwi_config(struct iwi_softc *sc) 2142145247Sdamien{ 2143145247Sdamien struct ieee80211com *ic = &sc->sc_ic; 2144145247Sdamien struct ifnet *ifp = ic->ic_ifp; 2145145247Sdamien struct iwi_configuration config; 2146145247Sdamien struct iwi_rateset rs; 2147145247Sdamien struct iwi_txpower power; 2148145247Sdamien struct ieee80211_key *wk; 2149145247Sdamien struct iwi_wep_key wepkey; 2150145247Sdamien uint32_t data; 2151145247Sdamien int error, i; 2152145247Sdamien 2153145247Sdamien IEEE80211_ADDR_COPY(ic->ic_myaddr, IF_LLADDR(ifp)); 2154145247Sdamien DPRINTF(("Setting MAC address to %6D\n", ic->ic_myaddr, ":")); 2155145247Sdamien error = iwi_cmd(sc, IWI_CMD_SET_MAC_ADDRESS, ic->ic_myaddr, 2156145247Sdamien IEEE80211_ADDR_LEN, 0); 2157145247Sdamien if (error != 0) 2158145247Sdamien return error; 2159145247Sdamien 2160145247Sdamien memset(&config, 0, sizeof config); 2161145247Sdamien config.bluetooth_coexistence = sc->bluetooth; 2162146500Sdamien config.antenna = sc->antenna; 2163145247Sdamien config.multicast_enabled = 1; 2164146500Sdamien config.answer_pbreq = (ic->ic_opmode == IEEE80211_M_IBSS) ? 1 : 0; 2165146500Sdamien config.disable_unicast_decryption = 1; 2166146500Sdamien config.disable_multicast_decryption = 1; 2167145247Sdamien DPRINTF(("Configuring adapter\n")); 2168145247Sdamien error = iwi_cmd(sc, IWI_CMD_SET_CONFIG, &config, sizeof config, 0); 2169145247Sdamien if (error != 0) 2170145247Sdamien return error; 2171145247Sdamien 2172145247Sdamien data = htole32(IWI_POWER_MODE_CAM); 2173145247Sdamien DPRINTF(("Setting power mode to %u\n", le32toh(data))); 2174145247Sdamien error = iwi_cmd(sc, IWI_CMD_SET_POWER_MODE, &data, sizeof data, 0); 2175145247Sdamien if (error != 0) 2176145247Sdamien return error; 2177145247Sdamien 2178145247Sdamien data = htole32(ic->ic_rtsthreshold); 2179145247Sdamien DPRINTF(("Setting RTS threshold to %u\n", le32toh(data))); 2180145247Sdamien error = iwi_cmd(sc, IWI_CMD_SET_RTS_THRESHOLD, &data, sizeof data, 0); 2181145247Sdamien if (error != 0) 2182145247Sdamien return error; 2183145247Sdamien 2184146500Sdamien data = htole32(ic->ic_fragthreshold); 2185146500Sdamien DPRINTF(("Setting fragmentation threshold to %u\n", le32toh(data))); 2186146500Sdamien error = iwi_cmd(sc, IWI_CMD_SET_FRAG_THRESHOLD, &data, sizeof data, 0); 2187146500Sdamien if (error != 0) 2188146500Sdamien return error; 2189146500Sdamien 2190145247Sdamien if (ic->ic_opmode == IEEE80211_M_IBSS) { 2191145247Sdamien power.mode = IWI_MODE_11B; 2192145247Sdamien power.nchan = 11; 2193145247Sdamien for (i = 0; i < 11; i++) { 2194145247Sdamien power.chan[i].chan = i + 1; 2195145247Sdamien power.chan[i].power = IWI_TXPOWER_MAX; 2196145247Sdamien } 2197145247Sdamien DPRINTF(("Setting .11b channels tx power\n")); 2198145247Sdamien error = iwi_cmd(sc, IWI_CMD_SET_TX_POWER, &power, sizeof power, 2199145247Sdamien 0); 2200145247Sdamien if (error != 0) 2201145247Sdamien return error; 2202145247Sdamien 2203145247Sdamien power.mode = IWI_MODE_11G; 2204145247Sdamien DPRINTF(("Setting .11g channels tx power\n")); 2205145247Sdamien error = iwi_cmd(sc, IWI_CMD_SET_TX_POWER, &power, sizeof power, 2206145247Sdamien 0); 2207145247Sdamien if (error != 0) 2208145247Sdamien return error; 2209145247Sdamien } 2210145247Sdamien 2211145247Sdamien rs.mode = IWI_MODE_11G; 2212145247Sdamien rs.type = IWI_RATESET_TYPE_SUPPORTED; 2213145247Sdamien rs.nrates = ic->ic_sup_rates[IEEE80211_MODE_11G].rs_nrates; 2214145247Sdamien memcpy(rs.rates, ic->ic_sup_rates[IEEE80211_MODE_11G].rs_rates, 2215145247Sdamien rs.nrates); 2216145247Sdamien DPRINTF(("Setting .11bg supported rates (%u)\n", rs.nrates)); 2217145247Sdamien error = iwi_cmd(sc, IWI_CMD_SET_RATES, &rs, sizeof rs, 0); 2218145247Sdamien if (error != 0) 2219145247Sdamien return error; 2220145247Sdamien 2221145247Sdamien rs.mode = IWI_MODE_11A; 2222145247Sdamien rs.type = IWI_RATESET_TYPE_SUPPORTED; 2223145247Sdamien rs.nrates = ic->ic_sup_rates[IEEE80211_MODE_11A].rs_nrates; 2224145247Sdamien memcpy(rs.rates, ic->ic_sup_rates[IEEE80211_MODE_11A].rs_rates, 2225145247Sdamien rs.nrates); 2226145247Sdamien DPRINTF(("Setting .11a supported rates (%u)\n", rs.nrates)); 2227145247Sdamien error = iwi_cmd(sc, IWI_CMD_SET_RATES, &rs, sizeof rs, 0); 2228145247Sdamien if (error != 0) 2229145247Sdamien return error; 2230145247Sdamien 2231150245Sdamien /* if we have a desired ESSID, set it now */ 2232150245Sdamien if (ic->ic_des_esslen != 0) { 2233150245Sdamien#ifdef IWI_DEBUG 2234150245Sdamien if (iwi_debug > 0) { 2235150245Sdamien printf("Setting desired ESSID to "); 2236150245Sdamien ieee80211_print_essid(ic->ic_des_essid, 2237150245Sdamien ic->ic_des_esslen); 2238150245Sdamien printf("\n"); 2239150245Sdamien } 2240150245Sdamien#endif 2241150245Sdamien error = iwi_cmd(sc, IWI_CMD_SET_ESSID, ic->ic_des_essid, 2242150330Sdamien ic->ic_des_esslen, 0); 2243150245Sdamien if (error != 0) 2244150245Sdamien return error; 2245150245Sdamien } 2246150245Sdamien 2247145247Sdamien data = htole32(arc4random()); 2248145247Sdamien DPRINTF(("Setting initialization vector to %u\n", le32toh(data))); 2249145247Sdamien error = iwi_cmd(sc, IWI_CMD_SET_IV, &data, sizeof data, 0); 2250145247Sdamien if (error != 0) 2251145247Sdamien return error; 2252145247Sdamien 2253145247Sdamien for (i = 0; i < IEEE80211_WEP_NKID; i++) { 2254145247Sdamien wk = &ic->ic_crypto.cs_nw_keys[i]; 2255145247Sdamien 2256145247Sdamien wepkey.cmd = IWI_WEP_KEY_CMD_SETKEY; 2257145247Sdamien wepkey.idx = i; 2258145247Sdamien wepkey.len = wk->wk_keylen; 2259145247Sdamien memset(wepkey.key, 0, sizeof wepkey.key); 2260145247Sdamien memcpy(wepkey.key, wk->wk_key, wk->wk_keylen); 2261145247Sdamien DPRINTF(("Setting wep key index %u len %u\n", wepkey.idx, 2262145247Sdamien wepkey.len)); 2263145247Sdamien error = iwi_cmd(sc, IWI_CMD_SET_WEP_KEY, &wepkey, 2264145247Sdamien sizeof wepkey, 0); 2265145247Sdamien if (error != 0) 2266145247Sdamien return error; 2267145247Sdamien } 2268145247Sdamien 2269145247Sdamien /* enable adapter */ 2270145247Sdamien DPRINTF(("Enabling adapter\n")); 2271145247Sdamien return iwi_cmd(sc, IWI_CMD_ENABLE, NULL, 0, 0); 2272145247Sdamien} 2273145247Sdamien 2274145247Sdamienstatic int 2275146500Sdamieniwi_set_chan(struct iwi_softc *sc, struct ieee80211_channel *chan) 2276146500Sdamien{ 2277146500Sdamien struct ieee80211com *ic = &sc->sc_ic; 2278146500Sdamien struct iwi_scan scan; 2279146500Sdamien 2280146500Sdamien memset(&scan, 0, sizeof scan); 2281146500Sdamien scan.type = IWI_SCAN_TYPE_PASSIVE; 2282146500Sdamien scan.dwelltime = htole16(2000); 2283146500Sdamien scan.channels[0] = 1 | (IEEE80211_IS_CHAN_5GHZ(chan) ? IWI_CHAN_5GHZ : 2284146500Sdamien IWI_CHAN_2GHZ); 2285146500Sdamien scan.channels[1] = ieee80211_chan2ieee(ic, chan); 2286146500Sdamien 2287146500Sdamien DPRINTF(("Setting channel to %u\n", ieee80211_chan2ieee(ic, chan))); 2288146500Sdamien return iwi_cmd(sc, IWI_CMD_SCAN, &scan, sizeof scan, 1); 2289146500Sdamien} 2290146500Sdamien 2291146500Sdamienstatic int 2292145247Sdamieniwi_scan(struct iwi_softc *sc) 2293145247Sdamien{ 2294145247Sdamien struct ieee80211com *ic = &sc->sc_ic; 2295145247Sdamien struct iwi_scan scan; 2296145247Sdamien uint8_t *p; 2297145247Sdamien int i, count; 2298145247Sdamien 2299145247Sdamien memset(&scan, 0, sizeof scan); 2300150245Sdamien scan.type = (ic->ic_des_esslen != 0) ? IWI_SCAN_TYPE_BDIRECTED : 2301150245Sdamien IWI_SCAN_TYPE_BROADCAST; 2302146500Sdamien scan.dwelltime = htole16(sc->dwelltime); 2303145247Sdamien 2304145247Sdamien p = scan.channels; 2305145247Sdamien count = 0; 2306145247Sdamien for (i = 0; i <= IEEE80211_CHAN_MAX; i++) { 2307145247Sdamien if (IEEE80211_IS_CHAN_5GHZ(&ic->ic_channels[i]) && 2308145247Sdamien isset(ic->ic_chan_active, i)) { 2309145247Sdamien *++p = i; 2310145247Sdamien count++; 2311145247Sdamien } 2312145247Sdamien } 2313145247Sdamien *(p - count) = IWI_CHAN_5GHZ | count; 2314145247Sdamien 2315145247Sdamien count = 0; 2316145247Sdamien for (i = 0; i <= IEEE80211_CHAN_MAX; i++) { 2317145247Sdamien if (IEEE80211_IS_CHAN_2GHZ(&ic->ic_channels[i]) && 2318145247Sdamien isset(ic->ic_chan_active, i)) { 2319145247Sdamien *++p = i; 2320145247Sdamien count++; 2321145247Sdamien } 2322145247Sdamien } 2323145247Sdamien *(p - count) = IWI_CHAN_2GHZ | count; 2324145247Sdamien 2325145247Sdamien DPRINTF(("Start scanning\n")); 2326145247Sdamien return iwi_cmd(sc, IWI_CMD_SCAN, &scan, sizeof scan, 1); 2327145247Sdamien} 2328145247Sdamien 2329145247Sdamienstatic int 2330145247Sdamieniwi_auth_and_assoc(struct iwi_softc *sc) 2331145247Sdamien{ 2332145247Sdamien struct ieee80211com *ic = &sc->sc_ic; 2333145247Sdamien struct ifnet *ifp = ic->ic_ifp; 2334145247Sdamien struct ieee80211_node *ni = ic->ic_bss; 2335149338Sdamien struct ieee80211_wme_info wme; 2336145247Sdamien struct iwi_configuration config; 2337145247Sdamien struct iwi_associate assoc; 2338145247Sdamien struct iwi_rateset rs; 2339146500Sdamien uint16_t capinfo; 2340145247Sdamien uint32_t data; 2341145247Sdamien int error; 2342145247Sdamien 2343145247Sdamien if (IEEE80211_IS_CHAN_2GHZ(ni->ni_chan)) { 2344145247Sdamien memset(&config, 0, sizeof config); 2345145247Sdamien config.bluetooth_coexistence = sc->bluetooth; 2346146500Sdamien config.antenna = sc->antenna; 2347145247Sdamien config.multicast_enabled = 1; 2348145247Sdamien config.use_protection = 1; 2349146500Sdamien config.answer_pbreq = 2350146500Sdamien (ic->ic_opmode == IEEE80211_M_IBSS) ? 1 : 0; 2351146500Sdamien config.disable_unicast_decryption = 1; 2352146500Sdamien config.disable_multicast_decryption = 1; 2353145247Sdamien DPRINTF(("Configuring adapter\n")); 2354145247Sdamien error = iwi_cmd(sc, IWI_CMD_SET_CONFIG, &config, sizeof config, 2355145247Sdamien 1); 2356145247Sdamien if (error != 0) 2357145247Sdamien return error; 2358145247Sdamien } 2359145247Sdamien 2360145247Sdamien#ifdef IWI_DEBUG 2361145247Sdamien if (iwi_debug > 0) { 2362145247Sdamien printf("Setting ESSID to "); 2363145247Sdamien ieee80211_print_essid(ni->ni_essid, ni->ni_esslen); 2364145247Sdamien printf("\n"); 2365145247Sdamien } 2366145247Sdamien#endif 2367145247Sdamien error = iwi_cmd(sc, IWI_CMD_SET_ESSID, ni->ni_essid, ni->ni_esslen, 1); 2368145247Sdamien if (error != 0) 2369145247Sdamien return error; 2370145247Sdamien 2371145247Sdamien /* the rate set has already been "negociated" */ 2372145247Sdamien rs.mode = IEEE80211_IS_CHAN_5GHZ(ni->ni_chan) ? IWI_MODE_11A : 2373145247Sdamien IWI_MODE_11G; 2374145247Sdamien rs.type = IWI_RATESET_TYPE_NEGOCIATED; 2375145247Sdamien rs.nrates = ni->ni_rates.rs_nrates; 2376145247Sdamien memcpy(rs.rates, ni->ni_rates.rs_rates, rs.nrates); 2377145247Sdamien DPRINTF(("Setting negociated rates (%u)\n", rs.nrates)); 2378145247Sdamien error = iwi_cmd(sc, IWI_CMD_SET_RATES, &rs, sizeof rs, 1); 2379145247Sdamien if (error != 0) 2380145247Sdamien return error; 2381145247Sdamien 2382149338Sdamien if ((ic->ic_flags & IEEE80211_F_WME) && ni->ni_wme_ie != NULL) { 2383149338Sdamien wme.wme_id = IEEE80211_ELEMID_VENDOR; 2384149338Sdamien wme.wme_len = sizeof (struct ieee80211_wme_info) - 2; 2385149338Sdamien wme.wme_oui[0] = 0x00; 2386149338Sdamien wme.wme_oui[1] = 0x50; 2387149338Sdamien wme.wme_oui[2] = 0xf2; 2388149338Sdamien wme.wme_type = WME_OUI_TYPE; 2389149338Sdamien wme.wme_subtype = WME_INFO_OUI_SUBTYPE; 2390149338Sdamien wme.wme_version = WME_VERSION; 2391149338Sdamien wme.wme_info = 0; 2392149338Sdamien 2393149338Sdamien DPRINTF(("Setting WME IE (len=%u)\n", wme.wme_len)); 2394149338Sdamien error = iwi_cmd(sc, IWI_CMD_SET_WMEIE, &wme, sizeof wme, 1); 2395149338Sdamien if (error != 0) 2396149338Sdamien return error; 2397149338Sdamien } 2398149338Sdamien 2399146500Sdamien if (ic->ic_opt_ie != NULL) { 2400146500Sdamien DPRINTF(("Setting optional IE (len=%u)\n", ic->ic_opt_ie_len)); 2401146500Sdamien error = iwi_cmd(sc, IWI_CMD_SET_OPTIE, ic->ic_opt_ie, 2402146500Sdamien ic->ic_opt_ie_len, 1); 2403146500Sdamien if (error != 0) 2404146500Sdamien return error; 2405146500Sdamien } 2406146500Sdamien 2407145247Sdamien data = htole32(ni->ni_rssi); 2408145247Sdamien DPRINTF(("Setting sensitivity to %d\n", (int8_t)ni->ni_rssi)); 2409145247Sdamien error = iwi_cmd(sc, IWI_CMD_SET_SENSITIVITY, &data, sizeof data, 1); 2410145247Sdamien if (error != 0) 2411145247Sdamien return error; 2412145247Sdamien 2413145247Sdamien memset(&assoc, 0, sizeof assoc); 2414145247Sdamien assoc.mode = IEEE80211_IS_CHAN_5GHZ(ni->ni_chan) ? IWI_MODE_11A : 2415145247Sdamien IWI_MODE_11G; 2416145247Sdamien assoc.chan = ieee80211_chan2ieee(ic, ni->ni_chan); 2417145247Sdamien if (ni->ni_authmode == IEEE80211_AUTH_SHARED) 2418145247Sdamien assoc.auth = ic->ic_crypto.cs_def_txkey << 4 | IWI_AUTH_SHARED; 2419149338Sdamien if ((ic->ic_flags & IEEE80211_F_WME) && ni->ni_wme_ie != NULL) 2420149338Sdamien assoc.policy |= htole16(IWI_POLICY_WME); 2421146500Sdamien if (ic->ic_opt_ie != NULL) 2422149338Sdamien assoc.policy |= htole16(IWI_POLICY_WPA); 2423145247Sdamien memcpy(assoc.tstamp, ni->ni_tstamp.data, 8); 2424146500Sdamien 2425146500Sdamien if (ic->ic_opmode == IEEE80211_M_IBSS) 2426146500Sdamien capinfo = IEEE80211_CAPINFO_IBSS; 2427146500Sdamien else 2428146500Sdamien capinfo = IEEE80211_CAPINFO_ESS; 2429146500Sdamien if (ic->ic_flags & IEEE80211_F_PRIVACY) 2430146500Sdamien capinfo |= IEEE80211_CAPINFO_PRIVACY; 2431146500Sdamien if ((ic->ic_flags & IEEE80211_F_SHPREAMBLE) && 2432146500Sdamien IEEE80211_IS_CHAN_2GHZ(ni->ni_chan)) 2433146500Sdamien capinfo |= IEEE80211_CAPINFO_SHORT_PREAMBLE; 2434146500Sdamien if (ic->ic_flags & IEEE80211_F_SHSLOT) 2435146500Sdamien capinfo |= IEEE80211_CAPINFO_SHORT_SLOTTIME; 2436146500Sdamien assoc.capinfo = htole16(capinfo); 2437146500Sdamien 2438145247Sdamien assoc.lintval = htole16(ic->ic_lintval); 2439145247Sdamien assoc.intval = htole16(ni->ni_intval); 2440145247Sdamien IEEE80211_ADDR_COPY(assoc.bssid, ni->ni_bssid); 2441145247Sdamien if (ic->ic_opmode == IEEE80211_M_IBSS) 2442145247Sdamien IEEE80211_ADDR_COPY(assoc.dst, ifp->if_broadcastaddr); 2443145247Sdamien else 2444145247Sdamien IEEE80211_ADDR_COPY(assoc.dst, ni->ni_bssid); 2445145247Sdamien 2446145247Sdamien DPRINTF(("Trying to associate to %6D channel %u auth %u\n", 2447145247Sdamien assoc.bssid, ":", assoc.chan, assoc.auth)); 2448145247Sdamien return iwi_cmd(sc, IWI_CMD_ASSOCIATE, &assoc, sizeof assoc, 1); 2449145247Sdamien} 2450145247Sdamien 2451145247Sdamienstatic void 2452145247Sdamieniwi_init(void *priv) 2453145247Sdamien{ 2454145247Sdamien struct iwi_softc *sc = priv; 2455145247Sdamien struct ieee80211com *ic = &sc->sc_ic; 2456145247Sdamien struct ifnet *ifp = ic->ic_ifp; 2457145247Sdamien struct iwi_firmware *fw = &sc->fw; 2458145247Sdamien struct iwi_rx_data *data; 2459145247Sdamien int i; 2460145247Sdamien 2461145247Sdamien /* exit immediately if firmware has not been ioctl'd */ 2462145247Sdamien if (!(sc->flags & IWI_FLAG_FW_CACHED)) { 2463146247Simp if (!(sc->flags & IWI_FLAG_FW_WARNED)) 2464146247Simp device_printf(sc->sc_dev, "Please load firmware\n"); 2465146247Simp sc->flags |= IWI_FLAG_FW_WARNED; 2466145247Sdamien ifp->if_flags &= ~IFF_UP; 2467145247Sdamien return; 2468145247Sdamien } 2469145247Sdamien 2470145247Sdamien iwi_stop(sc); 2471145247Sdamien 2472145247Sdamien if (iwi_reset(sc) != 0) { 2473145247Sdamien device_printf(sc->sc_dev, "could not reset adapter\n"); 2474145247Sdamien goto fail; 2475145247Sdamien } 2476145247Sdamien 2477145247Sdamien if (iwi_load_firmware(sc, fw->boot, fw->boot_size) != 0) { 2478145247Sdamien device_printf(sc->sc_dev, "could not load boot firmware\n"); 2479145247Sdamien goto fail; 2480145247Sdamien } 2481145247Sdamien 2482145247Sdamien if (iwi_load_ucode(sc, fw->ucode, fw->ucode_size) != 0) { 2483145247Sdamien device_printf(sc->sc_dev, "could not load microcode\n"); 2484145247Sdamien goto fail; 2485145247Sdamien } 2486145247Sdamien 2487145247Sdamien iwi_stop_master(sc); 2488145247Sdamien 2489145247Sdamien CSR_WRITE_4(sc, IWI_CSR_CMD_BASE, sc->cmdq.physaddr); 2490145247Sdamien CSR_WRITE_4(sc, IWI_CSR_CMD_SIZE, sc->cmdq.count); 2491145247Sdamien CSR_WRITE_4(sc, IWI_CSR_CMD_WIDX, sc->cmdq.cur); 2492145247Sdamien 2493149338Sdamien CSR_WRITE_4(sc, IWI_CSR_TX1_BASE, sc->txq[0].physaddr); 2494149338Sdamien CSR_WRITE_4(sc, IWI_CSR_TX1_SIZE, sc->txq[0].count); 2495149338Sdamien CSR_WRITE_4(sc, IWI_CSR_TX1_WIDX, sc->txq[0].cur); 2496145247Sdamien 2497149338Sdamien CSR_WRITE_4(sc, IWI_CSR_TX2_BASE, sc->txq[1].physaddr); 2498149338Sdamien CSR_WRITE_4(sc, IWI_CSR_TX2_SIZE, sc->txq[1].count); 2499149338Sdamien CSR_WRITE_4(sc, IWI_CSR_TX2_WIDX, sc->txq[1].cur); 2500145247Sdamien 2501149338Sdamien CSR_WRITE_4(sc, IWI_CSR_TX3_BASE, sc->txq[2].physaddr); 2502149338Sdamien CSR_WRITE_4(sc, IWI_CSR_TX3_SIZE, sc->txq[2].count); 2503149338Sdamien CSR_WRITE_4(sc, IWI_CSR_TX3_WIDX, sc->txq[2].cur); 2504145247Sdamien 2505149338Sdamien CSR_WRITE_4(sc, IWI_CSR_TX4_BASE, sc->txq[3].physaddr); 2506149338Sdamien CSR_WRITE_4(sc, IWI_CSR_TX4_SIZE, sc->txq[3].count); 2507149338Sdamien CSR_WRITE_4(sc, IWI_CSR_TX4_WIDX, sc->txq[3].cur); 2508145247Sdamien 2509145247Sdamien for (i = 0; i < sc->rxq.count; i++) { 2510145247Sdamien data = &sc->rxq.data[i]; 2511145247Sdamien CSR_WRITE_4(sc, data->reg, data->physaddr); 2512145247Sdamien } 2513145247Sdamien 2514145247Sdamien CSR_WRITE_4(sc, IWI_CSR_RX_WIDX, sc->rxq.count - 1); 2515145247Sdamien 2516145247Sdamien if (iwi_load_firmware(sc, fw->main, fw->main_size) != 0) { 2517145247Sdamien device_printf(sc->sc_dev, "could not load main firmware\n"); 2518145247Sdamien goto fail; 2519145247Sdamien } 2520145247Sdamien 2521145247Sdamien sc->flags |= IWI_FLAG_FW_INITED; 2522145247Sdamien 2523145247Sdamien if (iwi_config(sc) != 0) { 2524145247Sdamien device_printf(sc->sc_dev, "device configuration failed\n"); 2525145247Sdamien goto fail; 2526145247Sdamien } 2527145247Sdamien 2528149333Sdamien if (ic->ic_opmode != IEEE80211_M_MONITOR) { 2529149333Sdamien if (ic->ic_roaming != IEEE80211_ROAMING_MANUAL) 2530149333Sdamien ieee80211_new_state(ic, IEEE80211_S_SCAN, -1); 2531149333Sdamien } else 2532146500Sdamien ieee80211_new_state(ic, IEEE80211_S_RUN, -1); 2533145247Sdamien 2534148887Srwatson ifp->if_drv_flags &= ~IFF_DRV_OACTIVE; 2535148887Srwatson ifp->if_drv_flags |= IFF_DRV_RUNNING; 2536145247Sdamien 2537145247Sdamien return; 2538145247Sdamien 2539145247Sdamienfail: ifp->if_flags &= ~IFF_UP; 2540145247Sdamien iwi_stop(sc); 2541145247Sdamien} 2542145247Sdamien 2543145247Sdamienstatic void 2544145247Sdamieniwi_stop(void *priv) 2545145247Sdamien{ 2546145247Sdamien struct iwi_softc *sc = priv; 2547145247Sdamien struct ieee80211com *ic = &sc->sc_ic; 2548145247Sdamien struct ifnet *ifp = ic->ic_ifp; 2549145247Sdamien 2550145247Sdamien iwi_stop_master(sc); 2551145247Sdamien 2552145247Sdamien CSR_WRITE_4(sc, IWI_CSR_RST, IWI_RST_SOFT_RESET); 2553145247Sdamien 2554145247Sdamien /* reset rings */ 2555145247Sdamien iwi_reset_cmd_ring(sc, &sc->cmdq); 2556149338Sdamien iwi_reset_tx_ring(sc, &sc->txq[0]); 2557149338Sdamien iwi_reset_tx_ring(sc, &sc->txq[1]); 2558149338Sdamien iwi_reset_tx_ring(sc, &sc->txq[2]); 2559149338Sdamien iwi_reset_tx_ring(sc, &sc->txq[3]); 2560145247Sdamien iwi_reset_rx_ring(sc, &sc->rxq); 2561145247Sdamien 2562145247Sdamien sc->sc_tx_timer = 0; 2563145247Sdamien ifp->if_timer = 0; 2564148887Srwatson ifp->if_drv_flags &= ~(IFF_DRV_RUNNING | IFF_DRV_OACTIVE); 2565145247Sdamien 2566145247Sdamien ieee80211_new_state(ic, IEEE80211_S_INIT, -1); 2567145247Sdamien} 2568145247Sdamien 2569145247Sdamienstatic int 2570145247Sdamieniwi_sysctl_stats(SYSCTL_HANDLER_ARGS) 2571145247Sdamien{ 2572145247Sdamien struct iwi_softc *sc = arg1; 2573145247Sdamien uint32_t size, buf[128]; 2574145247Sdamien 2575145247Sdamien if (!(sc->flags & IWI_FLAG_FW_INITED)) { 2576145247Sdamien memset(buf, 0, sizeof buf); 2577145247Sdamien return SYSCTL_OUT(req, buf, sizeof buf); 2578145247Sdamien } 2579145247Sdamien 2580145247Sdamien size = min(CSR_READ_4(sc, IWI_CSR_TABLE0_SIZE), 128 - 1); 2581145247Sdamien CSR_READ_REGION_4(sc, IWI_CSR_TABLE0_BASE, &buf[1], size); 2582145247Sdamien 2583145247Sdamien return SYSCTL_OUT(req, buf, sizeof buf); 2584145247Sdamien} 2585145247Sdamien 2586145247Sdamienstatic int 2587145247Sdamieniwi_sysctl_radio(SYSCTL_HANDLER_ARGS) 2588145247Sdamien{ 2589145247Sdamien struct iwi_softc *sc = arg1; 2590145247Sdamien int val; 2591145247Sdamien 2592145247Sdamien val = (CSR_READ_4(sc, IWI_CSR_IO) & IWI_IO_RADIO_ENABLED) ? 1 : 0; 2593145247Sdamien 2594145247Sdamien return SYSCTL_OUT(req, &val, sizeof val); 2595145247Sdamien} 2596