1*4128Shx147065 /* 2*4128Shx147065 * Copyright 2007 Sun Microsystems, Inc. All rights reserved. 3*4128Shx147065 * Use is subject to license terms. 4*4128Shx147065 */ 5*4128Shx147065 6*4128Shx147065 /* 7*4128Shx147065 * Copyright (c) 2006 8*4128Shx147065 * Damien Bergamini <damien.bergamini@free.fr> 9*4128Shx147065 * 10*4128Shx147065 * Permission to use, copy, modify, and distribute this software for any 11*4128Shx147065 * purpose with or without fee is hereby granted, provided that the above 12*4128Shx147065 * copyright notice and this permission notice appear in all copies. 13*4128Shx147065 * 14*4128Shx147065 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 15*4128Shx147065 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 16*4128Shx147065 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 17*4128Shx147065 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 18*4128Shx147065 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 19*4128Shx147065 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 20*4128Shx147065 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 21*4128Shx147065 */ 22*4128Shx147065 23*4128Shx147065 #pragma ident "%Z%%M% %I% %E% SMI" 24*4128Shx147065 25*4128Shx147065 /* 26*4128Shx147065 * Driver for Intel PRO/Wireless 3945ABG 802.11 network adapters. 27*4128Shx147065 */ 28*4128Shx147065 29*4128Shx147065 #include <sys/types.h> 30*4128Shx147065 #include <sys/byteorder.h> 31*4128Shx147065 #include <sys/conf.h> 32*4128Shx147065 #include <sys/cmn_err.h> 33*4128Shx147065 #include <sys/stat.h> 34*4128Shx147065 #include <sys/ddi.h> 35*4128Shx147065 #include <sys/sunddi.h> 36*4128Shx147065 #include <sys/strsubr.h> 37*4128Shx147065 #include <sys/ethernet.h> 38*4128Shx147065 #include <inet/common.h> 39*4128Shx147065 #include <inet/nd.h> 40*4128Shx147065 #include <inet/mi.h> 41*4128Shx147065 #include <sys/note.h> 42*4128Shx147065 #include <sys/stream.h> 43*4128Shx147065 #include <sys/strsun.h> 44*4128Shx147065 #include <sys/modctl.h> 45*4128Shx147065 #include <sys/devops.h> 46*4128Shx147065 #include <sys/dlpi.h> 47*4128Shx147065 #include <sys/mac.h> 48*4128Shx147065 #include <sys/mac_wifi.h> 49*4128Shx147065 #include <sys/net80211.h> 50*4128Shx147065 #include <sys/net80211_proto.h> 51*4128Shx147065 #include <sys/varargs.h> 52*4128Shx147065 #include <sys/policy.h> 53*4128Shx147065 #include <sys/pci.h> 54*4128Shx147065 55*4128Shx147065 #include "wpireg.h" 56*4128Shx147065 #include "wpivar.h" 57*4128Shx147065 #include <inet/wifi_ioctl.h> 58*4128Shx147065 59*4128Shx147065 #ifdef DEBUG 60*4128Shx147065 #define WPI_DEBUG_80211 (1 << 0) 61*4128Shx147065 #define WPI_DEBUG_CMD (1 << 1) 62*4128Shx147065 #define WPI_DEBUG_DMA (1 << 2) 63*4128Shx147065 #define WPI_DEBUG_EEPROM (1 << 3) 64*4128Shx147065 #define WPI_DEBUG_FW (1 << 4) 65*4128Shx147065 #define WPI_DEBUG_HW (1 << 5) 66*4128Shx147065 #define WPI_DEBUG_INTR (1 << 6) 67*4128Shx147065 #define WPI_DEBUG_MRR (1 << 7) 68*4128Shx147065 #define WPI_DEBUG_PIO (1 << 8) 69*4128Shx147065 #define WPI_DEBUG_RX (1 << 9) 70*4128Shx147065 #define WPI_DEBUG_SCAN (1 << 10) 71*4128Shx147065 #define WPI_DEBUG_TX (1 << 11) 72*4128Shx147065 #define WPI_DEBUG_RATECTL (1 << 12) 73*4128Shx147065 #define WPI_DEBUG_RADIO (1 << 13) 74*4128Shx147065 uint32_t wpi_dbg_flags = 0; 75*4128Shx147065 #define WPI_DBG(x) \ 76*4128Shx147065 wpi_dbg x 77*4128Shx147065 #else 78*4128Shx147065 #define WPI_DBG(x) 79*4128Shx147065 #endif 80*4128Shx147065 81*4128Shx147065 static void *wpi_soft_state_p = NULL; 82*4128Shx147065 static uint8_t wpi_fw_bin [] = { 83*4128Shx147065 #include "fw-wpi/ipw3945.ucode.hex" 84*4128Shx147065 }; 85*4128Shx147065 86*4128Shx147065 /* DMA attributes for a shared page */ 87*4128Shx147065 static ddi_dma_attr_t sh_dma_attr = { 88*4128Shx147065 DMA_ATTR_V0, /* version of this structure */ 89*4128Shx147065 0, /* lowest usable address */ 90*4128Shx147065 0xffffffffU, /* highest usable address */ 91*4128Shx147065 0xffffffffU, /* maximum DMAable byte count */ 92*4128Shx147065 0x1000, /* alignment in bytes */ 93*4128Shx147065 0x1000, /* burst sizes (any?) */ 94*4128Shx147065 1, /* minimum transfer */ 95*4128Shx147065 0xffffffffU, /* maximum transfer */ 96*4128Shx147065 0xffffffffU, /* maximum segment length */ 97*4128Shx147065 1, /* maximum number of segments */ 98*4128Shx147065 1, /* granularity */ 99*4128Shx147065 0, /* flags (reserved) */ 100*4128Shx147065 }; 101*4128Shx147065 102*4128Shx147065 /* DMA attributes for a ring descriptor */ 103*4128Shx147065 static ddi_dma_attr_t ring_desc_dma_attr = { 104*4128Shx147065 DMA_ATTR_V0, /* version of this structure */ 105*4128Shx147065 0, /* lowest usable address */ 106*4128Shx147065 0xffffffffU, /* highest usable address */ 107*4128Shx147065 0xffffffffU, /* maximum DMAable byte count */ 108*4128Shx147065 0x4000, /* alignment in bytes */ 109*4128Shx147065 0x100, /* burst sizes (any?) */ 110*4128Shx147065 1, /* minimum transfer */ 111*4128Shx147065 0xffffffffU, /* maximum transfer */ 112*4128Shx147065 0xffffffffU, /* maximum segment length */ 113*4128Shx147065 1, /* maximum number of segments */ 114*4128Shx147065 1, /* granularity */ 115*4128Shx147065 0, /* flags (reserved) */ 116*4128Shx147065 }; 117*4128Shx147065 118*4128Shx147065 119*4128Shx147065 /* DMA attributes for a tx cmd */ 120*4128Shx147065 static ddi_dma_attr_t tx_cmd_dma_attr = { 121*4128Shx147065 DMA_ATTR_V0, /* version of this structure */ 122*4128Shx147065 0, /* lowest usable address */ 123*4128Shx147065 0xffffffffU, /* highest usable address */ 124*4128Shx147065 0xffffffffU, /* maximum DMAable byte count */ 125*4128Shx147065 4, /* alignment in bytes */ 126*4128Shx147065 0x100, /* burst sizes (any?) */ 127*4128Shx147065 1, /* minimum transfer */ 128*4128Shx147065 0xffffffffU, /* maximum transfer */ 129*4128Shx147065 0xffffffffU, /* maximum segment length */ 130*4128Shx147065 1, /* maximum number of segments */ 131*4128Shx147065 1, /* granularity */ 132*4128Shx147065 0, /* flags (reserved) */ 133*4128Shx147065 }; 134*4128Shx147065 135*4128Shx147065 /* DMA attributes for a rx buffer */ 136*4128Shx147065 static ddi_dma_attr_t rx_buffer_dma_attr = { 137*4128Shx147065 DMA_ATTR_V0, /* version of this structure */ 138*4128Shx147065 0, /* lowest usable address */ 139*4128Shx147065 0xffffffffU, /* highest usable address */ 140*4128Shx147065 0xffffffffU, /* maximum DMAable byte count */ 141*4128Shx147065 1, /* alignment in bytes */ 142*4128Shx147065 0x100, /* burst sizes (any?) */ 143*4128Shx147065 1, /* minimum transfer */ 144*4128Shx147065 0xffffffffU, /* maximum transfer */ 145*4128Shx147065 0xffffffffU, /* maximum segment length */ 146*4128Shx147065 1, /* maximum number of segments */ 147*4128Shx147065 1, /* granularity */ 148*4128Shx147065 0, /* flags (reserved) */ 149*4128Shx147065 }; 150*4128Shx147065 151*4128Shx147065 /* 152*4128Shx147065 * DMA attributes for a tx buffer. 153*4128Shx147065 * the maximum number of segments is 4 for the hardware. 154*4128Shx147065 * now all the wifi drivers put the whole frame in a single 155*4128Shx147065 * descriptor, so we define the maximum number of segments 4, 156*4128Shx147065 * just the same as the rx_buffer. we consider leverage the HW 157*4128Shx147065 * ability in the future, that is why we don't define rx and tx 158*4128Shx147065 * buffer_dma_attr as the same. 159*4128Shx147065 */ 160*4128Shx147065 static ddi_dma_attr_t tx_buffer_dma_attr = { 161*4128Shx147065 DMA_ATTR_V0, /* version of this structure */ 162*4128Shx147065 0, /* lowest usable address */ 163*4128Shx147065 0xffffffffU, /* highest usable address */ 164*4128Shx147065 0xffffffffU, /* maximum DMAable byte count */ 165*4128Shx147065 1, /* alignment in bytes */ 166*4128Shx147065 0x100, /* burst sizes (any?) */ 167*4128Shx147065 1, /* minimum transfer */ 168*4128Shx147065 0xffffffffU, /* maximum transfer */ 169*4128Shx147065 0xffffffffU, /* maximum segment length */ 170*4128Shx147065 1, /* maximum number of segments */ 171*4128Shx147065 1, /* granularity */ 172*4128Shx147065 0, /* flags (reserved) */ 173*4128Shx147065 }; 174*4128Shx147065 175*4128Shx147065 /* DMA attributes for a load firmware */ 176*4128Shx147065 static ddi_dma_attr_t fw_buffer_dma_attr = { 177*4128Shx147065 DMA_ATTR_V0, /* version of this structure */ 178*4128Shx147065 0, /* lowest usable address */ 179*4128Shx147065 0xffffffffU, /* highest usable address */ 180*4128Shx147065 0x7fffffff, /* maximum DMAable byte count */ 181*4128Shx147065 4, /* alignment in bytes */ 182*4128Shx147065 0x100, /* burst sizes (any?) */ 183*4128Shx147065 1, /* minimum transfer */ 184*4128Shx147065 0xffffffffU, /* maximum transfer */ 185*4128Shx147065 0xffffffffU, /* maximum segment length */ 186*4128Shx147065 4, /* maximum number of segments */ 187*4128Shx147065 1, /* granularity */ 188*4128Shx147065 0, /* flags (reserved) */ 189*4128Shx147065 }; 190*4128Shx147065 191*4128Shx147065 /* regs access attributes */ 192*4128Shx147065 static ddi_device_acc_attr_t wpi_reg_accattr = { 193*4128Shx147065 DDI_DEVICE_ATTR_V0, 194*4128Shx147065 DDI_STRUCTURE_LE_ACC, 195*4128Shx147065 DDI_STRICTORDER_ACC, 196*4128Shx147065 DDI_DEFAULT_ACC 197*4128Shx147065 }; 198*4128Shx147065 199*4128Shx147065 /* DMA access attributes */ 200*4128Shx147065 static ddi_device_acc_attr_t wpi_dma_accattr = { 201*4128Shx147065 DDI_DEVICE_ATTR_V0, 202*4128Shx147065 DDI_NEVERSWAP_ACC, 203*4128Shx147065 DDI_STRICTORDER_ACC, 204*4128Shx147065 DDI_DEFAULT_ACC 205*4128Shx147065 }; 206*4128Shx147065 207*4128Shx147065 static int wpi_ring_init(wpi_sc_t *); 208*4128Shx147065 static void wpi_ring_free(wpi_sc_t *); 209*4128Shx147065 static int wpi_alloc_shared(wpi_sc_t *); 210*4128Shx147065 static void wpi_free_shared(wpi_sc_t *); 211*4128Shx147065 static int wpi_alloc_fw_dma(wpi_sc_t *); 212*4128Shx147065 static void wpi_free_fw_dma(wpi_sc_t *); 213*4128Shx147065 static int wpi_alloc_rx_ring(wpi_sc_t *); 214*4128Shx147065 static void wpi_reset_rx_ring(wpi_sc_t *); 215*4128Shx147065 static void wpi_free_rx_ring(wpi_sc_t *); 216*4128Shx147065 static int wpi_alloc_tx_ring(wpi_sc_t *, wpi_tx_ring_t *, int, int); 217*4128Shx147065 static void wpi_reset_tx_ring(wpi_sc_t *, wpi_tx_ring_t *); 218*4128Shx147065 static void wpi_free_tx_ring(wpi_sc_t *, wpi_tx_ring_t *); 219*4128Shx147065 220*4128Shx147065 static ieee80211_node_t *wpi_node_alloc(ieee80211com_t *); 221*4128Shx147065 static void wpi_node_free(ieee80211_node_t *); 222*4128Shx147065 static int wpi_newstate(ieee80211com_t *, enum ieee80211_state, int); 223*4128Shx147065 static void wpi_mem_lock(wpi_sc_t *); 224*4128Shx147065 static void wpi_mem_unlock(wpi_sc_t *); 225*4128Shx147065 static uint32_t wpi_mem_read(wpi_sc_t *, uint16_t); 226*4128Shx147065 static void wpi_mem_write(wpi_sc_t *, uint16_t, uint32_t); 227*4128Shx147065 static void wpi_mem_write_region_4(wpi_sc_t *, uint16_t, 228*4128Shx147065 const uint32_t *, int); 229*4128Shx147065 static uint16_t wpi_read_prom_word(wpi_sc_t *, uint32_t); 230*4128Shx147065 static int wpi_load_microcode(wpi_sc_t *); 231*4128Shx147065 static int wpi_load_firmware(wpi_sc_t *, uint32_t); 232*4128Shx147065 static void wpi_rx_intr(wpi_sc_t *, wpi_rx_desc_t *, 233*4128Shx147065 wpi_rx_data_t *); 234*4128Shx147065 static void wpi_tx_intr(wpi_sc_t *, wpi_rx_desc_t *, 235*4128Shx147065 wpi_rx_data_t *); 236*4128Shx147065 static void wpi_cmd_intr(wpi_sc_t *, wpi_rx_desc_t *); 237*4128Shx147065 static uint_t wpi_intr(caddr_t); 238*4128Shx147065 static uint_t wpi_notif_softintr(caddr_t); 239*4128Shx147065 static uint8_t wpi_plcp_signal(int); 240*4128Shx147065 static void wpi_read_eeprom(wpi_sc_t *); 241*4128Shx147065 static int wpi_cmd(wpi_sc_t *, int, const void *, int, int); 242*4128Shx147065 static int wpi_mrr_setup(wpi_sc_t *); 243*4128Shx147065 static void wpi_set_led(wpi_sc_t *, uint8_t, uint8_t, uint8_t); 244*4128Shx147065 static int wpi_auth(wpi_sc_t *); 245*4128Shx147065 static int wpi_scan(wpi_sc_t *); 246*4128Shx147065 static int wpi_config(wpi_sc_t *); 247*4128Shx147065 static void wpi_stop_master(wpi_sc_t *); 248*4128Shx147065 static int wpi_power_up(wpi_sc_t *); 249*4128Shx147065 static int wpi_reset(wpi_sc_t *); 250*4128Shx147065 static void wpi_hw_config(wpi_sc_t *); 251*4128Shx147065 static int wpi_init(wpi_sc_t *); 252*4128Shx147065 static void wpi_stop(wpi_sc_t *); 253*4128Shx147065 static void wpi_amrr_init(wpi_amrr_t *); 254*4128Shx147065 static void wpi_amrr_timeout(wpi_sc_t *); 255*4128Shx147065 static void wpi_amrr_ratectl(void *, ieee80211_node_t *); 256*4128Shx147065 257*4128Shx147065 static int wpi_attach(dev_info_t *dip, ddi_attach_cmd_t cmd); 258*4128Shx147065 static int wpi_detach(dev_info_t *dip, ddi_detach_cmd_t cmd); 259*4128Shx147065 260*4128Shx147065 /* 261*4128Shx147065 * GLD specific operations 262*4128Shx147065 */ 263*4128Shx147065 static int wpi_m_stat(void *arg, uint_t stat, uint64_t *val); 264*4128Shx147065 static int wpi_m_start(void *arg); 265*4128Shx147065 static void wpi_m_stop(void *arg); 266*4128Shx147065 static int wpi_m_unicst(void *arg, const uint8_t *macaddr); 267*4128Shx147065 static int wpi_m_multicst(void *arg, boolean_t add, const uint8_t *m); 268*4128Shx147065 static int wpi_m_promisc(void *arg, boolean_t on); 269*4128Shx147065 static mblk_t *wpi_m_tx(void *arg, mblk_t *mp); 270*4128Shx147065 static void wpi_m_ioctl(void *arg, queue_t *wq, mblk_t *mp); 271*4128Shx147065 272*4128Shx147065 static void wpi_destroy_locks(wpi_sc_t *sc); 273*4128Shx147065 static int wpi_send(ieee80211com_t *ic, mblk_t *mp, uint8_t type); 274*4128Shx147065 static void wpi_thread(wpi_sc_t *sc); 275*4128Shx147065 276*4128Shx147065 /* 277*4128Shx147065 * Supported rates for 802.11a/b/g modes (in 500Kbps unit). 278*4128Shx147065 */ 279*4128Shx147065 static const struct ieee80211_rateset wpi_rateset_11b = 280*4128Shx147065 { 4, { 2, 4, 11, 22 } }; 281*4128Shx147065 282*4128Shx147065 static const struct ieee80211_rateset wpi_rateset_11g = 283*4128Shx147065 { 12, { 2, 4, 11, 22, 12, 18, 24, 36, 48, 72, 96, 108 } }; 284*4128Shx147065 285*4128Shx147065 static const uint8_t wpi_ridx_to_signal[] = { 286*4128Shx147065 /* OFDM: IEEE Std 802.11a-1999, pp. 14 Table 80 */ 287*4128Shx147065 /* R1-R4 (ral/ural is R4-R1) */ 288*4128Shx147065 0xd, 0xf, 0x5, 0x7, 0x9, 0xb, 0x1, 0x3, 289*4128Shx147065 /* CCK: device-dependent */ 290*4128Shx147065 10, 20, 55, 110 291*4128Shx147065 }; 292*4128Shx147065 293*4128Shx147065 /* 294*4128Shx147065 * For mfthread only 295*4128Shx147065 */ 296*4128Shx147065 extern pri_t minclsyspri; 297*4128Shx147065 298*4128Shx147065 /* 299*4128Shx147065 * Module Loading Data & Entry Points 300*4128Shx147065 */ 301*4128Shx147065 DDI_DEFINE_STREAM_OPS(wpi_devops, nulldev, nulldev, wpi_attach, 302*4128Shx147065 wpi_detach, nodev, NULL, D_MP, NULL); 303*4128Shx147065 304*4128Shx147065 static struct modldrv wpi_modldrv = { 305*4128Shx147065 &mod_driverops, 306*4128Shx147065 "Intel(R) PRO/Wireless 3945ABG driver", 307*4128Shx147065 &wpi_devops 308*4128Shx147065 }; 309*4128Shx147065 310*4128Shx147065 static struct modlinkage wpi_modlinkage = { 311*4128Shx147065 MODREV_1, 312*4128Shx147065 &wpi_modldrv, 313*4128Shx147065 NULL 314*4128Shx147065 }; 315*4128Shx147065 316*4128Shx147065 int 317*4128Shx147065 _init(void) 318*4128Shx147065 { 319*4128Shx147065 int status; 320*4128Shx147065 321*4128Shx147065 status = ddi_soft_state_init(&wpi_soft_state_p, 322*4128Shx147065 sizeof (wpi_sc_t), 1); 323*4128Shx147065 if (status != DDI_SUCCESS) 324*4128Shx147065 return (status); 325*4128Shx147065 326*4128Shx147065 mac_init_ops(&wpi_devops, "wpi"); 327*4128Shx147065 status = mod_install(&wpi_modlinkage); 328*4128Shx147065 if (status != DDI_SUCCESS) { 329*4128Shx147065 mac_fini_ops(&wpi_devops); 330*4128Shx147065 ddi_soft_state_fini(&wpi_soft_state_p); 331*4128Shx147065 } 332*4128Shx147065 333*4128Shx147065 return (status); 334*4128Shx147065 } 335*4128Shx147065 336*4128Shx147065 int 337*4128Shx147065 _fini(void) 338*4128Shx147065 { 339*4128Shx147065 int status; 340*4128Shx147065 341*4128Shx147065 status = mod_remove(&wpi_modlinkage); 342*4128Shx147065 if (status == DDI_SUCCESS) { 343*4128Shx147065 mac_fini_ops(&wpi_devops); 344*4128Shx147065 ddi_soft_state_fini(&wpi_soft_state_p); 345*4128Shx147065 } 346*4128Shx147065 347*4128Shx147065 return (status); 348*4128Shx147065 } 349*4128Shx147065 350*4128Shx147065 int 351*4128Shx147065 _info(struct modinfo *mip) 352*4128Shx147065 { 353*4128Shx147065 return (mod_info(&wpi_modlinkage, mip)); 354*4128Shx147065 } 355*4128Shx147065 356*4128Shx147065 /* 357*4128Shx147065 * Mac Call Back entries 358*4128Shx147065 */ 359*4128Shx147065 mac_callbacks_t wpi_m_callbacks = { 360*4128Shx147065 MC_IOCTL, 361*4128Shx147065 wpi_m_stat, 362*4128Shx147065 wpi_m_start, 363*4128Shx147065 wpi_m_stop, 364*4128Shx147065 wpi_m_promisc, 365*4128Shx147065 wpi_m_multicst, 366*4128Shx147065 wpi_m_unicst, 367*4128Shx147065 wpi_m_tx, 368*4128Shx147065 NULL, 369*4128Shx147065 wpi_m_ioctl 370*4128Shx147065 }; 371*4128Shx147065 372*4128Shx147065 #ifdef DEBUG 373*4128Shx147065 void 374*4128Shx147065 wpi_dbg(uint32_t flags, const char *fmt, ...) 375*4128Shx147065 { 376*4128Shx147065 va_list ap; 377*4128Shx147065 378*4128Shx147065 if (flags & wpi_dbg_flags) { 379*4128Shx147065 va_start(ap, fmt); 380*4128Shx147065 vcmn_err(CE_NOTE, fmt, ap); 381*4128Shx147065 va_end(ap); 382*4128Shx147065 } 383*4128Shx147065 } 384*4128Shx147065 #endif 385*4128Shx147065 /* 386*4128Shx147065 * device operations 387*4128Shx147065 */ 388*4128Shx147065 int 389*4128Shx147065 wpi_attach(dev_info_t *dip, ddi_attach_cmd_t cmd) 390*4128Shx147065 { 391*4128Shx147065 wpi_sc_t *sc; 392*4128Shx147065 ddi_acc_handle_t cfg_handle; 393*4128Shx147065 caddr_t cfg_base; 394*4128Shx147065 ieee80211com_t *ic; 395*4128Shx147065 int instance, err, i; 396*4128Shx147065 char strbuf[32]; 397*4128Shx147065 wifi_data_t wd = { 0 }; 398*4128Shx147065 mac_register_t *macp; 399*4128Shx147065 400*4128Shx147065 if (cmd != DDI_ATTACH) { 401*4128Shx147065 err = DDI_FAILURE; 402*4128Shx147065 goto attach_fail1; 403*4128Shx147065 } 404*4128Shx147065 405*4128Shx147065 instance = ddi_get_instance(dip); 406*4128Shx147065 err = ddi_soft_state_zalloc(wpi_soft_state_p, instance); 407*4128Shx147065 if (err != DDI_SUCCESS) { 408*4128Shx147065 cmn_err(CE_WARN, 409*4128Shx147065 "wpi_attach(): failed to allocate soft state\n"); 410*4128Shx147065 goto attach_fail1; 411*4128Shx147065 } 412*4128Shx147065 sc = ddi_get_soft_state(wpi_soft_state_p, instance); 413*4128Shx147065 sc->sc_dip = dip; 414*4128Shx147065 415*4128Shx147065 err = ddi_regs_map_setup(dip, 0, &cfg_base, 0, 0, 416*4128Shx147065 &wpi_reg_accattr, &cfg_handle); 417*4128Shx147065 if (err != DDI_SUCCESS) { 418*4128Shx147065 cmn_err(CE_WARN, 419*4128Shx147065 "wpi_attach(): failed to map config spaces regs\n"); 420*4128Shx147065 goto attach_fail2; 421*4128Shx147065 } 422*4128Shx147065 sc->sc_rev = ddi_get8(cfg_handle, 423*4128Shx147065 (uint8_t *)(cfg_base + PCI_CONF_REVID)); 424*4128Shx147065 ddi_put8(cfg_handle, (uint8_t *)(cfg_base + 0x41), 0); 425*4128Shx147065 sc->sc_clsz = ddi_get16(cfg_handle, 426*4128Shx147065 (uint16_t *)(cfg_base + PCI_CONF_CACHE_LINESZ)); 427*4128Shx147065 ddi_regs_map_free(&cfg_handle); 428*4128Shx147065 if (!sc->sc_clsz) 429*4128Shx147065 sc->sc_clsz = 16; 430*4128Shx147065 sc->sc_clsz = (sc->sc_clsz << 2); 431*4128Shx147065 sc->sc_dmabuf_sz = roundup(0x1000 + sizeof (struct ieee80211_frame) + 432*4128Shx147065 IEEE80211_MTU + IEEE80211_CRC_LEN + 433*4128Shx147065 (IEEE80211_WEP_IVLEN + IEEE80211_WEP_KIDLEN + 434*4128Shx147065 IEEE80211_WEP_CRCLEN), sc->sc_clsz); 435*4128Shx147065 /* 436*4128Shx147065 * Map operating registers 437*4128Shx147065 */ 438*4128Shx147065 err = ddi_regs_map_setup(dip, 1, &sc->sc_base, 439*4128Shx147065 0, 0, &wpi_reg_accattr, &sc->sc_handle); 440*4128Shx147065 if (err != DDI_SUCCESS) { 441*4128Shx147065 cmn_err(CE_WARN, 442*4128Shx147065 "wpi_attach(): failed to map device regs\n"); 443*4128Shx147065 goto attach_fail2; 444*4128Shx147065 } 445*4128Shx147065 446*4128Shx147065 /* 447*4128Shx147065 * Allocate shared page. 448*4128Shx147065 */ 449*4128Shx147065 err = wpi_alloc_shared(sc); 450*4128Shx147065 if (err != DDI_SUCCESS) { 451*4128Shx147065 cmn_err(CE_WARN, "failed to allocate shared page\n"); 452*4128Shx147065 goto attach_fail3; 453*4128Shx147065 } 454*4128Shx147065 455*4128Shx147065 /* 456*4128Shx147065 * Get the hw conf, including MAC address, then init all rings. 457*4128Shx147065 */ 458*4128Shx147065 wpi_read_eeprom(sc); 459*4128Shx147065 err = wpi_ring_init(sc); 460*4128Shx147065 if (err != DDI_SUCCESS) { 461*4128Shx147065 cmn_err(CE_WARN, "wpi_attach(): " 462*4128Shx147065 "failed to allocate and initialize ring\n"); 463*4128Shx147065 goto attach_fail4; 464*4128Shx147065 } 465*4128Shx147065 466*4128Shx147065 sc->sc_hdr = (const wpi_firmware_hdr_t *)wpi_fw_bin; 467*4128Shx147065 468*4128Shx147065 /* firmware image layout: |HDR|<--TEXT-->|<--DATA-->|<--BOOT-->| */ 469*4128Shx147065 sc->sc_text = (const char *)(sc->sc_hdr + 1); 470*4128Shx147065 sc->sc_data = sc->sc_text + LE_32(sc->sc_hdr->textsz); 471*4128Shx147065 sc->sc_boot = sc->sc_data + LE_32(sc->sc_hdr->datasz); 472*4128Shx147065 err = wpi_alloc_fw_dma(sc); 473*4128Shx147065 if (err != DDI_SUCCESS) { 474*4128Shx147065 cmn_err(CE_WARN, "wpi_attach(): " 475*4128Shx147065 "failed to allocate firmware dma\n"); 476*4128Shx147065 goto attach_fail5; 477*4128Shx147065 } 478*4128Shx147065 479*4128Shx147065 /* 480*4128Shx147065 * Initialize mutexs and condvars 481*4128Shx147065 */ 482*4128Shx147065 err = ddi_get_iblock_cookie(dip, 0, &sc->sc_iblk); 483*4128Shx147065 if (err != DDI_SUCCESS) { 484*4128Shx147065 cmn_err(CE_WARN, 485*4128Shx147065 "wpi_attach(): failed to do ddi_get_iblock_cookie()\n"); 486*4128Shx147065 goto attach_fail6; 487*4128Shx147065 } 488*4128Shx147065 mutex_init(&sc->sc_glock, NULL, MUTEX_DRIVER, sc->sc_iblk); 489*4128Shx147065 mutex_init(&sc->sc_tx_lock, NULL, MUTEX_DRIVER, sc->sc_iblk); 490*4128Shx147065 cv_init(&sc->sc_fw_cv, NULL, CV_DRIVER, NULL); 491*4128Shx147065 cv_init(&sc->sc_cmd_cv, NULL, CV_DRIVER, NULL); 492*4128Shx147065 cv_init(&sc->sc_tx_cv, "tx-ring", CV_DRIVER, NULL); 493*4128Shx147065 /* 494*4128Shx147065 * initialize the mfthread 495*4128Shx147065 */ 496*4128Shx147065 mutex_init(&sc->sc_mt_lock, NULL, MUTEX_DRIVER, 497*4128Shx147065 (void *) sc->sc_iblk); 498*4128Shx147065 cv_init(&sc->sc_mt_cv, NULL, CV_DRIVER, NULL); 499*4128Shx147065 sc->sc_mf_thread = NULL; 500*4128Shx147065 sc->sc_mf_thread_switch = 0; 501*4128Shx147065 /* 502*4128Shx147065 * Initialize the wifi part, which will be used by 503*4128Shx147065 * generic layer 504*4128Shx147065 */ 505*4128Shx147065 ic = &sc->sc_ic; 506*4128Shx147065 ic->ic_phytype = IEEE80211_T_OFDM; 507*4128Shx147065 ic->ic_opmode = IEEE80211_M_STA; /* default to BSS mode */ 508*4128Shx147065 ic->ic_state = IEEE80211_S_INIT; 509*4128Shx147065 ic->ic_maxrssi = 70; /* experimental number */ 510*4128Shx147065 /* 511*4128Shx147065 * use software WEP for the current version. 512*4128Shx147065 */ 513*4128Shx147065 ic->ic_caps = IEEE80211_C_SHPREAMBLE | IEEE80211_C_TXPMGT | 514*4128Shx147065 IEEE80211_C_PMGT; 515*4128Shx147065 516*4128Shx147065 /* set supported .11b and .11g rates */ 517*4128Shx147065 ic->ic_sup_rates[IEEE80211_MODE_11B] = wpi_rateset_11b; 518*4128Shx147065 ic->ic_sup_rates[IEEE80211_MODE_11G] = wpi_rateset_11g; 519*4128Shx147065 520*4128Shx147065 /* set supported .11b and .11g channels (1 through 14) */ 521*4128Shx147065 for (i = 1; i <= 14; i++) { 522*4128Shx147065 ic->ic_sup_channels[i].ich_freq = 523*4128Shx147065 ieee80211_ieee2mhz(i, IEEE80211_CHAN_2GHZ); 524*4128Shx147065 ic->ic_sup_channels[i].ich_flags = 525*4128Shx147065 IEEE80211_CHAN_CCK | IEEE80211_CHAN_OFDM | 526*4128Shx147065 IEEE80211_CHAN_DYN | IEEE80211_CHAN_2GHZ; 527*4128Shx147065 } 528*4128Shx147065 ic->ic_ibss_chan = &ic->ic_sup_channels[0]; 529*4128Shx147065 ic->ic_xmit = wpi_send; 530*4128Shx147065 /* 531*4128Shx147065 * init Wifi layer 532*4128Shx147065 */ 533*4128Shx147065 ieee80211_attach(ic); 534*4128Shx147065 535*4128Shx147065 /* 536*4128Shx147065 * Override 80211 default routines 537*4128Shx147065 */ 538*4128Shx147065 sc->sc_newstate = ic->ic_newstate; 539*4128Shx147065 ic->ic_newstate = wpi_newstate; 540*4128Shx147065 ic->ic_node_alloc = wpi_node_alloc; 541*4128Shx147065 ic->ic_node_free = wpi_node_free; 542*4128Shx147065 ieee80211_media_init(ic); 543*4128Shx147065 /* 544*4128Shx147065 * initialize default tx key 545*4128Shx147065 */ 546*4128Shx147065 ic->ic_def_txkey = 0; 547*4128Shx147065 548*4128Shx147065 err = ddi_add_softintr(dip, DDI_SOFTINT_LOW, 549*4128Shx147065 &sc->sc_notif_softint_id, &sc->sc_iblk, NULL, wpi_notif_softintr, 550*4128Shx147065 (caddr_t)sc); 551*4128Shx147065 if (err != DDI_SUCCESS) { 552*4128Shx147065 cmn_err(CE_WARN, 553*4128Shx147065 "wpi_attach(): failed to do ddi_add_softintr()\n"); 554*4128Shx147065 goto attach_fail7; 555*4128Shx147065 } 556*4128Shx147065 557*4128Shx147065 /* 558*4128Shx147065 * Add the interrupt handler 559*4128Shx147065 */ 560*4128Shx147065 err = ddi_add_intr(dip, 0, &sc->sc_iblk, NULL, 561*4128Shx147065 wpi_intr, (caddr_t)sc); 562*4128Shx147065 if (err != DDI_SUCCESS) { 563*4128Shx147065 cmn_err(CE_WARN, 564*4128Shx147065 "wpi_attach(): failed to do ddi_add_intr()\n"); 565*4128Shx147065 goto attach_fail8; 566*4128Shx147065 } 567*4128Shx147065 568*4128Shx147065 /* 569*4128Shx147065 * Initialize pointer to device specific functions 570*4128Shx147065 */ 571*4128Shx147065 wd.wd_secalloc = WIFI_SEC_NONE; 572*4128Shx147065 wd.wd_opmode = ic->ic_opmode; 573*4128Shx147065 IEEE80211_ADDR_COPY(wd.wd_bssid, ic->ic_macaddr); 574*4128Shx147065 575*4128Shx147065 macp = mac_alloc(MAC_VERSION); 576*4128Shx147065 if (err != DDI_SUCCESS) { 577*4128Shx147065 cmn_err(CE_WARN, 578*4128Shx147065 "wpi_attach(): failed to do mac_alloc()\n"); 579*4128Shx147065 goto attach_fail9; 580*4128Shx147065 } 581*4128Shx147065 582*4128Shx147065 macp->m_type_ident = MAC_PLUGIN_IDENT_WIFI; 583*4128Shx147065 macp->m_driver = sc; 584*4128Shx147065 macp->m_dip = dip; 585*4128Shx147065 macp->m_src_addr = ic->ic_macaddr; 586*4128Shx147065 macp->m_callbacks = &wpi_m_callbacks; 587*4128Shx147065 macp->m_min_sdu = 0; 588*4128Shx147065 macp->m_max_sdu = IEEE80211_MTU; 589*4128Shx147065 macp->m_pdata = &wd; 590*4128Shx147065 macp->m_pdata_size = sizeof (wd); 591*4128Shx147065 592*4128Shx147065 /* 593*4128Shx147065 * Register the macp to mac 594*4128Shx147065 */ 595*4128Shx147065 err = mac_register(macp, &ic->ic_mach); 596*4128Shx147065 mac_free(macp); 597*4128Shx147065 if (err != DDI_SUCCESS) { 598*4128Shx147065 cmn_err(CE_WARN, 599*4128Shx147065 "wpi_attach(): failed to do mac_register()\n"); 600*4128Shx147065 goto attach_fail9; 601*4128Shx147065 } 602*4128Shx147065 603*4128Shx147065 /* 604*4128Shx147065 * Create minor node of type DDI_NT_NET_WIFI 605*4128Shx147065 */ 606*4128Shx147065 (void) snprintf(strbuf, sizeof (strbuf), "wpi%d", instance); 607*4128Shx147065 err = ddi_create_minor_node(dip, strbuf, S_IFCHR, 608*4128Shx147065 instance + 1, DDI_NT_NET_WIFI, 0); 609*4128Shx147065 if (err != DDI_SUCCESS) 610*4128Shx147065 cmn_err(CE_WARN, 611*4128Shx147065 "wpi_attach(): failed to do ddi_create_minor_node()\n"); 612*4128Shx147065 613*4128Shx147065 /* 614*4128Shx147065 * Notify link is down now 615*4128Shx147065 */ 616*4128Shx147065 mac_link_update(ic->ic_mach, LINK_STATE_DOWN); 617*4128Shx147065 618*4128Shx147065 /* 619*4128Shx147065 * create the mf thread to handle the link status, 620*4128Shx147065 * recovery fatal error, etc. 621*4128Shx147065 */ 622*4128Shx147065 623*4128Shx147065 sc->sc_mf_thread_switch = 1; 624*4128Shx147065 if (sc->sc_mf_thread == NULL) 625*4128Shx147065 sc->sc_mf_thread = thread_create((caddr_t)NULL, 0, 626*4128Shx147065 wpi_thread, sc, 0, &p0, TS_RUN, minclsyspri); 627*4128Shx147065 628*4128Shx147065 sc->sc_flags |= WPI_F_ATTACHED; 629*4128Shx147065 630*4128Shx147065 return (DDI_SUCCESS); 631*4128Shx147065 attach_fail9: 632*4128Shx147065 ddi_remove_intr(dip, 0, sc->sc_iblk); 633*4128Shx147065 attach_fail8: 634*4128Shx147065 ddi_remove_softintr(sc->sc_notif_softint_id); 635*4128Shx147065 sc->sc_notif_softint_id = NULL; 636*4128Shx147065 attach_fail7: 637*4128Shx147065 ieee80211_detach(ic); 638*4128Shx147065 wpi_destroy_locks(sc); 639*4128Shx147065 attach_fail6: 640*4128Shx147065 wpi_free_fw_dma(sc); 641*4128Shx147065 attach_fail5: 642*4128Shx147065 wpi_ring_free(sc); 643*4128Shx147065 attach_fail4: 644*4128Shx147065 wpi_free_shared(sc); 645*4128Shx147065 attach_fail3: 646*4128Shx147065 ddi_regs_map_free(&sc->sc_handle); 647*4128Shx147065 attach_fail2: 648*4128Shx147065 ddi_soft_state_free(wpi_soft_state_p, instance); 649*4128Shx147065 attach_fail1: 650*4128Shx147065 return (err); 651*4128Shx147065 } 652*4128Shx147065 653*4128Shx147065 int 654*4128Shx147065 wpi_detach(dev_info_t *dip, ddi_detach_cmd_t cmd) 655*4128Shx147065 { 656*4128Shx147065 wpi_sc_t *sc; 657*4128Shx147065 int err; 658*4128Shx147065 659*4128Shx147065 sc = ddi_get_soft_state(wpi_soft_state_p, ddi_get_instance(dip)); 660*4128Shx147065 ASSERT(sc != NULL); 661*4128Shx147065 662*4128Shx147065 if (cmd != DDI_DETACH) 663*4128Shx147065 return (DDI_FAILURE); 664*4128Shx147065 if (!(sc->sc_flags & WPI_F_ATTACHED)) 665*4128Shx147065 return (DDI_FAILURE); 666*4128Shx147065 667*4128Shx147065 /* 668*4128Shx147065 * Destroy the mf_thread 669*4128Shx147065 */ 670*4128Shx147065 mutex_enter(&sc->sc_mt_lock); 671*4128Shx147065 sc->sc_mf_thread_switch = 0; 672*4128Shx147065 while (sc->sc_mf_thread != NULL) { 673*4128Shx147065 if (cv_wait_sig(&sc->sc_mt_cv, &sc->sc_mt_lock) == 0) 674*4128Shx147065 break; 675*4128Shx147065 } 676*4128Shx147065 mutex_exit(&sc->sc_mt_lock); 677*4128Shx147065 678*4128Shx147065 wpi_stop(sc); 679*4128Shx147065 680*4128Shx147065 /* 681*4128Shx147065 * Unregiste from the MAC layer subsystem 682*4128Shx147065 */ 683*4128Shx147065 err = mac_unregister(sc->sc_ic.ic_mach); 684*4128Shx147065 if (err != DDI_SUCCESS) 685*4128Shx147065 return (err); 686*4128Shx147065 687*4128Shx147065 mutex_enter(&sc->sc_glock); 688*4128Shx147065 wpi_free_fw_dma(sc); 689*4128Shx147065 wpi_ring_free(sc); 690*4128Shx147065 wpi_free_shared(sc); 691*4128Shx147065 mutex_exit(&sc->sc_glock); 692*4128Shx147065 693*4128Shx147065 ddi_remove_intr(dip, 0, sc->sc_iblk); 694*4128Shx147065 ddi_remove_softintr(sc->sc_notif_softint_id); 695*4128Shx147065 sc->sc_notif_softint_id = NULL; 696*4128Shx147065 697*4128Shx147065 /* 698*4128Shx147065 * detach ieee80211 699*4128Shx147065 */ 700*4128Shx147065 ieee80211_detach(&sc->sc_ic); 701*4128Shx147065 702*4128Shx147065 wpi_destroy_locks(sc); 703*4128Shx147065 704*4128Shx147065 ddi_regs_map_free(&sc->sc_handle); 705*4128Shx147065 ddi_remove_minor_node(dip, NULL); 706*4128Shx147065 ddi_soft_state_free(wpi_soft_state_p, ddi_get_instance(dip)); 707*4128Shx147065 708*4128Shx147065 return (DDI_SUCCESS); 709*4128Shx147065 } 710*4128Shx147065 711*4128Shx147065 static void 712*4128Shx147065 wpi_destroy_locks(wpi_sc_t *sc) 713*4128Shx147065 { 714*4128Shx147065 cv_destroy(&sc->sc_mt_cv); 715*4128Shx147065 mutex_destroy(&sc->sc_mt_lock); 716*4128Shx147065 cv_destroy(&sc->sc_tx_cv); 717*4128Shx147065 cv_destroy(&sc->sc_cmd_cv); 718*4128Shx147065 cv_destroy(&sc->sc_fw_cv); 719*4128Shx147065 mutex_destroy(&sc->sc_tx_lock); 720*4128Shx147065 mutex_destroy(&sc->sc_glock); 721*4128Shx147065 } 722*4128Shx147065 723*4128Shx147065 /* 724*4128Shx147065 * Allocate an area of memory and a DMA handle for accessing it 725*4128Shx147065 */ 726*4128Shx147065 static int 727*4128Shx147065 wpi_alloc_dma_mem(wpi_sc_t *sc, size_t memsize, ddi_dma_attr_t *dma_attr_p, 728*4128Shx147065 ddi_device_acc_attr_t *acc_attr_p, uint_t dma_flags, wpi_dma_t *dma_p) 729*4128Shx147065 { 730*4128Shx147065 caddr_t vaddr; 731*4128Shx147065 int err; 732*4128Shx147065 733*4128Shx147065 /* 734*4128Shx147065 * Allocate handle 735*4128Shx147065 */ 736*4128Shx147065 err = ddi_dma_alloc_handle(sc->sc_dip, dma_attr_p, 737*4128Shx147065 DDI_DMA_SLEEP, NULL, &dma_p->dma_hdl); 738*4128Shx147065 if (err != DDI_SUCCESS) { 739*4128Shx147065 dma_p->dma_hdl = NULL; 740*4128Shx147065 return (DDI_FAILURE); 741*4128Shx147065 } 742*4128Shx147065 743*4128Shx147065 /* 744*4128Shx147065 * Allocate memory 745*4128Shx147065 */ 746*4128Shx147065 err = ddi_dma_mem_alloc(dma_p->dma_hdl, memsize, acc_attr_p, 747*4128Shx147065 dma_flags & (DDI_DMA_CONSISTENT | DDI_DMA_STREAMING), 748*4128Shx147065 DDI_DMA_SLEEP, NULL, &vaddr, &dma_p->alength, &dma_p->acc_hdl); 749*4128Shx147065 if (err != DDI_SUCCESS) { 750*4128Shx147065 ddi_dma_free_handle(&dma_p->dma_hdl); 751*4128Shx147065 dma_p->dma_hdl = NULL; 752*4128Shx147065 dma_p->acc_hdl = NULL; 753*4128Shx147065 return (DDI_FAILURE); 754*4128Shx147065 } 755*4128Shx147065 756*4128Shx147065 /* 757*4128Shx147065 * Bind the two together 758*4128Shx147065 */ 759*4128Shx147065 dma_p->mem_va = vaddr; 760*4128Shx147065 err = ddi_dma_addr_bind_handle(dma_p->dma_hdl, NULL, 761*4128Shx147065 vaddr, dma_p->alength, dma_flags, DDI_DMA_SLEEP, NULL, 762*4128Shx147065 &dma_p->cookie, &dma_p->ncookies); 763*4128Shx147065 if (err != DDI_DMA_MAPPED) { 764*4128Shx147065 ddi_dma_mem_free(&dma_p->acc_hdl); 765*4128Shx147065 ddi_dma_free_handle(&dma_p->dma_hdl); 766*4128Shx147065 dma_p->acc_hdl = NULL; 767*4128Shx147065 dma_p->dma_hdl = NULL; 768*4128Shx147065 return (DDI_FAILURE); 769*4128Shx147065 } 770*4128Shx147065 771*4128Shx147065 dma_p->nslots = ~0U; 772*4128Shx147065 dma_p->size = ~0U; 773*4128Shx147065 dma_p->token = ~0U; 774*4128Shx147065 dma_p->offset = 0; 775*4128Shx147065 return (DDI_SUCCESS); 776*4128Shx147065 } 777*4128Shx147065 778*4128Shx147065 /* 779*4128Shx147065 * Free one allocated area of DMAable memory 780*4128Shx147065 */ 781*4128Shx147065 static void 782*4128Shx147065 wpi_free_dma_mem(wpi_dma_t *dma_p) 783*4128Shx147065 { 784*4128Shx147065 if (dma_p->dma_hdl != NULL) { 785*4128Shx147065 if (dma_p->ncookies) { 786*4128Shx147065 (void) ddi_dma_unbind_handle(dma_p->dma_hdl); 787*4128Shx147065 dma_p->ncookies = 0; 788*4128Shx147065 } 789*4128Shx147065 ddi_dma_free_handle(&dma_p->dma_hdl); 790*4128Shx147065 dma_p->dma_hdl = NULL; 791*4128Shx147065 } 792*4128Shx147065 793*4128Shx147065 if (dma_p->acc_hdl != NULL) { 794*4128Shx147065 ddi_dma_mem_free(&dma_p->acc_hdl); 795*4128Shx147065 dma_p->acc_hdl = NULL; 796*4128Shx147065 } 797*4128Shx147065 } 798*4128Shx147065 799*4128Shx147065 /* 800*4128Shx147065 * Allocate an area of dma memory for firmware load. 801*4128Shx147065 * Idealy, this allocation should be a one time action, that is, 802*4128Shx147065 * the memory will be freed after the firmware is uploaded to the 803*4128Shx147065 * card. but since a recovery mechanism for the fatal firmware need 804*4128Shx147065 * reload the firmware, and re-allocate dma at run time may be failed, 805*4128Shx147065 * so we allocate it at attach and keep it in the whole lifecycle of 806*4128Shx147065 * the driver. 807*4128Shx147065 */ 808*4128Shx147065 static int 809*4128Shx147065 wpi_alloc_fw_dma(wpi_sc_t *sc) 810*4128Shx147065 { 811*4128Shx147065 int i, err = DDI_SUCCESS; 812*4128Shx147065 wpi_dma_t *dma_p; 813*4128Shx147065 814*4128Shx147065 err = wpi_alloc_dma_mem(sc, LE_32(sc->sc_hdr->textsz), 815*4128Shx147065 &fw_buffer_dma_attr, &wpi_dma_accattr, 816*4128Shx147065 DDI_DMA_RDWR | DDI_DMA_CONSISTENT, 817*4128Shx147065 &sc->sc_dma_fw_text); 818*4128Shx147065 dma_p = &sc->sc_dma_fw_text; 819*4128Shx147065 WPI_DBG((WPI_DEBUG_DMA, "ncookies:%d addr1:%x size1:%x\n", 820*4128Shx147065 dma_p->ncookies, dma_p->cookie.dmac_address, 821*4128Shx147065 dma_p->cookie.dmac_size)); 822*4128Shx147065 if (err != DDI_SUCCESS) { 823*4128Shx147065 cmn_err(CE_WARN, "wpi_alloc_fw_dma(): failed to alloc" 824*4128Shx147065 "text dma memory"); 825*4128Shx147065 goto fail; 826*4128Shx147065 } 827*4128Shx147065 for (i = 0; i < dma_p->ncookies; i++) { 828*4128Shx147065 sc->sc_fw_text_cookie[i] = dma_p->cookie; 829*4128Shx147065 ddi_dma_nextcookie(dma_p->dma_hdl, &dma_p->cookie); 830*4128Shx147065 } 831*4128Shx147065 err = wpi_alloc_dma_mem(sc, LE_32(sc->sc_hdr->datasz), 832*4128Shx147065 &fw_buffer_dma_attr, &wpi_dma_accattr, 833*4128Shx147065 DDI_DMA_RDWR | DDI_DMA_CONSISTENT, 834*4128Shx147065 &sc->sc_dma_fw_data); 835*4128Shx147065 dma_p = &sc->sc_dma_fw_data; 836*4128Shx147065 WPI_DBG((WPI_DEBUG_DMA, "ncookies:%d addr1:%x size1:%x\n", 837*4128Shx147065 dma_p->ncookies, dma_p->cookie.dmac_address, 838*4128Shx147065 dma_p->cookie.dmac_size)); 839*4128Shx147065 if (err != DDI_SUCCESS) { 840*4128Shx147065 cmn_err(CE_WARN, "wpi_alloc_fw_dma(): failed to alloc" 841*4128Shx147065 "data dma memory"); 842*4128Shx147065 goto fail; 843*4128Shx147065 } 844*4128Shx147065 for (i = 0; i < dma_p->ncookies; i++) { 845*4128Shx147065 sc->sc_fw_data_cookie[i] = dma_p->cookie; 846*4128Shx147065 ddi_dma_nextcookie(dma_p->dma_hdl, &dma_p->cookie); 847*4128Shx147065 } 848*4128Shx147065 fail: 849*4128Shx147065 return (err); 850*4128Shx147065 } 851*4128Shx147065 852*4128Shx147065 static void 853*4128Shx147065 wpi_free_fw_dma(wpi_sc_t *sc) 854*4128Shx147065 { 855*4128Shx147065 wpi_free_dma_mem(&sc->sc_dma_fw_text); 856*4128Shx147065 wpi_free_dma_mem(&sc->sc_dma_fw_data); 857*4128Shx147065 } 858*4128Shx147065 859*4128Shx147065 /* 860*4128Shx147065 * Allocate a shared page between host and NIC. 861*4128Shx147065 */ 862*4128Shx147065 static int 863*4128Shx147065 wpi_alloc_shared(wpi_sc_t *sc) 864*4128Shx147065 { 865*4128Shx147065 int err = DDI_SUCCESS; 866*4128Shx147065 867*4128Shx147065 /* must be aligned on a 4K-page boundary */ 868*4128Shx147065 err = wpi_alloc_dma_mem(sc, sizeof (wpi_shared_t), 869*4128Shx147065 &sh_dma_attr, &wpi_dma_accattr, 870*4128Shx147065 DDI_DMA_RDWR | DDI_DMA_CONSISTENT, 871*4128Shx147065 &sc->sc_dma_sh); 872*4128Shx147065 if (err != DDI_SUCCESS) 873*4128Shx147065 goto fail; 874*4128Shx147065 sc->sc_shared = (wpi_shared_t *)sc->sc_dma_sh.mem_va; 875*4128Shx147065 return (err); 876*4128Shx147065 877*4128Shx147065 fail: 878*4128Shx147065 wpi_free_shared(sc); 879*4128Shx147065 return (err); 880*4128Shx147065 } 881*4128Shx147065 882*4128Shx147065 static void 883*4128Shx147065 wpi_free_shared(wpi_sc_t *sc) 884*4128Shx147065 { 885*4128Shx147065 wpi_free_dma_mem(&sc->sc_dma_sh); 886*4128Shx147065 } 887*4128Shx147065 888*4128Shx147065 static int 889*4128Shx147065 wpi_alloc_rx_ring(wpi_sc_t *sc) 890*4128Shx147065 { 891*4128Shx147065 wpi_rx_ring_t *ring; 892*4128Shx147065 wpi_rx_data_t *data; 893*4128Shx147065 int i, err = DDI_SUCCESS; 894*4128Shx147065 895*4128Shx147065 ring = &sc->sc_rxq; 896*4128Shx147065 ring->cur = 0; 897*4128Shx147065 898*4128Shx147065 err = wpi_alloc_dma_mem(sc, WPI_RX_RING_COUNT * sizeof (uint32_t), 899*4128Shx147065 &ring_desc_dma_attr, &wpi_dma_accattr, 900*4128Shx147065 DDI_DMA_RDWR | DDI_DMA_CONSISTENT, 901*4128Shx147065 &ring->dma_desc); 902*4128Shx147065 if (err != DDI_SUCCESS) { 903*4128Shx147065 WPI_DBG((WPI_DEBUG_DMA, "dma alloc rx ring desc failed\n")); 904*4128Shx147065 goto fail; 905*4128Shx147065 } 906*4128Shx147065 ring->desc = (uint32_t *)ring->dma_desc.mem_va; 907*4128Shx147065 908*4128Shx147065 /* 909*4128Shx147065 * Allocate Rx buffers. 910*4128Shx147065 */ 911*4128Shx147065 for (i = 0; i < WPI_RX_RING_COUNT; i++) { 912*4128Shx147065 data = &ring->data[i]; 913*4128Shx147065 err = wpi_alloc_dma_mem(sc, sc->sc_dmabuf_sz, 914*4128Shx147065 &rx_buffer_dma_attr, &wpi_dma_accattr, 915*4128Shx147065 DDI_DMA_READ | DDI_DMA_STREAMING, 916*4128Shx147065 &data->dma_data); 917*4128Shx147065 if (err != DDI_SUCCESS) { 918*4128Shx147065 WPI_DBG((WPI_DEBUG_DMA, "dma alloc rx ring buf[%d] " 919*4128Shx147065 "failed\n", i)); 920*4128Shx147065 goto fail; 921*4128Shx147065 } 922*4128Shx147065 923*4128Shx147065 ring->desc[i] = LE_32(data->dma_data.cookie.dmac_address); 924*4128Shx147065 } 925*4128Shx147065 926*4128Shx147065 WPI_DMA_SYNC(ring->dma_desc, DDI_DMA_SYNC_FORDEV); 927*4128Shx147065 928*4128Shx147065 return (err); 929*4128Shx147065 930*4128Shx147065 fail: 931*4128Shx147065 wpi_free_rx_ring(sc); 932*4128Shx147065 return (err); 933*4128Shx147065 } 934*4128Shx147065 935*4128Shx147065 static void 936*4128Shx147065 wpi_reset_rx_ring(wpi_sc_t *sc) 937*4128Shx147065 { 938*4128Shx147065 int ntries; 939*4128Shx147065 940*4128Shx147065 wpi_mem_lock(sc); 941*4128Shx147065 942*4128Shx147065 WPI_WRITE(sc, WPI_RX_CONFIG, 0); 943*4128Shx147065 for (ntries = 0; ntries < 2000; ntries++) { 944*4128Shx147065 if (WPI_READ(sc, WPI_RX_STATUS) & WPI_RX_IDLE) 945*4128Shx147065 break; 946*4128Shx147065 DELAY(1000); 947*4128Shx147065 } 948*4128Shx147065 #ifdef DEBUG 949*4128Shx147065 if (ntries == 2000) 950*4128Shx147065 WPI_DBG((WPI_DEBUG_DMA, "timeout resetting Rx ring\n")); 951*4128Shx147065 #endif 952*4128Shx147065 wpi_mem_unlock(sc); 953*4128Shx147065 954*4128Shx147065 sc->sc_rxq.cur = 0; 955*4128Shx147065 } 956*4128Shx147065 957*4128Shx147065 static void 958*4128Shx147065 wpi_free_rx_ring(wpi_sc_t *sc) 959*4128Shx147065 { 960*4128Shx147065 int i; 961*4128Shx147065 962*4128Shx147065 for (i = 0; i < WPI_RX_RING_COUNT; i++) { 963*4128Shx147065 if (sc->sc_rxq.data[i].dma_data.dma_hdl) 964*4128Shx147065 WPI_DMA_SYNC(sc->sc_rxq.data[i].dma_data, 965*4128Shx147065 DDI_DMA_SYNC_FORCPU); 966*4128Shx147065 wpi_free_dma_mem(&sc->sc_rxq.data[i].dma_data); 967*4128Shx147065 } 968*4128Shx147065 969*4128Shx147065 if (sc->sc_rxq.dma_desc.dma_hdl) 970*4128Shx147065 WPI_DMA_SYNC(sc->sc_rxq.dma_desc, DDI_DMA_SYNC_FORDEV); 971*4128Shx147065 wpi_free_dma_mem(&sc->sc_rxq.dma_desc); 972*4128Shx147065 } 973*4128Shx147065 974*4128Shx147065 static int 975*4128Shx147065 wpi_alloc_tx_ring(wpi_sc_t *sc, wpi_tx_ring_t *ring, int count, int qid) 976*4128Shx147065 { 977*4128Shx147065 wpi_tx_data_t *data; 978*4128Shx147065 wpi_tx_desc_t *desc_h; 979*4128Shx147065 uint32_t paddr_desc_h; 980*4128Shx147065 wpi_tx_cmd_t *cmd_h; 981*4128Shx147065 uint32_t paddr_cmd_h; 982*4128Shx147065 int i, err = DDI_SUCCESS; 983*4128Shx147065 984*4128Shx147065 ring->qid = qid; 985*4128Shx147065 ring->count = count; 986*4128Shx147065 ring->queued = 0; 987*4128Shx147065 ring->cur = 0; 988*4128Shx147065 989*4128Shx147065 err = wpi_alloc_dma_mem(sc, count * sizeof (wpi_tx_desc_t), 990*4128Shx147065 &ring_desc_dma_attr, &wpi_dma_accattr, 991*4128Shx147065 DDI_DMA_RDWR | DDI_DMA_CONSISTENT, 992*4128Shx147065 &ring->dma_desc); 993*4128Shx147065 if (err != DDI_SUCCESS) { 994*4128Shx147065 WPI_DBG((WPI_DEBUG_DMA, "dma alloc tx ring desc[%d] failed\n", 995*4128Shx147065 qid)); 996*4128Shx147065 goto fail; 997*4128Shx147065 } 998*4128Shx147065 999*4128Shx147065 /* update shared page with ring's base address */ 1000*4128Shx147065 sc->sc_shared->txbase[qid] = ring->dma_desc.cookie.dmac_address; 1001*4128Shx147065 1002*4128Shx147065 desc_h = (wpi_tx_desc_t *)ring->dma_desc.mem_va; 1003*4128Shx147065 paddr_desc_h = ring->dma_desc.cookie.dmac_address; 1004*4128Shx147065 1005*4128Shx147065 err = wpi_alloc_dma_mem(sc, count * sizeof (wpi_tx_cmd_t), 1006*4128Shx147065 &tx_cmd_dma_attr, &wpi_dma_accattr, 1007*4128Shx147065 DDI_DMA_RDWR | DDI_DMA_CONSISTENT, 1008*4128Shx147065 &ring->dma_cmd); 1009*4128Shx147065 if (err != DDI_SUCCESS) { 1010*4128Shx147065 WPI_DBG((WPI_DEBUG_DMA, "dma alloc tx ring cmd[%d] failed\n", 1011*4128Shx147065 qid)); 1012*4128Shx147065 goto fail; 1013*4128Shx147065 } 1014*4128Shx147065 1015*4128Shx147065 cmd_h = (wpi_tx_cmd_t *)ring->dma_cmd.mem_va; 1016*4128Shx147065 paddr_cmd_h = ring->dma_cmd.cookie.dmac_address; 1017*4128Shx147065 1018*4128Shx147065 /* 1019*4128Shx147065 * Allocate Tx buffers. 1020*4128Shx147065 */ 1021*4128Shx147065 ring->data = kmem_zalloc(sizeof (wpi_tx_data_t) * count, KM_NOSLEEP); 1022*4128Shx147065 if (ring->data == NULL) { 1023*4128Shx147065 WPI_DBG((WPI_DEBUG_DMA, "could not allocate tx data slots\n")); 1024*4128Shx147065 goto fail; 1025*4128Shx147065 } 1026*4128Shx147065 1027*4128Shx147065 for (i = 0; i < count; i++) { 1028*4128Shx147065 data = &ring->data[i]; 1029*4128Shx147065 err = wpi_alloc_dma_mem(sc, sc->sc_dmabuf_sz, 1030*4128Shx147065 &tx_buffer_dma_attr, &wpi_dma_accattr, 1031*4128Shx147065 DDI_DMA_WRITE | DDI_DMA_STREAMING, 1032*4128Shx147065 &data->dma_data); 1033*4128Shx147065 if (err != DDI_SUCCESS) { 1034*4128Shx147065 WPI_DBG((WPI_DEBUG_DMA, "dma alloc tx ring buf[%d] " 1035*4128Shx147065 "failed\n", i)); 1036*4128Shx147065 goto fail; 1037*4128Shx147065 } 1038*4128Shx147065 1039*4128Shx147065 data->desc = desc_h + i; 1040*4128Shx147065 data->paddr_desc = paddr_desc_h + 1041*4128Shx147065 ((caddr_t)data->desc - (caddr_t)desc_h); 1042*4128Shx147065 data->cmd = cmd_h + i; 1043*4128Shx147065 data->paddr_cmd = paddr_cmd_h + 1044*4128Shx147065 ((caddr_t)data->cmd - (caddr_t)cmd_h); 1045*4128Shx147065 } 1046*4128Shx147065 1047*4128Shx147065 return (err); 1048*4128Shx147065 1049*4128Shx147065 fail: 1050*4128Shx147065 if (ring->data) 1051*4128Shx147065 kmem_free(ring->data, sizeof (wpi_tx_data_t) * count); 1052*4128Shx147065 wpi_free_tx_ring(sc, ring); 1053*4128Shx147065 return (err); 1054*4128Shx147065 } 1055*4128Shx147065 1056*4128Shx147065 static void 1057*4128Shx147065 wpi_reset_tx_ring(wpi_sc_t *sc, wpi_tx_ring_t *ring) 1058*4128Shx147065 { 1059*4128Shx147065 wpi_tx_data_t *data; 1060*4128Shx147065 int i, ntries; 1061*4128Shx147065 1062*4128Shx147065 wpi_mem_lock(sc); 1063*4128Shx147065 1064*4128Shx147065 WPI_WRITE(sc, WPI_TX_CONFIG(ring->qid), 0); 1065*4128Shx147065 for (ntries = 0; ntries < 100; ntries++) { 1066*4128Shx147065 if (WPI_READ(sc, WPI_TX_STATUS) & WPI_TX_IDLE(ring->qid)) 1067*4128Shx147065 break; 1068*4128Shx147065 DELAY(10); 1069*4128Shx147065 } 1070*4128Shx147065 #ifdef DEBUG 1071*4128Shx147065 if (ntries == 100 && wpi_dbg_flags > 0) { 1072*4128Shx147065 WPI_DBG((WPI_DEBUG_DMA, "timeout resetting Tx ring %d\n", 1073*4128Shx147065 ring->qid)); 1074*4128Shx147065 } 1075*4128Shx147065 #endif 1076*4128Shx147065 wpi_mem_unlock(sc); 1077*4128Shx147065 1078*4128Shx147065 for (i = 0; i < ring->count; i++) { 1079*4128Shx147065 data = &ring->data[i]; 1080*4128Shx147065 WPI_DMA_SYNC(data->dma_data, DDI_DMA_SYNC_FORDEV); 1081*4128Shx147065 } 1082*4128Shx147065 1083*4128Shx147065 ring->queued = 0; 1084*4128Shx147065 ring->cur = 0; 1085*4128Shx147065 } 1086*4128Shx147065 1087*4128Shx147065 /*ARGSUSED*/ 1088*4128Shx147065 static void 1089*4128Shx147065 wpi_free_tx_ring(wpi_sc_t *sc, wpi_tx_ring_t *ring) 1090*4128Shx147065 { 1091*4128Shx147065 int i; 1092*4128Shx147065 1093*4128Shx147065 if (ring->dma_desc.dma_hdl != NULL) 1094*4128Shx147065 WPI_DMA_SYNC(ring->dma_desc, DDI_DMA_SYNC_FORDEV); 1095*4128Shx147065 wpi_free_dma_mem(&ring->dma_desc); 1096*4128Shx147065 1097*4128Shx147065 if (ring->dma_cmd.dma_hdl != NULL) 1098*4128Shx147065 WPI_DMA_SYNC(ring->dma_cmd, DDI_DMA_SYNC_FORDEV); 1099*4128Shx147065 wpi_free_dma_mem(&ring->dma_cmd); 1100*4128Shx147065 1101*4128Shx147065 if (ring->data != NULL) { 1102*4128Shx147065 for (i = 0; i < ring->count; i++) { 1103*4128Shx147065 if (ring->data[i].dma_data.dma_hdl) 1104*4128Shx147065 WPI_DMA_SYNC(ring->data[i].dma_data, 1105*4128Shx147065 DDI_DMA_SYNC_FORDEV); 1106*4128Shx147065 wpi_free_dma_mem(&ring->data[i].dma_data); 1107*4128Shx147065 } 1108*4128Shx147065 kmem_free(ring->data, ring->count * sizeof (wpi_tx_data_t)); 1109*4128Shx147065 } 1110*4128Shx147065 } 1111*4128Shx147065 1112*4128Shx147065 static int 1113*4128Shx147065 wpi_ring_init(wpi_sc_t *sc) 1114*4128Shx147065 { 1115*4128Shx147065 int i, err = DDI_SUCCESS; 1116*4128Shx147065 1117*4128Shx147065 for (i = 0; i < 4; i++) { 1118*4128Shx147065 err = wpi_alloc_tx_ring(sc, &sc->sc_txq[i], WPI_TX_RING_COUNT, 1119*4128Shx147065 i); 1120*4128Shx147065 if (err != DDI_SUCCESS) 1121*4128Shx147065 goto fail; 1122*4128Shx147065 } 1123*4128Shx147065 err = wpi_alloc_tx_ring(sc, &sc->sc_cmdq, WPI_CMD_RING_COUNT, 4); 1124*4128Shx147065 if (err != DDI_SUCCESS) 1125*4128Shx147065 goto fail; 1126*4128Shx147065 err = wpi_alloc_tx_ring(sc, &sc->sc_svcq, WPI_SVC_RING_COUNT, 5); 1127*4128Shx147065 if (err != DDI_SUCCESS) 1128*4128Shx147065 goto fail; 1129*4128Shx147065 err = wpi_alloc_rx_ring(sc); 1130*4128Shx147065 if (err != DDI_SUCCESS) 1131*4128Shx147065 goto fail; 1132*4128Shx147065 return (err); 1133*4128Shx147065 1134*4128Shx147065 fail: 1135*4128Shx147065 return (err); 1136*4128Shx147065 } 1137*4128Shx147065 1138*4128Shx147065 static void 1139*4128Shx147065 wpi_ring_free(wpi_sc_t *sc) 1140*4128Shx147065 { 1141*4128Shx147065 int i = 4; 1142*4128Shx147065 1143*4128Shx147065 wpi_free_rx_ring(sc); 1144*4128Shx147065 wpi_free_tx_ring(sc, &sc->sc_svcq); 1145*4128Shx147065 wpi_free_tx_ring(sc, &sc->sc_cmdq); 1146*4128Shx147065 while (--i >= 0) { 1147*4128Shx147065 wpi_free_tx_ring(sc, &sc->sc_txq[i]); 1148*4128Shx147065 } 1149*4128Shx147065 } 1150*4128Shx147065 1151*4128Shx147065 /* ARGSUSED */ 1152*4128Shx147065 static ieee80211_node_t * 1153*4128Shx147065 wpi_node_alloc(ieee80211com_t *ic) 1154*4128Shx147065 { 1155*4128Shx147065 wpi_amrr_t *amrr; 1156*4128Shx147065 1157*4128Shx147065 amrr = kmem_zalloc(sizeof (wpi_amrr_t), KM_SLEEP); 1158*4128Shx147065 if (amrr != NULL) 1159*4128Shx147065 wpi_amrr_init(amrr); 1160*4128Shx147065 return (&amrr->in); 1161*4128Shx147065 } 1162*4128Shx147065 1163*4128Shx147065 static void 1164*4128Shx147065 wpi_node_free(ieee80211_node_t *in) 1165*4128Shx147065 { 1166*4128Shx147065 ieee80211com_t *ic = in->in_ic; 1167*4128Shx147065 1168*4128Shx147065 ic->ic_node_cleanup(in); 1169*4128Shx147065 kmem_free(in, sizeof (wpi_amrr_t)); 1170*4128Shx147065 } 1171*4128Shx147065 1172*4128Shx147065 /*ARGSUSED*/ 1173*4128Shx147065 static int 1174*4128Shx147065 wpi_newstate(ieee80211com_t *ic, enum ieee80211_state nstate, int arg) 1175*4128Shx147065 { 1176*4128Shx147065 wpi_sc_t *sc = (wpi_sc_t *)ic; 1177*4128Shx147065 ieee80211_node_t *in = ic->ic_bss; 1178*4128Shx147065 int i, err = WPI_SUCCESS; 1179*4128Shx147065 1180*4128Shx147065 mutex_enter(&sc->sc_glock); 1181*4128Shx147065 switch (nstate) { 1182*4128Shx147065 case IEEE80211_S_SCAN: 1183*4128Shx147065 /* ieee80211_node_table_reset(&ic->ic_scan); */ 1184*4128Shx147065 ic->ic_flags |= IEEE80211_F_SCAN | IEEE80211_F_ASCAN; 1185*4128Shx147065 /* make the link LED blink while we're scanning */ 1186*4128Shx147065 wpi_set_led(sc, WPI_LED_LINK, 20, 2); 1187*4128Shx147065 1188*4128Shx147065 if ((err = wpi_scan(sc)) != 0) { 1189*4128Shx147065 WPI_DBG((WPI_DEBUG_80211, "could not initiate scan\n")); 1190*4128Shx147065 ic->ic_flags &= ~(IEEE80211_F_SCAN | 1191*4128Shx147065 IEEE80211_F_ASCAN); 1192*4128Shx147065 mutex_exit(&sc->sc_glock); 1193*4128Shx147065 return (err); 1194*4128Shx147065 } 1195*4128Shx147065 ic->ic_state = nstate; 1196*4128Shx147065 sc->sc_clk = 0; 1197*4128Shx147065 1198*4128Shx147065 mutex_exit(&sc->sc_glock); 1199*4128Shx147065 return (WPI_SUCCESS); 1200*4128Shx147065 1201*4128Shx147065 case IEEE80211_S_AUTH: 1202*4128Shx147065 /* reset state to handle reassociations correctly */ 1203*4128Shx147065 sc->sc_config.state = 0; 1204*4128Shx147065 sc->sc_config.filter &= ~LE_32(WPI_FILTER_BSS); 1205*4128Shx147065 1206*4128Shx147065 if ((err = wpi_auth(sc)) != 0) { 1207*4128Shx147065 WPI_DBG((WPI_DEBUG_80211, 1208*4128Shx147065 "could not send authentication request\n")); 1209*4128Shx147065 mutex_exit(&sc->sc_glock); 1210*4128Shx147065 return (err); 1211*4128Shx147065 } 1212*4128Shx147065 break; 1213*4128Shx147065 1214*4128Shx147065 case IEEE80211_S_RUN: 1215*4128Shx147065 if (ic->ic_opmode == IEEE80211_M_MONITOR) { 1216*4128Shx147065 /* link LED blinks while monitoring */ 1217*4128Shx147065 wpi_set_led(sc, WPI_LED_LINK, 5, 5); 1218*4128Shx147065 break; 1219*4128Shx147065 } 1220*4128Shx147065 1221*4128Shx147065 if (ic->ic_opmode != IEEE80211_M_STA) { 1222*4128Shx147065 (void) wpi_auth(sc); 1223*4128Shx147065 /* need setup beacon here */ 1224*4128Shx147065 } 1225*4128Shx147065 WPI_DBG((WPI_DEBUG_80211, "wpi: associated.")); 1226*4128Shx147065 1227*4128Shx147065 /* update adapter's configuration */ 1228*4128Shx147065 sc->sc_config.state = LE_16(WPI_CONFIG_ASSOCIATED); 1229*4128Shx147065 /* short preamble/slot time are negotiated when associating */ 1230*4128Shx147065 sc->sc_config.flags &= ~LE_32(WPI_CONFIG_SHPREAMBLE | 1231*4128Shx147065 WPI_CONFIG_SHSLOT); 1232*4128Shx147065 if (ic->ic_flags & IEEE80211_F_SHSLOT) 1233*4128Shx147065 sc->sc_config.flags |= LE_32(WPI_CONFIG_SHSLOT); 1234*4128Shx147065 if (ic->ic_flags & IEEE80211_F_SHPREAMBLE) 1235*4128Shx147065 sc->sc_config.flags |= LE_32(WPI_CONFIG_SHPREAMBLE); 1236*4128Shx147065 sc->sc_config.filter |= LE_32(WPI_FILTER_BSS); 1237*4128Shx147065 if (ic->ic_opmode != IEEE80211_M_STA) 1238*4128Shx147065 sc->sc_config.filter |= LE_32(WPI_FILTER_BEACON); 1239*4128Shx147065 1240*4128Shx147065 WPI_DBG((WPI_DEBUG_80211, "config chan %d flags %x\n", 1241*4128Shx147065 sc->sc_config.chan, sc->sc_config.flags)); 1242*4128Shx147065 err = wpi_cmd(sc, WPI_CMD_CONFIGURE, &sc->sc_config, 1243*4128Shx147065 sizeof (wpi_config_t), 1); 1244*4128Shx147065 if (err != WPI_SUCCESS) { 1245*4128Shx147065 WPI_DBG((WPI_DEBUG_80211, 1246*4128Shx147065 "could not update configuration\n")); 1247*4128Shx147065 mutex_exit(&sc->sc_glock); 1248*4128Shx147065 return (err); 1249*4128Shx147065 } 1250*4128Shx147065 1251*4128Shx147065 /* start automatic rate control */ 1252*4128Shx147065 mutex_enter(&sc->sc_mt_lock); 1253*4128Shx147065 if (ic->ic_fixed_rate == IEEE80211_FIXED_RATE_NONE) { 1254*4128Shx147065 sc->sc_flags |= WPI_F_RATE_AUTO_CTL; 1255*4128Shx147065 /* set rate to some reasonable initial value */ 1256*4128Shx147065 for (i = in->in_rates.ir_nrates - 1; 1257*4128Shx147065 i > 0 && IEEE80211_RATE(i) > 72; i--); 1258*4128Shx147065 in->in_txrate = i; 1259*4128Shx147065 } else { 1260*4128Shx147065 sc->sc_flags &= ~WPI_F_RATE_AUTO_CTL; 1261*4128Shx147065 } 1262*4128Shx147065 mutex_exit(&sc->sc_mt_lock); 1263*4128Shx147065 1264*4128Shx147065 /* link LED always on while associated */ 1265*4128Shx147065 wpi_set_led(sc, WPI_LED_LINK, 0, 1); 1266*4128Shx147065 break; 1267*4128Shx147065 1268*4128Shx147065 case IEEE80211_S_INIT: 1269*4128Shx147065 case IEEE80211_S_ASSOC: 1270*4128Shx147065 break; 1271*4128Shx147065 } 1272*4128Shx147065 1273*4128Shx147065 mutex_exit(&sc->sc_glock); 1274*4128Shx147065 return (sc->sc_newstate(ic, nstate, arg)); 1275*4128Shx147065 } 1276*4128Shx147065 1277*4128Shx147065 /* 1278*4128Shx147065 * Grab exclusive access to NIC memory. 1279*4128Shx147065 */ 1280*4128Shx147065 static void 1281*4128Shx147065 wpi_mem_lock(wpi_sc_t *sc) 1282*4128Shx147065 { 1283*4128Shx147065 uint32_t tmp; 1284*4128Shx147065 int ntries; 1285*4128Shx147065 1286*4128Shx147065 tmp = WPI_READ(sc, WPI_GPIO_CTL); 1287*4128Shx147065 WPI_WRITE(sc, WPI_GPIO_CTL, tmp | WPI_GPIO_MAC); 1288*4128Shx147065 1289*4128Shx147065 /* spin until we actually get the lock */ 1290*4128Shx147065 for (ntries = 0; ntries < 1000; ntries++) { 1291*4128Shx147065 if ((WPI_READ(sc, WPI_GPIO_CTL) & 1292*4128Shx147065 (WPI_GPIO_CLOCK | WPI_GPIO_SLEEP)) == WPI_GPIO_CLOCK) 1293*4128Shx147065 break; 1294*4128Shx147065 DELAY(10); 1295*4128Shx147065 } 1296*4128Shx147065 if (ntries == 1000) 1297*4128Shx147065 WPI_DBG((WPI_DEBUG_PIO, "could not lock memory\n")); 1298*4128Shx147065 } 1299*4128Shx147065 1300*4128Shx147065 /* 1301*4128Shx147065 * Release lock on NIC memory. 1302*4128Shx147065 */ 1303*4128Shx147065 static void 1304*4128Shx147065 wpi_mem_unlock(wpi_sc_t *sc) 1305*4128Shx147065 { 1306*4128Shx147065 uint32_t tmp = WPI_READ(sc, WPI_GPIO_CTL); 1307*4128Shx147065 WPI_WRITE(sc, WPI_GPIO_CTL, tmp & ~WPI_GPIO_MAC); 1308*4128Shx147065 } 1309*4128Shx147065 1310*4128Shx147065 static uint32_t 1311*4128Shx147065 wpi_mem_read(wpi_sc_t *sc, uint16_t addr) 1312*4128Shx147065 { 1313*4128Shx147065 WPI_WRITE(sc, WPI_READ_MEM_ADDR, WPI_MEM_4 | addr); 1314*4128Shx147065 return (WPI_READ(sc, WPI_READ_MEM_DATA)); 1315*4128Shx147065 } 1316*4128Shx147065 1317*4128Shx147065 static void 1318*4128Shx147065 wpi_mem_write(wpi_sc_t *sc, uint16_t addr, uint32_t data) 1319*4128Shx147065 { 1320*4128Shx147065 WPI_WRITE(sc, WPI_WRITE_MEM_ADDR, WPI_MEM_4 | addr); 1321*4128Shx147065 WPI_WRITE(sc, WPI_WRITE_MEM_DATA, data); 1322*4128Shx147065 } 1323*4128Shx147065 1324*4128Shx147065 static void 1325*4128Shx147065 wpi_mem_write_region_4(wpi_sc_t *sc, uint16_t addr, 1326*4128Shx147065 const uint32_t *data, int wlen) 1327*4128Shx147065 { 1328*4128Shx147065 for (; wlen > 0; wlen--, data++, addr += 4) 1329*4128Shx147065 wpi_mem_write(sc, addr, *data); 1330*4128Shx147065 } 1331*4128Shx147065 1332*4128Shx147065 /* 1333*4128Shx147065 * Read 16 bits from the EEPROM. We access EEPROM through the MAC instead of 1334*4128Shx147065 * using the traditional bit-bang method. 1335*4128Shx147065 */ 1336*4128Shx147065 static uint16_t 1337*4128Shx147065 wpi_read_prom_word(wpi_sc_t *sc, uint32_t addr) 1338*4128Shx147065 { 1339*4128Shx147065 uint32_t val; 1340*4128Shx147065 int ntries; 1341*4128Shx147065 1342*4128Shx147065 WPI_WRITE(sc, WPI_EEPROM_CTL, addr << 2); 1343*4128Shx147065 1344*4128Shx147065 wpi_mem_lock(sc); 1345*4128Shx147065 for (ntries = 0; ntries < 10; ntries++) { 1346*4128Shx147065 if ((val = WPI_READ(sc, WPI_EEPROM_CTL)) & WPI_EEPROM_READY) 1347*4128Shx147065 break; 1348*4128Shx147065 DELAY(10); 1349*4128Shx147065 } 1350*4128Shx147065 wpi_mem_unlock(sc); 1351*4128Shx147065 1352*4128Shx147065 if (ntries == 10) { 1353*4128Shx147065 WPI_DBG((WPI_DEBUG_PIO, "could not read EEPROM\n")); 1354*4128Shx147065 return (0xdead); 1355*4128Shx147065 } 1356*4128Shx147065 return (val >> 16); 1357*4128Shx147065 } 1358*4128Shx147065 1359*4128Shx147065 /* 1360*4128Shx147065 * The firmware boot code is small and is intended to be copied directly into 1361*4128Shx147065 * the NIC internal memory. 1362*4128Shx147065 */ 1363*4128Shx147065 static int 1364*4128Shx147065 wpi_load_microcode(wpi_sc_t *sc) 1365*4128Shx147065 { 1366*4128Shx147065 const char *ucode; 1367*4128Shx147065 int size; 1368*4128Shx147065 1369*4128Shx147065 ucode = sc->sc_boot; 1370*4128Shx147065 size = LE_32(sc->sc_hdr->bootsz); 1371*4128Shx147065 /* check that microcode size is a multiple of 4 */ 1372*4128Shx147065 if (size & 3) 1373*4128Shx147065 return (EINVAL); 1374*4128Shx147065 1375*4128Shx147065 size /= sizeof (uint32_t); 1376*4128Shx147065 1377*4128Shx147065 wpi_mem_lock(sc); 1378*4128Shx147065 1379*4128Shx147065 /* copy microcode image into NIC memory */ 1380*4128Shx147065 wpi_mem_write_region_4(sc, WPI_MEM_UCODE_BASE, (const uint32_t *)ucode, 1381*4128Shx147065 size); 1382*4128Shx147065 1383*4128Shx147065 wpi_mem_write(sc, WPI_MEM_UCODE_SRC, 0); 1384*4128Shx147065 wpi_mem_write(sc, WPI_MEM_UCODE_DST, WPI_FW_TEXT); 1385*4128Shx147065 wpi_mem_write(sc, WPI_MEM_UCODE_SIZE, size); 1386*4128Shx147065 1387*4128Shx147065 /* run microcode */ 1388*4128Shx147065 wpi_mem_write(sc, WPI_MEM_UCODE_CTL, WPI_UC_RUN); 1389*4128Shx147065 1390*4128Shx147065 wpi_mem_unlock(sc); 1391*4128Shx147065 1392*4128Shx147065 return (WPI_SUCCESS); 1393*4128Shx147065 } 1394*4128Shx147065 1395*4128Shx147065 /* 1396*4128Shx147065 * The firmware text and data segments are transferred to the NIC using DMA. 1397*4128Shx147065 * The driver just copies the firmware into DMA-safe memory and tells the NIC 1398*4128Shx147065 * where to find it. Once the NIC has copied the firmware into its internal 1399*4128Shx147065 * memory, we can free our local copy in the driver. 1400*4128Shx147065 */ 1401*4128Shx147065 static int 1402*4128Shx147065 wpi_load_firmware(wpi_sc_t *sc, uint32_t target) 1403*4128Shx147065 { 1404*4128Shx147065 const char *fw; 1405*4128Shx147065 int size; 1406*4128Shx147065 wpi_dma_t *dma_p; 1407*4128Shx147065 ddi_dma_cookie_t *cookie; 1408*4128Shx147065 wpi_tx_desc_t desc; 1409*4128Shx147065 int i, ntries, err = WPI_SUCCESS; 1410*4128Shx147065 1411*4128Shx147065 /* only text and data here */ 1412*4128Shx147065 if (target == WPI_FW_TEXT) { 1413*4128Shx147065 fw = sc->sc_text; 1414*4128Shx147065 size = LE_32(sc->sc_hdr->textsz); 1415*4128Shx147065 dma_p = &sc->sc_dma_fw_text; 1416*4128Shx147065 cookie = sc->sc_fw_text_cookie; 1417*4128Shx147065 } else { 1418*4128Shx147065 fw = sc->sc_data; 1419*4128Shx147065 size = LE_32(sc->sc_hdr->datasz); 1420*4128Shx147065 dma_p = &sc->sc_dma_fw_data; 1421*4128Shx147065 cookie = sc->sc_fw_data_cookie; 1422*4128Shx147065 } 1423*4128Shx147065 1424*4128Shx147065 /* copy firmware image to DMA-safe memory */ 1425*4128Shx147065 (void) memcpy(dma_p->mem_va, fw, size); 1426*4128Shx147065 1427*4128Shx147065 /* make sure the adapter will get up-to-date values */ 1428*4128Shx147065 (void) ddi_dma_sync(dma_p->dma_hdl, 0, size, DDI_DMA_SYNC_FORDEV); 1429*4128Shx147065 1430*4128Shx147065 (void) memset(&desc, 0, sizeof (desc)); 1431*4128Shx147065 desc.flags = LE_32(WPI_PAD32(size) << 28 | dma_p->ncookies << 24); 1432*4128Shx147065 for (i = 0; i < dma_p->ncookies; i++) { 1433*4128Shx147065 WPI_DBG((WPI_DEBUG_DMA, "cookie%d addr:%x size:%x\n", 1434*4128Shx147065 i, cookie[i].dmac_address, cookie[i].dmac_size)); 1435*4128Shx147065 desc.segs[i].addr = cookie[i].dmac_address; 1436*4128Shx147065 desc.segs[i].len = (uint32_t)cookie[i].dmac_size; 1437*4128Shx147065 } 1438*4128Shx147065 1439*4128Shx147065 wpi_mem_lock(sc); 1440*4128Shx147065 1441*4128Shx147065 /* tell adapter where to copy image in its internal memory */ 1442*4128Shx147065 WPI_WRITE(sc, WPI_FW_TARGET, target); 1443*4128Shx147065 1444*4128Shx147065 WPI_WRITE(sc, WPI_TX_CONFIG(6), 0); 1445*4128Shx147065 1446*4128Shx147065 /* copy firmware descriptor into NIC memory */ 1447*4128Shx147065 WPI_WRITE_REGION_4(sc, WPI_TX_DESC(6), (uint32_t *)&desc, 1448*4128Shx147065 sizeof desc / sizeof (uint32_t)); 1449*4128Shx147065 1450*4128Shx147065 WPI_WRITE(sc, WPI_TX_CREDIT(6), 0xfffff); 1451*4128Shx147065 WPI_WRITE(sc, WPI_TX_STATE(6), 0x4001); 1452*4128Shx147065 WPI_WRITE(sc, WPI_TX_CONFIG(6), 0x80000001); 1453*4128Shx147065 1454*4128Shx147065 /* wait while the adapter is busy copying the firmware */ 1455*4128Shx147065 for (ntries = 0; ntries < 100; ntries++) { 1456*4128Shx147065 if (WPI_READ(sc, WPI_TX_STATUS) & WPI_TX_IDLE(6)) 1457*4128Shx147065 break; 1458*4128Shx147065 DELAY(1000); 1459*4128Shx147065 } 1460*4128Shx147065 if (ntries == 100) { 1461*4128Shx147065 WPI_DBG((WPI_DEBUG_FW, "timeout transferring firmware\n")); 1462*4128Shx147065 err = ETIMEDOUT; 1463*4128Shx147065 } 1464*4128Shx147065 1465*4128Shx147065 WPI_WRITE(sc, WPI_TX_CREDIT(6), 0); 1466*4128Shx147065 1467*4128Shx147065 wpi_mem_unlock(sc); 1468*4128Shx147065 1469*4128Shx147065 return (err); 1470*4128Shx147065 } 1471*4128Shx147065 1472*4128Shx147065 /*ARGSUSED*/ 1473*4128Shx147065 static void 1474*4128Shx147065 wpi_rx_intr(wpi_sc_t *sc, wpi_rx_desc_t *desc, wpi_rx_data_t *data) 1475*4128Shx147065 { 1476*4128Shx147065 ieee80211com_t *ic = &sc->sc_ic; 1477*4128Shx147065 wpi_rx_ring_t *ring = &sc->sc_rxq; 1478*4128Shx147065 wpi_rx_stat_t *stat; 1479*4128Shx147065 wpi_rx_head_t *head; 1480*4128Shx147065 wpi_rx_tail_t *tail; 1481*4128Shx147065 ieee80211_node_t *in; 1482*4128Shx147065 struct ieee80211_frame *wh; 1483*4128Shx147065 mblk_t *mp; 1484*4128Shx147065 uint16_t len; 1485*4128Shx147065 1486*4128Shx147065 stat = (wpi_rx_stat_t *)(desc + 1); 1487*4128Shx147065 1488*4128Shx147065 if (stat->len > WPI_STAT_MAXLEN) { 1489*4128Shx147065 WPI_DBG((WPI_DEBUG_RX, "invalid rx statistic header\n")); 1490*4128Shx147065 return; 1491*4128Shx147065 } 1492*4128Shx147065 1493*4128Shx147065 head = (wpi_rx_head_t *)((caddr_t)(stat + 1) + stat->len); 1494*4128Shx147065 tail = (wpi_rx_tail_t *)((caddr_t)(head + 1) + LE_16(head->len)); 1495*4128Shx147065 1496*4128Shx147065 len = LE_16(head->len); 1497*4128Shx147065 1498*4128Shx147065 WPI_DBG((WPI_DEBUG_RX, "rx intr: idx=%d len=%d stat len=%d rssi=%d " 1499*4128Shx147065 "rate=%x chan=%d tstamp=%llu", ring->cur, LE_32(desc->len), 1500*4128Shx147065 len, (int8_t)stat->rssi, head->rate, head->chan, 1501*4128Shx147065 LE_64(tail->tstamp))); 1502*4128Shx147065 1503*4128Shx147065 if ((len < 20) || (len > sc->sc_dmabuf_sz)) { 1504*4128Shx147065 sc->sc_rx_err++; 1505*4128Shx147065 return; 1506*4128Shx147065 } 1507*4128Shx147065 1508*4128Shx147065 /* 1509*4128Shx147065 * Discard Rx frames with bad CRC early 1510*4128Shx147065 */ 1511*4128Shx147065 if ((LE_32(tail->flags) & WPI_RX_NOERROR) != WPI_RX_NOERROR) { 1512*4128Shx147065 WPI_DBG((WPI_DEBUG_RX, "rx tail flags error %x\n", 1513*4128Shx147065 LE_32(tail->flags))); 1514*4128Shx147065 sc->sc_rx_err++; 1515*4128Shx147065 return; 1516*4128Shx147065 } 1517*4128Shx147065 1518*4128Shx147065 /* update Rx descriptor */ 1519*4128Shx147065 /* ring->desc[ring->cur] = LE_32(data->dma_data.cookie.dmac_address); */ 1520*4128Shx147065 1521*4128Shx147065 #ifdef WPI_BPF 1522*4128Shx147065 #ifndef WPI_CURRENT 1523*4128Shx147065 if (sc->sc_drvbpf != NULL) { 1524*4128Shx147065 #else 1525*4128Shx147065 if (bpf_peers_present(sc->sc_drvbpf)) { 1526*4128Shx147065 #endif 1527*4128Shx147065 struct wpi_rx_radiotap_header *tap = &sc->sc_rxtap; 1528*4128Shx147065 1529*4128Shx147065 tap->wr_flags = 0; 1530*4128Shx147065 tap->wr_rate = head->rate; 1531*4128Shx147065 tap->wr_chan_freq = 1532*4128Shx147065 LE_16(ic->ic_channels[head->chan].ic_freq); 1533*4128Shx147065 tap->wr_chan_flags = 1534*4128Shx147065 LE_16(ic->ic_channels[head->chan].ic_flags); 1535*4128Shx147065 tap->wr_dbm_antsignal = (int8_t)(stat->rssi - WPI_RSSI_OFFSET); 1536*4128Shx147065 tap->wr_dbm_antnoise = (int8_t)LE_16(stat->noise); 1537*4128Shx147065 tap->wr_tsft = tail->tstamp; 1538*4128Shx147065 tap->wr_antenna = (LE_16(head->flags) >> 4) & 0xf; 1539*4128Shx147065 switch (head->rate) { 1540*4128Shx147065 /* CCK rates */ 1541*4128Shx147065 case 10: tap->wr_rate = 2; break; 1542*4128Shx147065 case 20: tap->wr_rate = 4; break; 1543*4128Shx147065 case 55: tap->wr_rate = 11; break; 1544*4128Shx147065 case 110: tap->wr_rate = 22; break; 1545*4128Shx147065 /* OFDM rates */ 1546*4128Shx147065 case 0xd: tap->wr_rate = 12; break; 1547*4128Shx147065 case 0xf: tap->wr_rate = 18; break; 1548*4128Shx147065 case 0x5: tap->wr_rate = 24; break; 1549*4128Shx147065 case 0x7: tap->wr_rate = 36; break; 1550*4128Shx147065 case 0x9: tap->wr_rate = 48; break; 1551*4128Shx147065 case 0xb: tap->wr_rate = 72; break; 1552*4128Shx147065 case 0x1: tap->wr_rate = 96; break; 1553*4128Shx147065 case 0x3: tap->wr_rate = 108; break; 1554*4128Shx147065 /* unknown rate: should not happen */ 1555*4128Shx147065 default: tap->wr_rate = 0; 1556*4128Shx147065 } 1557*4128Shx147065 if (LE_16(head->flags) & 0x4) 1558*4128Shx147065 tap->wr_flags |= IEEE80211_RADIOTAP_F_SHORTPRE; 1559*4128Shx147065 1560*4128Shx147065 bpf_mtap2(sc->sc_drvbpf, tap, sc->sc_rxtap_len, m); 1561*4128Shx147065 } 1562*4128Shx147065 #endif 1563*4128Shx147065 /* grab a reference to the source node */ 1564*4128Shx147065 wh = (struct ieee80211_frame *)(head + 1); 1565*4128Shx147065 1566*4128Shx147065 #ifdef DEBUG 1567*4128Shx147065 if (wpi_dbg_flags & WPI_DEBUG_RX) 1568*4128Shx147065 ieee80211_dump_pkt((uint8_t *)wh, len, 0, 0); 1569*4128Shx147065 #endif 1570*4128Shx147065 1571*4128Shx147065 in = ieee80211_find_rxnode(ic, wh); 1572*4128Shx147065 mp = allocb(len, BPRI_MED); 1573*4128Shx147065 if (mp) { 1574*4128Shx147065 (void) memcpy(mp->b_wptr, wh, len); 1575*4128Shx147065 mp->b_wptr += len; 1576*4128Shx147065 1577*4128Shx147065 /* send the frame to the 802.11 layer */ 1578*4128Shx147065 (void) ieee80211_input(ic, mp, in, stat->rssi, 0); 1579*4128Shx147065 } else { 1580*4128Shx147065 sc->sc_rx_nobuf++; 1581*4128Shx147065 WPI_DBG((WPI_DEBUG_RX, 1582*4128Shx147065 "wpi_rx_intr(): alloc rx buf failed\n")); 1583*4128Shx147065 } 1584*4128Shx147065 /* release node reference */ 1585*4128Shx147065 ieee80211_free_node(in); 1586*4128Shx147065 } 1587*4128Shx147065 1588*4128Shx147065 /*ARGSUSED*/ 1589*4128Shx147065 static void 1590*4128Shx147065 wpi_tx_intr(wpi_sc_t *sc, wpi_rx_desc_t *desc, wpi_rx_data_t *data) 1591*4128Shx147065 { 1592*4128Shx147065 ieee80211com_t *ic = &sc->sc_ic; 1593*4128Shx147065 wpi_tx_ring_t *ring = &sc->sc_txq[desc->qid & 0x3]; 1594*4128Shx147065 /* wpi_tx_data_t *txdata = &ring->data[desc->idx]; */ 1595*4128Shx147065 wpi_tx_stat_t *stat = (wpi_tx_stat_t *)(desc + 1); 1596*4128Shx147065 wpi_amrr_t *amrr = (wpi_amrr_t *)ic->ic_bss; 1597*4128Shx147065 1598*4128Shx147065 WPI_DBG((WPI_DEBUG_TX, "tx done: qid=%d idx=%d retries=%d nkill=%d " 1599*4128Shx147065 "rate=%x duration=%d status=%x\n", 1600*4128Shx147065 desc->qid, desc->idx, stat->ntries, stat->nkill, stat->rate, 1601*4128Shx147065 LE_32(stat->duration), LE_32(stat->status))); 1602*4128Shx147065 1603*4128Shx147065 amrr->txcnt++; 1604*4128Shx147065 WPI_DBG((WPI_DEBUG_RATECTL, "tx: %d cnt\n", amrr->txcnt)); 1605*4128Shx147065 if (stat->ntries > 0) { 1606*4128Shx147065 amrr->retrycnt++; 1607*4128Shx147065 sc->sc_tx_retries++; 1608*4128Shx147065 WPI_DBG((WPI_DEBUG_RATECTL, "tx: %d retries\n", 1609*4128Shx147065 amrr->retrycnt)); 1610*4128Shx147065 } 1611*4128Shx147065 1612*4128Shx147065 sc->sc_tx_timer = 0; 1613*4128Shx147065 1614*4128Shx147065 mutex_enter(&sc->sc_tx_lock); 1615*4128Shx147065 ring->queued--; 1616*4128Shx147065 if (ring->queued < 0) 1617*4128Shx147065 ring->queued = 0; 1618*4128Shx147065 if ((sc->sc_need_reschedule) && (ring->queued <= (ring->count << 3))) { 1619*4128Shx147065 sc->sc_need_reschedule = 0; 1620*4128Shx147065 mutex_exit(&sc->sc_tx_lock); 1621*4128Shx147065 mac_tx_update(ic->ic_mach); 1622*4128Shx147065 mutex_enter(&sc->sc_tx_lock); 1623*4128Shx147065 } 1624*4128Shx147065 mutex_exit(&sc->sc_tx_lock); 1625*4128Shx147065 } 1626*4128Shx147065 1627*4128Shx147065 static void 1628*4128Shx147065 wpi_cmd_intr(wpi_sc_t *sc, wpi_rx_desc_t *desc) 1629*4128Shx147065 { 1630*4128Shx147065 if ((desc->qid & 7) != 4) { 1631*4128Shx147065 return; /* not a command ack */ 1632*4128Shx147065 } 1633*4128Shx147065 mutex_enter(&sc->sc_glock); 1634*4128Shx147065 sc->sc_flags |= WPI_F_CMD_DONE; 1635*4128Shx147065 cv_signal(&sc->sc_cmd_cv); 1636*4128Shx147065 mutex_exit(&sc->sc_glock); 1637*4128Shx147065 } 1638*4128Shx147065 1639*4128Shx147065 static uint_t 1640*4128Shx147065 wpi_notif_softintr(caddr_t arg) 1641*4128Shx147065 { 1642*4128Shx147065 wpi_sc_t *sc = (wpi_sc_t *)arg; 1643*4128Shx147065 ieee80211com_t *ic = &sc->sc_ic; 1644*4128Shx147065 wpi_rx_desc_t *desc; 1645*4128Shx147065 wpi_rx_data_t *data; 1646*4128Shx147065 uint32_t hw; 1647*4128Shx147065 1648*4128Shx147065 mutex_enter(&sc->sc_glock); 1649*4128Shx147065 if (sc->sc_notif_softint_pending != 1) { 1650*4128Shx147065 mutex_exit(&sc->sc_glock); 1651*4128Shx147065 return (DDI_INTR_UNCLAIMED); 1652*4128Shx147065 } 1653*4128Shx147065 mutex_exit(&sc->sc_glock); 1654*4128Shx147065 1655*4128Shx147065 hw = LE_32(sc->sc_shared->next); 1656*4128Shx147065 1657*4128Shx147065 while (sc->sc_rxq.cur != hw) { 1658*4128Shx147065 data = &sc->sc_rxq.data[sc->sc_rxq.cur]; 1659*4128Shx147065 desc = (wpi_rx_desc_t *)data->dma_data.mem_va; 1660*4128Shx147065 1661*4128Shx147065 WPI_DBG((WPI_DEBUG_INTR, "rx notification hw = %d cur = %d " 1662*4128Shx147065 "qid=%x idx=%d flags=%x type=%d len=%d\n", 1663*4128Shx147065 hw, sc->sc_rxq.cur, desc->qid, desc->idx, desc->flags, 1664*4128Shx147065 desc->type, LE_32(desc->len))); 1665*4128Shx147065 1666*4128Shx147065 if (!(desc->qid & 0x80)) /* reply to a command */ 1667*4128Shx147065 wpi_cmd_intr(sc, desc); 1668*4128Shx147065 1669*4128Shx147065 switch (desc->type) { 1670*4128Shx147065 case WPI_RX_DONE: 1671*4128Shx147065 /* a 802.11 frame was received */ 1672*4128Shx147065 wpi_rx_intr(sc, desc, data); 1673*4128Shx147065 break; 1674*4128Shx147065 1675*4128Shx147065 case WPI_TX_DONE: 1676*4128Shx147065 /* a 802.11 frame has been transmitted */ 1677*4128Shx147065 wpi_tx_intr(sc, desc, data); 1678*4128Shx147065 break; 1679*4128Shx147065 1680*4128Shx147065 case WPI_UC_READY: 1681*4128Shx147065 { 1682*4128Shx147065 wpi_ucode_info_t *uc = 1683*4128Shx147065 (wpi_ucode_info_t *)(desc + 1); 1684*4128Shx147065 1685*4128Shx147065 /* the microcontroller is ready */ 1686*4128Shx147065 WPI_DBG((WPI_DEBUG_FW, 1687*4128Shx147065 "microcode alive notification version %x " 1688*4128Shx147065 "alive %x\n", LE_32(uc->version), 1689*4128Shx147065 LE_32(uc->valid))); 1690*4128Shx147065 1691*4128Shx147065 if (LE_32(uc->valid) != 1) { 1692*4128Shx147065 WPI_DBG((WPI_DEBUG_FW, 1693*4128Shx147065 "microcontroller initialization failed\n")); 1694*4128Shx147065 } 1695*4128Shx147065 break; 1696*4128Shx147065 } 1697*4128Shx147065 case WPI_STATE_CHANGED: 1698*4128Shx147065 { 1699*4128Shx147065 uint32_t *status = (uint32_t *)(desc + 1); 1700*4128Shx147065 1701*4128Shx147065 /* enabled/disabled notification */ 1702*4128Shx147065 WPI_DBG((WPI_DEBUG_RADIO, "state changed to %x\n", 1703*4128Shx147065 LE_32(*status))); 1704*4128Shx147065 1705*4128Shx147065 if (LE_32(*status) & 1) { 1706*4128Shx147065 /* the radio button has to be pushed */ 1707*4128Shx147065 cmn_err(CE_NOTE, 1708*4128Shx147065 "wpi: Radio transmitter is off\n"); 1709*4128Shx147065 } 1710*4128Shx147065 break; 1711*4128Shx147065 } 1712*4128Shx147065 case WPI_START_SCAN: 1713*4128Shx147065 { 1714*4128Shx147065 wpi_start_scan_t *scan = 1715*4128Shx147065 (wpi_start_scan_t *)(desc + 1); 1716*4128Shx147065 1717*4128Shx147065 WPI_DBG((WPI_DEBUG_SCAN, 1718*4128Shx147065 "scanning channel %d status %x\n", 1719*4128Shx147065 scan->chan, LE_32(scan->status))); 1720*4128Shx147065 1721*4128Shx147065 /* fix current channel */ 1722*4128Shx147065 ic->ic_curchan = &ic->ic_sup_channels[scan->chan]; 1723*4128Shx147065 break; 1724*4128Shx147065 } 1725*4128Shx147065 case WPI_STOP_SCAN: 1726*4128Shx147065 WPI_DBG((WPI_DEBUG_SCAN, "scan finished\n")); 1727*4128Shx147065 ieee80211_end_scan(ic); 1728*4128Shx147065 break; 1729*4128Shx147065 } 1730*4128Shx147065 1731*4128Shx147065 sc->sc_rxq.cur = (sc->sc_rxq.cur + 1) % WPI_RX_RING_COUNT; 1732*4128Shx147065 } 1733*4128Shx147065 1734*4128Shx147065 /* tell the firmware what we have processed */ 1735*4128Shx147065 hw = (hw == 0) ? WPI_RX_RING_COUNT - 1 : hw - 1; 1736*4128Shx147065 WPI_WRITE(sc, WPI_RX_WIDX, hw & (~7)); 1737*4128Shx147065 mutex_enter(&sc->sc_glock); 1738*4128Shx147065 sc->sc_notif_softint_pending = 0; 1739*4128Shx147065 mutex_exit(&sc->sc_glock); 1740*4128Shx147065 1741*4128Shx147065 return (DDI_INTR_CLAIMED); 1742*4128Shx147065 } 1743*4128Shx147065 1744*4128Shx147065 static uint_t 1745*4128Shx147065 wpi_intr(caddr_t arg) 1746*4128Shx147065 { 1747*4128Shx147065 wpi_sc_t *sc = (wpi_sc_t *)arg; 1748*4128Shx147065 uint32_t r; 1749*4128Shx147065 1750*4128Shx147065 mutex_enter(&sc->sc_glock); 1751*4128Shx147065 r = WPI_READ(sc, WPI_INTR); 1752*4128Shx147065 if (r == 0 || r == 0xffffffff) { 1753*4128Shx147065 mutex_exit(&sc->sc_glock); 1754*4128Shx147065 return (DDI_INTR_UNCLAIMED); 1755*4128Shx147065 } 1756*4128Shx147065 1757*4128Shx147065 WPI_DBG((WPI_DEBUG_INTR, "interrupt reg %x\n", r)); 1758*4128Shx147065 1759*4128Shx147065 /* disable interrupts */ 1760*4128Shx147065 WPI_WRITE(sc, WPI_MASK, 0); 1761*4128Shx147065 /* ack interrupts */ 1762*4128Shx147065 WPI_WRITE(sc, WPI_INTR, r); 1763*4128Shx147065 1764*4128Shx147065 if (sc->sc_notif_softint_id == NULL) { 1765*4128Shx147065 mutex_exit(&sc->sc_glock); 1766*4128Shx147065 return (DDI_INTR_CLAIMED); 1767*4128Shx147065 } 1768*4128Shx147065 1769*4128Shx147065 if (r & (WPI_SW_ERROR | WPI_HW_ERROR)) { 1770*4128Shx147065 WPI_DBG((WPI_DEBUG_FW, "fatal firmware error\n")); 1771*4128Shx147065 mutex_exit(&sc->sc_glock); 1772*4128Shx147065 wpi_stop(sc); 1773*4128Shx147065 sc->sc_ostate = sc->sc_ic.ic_state; 1774*4128Shx147065 ieee80211_new_state(&sc->sc_ic, IEEE80211_S_INIT, -1); 1775*4128Shx147065 sc->sc_flags |= WPI_F_HW_ERR_RECOVER; 1776*4128Shx147065 return (DDI_INTR_CLAIMED); 1777*4128Shx147065 } 1778*4128Shx147065 1779*4128Shx147065 if (r & WPI_RX_INTR) { 1780*4128Shx147065 sc->sc_notif_softint_pending = 1; 1781*4128Shx147065 ddi_trigger_softintr(sc->sc_notif_softint_id); 1782*4128Shx147065 } 1783*4128Shx147065 1784*4128Shx147065 if (r & WPI_ALIVE_INTR) { /* firmware initialized */ 1785*4128Shx147065 sc->sc_flags |= WPI_F_FW_INIT; 1786*4128Shx147065 cv_signal(&sc->sc_fw_cv); 1787*4128Shx147065 } 1788*4128Shx147065 1789*4128Shx147065 /* re-enable interrupts */ 1790*4128Shx147065 WPI_WRITE(sc, WPI_MASK, WPI_INTR_MASK); 1791*4128Shx147065 mutex_exit(&sc->sc_glock); 1792*4128Shx147065 1793*4128Shx147065 return (DDI_INTR_CLAIMED); 1794*4128Shx147065 } 1795*4128Shx147065 1796*4128Shx147065 static uint8_t 1797*4128Shx147065 wpi_plcp_signal(int rate) 1798*4128Shx147065 { 1799*4128Shx147065 switch (rate) { 1800*4128Shx147065 /* CCK rates (returned values are device-dependent) */ 1801*4128Shx147065 case 2: return (10); 1802*4128Shx147065 case 4: return (20); 1803*4128Shx147065 case 11: return (55); 1804*4128Shx147065 case 22: return (110); 1805*4128Shx147065 1806*4128Shx147065 /* OFDM rates (cf IEEE Std 802.11a-1999, pp. 14 Table 80) */ 1807*4128Shx147065 /* R1-R4 (ral/ural is R4-R1) */ 1808*4128Shx147065 case 12: return (0xd); 1809*4128Shx147065 case 18: return (0xf); 1810*4128Shx147065 case 24: return (0x5); 1811*4128Shx147065 case 36: return (0x7); 1812*4128Shx147065 case 48: return (0x9); 1813*4128Shx147065 case 72: return (0xb); 1814*4128Shx147065 case 96: return (0x1); 1815*4128Shx147065 case 108: return (0x3); 1816*4128Shx147065 1817*4128Shx147065 /* unsupported rates (should not get there) */ 1818*4128Shx147065 default: return (0); 1819*4128Shx147065 } 1820*4128Shx147065 } 1821*4128Shx147065 1822*4128Shx147065 static mblk_t * 1823*4128Shx147065 wpi_m_tx(void *arg, mblk_t *mp) 1824*4128Shx147065 { 1825*4128Shx147065 wpi_sc_t *sc = (wpi_sc_t *)arg; 1826*4128Shx147065 ieee80211com_t *ic = &sc->sc_ic; 1827*4128Shx147065 mblk_t *next; 1828*4128Shx147065 1829*4128Shx147065 if (ic->ic_state != IEEE80211_S_RUN) { 1830*4128Shx147065 freemsgchain(mp); 1831*4128Shx147065 return (NULL); 1832*4128Shx147065 } 1833*4128Shx147065 1834*4128Shx147065 while (mp != NULL) { 1835*4128Shx147065 next = mp->b_next; 1836*4128Shx147065 mp->b_next = NULL; 1837*4128Shx147065 if (wpi_send(ic, mp, IEEE80211_FC0_TYPE_DATA) != 0) { 1838*4128Shx147065 mp->b_next = next; 1839*4128Shx147065 break; 1840*4128Shx147065 } 1841*4128Shx147065 mp = next; 1842*4128Shx147065 } 1843*4128Shx147065 return (mp); 1844*4128Shx147065 } 1845*4128Shx147065 1846*4128Shx147065 /* ARGSUSED */ 1847*4128Shx147065 static int 1848*4128Shx147065 wpi_send(ieee80211com_t *ic, mblk_t *mp, uint8_t type) 1849*4128Shx147065 { 1850*4128Shx147065 wpi_sc_t *sc = (wpi_sc_t *)ic; 1851*4128Shx147065 wpi_tx_ring_t *ring; 1852*4128Shx147065 wpi_tx_desc_t *desc; 1853*4128Shx147065 wpi_tx_data_t *data; 1854*4128Shx147065 wpi_tx_cmd_t *cmd; 1855*4128Shx147065 wpi_cmd_data_t *tx; 1856*4128Shx147065 ieee80211_node_t *in; 1857*4128Shx147065 struct ieee80211_frame *wh; 1858*4128Shx147065 struct ieee80211_key *k; 1859*4128Shx147065 mblk_t *m, *m0; 1860*4128Shx147065 int rate, hdrlen, len, mblen, off, err = WPI_SUCCESS; 1861*4128Shx147065 1862*4128Shx147065 ring = ((type & IEEE80211_FC0_TYPE_MASK) != IEEE80211_FC0_TYPE_DATA) ? 1863*4128Shx147065 (&sc->sc_txq[0]) : (&sc->sc_txq[1]); 1864*4128Shx147065 data = &ring->data[ring->cur]; 1865*4128Shx147065 desc = data->desc; 1866*4128Shx147065 cmd = data->cmd; 1867*4128Shx147065 bzero(desc, sizeof (*desc)); 1868*4128Shx147065 bzero(cmd, sizeof (*cmd)); 1869*4128Shx147065 1870*4128Shx147065 mutex_enter(&sc->sc_tx_lock); 1871*4128Shx147065 if (ring->queued > ring->count - 64) { 1872*4128Shx147065 WPI_DBG((WPI_DEBUG_TX, "wpi_send(): no txbuf\n")); 1873*4128Shx147065 sc->sc_need_reschedule = 1; 1874*4128Shx147065 mutex_exit(&sc->sc_tx_lock); 1875*4128Shx147065 if ((type & IEEE80211_FC0_TYPE_MASK) != 1876*4128Shx147065 IEEE80211_FC0_TYPE_DATA) { 1877*4128Shx147065 freemsg(mp); 1878*4128Shx147065 } 1879*4128Shx147065 sc->sc_tx_nobuf++; 1880*4128Shx147065 err = WPI_FAIL; 1881*4128Shx147065 goto exit; 1882*4128Shx147065 } 1883*4128Shx147065 mutex_exit(&sc->sc_tx_lock); 1884*4128Shx147065 1885*4128Shx147065 hdrlen = sizeof (struct ieee80211_frame); 1886*4128Shx147065 1887*4128Shx147065 m = allocb(msgdsize(mp) + 32, BPRI_MED); 1888*4128Shx147065 if (m == NULL) { /* can not alloc buf, drop this package */ 1889*4128Shx147065 cmn_err(CE_WARN, 1890*4128Shx147065 "wpi_send(): failed to allocate msgbuf\n"); 1891*4128Shx147065 freemsg(mp); 1892*4128Shx147065 err = WPI_SUCCESS; 1893*4128Shx147065 goto exit; 1894*4128Shx147065 } 1895*4128Shx147065 for (off = 0, m0 = mp; m0 != NULL; m0 = m0->b_cont) { 1896*4128Shx147065 mblen = MBLKL(m0); 1897*4128Shx147065 (void) memcpy(m->b_rptr + off, m0->b_rptr, mblen); 1898*4128Shx147065 off += mblen; 1899*4128Shx147065 } 1900*4128Shx147065 m->b_wptr += off; 1901*4128Shx147065 freemsg(mp); 1902*4128Shx147065 1903*4128Shx147065 wh = (struct ieee80211_frame *)m->b_rptr; 1904*4128Shx147065 1905*4128Shx147065 in = ieee80211_find_txnode(ic, wh->i_addr1); 1906*4128Shx147065 if (in == NULL) { 1907*4128Shx147065 cmn_err(CE_WARN, "wpi_send(): failed to find tx node\n"); 1908*4128Shx147065 freemsg(m); 1909*4128Shx147065 sc->sc_tx_err++; 1910*4128Shx147065 err = WPI_SUCCESS; 1911*4128Shx147065 goto exit; 1912*4128Shx147065 } 1913*4128Shx147065 if (wh->i_fc[1] & IEEE80211_FC1_WEP) { 1914*4128Shx147065 k = ieee80211_crypto_encap(ic, m); 1915*4128Shx147065 if (k == NULL) { 1916*4128Shx147065 freemsg(m); 1917*4128Shx147065 sc->sc_tx_err++; 1918*4128Shx147065 err = WPI_SUCCESS; 1919*4128Shx147065 goto exit; 1920*4128Shx147065 } 1921*4128Shx147065 1922*4128Shx147065 /* packet header may have moved, reset our local pointer */ 1923*4128Shx147065 wh = (struct ieee80211_frame *)m->b_rptr; 1924*4128Shx147065 } 1925*4128Shx147065 1926*4128Shx147065 len = msgdsize(m); 1927*4128Shx147065 1928*4128Shx147065 #ifdef DEBUG 1929*4128Shx147065 if (wpi_dbg_flags & WPI_DEBUG_TX) 1930*4128Shx147065 ieee80211_dump_pkt((uint8_t *)wh, hdrlen, 0, 0); 1931*4128Shx147065 #endif 1932*4128Shx147065 1933*4128Shx147065 /* pickup a rate */ 1934*4128Shx147065 if ((wh->i_fc[0] & IEEE80211_FC0_TYPE_MASK) == 1935*4128Shx147065 IEEE80211_FC0_TYPE_MGT) { 1936*4128Shx147065 /* mgmt frames are sent at the lowest available bit-rate */ 1937*4128Shx147065 rate = in->in_rates.ir_rates[0]; 1938*4128Shx147065 } else { 1939*4128Shx147065 if (ic->ic_fixed_rate != IEEE80211_FIXED_RATE_NONE) { 1940*4128Shx147065 rate = ic->ic_fixed_rate; 1941*4128Shx147065 } else 1942*4128Shx147065 rate = in->in_rates.ir_rates[in->in_txrate]; 1943*4128Shx147065 } 1944*4128Shx147065 rate &= IEEE80211_RATE_VAL; 1945*4128Shx147065 WPI_DBG((WPI_DEBUG_RATECTL, "tx rate[%d of %d] = %x", 1946*4128Shx147065 in->in_txrate, in->in_rates.ir_nrates, rate)); 1947*4128Shx147065 #ifdef WPI_BPF 1948*4128Shx147065 #ifndef WPI_CURRENT 1949*4128Shx147065 if (sc->sc_drvbpf != NULL) { 1950*4128Shx147065 #else 1951*4128Shx147065 if (bpf_peers_present(sc->sc_drvbpf)) { 1952*4128Shx147065 #endif 1953*4128Shx147065 struct wpi_tx_radiotap_header *tap = &sc->sc_txtap; 1954*4128Shx147065 1955*4128Shx147065 tap->wt_flags = 0; 1956*4128Shx147065 tap->wt_chan_freq = LE_16(ic->ic_curchan->ic_freq); 1957*4128Shx147065 tap->wt_chan_flags = LE_16(ic->ic_curchan->ic_flags); 1958*4128Shx147065 tap->wt_rate = rate; 1959*4128Shx147065 if (wh->i_fc[1] & IEEE80211_FC1_WEP) 1960*4128Shx147065 tap->wt_flags |= IEEE80211_RADIOTAP_F_WEP; 1961*4128Shx147065 1962*4128Shx147065 bpf_mtap2(sc->sc_drvbpf, tap, sc->sc_txtap_len, m0); 1963*4128Shx147065 } 1964*4128Shx147065 #endif 1965*4128Shx147065 1966*4128Shx147065 cmd->code = WPI_CMD_TX_DATA; 1967*4128Shx147065 cmd->flags = 0; 1968*4128Shx147065 cmd->qid = ring->qid; 1969*4128Shx147065 cmd->idx = ring->cur; 1970*4128Shx147065 1971*4128Shx147065 tx = (wpi_cmd_data_t *)cmd->data; 1972*4128Shx147065 tx->flags = 0; 1973*4128Shx147065 if (!IEEE80211_IS_MULTICAST(wh->i_addr1)) { 1974*4128Shx147065 tx->flags |= LE_32(WPI_TX_NEED_ACK); 1975*4128Shx147065 } else { 1976*4128Shx147065 tx->flags &= ~(LE_32(WPI_TX_NEED_ACK)); 1977*4128Shx147065 } 1978*4128Shx147065 1979*4128Shx147065 tx->flags |= (LE_32(WPI_TX_AUTO_SEQ)); 1980*4128Shx147065 tx->flags |= LE_32(WPI_TX_BT_DISABLE | WPI_TX_CALIBRATION); 1981*4128Shx147065 1982*4128Shx147065 /* retrieve destination node's id */ 1983*4128Shx147065 tx->id = IEEE80211_IS_MULTICAST(wh->i_addr1) ? WPI_ID_BROADCAST : 1984*4128Shx147065 WPI_ID_BSS; 1985*4128Shx147065 1986*4128Shx147065 if ((wh->i_fc[0] & IEEE80211_FC0_TYPE_MASK) == 1987*4128Shx147065 IEEE80211_FC0_TYPE_MGT) { 1988*4128Shx147065 /* tell h/w to set timestamp in probe responses */ 1989*4128Shx147065 if ((wh->i_fc[0] & IEEE80211_FC0_SUBTYPE_MASK) == 1990*4128Shx147065 IEEE80211_FC0_SUBTYPE_PROBE_RESP) 1991*4128Shx147065 tx->flags |= LE_32(WPI_TX_INSERT_TSTAMP); 1992*4128Shx147065 1993*4128Shx147065 if (((wh->i_fc[0] & IEEE80211_FC0_SUBTYPE_MASK) == 1994*4128Shx147065 IEEE80211_FC0_SUBTYPE_ASSOC_REQ) || 1995*4128Shx147065 ((wh->i_fc[0] & IEEE80211_FC0_SUBTYPE_MASK) == 1996*4128Shx147065 IEEE80211_FC0_SUBTYPE_REASSOC_REQ)) 1997*4128Shx147065 tx->timeout = 3; 1998*4128Shx147065 else 1999*4128Shx147065 tx->timeout = 2; 2000*4128Shx147065 } else 2001*4128Shx147065 tx->timeout = 0; 2002*4128Shx147065 2003*4128Shx147065 tx->rate = wpi_plcp_signal(rate); 2004*4128Shx147065 2005*4128Shx147065 /* be very persistant at sending frames out */ 2006*4128Shx147065 tx->rts_ntries = 7; 2007*4128Shx147065 tx->data_ntries = 15; 2008*4128Shx147065 2009*4128Shx147065 tx->cck_mask = 0x0f; 2010*4128Shx147065 tx->ofdm_mask = 0xff; 2011*4128Shx147065 tx->lifetime = LE_32(0xffffffff); 2012*4128Shx147065 2013*4128Shx147065 tx->len = LE_16(len); 2014*4128Shx147065 2015*4128Shx147065 /* save and trim IEEE802.11 header */ 2016*4128Shx147065 (void) memcpy(tx + 1, m->b_rptr, hdrlen); 2017*4128Shx147065 m->b_rptr += hdrlen; 2018*4128Shx147065 (void) memcpy(data->dma_data.mem_va, m->b_rptr, len - hdrlen); 2019*4128Shx147065 2020*4128Shx147065 WPI_DBG((WPI_DEBUG_TX, "sending data: qid=%d idx=%d len=%d", ring->qid, 2021*4128Shx147065 ring->cur, len)); 2022*4128Shx147065 2023*4128Shx147065 /* first scatter/gather segment is used by the tx data command */ 2024*4128Shx147065 desc->flags = LE_32(WPI_PAD32(len) << 28 | (2) << 24); 2025*4128Shx147065 desc->segs[0].addr = LE_32(data->paddr_cmd); 2026*4128Shx147065 desc->segs[0].len = LE_32( 2027*4128Shx147065 roundup(4 + sizeof (wpi_cmd_data_t) + hdrlen, 4)); 2028*4128Shx147065 desc->segs[1].addr = LE_32(data->dma_data.cookie.dmac_address); 2029*4128Shx147065 desc->segs[1].len = LE_32(len - hdrlen); 2030*4128Shx147065 2031*4128Shx147065 WPI_DMA_SYNC(data->dma_data, DDI_DMA_SYNC_FORDEV); 2032*4128Shx147065 WPI_DMA_SYNC(ring->dma_desc, DDI_DMA_SYNC_FORDEV); 2033*4128Shx147065 2034*4128Shx147065 mutex_enter(&sc->sc_tx_lock); 2035*4128Shx147065 ring->queued++; 2036*4128Shx147065 mutex_exit(&sc->sc_tx_lock); 2037*4128Shx147065 2038*4128Shx147065 /* kick ring */ 2039*4128Shx147065 ring->cur = (ring->cur + 1) % WPI_TX_RING_COUNT; 2040*4128Shx147065 WPI_WRITE(sc, WPI_TX_WIDX, ring->qid << 8 | ring->cur); 2041*4128Shx147065 freemsg(m); 2042*4128Shx147065 /* release node reference */ 2043*4128Shx147065 ieee80211_free_node(in); 2044*4128Shx147065 2045*4128Shx147065 ic->ic_stats.is_tx_bytes += len; 2046*4128Shx147065 ic->ic_stats.is_tx_frags++; 2047*4128Shx147065 2048*4128Shx147065 if (sc->sc_tx_timer == 0) 2049*4128Shx147065 sc->sc_tx_timer = 5; 2050*4128Shx147065 exit: 2051*4128Shx147065 return (err); 2052*4128Shx147065 } 2053*4128Shx147065 2054*4128Shx147065 static void 2055*4128Shx147065 wpi_m_ioctl(void* arg, queue_t *wq, mblk_t *mp) 2056*4128Shx147065 { 2057*4128Shx147065 wpi_sc_t *sc = (wpi_sc_t *)arg; 2058*4128Shx147065 ieee80211com_t *ic = &sc->sc_ic; 2059*4128Shx147065 int err; 2060*4128Shx147065 2061*4128Shx147065 err = ieee80211_ioctl(ic, wq, mp); 2062*4128Shx147065 if (err == ENETRESET) { 2063*4128Shx147065 (void) ieee80211_new_state(ic, 2064*4128Shx147065 IEEE80211_S_SCAN, -1); 2065*4128Shx147065 } 2066*4128Shx147065 } 2067*4128Shx147065 2068*4128Shx147065 /*ARGSUSED*/ 2069*4128Shx147065 static int 2070*4128Shx147065 wpi_m_stat(void *arg, uint_t stat, uint64_t *val) 2071*4128Shx147065 { 2072*4128Shx147065 wpi_sc_t *sc = (wpi_sc_t *)arg; 2073*4128Shx147065 ieee80211com_t *ic = &sc->sc_ic; 2074*4128Shx147065 ieee80211_node_t *in = ic->ic_bss; 2075*4128Shx147065 struct ieee80211_rateset *rs = &in->in_rates; 2076*4128Shx147065 2077*4128Shx147065 mutex_enter(&sc->sc_glock); 2078*4128Shx147065 switch (stat) { 2079*4128Shx147065 case MAC_STAT_IFSPEED: 2080*4128Shx147065 *val = ((ic->ic_fixed_rate == IEEE80211_FIXED_RATE_NONE) ? 2081*4128Shx147065 (rs->ir_rates[in->in_txrate] & IEEE80211_RATE_VAL) 2082*4128Shx147065 : ic->ic_fixed_rate) * 5000000ull; 2083*4128Shx147065 break; 2084*4128Shx147065 case MAC_STAT_NOXMTBUF: 2085*4128Shx147065 *val = sc->sc_tx_nobuf; 2086*4128Shx147065 break; 2087*4128Shx147065 case MAC_STAT_NORCVBUF: 2088*4128Shx147065 *val = sc->sc_rx_nobuf; 2089*4128Shx147065 break; 2090*4128Shx147065 case MAC_STAT_IERRORS: 2091*4128Shx147065 *val = sc->sc_rx_err; 2092*4128Shx147065 break; 2093*4128Shx147065 case MAC_STAT_RBYTES: 2094*4128Shx147065 *val = ic->ic_stats.is_rx_bytes; 2095*4128Shx147065 break; 2096*4128Shx147065 case MAC_STAT_IPACKETS: 2097*4128Shx147065 *val = ic->ic_stats.is_rx_frags; 2098*4128Shx147065 break; 2099*4128Shx147065 case MAC_STAT_OBYTES: 2100*4128Shx147065 *val = ic->ic_stats.is_tx_bytes; 2101*4128Shx147065 break; 2102*4128Shx147065 case MAC_STAT_OPACKETS: 2103*4128Shx147065 *val = ic->ic_stats.is_tx_frags; 2104*4128Shx147065 break; 2105*4128Shx147065 case MAC_STAT_OERRORS: 2106*4128Shx147065 case WIFI_STAT_TX_FAILED: 2107*4128Shx147065 *val = sc->sc_tx_err; 2108*4128Shx147065 break; 2109*4128Shx147065 case WIFI_STAT_TX_RETRANS: 2110*4128Shx147065 *val = sc->sc_tx_retries; 2111*4128Shx147065 break; 2112*4128Shx147065 case WIFI_STAT_FCS_ERRORS: 2113*4128Shx147065 case WIFI_STAT_WEP_ERRORS: 2114*4128Shx147065 case WIFI_STAT_TX_FRAGS: 2115*4128Shx147065 case WIFI_STAT_MCAST_TX: 2116*4128Shx147065 case WIFI_STAT_RTS_SUCCESS: 2117*4128Shx147065 case WIFI_STAT_RTS_FAILURE: 2118*4128Shx147065 case WIFI_STAT_ACK_FAILURE: 2119*4128Shx147065 case WIFI_STAT_RX_FRAGS: 2120*4128Shx147065 case WIFI_STAT_MCAST_RX: 2121*4128Shx147065 case WIFI_STAT_RX_DUPS: 2122*4128Shx147065 mutex_exit(&sc->sc_glock); 2123*4128Shx147065 return (ieee80211_stat(ic, stat, val)); 2124*4128Shx147065 default: 2125*4128Shx147065 mutex_exit(&sc->sc_glock); 2126*4128Shx147065 return (ENOTSUP); 2127*4128Shx147065 } 2128*4128Shx147065 mutex_exit(&sc->sc_glock); 2129*4128Shx147065 2130*4128Shx147065 return (WPI_SUCCESS); 2131*4128Shx147065 2132*4128Shx147065 } 2133*4128Shx147065 2134*4128Shx147065 static int 2135*4128Shx147065 wpi_m_start(void *arg) 2136*4128Shx147065 { 2137*4128Shx147065 wpi_sc_t *sc = (wpi_sc_t *)arg; 2138*4128Shx147065 ieee80211com_t *ic = &sc->sc_ic; 2139*4128Shx147065 int err; 2140*4128Shx147065 2141*4128Shx147065 err = wpi_init(sc); 2142*4128Shx147065 if (err != WPI_SUCCESS) { 2143*4128Shx147065 wpi_stop(sc); 2144*4128Shx147065 DELAY(1000000); 2145*4128Shx147065 err = wpi_init(sc); 2146*4128Shx147065 } 2147*4128Shx147065 ieee80211_new_state(ic, IEEE80211_S_INIT, -1); 2148*4128Shx147065 2149*4128Shx147065 return (err); 2150*4128Shx147065 } 2151*4128Shx147065 2152*4128Shx147065 static void 2153*4128Shx147065 wpi_m_stop(void *arg) 2154*4128Shx147065 { 2155*4128Shx147065 wpi_sc_t *sc = (wpi_sc_t *)arg; 2156*4128Shx147065 ieee80211com_t *ic = &sc->sc_ic; 2157*4128Shx147065 2158*4128Shx147065 wpi_stop(sc); 2159*4128Shx147065 ieee80211_new_state(ic, IEEE80211_S_INIT, -1); 2160*4128Shx147065 mutex_enter(&sc->sc_mt_lock); 2161*4128Shx147065 sc->sc_flags &= ~WPI_F_HW_ERR_RECOVER; 2162*4128Shx147065 sc->sc_flags &= ~WPI_F_RATE_AUTO_CTL; 2163*4128Shx147065 mutex_exit(&sc->sc_mt_lock); 2164*4128Shx147065 } 2165*4128Shx147065 2166*4128Shx147065 /*ARGSUSED*/ 2167*4128Shx147065 static int 2168*4128Shx147065 wpi_m_unicst(void *arg, const uint8_t *macaddr) 2169*4128Shx147065 { 2170*4128Shx147065 wpi_sc_t *sc = (wpi_sc_t *)arg; 2171*4128Shx147065 ieee80211com_t *ic = &sc->sc_ic; 2172*4128Shx147065 int err; 2173*4128Shx147065 2174*4128Shx147065 if (!IEEE80211_ADDR_EQ(ic->ic_macaddr, macaddr)) { 2175*4128Shx147065 IEEE80211_ADDR_COPY(ic->ic_macaddr, macaddr); 2176*4128Shx147065 mutex_enter(&sc->sc_glock); 2177*4128Shx147065 err = wpi_config(sc); 2178*4128Shx147065 mutex_exit(&sc->sc_glock); 2179*4128Shx147065 if (err != WPI_SUCCESS) { 2180*4128Shx147065 cmn_err(CE_WARN, 2181*4128Shx147065 "wpi_m_unicst(): " 2182*4128Shx147065 "failed to configure device\n"); 2183*4128Shx147065 goto fail; 2184*4128Shx147065 } 2185*4128Shx147065 } 2186*4128Shx147065 return (WPI_SUCCESS); 2187*4128Shx147065 fail: 2188*4128Shx147065 return (err); 2189*4128Shx147065 } 2190*4128Shx147065 2191*4128Shx147065 /*ARGSUSED*/ 2192*4128Shx147065 static int 2193*4128Shx147065 wpi_m_multicst(void *arg, boolean_t add, const uint8_t *m) 2194*4128Shx147065 { 2195*4128Shx147065 return (WPI_SUCCESS); 2196*4128Shx147065 } 2197*4128Shx147065 2198*4128Shx147065 /*ARGSUSED*/ 2199*4128Shx147065 static int 2200*4128Shx147065 wpi_m_promisc(void *arg, boolean_t on) 2201*4128Shx147065 { 2202*4128Shx147065 return (WPI_SUCCESS); 2203*4128Shx147065 } 2204*4128Shx147065 2205*4128Shx147065 static void 2206*4128Shx147065 wpi_thread(wpi_sc_t *sc) 2207*4128Shx147065 { 2208*4128Shx147065 ieee80211com_t *ic = &sc->sc_ic; 2209*4128Shx147065 clock_t clk; 2210*4128Shx147065 int times = 0, err, n = 0, timeout = 0; 2211*4128Shx147065 2212*4128Shx147065 mutex_enter(&sc->sc_mt_lock); 2213*4128Shx147065 while (sc->sc_mf_thread_switch) { 2214*4128Shx147065 /* 2215*4128Shx147065 * recovery fatal error 2216*4128Shx147065 */ 2217*4128Shx147065 if (ic->ic_mach && 2218*4128Shx147065 (sc->sc_flags & WPI_F_HW_ERR_RECOVER)) { 2219*4128Shx147065 2220*4128Shx147065 WPI_DBG((WPI_DEBUG_FW, 2221*4128Shx147065 "wpi_thread(): " 2222*4128Shx147065 "try to recover fatal hw error: %d\n", times++)); 2223*4128Shx147065 2224*4128Shx147065 wpi_stop(sc); 2225*4128Shx147065 ieee80211_new_state(ic, IEEE80211_S_INIT, -1); 2226*4128Shx147065 2227*4128Shx147065 mutex_exit(&sc->sc_mt_lock); 2228*4128Shx147065 delay(drv_usectohz(2000000)); 2229*4128Shx147065 mutex_enter(&sc->sc_mt_lock); 2230*4128Shx147065 err = wpi_init(sc); 2231*4128Shx147065 if (err != WPI_SUCCESS) { 2232*4128Shx147065 n++; 2233*4128Shx147065 if (n < 3) 2234*4128Shx147065 continue; 2235*4128Shx147065 } 2236*4128Shx147065 n = 0; 2237*4128Shx147065 sc->sc_flags &= ~WPI_F_HW_ERR_RECOVER; 2238*4128Shx147065 mutex_exit(&sc->sc_mt_lock); 2239*4128Shx147065 delay(drv_usectohz(2000000)); 2240*4128Shx147065 if (sc->sc_ostate != IEEE80211_S_INIT) 2241*4128Shx147065 ieee80211_begin_scan(ic, 0); 2242*4128Shx147065 mutex_enter(&sc->sc_mt_lock); 2243*4128Shx147065 } 2244*4128Shx147065 2245*4128Shx147065 /* 2246*4128Shx147065 * rate ctl 2247*4128Shx147065 */ 2248*4128Shx147065 if (ic->ic_mach && 2249*4128Shx147065 (sc->sc_flags & WPI_F_RATE_AUTO_CTL)) { 2250*4128Shx147065 clk = ddi_get_lbolt(); 2251*4128Shx147065 if (clk > sc->sc_clk + drv_usectohz(500000)) { 2252*4128Shx147065 wpi_amrr_timeout(sc); 2253*4128Shx147065 } 2254*4128Shx147065 } 2255*4128Shx147065 mutex_exit(&sc->sc_mt_lock); 2256*4128Shx147065 delay(drv_usectohz(100000)); 2257*4128Shx147065 mutex_enter(&sc->sc_mt_lock); 2258*4128Shx147065 if (sc->sc_tx_timer) { 2259*4128Shx147065 timeout++; 2260*4128Shx147065 if (timeout == 10) { 2261*4128Shx147065 sc->sc_tx_timer--; 2262*4128Shx147065 if (sc->sc_tx_timer == 0) { 2263*4128Shx147065 sc->sc_flags |= WPI_F_HW_ERR_RECOVER; 2264*4128Shx147065 sc->sc_ostate = IEEE80211_S_RUN; 2265*4128Shx147065 } 2266*4128Shx147065 timeout = 0; 2267*4128Shx147065 } 2268*4128Shx147065 } 2269*4128Shx147065 } 2270*4128Shx147065 sc->sc_mf_thread = NULL; 2271*4128Shx147065 cv_signal(&sc->sc_mt_cv); 2272*4128Shx147065 mutex_exit(&sc->sc_mt_lock); 2273*4128Shx147065 } 2274*4128Shx147065 2275*4128Shx147065 /* 2276*4128Shx147065 * Extract various information from EEPROM. 2277*4128Shx147065 */ 2278*4128Shx147065 static void 2279*4128Shx147065 wpi_read_eeprom(wpi_sc_t *sc) 2280*4128Shx147065 { 2281*4128Shx147065 ieee80211com_t *ic = &sc->sc_ic; 2282*4128Shx147065 uint16_t val; 2283*4128Shx147065 int i; 2284*4128Shx147065 2285*4128Shx147065 /* read MAC address */ 2286*4128Shx147065 val = wpi_read_prom_word(sc, WPI_EEPROM_MAC + 0); 2287*4128Shx147065 ic->ic_macaddr[0] = val & 0xff; 2288*4128Shx147065 ic->ic_macaddr[1] = val >> 8; 2289*4128Shx147065 val = wpi_read_prom_word(sc, WPI_EEPROM_MAC + 1); 2290*4128Shx147065 ic->ic_macaddr[2] = val & 0xff; 2291*4128Shx147065 ic->ic_macaddr[3] = val >> 8; 2292*4128Shx147065 val = wpi_read_prom_word(sc, WPI_EEPROM_MAC + 2); 2293*4128Shx147065 ic->ic_macaddr[4] = val & 0xff; 2294*4128Shx147065 ic->ic_macaddr[5] = val >> 8; 2295*4128Shx147065 2296*4128Shx147065 WPI_DBG((WPI_DEBUG_EEPROM, 2297*4128Shx147065 "mac:%2x:%2x:%2x:%2x:%2x:%2x\n", 2298*4128Shx147065 ic->ic_macaddr[0], ic->ic_macaddr[1], 2299*4128Shx147065 ic->ic_macaddr[2], ic->ic_macaddr[3], 2300*4128Shx147065 ic->ic_macaddr[4], ic->ic_macaddr[5])); 2301*4128Shx147065 /* read power settings for 2.4GHz channels */ 2302*4128Shx147065 for (i = 0; i < 14; i++) { 2303*4128Shx147065 sc->sc_pwr1[i] = wpi_read_prom_word(sc, WPI_EEPROM_PWR1 + i); 2304*4128Shx147065 sc->sc_pwr2[i] = wpi_read_prom_word(sc, WPI_EEPROM_PWR2 + i); 2305*4128Shx147065 WPI_DBG((WPI_DEBUG_EEPROM, 2306*4128Shx147065 "channel %d pwr1 0x%04x pwr2 0x%04x\n", i + 1, 2307*4128Shx147065 sc->sc_pwr1[i], sc->sc_pwr2[i])); 2308*4128Shx147065 } 2309*4128Shx147065 } 2310*4128Shx147065 2311*4128Shx147065 /* 2312*4128Shx147065 * Send a command to the firmware. 2313*4128Shx147065 */ 2314*4128Shx147065 static int 2315*4128Shx147065 wpi_cmd(wpi_sc_t *sc, int code, const void *buf, int size, int async) 2316*4128Shx147065 { 2317*4128Shx147065 wpi_tx_ring_t *ring = &sc->sc_cmdq; 2318*4128Shx147065 wpi_tx_desc_t *desc; 2319*4128Shx147065 wpi_tx_cmd_t *cmd; 2320*4128Shx147065 2321*4128Shx147065 ASSERT(size <= sizeof (cmd->data)); 2322*4128Shx147065 ASSERT(mutex_owned(&sc->sc_glock)); 2323*4128Shx147065 2324*4128Shx147065 WPI_DBG((WPI_DEBUG_CMD, "wpi_cmd() # code[%d]", code)); 2325*4128Shx147065 desc = ring->data[ring->cur].desc; 2326*4128Shx147065 cmd = ring->data[ring->cur].cmd; 2327*4128Shx147065 2328*4128Shx147065 cmd->code = (uint8_t)code; 2329*4128Shx147065 cmd->flags = 0; 2330*4128Shx147065 cmd->qid = ring->qid; 2331*4128Shx147065 cmd->idx = ring->cur; 2332*4128Shx147065 (void) memcpy(cmd->data, buf, size); 2333*4128Shx147065 2334*4128Shx147065 desc->flags = LE_32(WPI_PAD32(size) << 28 | 1 << 24); 2335*4128Shx147065 desc->segs[0].addr = ring->data[ring->cur].paddr_cmd; 2336*4128Shx147065 desc->segs[0].len = 4 + size; 2337*4128Shx147065 2338*4128Shx147065 /* kick cmd ring */ 2339*4128Shx147065 ring->cur = (ring->cur + 1) % WPI_CMD_RING_COUNT; 2340*4128Shx147065 WPI_WRITE(sc, WPI_TX_WIDX, ring->qid << 8 | ring->cur); 2341*4128Shx147065 2342*4128Shx147065 if (async) 2343*4128Shx147065 return (WPI_SUCCESS); 2344*4128Shx147065 else { 2345*4128Shx147065 clock_t clk; 2346*4128Shx147065 sc->sc_flags &= ~WPI_F_CMD_DONE; 2347*4128Shx147065 clk = ddi_get_lbolt() + drv_usectohz(2000000); 2348*4128Shx147065 while (!(sc->sc_flags & WPI_F_CMD_DONE)) { 2349*4128Shx147065 if (cv_timedwait(&sc->sc_cmd_cv, &sc->sc_glock, clk) 2350*4128Shx147065 < 0) 2351*4128Shx147065 break; 2352*4128Shx147065 } 2353*4128Shx147065 if (sc->sc_flags & WPI_F_CMD_DONE) 2354*4128Shx147065 return (WPI_SUCCESS); 2355*4128Shx147065 else 2356*4128Shx147065 return (WPI_FAIL); 2357*4128Shx147065 } 2358*4128Shx147065 } 2359*4128Shx147065 2360*4128Shx147065 /* 2361*4128Shx147065 * Configure h/w multi-rate retries. 2362*4128Shx147065 */ 2363*4128Shx147065 static int 2364*4128Shx147065 wpi_mrr_setup(wpi_sc_t *sc) 2365*4128Shx147065 { 2366*4128Shx147065 wpi_mrr_setup_t mrr; 2367*4128Shx147065 int i, err; 2368*4128Shx147065 2369*4128Shx147065 /* CCK rates (not used with 802.11a) */ 2370*4128Shx147065 for (i = WPI_CCK1; i <= WPI_CCK11; i++) { 2371*4128Shx147065 mrr.rates[i].flags = 0; 2372*4128Shx147065 mrr.rates[i].signal = wpi_ridx_to_signal[i]; 2373*4128Shx147065 /* fallback to the immediate lower CCK rate (if any) */ 2374*4128Shx147065 mrr.rates[i].next = (i == WPI_CCK1) ? WPI_CCK1 : i - 1; 2375*4128Shx147065 /* try one time at this rate before falling back to "next" */ 2376*4128Shx147065 mrr.rates[i].ntries = 1; 2377*4128Shx147065 } 2378*4128Shx147065 2379*4128Shx147065 /* OFDM rates (not used with 802.11b) */ 2380*4128Shx147065 for (i = WPI_OFDM6; i <= WPI_OFDM54; i++) { 2381*4128Shx147065 mrr.rates[i].flags = 0; 2382*4128Shx147065 mrr.rates[i].signal = wpi_ridx_to_signal[i]; 2383*4128Shx147065 /* fallback to the immediate lower OFDM rate (if any) */ 2384*4128Shx147065 mrr.rates[i].next = (i == WPI_OFDM6) ? WPI_OFDM6 : i - 1; 2385*4128Shx147065 /* try one time at this rate before falling back to "next" */ 2386*4128Shx147065 mrr.rates[i].ntries = 1; 2387*4128Shx147065 } 2388*4128Shx147065 2389*4128Shx147065 /* setup MRR for control frames */ 2390*4128Shx147065 mrr.which = LE_32(WPI_MRR_CTL); 2391*4128Shx147065 err = wpi_cmd(sc, WPI_CMD_MRR_SETUP, &mrr, sizeof (mrr), 1); 2392*4128Shx147065 if (err != WPI_SUCCESS) { 2393*4128Shx147065 WPI_DBG((WPI_DEBUG_MRR, 2394*4128Shx147065 "could not setup MRR for control frames\n")); 2395*4128Shx147065 return (err); 2396*4128Shx147065 } 2397*4128Shx147065 2398*4128Shx147065 /* setup MRR for data frames */ 2399*4128Shx147065 mrr.which = LE_32(WPI_MRR_DATA); 2400*4128Shx147065 err = wpi_cmd(sc, WPI_CMD_MRR_SETUP, &mrr, sizeof (mrr), 1); 2401*4128Shx147065 if (err != WPI_SUCCESS) { 2402*4128Shx147065 WPI_DBG((WPI_DEBUG_MRR, 2403*4128Shx147065 "could not setup MRR for data frames\n")); 2404*4128Shx147065 return (err); 2405*4128Shx147065 } 2406*4128Shx147065 2407*4128Shx147065 return (WPI_SUCCESS); 2408*4128Shx147065 } 2409*4128Shx147065 2410*4128Shx147065 static void 2411*4128Shx147065 wpi_set_led(wpi_sc_t *sc, uint8_t which, uint8_t off, uint8_t on) 2412*4128Shx147065 { 2413*4128Shx147065 wpi_cmd_led_t led; 2414*4128Shx147065 2415*4128Shx147065 led.which = which; 2416*4128Shx147065 led.unit = LE_32(100000); /* on/off in unit of 100ms */ 2417*4128Shx147065 led.off = off; 2418*4128Shx147065 led.on = on; 2419*4128Shx147065 2420*4128Shx147065 (void) wpi_cmd(sc, WPI_CMD_SET_LED, &led, sizeof (led), 1); 2421*4128Shx147065 } 2422*4128Shx147065 2423*4128Shx147065 static int 2424*4128Shx147065 wpi_auth(wpi_sc_t *sc) 2425*4128Shx147065 { 2426*4128Shx147065 ieee80211com_t *ic = &sc->sc_ic; 2427*4128Shx147065 ieee80211_node_t *in = ic->ic_bss; 2428*4128Shx147065 wpi_node_t node; 2429*4128Shx147065 int err; 2430*4128Shx147065 2431*4128Shx147065 /* update adapter's configuration */ 2432*4128Shx147065 IEEE80211_ADDR_COPY(sc->sc_config.bssid, in->in_bssid); 2433*4128Shx147065 sc->sc_config.chan = ieee80211_chan2ieee(ic, in->in_chan); 2434*4128Shx147065 if (ic->ic_curmode == IEEE80211_MODE_11B) { 2435*4128Shx147065 sc->sc_config.cck_mask = 0x03; 2436*4128Shx147065 sc->sc_config.ofdm_mask = 0; 2437*4128Shx147065 } else if ((in->in_chan != IEEE80211_CHAN_ANYC) && 2438*4128Shx147065 (IEEE80211_IS_CHAN_5GHZ(in->in_chan))) { 2439*4128Shx147065 sc->sc_config.cck_mask = 0; 2440*4128Shx147065 sc->sc_config.ofdm_mask = 0x15; 2441*4128Shx147065 } else { /* assume 802.11b/g */ 2442*4128Shx147065 sc->sc_config.cck_mask = 0x0f; 2443*4128Shx147065 sc->sc_config.ofdm_mask = 0x15; 2444*4128Shx147065 } 2445*4128Shx147065 2446*4128Shx147065 WPI_DBG((WPI_DEBUG_80211, "config chan %d flags %x cck %x ofdm %x" 2447*4128Shx147065 " bssid:%02x:%02x:%02x:%02x:%02x:%2x\n", 2448*4128Shx147065 sc->sc_config.chan, sc->sc_config.flags, 2449*4128Shx147065 sc->sc_config.cck_mask, sc->sc_config.ofdm_mask, 2450*4128Shx147065 sc->sc_config.bssid[0], sc->sc_config.bssid[1], 2451*4128Shx147065 sc->sc_config.bssid[2], sc->sc_config.bssid[3], 2452*4128Shx147065 sc->sc_config.bssid[4], sc->sc_config.bssid[5])); 2453*4128Shx147065 err = wpi_cmd(sc, WPI_CMD_CONFIGURE, &sc->sc_config, 2454*4128Shx147065 sizeof (wpi_config_t), 1); 2455*4128Shx147065 if (err != WPI_SUCCESS) { 2456*4128Shx147065 cmn_err(CE_WARN, "wpi_auth(): failed to configurate chan%d\n", 2457*4128Shx147065 sc->sc_config.chan); 2458*4128Shx147065 return (err); 2459*4128Shx147065 } 2460*4128Shx147065 2461*4128Shx147065 /* add default node */ 2462*4128Shx147065 (void) memset(&node, 0, sizeof (node)); 2463*4128Shx147065 IEEE80211_ADDR_COPY(node.bssid, in->in_bssid); 2464*4128Shx147065 node.id = WPI_ID_BSS; 2465*4128Shx147065 node.rate = wpi_plcp_signal(2); 2466*4128Shx147065 err = wpi_cmd(sc, WPI_CMD_ADD_NODE, &node, sizeof (node), 1); 2467*4128Shx147065 if (err != WPI_SUCCESS) { 2468*4128Shx147065 cmn_err(CE_WARN, "wpi_auth(): failed to add BSS node\n"); 2469*4128Shx147065 return (err); 2470*4128Shx147065 } 2471*4128Shx147065 2472*4128Shx147065 err = wpi_mrr_setup(sc); 2473*4128Shx147065 if (err != WPI_SUCCESS) { 2474*4128Shx147065 cmn_err(CE_WARN, "wpi_auth(): failed to setup MRR\n"); 2475*4128Shx147065 return (err); 2476*4128Shx147065 } 2477*4128Shx147065 2478*4128Shx147065 return (WPI_SUCCESS); 2479*4128Shx147065 } 2480*4128Shx147065 2481*4128Shx147065 /* 2482*4128Shx147065 * Send a scan request to the firmware. 2483*4128Shx147065 */ 2484*4128Shx147065 static int 2485*4128Shx147065 wpi_scan(wpi_sc_t *sc) 2486*4128Shx147065 { 2487*4128Shx147065 ieee80211com_t *ic = &sc->sc_ic; 2488*4128Shx147065 wpi_tx_ring_t *ring = &sc->sc_cmdq; 2489*4128Shx147065 wpi_tx_desc_t *desc; 2490*4128Shx147065 wpi_tx_data_t *data; 2491*4128Shx147065 wpi_tx_cmd_t *cmd; 2492*4128Shx147065 wpi_scan_hdr_t *hdr; 2493*4128Shx147065 wpi_scan_chan_t *chan; 2494*4128Shx147065 struct ieee80211_frame *wh; 2495*4128Shx147065 ieee80211_node_t *in = ic->ic_bss; 2496*4128Shx147065 struct ieee80211_rateset *rs; 2497*4128Shx147065 enum ieee80211_phymode mode; 2498*4128Shx147065 uint8_t *frm; 2499*4128Shx147065 int i, pktlen, nrates; 2500*4128Shx147065 2501*4128Shx147065 data = &ring->data[ring->cur]; 2502*4128Shx147065 desc = data->desc; 2503*4128Shx147065 cmd = (wpi_tx_cmd_t *)data->dma_data.mem_va; 2504*4128Shx147065 2505*4128Shx147065 cmd->code = WPI_CMD_SCAN; 2506*4128Shx147065 cmd->flags = 0; 2507*4128Shx147065 cmd->qid = ring->qid; 2508*4128Shx147065 cmd->idx = ring->cur; 2509*4128Shx147065 2510*4128Shx147065 hdr = (wpi_scan_hdr_t *)cmd->data; 2511*4128Shx147065 (void) memset(hdr, 0, sizeof (wpi_scan_hdr_t)); 2512*4128Shx147065 hdr->first = 1; 2513*4128Shx147065 hdr->nchan = 14; 2514*4128Shx147065 hdr->len = hdr->nchan * sizeof (wpi_scan_chan_t); 2515*4128Shx147065 hdr->quiet = LE_16(5); 2516*4128Shx147065 hdr->threshold = LE_16(1); 2517*4128Shx147065 hdr->filter = LE_32(5); 2518*4128Shx147065 hdr->rate = wpi_plcp_signal(2); 2519*4128Shx147065 hdr->id = WPI_ID_BROADCAST; 2520*4128Shx147065 hdr->mask = LE_32(0xffffffff); 2521*4128Shx147065 hdr->esslen = ic->ic_des_esslen; 2522*4128Shx147065 if (ic->ic_des_esslen) 2523*4128Shx147065 bcopy(ic->ic_des_essid, hdr->essid, ic->ic_des_esslen); 2524*4128Shx147065 else 2525*4128Shx147065 bzero(hdr->essid, sizeof (hdr->essid)); 2526*4128Shx147065 /* 2527*4128Shx147065 * Build a probe request frame. Most of the following code is a 2528*4128Shx147065 * copy & paste of what is done in net80211. Unfortunately, the 2529*4128Shx147065 * functions to add IEs are static and thus can't be reused here. 2530*4128Shx147065 */ 2531*4128Shx147065 wh = (struct ieee80211_frame *)(hdr + 1); 2532*4128Shx147065 wh->i_fc[0] = IEEE80211_FC0_VERSION_0 | IEEE80211_FC0_TYPE_MGT | 2533*4128Shx147065 IEEE80211_FC0_SUBTYPE_PROBE_REQ; 2534*4128Shx147065 wh->i_fc[1] = IEEE80211_FC1_DIR_NODS; 2535*4128Shx147065 (void) memset(wh->i_addr1, 0xff, 6); 2536*4128Shx147065 IEEE80211_ADDR_COPY(wh->i_addr2, ic->ic_macaddr); 2537*4128Shx147065 (void) memset(wh->i_addr3, 0xff, 6); 2538*4128Shx147065 *(uint16_t *)&wh->i_dur[0] = 0; /* filled by h/w */ 2539*4128Shx147065 *(uint16_t *)&wh->i_seq[0] = 0; /* filled by h/w */ 2540*4128Shx147065 2541*4128Shx147065 frm = (uint8_t *)(wh + 1); 2542*4128Shx147065 2543*4128Shx147065 /* add essid IE */ 2544*4128Shx147065 *frm++ = IEEE80211_ELEMID_SSID; 2545*4128Shx147065 *frm++ = in->in_esslen; 2546*4128Shx147065 (void) memcpy(frm, in->in_essid, in->in_esslen); 2547*4128Shx147065 frm += in->in_esslen; 2548*4128Shx147065 2549*4128Shx147065 mode = ieee80211_chan2mode(ic, ic->ic_curchan); 2550*4128Shx147065 rs = &ic->ic_sup_rates[mode]; 2551*4128Shx147065 2552*4128Shx147065 /* add supported rates IE */ 2553*4128Shx147065 *frm++ = IEEE80211_ELEMID_RATES; 2554*4128Shx147065 nrates = rs->ir_nrates; 2555*4128Shx147065 if (nrates > IEEE80211_RATE_SIZE) 2556*4128Shx147065 nrates = IEEE80211_RATE_SIZE; 2557*4128Shx147065 *frm++ = (uint8_t)nrates; 2558*4128Shx147065 (void) memcpy(frm, rs->ir_rates, nrates); 2559*4128Shx147065 frm += nrates; 2560*4128Shx147065 2561*4128Shx147065 /* add supported xrates IE */ 2562*4128Shx147065 if (rs->ir_nrates > IEEE80211_RATE_SIZE) { 2563*4128Shx147065 nrates = rs->ir_nrates - IEEE80211_RATE_SIZE; 2564*4128Shx147065 *frm++ = IEEE80211_ELEMID_XRATES; 2565*4128Shx147065 *frm++ = (uint8_t)nrates; 2566*4128Shx147065 (void) memcpy(frm, rs->ir_rates + IEEE80211_RATE_SIZE, nrates); 2567*4128Shx147065 frm += nrates; 2568*4128Shx147065 } 2569*4128Shx147065 2570*4128Shx147065 /* add optionnal IE (usually an RSN IE) */ 2571*4128Shx147065 if (ic->ic_opt_ie != NULL) { 2572*4128Shx147065 (void) memcpy(frm, ic->ic_opt_ie, ic->ic_opt_ie_len); 2573*4128Shx147065 frm += ic->ic_opt_ie_len; 2574*4128Shx147065 } 2575*4128Shx147065 2576*4128Shx147065 /* setup length of probe request */ 2577*4128Shx147065 hdr->pbrlen = LE_16(frm - (uint8_t *)wh); 2578*4128Shx147065 2579*4128Shx147065 /* align on a 4-byte boundary */ 2580*4128Shx147065 chan = (wpi_scan_chan_t *)frm; 2581*4128Shx147065 for (i = 1; i <= hdr->nchan; i++, chan++) { 2582*4128Shx147065 chan->flags = 3; 2583*4128Shx147065 chan->chan = (uint8_t)i; 2584*4128Shx147065 chan->magic = LE_16(0x62ab); 2585*4128Shx147065 chan->active = LE_16(20); 2586*4128Shx147065 chan->passive = LE_16(120); 2587*4128Shx147065 2588*4128Shx147065 frm += sizeof (wpi_scan_chan_t); 2589*4128Shx147065 } 2590*4128Shx147065 2591*4128Shx147065 pktlen = frm - (uint8_t *)cmd; 2592*4128Shx147065 2593*4128Shx147065 desc->flags = LE_32(WPI_PAD32(pktlen) << 28 | 1 << 24); 2594*4128Shx147065 desc->segs[0].addr = LE_32(data->dma_data.cookie.dmac_address); 2595*4128Shx147065 desc->segs[0].len = LE_32(pktlen); 2596*4128Shx147065 2597*4128Shx147065 WPI_DMA_SYNC(data->dma_data, DDI_DMA_SYNC_FORDEV); 2598*4128Shx147065 WPI_DMA_SYNC(ring->dma_desc, DDI_DMA_SYNC_FORDEV); 2599*4128Shx147065 2600*4128Shx147065 /* kick cmd ring */ 2601*4128Shx147065 ring->cur = (ring->cur + 1) % WPI_CMD_RING_COUNT; 2602*4128Shx147065 WPI_WRITE(sc, WPI_TX_WIDX, ring->qid << 8 | ring->cur); 2603*4128Shx147065 2604*4128Shx147065 return (WPI_SUCCESS); /* will be notified async. of failure/success */ 2605*4128Shx147065 } 2606*4128Shx147065 2607*4128Shx147065 static int 2608*4128Shx147065 wpi_config(wpi_sc_t *sc) 2609*4128Shx147065 { 2610*4128Shx147065 ieee80211com_t *ic = &sc->sc_ic; 2611*4128Shx147065 wpi_txpower_t txpower; 2612*4128Shx147065 wpi_power_t power; 2613*4128Shx147065 #ifdef WPI_BLUE_COEXISTENCE 2614*4128Shx147065 wpi_bluetooth_t bluetooth; 2615*4128Shx147065 #endif 2616*4128Shx147065 wpi_node_t node; 2617*4128Shx147065 int err; 2618*4128Shx147065 2619*4128Shx147065 /* Intel's binary only daemon is a joke.. */ 2620*4128Shx147065 2621*4128Shx147065 /* set Tx power for 2.4GHz channels (values read from EEPROM) */ 2622*4128Shx147065 (void) memset(&txpower, 0, sizeof (txpower)); 2623*4128Shx147065 (void) memcpy(txpower.pwr1, sc->sc_pwr1, 14 * sizeof (uint16_t)); 2624*4128Shx147065 (void) memcpy(txpower.pwr2, sc->sc_pwr2, 14 * sizeof (uint16_t)); 2625*4128Shx147065 err = wpi_cmd(sc, WPI_CMD_TXPOWER, &txpower, sizeof (txpower), 0); 2626*4128Shx147065 if (err != WPI_SUCCESS) { 2627*4128Shx147065 cmn_err(CE_WARN, "wpi_config(): failed to set txpower\n"); 2628*4128Shx147065 return (err); 2629*4128Shx147065 } 2630*4128Shx147065 2631*4128Shx147065 /* set power mode */ 2632*4128Shx147065 (void) memset(&power, 0, sizeof (power)); 2633*4128Shx147065 power.flags = LE_32(0x8); 2634*4128Shx147065 err = wpi_cmd(sc, WPI_CMD_SET_POWER_MODE, &power, sizeof (power), 0); 2635*4128Shx147065 if (err != WPI_SUCCESS) { 2636*4128Shx147065 cmn_err(CE_WARN, "wpi_config(): failed to set power mode\n"); 2637*4128Shx147065 return (err); 2638*4128Shx147065 } 2639*4128Shx147065 #ifdef WPI_BLUE_COEXISTENCE 2640*4128Shx147065 /* configure bluetooth coexistence */ 2641*4128Shx147065 (void) memset(&bluetooth, 0, sizeof (bluetooth)); 2642*4128Shx147065 bluetooth.flags = 3; 2643*4128Shx147065 bluetooth.lead = 0xaa; 2644*4128Shx147065 bluetooth.kill = 1; 2645*4128Shx147065 err = wpi_cmd(sc, WPI_CMD_BLUETOOTH, &bluetooth, 2646*4128Shx147065 sizeof (bluetooth), 0); 2647*4128Shx147065 if (err != WPI_SUCCESS) { 2648*4128Shx147065 cmn_err(CE_WARN, 2649*4128Shx147065 "wpi_config(): " 2650*4128Shx147065 "failed to configurate bluetooth coexistence\n"); 2651*4128Shx147065 return (err); 2652*4128Shx147065 } 2653*4128Shx147065 #endif 2654*4128Shx147065 /* configure adapter */ 2655*4128Shx147065 (void) memset(&sc->sc_config, 0, sizeof (wpi_config_t)); 2656*4128Shx147065 IEEE80211_ADDR_COPY(sc->sc_config.myaddr, ic->ic_macaddr); 2657*4128Shx147065 sc->sc_config.chan = ieee80211_chan2ieee(ic, ic->ic_curchan); 2658*4128Shx147065 sc->sc_config.flags = LE_32(WPI_CONFIG_TSF | WPI_CONFIG_AUTO | 2659*4128Shx147065 WPI_CONFIG_24GHZ); 2660*4128Shx147065 sc->sc_config.filter = 0; 2661*4128Shx147065 switch (ic->ic_opmode) { 2662*4128Shx147065 case IEEE80211_M_STA: 2663*4128Shx147065 sc->sc_config.mode = WPI_MODE_STA; 2664*4128Shx147065 sc->sc_config.filter |= LE_32(WPI_FILTER_MULTICAST | 2665*4128Shx147065 WPI_FILTER_NODECRYPT); 2666*4128Shx147065 break; 2667*4128Shx147065 case IEEE80211_M_IBSS: 2668*4128Shx147065 case IEEE80211_M_AHDEMO: 2669*4128Shx147065 sc->sc_config.mode = WPI_MODE_IBSS; 2670*4128Shx147065 break; 2671*4128Shx147065 case IEEE80211_M_HOSTAP: 2672*4128Shx147065 sc->sc_config.mode = WPI_MODE_HOSTAP; 2673*4128Shx147065 break; 2674*4128Shx147065 case IEEE80211_M_MONITOR: 2675*4128Shx147065 sc->sc_config.mode = WPI_MODE_MONITOR; 2676*4128Shx147065 sc->sc_config.filter |= LE_32(WPI_FILTER_MULTICAST | 2677*4128Shx147065 WPI_FILTER_CTL | WPI_FILTER_PROMISC); 2678*4128Shx147065 break; 2679*4128Shx147065 } 2680*4128Shx147065 sc->sc_config.cck_mask = 0x0f; /* not yet negotiated */ 2681*4128Shx147065 sc->sc_config.ofdm_mask = 0xff; /* not yet negotiated */ 2682*4128Shx147065 err = wpi_cmd(sc, WPI_CMD_CONFIGURE, &sc->sc_config, 2683*4128Shx147065 sizeof (wpi_config_t), 0); 2684*4128Shx147065 if (err != WPI_SUCCESS) { 2685*4128Shx147065 cmn_err(CE_WARN, "wpi_config(): " 2686*4128Shx147065 "failed to set configure command\n"); 2687*4128Shx147065 return (err); 2688*4128Shx147065 } 2689*4128Shx147065 2690*4128Shx147065 /* add broadcast node */ 2691*4128Shx147065 (void) memset(&node, 0, sizeof (node)); 2692*4128Shx147065 (void) memset(node.bssid, 0xff, 6); 2693*4128Shx147065 node.id = WPI_ID_BROADCAST; 2694*4128Shx147065 node.rate = wpi_plcp_signal(2); 2695*4128Shx147065 err = wpi_cmd(sc, WPI_CMD_ADD_NODE, &node, sizeof (node), 0); 2696*4128Shx147065 if (err != WPI_SUCCESS) { 2697*4128Shx147065 cmn_err(CE_WARN, "wpi_config(): " 2698*4128Shx147065 "failed to add broadcast node\n"); 2699*4128Shx147065 return (err); 2700*4128Shx147065 } 2701*4128Shx147065 2702*4128Shx147065 return (WPI_SUCCESS); 2703*4128Shx147065 } 2704*4128Shx147065 2705*4128Shx147065 static void 2706*4128Shx147065 wpi_stop_master(wpi_sc_t *sc) 2707*4128Shx147065 { 2708*4128Shx147065 uint32_t tmp; 2709*4128Shx147065 int ntries; 2710*4128Shx147065 2711*4128Shx147065 tmp = WPI_READ(sc, WPI_RESET); 2712*4128Shx147065 WPI_WRITE(sc, WPI_RESET, tmp | WPI_STOP_MASTER); 2713*4128Shx147065 2714*4128Shx147065 tmp = WPI_READ(sc, WPI_GPIO_CTL); 2715*4128Shx147065 if ((tmp & WPI_GPIO_PWR_STATUS) == WPI_GPIO_PWR_SLEEP) 2716*4128Shx147065 return; /* already asleep */ 2717*4128Shx147065 2718*4128Shx147065 for (ntries = 0; ntries < 2000; ntries++) { 2719*4128Shx147065 if (WPI_READ(sc, WPI_RESET) & WPI_MASTER_DISABLED) 2720*4128Shx147065 break; 2721*4128Shx147065 DELAY(1000); 2722*4128Shx147065 } 2723*4128Shx147065 if (ntries == 2000) 2724*4128Shx147065 WPI_DBG((WPI_DEBUG_HW, "timeout waiting for master\n")); 2725*4128Shx147065 } 2726*4128Shx147065 2727*4128Shx147065 static int 2728*4128Shx147065 wpi_power_up(wpi_sc_t *sc) 2729*4128Shx147065 { 2730*4128Shx147065 uint32_t tmp; 2731*4128Shx147065 int ntries; 2732*4128Shx147065 2733*4128Shx147065 wpi_mem_lock(sc); 2734*4128Shx147065 tmp = wpi_mem_read(sc, WPI_MEM_POWER); 2735*4128Shx147065 wpi_mem_write(sc, WPI_MEM_POWER, tmp & ~0x03000000); 2736*4128Shx147065 wpi_mem_unlock(sc); 2737*4128Shx147065 2738*4128Shx147065 for (ntries = 0; ntries < 5000; ntries++) { 2739*4128Shx147065 if (WPI_READ(sc, WPI_GPIO_STATUS) & WPI_POWERED) 2740*4128Shx147065 break; 2741*4128Shx147065 DELAY(10); 2742*4128Shx147065 } 2743*4128Shx147065 if (ntries == 5000) { 2744*4128Shx147065 cmn_err(CE_WARN, 2745*4128Shx147065 "wpi_power_up(): timeout waiting for NIC to power up\n"); 2746*4128Shx147065 return (ETIMEDOUT); 2747*4128Shx147065 } 2748*4128Shx147065 return (WPI_SUCCESS); 2749*4128Shx147065 } 2750*4128Shx147065 2751*4128Shx147065 static int 2752*4128Shx147065 wpi_reset(wpi_sc_t *sc) 2753*4128Shx147065 { 2754*4128Shx147065 uint32_t tmp; 2755*4128Shx147065 int ntries; 2756*4128Shx147065 2757*4128Shx147065 /* clear any pending interrupts */ 2758*4128Shx147065 WPI_WRITE(sc, WPI_INTR, 0xffffffff); 2759*4128Shx147065 2760*4128Shx147065 tmp = WPI_READ(sc, WPI_PLL_CTL); 2761*4128Shx147065 WPI_WRITE(sc, WPI_PLL_CTL, tmp | WPI_PLL_INIT); 2762*4128Shx147065 2763*4128Shx147065 tmp = WPI_READ(sc, WPI_CHICKEN); 2764*4128Shx147065 WPI_WRITE(sc, WPI_CHICKEN, tmp | WPI_CHICKEN_RXNOLOS); 2765*4128Shx147065 2766*4128Shx147065 tmp = WPI_READ(sc, WPI_GPIO_CTL); 2767*4128Shx147065 WPI_WRITE(sc, WPI_GPIO_CTL, tmp | WPI_GPIO_INIT); 2768*4128Shx147065 2769*4128Shx147065 /* wait for clock stabilization */ 2770*4128Shx147065 for (ntries = 0; ntries < 1000; ntries++) { 2771*4128Shx147065 if (WPI_READ(sc, WPI_GPIO_CTL) & WPI_GPIO_CLOCK) 2772*4128Shx147065 break; 2773*4128Shx147065 DELAY(10); 2774*4128Shx147065 } 2775*4128Shx147065 if (ntries == 1000) { 2776*4128Shx147065 cmn_err(CE_WARN, 2777*4128Shx147065 "wpi_reset(): timeout waiting for clock stabilization\n"); 2778*4128Shx147065 return (ETIMEDOUT); 2779*4128Shx147065 } 2780*4128Shx147065 2781*4128Shx147065 /* initialize EEPROM */ 2782*4128Shx147065 tmp = WPI_READ(sc, WPI_EEPROM_STATUS); 2783*4128Shx147065 if ((tmp & WPI_EEPROM_VERSION) == 0) { 2784*4128Shx147065 cmn_err(CE_WARN, "wpi_reset(): EEPROM not found\n"); 2785*4128Shx147065 return (EIO); 2786*4128Shx147065 } 2787*4128Shx147065 WPI_WRITE(sc, WPI_EEPROM_STATUS, tmp & ~WPI_EEPROM_LOCKED); 2788*4128Shx147065 2789*4128Shx147065 return (WPI_SUCCESS); 2790*4128Shx147065 } 2791*4128Shx147065 2792*4128Shx147065 static void 2793*4128Shx147065 wpi_hw_config(wpi_sc_t *sc) 2794*4128Shx147065 { 2795*4128Shx147065 uint16_t val; 2796*4128Shx147065 uint32_t hw; 2797*4128Shx147065 2798*4128Shx147065 /* voodoo from the Linux "driver".. */ 2799*4128Shx147065 hw = WPI_READ(sc, WPI_HWCONFIG); 2800*4128Shx147065 2801*4128Shx147065 if ((sc->sc_rev & 0xc0) == 0x40) 2802*4128Shx147065 hw |= WPI_HW_ALM_MB; 2803*4128Shx147065 else if (!(sc->sc_rev & 0x80)) 2804*4128Shx147065 hw |= WPI_HW_ALM_MM; 2805*4128Shx147065 2806*4128Shx147065 val = wpi_read_prom_word(sc, WPI_EEPROM_CAPABILITIES); 2807*4128Shx147065 if ((val & 0xff) == 0x80) 2808*4128Shx147065 hw |= WPI_HW_SKU_MRC; 2809*4128Shx147065 2810*4128Shx147065 val = wpi_read_prom_word(sc, WPI_EEPROM_REVISION); 2811*4128Shx147065 hw &= ~WPI_HW_REV_D; 2812*4128Shx147065 if ((val & 0xf0) == 0xd0) 2813*4128Shx147065 hw |= WPI_HW_REV_D; 2814*4128Shx147065 2815*4128Shx147065 val = wpi_read_prom_word(sc, WPI_EEPROM_TYPE); 2816*4128Shx147065 if ((val & 0xff) > 1) 2817*4128Shx147065 hw |= WPI_HW_TYPE_B; 2818*4128Shx147065 2819*4128Shx147065 WPI_DBG((WPI_DEBUG_HW, "setting h/w config %x\n", hw)); 2820*4128Shx147065 WPI_WRITE(sc, WPI_HWCONFIG, hw); 2821*4128Shx147065 } 2822*4128Shx147065 2823*4128Shx147065 static int 2824*4128Shx147065 wpi_init(wpi_sc_t *sc) 2825*4128Shx147065 { 2826*4128Shx147065 uint32_t tmp; 2827*4128Shx147065 int qid, ntries, err; 2828*4128Shx147065 clock_t clk; 2829*4128Shx147065 2830*4128Shx147065 mutex_enter(&sc->sc_glock); 2831*4128Shx147065 sc->sc_flags &= ~WPI_F_FW_INIT; 2832*4128Shx147065 2833*4128Shx147065 (void) wpi_reset(sc); 2834*4128Shx147065 2835*4128Shx147065 wpi_mem_lock(sc); 2836*4128Shx147065 wpi_mem_write(sc, WPI_MEM_CLOCK1, 0xa00); 2837*4128Shx147065 DELAY(20); 2838*4128Shx147065 tmp = wpi_mem_read(sc, WPI_MEM_PCIDEV); 2839*4128Shx147065 wpi_mem_write(sc, WPI_MEM_PCIDEV, tmp | 0x800); 2840*4128Shx147065 wpi_mem_unlock(sc); 2841*4128Shx147065 2842*4128Shx147065 (void) wpi_power_up(sc); 2843*4128Shx147065 wpi_hw_config(sc); 2844*4128Shx147065 2845*4128Shx147065 /* init Rx ring */ 2846*4128Shx147065 wpi_mem_lock(sc); 2847*4128Shx147065 WPI_WRITE(sc, WPI_RX_BASE, sc->sc_rxq.dma_desc.cookie.dmac_address); 2848*4128Shx147065 WPI_WRITE(sc, WPI_RX_RIDX_PTR, 2849*4128Shx147065 (uint32_t)(sc->sc_dma_sh.cookie.dmac_address + 2850*4128Shx147065 offsetof(wpi_shared_t, next))); 2851*4128Shx147065 WPI_WRITE(sc, WPI_RX_WIDX, (WPI_RX_RING_COUNT - 1) & (~7)); 2852*4128Shx147065 WPI_WRITE(sc, WPI_RX_CONFIG, 0xa9601010); 2853*4128Shx147065 wpi_mem_unlock(sc); 2854*4128Shx147065 2855*4128Shx147065 /* init Tx rings */ 2856*4128Shx147065 wpi_mem_lock(sc); 2857*4128Shx147065 wpi_mem_write(sc, WPI_MEM_MODE, 2); /* bypass mode */ 2858*4128Shx147065 wpi_mem_write(sc, WPI_MEM_RA, 1); /* enable RA0 */ 2859*4128Shx147065 wpi_mem_write(sc, WPI_MEM_TXCFG, 0x3f); /* enable all 6 Tx rings */ 2860*4128Shx147065 wpi_mem_write(sc, WPI_MEM_BYPASS1, 0x10000); 2861*4128Shx147065 wpi_mem_write(sc, WPI_MEM_BYPASS2, 0x30002); 2862*4128Shx147065 wpi_mem_write(sc, WPI_MEM_MAGIC4, 4); 2863*4128Shx147065 wpi_mem_write(sc, WPI_MEM_MAGIC5, 5); 2864*4128Shx147065 2865*4128Shx147065 WPI_WRITE(sc, WPI_TX_BASE_PTR, sc->sc_dma_sh.cookie.dmac_address); 2866*4128Shx147065 WPI_WRITE(sc, WPI_MSG_CONFIG, 0xffff05a5); 2867*4128Shx147065 2868*4128Shx147065 for (qid = 0; qid < 6; qid++) { 2869*4128Shx147065 WPI_WRITE(sc, WPI_TX_CTL(qid), 0); 2870*4128Shx147065 WPI_WRITE(sc, WPI_TX_BASE(qid), 0); 2871*4128Shx147065 WPI_WRITE(sc, WPI_TX_CONFIG(qid), 0x80200008); 2872*4128Shx147065 } 2873*4128Shx147065 wpi_mem_unlock(sc); 2874*4128Shx147065 2875*4128Shx147065 /* clear "radio off" and "disable command" bits (reversed logic) */ 2876*4128Shx147065 WPI_WRITE(sc, WPI_UCODE_CLR, WPI_RADIO_OFF); 2877*4128Shx147065 WPI_WRITE(sc, WPI_UCODE_CLR, WPI_DISABLE_CMD); 2878*4128Shx147065 2879*4128Shx147065 /* clear any pending interrupts */ 2880*4128Shx147065 WPI_WRITE(sc, WPI_INTR, 0xffffffff); 2881*4128Shx147065 2882*4128Shx147065 /* enable interrupts */ 2883*4128Shx147065 WPI_WRITE(sc, WPI_MASK, WPI_INTR_MASK); 2884*4128Shx147065 2885*4128Shx147065 /* load firmware boot code into NIC */ 2886*4128Shx147065 err = wpi_load_microcode(sc); 2887*4128Shx147065 if (err != WPI_SUCCESS) { 2888*4128Shx147065 cmn_err(CE_WARN, "wpi_init(): failed to load microcode\n"); 2889*4128Shx147065 goto fail1; 2890*4128Shx147065 } 2891*4128Shx147065 2892*4128Shx147065 /* load firmware .text segment into NIC */ 2893*4128Shx147065 err = wpi_load_firmware(sc, WPI_FW_TEXT); 2894*4128Shx147065 if (err != WPI_SUCCESS) { 2895*4128Shx147065 cmn_err(CE_WARN, "wpi_init(): " 2896*4128Shx147065 "failed to load firmware(text)\n"); 2897*4128Shx147065 goto fail1; 2898*4128Shx147065 } 2899*4128Shx147065 2900*4128Shx147065 /* load firmware .data segment into NIC */ 2901*4128Shx147065 err = wpi_load_firmware(sc, WPI_FW_DATA); 2902*4128Shx147065 if (err != WPI_SUCCESS) { 2903*4128Shx147065 cmn_err(CE_WARN, "wpi_init(): " 2904*4128Shx147065 "failed to load firmware(data)\n"); 2905*4128Shx147065 goto fail1; 2906*4128Shx147065 } 2907*4128Shx147065 2908*4128Shx147065 /* now press "execute" ;-) */ 2909*4128Shx147065 tmp = WPI_READ(sc, WPI_RESET); 2910*4128Shx147065 tmp &= ~(WPI_MASTER_DISABLED | WPI_STOP_MASTER | WPI_NEVO_RESET); 2911*4128Shx147065 WPI_WRITE(sc, WPI_RESET, tmp); 2912*4128Shx147065 2913*4128Shx147065 /* ..and wait at most one second for adapter to initialize */ 2914*4128Shx147065 clk = ddi_get_lbolt() + drv_usectohz(2000000); 2915*4128Shx147065 while (!(sc->sc_flags & WPI_F_FW_INIT)) { 2916*4128Shx147065 if (cv_timedwait(&sc->sc_fw_cv, &sc->sc_glock, clk) < 0) 2917*4128Shx147065 break; 2918*4128Shx147065 } 2919*4128Shx147065 if (!(sc->sc_flags & WPI_F_FW_INIT)) { 2920*4128Shx147065 cmn_err(CE_WARN, 2921*4128Shx147065 "wpi_init(): timeout waiting for firmware init\n"); 2922*4128Shx147065 goto fail1; 2923*4128Shx147065 } 2924*4128Shx147065 2925*4128Shx147065 /* wait for thermal sensors to calibrate */ 2926*4128Shx147065 for (ntries = 0; ntries < 1000; ntries++) { 2927*4128Shx147065 if (WPI_READ(sc, WPI_TEMPERATURE) != 0) 2928*4128Shx147065 break; 2929*4128Shx147065 DELAY(10); 2930*4128Shx147065 } 2931*4128Shx147065 2932*4128Shx147065 if (ntries == 1000) { 2933*4128Shx147065 WPI_DBG((WPI_DEBUG_HW, 2934*4128Shx147065 "wpi_init(): timeout waiting for thermal sensors " 2935*4128Shx147065 "calibration\n")); 2936*4128Shx147065 } 2937*4128Shx147065 2938*4128Shx147065 WPI_DBG((WPI_DEBUG_HW, "temperature %d\n", 2939*4128Shx147065 (int)WPI_READ(sc, WPI_TEMPERATURE))); 2940*4128Shx147065 2941*4128Shx147065 err = wpi_config(sc); 2942*4128Shx147065 if (err) { 2943*4128Shx147065 cmn_err(CE_WARN, "wpi_init(): failed to configure device\n"); 2944*4128Shx147065 goto fail1; 2945*4128Shx147065 } 2946*4128Shx147065 2947*4128Shx147065 mutex_exit(&sc->sc_glock); 2948*4128Shx147065 return (WPI_SUCCESS); 2949*4128Shx147065 2950*4128Shx147065 fail1: 2951*4128Shx147065 err = WPI_FAIL; 2952*4128Shx147065 mutex_exit(&sc->sc_glock); 2953*4128Shx147065 return (err); 2954*4128Shx147065 } 2955*4128Shx147065 2956*4128Shx147065 static void 2957*4128Shx147065 wpi_stop(wpi_sc_t *sc) 2958*4128Shx147065 { 2959*4128Shx147065 uint32_t tmp; 2960*4128Shx147065 int ac; 2961*4128Shx147065 2962*4128Shx147065 2963*4128Shx147065 mutex_enter(&sc->sc_glock); 2964*4128Shx147065 /* disable interrupts */ 2965*4128Shx147065 WPI_WRITE(sc, WPI_MASK, 0); 2966*4128Shx147065 WPI_WRITE(sc, WPI_INTR, WPI_INTR_MASK); 2967*4128Shx147065 WPI_WRITE(sc, WPI_INTR_STATUS, 0xff); 2968*4128Shx147065 WPI_WRITE(sc, WPI_INTR_STATUS, 0x00070000); 2969*4128Shx147065 2970*4128Shx147065 wpi_mem_lock(sc); 2971*4128Shx147065 wpi_mem_write(sc, WPI_MEM_MODE, 0); 2972*4128Shx147065 wpi_mem_unlock(sc); 2973*4128Shx147065 2974*4128Shx147065 /* reset all Tx rings */ 2975*4128Shx147065 for (ac = 0; ac < 4; ac++) 2976*4128Shx147065 wpi_reset_tx_ring(sc, &sc->sc_txq[ac]); 2977*4128Shx147065 wpi_reset_tx_ring(sc, &sc->sc_cmdq); 2978*4128Shx147065 wpi_reset_tx_ring(sc, &sc->sc_svcq); 2979*4128Shx147065 2980*4128Shx147065 /* reset Rx ring */ 2981*4128Shx147065 wpi_reset_rx_ring(sc); 2982*4128Shx147065 2983*4128Shx147065 wpi_mem_lock(sc); 2984*4128Shx147065 wpi_mem_write(sc, WPI_MEM_CLOCK2, 0x200); 2985*4128Shx147065 wpi_mem_unlock(sc); 2986*4128Shx147065 2987*4128Shx147065 DELAY(5); 2988*4128Shx147065 2989*4128Shx147065 wpi_stop_master(sc); 2990*4128Shx147065 2991*4128Shx147065 sc->sc_tx_timer = 0; 2992*4128Shx147065 tmp = WPI_READ(sc, WPI_RESET); 2993*4128Shx147065 WPI_WRITE(sc, WPI_RESET, tmp | WPI_SW_RESET); 2994*4128Shx147065 mutex_exit(&sc->sc_glock); 2995*4128Shx147065 } 2996*4128Shx147065 2997*4128Shx147065 /* 2998*4128Shx147065 * Naive implementation of the Adaptive Multi Rate Retry algorithm: 2999*4128Shx147065 * "IEEE 802.11 Rate Adaptation: A Practical Approach" 3000*4128Shx147065 * Mathieu Lacage, Hossein Manshaei, Thierry Turletti 3001*4128Shx147065 * INRIA Sophia - Projet Planete 3002*4128Shx147065 * http://www-sop.inria.fr/rapports/sophia/RR-5208.html 3003*4128Shx147065 */ 3004*4128Shx147065 #define is_success(amrr) \ 3005*4128Shx147065 ((amrr)->retrycnt < (amrr)->txcnt / 10) 3006*4128Shx147065 #define is_failure(amrr) \ 3007*4128Shx147065 ((amrr)->retrycnt > (amrr)->txcnt / 3) 3008*4128Shx147065 #define is_enough(amrr) \ 3009*4128Shx147065 ((amrr)->txcnt > 100) 3010*4128Shx147065 #define is_min_rate(in) \ 3011*4128Shx147065 ((in)->in_txrate == 0) 3012*4128Shx147065 #define is_max_rate(in) \ 3013*4128Shx147065 ((in)->in_txrate == (in)->in_rates.ir_nrates - 1) 3014*4128Shx147065 #define increase_rate(in) \ 3015*4128Shx147065 ((in)->in_txrate++) 3016*4128Shx147065 #define decrease_rate(in) \ 3017*4128Shx147065 ((in)->in_txrate--) 3018*4128Shx147065 #define reset_cnt(amrr) \ 3019*4128Shx147065 { (amrr)->txcnt = (amrr)->retrycnt = 0; } 3020*4128Shx147065 3021*4128Shx147065 #define WPI_AMRR_MIN_SUCCESS_THRESHOLD 1 3022*4128Shx147065 #define WPI_AMRR_MAX_SUCCESS_THRESHOLD 15 3023*4128Shx147065 3024*4128Shx147065 static void 3025*4128Shx147065 wpi_amrr_init(wpi_amrr_t *amrr) 3026*4128Shx147065 { 3027*4128Shx147065 amrr->success = 0; 3028*4128Shx147065 amrr->recovery = 0; 3029*4128Shx147065 amrr->txcnt = amrr->retrycnt = 0; 3030*4128Shx147065 amrr->success_threshold = WPI_AMRR_MIN_SUCCESS_THRESHOLD; 3031*4128Shx147065 } 3032*4128Shx147065 3033*4128Shx147065 static void 3034*4128Shx147065 wpi_amrr_timeout(wpi_sc_t *sc) 3035*4128Shx147065 { 3036*4128Shx147065 ieee80211com_t *ic = &sc->sc_ic; 3037*4128Shx147065 3038*4128Shx147065 WPI_DBG((WPI_DEBUG_RATECTL, "wpi_amrr_timeout() enter\n")); 3039*4128Shx147065 if (ic->ic_opmode == IEEE80211_M_STA) 3040*4128Shx147065 wpi_amrr_ratectl(NULL, ic->ic_bss); 3041*4128Shx147065 else 3042*4128Shx147065 ieee80211_iterate_nodes(&ic->ic_sta, wpi_amrr_ratectl, NULL); 3043*4128Shx147065 sc->sc_clk = ddi_get_lbolt(); 3044*4128Shx147065 } 3045*4128Shx147065 3046*4128Shx147065 /* ARGSUSED */ 3047*4128Shx147065 static void 3048*4128Shx147065 wpi_amrr_ratectl(void *arg, ieee80211_node_t *in) 3049*4128Shx147065 { 3050*4128Shx147065 wpi_amrr_t *amrr = (wpi_amrr_t *)in; 3051*4128Shx147065 int need_change = 0; 3052*4128Shx147065 3053*4128Shx147065 if (is_success(amrr) && is_enough(amrr)) { 3054*4128Shx147065 amrr->success++; 3055*4128Shx147065 if (amrr->success >= amrr->success_threshold && 3056*4128Shx147065 !is_max_rate(in)) { 3057*4128Shx147065 amrr->recovery = 1; 3058*4128Shx147065 amrr->success = 0; 3059*4128Shx147065 increase_rate(in); 3060*4128Shx147065 WPI_DBG((WPI_DEBUG_RATECTL, 3061*4128Shx147065 "AMRR increasing rate %d (txcnt=%d retrycnt=%d)\n", 3062*4128Shx147065 in->in_txrate, amrr->txcnt, amrr->retrycnt)); 3063*4128Shx147065 need_change = 1; 3064*4128Shx147065 } else { 3065*4128Shx147065 amrr->recovery = 0; 3066*4128Shx147065 } 3067*4128Shx147065 } else if (is_failure(amrr)) { 3068*4128Shx147065 amrr->success = 0; 3069*4128Shx147065 if (!is_min_rate(in)) { 3070*4128Shx147065 if (amrr->recovery) { 3071*4128Shx147065 amrr->success_threshold++; 3072*4128Shx147065 if (amrr->success_threshold > 3073*4128Shx147065 WPI_AMRR_MAX_SUCCESS_THRESHOLD) 3074*4128Shx147065 amrr->success_threshold = 3075*4128Shx147065 WPI_AMRR_MAX_SUCCESS_THRESHOLD; 3076*4128Shx147065 } else { 3077*4128Shx147065 amrr->success_threshold = 3078*4128Shx147065 WPI_AMRR_MIN_SUCCESS_THRESHOLD; 3079*4128Shx147065 } 3080*4128Shx147065 decrease_rate(in); 3081*4128Shx147065 WPI_DBG((WPI_DEBUG_RATECTL, 3082*4128Shx147065 "AMRR decreasing rate %d (txcnt=%d retrycnt=%d)\n", 3083*4128Shx147065 in->in_txrate, amrr->txcnt, amrr->retrycnt)); 3084*4128Shx147065 need_change = 1; 3085*4128Shx147065 } 3086*4128Shx147065 amrr->recovery = 0; /* paper is incorrect */ 3087*4128Shx147065 } 3088*4128Shx147065 3089*4128Shx147065 if (is_enough(amrr) || need_change) 3090*4128Shx147065 reset_cnt(amrr); 3091*4128Shx147065 } 3092