if_iwi.c revision 149186
1145247Sdamien/* $FreeBSD: head/sys/dev/iwi/if_iwi.c 149186 2005-08-17 14:08:52Z jhb $ */ 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 149186 2005-08-17 14:08:52Z jhb $"); 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 *, 112145247Sdamien int); 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 *); 119145247Sdamienstatic int iwi_media_change(struct ifnet *); 120145247Sdamienstatic void iwi_media_status(struct ifnet *, struct ifmediareq *); 121145247Sdamienstatic int iwi_newstate(struct ieee80211com *, enum ieee80211_state, int); 122145247Sdamienstatic uint16_t iwi_read_prom_word(struct iwi_softc *, uint8_t); 123145247Sdamienstatic void iwi_fix_channel(struct ieee80211com *, struct mbuf *); 124145247Sdamienstatic void iwi_frame_intr(struct iwi_softc *, struct iwi_rx_data *, int, 125145247Sdamien struct iwi_frame *); 126145247Sdamienstatic void iwi_notification_intr(struct iwi_softc *, struct iwi_notif *); 127145247Sdamienstatic void iwi_rx_intr(struct iwi_softc *); 128145247Sdamienstatic void iwi_tx_intr(struct iwi_softc *); 129145247Sdamienstatic void iwi_intr(void *); 130145247Sdamienstatic int iwi_cmd(struct iwi_softc *, uint8_t, void *, uint8_t, int); 131145247Sdamienstatic int iwi_tx_start(struct ifnet *, struct mbuf *, 132145247Sdamien struct ieee80211_node *); 133145247Sdamienstatic void iwi_start(struct ifnet *); 134145247Sdamienstatic void iwi_watchdog(struct ifnet *); 135145247Sdamienstatic int iwi_ioctl(struct ifnet *, u_long, caddr_t); 136145247Sdamienstatic void iwi_stop_master(struct iwi_softc *); 137145247Sdamienstatic int iwi_reset(struct iwi_softc *); 138145247Sdamienstatic int iwi_load_ucode(struct iwi_softc *, void *, int); 139145247Sdamienstatic int iwi_load_firmware(struct iwi_softc *, void *, int); 140145247Sdamienstatic int iwi_cache_firmware(struct iwi_softc *, void *); 141145247Sdamienstatic void iwi_free_firmware(struct iwi_softc *); 142145247Sdamienstatic int iwi_config(struct iwi_softc *); 143146500Sdamienstatic int iwi_set_chan(struct iwi_softc *, struct ieee80211_channel *); 144145247Sdamienstatic int iwi_scan(struct iwi_softc *); 145145247Sdamienstatic int iwi_auth_and_assoc(struct iwi_softc *); 146145247Sdamienstatic void iwi_init(void *); 147145247Sdamienstatic void iwi_stop(void *); 148145247Sdamien#ifdef IWI_DEBUG 149145247Sdamienstatic int iwi_sysctl_stats(SYSCTL_HANDLER_ARGS); 150145247Sdamien#endif 151145247Sdamienstatic int iwi_sysctl_radio(SYSCTL_HANDLER_ARGS); 152145247Sdamien 153145247Sdamienstatic int iwi_probe(device_t); 154145247Sdamienstatic int iwi_attach(device_t); 155145247Sdamienstatic int iwi_detach(device_t); 156145247Sdamienstatic int iwi_shutdown(device_t); 157145247Sdamienstatic int iwi_suspend(device_t); 158145247Sdamienstatic int iwi_resume(device_t); 159145247Sdamien 160145247Sdamienstatic device_method_t iwi_methods[] = { 161145247Sdamien /* Device interface */ 162145247Sdamien DEVMETHOD(device_probe, iwi_probe), 163145247Sdamien DEVMETHOD(device_attach, iwi_attach), 164145247Sdamien DEVMETHOD(device_detach, iwi_detach), 165145247Sdamien DEVMETHOD(device_shutdown, iwi_shutdown), 166145247Sdamien DEVMETHOD(device_suspend, iwi_suspend), 167145247Sdamien DEVMETHOD(device_resume, iwi_resume), 168145247Sdamien 169145247Sdamien { 0, 0 } 170145247Sdamien}; 171145247Sdamien 172145247Sdamienstatic driver_t iwi_driver = { 173145247Sdamien "iwi", 174145247Sdamien iwi_methods, 175145247Sdamien sizeof (struct iwi_softc) 176145247Sdamien}; 177145247Sdamien 178145247Sdamienstatic devclass_t iwi_devclass; 179145247Sdamien 180145247SdamienDRIVER_MODULE(iwi, pci, iwi_driver, iwi_devclass, 0, 0); 181145247Sdamien 182145247Sdamien/* 183145247Sdamien * Supported rates for 802.11a/b/g modes (in 500Kbps unit). 184145247Sdamien */ 185145247Sdamienstatic const struct ieee80211_rateset iwi_rateset_11a = 186145247Sdamien { 8, { 12, 18, 24, 36, 48, 72, 96, 108 } }; 187145247Sdamien 188145247Sdamienstatic const struct ieee80211_rateset iwi_rateset_11b = 189145247Sdamien { 4, { 2, 4, 11, 22 } }; 190145247Sdamien 191145247Sdamienstatic const struct ieee80211_rateset iwi_rateset_11g = 192145247Sdamien { 12, { 2, 4, 11, 22, 12, 18, 24, 36, 48, 72, 96, 108 } }; 193145247Sdamien 194145247Sdamienstatic __inline uint8_t 195145247SdamienMEM_READ_1(struct iwi_softc *sc, uint32_t addr) 196145247Sdamien{ 197145247Sdamien CSR_WRITE_4(sc, IWI_CSR_INDIRECT_ADDR, addr); 198145247Sdamien return CSR_READ_1(sc, IWI_CSR_INDIRECT_DATA); 199145247Sdamien} 200145247Sdamien 201145247Sdamienstatic __inline uint32_t 202145247SdamienMEM_READ_4(struct iwi_softc *sc, uint32_t addr) 203145247Sdamien{ 204145247Sdamien CSR_WRITE_4(sc, IWI_CSR_INDIRECT_ADDR, addr); 205145247Sdamien return CSR_READ_4(sc, IWI_CSR_INDIRECT_DATA); 206145247Sdamien} 207145247Sdamien 208145247Sdamienstatic int 209145247Sdamieniwi_probe(device_t dev) 210145247Sdamien{ 211145247Sdamien const struct iwi_ident *ident; 212145247Sdamien 213145247Sdamien for (ident = iwi_ident_table; ident->name != NULL; ident++) { 214145247Sdamien if (pci_get_vendor(dev) == ident->vendor && 215145247Sdamien pci_get_device(dev) == ident->device) { 216145247Sdamien device_set_desc(dev, ident->name); 217145247Sdamien return 0; 218145247Sdamien } 219145247Sdamien } 220145247Sdamien return ENXIO; 221145247Sdamien} 222145247Sdamien 223145247Sdamien/* Base Address Register */ 224145247Sdamien#define IWI_PCI_BAR0 0x10 225145247Sdamien 226145247Sdamienstatic int 227145247Sdamieniwi_attach(device_t dev) 228145247Sdamien{ 229145247Sdamien struct iwi_softc *sc = device_get_softc(dev); 230147256Sbrooks struct ifnet *ifp; 231145247Sdamien struct ieee80211com *ic = &sc->sc_ic; 232145247Sdamien uint16_t val; 233145247Sdamien int error, i; 234145247Sdamien 235145247Sdamien sc->sc_dev = dev; 236145247Sdamien 237145247Sdamien mtx_init(&sc->sc_mtx, device_get_nameunit(dev), MTX_NETWORK_LOCK, 238145247Sdamien MTX_DEF | MTX_RECURSE); 239145247Sdamien 240145247Sdamien if (pci_get_powerstate(dev) != PCI_POWERSTATE_D0) { 241145247Sdamien device_printf(dev, "chip is in D%d power mode " 242145247Sdamien "-- setting to D0\n", pci_get_powerstate(dev)); 243145247Sdamien pci_set_powerstate(dev, PCI_POWERSTATE_D0); 244145247Sdamien } 245145247Sdamien 246146500Sdamien pci_write_config(dev, 0x41, 0, 1); 247146500Sdamien 248145247Sdamien /* enable bus-mastering */ 249145247Sdamien pci_enable_busmaster(dev); 250145247Sdamien 251145247Sdamien sc->mem_rid = IWI_PCI_BAR0; 252145247Sdamien sc->mem = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &sc->mem_rid, 253145247Sdamien RF_ACTIVE); 254145247Sdamien if (sc->mem == NULL) { 255145247Sdamien device_printf(dev, "could not allocate memory resource\n"); 256145247Sdamien goto fail; 257145247Sdamien } 258145247Sdamien 259145247Sdamien sc->sc_st = rman_get_bustag(sc->mem); 260145247Sdamien sc->sc_sh = rman_get_bushandle(sc->mem); 261145247Sdamien 262145247Sdamien sc->irq_rid = 0; 263145247Sdamien sc->irq = bus_alloc_resource_any(dev, SYS_RES_IRQ, &sc->irq_rid, 264145247Sdamien RF_ACTIVE | RF_SHAREABLE); 265145247Sdamien if (sc->irq == NULL) { 266145247Sdamien device_printf(dev, "could not allocate interrupt resource\n"); 267145247Sdamien goto fail; 268145247Sdamien } 269145247Sdamien 270145247Sdamien if (iwi_reset(sc) != 0) { 271145247Sdamien device_printf(dev, "could not reset adapter\n"); 272145247Sdamien goto fail; 273145247Sdamien } 274145247Sdamien 275145247Sdamien /* 276145247Sdamien * Allocate rings. 277145247Sdamien */ 278145247Sdamien if (iwi_alloc_cmd_ring(sc, &sc->cmdq, IWI_CMD_RING_COUNT) != 0) { 279145247Sdamien device_printf(dev, "could not allocate Cmd ring\n"); 280145247Sdamien goto fail; 281145247Sdamien } 282145247Sdamien 283145247Sdamien if (iwi_alloc_tx_ring(sc, &sc->txq, IWI_TX_RING_COUNT) != 0) { 284145247Sdamien device_printf(dev, "could not allocate Tx ring\n"); 285145247Sdamien goto fail; 286145247Sdamien } 287145247Sdamien 288145247Sdamien if (iwi_alloc_rx_ring(sc, &sc->rxq, IWI_RX_RING_COUNT) != 0) { 289145247Sdamien device_printf(dev, "could not allocate Rx ring\n"); 290145247Sdamien goto fail; 291145247Sdamien } 292145247Sdamien 293147256Sbrooks ifp = sc->sc_ifp = if_alloc(IFT_ETHER); 294147256Sbrooks if (ifp == NULL) { 295147256Sbrooks device_printf(dev, "can not if_alloc()\n"); 296147256Sbrooks goto fail; 297147256Sbrooks return (ENOSPC); 298147256Sbrooks } 299145247Sdamien ifp->if_softc = sc; 300145247Sdamien if_initname(ifp, device_get_name(dev), device_get_unit(dev)); 301145247Sdamien ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST; 302145247Sdamien ifp->if_init = iwi_init; 303145247Sdamien ifp->if_ioctl = iwi_ioctl; 304145247Sdamien ifp->if_start = iwi_start; 305145247Sdamien ifp->if_watchdog = iwi_watchdog; 306145247Sdamien IFQ_SET_MAXLEN(&ifp->if_snd, IFQ_MAXLEN); 307145247Sdamien ifp->if_snd.ifq_drv_maxlen = IFQ_MAXLEN; 308145247Sdamien IFQ_SET_READY(&ifp->if_snd); 309145247Sdamien 310145247Sdamien ic->ic_ifp = ifp; 311145247Sdamien ic->ic_phytype = IEEE80211_T_OFDM; /* not only, but not used */ 312145247Sdamien ic->ic_opmode = IEEE80211_M_STA; /* default to BSS mode */ 313145247Sdamien ic->ic_state = IEEE80211_S_INIT; 314145247Sdamien 315145247Sdamien /* set device capabilities */ 316146500Sdamien ic->ic_caps = IEEE80211_C_WPA | IEEE80211_C_PMGT | IEEE80211_C_TXPMGT | 317146500Sdamien IEEE80211_C_SHPREAMBLE | IEEE80211_C_MONITOR; 318145247Sdamien 319145247Sdamien /* read MAC address from EEPROM */ 320145247Sdamien val = iwi_read_prom_word(sc, IWI_EEPROM_MAC + 0); 321145247Sdamien ic->ic_myaddr[0] = val >> 8; 322145247Sdamien ic->ic_myaddr[1] = val & 0xff; 323145247Sdamien val = iwi_read_prom_word(sc, IWI_EEPROM_MAC + 1); 324145247Sdamien ic->ic_myaddr[2] = val >> 8; 325145247Sdamien ic->ic_myaddr[3] = val & 0xff; 326145247Sdamien val = iwi_read_prom_word(sc, IWI_EEPROM_MAC + 2); 327145247Sdamien ic->ic_myaddr[4] = val >> 8; 328145247Sdamien ic->ic_myaddr[5] = val & 0xff; 329145247Sdamien 330146500Sdamien#if 0 331145247Sdamien if (pci_get_device(dev) >= 0x4223) { 332145247Sdamien /* set supported .11a rates (2915ABG only) */ 333145247Sdamien ic->ic_sup_rates[IEEE80211_MODE_11A] = iwi_rateset_11a; 334145247Sdamien 335145247Sdamien /* set supported .11a channels */ 336145247Sdamien for (i = 36; i <= 64; i += 4) { 337145247Sdamien ic->ic_channels[i].ic_freq = 338145247Sdamien ieee80211_ieee2mhz(i, IEEE80211_CHAN_5GHZ); 339145247Sdamien ic->ic_channels[i].ic_flags = IEEE80211_CHAN_A; 340145247Sdamien } 341145247Sdamien for (i = 149; i <= 165; i += 4) { 342145247Sdamien ic->ic_channels[i].ic_freq = 343145247Sdamien ieee80211_ieee2mhz(i, IEEE80211_CHAN_5GHZ); 344145247Sdamien ic->ic_channels[i].ic_flags = IEEE80211_CHAN_A; 345145247Sdamien } 346145247Sdamien } 347146500Sdamien#endif 348145247Sdamien 349145247Sdamien /* set supported .11b and .11g rates */ 350145247Sdamien ic->ic_sup_rates[IEEE80211_MODE_11B] = iwi_rateset_11b; 351145247Sdamien ic->ic_sup_rates[IEEE80211_MODE_11G] = iwi_rateset_11g; 352145247Sdamien 353145247Sdamien /* set supported .11b and .11g channels (1 through 14) */ 354145247Sdamien for (i = 1; i <= 14; i++) { 355145247Sdamien ic->ic_channels[i].ic_freq = 356145247Sdamien ieee80211_ieee2mhz(i, IEEE80211_CHAN_2GHZ); 357145247Sdamien ic->ic_channels[i].ic_flags = 358145247Sdamien IEEE80211_CHAN_CCK | IEEE80211_CHAN_OFDM | 359145247Sdamien IEEE80211_CHAN_DYN | IEEE80211_CHAN_2GHZ; 360145247Sdamien } 361145247Sdamien 362145247Sdamien ieee80211_ifattach(ic); 363145247Sdamien /* override state transition machine */ 364145247Sdamien sc->sc_newstate = ic->ic_newstate; 365145247Sdamien ic->ic_newstate = iwi_newstate; 366145247Sdamien ieee80211_media_init(ic, iwi_media_change, iwi_media_status); 367145247Sdamien 368145247Sdamien bpfattach2(ifp, DLT_IEEE802_11_RADIO, 369145247Sdamien sizeof (struct ieee80211_frame) + 64, &sc->sc_drvbpf); 370145247Sdamien 371145247Sdamien sc->sc_rxtap_len = sizeof sc->sc_rxtapu; 372145247Sdamien sc->sc_rxtap.wr_ihdr.it_len = htole16(sc->sc_rxtap_len); 373145247Sdamien sc->sc_rxtap.wr_ihdr.it_present = htole32(IWI_RX_RADIOTAP_PRESENT); 374145247Sdamien 375145247Sdamien sc->sc_txtap_len = sizeof sc->sc_txtapu; 376145247Sdamien sc->sc_txtap.wt_ihdr.it_len = htole16(sc->sc_txtap_len); 377145247Sdamien sc->sc_txtap.wt_ihdr.it_present = htole32(IWI_TX_RADIOTAP_PRESENT); 378145247Sdamien 379145247Sdamien /* 380145247Sdamien * Add a few sysctl knobs. 381145247Sdamien */ 382145247Sdamien sc->dwelltime = 100; 383145247Sdamien sc->bluetooth = 1; 384146500Sdamien sc->antenna = 0; 385145247Sdamien 386145247Sdamien SYSCTL_ADD_PROC(device_get_sysctl_ctx(dev), 387145247Sdamien SYSCTL_CHILDREN(device_get_sysctl_tree(dev)), OID_AUTO, "radio", 388145247Sdamien CTLTYPE_INT | CTLFLAG_RD, sc, 0, iwi_sysctl_radio, "I", 389145247Sdamien "radio transmitter switch state (0=off, 1=on)"); 390145247Sdamien 391145247Sdamien#ifdef IWI_DEBUG 392145247Sdamien SYSCTL_ADD_PROC(device_get_sysctl_ctx(dev), 393145247Sdamien SYSCTL_CHILDREN(device_get_sysctl_tree(dev)), OID_AUTO, "stats", 394145247Sdamien CTLTYPE_OPAQUE | CTLFLAG_RD, sc, 0, iwi_sysctl_stats, "S", 395145247Sdamien "statistics"); 396145247Sdamien#endif 397145247Sdamien 398145247Sdamien SYSCTL_ADD_INT(device_get_sysctl_ctx(dev), 399145247Sdamien SYSCTL_CHILDREN(device_get_sysctl_tree(dev)), OID_AUTO, "dwell", 400145247Sdamien CTLFLAG_RW, &sc->dwelltime, 0, 401145247Sdamien "channel dwell time (ms) for AP/station scanning"); 402145247Sdamien 403145247Sdamien SYSCTL_ADD_INT(device_get_sysctl_ctx(dev), 404145247Sdamien SYSCTL_CHILDREN(device_get_sysctl_tree(dev)), OID_AUTO, "bluetooth", 405145247Sdamien CTLFLAG_RW, &sc->bluetooth, 0, "bluetooth coexistence"); 406145247Sdamien 407146500Sdamien SYSCTL_ADD_INT(device_get_sysctl_ctx(dev), 408146500Sdamien SYSCTL_CHILDREN(device_get_sysctl_tree(dev)), OID_AUTO, "antenna", 409146500Sdamien CTLFLAG_RW, &sc->antenna, 0, "antenna (0=auto)"); 410146500Sdamien 411145247Sdamien /* 412145247Sdamien * Hook our interrupt after all initialization is complete. 413145247Sdamien */ 414145247Sdamien error = bus_setup_intr(dev, sc->irq, INTR_TYPE_NET | INTR_MPSAFE, 415145247Sdamien iwi_intr, sc, &sc->sc_ih); 416145247Sdamien if (error != 0) { 417145247Sdamien device_printf(dev, "could not set up interrupt\n"); 418145247Sdamien goto fail; 419145247Sdamien } 420145247Sdamien 421145247Sdamien if (bootverbose) 422145247Sdamien ieee80211_announce(ic); 423145247Sdamien 424145247Sdamien return 0; 425145247Sdamien 426145247Sdamienfail: iwi_detach(dev); 427145247Sdamien return ENXIO; 428145247Sdamien} 429145247Sdamien 430145247Sdamienstatic int 431145247Sdamieniwi_detach(device_t dev) 432145247Sdamien{ 433145247Sdamien struct iwi_softc *sc = device_get_softc(dev); 434145247Sdamien struct ieee80211com *ic = &sc->sc_ic; 435145247Sdamien struct ifnet *ifp = ic->ic_ifp; 436145247Sdamien 437145247Sdamien iwi_stop(sc); 438145247Sdamien 439145247Sdamien iwi_free_firmware(sc); 440145247Sdamien 441147256Sbrooks if (ifp != NULL) 442147256Sbrooks bpfdetach(ifp); 443145247Sdamien ieee80211_ifdetach(ic); 444147256Sbrooks if (ifp != NULL) 445147256Sbrooks if_free(ifp); 446145247Sdamien 447145247Sdamien iwi_free_cmd_ring(sc, &sc->cmdq); 448145247Sdamien iwi_free_tx_ring(sc, &sc->txq); 449145247Sdamien iwi_free_rx_ring(sc, &sc->rxq); 450145247Sdamien 451145247Sdamien if (sc->irq != NULL) { 452145247Sdamien bus_teardown_intr(dev, sc->irq, sc->sc_ih); 453145247Sdamien bus_release_resource(dev, SYS_RES_IRQ, sc->irq_rid, sc->irq); 454145247Sdamien } 455145247Sdamien 456145247Sdamien if (sc->mem != NULL) 457145247Sdamien bus_release_resource(dev, SYS_RES_MEMORY, sc->mem_rid, sc->mem); 458145247Sdamien 459145247Sdamien mtx_destroy(&sc->sc_mtx); 460145247Sdamien 461145247Sdamien return 0; 462145247Sdamien} 463145247Sdamien 464145247Sdamienstatic void 465145247Sdamieniwi_dma_map_addr(void *arg, bus_dma_segment_t *segs, int nseg, int error) 466145247Sdamien{ 467145247Sdamien if (error != 0) 468145247Sdamien return; 469145247Sdamien 470145247Sdamien KASSERT(nseg == 1, ("too many DMA segments, %d should be 1", nseg)); 471145247Sdamien 472145247Sdamien *(bus_addr_t *)arg = segs[0].ds_addr; 473145247Sdamien} 474145247Sdamien 475145247Sdamienstatic int 476145247Sdamieniwi_alloc_cmd_ring(struct iwi_softc *sc, struct iwi_cmd_ring *ring, int count) 477145247Sdamien{ 478145247Sdamien int error; 479145247Sdamien 480145247Sdamien ring->count = count; 481145247Sdamien ring->queued = 0; 482145247Sdamien ring->cur = ring->next = 0; 483145247Sdamien 484145247Sdamien error = bus_dma_tag_create(NULL, 4, 0, BUS_SPACE_MAXADDR_32BIT, 485145247Sdamien BUS_SPACE_MAXADDR, NULL, NULL, count * IWI_CMD_DESC_SIZE, 1, 486145247Sdamien count * IWI_CMD_DESC_SIZE, 0, NULL, NULL, &ring->desc_dmat); 487145247Sdamien if (error != 0) { 488145247Sdamien device_printf(sc->sc_dev, "could not create desc DMA tag\n"); 489145247Sdamien goto fail; 490145247Sdamien } 491145247Sdamien 492145247Sdamien error = bus_dmamem_alloc(ring->desc_dmat, (void **)&ring->desc, 493145247Sdamien BUS_DMA_NOWAIT | BUS_DMA_ZERO, &ring->desc_map); 494145247Sdamien if (error != 0) { 495145247Sdamien device_printf(sc->sc_dev, "could not allocate DMA memory\n"); 496145247Sdamien goto fail; 497145247Sdamien } 498145247Sdamien 499145247Sdamien error = bus_dmamap_load(ring->desc_dmat, ring->desc_map, ring->desc, 500145247Sdamien count * IWI_CMD_DESC_SIZE, iwi_dma_map_addr, &ring->physaddr, 0); 501145247Sdamien if (error != 0) { 502145247Sdamien device_printf(sc->sc_dev, "could not load desc DMA map\n"); 503145247Sdamien goto fail; 504145247Sdamien } 505145247Sdamien 506145247Sdamien return 0; 507145247Sdamien 508145247Sdamienfail: iwi_free_cmd_ring(sc, ring); 509145247Sdamien return error; 510145247Sdamien} 511145247Sdamien 512145247Sdamienstatic void 513145247Sdamieniwi_reset_cmd_ring(struct iwi_softc *sc, struct iwi_cmd_ring *ring) 514145247Sdamien{ 515145247Sdamien ring->queued = 0; 516145247Sdamien ring->cur = ring->next = 0; 517145247Sdamien} 518145247Sdamien 519145247Sdamienstatic void 520145247Sdamieniwi_free_cmd_ring(struct iwi_softc *sc, struct iwi_cmd_ring *ring) 521145247Sdamien{ 522145247Sdamien if (ring->desc != NULL) { 523145247Sdamien bus_dmamap_sync(ring->desc_dmat, ring->desc_map, 524145247Sdamien BUS_DMASYNC_POSTWRITE); 525145247Sdamien bus_dmamap_unload(ring->desc_dmat, ring->desc_map); 526145247Sdamien bus_dmamem_free(ring->desc_dmat, ring->desc, ring->desc_map); 527145247Sdamien } 528145247Sdamien 529145247Sdamien if (ring->desc_dmat != NULL) 530145247Sdamien bus_dma_tag_destroy(ring->desc_dmat); 531145247Sdamien} 532145247Sdamien 533145247Sdamienstatic int 534145247Sdamieniwi_alloc_tx_ring(struct iwi_softc *sc, struct iwi_tx_ring *ring, int count) 535145247Sdamien{ 536145247Sdamien int i, error; 537145247Sdamien 538145247Sdamien ring->count = count; 539145247Sdamien ring->queued = 0; 540145247Sdamien ring->cur = ring->next = 0; 541145247Sdamien 542145247Sdamien error = bus_dma_tag_create(NULL, 4, 0, BUS_SPACE_MAXADDR_32BIT, 543145247Sdamien BUS_SPACE_MAXADDR, NULL, NULL, count * IWI_TX_DESC_SIZE, 1, 544145247Sdamien count * IWI_TX_DESC_SIZE, 0, NULL, NULL, &ring->desc_dmat); 545145247Sdamien if (error != 0) { 546145247Sdamien device_printf(sc->sc_dev, "could not create desc DMA tag\n"); 547145247Sdamien goto fail; 548145247Sdamien } 549145247Sdamien 550145247Sdamien error = bus_dmamem_alloc(ring->desc_dmat, (void **)&ring->desc, 551145247Sdamien BUS_DMA_NOWAIT | BUS_DMA_ZERO, &ring->desc_map); 552145247Sdamien if (error != 0) { 553145247Sdamien device_printf(sc->sc_dev, "could not allocate DMA memory\n"); 554145247Sdamien goto fail; 555145247Sdamien } 556145247Sdamien 557145247Sdamien error = bus_dmamap_load(ring->desc_dmat, ring->desc_map, ring->desc, 558145247Sdamien count * IWI_TX_DESC_SIZE, iwi_dma_map_addr, &ring->physaddr, 0); 559145247Sdamien if (error != 0) { 560145247Sdamien device_printf(sc->sc_dev, "could not load desc DMA map\n"); 561145247Sdamien goto fail; 562145247Sdamien } 563145247Sdamien 564145247Sdamien ring->data = malloc(count * sizeof (struct iwi_tx_data), M_DEVBUF, 565145247Sdamien M_NOWAIT | M_ZERO); 566145247Sdamien if (ring->data == NULL) { 567145247Sdamien device_printf(sc->sc_dev, "could not allocate soft data\n"); 568145247Sdamien error = ENOMEM; 569145247Sdamien goto fail; 570145247Sdamien } 571145247Sdamien 572145247Sdamien error = bus_dma_tag_create(NULL, 1, 0, BUS_SPACE_MAXADDR_32BIT, 573145247Sdamien BUS_SPACE_MAXADDR, NULL, NULL, MCLBYTES, 1, MCLBYTES, 0, NULL, 574145247Sdamien NULL, &ring->data_dmat); 575145247Sdamien if (error != 0) { 576145247Sdamien device_printf(sc->sc_dev, "could not create data DMA tag\n"); 577145247Sdamien goto fail; 578145247Sdamien } 579145247Sdamien 580145247Sdamien for (i = 0; i < count; i++) { 581145247Sdamien error = bus_dmamap_create(ring->data_dmat, 0, 582145247Sdamien &ring->data[i].map); 583145247Sdamien if (error != 0) { 584145247Sdamien device_printf(sc->sc_dev, "could not create DMA map\n"); 585145247Sdamien goto fail; 586145247Sdamien } 587145247Sdamien } 588145247Sdamien 589145247Sdamien return 0; 590145247Sdamien 591145247Sdamienfail: iwi_free_tx_ring(sc, ring); 592145247Sdamien return error; 593145247Sdamien} 594145247Sdamien 595145247Sdamienstatic void 596145247Sdamieniwi_reset_tx_ring(struct iwi_softc *sc, struct iwi_tx_ring *ring) 597145247Sdamien{ 598145247Sdamien struct iwi_tx_data *data; 599145247Sdamien int i; 600145247Sdamien 601145247Sdamien for (i = 0; i < ring->count; i++) { 602145247Sdamien data = &ring->data[i]; 603145247Sdamien 604145247Sdamien if (data->m != NULL) { 605145247Sdamien bus_dmamap_sync(ring->data_dmat, data->map, 606145247Sdamien BUS_DMASYNC_POSTWRITE); 607145247Sdamien bus_dmamap_unload(ring->data_dmat, data->map); 608145247Sdamien m_freem(data->m); 609145247Sdamien data->m = NULL; 610145247Sdamien } 611145247Sdamien 612145247Sdamien if (data->ni != NULL) { 613145247Sdamien ieee80211_free_node(data->ni); 614145247Sdamien data->ni = NULL; 615145247Sdamien } 616145247Sdamien } 617145247Sdamien 618145247Sdamien ring->queued = 0; 619145247Sdamien ring->cur = ring->next = 0; 620145247Sdamien} 621145247Sdamien 622145247Sdamienstatic void 623145247Sdamieniwi_free_tx_ring(struct iwi_softc *sc, struct iwi_tx_ring *ring) 624145247Sdamien{ 625145247Sdamien struct iwi_tx_data *data; 626145247Sdamien int i; 627145247Sdamien 628145247Sdamien if (ring->desc != NULL) { 629145247Sdamien bus_dmamap_sync(ring->desc_dmat, ring->desc_map, 630145247Sdamien BUS_DMASYNC_POSTWRITE); 631145247Sdamien bus_dmamap_unload(ring->desc_dmat, ring->desc_map); 632145247Sdamien bus_dmamem_free(ring->desc_dmat, ring->desc, ring->desc_map); 633145247Sdamien } 634145247Sdamien 635145247Sdamien if (ring->desc_dmat != NULL) 636145247Sdamien bus_dma_tag_destroy(ring->desc_dmat); 637145247Sdamien 638145247Sdamien if (ring->data != NULL) { 639145247Sdamien for (i = 0; i < ring->count; i++) { 640145247Sdamien data = &ring->data[i]; 641145247Sdamien 642145247Sdamien if (data->m != NULL) { 643145247Sdamien bus_dmamap_sync(ring->data_dmat, data->map, 644145247Sdamien BUS_DMASYNC_POSTWRITE); 645145247Sdamien bus_dmamap_unload(ring->data_dmat, data->map); 646145247Sdamien m_freem(data->m); 647145247Sdamien } 648145247Sdamien 649145247Sdamien if (data->ni != NULL) 650145247Sdamien ieee80211_free_node(data->ni); 651145247Sdamien 652145247Sdamien if (data->map != NULL) 653145247Sdamien bus_dmamap_destroy(ring->data_dmat, data->map); 654145247Sdamien } 655145247Sdamien 656145247Sdamien free(ring->data, M_DEVBUF); 657145247Sdamien } 658145247Sdamien 659145247Sdamien if (ring->data_dmat != NULL) 660145247Sdamien bus_dma_tag_destroy(ring->data_dmat); 661145247Sdamien} 662145247Sdamien 663145247Sdamienstatic int 664145247Sdamieniwi_alloc_rx_ring(struct iwi_softc *sc, struct iwi_rx_ring *ring, int count) 665145247Sdamien{ 666145247Sdamien struct iwi_rx_data *data; 667145247Sdamien int i, error; 668145247Sdamien 669145247Sdamien ring->count = count; 670145247Sdamien ring->cur = 0; 671145247Sdamien 672145247Sdamien ring->data = malloc(count * sizeof (struct iwi_rx_data), M_DEVBUF, 673145247Sdamien M_NOWAIT | M_ZERO); 674145247Sdamien if (ring->data == NULL) { 675145247Sdamien device_printf(sc->sc_dev, "could not allocate soft data\n"); 676145247Sdamien error = ENOMEM; 677145247Sdamien goto fail; 678145247Sdamien } 679145247Sdamien 680145247Sdamien error = bus_dma_tag_create(NULL, 1, 0, BUS_SPACE_MAXADDR_32BIT, 681145247Sdamien BUS_SPACE_MAXADDR, NULL, NULL, MCLBYTES, 1, MCLBYTES, 0, NULL, 682145247Sdamien NULL, &ring->data_dmat); 683145247Sdamien if (error != 0) { 684145247Sdamien device_printf(sc->sc_dev, "could not create data DMA tag\n"); 685145247Sdamien goto fail; 686145247Sdamien } 687145247Sdamien 688145247Sdamien for (i = 0; i < count; i++) { 689145247Sdamien data = &ring->data[i]; 690145247Sdamien 691145247Sdamien error = bus_dmamap_create(ring->data_dmat, 0, &data->map); 692145247Sdamien if (error != 0) { 693145247Sdamien device_printf(sc->sc_dev, "could not create DMA map\n"); 694145247Sdamien goto fail; 695145247Sdamien } 696145247Sdamien 697145247Sdamien data->m = m_getcl(M_DONTWAIT, MT_DATA, M_PKTHDR); 698145247Sdamien if (data->m == NULL) { 699145247Sdamien device_printf(sc->sc_dev, 700145247Sdamien "could not allocate rx mbuf\n"); 701145247Sdamien error = ENOMEM; 702145247Sdamien goto fail; 703145247Sdamien } 704145247Sdamien 705145247Sdamien error = bus_dmamap_load(ring->data_dmat, data->map, 706145247Sdamien mtod(data->m, void *), MCLBYTES, iwi_dma_map_addr, 707145247Sdamien &data->physaddr, 0); 708145247Sdamien if (error != 0) { 709145247Sdamien device_printf(sc->sc_dev, 710145247Sdamien "could not load rx buf DMA map"); 711145247Sdamien goto fail; 712145247Sdamien } 713145247Sdamien 714145247Sdamien data->reg = IWI_CSR_RX_BASE + i * 4; 715145247Sdamien } 716145247Sdamien 717145247Sdamien return 0; 718145247Sdamien 719145247Sdamienfail: iwi_free_rx_ring(sc, ring); 720145247Sdamien return error; 721145247Sdamien} 722145247Sdamien 723145247Sdamienstatic void 724145247Sdamieniwi_reset_rx_ring(struct iwi_softc *sc, struct iwi_rx_ring *ring) 725145247Sdamien{ 726145247Sdamien ring->cur = 0; 727145247Sdamien} 728145247Sdamien 729145247Sdamienstatic void 730145247Sdamieniwi_free_rx_ring(struct iwi_softc *sc, struct iwi_rx_ring *ring) 731145247Sdamien{ 732145247Sdamien struct iwi_rx_data *data; 733145247Sdamien int i; 734145247Sdamien 735145247Sdamien if (ring->data != NULL) { 736145247Sdamien for (i = 0; i < ring->count; i++) { 737145247Sdamien data = &ring->data[i]; 738145247Sdamien 739145247Sdamien if (data->m != NULL) { 740145247Sdamien bus_dmamap_sync(ring->data_dmat, data->map, 741145247Sdamien BUS_DMASYNC_POSTREAD); 742145247Sdamien bus_dmamap_unload(ring->data_dmat, data->map); 743145247Sdamien m_freem(data->m); 744145247Sdamien } 745145247Sdamien 746145247Sdamien if (data->map != NULL) 747145247Sdamien bus_dmamap_destroy(ring->data_dmat, data->map); 748145247Sdamien } 749145247Sdamien 750145247Sdamien free(ring->data, M_DEVBUF); 751145247Sdamien } 752145247Sdamien 753145247Sdamien if (ring->data_dmat != NULL) 754145247Sdamien bus_dma_tag_destroy(ring->data_dmat); 755145247Sdamien} 756145247Sdamien 757145247Sdamienstatic int 758145247Sdamieniwi_shutdown(device_t dev) 759145247Sdamien{ 760145247Sdamien struct iwi_softc *sc = device_get_softc(dev); 761145247Sdamien 762145247Sdamien iwi_stop(sc); 763145247Sdamien 764145247Sdamien return 0; 765145247Sdamien} 766145247Sdamien 767145247Sdamienstatic int 768145247Sdamieniwi_suspend(device_t dev) 769145247Sdamien{ 770145247Sdamien struct iwi_softc *sc = device_get_softc(dev); 771145247Sdamien 772145247Sdamien iwi_stop(sc); 773145247Sdamien 774145247Sdamien return 0; 775145247Sdamien} 776145247Sdamien 777145247Sdamienstatic int 778145247Sdamieniwi_resume(device_t dev) 779145247Sdamien{ 780145247Sdamien struct iwi_softc *sc = device_get_softc(dev); 781145247Sdamien struct ifnet *ifp = sc->sc_ic.ic_ifp; 782145247Sdamien 783145247Sdamien IWI_LOCK(sc); 784145247Sdamien 785146500Sdamien pci_write_config(dev, 0x41, 0, 1); 786146500Sdamien 787145247Sdamien if (ifp->if_flags & IFF_UP) { 788145247Sdamien ifp->if_init(ifp->if_softc); 789148887Srwatson if (ifp->if_drv_flags & IFF_DRV_RUNNING) 790145247Sdamien ifp->if_start(ifp); 791145247Sdamien } 792145247Sdamien 793145247Sdamien IWI_UNLOCK(sc); 794145247Sdamien 795145247Sdamien return 0; 796145247Sdamien} 797145247Sdamien 798145247Sdamienstatic int 799145247Sdamieniwi_media_change(struct ifnet *ifp) 800145247Sdamien{ 801145247Sdamien struct iwi_softc *sc = ifp->if_softc; 802145247Sdamien int error; 803145247Sdamien 804145247Sdamien IWI_LOCK(sc); 805145247Sdamien 806145247Sdamien error = ieee80211_media_change(ifp); 807145247Sdamien if (error != ENETRESET) { 808145247Sdamien IWI_UNLOCK(sc); 809145247Sdamien return error; 810145247Sdamien } 811145247Sdamien 812148887Srwatson if ((ifp->if_flags & IFF_UP) && (ifp->if_drv_flags & IFF_DRV_RUNNING)) 813145247Sdamien iwi_init(sc); 814145247Sdamien 815145247Sdamien IWI_UNLOCK(sc); 816145247Sdamien 817145247Sdamien return 0; 818145247Sdamien} 819145247Sdamien 820145247Sdamien/* 821145247Sdamien * The firmware automaticly adapt the transmit speed. We report the current 822145247Sdamien * transmit speed here. 823145247Sdamien */ 824145247Sdamienstatic void 825145247Sdamieniwi_media_status(struct ifnet *ifp, struct ifmediareq *imr) 826145247Sdamien{ 827145247Sdamien struct iwi_softc *sc = ifp->if_softc; 828145247Sdamien struct ieee80211com *ic = &sc->sc_ic; 829145247Sdamien#define N(a) (sizeof (a) / sizeof (a[0])) 830145247Sdamien static const struct { 831145247Sdamien uint32_t val; 832145247Sdamien int rate; 833145247Sdamien } rates[] = { 834145247Sdamien { IWI_RATE_DS1, 2 }, 835145247Sdamien { IWI_RATE_DS2, 4 }, 836145247Sdamien { IWI_RATE_DS5, 11 }, 837145247Sdamien { IWI_RATE_DS11, 22 }, 838145247Sdamien { IWI_RATE_OFDM6, 12 }, 839145247Sdamien { IWI_RATE_OFDM9, 18 }, 840145247Sdamien { IWI_RATE_OFDM12, 24 }, 841145247Sdamien { IWI_RATE_OFDM18, 36 }, 842145247Sdamien { IWI_RATE_OFDM24, 48 }, 843145247Sdamien { IWI_RATE_OFDM36, 72 }, 844145247Sdamien { IWI_RATE_OFDM48, 96 }, 845145247Sdamien { IWI_RATE_OFDM54, 108 }, 846145247Sdamien }; 847145247Sdamien uint32_t val; 848145247Sdamien int rate, i; 849145247Sdamien 850145247Sdamien imr->ifm_status = IFM_AVALID; 851145247Sdamien imr->ifm_active = IFM_IEEE80211; 852145247Sdamien if (ic->ic_state == IEEE80211_S_RUN) 853145247Sdamien imr->ifm_status |= IFM_ACTIVE; 854145247Sdamien 855145247Sdamien /* read current transmission rate from adapter */ 856145247Sdamien val = CSR_READ_4(sc, IWI_CSR_CURRENT_TX_RATE); 857145247Sdamien 858145247Sdamien /* convert rate to 802.11 rate */ 859145247Sdamien for (i = 0; i < N(rates) && rates[i].val != val; i++); 860145247Sdamien rate = (i < N(rates)) ? rates[i].rate : 0; 861145247Sdamien 862145247Sdamien imr->ifm_active |= ieee80211_rate2media(ic, rate, ic->ic_curmode); 863145247Sdamien switch (ic->ic_opmode) { 864145247Sdamien case IEEE80211_M_STA: 865145247Sdamien break; 866145247Sdamien 867145247Sdamien case IEEE80211_M_IBSS: 868145247Sdamien imr->ifm_active |= IFM_IEEE80211_ADHOC; 869145247Sdamien break; 870145247Sdamien 871145247Sdamien case IEEE80211_M_MONITOR: 872145247Sdamien imr->ifm_active |= IFM_IEEE80211_MONITOR; 873145247Sdamien break; 874145247Sdamien 875145247Sdamien case IEEE80211_M_AHDEMO: 876145247Sdamien case IEEE80211_M_HOSTAP: 877145247Sdamien /* should not get there */ 878145247Sdamien break; 879145247Sdamien } 880145247Sdamien#undef N 881145247Sdamien} 882145247Sdamien 883145247Sdamienstatic int 884145247Sdamieniwi_newstate(struct ieee80211com *ic, enum ieee80211_state nstate, int arg) 885145247Sdamien{ 886145247Sdamien struct ifnet *ifp = ic->ic_ifp; 887145247Sdamien struct iwi_softc *sc = ifp->if_softc; 888145247Sdamien 889145247Sdamien switch (nstate) { 890145247Sdamien case IEEE80211_S_SCAN: 891146500Sdamien if (sc->flags & IWI_FLAG_SCANNING) 892146500Sdamien break; 893146500Sdamien 894146500Sdamien ieee80211_node_table_reset(&ic->ic_scan); 895146500Sdamien ic->ic_flags |= IEEE80211_F_SCAN | IEEE80211_F_ASCAN; 896146500Sdamien sc->flags |= IWI_FLAG_SCANNING; 897145247Sdamien iwi_scan(sc); 898145247Sdamien break; 899145247Sdamien 900145247Sdamien case IEEE80211_S_AUTH: 901145247Sdamien iwi_auth_and_assoc(sc); 902145247Sdamien break; 903145247Sdamien 904145247Sdamien case IEEE80211_S_RUN: 905145247Sdamien if (ic->ic_opmode == IEEE80211_M_IBSS) 906145247Sdamien ieee80211_new_state(ic, IEEE80211_S_AUTH, -1); 907146500Sdamien else if (ic->ic_opmode == IEEE80211_M_MONITOR) 908146500Sdamien iwi_set_chan(sc, ic->ic_ibss_chan); 909146500Sdamien 910146500Sdamien return sc->sc_newstate(ic, nstate, 911146500Sdamien IEEE80211_FC0_SUBTYPE_ASSOC_RESP); 912146500Sdamien 913146500Sdamien case IEEE80211_S_ASSOC: 914145247Sdamien break; 915145247Sdamien 916145247Sdamien case IEEE80211_S_INIT: 917146500Sdamien sc->flags &= ~IWI_FLAG_SCANNING; 918145247Sdamien break; 919145247Sdamien } 920145247Sdamien 921145247Sdamien ic->ic_state = nstate; 922145247Sdamien return 0; 923145247Sdamien} 924145247Sdamien 925145247Sdamien/* 926145247Sdamien * Read 16 bits at address 'addr' from the serial EEPROM. 927145247Sdamien */ 928145247Sdamienstatic uint16_t 929145247Sdamieniwi_read_prom_word(struct iwi_softc *sc, uint8_t addr) 930145247Sdamien{ 931145247Sdamien uint32_t tmp; 932145247Sdamien uint16_t val; 933145247Sdamien int n; 934145247Sdamien 935145247Sdamien /* clock C once before the first command */ 936145247Sdamien IWI_EEPROM_CTL(sc, 0); 937145247Sdamien IWI_EEPROM_CTL(sc, IWI_EEPROM_S); 938145247Sdamien IWI_EEPROM_CTL(sc, IWI_EEPROM_S | IWI_EEPROM_C); 939145247Sdamien IWI_EEPROM_CTL(sc, IWI_EEPROM_S); 940145247Sdamien 941145247Sdamien /* write start bit (1) */ 942145247Sdamien IWI_EEPROM_CTL(sc, IWI_EEPROM_S | IWI_EEPROM_D); 943145247Sdamien IWI_EEPROM_CTL(sc, IWI_EEPROM_S | IWI_EEPROM_D | IWI_EEPROM_C); 944145247Sdamien 945145247Sdamien /* write READ opcode (10) */ 946145247Sdamien IWI_EEPROM_CTL(sc, IWI_EEPROM_S | IWI_EEPROM_D); 947145247Sdamien IWI_EEPROM_CTL(sc, IWI_EEPROM_S | IWI_EEPROM_D | IWI_EEPROM_C); 948145247Sdamien IWI_EEPROM_CTL(sc, IWI_EEPROM_S); 949145247Sdamien IWI_EEPROM_CTL(sc, IWI_EEPROM_S | IWI_EEPROM_C); 950145247Sdamien 951145247Sdamien /* write address A7-A0 */ 952145247Sdamien for (n = 7; n >= 0; n--) { 953145247Sdamien IWI_EEPROM_CTL(sc, IWI_EEPROM_S | 954145247Sdamien (((addr >> n) & 1) << IWI_EEPROM_SHIFT_D)); 955145247Sdamien IWI_EEPROM_CTL(sc, IWI_EEPROM_S | 956145247Sdamien (((addr >> n) & 1) << IWI_EEPROM_SHIFT_D) | IWI_EEPROM_C); 957145247Sdamien } 958145247Sdamien 959145247Sdamien IWI_EEPROM_CTL(sc, IWI_EEPROM_S); 960145247Sdamien 961145247Sdamien /* read data Q15-Q0 */ 962145247Sdamien val = 0; 963145247Sdamien for (n = 15; n >= 0; n--) { 964145247Sdamien IWI_EEPROM_CTL(sc, IWI_EEPROM_S | IWI_EEPROM_C); 965145247Sdamien IWI_EEPROM_CTL(sc, IWI_EEPROM_S); 966145247Sdamien tmp = MEM_READ_4(sc, IWI_MEM_EEPROM_CTL); 967145247Sdamien val |= ((tmp & IWI_EEPROM_Q) >> IWI_EEPROM_SHIFT_Q) << n; 968145247Sdamien } 969145247Sdamien 970145247Sdamien IWI_EEPROM_CTL(sc, 0); 971145247Sdamien 972145247Sdamien /* clear Chip Select and clock C */ 973145247Sdamien IWI_EEPROM_CTL(sc, IWI_EEPROM_S); 974145247Sdamien IWI_EEPROM_CTL(sc, 0); 975145247Sdamien IWI_EEPROM_CTL(sc, IWI_EEPROM_C); 976145247Sdamien 977145247Sdamien return be16toh(val); 978145247Sdamien} 979145247Sdamien 980145247Sdamien/* 981145247Sdamien * XXX: Hack to set the current channel to the value advertised in beacons or 982145247Sdamien * probe responses. Only used during AP detection. 983145247Sdamien */ 984145247Sdamienstatic void 985145247Sdamieniwi_fix_channel(struct ieee80211com *ic, struct mbuf *m) 986145247Sdamien{ 987145247Sdamien struct ieee80211_frame *wh; 988145247Sdamien uint8_t subtype; 989145247Sdamien uint8_t *frm, *efrm; 990145247Sdamien 991145247Sdamien wh = mtod(m, struct ieee80211_frame *); 992145247Sdamien 993145247Sdamien if ((wh->i_fc[0] & IEEE80211_FC0_TYPE_MASK) != IEEE80211_FC0_TYPE_MGT) 994145247Sdamien return; 995145247Sdamien 996145247Sdamien subtype = wh->i_fc[0] & IEEE80211_FC0_SUBTYPE_MASK; 997145247Sdamien 998145247Sdamien if (subtype != IEEE80211_FC0_SUBTYPE_BEACON && 999145247Sdamien subtype != IEEE80211_FC0_SUBTYPE_PROBE_RESP) 1000145247Sdamien return; 1001145247Sdamien 1002145247Sdamien frm = (uint8_t *)(wh + 1); 1003145247Sdamien efrm = mtod(m, uint8_t *) + m->m_len; 1004145247Sdamien 1005145247Sdamien frm += 12; /* skip tstamp, bintval and capinfo fields */ 1006145247Sdamien while (frm < efrm) { 1007145247Sdamien if (*frm == IEEE80211_ELEMID_DSPARMS) 1008145247Sdamien#if IEEE80211_CHAN_MAX < 255 1009145247Sdamien if (frm[2] <= IEEE80211_CHAN_MAX) 1010145247Sdamien#endif 1011149186Sjhb ic->ic_curchan = &ic->ic_channels[frm[2]]; 1012145247Sdamien 1013145247Sdamien frm += frm[1] + 2; 1014145247Sdamien } 1015145247Sdamien} 1016145247Sdamien 1017145247Sdamienstatic void 1018145247Sdamieniwi_frame_intr(struct iwi_softc *sc, struct iwi_rx_data *data, int i, 1019145247Sdamien struct iwi_frame *frame) 1020145247Sdamien{ 1021145247Sdamien struct ieee80211com *ic = &sc->sc_ic; 1022145247Sdamien struct ifnet *ifp = ic->ic_ifp; 1023145247Sdamien struct mbuf *m; 1024145247Sdamien struct ieee80211_frame *wh; 1025145247Sdamien struct ieee80211_node *ni; 1026145247Sdamien int error; 1027145247Sdamien 1028145247Sdamien DPRINTFN(5, ("received frame len=%u chan=%u rssi=%u\n", 1029145247Sdamien le16toh(frame->len), frame->chan, frame->rssi_dbm)); 1030145247Sdamien 1031146500Sdamien if (le16toh(frame->len) < sizeof (struct ieee80211_frame)) 1032146500Sdamien return; 1033146500Sdamien 1034145247Sdamien bus_dmamap_unload(sc->rxq.data_dmat, data->map); 1035145247Sdamien 1036145247Sdamien /* finalize mbuf */ 1037145247Sdamien m = data->m; 1038145247Sdamien m->m_pkthdr.rcvif = ifp; 1039145247Sdamien m->m_pkthdr.len = m->m_len = sizeof (struct iwi_hdr) + 1040145247Sdamien sizeof (struct iwi_frame) + le16toh(frame->len); 1041145247Sdamien 1042145247Sdamien m_adj(m, sizeof (struct iwi_hdr) + sizeof (struct iwi_frame)); 1043145247Sdamien 1044145247Sdamien if (ic->ic_state == IEEE80211_S_SCAN) 1045145247Sdamien iwi_fix_channel(ic, m); 1046145247Sdamien 1047145247Sdamien if (sc->sc_drvbpf != NULL) { 1048145247Sdamien struct iwi_rx_radiotap_header *tap = &sc->sc_rxtap; 1049145247Sdamien 1050145247Sdamien tap->wr_flags = 0; 1051145247Sdamien tap->wr_rate = frame->rate; 1052145247Sdamien tap->wr_chan_freq = 1053145247Sdamien htole16(ic->ic_channels[frame->chan].ic_freq); 1054145247Sdamien tap->wr_chan_flags = 1055145247Sdamien htole16(ic->ic_channels[frame->chan].ic_flags); 1056145247Sdamien tap->wr_antsignal = frame->signal; 1057145247Sdamien tap->wr_antenna = frame->antenna; 1058145247Sdamien 1059145247Sdamien bpf_mtap2(sc->sc_drvbpf, tap, sc->sc_rxtap_len, m); 1060145247Sdamien } 1061145247Sdamien 1062145247Sdamien wh = mtod(m, struct ieee80211_frame *); 1063145247Sdamien ni = ieee80211_find_rxnode(ic, (struct ieee80211_frame_min *)wh); 1064145247Sdamien 1065145247Sdamien /* send the frame to the 802.11 layer */ 1066146500Sdamien ieee80211_input(ic, m, ni, frame->rssi_dbm, 0); 1067145247Sdamien 1068145247Sdamien /* node is no longer needed */ 1069145247Sdamien ieee80211_free_node(ni); 1070145247Sdamien 1071145247Sdamien data->m = m_getcl(M_DONTWAIT, MT_DATA, M_PKTHDR); 1072145247Sdamien if (data->m == NULL) { 1073145247Sdamien device_printf(sc->sc_dev, "could not allocate rx mbuf\n"); 1074145247Sdamien return; 1075145247Sdamien } 1076145247Sdamien 1077145247Sdamien error = bus_dmamap_load(sc->rxq.data_dmat, data->map, 1078145247Sdamien mtod(data->m, void *), MCLBYTES, iwi_dma_map_addr, &data->physaddr, 1079145247Sdamien 0); 1080145247Sdamien if (error != 0) { 1081145247Sdamien device_printf(sc->sc_dev, "could not load rx buf DMA map\n"); 1082145247Sdamien m_freem(data->m); 1083145247Sdamien data->m = NULL; 1084145247Sdamien return; 1085145247Sdamien } 1086145247Sdamien 1087145247Sdamien CSR_WRITE_4(sc, data->reg, data->physaddr); 1088145247Sdamien} 1089145247Sdamien 1090145247Sdamienstatic void 1091145247Sdamieniwi_notification_intr(struct iwi_softc *sc, struct iwi_notif *notif) 1092145247Sdamien{ 1093145247Sdamien struct ieee80211com *ic = &sc->sc_ic; 1094145247Sdamien struct iwi_notif_scan_channel *chan; 1095145247Sdamien struct iwi_notif_scan_complete *scan; 1096145247Sdamien struct iwi_notif_authentication *auth; 1097145247Sdamien struct iwi_notif_association *assoc; 1098145247Sdamien 1099145247Sdamien switch (notif->type) { 1100145247Sdamien case IWI_NOTIF_TYPE_SCAN_CHANNEL: 1101145247Sdamien chan = (struct iwi_notif_scan_channel *)(notif + 1); 1102145247Sdamien 1103145247Sdamien DPRINTFN(2, ("Scanning channel (%u)\n", chan->nchan)); 1104145247Sdamien break; 1105145247Sdamien 1106145247Sdamien case IWI_NOTIF_TYPE_SCAN_COMPLETE: 1107145247Sdamien scan = (struct iwi_notif_scan_complete *)(notif + 1); 1108145247Sdamien 1109145247Sdamien DPRINTFN(2, ("Scan completed (%u, %u)\n", scan->nchan, 1110145247Sdamien scan->status)); 1111145247Sdamien 1112146500Sdamien /* monitor mode uses scan to set the channel ... */ 1113146500Sdamien if (ic->ic_opmode != IEEE80211_M_MONITOR) { 1114146500Sdamien sc->flags &= ~IWI_FLAG_SCANNING; 1115146500Sdamien ieee80211_end_scan(ic); 1116146500Sdamien } else 1117146500Sdamien iwi_set_chan(sc, ic->ic_ibss_chan); 1118145247Sdamien break; 1119145247Sdamien 1120145247Sdamien case IWI_NOTIF_TYPE_AUTHENTICATION: 1121145247Sdamien auth = (struct iwi_notif_authentication *)(notif + 1); 1122145247Sdamien 1123145247Sdamien DPRINTFN(2, ("Authentication (%u)\n", auth->state)); 1124145247Sdamien 1125145247Sdamien switch (auth->state) { 1126145247Sdamien case IWI_AUTHENTICATED: 1127148302Ssam ieee80211_node_authorize(ic->ic_bss); 1128145247Sdamien ieee80211_new_state(ic, IEEE80211_S_ASSOC, -1); 1129145247Sdamien break; 1130145247Sdamien 1131145247Sdamien case IWI_DEAUTHENTICATED: 1132145247Sdamien break; 1133145247Sdamien 1134145247Sdamien default: 1135145247Sdamien device_printf(sc->sc_dev, 1136145247Sdamien "unknown authentication state %u\n", auth->state); 1137145247Sdamien } 1138145247Sdamien break; 1139145247Sdamien 1140145247Sdamien case IWI_NOTIF_TYPE_ASSOCIATION: 1141145247Sdamien assoc = (struct iwi_notif_association *)(notif + 1); 1142145247Sdamien 1143145247Sdamien DPRINTFN(2, ("Association (%u, %u)\n", assoc->state, 1144145247Sdamien assoc->status)); 1145145247Sdamien 1146145247Sdamien switch (assoc->state) { 1147145247Sdamien case IWI_AUTHENTICATED: 1148145247Sdamien /* re-association, do nothing */ 1149145247Sdamien break; 1150145247Sdamien 1151145247Sdamien case IWI_ASSOCIATED: 1152145247Sdamien ieee80211_new_state(ic, IEEE80211_S_RUN, -1); 1153145247Sdamien break; 1154145247Sdamien 1155145247Sdamien case IWI_DEASSOCIATED: 1156145247Sdamien ieee80211_begin_scan(ic, 1); 1157145247Sdamien break; 1158145247Sdamien 1159145247Sdamien default: 1160145247Sdamien device_printf(sc->sc_dev, 1161145247Sdamien "unknown association state %u\n", assoc->state); 1162145247Sdamien } 1163145247Sdamien break; 1164145247Sdamien 1165145247Sdamien case IWI_NOTIF_TYPE_CALIBRATION: 1166145247Sdamien case IWI_NOTIF_TYPE_BEACON: 1167145247Sdamien case IWI_NOTIF_TYPE_NOISE: 1168145247Sdamien DPRINTFN(5, ("Notification (%u)\n", notif->type)); 1169145247Sdamien break; 1170145247Sdamien 1171145247Sdamien default: 1172145247Sdamien device_printf(sc->sc_dev, "unknown notification type %u\n", 1173145247Sdamien notif->type); 1174145247Sdamien } 1175145247Sdamien} 1176145247Sdamien 1177145247Sdamienstatic void 1178145247Sdamieniwi_rx_intr(struct iwi_softc *sc) 1179145247Sdamien{ 1180145247Sdamien struct iwi_rx_data *data; 1181145247Sdamien struct iwi_hdr *hdr; 1182145247Sdamien uint32_t hw; 1183145247Sdamien 1184145247Sdamien hw = CSR_READ_4(sc, IWI_CSR_RX_RIDX); 1185145247Sdamien 1186145247Sdamien for (; sc->rxq.cur != hw;) { 1187145247Sdamien data = &sc->rxq.data[sc->rxq.cur]; 1188145247Sdamien 1189145247Sdamien bus_dmamap_sync(sc->rxq.data_dmat, data->map, 1190145247Sdamien BUS_DMASYNC_POSTREAD); 1191145247Sdamien 1192145247Sdamien hdr = mtod(data->m, struct iwi_hdr *); 1193145247Sdamien 1194145247Sdamien switch (hdr->type) { 1195145247Sdamien case IWI_HDR_TYPE_FRAME: 1196145247Sdamien iwi_frame_intr(sc, data, sc->rxq.cur, 1197145247Sdamien (struct iwi_frame *)(hdr + 1)); 1198145247Sdamien break; 1199145247Sdamien 1200145247Sdamien case IWI_HDR_TYPE_NOTIF: 1201145247Sdamien iwi_notification_intr(sc, 1202145247Sdamien (struct iwi_notif *)(hdr + 1)); 1203145247Sdamien break; 1204145247Sdamien 1205145247Sdamien default: 1206145247Sdamien device_printf(sc->sc_dev, "unknown hdr type %u\n", 1207145247Sdamien hdr->type); 1208145247Sdamien } 1209145247Sdamien 1210145247Sdamien DPRINTFN(15, ("rx done idx=%u\n", sc->rxq.cur)); 1211145247Sdamien 1212145247Sdamien sc->rxq.cur = (sc->rxq.cur + 1) % IWI_RX_RING_COUNT; 1213145247Sdamien } 1214145247Sdamien 1215145247Sdamien /* tell the firmware what we have processed */ 1216145247Sdamien hw = (hw == 0) ? IWI_RX_RING_COUNT - 1 : hw - 1; 1217145247Sdamien CSR_WRITE_4(sc, IWI_CSR_RX_WIDX, hw); 1218145247Sdamien} 1219145247Sdamien 1220145247Sdamienstatic void 1221145247Sdamieniwi_tx_intr(struct iwi_softc *sc) 1222145247Sdamien{ 1223145247Sdamien struct ieee80211com *ic = &sc->sc_ic; 1224145247Sdamien struct ifnet *ifp = ic->ic_ifp; 1225145247Sdamien struct iwi_tx_data *data; 1226145247Sdamien uint32_t hw; 1227145247Sdamien 1228145247Sdamien hw = CSR_READ_4(sc, IWI_CSR_TX1_RIDX); 1229145247Sdamien 1230145247Sdamien for (; sc->txq.next != hw;) { 1231145247Sdamien data = &sc->txq.data[sc->txq.next]; 1232145247Sdamien 1233145247Sdamien bus_dmamap_sync(sc->txq.data_dmat, data->map, 1234145247Sdamien BUS_DMASYNC_POSTWRITE); 1235145247Sdamien bus_dmamap_unload(sc->txq.data_dmat, data->map); 1236145247Sdamien m_freem(data->m); 1237145247Sdamien data->m = NULL; 1238145247Sdamien ieee80211_free_node(data->ni); 1239145247Sdamien data->ni = NULL; 1240145247Sdamien 1241145247Sdamien DPRINTFN(15, ("tx done idx=%u\n", sc->txq.next)); 1242145247Sdamien 1243145247Sdamien ifp->if_opackets++; 1244145247Sdamien 1245145247Sdamien sc->txq.queued--; 1246145247Sdamien sc->txq.next = (sc->txq.next + 1) % IWI_TX_RING_COUNT; 1247145247Sdamien } 1248145247Sdamien 1249145247Sdamien sc->sc_tx_timer = 0; 1250148887Srwatson ifp->if_drv_flags &= ~IFF_DRV_OACTIVE; 1251145247Sdamien iwi_start(ifp); 1252145247Sdamien} 1253145247Sdamien 1254145247Sdamienstatic void 1255145247Sdamieniwi_intr(void *arg) 1256145247Sdamien{ 1257145247Sdamien struct iwi_softc *sc = arg; 1258145247Sdamien uint32_t r; 1259145247Sdamien 1260145247Sdamien IWI_LOCK(sc); 1261145247Sdamien 1262145247Sdamien if ((r = CSR_READ_4(sc, IWI_CSR_INTR)) == 0 || r == 0xffffffff) { 1263145247Sdamien IWI_UNLOCK(sc); 1264145247Sdamien return; 1265145247Sdamien } 1266145247Sdamien 1267145247Sdamien /* disable interrupts */ 1268145247Sdamien CSR_WRITE_4(sc, IWI_CSR_INTR_MASK, 0); 1269145247Sdamien 1270145247Sdamien if (r & (IWI_INTR_FATAL_ERROR | IWI_INTR_PARITY_ERROR)) { 1271145247Sdamien device_printf(sc->sc_dev, "fatal error\n"); 1272145247Sdamien sc->sc_ic.ic_ifp->if_flags &= ~IFF_UP; 1273145247Sdamien iwi_stop(sc); 1274145247Sdamien } 1275145247Sdamien 1276145247Sdamien if (r & IWI_INTR_FW_INITED) { 1277145247Sdamien if (!(r & (IWI_INTR_FATAL_ERROR | IWI_INTR_PARITY_ERROR))) 1278145247Sdamien wakeup(sc); 1279145247Sdamien } 1280145247Sdamien 1281145247Sdamien if (r & IWI_INTR_RADIO_OFF) { 1282145247Sdamien DPRINTF(("radio transmitter turned off\n")); 1283145247Sdamien sc->sc_ic.ic_ifp->if_flags &= ~IFF_UP; 1284145247Sdamien iwi_stop(sc); 1285145247Sdamien } 1286145247Sdamien 1287145247Sdamien if (r & IWI_INTR_RX_DONE) 1288145247Sdamien iwi_rx_intr(sc); 1289145247Sdamien 1290145247Sdamien if (r & IWI_INTR_CMD_DONE) 1291145247Sdamien wakeup(sc); 1292145247Sdamien 1293145247Sdamien if (r & IWI_INTR_TX1_DONE) 1294145247Sdamien iwi_tx_intr(sc); 1295145247Sdamien 1296145247Sdamien /* acknowledge interrupts */ 1297145247Sdamien CSR_WRITE_4(sc, IWI_CSR_INTR, r); 1298145247Sdamien 1299145247Sdamien /* re-enable interrupts */ 1300145247Sdamien CSR_WRITE_4(sc, IWI_CSR_INTR_MASK, IWI_INTR_MASK); 1301145247Sdamien 1302145247Sdamien IWI_UNLOCK(sc); 1303145247Sdamien} 1304145247Sdamien 1305145247Sdamienstatic int 1306145247Sdamieniwi_cmd(struct iwi_softc *sc, uint8_t type, void *data, uint8_t len, int async) 1307145247Sdamien{ 1308145247Sdamien struct iwi_cmd_desc *desc; 1309145247Sdamien 1310145247Sdamien desc = &sc->cmdq.desc[sc->cmdq.cur]; 1311145247Sdamien 1312145247Sdamien desc->hdr.type = IWI_HDR_TYPE_COMMAND; 1313145247Sdamien desc->hdr.flags = IWI_HDR_FLAG_IRQ; 1314145247Sdamien desc->type = type; 1315145247Sdamien desc->len = len; 1316145247Sdamien memcpy(desc->data, data, len); 1317145247Sdamien 1318145247Sdamien bus_dmamap_sync(sc->cmdq.desc_dmat, sc->cmdq.desc_map, 1319145247Sdamien BUS_DMASYNC_PREWRITE); 1320145247Sdamien 1321145247Sdamien DPRINTFN(2, ("sending command idx=%u type=%u len=%u\n", sc->cmdq.cur, 1322145247Sdamien type, len)); 1323145247Sdamien 1324145247Sdamien sc->cmdq.cur = (sc->cmdq.cur + 1) % IWI_CMD_RING_COUNT; 1325145247Sdamien CSR_WRITE_4(sc, IWI_CSR_CMD_WIDX, sc->cmdq.cur); 1326145247Sdamien 1327145247Sdamien return async ? 0 : msleep(sc, &sc->sc_mtx, 0, "iwicmd", hz); 1328145247Sdamien} 1329145247Sdamien 1330145247Sdamienstatic int 1331145247Sdamieniwi_tx_start(struct ifnet *ifp, struct mbuf *m0, struct ieee80211_node *ni) 1332145247Sdamien{ 1333145247Sdamien struct iwi_softc *sc = ifp->if_softc; 1334145247Sdamien struct ieee80211com *ic = &sc->sc_ic; 1335147538Ssilby struct ieee80211_frame wh; 1336146500Sdamien struct ieee80211_key *k; 1337145247Sdamien struct iwi_tx_data *data; 1338145247Sdamien struct iwi_tx_desc *desc; 1339145247Sdamien struct mbuf *mnew; 1340145247Sdamien bus_dma_segment_t segs[IWI_MAX_NSEG]; 1341145247Sdamien int nsegs, error, i; 1342145247Sdamien 1343147538Ssilby bcopy(mtod(m0, struct ieee80211_frame *), &wh, sizeof (struct ieee80211_frame)); 1344147538Ssilby if (wh.i_fc[1] & IEEE80211_FC1_WEP) { 1345146500Sdamien k = ieee80211_crypto_encap(ic, ni, m0); 1346147806Ssam if (k == NULL) { 1347147806Ssam m_freem(m0); 1348146500Sdamien return ENOBUFS; 1349147806Ssam } 1350146500Sdamien } 1351146500Sdamien 1352145247Sdamien if (sc->sc_drvbpf != NULL) { 1353145247Sdamien struct iwi_tx_radiotap_header *tap = &sc->sc_txtap; 1354145247Sdamien 1355145247Sdamien tap->wt_flags = 0; 1356146500Sdamien tap->wt_chan_freq = htole16(ic->ic_ibss_chan->ic_freq); 1357146500Sdamien tap->wt_chan_flags = htole16(ic->ic_ibss_chan->ic_flags); 1358145247Sdamien 1359145247Sdamien bpf_mtap2(sc->sc_drvbpf, tap, sc->sc_txtap_len, m0); 1360145247Sdamien } 1361145247Sdamien 1362145247Sdamien data = &sc->txq.data[sc->txq.cur]; 1363145247Sdamien desc = &sc->txq.desc[sc->txq.cur]; 1364145247Sdamien 1365145247Sdamien /* trim IEEE802.11 header */ 1366145247Sdamien m_adj(m0, sizeof (struct ieee80211_frame)); 1367145247Sdamien 1368145247Sdamien error = bus_dmamap_load_mbuf_sg(sc->txq.data_dmat, data->map, m0, segs, 1369145247Sdamien &nsegs, 0); 1370145247Sdamien if (error != 0 && error != EFBIG) { 1371145247Sdamien device_printf(sc->sc_dev, "could not map mbuf (error %d)\n", 1372145247Sdamien error); 1373145247Sdamien m_freem(m0); 1374145247Sdamien return error; 1375145247Sdamien } 1376145247Sdamien if (error != 0) { 1377145247Sdamien mnew = m_defrag(m0, M_DONTWAIT); 1378145247Sdamien if (mnew == NULL) { 1379145247Sdamien device_printf(sc->sc_dev, 1380145247Sdamien "could not defragment mbuf\n"); 1381145247Sdamien m_freem(m0); 1382145247Sdamien return ENOBUFS; 1383145247Sdamien } 1384145247Sdamien m0 = mnew; 1385145247Sdamien 1386145247Sdamien error = bus_dmamap_load_mbuf_sg(sc->txq.data_dmat, data->map, 1387145247Sdamien m0, segs, &nsegs, 0); 1388145247Sdamien if (error != 0) { 1389145247Sdamien device_printf(sc->sc_dev, 1390145247Sdamien "could not map mbuf (error %d)\n", error); 1391145247Sdamien m_freem(m0); 1392145247Sdamien return error; 1393145247Sdamien } 1394145247Sdamien } 1395145247Sdamien 1396145247Sdamien data->m = m0; 1397145247Sdamien data->ni = ni; 1398145247Sdamien 1399145247Sdamien desc->hdr.type = IWI_HDR_TYPE_DATA; 1400145247Sdamien desc->hdr.flags = IWI_HDR_FLAG_IRQ; 1401145247Sdamien desc->cmd = IWI_DATA_CMD_TX; 1402145247Sdamien desc->len = htole16(m0->m_pkthdr.len); 1403147538Ssilby memcpy(&desc->wh, &wh, sizeof (struct ieee80211_frame)); 1404145247Sdamien desc->flags = 0; 1405145247Sdamien 1406147538Ssilby if (!IEEE80211_IS_MULTICAST(wh.i_addr1)) 1407145247Sdamien desc->flags |= IWI_DATA_FLAG_NEED_ACK; 1408145247Sdamien 1409146500Sdamien#if 0 1410145247Sdamien if (ic->ic_flags & IEEE80211_F_PRIVACY) { 1411147538Ssilby wh.i_fc[1] |= IEEE80211_FC1_WEP; 1412145247Sdamien desc->wep_txkey = ic->ic_crypto.cs_def_txkey; 1413145247Sdamien } else 1414146500Sdamien#endif 1415145247Sdamien desc->flags |= IWI_DATA_FLAG_NO_WEP; 1416145247Sdamien 1417145247Sdamien if (ic->ic_flags & IEEE80211_F_SHPREAMBLE) 1418145247Sdamien desc->flags |= IWI_DATA_FLAG_SHPREAMBLE; 1419145247Sdamien 1420145247Sdamien desc->nseg = htole32(nsegs); 1421145247Sdamien for (i = 0; i < nsegs; i++) { 1422145247Sdamien desc->seg_addr[i] = htole32(segs[i].ds_addr); 1423145247Sdamien desc->seg_len[i] = htole32(segs[i].ds_len); 1424145247Sdamien } 1425145247Sdamien 1426145247Sdamien bus_dmamap_sync(sc->txq.data_dmat, data->map, BUS_DMASYNC_PREWRITE); 1427145247Sdamien bus_dmamap_sync(sc->txq.desc_dmat, sc->txq.desc_map, 1428145247Sdamien BUS_DMASYNC_PREWRITE); 1429145247Sdamien 1430145247Sdamien DPRINTFN(5, ("sending data frame idx=%u len=%u nseg=%u\n", sc->txq.cur, 1431145247Sdamien desc->len, desc->nseg)); 1432145247Sdamien 1433145247Sdamien sc->txq.queued++; 1434145247Sdamien sc->txq.cur = (sc->txq.cur + 1) % IWI_TX_RING_COUNT; 1435145247Sdamien CSR_WRITE_4(sc, IWI_CSR_TX1_WIDX, sc->txq.cur); 1436145247Sdamien 1437145247Sdamien return 0; 1438145247Sdamien} 1439145247Sdamien 1440145247Sdamienstatic void 1441145247Sdamieniwi_start(struct ifnet *ifp) 1442145247Sdamien{ 1443145247Sdamien struct iwi_softc *sc = ifp->if_softc; 1444145247Sdamien struct ieee80211com *ic = &sc->sc_ic; 1445145247Sdamien struct mbuf *m0; 1446145247Sdamien struct ether_header *eh; 1447145247Sdamien struct ieee80211_node *ni; 1448145247Sdamien 1449145247Sdamien IWI_LOCK(sc); 1450145247Sdamien 1451145247Sdamien if (ic->ic_state != IEEE80211_S_RUN) { 1452145247Sdamien IWI_UNLOCK(sc); 1453145247Sdamien return; 1454145247Sdamien } 1455145247Sdamien 1456145247Sdamien for (;;) { 1457145247Sdamien IFQ_DRV_DEQUEUE(&ifp->if_snd, m0); 1458145247Sdamien if (m0 == NULL) 1459145247Sdamien break; 1460145247Sdamien 1461145247Sdamien if (sc->txq.queued >= IWI_TX_RING_COUNT - 4) { 1462145247Sdamien IFQ_DRV_PREPEND(&ifp->if_snd, m0); 1463148887Srwatson ifp->if_drv_flags |= IFF_DRV_OACTIVE; 1464145247Sdamien break; 1465145247Sdamien } 1466145247Sdamien 1467145247Sdamien if (m0->m_len < sizeof (struct ether_header) && 1468145247Sdamien (m0 = m_pullup(m0, sizeof (struct ether_header))) == NULL) 1469145247Sdamien continue; 1470145247Sdamien 1471145247Sdamien eh = mtod(m0, struct ether_header *); 1472145247Sdamien ni = ieee80211_find_txnode(ic, eh->ether_dhost); 1473145247Sdamien if (ni == NULL) { 1474145247Sdamien m_freem(m0); 1475145247Sdamien continue; 1476145247Sdamien } 1477145247Sdamien BPF_MTAP(ifp, m0); 1478145247Sdamien 1479145247Sdamien m0 = ieee80211_encap(ic, m0, ni); 1480147834Ssam if (m0 == NULL) { 1481147834Ssam ieee80211_free_node(ni); 1482145247Sdamien continue; 1483147834Ssam } 1484145247Sdamien 1485145247Sdamien if (ic->ic_rawbpf != NULL) 1486145247Sdamien bpf_mtap(ic->ic_rawbpf, m0); 1487145247Sdamien 1488145247Sdamien if (iwi_tx_start(ifp, m0, ni) != 0) { 1489145247Sdamien ieee80211_free_node(ni); 1490145247Sdamien ifp->if_oerrors++; 1491145247Sdamien break; 1492145247Sdamien } 1493145247Sdamien 1494145247Sdamien sc->sc_tx_timer = 5; 1495145247Sdamien ifp->if_timer = 1; 1496145247Sdamien } 1497145247Sdamien 1498145247Sdamien IWI_UNLOCK(sc); 1499145247Sdamien} 1500145247Sdamien 1501145247Sdamienstatic void 1502145247Sdamieniwi_watchdog(struct ifnet *ifp) 1503145247Sdamien{ 1504145247Sdamien struct iwi_softc *sc = ifp->if_softc; 1505145247Sdamien struct ieee80211com *ic = &sc->sc_ic; 1506145247Sdamien 1507145247Sdamien IWI_LOCK(sc); 1508145247Sdamien 1509145247Sdamien ifp->if_timer = 0; 1510145247Sdamien 1511145247Sdamien if (sc->sc_tx_timer > 0) { 1512145247Sdamien if (--sc->sc_tx_timer == 0) { 1513145247Sdamien if_printf(ifp, "device timeout\n"); 1514145247Sdamien ifp->if_oerrors++; 1515145247Sdamien ifp->if_flags &= ~IFF_UP; 1516145247Sdamien iwi_stop(sc); 1517145247Sdamien IWI_UNLOCK(sc); 1518145247Sdamien return; 1519145247Sdamien } 1520145247Sdamien ifp->if_timer = 1; 1521145247Sdamien } 1522145247Sdamien 1523145247Sdamien ieee80211_watchdog(ic); 1524145247Sdamien 1525145247Sdamien IWI_UNLOCK(sc); 1526145247Sdamien} 1527145247Sdamien 1528145247Sdamienstatic int 1529145247Sdamieniwi_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data) 1530145247Sdamien{ 1531145247Sdamien struct iwi_softc *sc = ifp->if_softc; 1532145247Sdamien struct ieee80211com *ic = &sc->sc_ic; 1533145247Sdamien struct ifreq *ifr; 1534145247Sdamien int error = 0; 1535145247Sdamien 1536145247Sdamien IWI_LOCK(sc); 1537145247Sdamien 1538145247Sdamien switch (cmd) { 1539145247Sdamien case SIOCSIFFLAGS: 1540145247Sdamien if (ifp->if_flags & IFF_UP) { 1541148887Srwatson if (!(ifp->if_drv_flags & IFF_DRV_RUNNING)) 1542145247Sdamien iwi_init(sc); 1543145247Sdamien } else { 1544148887Srwatson if (ifp->if_drv_flags & IFF_DRV_RUNNING) 1545145247Sdamien iwi_stop(sc); 1546145247Sdamien } 1547145247Sdamien break; 1548145247Sdamien 1549145247Sdamien case SIOCSLOADFW: 1550145247Sdamien /* only super-user can do that! */ 1551145247Sdamien if ((error = suser(curthread)) != 0) 1552145247Sdamien break; 1553145247Sdamien 1554145247Sdamien ifr = (struct ifreq *)data; 1555145247Sdamien error = iwi_cache_firmware(sc, ifr->ifr_data); 1556145247Sdamien break; 1557145247Sdamien 1558145247Sdamien case SIOCSKILLFW: 1559145247Sdamien /* only super-user can do that! */ 1560145247Sdamien if ((error = suser(curthread)) != 0) 1561145247Sdamien break; 1562145247Sdamien 1563145247Sdamien ifp->if_flags &= ~IFF_UP; 1564145247Sdamien iwi_stop(sc); 1565145247Sdamien iwi_free_firmware(sc); 1566145247Sdamien break; 1567145247Sdamien 1568145247Sdamien default: 1569145247Sdamien error = ieee80211_ioctl(ic, cmd, data); 1570145247Sdamien } 1571145247Sdamien 1572145247Sdamien if (error == ENETRESET) { 1573148887Srwatson if ((ifp->if_flags & IFF_UP) && 1574148887Srwatson (ifp->if_drv_flags & IFF_DRV_RUNNING)) 1575145247Sdamien iwi_init(sc); 1576145247Sdamien error = 0; 1577145247Sdamien } 1578145247Sdamien 1579145247Sdamien IWI_UNLOCK(sc); 1580145247Sdamien 1581145247Sdamien return error; 1582145247Sdamien} 1583145247Sdamien 1584145247Sdamienstatic void 1585145247Sdamieniwi_stop_master(struct iwi_softc *sc) 1586145247Sdamien{ 1587145247Sdamien uint32_t tmp; 1588145247Sdamien int ntries; 1589145247Sdamien 1590145247Sdamien /* disable interrupts */ 1591145247Sdamien CSR_WRITE_4(sc, IWI_CSR_INTR_MASK, 0); 1592145247Sdamien 1593145247Sdamien CSR_WRITE_4(sc, IWI_CSR_RST, IWI_RST_STOP_MASTER); 1594145247Sdamien for (ntries = 0; ntries < 5; ntries++) { 1595145247Sdamien if (CSR_READ_4(sc, IWI_CSR_RST) & IWI_RST_MASTER_DISABLED) 1596145247Sdamien break; 1597145247Sdamien DELAY(10); 1598145247Sdamien } 1599145247Sdamien if (ntries == 5) 1600145247Sdamien device_printf(sc->sc_dev, "timeout waiting for master\n"); 1601145247Sdamien 1602145247Sdamien tmp = CSR_READ_4(sc, IWI_CSR_RST); 1603145247Sdamien CSR_WRITE_4(sc, IWI_CSR_RST, tmp | IWI_RST_PRINCETON_RESET); 1604145247Sdamien 1605145247Sdamien sc->flags &= ~IWI_FLAG_FW_INITED; 1606145247Sdamien} 1607145247Sdamien 1608145247Sdamienstatic int 1609145247Sdamieniwi_reset(struct iwi_softc *sc) 1610145247Sdamien{ 1611145247Sdamien uint32_t tmp; 1612145247Sdamien int i, ntries; 1613145247Sdamien 1614145247Sdamien iwi_stop_master(sc); 1615145247Sdamien 1616145247Sdamien tmp = CSR_READ_4(sc, IWI_CSR_CTL); 1617145247Sdamien CSR_WRITE_4(sc, IWI_CSR_CTL, tmp | IWI_CTL_INIT); 1618145247Sdamien 1619145247Sdamien CSR_WRITE_4(sc, IWI_CSR_READ_INT, IWI_READ_INT_INIT_HOST); 1620145247Sdamien 1621145247Sdamien /* wait for clock stabilization */ 1622145247Sdamien for (ntries = 0; ntries < 1000; ntries++) { 1623145247Sdamien if (CSR_READ_4(sc, IWI_CSR_CTL) & IWI_CTL_CLOCK_READY) 1624145247Sdamien break; 1625145247Sdamien DELAY(200); 1626145247Sdamien } 1627145247Sdamien if (ntries == 1000) { 1628145247Sdamien device_printf(sc->sc_dev, 1629145247Sdamien "timeout waiting for clock stabilization\n"); 1630145247Sdamien return EIO; 1631145247Sdamien } 1632145247Sdamien 1633145247Sdamien tmp = CSR_READ_4(sc, IWI_CSR_RST); 1634145247Sdamien CSR_WRITE_4(sc, IWI_CSR_RST, tmp | IWI_RST_SOFT_RESET); 1635145247Sdamien 1636145247Sdamien DELAY(10); 1637145247Sdamien 1638145247Sdamien tmp = CSR_READ_4(sc, IWI_CSR_CTL); 1639145247Sdamien CSR_WRITE_4(sc, IWI_CSR_CTL, tmp | IWI_CTL_INIT); 1640145247Sdamien 1641145247Sdamien /* clear NIC memory */ 1642145247Sdamien CSR_WRITE_4(sc, IWI_CSR_AUTOINC_ADDR, 0); 1643145247Sdamien for (i = 0; i < 0xc000; i++) 1644145247Sdamien CSR_WRITE_4(sc, IWI_CSR_AUTOINC_DATA, 0); 1645145247Sdamien 1646145247Sdamien return 0; 1647145247Sdamien} 1648145247Sdamien 1649145247Sdamienstatic int 1650145247Sdamieniwi_load_ucode(struct iwi_softc *sc, void *uc, int size) 1651145247Sdamien{ 1652145247Sdamien uint32_t tmp; 1653145247Sdamien uint16_t *w; 1654145247Sdamien int ntries, i; 1655145247Sdamien 1656145247Sdamien CSR_WRITE_4(sc, IWI_CSR_RST, CSR_READ_4(sc, IWI_CSR_RST) | 1657145247Sdamien IWI_RST_STOP_MASTER); 1658145247Sdamien for (ntries = 0; ntries < 5; ntries++) { 1659145247Sdamien if (CSR_READ_4(sc, IWI_CSR_RST) & IWI_RST_MASTER_DISABLED) 1660145247Sdamien break; 1661145247Sdamien DELAY(10); 1662145247Sdamien } 1663145247Sdamien if (ntries == 5) { 1664145247Sdamien device_printf(sc->sc_dev, "timeout waiting for master\n"); 1665145247Sdamien return EIO; 1666145247Sdamien } 1667145247Sdamien 1668145247Sdamien MEM_WRITE_4(sc, 0x3000e0, 0x80000000); 1669145247Sdamien DELAY(5000); 1670145247Sdamien 1671145247Sdamien tmp = CSR_READ_4(sc, IWI_CSR_RST); 1672145247Sdamien tmp &= ~IWI_RST_PRINCETON_RESET; 1673145247Sdamien CSR_WRITE_4(sc, IWI_CSR_RST, tmp); 1674145247Sdamien 1675145247Sdamien DELAY(5000); 1676145247Sdamien MEM_WRITE_4(sc, 0x3000e0, 0); 1677145247Sdamien DELAY(1000); 1678145247Sdamien MEM_WRITE_4(sc, 0x300004, 1); 1679145247Sdamien DELAY(1000); 1680145247Sdamien MEM_WRITE_4(sc, 0x300004, 0); 1681145247Sdamien DELAY(1000); 1682145247Sdamien MEM_WRITE_1(sc, 0x200000, 0x00); 1683145247Sdamien MEM_WRITE_1(sc, 0x200000, 0x40); 1684145247Sdamien DELAY(1000); 1685145247Sdamien 1686145247Sdamien /* write microcode into adapter memory */ 1687145247Sdamien for (w = uc; size > 0; w++, size -= 2) 1688145247Sdamien MEM_WRITE_2(sc, 0x200010, *w); 1689145247Sdamien 1690145247Sdamien MEM_WRITE_1(sc, 0x200000, 0x00); 1691145247Sdamien MEM_WRITE_1(sc, 0x200000, 0x80); 1692145247Sdamien 1693145247Sdamien /* wait until we get an answer */ 1694145247Sdamien for (ntries = 0; ntries < 100; ntries++) { 1695145247Sdamien if (MEM_READ_1(sc, 0x200000) & 1) 1696145247Sdamien break; 1697145247Sdamien DELAY(100); 1698145247Sdamien } 1699145247Sdamien if (ntries == 100) { 1700145247Sdamien device_printf(sc->sc_dev, 1701145247Sdamien "timeout waiting for ucode to initialize\n"); 1702145247Sdamien return EIO; 1703145247Sdamien } 1704145247Sdamien 1705145247Sdamien /* read the answer or the firmware will not initialize properly */ 1706145247Sdamien for (i = 0; i < 7; i++) 1707145247Sdamien MEM_READ_4(sc, 0x200004); 1708145247Sdamien 1709145247Sdamien MEM_WRITE_1(sc, 0x200000, 0x00); 1710145247Sdamien 1711145247Sdamien return 0; 1712145247Sdamien} 1713145247Sdamien 1714145247Sdamien/* macro to handle unaligned little endian data in firmware image */ 1715145247Sdamien#define GETLE32(p) ((p)[0] | (p)[1] << 8 | (p)[2] << 16 | (p)[3] << 24) 1716145247Sdamien 1717145247Sdamienstatic int 1718145247Sdamieniwi_load_firmware(struct iwi_softc *sc, void *fw, int size) 1719145247Sdamien{ 1720145247Sdamien bus_dma_tag_t dmat; 1721145247Sdamien bus_dmamap_t map; 1722145247Sdamien bus_addr_t physaddr; 1723145247Sdamien void *virtaddr; 1724145247Sdamien u_char *p, *end; 1725145247Sdamien uint32_t sentinel, ctl, src, dst, sum, len, mlen, tmp; 1726145247Sdamien int ntries, error = 0; 1727145247Sdamien 1728145247Sdamien /* allocate DMA memory for mapping firmware image */ 1729145247Sdamien error = bus_dma_tag_create(NULL, 4, 0, BUS_SPACE_MAXADDR_32BIT, 1730145247Sdamien BUS_SPACE_MAXADDR, NULL, NULL, size, 1, size, 0, NULL, NULL, &dmat); 1731145247Sdamien if (error != 0) { 1732145247Sdamien device_printf(sc->sc_dev, 1733145247Sdamien "could not create firmware DMA tag\n"); 1734145247Sdamien goto fail1; 1735145247Sdamien } 1736145247Sdamien 1737145247Sdamien error = bus_dmamem_alloc(dmat, &virtaddr, BUS_DMA_NOWAIT, &map); 1738145247Sdamien if (error != 0) { 1739145247Sdamien device_printf(sc->sc_dev, 1740145247Sdamien "could not allocate firmware DMA memory\n"); 1741145247Sdamien goto fail2; 1742145247Sdamien } 1743145247Sdamien 1744145247Sdamien error = bus_dmamap_load(dmat, map, virtaddr, size, iwi_dma_map_addr, 1745145247Sdamien &physaddr, 0); 1746145247Sdamien if (error != 0) { 1747145247Sdamien device_printf(sc->sc_dev, "could not load firmware DMA map\n"); 1748145247Sdamien goto fail3; 1749145247Sdamien } 1750145247Sdamien 1751145247Sdamien /* copy firmware image to DMA memory */ 1752145247Sdamien memcpy(virtaddr, fw, size); 1753145247Sdamien 1754145247Sdamien /* make sure the adapter will get up-to-date values */ 1755145247Sdamien bus_dmamap_sync(dmat, map, BUS_DMASYNC_PREWRITE); 1756145247Sdamien 1757145247Sdamien /* tell the adapter where the command blocks are stored */ 1758145247Sdamien MEM_WRITE_4(sc, 0x3000a0, 0x27000); 1759145247Sdamien 1760145247Sdamien /* 1761145247Sdamien * Store command blocks into adapter's internal memory using register 1762145247Sdamien * indirections. The adapter will read the firmware image through DMA 1763145247Sdamien * using information stored in command blocks. 1764145247Sdamien */ 1765145247Sdamien src = physaddr; 1766145247Sdamien p = virtaddr; 1767145247Sdamien end = p + size; 1768145247Sdamien CSR_WRITE_4(sc, IWI_CSR_AUTOINC_ADDR, 0x27000); 1769145247Sdamien 1770145247Sdamien while (p < end) { 1771145247Sdamien dst = GETLE32(p); p += 4; src += 4; 1772145247Sdamien len = GETLE32(p); p += 4; src += 4; 1773145247Sdamien p += len; 1774145247Sdamien 1775145247Sdamien while (len > 0) { 1776145247Sdamien mlen = min(len, IWI_CB_MAXDATALEN); 1777145247Sdamien 1778145247Sdamien ctl = IWI_CB_DEFAULT_CTL | mlen; 1779145247Sdamien sum = ctl ^ src ^ dst; 1780145247Sdamien 1781145247Sdamien /* write a command block */ 1782145247Sdamien CSR_WRITE_4(sc, IWI_CSR_AUTOINC_DATA, ctl); 1783145247Sdamien CSR_WRITE_4(sc, IWI_CSR_AUTOINC_DATA, src); 1784145247Sdamien CSR_WRITE_4(sc, IWI_CSR_AUTOINC_DATA, dst); 1785145247Sdamien CSR_WRITE_4(sc, IWI_CSR_AUTOINC_DATA, sum); 1786145247Sdamien 1787145247Sdamien src += mlen; 1788145247Sdamien dst += mlen; 1789145247Sdamien len -= mlen; 1790145247Sdamien } 1791145247Sdamien } 1792145247Sdamien 1793145247Sdamien /* write a fictive final command block (sentinel) */ 1794145247Sdamien sentinel = CSR_READ_4(sc, IWI_CSR_AUTOINC_ADDR); 1795145247Sdamien CSR_WRITE_4(sc, IWI_CSR_AUTOINC_DATA, 0); 1796145247Sdamien 1797145247Sdamien tmp = CSR_READ_4(sc, IWI_CSR_RST); 1798145247Sdamien tmp &= ~(IWI_RST_MASTER_DISABLED | IWI_RST_STOP_MASTER); 1799145247Sdamien CSR_WRITE_4(sc, IWI_CSR_RST, tmp); 1800145247Sdamien 1801145247Sdamien /* tell the adapter to start processing command blocks */ 1802145247Sdamien MEM_WRITE_4(sc, 0x3000a4, 0x540100); 1803145247Sdamien 1804145247Sdamien /* wait until the adapter reach the sentinel */ 1805145247Sdamien for (ntries = 0; ntries < 400; ntries++) { 1806145247Sdamien if (MEM_READ_4(sc, 0x3000d0) >= sentinel) 1807145247Sdamien break; 1808145247Sdamien DELAY(100); 1809145247Sdamien } 1810145247Sdamien if (ntries == 400) { 1811145247Sdamien device_printf(sc->sc_dev, 1812145247Sdamien "timeout processing command blocks\n"); 1813145247Sdamien error = EIO; 1814145247Sdamien goto fail4; 1815145247Sdamien } 1816145247Sdamien 1817145247Sdamien /* we're done with command blocks processing */ 1818145247Sdamien MEM_WRITE_4(sc, 0x3000a4, 0x540c00); 1819145247Sdamien 1820145247Sdamien /* allow interrupts so we know when the firmware is inited */ 1821145247Sdamien CSR_WRITE_4(sc, IWI_CSR_INTR_MASK, IWI_INTR_MASK); 1822145247Sdamien 1823145247Sdamien /* tell the adapter to initialize the firmware */ 1824145247Sdamien CSR_WRITE_4(sc, IWI_CSR_RST, 0); 1825145247Sdamien 1826145247Sdamien tmp = CSR_READ_4(sc, IWI_CSR_CTL); 1827145247Sdamien CSR_WRITE_4(sc, IWI_CSR_CTL, tmp | IWI_CTL_ALLOW_STANDBY); 1828145247Sdamien 1829145247Sdamien /* wait at most one second for firmware initialization to complete */ 1830145247Sdamien if ((error = msleep(sc, &sc->sc_mtx, 0, "iwiinit", hz)) != 0) { 1831145247Sdamien device_printf(sc->sc_dev, "timeout waiting for firmware " 1832145247Sdamien "initialization to complete\n"); 1833145247Sdamien goto fail4; 1834145247Sdamien } 1835145247Sdamien 1836145247Sdamienfail4: bus_dmamap_sync(dmat, map, BUS_DMASYNC_POSTWRITE); 1837145247Sdamien bus_dmamap_unload(dmat, map); 1838145247Sdamienfail3: bus_dmamem_free(dmat, virtaddr, map); 1839145247Sdamienfail2: bus_dma_tag_destroy(dmat); 1840145247Sdamienfail1: 1841145247Sdamien return error; 1842145247Sdamien} 1843145247Sdamien 1844145247Sdamien/* 1845145247Sdamien * Store firmware into kernel memory so we can download it when we need to, 1846145247Sdamien * e.g when the adapter wakes up from suspend mode. 1847145247Sdamien */ 1848145247Sdamienstatic int 1849145247Sdamieniwi_cache_firmware(struct iwi_softc *sc, void *data) 1850145247Sdamien{ 1851145247Sdamien struct iwi_firmware *kfw = &sc->fw; 1852145247Sdamien struct iwi_firmware ufw; 1853145247Sdamien int error; 1854145247Sdamien 1855145247Sdamien iwi_free_firmware(sc); 1856145247Sdamien 1857145247Sdamien IWI_UNLOCK(sc); 1858145247Sdamien 1859145247Sdamien if ((error = copyin(data, &ufw, sizeof ufw)) != 0) 1860145247Sdamien goto fail1; 1861145247Sdamien 1862145247Sdamien kfw->boot_size = ufw.boot_size; 1863145247Sdamien kfw->ucode_size = ufw.ucode_size; 1864145247Sdamien kfw->main_size = ufw.main_size; 1865145247Sdamien 1866145247Sdamien kfw->boot = malloc(kfw->boot_size, M_DEVBUF, M_NOWAIT); 1867145247Sdamien if (kfw->boot == NULL) { 1868145247Sdamien error = ENOMEM; 1869145247Sdamien goto fail1; 1870145247Sdamien } 1871145247Sdamien 1872145247Sdamien kfw->ucode = malloc(kfw->ucode_size, M_DEVBUF, M_NOWAIT); 1873145247Sdamien if (kfw->ucode == NULL) { 1874145247Sdamien error = ENOMEM; 1875145247Sdamien goto fail2; 1876145247Sdamien } 1877145247Sdamien 1878145247Sdamien kfw->main = malloc(kfw->main_size, M_DEVBUF, M_NOWAIT); 1879145247Sdamien if (kfw->main == NULL) { 1880145247Sdamien error = ENOMEM; 1881145247Sdamien goto fail3; 1882145247Sdamien } 1883145247Sdamien 1884145247Sdamien if ((error = copyin(ufw.boot, kfw->boot, kfw->boot_size)) != 0) 1885145247Sdamien goto fail4; 1886145247Sdamien 1887145247Sdamien if ((error = copyin(ufw.ucode, kfw->ucode, kfw->ucode_size)) != 0) 1888145247Sdamien goto fail4; 1889145247Sdamien 1890145247Sdamien if ((error = copyin(ufw.main, kfw->main, kfw->main_size)) != 0) 1891145247Sdamien goto fail4; 1892145247Sdamien 1893145247Sdamien DPRINTF(("Firmware cached: boot %u, ucode %u, main %u\n", 1894145247Sdamien kfw->boot_size, kfw->ucode_size, kfw->main_size)); 1895145247Sdamien 1896145247Sdamien IWI_LOCK(sc); 1897145247Sdamien 1898145247Sdamien sc->flags |= IWI_FLAG_FW_CACHED; 1899145247Sdamien 1900145247Sdamien return 0; 1901145247Sdamien 1902145247Sdamienfail4: free(kfw->boot, M_DEVBUF); 1903145247Sdamienfail3: free(kfw->ucode, M_DEVBUF); 1904145247Sdamienfail2: free(kfw->main, M_DEVBUF); 1905145247Sdamienfail1: IWI_LOCK(sc); 1906145247Sdamien 1907145247Sdamien return error; 1908145247Sdamien} 1909145247Sdamien 1910145247Sdamienstatic void 1911145247Sdamieniwi_free_firmware(struct iwi_softc *sc) 1912145247Sdamien{ 1913145247Sdamien if (!(sc->flags & IWI_FLAG_FW_CACHED)) 1914145247Sdamien return; 1915145247Sdamien 1916145247Sdamien free(sc->fw.boot, M_DEVBUF); 1917145247Sdamien free(sc->fw.ucode, M_DEVBUF); 1918145247Sdamien free(sc->fw.main, M_DEVBUF); 1919145247Sdamien 1920145247Sdamien sc->flags &= ~IWI_FLAG_FW_CACHED; 1921145247Sdamien} 1922145247Sdamien 1923145247Sdamienstatic int 1924145247Sdamieniwi_config(struct iwi_softc *sc) 1925145247Sdamien{ 1926145247Sdamien struct ieee80211com *ic = &sc->sc_ic; 1927145247Sdamien struct ifnet *ifp = ic->ic_ifp; 1928145247Sdamien struct iwi_configuration config; 1929145247Sdamien struct iwi_rateset rs; 1930145247Sdamien struct iwi_txpower power; 1931145247Sdamien struct ieee80211_key *wk; 1932145247Sdamien struct iwi_wep_key wepkey; 1933145247Sdamien uint32_t data; 1934145247Sdamien int error, i; 1935145247Sdamien 1936145247Sdamien IEEE80211_ADDR_COPY(ic->ic_myaddr, IF_LLADDR(ifp)); 1937145247Sdamien DPRINTF(("Setting MAC address to %6D\n", ic->ic_myaddr, ":")); 1938145247Sdamien error = iwi_cmd(sc, IWI_CMD_SET_MAC_ADDRESS, ic->ic_myaddr, 1939145247Sdamien IEEE80211_ADDR_LEN, 0); 1940145247Sdamien if (error != 0) 1941145247Sdamien return error; 1942145247Sdamien 1943145247Sdamien memset(&config, 0, sizeof config); 1944145247Sdamien config.bluetooth_coexistence = sc->bluetooth; 1945146500Sdamien config.antenna = sc->antenna; 1946145247Sdamien config.multicast_enabled = 1; 1947146500Sdamien config.answer_pbreq = (ic->ic_opmode == IEEE80211_M_IBSS) ? 1 : 0; 1948146500Sdamien config.disable_unicast_decryption = 1; 1949146500Sdamien config.disable_multicast_decryption = 1; 1950145247Sdamien DPRINTF(("Configuring adapter\n")); 1951145247Sdamien error = iwi_cmd(sc, IWI_CMD_SET_CONFIG, &config, sizeof config, 0); 1952145247Sdamien if (error != 0) 1953145247Sdamien return error; 1954145247Sdamien 1955145247Sdamien data = htole32(IWI_POWER_MODE_CAM); 1956145247Sdamien DPRINTF(("Setting power mode to %u\n", le32toh(data))); 1957145247Sdamien error = iwi_cmd(sc, IWI_CMD_SET_POWER_MODE, &data, sizeof data, 0); 1958145247Sdamien if (error != 0) 1959145247Sdamien return error; 1960145247Sdamien 1961145247Sdamien data = htole32(ic->ic_rtsthreshold); 1962145247Sdamien DPRINTF(("Setting RTS threshold to %u\n", le32toh(data))); 1963145247Sdamien error = iwi_cmd(sc, IWI_CMD_SET_RTS_THRESHOLD, &data, sizeof data, 0); 1964145247Sdamien if (error != 0) 1965145247Sdamien return error; 1966145247Sdamien 1967146500Sdamien data = htole32(ic->ic_fragthreshold); 1968146500Sdamien DPRINTF(("Setting fragmentation threshold to %u\n", le32toh(data))); 1969146500Sdamien error = iwi_cmd(sc, IWI_CMD_SET_FRAG_THRESHOLD, &data, sizeof data, 0); 1970146500Sdamien if (error != 0) 1971146500Sdamien return error; 1972146500Sdamien 1973145247Sdamien if (ic->ic_opmode == IEEE80211_M_IBSS) { 1974145247Sdamien power.mode = IWI_MODE_11B; 1975145247Sdamien power.nchan = 11; 1976145247Sdamien for (i = 0; i < 11; i++) { 1977145247Sdamien power.chan[i].chan = i + 1; 1978145247Sdamien power.chan[i].power = IWI_TXPOWER_MAX; 1979145247Sdamien } 1980145247Sdamien DPRINTF(("Setting .11b channels tx power\n")); 1981145247Sdamien error = iwi_cmd(sc, IWI_CMD_SET_TX_POWER, &power, sizeof power, 1982145247Sdamien 0); 1983145247Sdamien if (error != 0) 1984145247Sdamien return error; 1985145247Sdamien 1986145247Sdamien power.mode = IWI_MODE_11G; 1987145247Sdamien DPRINTF(("Setting .11g channels tx power\n")); 1988145247Sdamien error = iwi_cmd(sc, IWI_CMD_SET_TX_POWER, &power, sizeof power, 1989145247Sdamien 0); 1990145247Sdamien if (error != 0) 1991145247Sdamien return error; 1992145247Sdamien } 1993145247Sdamien 1994145247Sdamien rs.mode = IWI_MODE_11G; 1995145247Sdamien rs.type = IWI_RATESET_TYPE_SUPPORTED; 1996145247Sdamien rs.nrates = ic->ic_sup_rates[IEEE80211_MODE_11G].rs_nrates; 1997145247Sdamien memcpy(rs.rates, ic->ic_sup_rates[IEEE80211_MODE_11G].rs_rates, 1998145247Sdamien rs.nrates); 1999145247Sdamien DPRINTF(("Setting .11bg supported rates (%u)\n", rs.nrates)); 2000145247Sdamien error = iwi_cmd(sc, IWI_CMD_SET_RATES, &rs, sizeof rs, 0); 2001145247Sdamien if (error != 0) 2002145247Sdamien return error; 2003145247Sdamien 2004145247Sdamien rs.mode = IWI_MODE_11A; 2005145247Sdamien rs.type = IWI_RATESET_TYPE_SUPPORTED; 2006145247Sdamien rs.nrates = ic->ic_sup_rates[IEEE80211_MODE_11A].rs_nrates; 2007145247Sdamien memcpy(rs.rates, ic->ic_sup_rates[IEEE80211_MODE_11A].rs_rates, 2008145247Sdamien rs.nrates); 2009145247Sdamien DPRINTF(("Setting .11a supported rates (%u)\n", rs.nrates)); 2010145247Sdamien error = iwi_cmd(sc, IWI_CMD_SET_RATES, &rs, sizeof rs, 0); 2011145247Sdamien if (error != 0) 2012145247Sdamien return error; 2013145247Sdamien 2014145247Sdamien data = htole32(arc4random()); 2015145247Sdamien DPRINTF(("Setting initialization vector to %u\n", le32toh(data))); 2016145247Sdamien error = iwi_cmd(sc, IWI_CMD_SET_IV, &data, sizeof data, 0); 2017145247Sdamien if (error != 0) 2018145247Sdamien return error; 2019145247Sdamien 2020145247Sdamien for (i = 0; i < IEEE80211_WEP_NKID; i++) { 2021145247Sdamien wk = &ic->ic_crypto.cs_nw_keys[i]; 2022145247Sdamien 2023145247Sdamien wepkey.cmd = IWI_WEP_KEY_CMD_SETKEY; 2024145247Sdamien wepkey.idx = i; 2025145247Sdamien wepkey.len = wk->wk_keylen; 2026145247Sdamien memset(wepkey.key, 0, sizeof wepkey.key); 2027145247Sdamien memcpy(wepkey.key, wk->wk_key, wk->wk_keylen); 2028145247Sdamien DPRINTF(("Setting wep key index %u len %u\n", wepkey.idx, 2029145247Sdamien wepkey.len)); 2030145247Sdamien error = iwi_cmd(sc, IWI_CMD_SET_WEP_KEY, &wepkey, 2031145247Sdamien sizeof wepkey, 0); 2032145247Sdamien if (error != 0) 2033145247Sdamien return error; 2034145247Sdamien } 2035145247Sdamien 2036145247Sdamien /* enable adapter */ 2037145247Sdamien DPRINTF(("Enabling adapter\n")); 2038145247Sdamien return iwi_cmd(sc, IWI_CMD_ENABLE, NULL, 0, 0); 2039145247Sdamien} 2040145247Sdamien 2041145247Sdamienstatic int 2042146500Sdamieniwi_set_chan(struct iwi_softc *sc, struct ieee80211_channel *chan) 2043146500Sdamien{ 2044146500Sdamien struct ieee80211com *ic = &sc->sc_ic; 2045146500Sdamien struct iwi_scan scan; 2046146500Sdamien 2047146500Sdamien memset(&scan, 0, sizeof scan); 2048146500Sdamien scan.type = IWI_SCAN_TYPE_PASSIVE; 2049146500Sdamien scan.dwelltime = htole16(2000); 2050146500Sdamien scan.channels[0] = 1 | (IEEE80211_IS_CHAN_5GHZ(chan) ? IWI_CHAN_5GHZ : 2051146500Sdamien IWI_CHAN_2GHZ); 2052146500Sdamien scan.channels[1] = ieee80211_chan2ieee(ic, chan); 2053146500Sdamien 2054146500Sdamien DPRINTF(("Setting channel to %u\n", ieee80211_chan2ieee(ic, chan))); 2055146500Sdamien return iwi_cmd(sc, IWI_CMD_SCAN, &scan, sizeof scan, 1); 2056146500Sdamien} 2057146500Sdamien 2058146500Sdamienstatic int 2059145247Sdamieniwi_scan(struct iwi_softc *sc) 2060145247Sdamien{ 2061145247Sdamien struct ieee80211com *ic = &sc->sc_ic; 2062145247Sdamien struct iwi_scan scan; 2063145247Sdamien uint8_t *p; 2064145247Sdamien int i, count; 2065145247Sdamien 2066145247Sdamien memset(&scan, 0, sizeof scan); 2067145247Sdamien scan.type = IWI_SCAN_TYPE_BROADCAST; 2068146500Sdamien scan.dwelltime = htole16(sc->dwelltime); 2069145247Sdamien 2070145247Sdamien p = scan.channels; 2071145247Sdamien count = 0; 2072145247Sdamien for (i = 0; i <= IEEE80211_CHAN_MAX; i++) { 2073145247Sdamien if (IEEE80211_IS_CHAN_5GHZ(&ic->ic_channels[i]) && 2074145247Sdamien isset(ic->ic_chan_active, i)) { 2075145247Sdamien *++p = i; 2076145247Sdamien count++; 2077145247Sdamien } 2078145247Sdamien } 2079145247Sdamien *(p - count) = IWI_CHAN_5GHZ | count; 2080145247Sdamien 2081145247Sdamien count = 0; 2082145247Sdamien for (i = 0; i <= IEEE80211_CHAN_MAX; i++) { 2083145247Sdamien if (IEEE80211_IS_CHAN_2GHZ(&ic->ic_channels[i]) && 2084145247Sdamien isset(ic->ic_chan_active, i)) { 2085145247Sdamien *++p = i; 2086145247Sdamien count++; 2087145247Sdamien } 2088145247Sdamien } 2089145247Sdamien *(p - count) = IWI_CHAN_2GHZ | count; 2090145247Sdamien 2091145247Sdamien DPRINTF(("Start scanning\n")); 2092145247Sdamien return iwi_cmd(sc, IWI_CMD_SCAN, &scan, sizeof scan, 1); 2093145247Sdamien} 2094145247Sdamien 2095145247Sdamienstatic int 2096145247Sdamieniwi_auth_and_assoc(struct iwi_softc *sc) 2097145247Sdamien{ 2098145247Sdamien struct ieee80211com *ic = &sc->sc_ic; 2099145247Sdamien struct ifnet *ifp = ic->ic_ifp; 2100145247Sdamien struct ieee80211_node *ni = ic->ic_bss; 2101145247Sdamien struct iwi_configuration config; 2102145247Sdamien struct iwi_associate assoc; 2103145247Sdamien struct iwi_rateset rs; 2104146500Sdamien uint16_t capinfo; 2105145247Sdamien uint32_t data; 2106145247Sdamien int error; 2107145247Sdamien 2108145247Sdamien if (IEEE80211_IS_CHAN_2GHZ(ni->ni_chan)) { 2109145247Sdamien memset(&config, 0, sizeof config); 2110145247Sdamien config.bluetooth_coexistence = sc->bluetooth; 2111146500Sdamien config.antenna = sc->antenna; 2112145247Sdamien config.multicast_enabled = 1; 2113145247Sdamien config.use_protection = 1; 2114146500Sdamien config.answer_pbreq = 2115146500Sdamien (ic->ic_opmode == IEEE80211_M_IBSS) ? 1 : 0; 2116146500Sdamien config.disable_unicast_decryption = 1; 2117146500Sdamien config.disable_multicast_decryption = 1; 2118145247Sdamien DPRINTF(("Configuring adapter\n")); 2119145247Sdamien error = iwi_cmd(sc, IWI_CMD_SET_CONFIG, &config, sizeof config, 2120145247Sdamien 1); 2121145247Sdamien if (error != 0) 2122145247Sdamien return error; 2123145247Sdamien } 2124145247Sdamien 2125145247Sdamien#ifdef IWI_DEBUG 2126145247Sdamien if (iwi_debug > 0) { 2127145247Sdamien printf("Setting ESSID to "); 2128145247Sdamien ieee80211_print_essid(ni->ni_essid, ni->ni_esslen); 2129145247Sdamien printf("\n"); 2130145247Sdamien } 2131145247Sdamien#endif 2132145247Sdamien error = iwi_cmd(sc, IWI_CMD_SET_ESSID, ni->ni_essid, ni->ni_esslen, 1); 2133145247Sdamien if (error != 0) 2134145247Sdamien return error; 2135145247Sdamien 2136145247Sdamien /* the rate set has already been "negociated" */ 2137145247Sdamien rs.mode = IEEE80211_IS_CHAN_5GHZ(ni->ni_chan) ? IWI_MODE_11A : 2138145247Sdamien IWI_MODE_11G; 2139145247Sdamien rs.type = IWI_RATESET_TYPE_NEGOCIATED; 2140145247Sdamien rs.nrates = ni->ni_rates.rs_nrates; 2141145247Sdamien memcpy(rs.rates, ni->ni_rates.rs_rates, rs.nrates); 2142145247Sdamien DPRINTF(("Setting negociated rates (%u)\n", rs.nrates)); 2143145247Sdamien error = iwi_cmd(sc, IWI_CMD_SET_RATES, &rs, sizeof rs, 1); 2144145247Sdamien if (error != 0) 2145145247Sdamien return error; 2146145247Sdamien 2147146500Sdamien if (ic->ic_opt_ie != NULL) { 2148146500Sdamien DPRINTF(("Setting optional IE (len=%u)\n", ic->ic_opt_ie_len)); 2149146500Sdamien error = iwi_cmd(sc, IWI_CMD_SET_OPTIE, ic->ic_opt_ie, 2150146500Sdamien ic->ic_opt_ie_len, 1); 2151146500Sdamien if (error != 0) 2152146500Sdamien return error; 2153146500Sdamien } 2154146500Sdamien 2155145247Sdamien data = htole32(ni->ni_rssi); 2156145247Sdamien DPRINTF(("Setting sensitivity to %d\n", (int8_t)ni->ni_rssi)); 2157145247Sdamien error = iwi_cmd(sc, IWI_CMD_SET_SENSITIVITY, &data, sizeof data, 1); 2158145247Sdamien if (error != 0) 2159145247Sdamien return error; 2160145247Sdamien 2161145247Sdamien memset(&assoc, 0, sizeof assoc); 2162145247Sdamien assoc.mode = IEEE80211_IS_CHAN_5GHZ(ni->ni_chan) ? IWI_MODE_11A : 2163145247Sdamien IWI_MODE_11G; 2164145247Sdamien assoc.chan = ieee80211_chan2ieee(ic, ni->ni_chan); 2165145247Sdamien if (ni->ni_authmode == IEEE80211_AUTH_SHARED) 2166145247Sdamien assoc.auth = ic->ic_crypto.cs_def_txkey << 4 | IWI_AUTH_SHARED; 2167146500Sdamien if (ic->ic_opt_ie != NULL) 2168146500Sdamien assoc.policy |= htole16(IWI_POLICY_OPTIE); 2169145247Sdamien memcpy(assoc.tstamp, ni->ni_tstamp.data, 8); 2170146500Sdamien 2171146500Sdamien if (ic->ic_opmode == IEEE80211_M_IBSS) 2172146500Sdamien capinfo = IEEE80211_CAPINFO_IBSS; 2173146500Sdamien else 2174146500Sdamien capinfo = IEEE80211_CAPINFO_ESS; 2175146500Sdamien if (ic->ic_flags & IEEE80211_F_PRIVACY) 2176146500Sdamien capinfo |= IEEE80211_CAPINFO_PRIVACY; 2177146500Sdamien if ((ic->ic_flags & IEEE80211_F_SHPREAMBLE) && 2178146500Sdamien IEEE80211_IS_CHAN_2GHZ(ni->ni_chan)) 2179146500Sdamien capinfo |= IEEE80211_CAPINFO_SHORT_PREAMBLE; 2180146500Sdamien if (ic->ic_flags & IEEE80211_F_SHSLOT) 2181146500Sdamien capinfo |= IEEE80211_CAPINFO_SHORT_SLOTTIME; 2182146500Sdamien assoc.capinfo = htole16(capinfo); 2183146500Sdamien 2184145247Sdamien assoc.lintval = htole16(ic->ic_lintval); 2185145247Sdamien assoc.intval = htole16(ni->ni_intval); 2186145247Sdamien IEEE80211_ADDR_COPY(assoc.bssid, ni->ni_bssid); 2187145247Sdamien if (ic->ic_opmode == IEEE80211_M_IBSS) 2188145247Sdamien IEEE80211_ADDR_COPY(assoc.dst, ifp->if_broadcastaddr); 2189145247Sdamien else 2190145247Sdamien IEEE80211_ADDR_COPY(assoc.dst, ni->ni_bssid); 2191145247Sdamien 2192145247Sdamien DPRINTF(("Trying to associate to %6D channel %u auth %u\n", 2193145247Sdamien assoc.bssid, ":", assoc.chan, assoc.auth)); 2194145247Sdamien return iwi_cmd(sc, IWI_CMD_ASSOCIATE, &assoc, sizeof assoc, 1); 2195145247Sdamien} 2196145247Sdamien 2197145247Sdamienstatic void 2198145247Sdamieniwi_init(void *priv) 2199145247Sdamien{ 2200145247Sdamien struct iwi_softc *sc = priv; 2201145247Sdamien struct ieee80211com *ic = &sc->sc_ic; 2202145247Sdamien struct ifnet *ifp = ic->ic_ifp; 2203145247Sdamien struct iwi_firmware *fw = &sc->fw; 2204145247Sdamien struct iwi_rx_data *data; 2205145247Sdamien int i; 2206145247Sdamien 2207145247Sdamien /* exit immediately if firmware has not been ioctl'd */ 2208145247Sdamien if (!(sc->flags & IWI_FLAG_FW_CACHED)) { 2209146247Simp if (!(sc->flags & IWI_FLAG_FW_WARNED)) 2210146247Simp device_printf(sc->sc_dev, "Please load firmware\n"); 2211146247Simp sc->flags |= IWI_FLAG_FW_WARNED; 2212145247Sdamien ifp->if_flags &= ~IFF_UP; 2213145247Sdamien return; 2214145247Sdamien } 2215145247Sdamien 2216145247Sdamien iwi_stop(sc); 2217145247Sdamien 2218145247Sdamien if (iwi_reset(sc) != 0) { 2219145247Sdamien device_printf(sc->sc_dev, "could not reset adapter\n"); 2220145247Sdamien goto fail; 2221145247Sdamien } 2222145247Sdamien 2223145247Sdamien if (iwi_load_firmware(sc, fw->boot, fw->boot_size) != 0) { 2224145247Sdamien device_printf(sc->sc_dev, "could not load boot firmware\n"); 2225145247Sdamien goto fail; 2226145247Sdamien } 2227145247Sdamien 2228145247Sdamien if (iwi_load_ucode(sc, fw->ucode, fw->ucode_size) != 0) { 2229145247Sdamien device_printf(sc->sc_dev, "could not load microcode\n"); 2230145247Sdamien goto fail; 2231145247Sdamien } 2232145247Sdamien 2233145247Sdamien iwi_stop_master(sc); 2234145247Sdamien 2235145247Sdamien CSR_WRITE_4(sc, IWI_CSR_CMD_BASE, sc->cmdq.physaddr); 2236145247Sdamien CSR_WRITE_4(sc, IWI_CSR_CMD_SIZE, sc->cmdq.count); 2237145247Sdamien CSR_WRITE_4(sc, IWI_CSR_CMD_WIDX, sc->cmdq.cur); 2238145247Sdamien 2239145247Sdamien CSR_WRITE_4(sc, IWI_CSR_TX1_BASE, sc->txq.physaddr); 2240145247Sdamien CSR_WRITE_4(sc, IWI_CSR_TX1_SIZE, sc->txq.count); 2241145247Sdamien CSR_WRITE_4(sc, IWI_CSR_TX1_WIDX, sc->txq.cur); 2242145247Sdamien 2243145247Sdamien CSR_WRITE_4(sc, IWI_CSR_TX2_BASE, sc->txq.physaddr); 2244145247Sdamien CSR_WRITE_4(sc, IWI_CSR_TX2_SIZE, sc->txq.count); 2245145247Sdamien CSR_WRITE_4(sc, IWI_CSR_TX2_WIDX, sc->txq.cur); 2246145247Sdamien 2247145247Sdamien CSR_WRITE_4(sc, IWI_CSR_TX3_BASE, sc->txq.physaddr); 2248145247Sdamien CSR_WRITE_4(sc, IWI_CSR_TX3_SIZE, sc->txq.count); 2249145247Sdamien CSR_WRITE_4(sc, IWI_CSR_TX3_WIDX, sc->txq.cur); 2250145247Sdamien 2251145247Sdamien CSR_WRITE_4(sc, IWI_CSR_TX4_BASE, sc->txq.physaddr); 2252145247Sdamien CSR_WRITE_4(sc, IWI_CSR_TX4_SIZE, sc->txq.count); 2253145247Sdamien CSR_WRITE_4(sc, IWI_CSR_TX4_WIDX, sc->txq.cur); 2254145247Sdamien 2255145247Sdamien for (i = 0; i < sc->rxq.count; i++) { 2256145247Sdamien data = &sc->rxq.data[i]; 2257145247Sdamien CSR_WRITE_4(sc, data->reg, data->physaddr); 2258145247Sdamien } 2259145247Sdamien 2260145247Sdamien CSR_WRITE_4(sc, IWI_CSR_RX_WIDX, sc->rxq.count - 1); 2261145247Sdamien 2262145247Sdamien if (iwi_load_firmware(sc, fw->main, fw->main_size) != 0) { 2263145247Sdamien device_printf(sc->sc_dev, "could not load main firmware\n"); 2264145247Sdamien goto fail; 2265145247Sdamien } 2266145247Sdamien 2267145247Sdamien sc->flags |= IWI_FLAG_FW_INITED; 2268145247Sdamien 2269145247Sdamien if (iwi_config(sc) != 0) { 2270145247Sdamien device_printf(sc->sc_dev, "device configuration failed\n"); 2271145247Sdamien goto fail; 2272145247Sdamien } 2273145247Sdamien 2274146500Sdamien if (ic->ic_opmode == IEEE80211_M_MONITOR) 2275146500Sdamien ieee80211_new_state(ic, IEEE80211_S_RUN, -1); 2276146500Sdamien else 2277146500Sdamien ieee80211_new_state(ic, IEEE80211_S_SCAN, -1); 2278145247Sdamien 2279148887Srwatson ifp->if_drv_flags &= ~IFF_DRV_OACTIVE; 2280148887Srwatson ifp->if_drv_flags |= IFF_DRV_RUNNING; 2281145247Sdamien 2282145247Sdamien return; 2283145247Sdamien 2284145247Sdamienfail: ifp->if_flags &= ~IFF_UP; 2285145247Sdamien iwi_stop(sc); 2286145247Sdamien} 2287145247Sdamien 2288145247Sdamienstatic void 2289145247Sdamieniwi_stop(void *priv) 2290145247Sdamien{ 2291145247Sdamien struct iwi_softc *sc = priv; 2292145247Sdamien struct ieee80211com *ic = &sc->sc_ic; 2293145247Sdamien struct ifnet *ifp = ic->ic_ifp; 2294145247Sdamien 2295145247Sdamien iwi_stop_master(sc); 2296145247Sdamien 2297145247Sdamien CSR_WRITE_4(sc, IWI_CSR_RST, IWI_RST_SOFT_RESET); 2298145247Sdamien 2299145247Sdamien /* reset rings */ 2300145247Sdamien iwi_reset_cmd_ring(sc, &sc->cmdq); 2301145247Sdamien iwi_reset_tx_ring(sc, &sc->txq); 2302145247Sdamien iwi_reset_rx_ring(sc, &sc->rxq); 2303145247Sdamien 2304145247Sdamien sc->sc_tx_timer = 0; 2305145247Sdamien ifp->if_timer = 0; 2306148887Srwatson ifp->if_drv_flags &= ~(IFF_DRV_RUNNING | IFF_DRV_OACTIVE); 2307145247Sdamien 2308145247Sdamien ieee80211_new_state(ic, IEEE80211_S_INIT, -1); 2309145247Sdamien} 2310145247Sdamien 2311145247Sdamien#ifdef IWI_DEBUG 2312145247Sdamienstatic int 2313145247Sdamieniwi_sysctl_stats(SYSCTL_HANDLER_ARGS) 2314145247Sdamien{ 2315145247Sdamien struct iwi_softc *sc = arg1; 2316145247Sdamien uint32_t size, buf[128]; 2317145247Sdamien 2318145247Sdamien if (!(sc->flags & IWI_FLAG_FW_INITED)) { 2319145247Sdamien memset(buf, 0, sizeof buf); 2320145247Sdamien return SYSCTL_OUT(req, buf, sizeof buf); 2321145247Sdamien } 2322145247Sdamien 2323145247Sdamien size = min(CSR_READ_4(sc, IWI_CSR_TABLE0_SIZE), 128 - 1); 2324145247Sdamien CSR_READ_REGION_4(sc, IWI_CSR_TABLE0_BASE, &buf[1], size); 2325145247Sdamien 2326145247Sdamien return SYSCTL_OUT(req, buf, sizeof buf); 2327145247Sdamien} 2328145247Sdamien#endif 2329145247Sdamien 2330145247Sdamienstatic int 2331145247Sdamieniwi_sysctl_radio(SYSCTL_HANDLER_ARGS) 2332145247Sdamien{ 2333145247Sdamien struct iwi_softc *sc = arg1; 2334145247Sdamien int val; 2335145247Sdamien 2336145247Sdamien val = (CSR_READ_4(sc, IWI_CSR_IO) & IWI_IO_RADIO_ENABLED) ? 1 : 0; 2337145247Sdamien 2338145247Sdamien return SYSCTL_OUT(req, &val, sizeof val); 2339145247Sdamien} 2340