1 /* 2 * Copyright 2009 Sun Microsystems, Inc. All rights reserved. 3 * Use is subject to license terms. 4 */ 5 6 /* 7 * Copyright (c) 2009, Intel Corporation 8 * All rights reserved. 9 */ 10 11 /* 12 * Copyright (c) 2006 13 * Copyright (c) 2007 14 * Damien Bergamini <damien.bergamini@free.fr> 15 * 16 * Permission to use, copy, modify, and distribute this software for any 17 * purpose with or without fee is hereby granted, provided that the above 18 * copyright notice and this permission notice appear in all copies. 19 * 20 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 21 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 22 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 23 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 24 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 25 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 26 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 27 */ 28 29 /* 30 * Intel(R) WiFi Link 5100/5300 Driver 31 */ 32 33 #include <sys/types.h> 34 #include <sys/byteorder.h> 35 #include <sys/conf.h> 36 #include <sys/cmn_err.h> 37 #include <sys/stat.h> 38 #include <sys/ddi.h> 39 #include <sys/sunddi.h> 40 #include <sys/strsubr.h> 41 #include <sys/ethernet.h> 42 #include <inet/common.h> 43 #include <inet/nd.h> 44 #include <inet/mi.h> 45 #include <sys/note.h> 46 #include <sys/stream.h> 47 #include <sys/strsun.h> 48 #include <sys/modctl.h> 49 #include <sys/devops.h> 50 #include <sys/dlpi.h> 51 #include <sys/mac_provider.h> 52 #include <sys/mac_wifi.h> 53 #include <sys/net80211.h> 54 #include <sys/net80211_proto.h> 55 #include <sys/net80211_ht.h> 56 #include <sys/varargs.h> 57 #include <sys/policy.h> 58 #include <sys/pci.h> 59 60 #include "iwh_calibration.h" 61 #include "iwh_hw.h" 62 #include "iwh_eeprom.h" 63 #include "iwh_var.h" 64 #include <inet/wifi_ioctl.h> 65 66 #ifdef DEBUG 67 #define IWH_DEBUG_80211 (1 << 0) 68 #define IWH_DEBUG_CMD (1 << 1) 69 #define IWH_DEBUG_DMA (1 << 2) 70 #define IWH_DEBUG_EEPROM (1 << 3) 71 #define IWH_DEBUG_FW (1 << 4) 72 #define IWH_DEBUG_HW (1 << 5) 73 #define IWH_DEBUG_INTR (1 << 6) 74 #define IWH_DEBUG_MRR (1 << 7) 75 #define IWH_DEBUG_PIO (1 << 8) 76 #define IWH_DEBUG_RX (1 << 9) 77 #define IWH_DEBUG_SCAN (1 << 10) 78 #define IWH_DEBUG_TX (1 << 11) 79 #define IWH_DEBUG_RATECTL (1 << 12) 80 #define IWH_DEBUG_RADIO (1 << 13) 81 #define IWH_DEBUG_RESUME (1 << 14) 82 #define IWH_DEBUG_CALIBRATION (1 << 15) 83 #define IWH_DEBUG_BA (1 << 16) 84 #define IWH_DEBUG_RXON (1 << 17) 85 #define IWH_DEBUG_HWRATE (1 << 18) 86 #define IWH_DEBUG_HTRATE (1 << 19) 87 #define IWH_DEBUG_QOS (1 << 20) 88 /* 89 * if want to see debug message of a given section, 90 * please set this flag to one of above values 91 */ 92 uint32_t iwh_dbg_flags = 0; 93 #define IWH_DBG(x) \ 94 iwh_dbg x 95 #else 96 #define IWH_DBG(x) 97 #endif 98 99 #define MS(v, f) (((v) & f) >> f##_S) 100 101 static void *iwh_soft_state_p = NULL; 102 103 /* 104 * ucode will be compiled into driver image 105 */ 106 static uint8_t iwh_fw_bin [] = { 107 #include "fw-iw/iwh.ucode" 108 }; 109 110 /* 111 * DMA attributes for a shared page 112 */ 113 static ddi_dma_attr_t sh_dma_attr = { 114 DMA_ATTR_V0, /* version of this structure */ 115 0, /* lowest usable address */ 116 0xffffffffU, /* highest usable address */ 117 0xffffffffU, /* maximum DMAable byte count */ 118 0x1000, /* alignment in bytes */ 119 0x1000, /* burst sizes (any?) */ 120 1, /* minimum transfer */ 121 0xffffffffU, /* maximum transfer */ 122 0xffffffffU, /* maximum segment length */ 123 1, /* maximum number of segments */ 124 1, /* granularity */ 125 0, /* flags (reserved) */ 126 }; 127 128 /* 129 * DMA attributes for a keep warm DRAM descriptor 130 */ 131 static ddi_dma_attr_t kw_dma_attr = { 132 DMA_ATTR_V0, /* version of this structure */ 133 0, /* lowest usable address */ 134 0xffffffffU, /* highest usable address */ 135 0xffffffffU, /* maximum DMAable byte count */ 136 0x1000, /* alignment in bytes */ 137 0x1000, /* burst sizes (any?) */ 138 1, /* minimum transfer */ 139 0xffffffffU, /* maximum transfer */ 140 0xffffffffU, /* maximum segment length */ 141 1, /* maximum number of segments */ 142 1, /* granularity */ 143 0, /* flags (reserved) */ 144 }; 145 146 /* 147 * DMA attributes for a ring descriptor 148 */ 149 static ddi_dma_attr_t ring_desc_dma_attr = { 150 DMA_ATTR_V0, /* version of this structure */ 151 0, /* lowest usable address */ 152 0xffffffffU, /* highest usable address */ 153 0xffffffffU, /* maximum DMAable byte count */ 154 0x100, /* alignment in bytes */ 155 0x100, /* burst sizes (any?) */ 156 1, /* minimum transfer */ 157 0xffffffffU, /* maximum transfer */ 158 0xffffffffU, /* maximum segment length */ 159 1, /* maximum number of segments */ 160 1, /* granularity */ 161 0, /* flags (reserved) */ 162 }; 163 164 /* 165 * DMA attributes for a cmd 166 */ 167 static ddi_dma_attr_t cmd_dma_attr = { 168 DMA_ATTR_V0, /* version of this structure */ 169 0, /* lowest usable address */ 170 0xffffffffU, /* highest usable address */ 171 0xffffffffU, /* maximum DMAable byte count */ 172 4, /* alignment in bytes */ 173 0x100, /* burst sizes (any?) */ 174 1, /* minimum transfer */ 175 0xffffffffU, /* maximum transfer */ 176 0xffffffffU, /* maximum segment length */ 177 1, /* maximum number of segments */ 178 1, /* granularity */ 179 0, /* flags (reserved) */ 180 }; 181 182 /* 183 * DMA attributes for a rx buffer 184 */ 185 static ddi_dma_attr_t rx_buffer_dma_attr = { 186 DMA_ATTR_V0, /* version of this structure */ 187 0, /* lowest usable address */ 188 0xffffffffU, /* highest usable address */ 189 0xffffffffU, /* maximum DMAable byte count */ 190 0x100, /* alignment in bytes */ 191 0x100, /* burst sizes (any?) */ 192 1, /* minimum transfer */ 193 0xffffffffU, /* maximum transfer */ 194 0xffffffffU, /* maximum segment length */ 195 1, /* maximum number of segments */ 196 1, /* granularity */ 197 0, /* flags (reserved) */ 198 }; 199 200 /* 201 * DMA attributes for a tx buffer. 202 * the maximum number of segments is 4 for the hardware. 203 * now all the wifi drivers put the whole frame in a single 204 * descriptor, so we define the maximum number of segments 1, 205 * just the same as the rx_buffer. we consider leverage the HW 206 * ability in the future, that is why we don't define rx and tx 207 * buffer_dma_attr as the same. 208 */ 209 static ddi_dma_attr_t tx_buffer_dma_attr = { 210 DMA_ATTR_V0, /* version of this structure */ 211 0, /* lowest usable address */ 212 0xffffffffU, /* highest usable address */ 213 0xffffffffU, /* maximum DMAable byte count */ 214 4, /* alignment in bytes */ 215 0x100, /* burst sizes (any?) */ 216 1, /* minimum transfer */ 217 0xffffffffU, /* maximum transfer */ 218 0xffffffffU, /* maximum segment length */ 219 1, /* maximum number of segments */ 220 1, /* granularity */ 221 0, /* flags (reserved) */ 222 }; 223 224 /* 225 * DMA attributes for text and data part in the firmware 226 */ 227 static ddi_dma_attr_t fw_dma_attr = { 228 DMA_ATTR_V0, /* version of this structure */ 229 0, /* lowest usable address */ 230 0xffffffffU, /* highest usable address */ 231 0x7fffffff, /* maximum DMAable byte count */ 232 0x10, /* alignment in bytes */ 233 0x100, /* burst sizes (any?) */ 234 1, /* minimum transfer */ 235 0xffffffffU, /* maximum transfer */ 236 0xffffffffU, /* maximum segment length */ 237 1, /* maximum number of segments */ 238 1, /* granularity */ 239 0, /* flags (reserved) */ 240 }; 241 242 243 /* 244 * regs access attributes 245 */ 246 static ddi_device_acc_attr_t iwh_reg_accattr = { 247 DDI_DEVICE_ATTR_V0, 248 DDI_STRUCTURE_LE_ACC, 249 DDI_STRICTORDER_ACC, 250 DDI_DEFAULT_ACC 251 }; 252 253 /* 254 * DMA access attributes for descriptor 255 */ 256 static ddi_device_acc_attr_t iwh_dma_descattr = { 257 DDI_DEVICE_ATTR_V0, 258 DDI_STRUCTURE_LE_ACC, 259 DDI_STRICTORDER_ACC, 260 DDI_DEFAULT_ACC 261 }; 262 263 /* 264 * DMA access attributes 265 */ 266 static ddi_device_acc_attr_t iwh_dma_accattr = { 267 DDI_DEVICE_ATTR_V0, 268 DDI_NEVERSWAP_ACC, 269 DDI_STRICTORDER_ACC, 270 DDI_DEFAULT_ACC 271 }; 272 273 static int iwh_ring_init(iwh_sc_t *); 274 static void iwh_ring_free(iwh_sc_t *); 275 static int iwh_alloc_shared(iwh_sc_t *); 276 static void iwh_free_shared(iwh_sc_t *); 277 static int iwh_alloc_kw(iwh_sc_t *); 278 static void iwh_free_kw(iwh_sc_t *); 279 static int iwh_alloc_fw_dma(iwh_sc_t *); 280 static void iwh_free_fw_dma(iwh_sc_t *); 281 static int iwh_alloc_rx_ring(iwh_sc_t *); 282 static void iwh_reset_rx_ring(iwh_sc_t *); 283 static void iwh_free_rx_ring(iwh_sc_t *); 284 static int iwh_alloc_tx_ring(iwh_sc_t *, iwh_tx_ring_t *, 285 int, int); 286 static void iwh_reset_tx_ring(iwh_sc_t *, iwh_tx_ring_t *); 287 static void iwh_free_tx_ring(iwh_tx_ring_t *); 288 static ieee80211_node_t *iwh_node_alloc(ieee80211com_t *); 289 static void iwh_node_free(ieee80211_node_t *); 290 static int iwh_newstate(ieee80211com_t *, enum ieee80211_state, int); 291 static void iwh_mac_access_enter(iwh_sc_t *); 292 static void iwh_mac_access_exit(iwh_sc_t *); 293 static uint32_t iwh_reg_read(iwh_sc_t *, uint32_t); 294 static void iwh_reg_write(iwh_sc_t *, uint32_t, uint32_t); 295 static int iwh_load_init_firmware(iwh_sc_t *); 296 static int iwh_load_run_firmware(iwh_sc_t *); 297 static void iwh_tx_intr(iwh_sc_t *, iwh_rx_desc_t *); 298 static void iwh_cmd_intr(iwh_sc_t *, iwh_rx_desc_t *); 299 static uint_t iwh_intr(caddr_t, caddr_t); 300 static int iwh_eep_load(iwh_sc_t *); 301 static void iwh_get_mac_from_eep(iwh_sc_t *); 302 static int iwh_eep_sem_down(iwh_sc_t *); 303 static void iwh_eep_sem_up(iwh_sc_t *); 304 static uint_t iwh_rx_softintr(caddr_t, caddr_t); 305 static uint8_t iwh_rate_to_plcp(int); 306 static int iwh_cmd(iwh_sc_t *, int, const void *, int, int); 307 static void iwh_set_led(iwh_sc_t *, uint8_t, uint8_t, uint8_t); 308 static int iwh_hw_set_before_auth(iwh_sc_t *); 309 static int iwh_scan(iwh_sc_t *); 310 static int iwh_config(iwh_sc_t *); 311 static void iwh_stop_master(iwh_sc_t *); 312 static int iwh_power_up(iwh_sc_t *); 313 static int iwh_preinit(iwh_sc_t *); 314 static int iwh_init(iwh_sc_t *); 315 static void iwh_stop(iwh_sc_t *); 316 static int iwh_quiesce(dev_info_t *t); 317 static void iwh_amrr_init(iwh_amrr_t *); 318 static void iwh_amrr_timeout(iwh_sc_t *); 319 static void iwh_amrr_ratectl(void *, ieee80211_node_t *); 320 static void iwh_ucode_alive(iwh_sc_t *, iwh_rx_desc_t *); 321 static void iwh_rx_phy_intr(iwh_sc_t *, iwh_rx_desc_t *); 322 static void iwh_rx_mpdu_intr(iwh_sc_t *, iwh_rx_desc_t *); 323 static void iwh_release_calib_buffer(iwh_sc_t *); 324 static int iwh_init_common(iwh_sc_t *); 325 static uint8_t *iwh_eep_addr_trans(iwh_sc_t *, uint32_t); 326 static int iwh_put_seg_fw(iwh_sc_t *, uint32_t, uint32_t, uint32_t); 327 static int iwh_alive_common(iwh_sc_t *); 328 static void iwh_save_calib_result(iwh_sc_t *, iwh_rx_desc_t *); 329 static int iwh_tx_power_table(iwh_sc_t *, int); 330 static int iwh_attach(dev_info_t *, ddi_attach_cmd_t); 331 static int iwh_detach(dev_info_t *, ddi_detach_cmd_t); 332 static void iwh_destroy_locks(iwh_sc_t *); 333 static int iwh_send(ieee80211com_t *, mblk_t *, uint8_t); 334 static void iwh_thread(iwh_sc_t *); 335 static int iwh_run_state_config(iwh_sc_t *); 336 static int iwh_fast_recover(iwh_sc_t *); 337 static int iwh_wme_update(ieee80211com_t *); 338 static int iwh_qosparam_to_hw(iwh_sc_t *, int); 339 static int iwh_wme_to_qos_ac(int); 340 static uint16_t iwh_cw_e_to_cw(uint8_t); 341 static int iwh_wmeparam_check(struct wmeParams *); 342 static inline int iwh_wme_tid_qos_ac(int); 343 static inline int iwh_qos_ac_to_txq(int); 344 static int iwh_wme_tid_to_txq(int); 345 static void iwh_init_ht_conf(iwh_sc_t *); 346 static void iwh_overwrite_11n_rateset(iwh_sc_t *); 347 static void iwh_overwrite_ic_default(iwh_sc_t *); 348 static void iwh_config_rxon_chain(iwh_sc_t *); 349 static int iwh_add_ap_sta(iwh_sc_t *); 350 static int iwh_ap_lq(iwh_sc_t *); 351 static void iwh_recv_action(struct ieee80211_node *, 352 const uint8_t *, const uint8_t *); 353 static int iwh_send_action(struct ieee80211_node *, 354 int, int, uint16_t[4]); 355 static int iwh_is_max_rate(ieee80211_node_t *); 356 static int iwh_is_min_rate(ieee80211_node_t *); 357 static void iwh_increase_rate(ieee80211_node_t *); 358 static void iwh_decrease_rate(ieee80211_node_t *); 359 static int iwh_alloc_dma_mem(iwh_sc_t *, size_t, 360 ddi_dma_attr_t *, ddi_device_acc_attr_t *, 361 uint_t, iwh_dma_t *); 362 static void iwh_free_dma_mem(iwh_dma_t *); 363 364 /* 365 * GLD specific operations 366 */ 367 static int iwh_m_stat(void *, uint_t, uint64_t *); 368 static int iwh_m_start(void *); 369 static void iwh_m_stop(void *); 370 static int iwh_m_unicst(void *, const uint8_t *); 371 static int iwh_m_multicst(void *, boolean_t, const uint8_t *); 372 static int iwh_m_promisc(void *, boolean_t); 373 static mblk_t *iwh_m_tx(void *, mblk_t *); 374 static void iwh_m_ioctl(void *, queue_t *, mblk_t *); 375 static int iwh_m_setprop(void *arg, const char *pr_name, 376 mac_prop_id_t wldp_pr_num, uint_t wldp_length, const void *wldp_buf); 377 static int iwh_m_getprop(void *arg, const char *pr_name, 378 mac_prop_id_t wldp_pr_num, uint_t pr_flags, uint_t wldp_length, 379 void *wldp_buf, uint_t *perm); 380 381 /* 382 * Supported rates for 802.11b/g modes (in 500Kbps unit). 383 */ 384 static const struct ieee80211_rateset iwh_rateset_11b = 385 { 4, { 2, 4, 11, 22 } }; 386 387 static const struct ieee80211_rateset iwh_rateset_11g = 388 { 12, { 2, 4, 11, 22, 12, 18, 24, 36, 48, 72, 96, 108 } }; 389 390 /* 391 * Default 11n reates supported by this station. 392 */ 393 extern struct ieee80211_htrateset ieee80211_rateset_11n; 394 395 /* 396 * For mfthread only 397 */ 398 extern pri_t minclsyspri; 399 400 #define DRV_NAME_SP "iwh" 401 402 /* 403 * Module Loading Data & Entry Points 404 */ 405 DDI_DEFINE_STREAM_OPS(iwh_devops, nulldev, nulldev, iwh_attach, 406 iwh_detach, nodev, NULL, D_MP, NULL, iwh_quiesce); 407 408 static struct modldrv iwh_modldrv = { 409 &mod_driverops, 410 "Intel(R) ShirleyPeak driver(N)", 411 &iwh_devops 412 }; 413 414 static struct modlinkage iwh_modlinkage = { 415 MODREV_1, 416 &iwh_modldrv, 417 NULL 418 }; 419 420 int 421 _init(void) 422 { 423 int status; 424 425 status = ddi_soft_state_init(&iwh_soft_state_p, 426 sizeof (iwh_sc_t), 1); 427 if (status != DDI_SUCCESS) { 428 return (status); 429 } 430 431 mac_init_ops(&iwh_devops, DRV_NAME_SP); 432 status = mod_install(&iwh_modlinkage); 433 if (status != DDI_SUCCESS) { 434 mac_fini_ops(&iwh_devops); 435 ddi_soft_state_fini(&iwh_soft_state_p); 436 } 437 438 return (status); 439 } 440 441 int 442 _fini(void) 443 { 444 int status; 445 446 status = mod_remove(&iwh_modlinkage); 447 if (DDI_SUCCESS == status) { 448 mac_fini_ops(&iwh_devops); 449 ddi_soft_state_fini(&iwh_soft_state_p); 450 } 451 452 return (status); 453 } 454 455 int 456 _info(struct modinfo *mip) 457 { 458 return (mod_info(&iwh_modlinkage, mip)); 459 } 460 461 /* 462 * Mac Call Back entries 463 */ 464 mac_callbacks_t iwh_m_callbacks = { 465 MC_IOCTL | MC_SETPROP | MC_GETPROP, 466 iwh_m_stat, 467 iwh_m_start, 468 iwh_m_stop, 469 iwh_m_promisc, 470 iwh_m_multicst, 471 iwh_m_unicst, 472 iwh_m_tx, 473 iwh_m_ioctl, 474 NULL, 475 NULL, 476 NULL, 477 iwh_m_setprop, 478 iwh_m_getprop 479 }; 480 481 #ifdef DEBUG 482 void 483 iwh_dbg(uint32_t flags, const char *fmt, ...) 484 { 485 va_list ap; 486 487 if (flags & iwh_dbg_flags) { 488 va_start(ap, fmt); 489 vcmn_err(CE_NOTE, fmt, ap); 490 va_end(ap); 491 } 492 } 493 #endif /* DEBUG */ 494 495 /* 496 * device operations 497 */ 498 int 499 iwh_attach(dev_info_t *dip, ddi_attach_cmd_t cmd) 500 { 501 iwh_sc_t *sc; 502 ieee80211com_t *ic; 503 int instance, i; 504 char strbuf[32]; 505 wifi_data_t wd = { 0 }; 506 mac_register_t *macp; 507 int intr_type; 508 int intr_count; 509 int intr_actual; 510 int err = DDI_FAILURE; 511 512 switch (cmd) { 513 case DDI_ATTACH: 514 break; 515 516 case DDI_RESUME: 517 instance = ddi_get_instance(dip); 518 sc = ddi_get_soft_state(iwh_soft_state_p, 519 instance); 520 ASSERT(sc != NULL); 521 522 sc->sc_flags &= ~IWH_F_SUSPEND; 523 if (sc->sc_flags & IWH_F_RUNNING) { 524 (void) iwh_init(sc); 525 } 526 527 IWH_DBG((IWH_DEBUG_RESUME, "iwh_attach(): " 528 "resume\n")); 529 return (DDI_SUCCESS); 530 531 default: 532 goto attach_fail1; 533 } 534 535 instance = ddi_get_instance(dip); 536 err = ddi_soft_state_zalloc(iwh_soft_state_p, instance); 537 if (err != DDI_SUCCESS) { 538 cmn_err(CE_WARN, "iwh_attach(): " 539 "failed to allocate soft state\n"); 540 goto attach_fail1; 541 } 542 543 sc = ddi_get_soft_state(iwh_soft_state_p, instance); 544 ASSERT(sc != NULL); 545 546 sc->sc_dip = dip; 547 548 /* 549 * map configure space 550 */ 551 err = ddi_regs_map_setup(dip, 0, &sc->sc_cfg_base, 0, 0, 552 &iwh_reg_accattr, &sc->sc_cfg_handle); 553 if (err != DDI_SUCCESS) { 554 cmn_err(CE_WARN, "iwh_attach(): " 555 "failed to map config spaces regs\n"); 556 goto attach_fail2; 557 } 558 559 sc->sc_dev_id = ddi_get16(sc->sc_cfg_handle, 560 (uint16_t *)(sc->sc_cfg_base + PCI_CONF_DEVID)); 561 if ((sc->sc_dev_id != 0x4232) && 562 (sc->sc_dev_id != 0x4235) && 563 (sc->sc_dev_id != 0x4236) && 564 (sc->sc_dev_id != 0x4237) && 565 (sc->sc_dev_id != 0x423a)) { 566 cmn_err(CE_WARN, "iwh_attach(): " 567 "Do not support this device\n"); 568 goto attach_fail3; 569 } 570 571 iwh_init_ht_conf(sc); 572 iwh_overwrite_11n_rateset(sc); 573 574 sc->sc_rev = ddi_get8(sc->sc_cfg_handle, 575 (uint8_t *)(sc->sc_cfg_base + PCI_CONF_REVID)); 576 577 /* 578 * keep from disturbing C3 state of CPU 579 */ 580 ddi_put8(sc->sc_cfg_handle, (uint8_t *)(sc->sc_cfg_base + 0x41), 0); 581 582 /* 583 * determine the size of buffer for frame and command to ucode 584 */ 585 sc->sc_clsz = ddi_get16(sc->sc_cfg_handle, 586 (uint16_t *)(sc->sc_cfg_base + PCI_CONF_CACHE_LINESZ)); 587 if (!sc->sc_clsz) { 588 sc->sc_clsz = 16; 589 } 590 sc->sc_clsz = (sc->sc_clsz << 2); 591 592 sc->sc_dmabuf_sz = roundup(0x2000 + sizeof (struct ieee80211_frame) + 593 IEEE80211_MTU + IEEE80211_CRC_LEN + 594 (IEEE80211_WEP_IVLEN + IEEE80211_WEP_KIDLEN + 595 IEEE80211_WEP_CRCLEN), sc->sc_clsz); 596 597 /* 598 * Map operating registers 599 */ 600 err = ddi_regs_map_setup(dip, 1, &sc->sc_base, 601 0, 0, &iwh_reg_accattr, &sc->sc_handle); 602 if (err != DDI_SUCCESS) { 603 cmn_err(CE_WARN, "iwh_attach(): " 604 "failed to map device regs\n"); 605 goto attach_fail3; 606 } 607 608 /* 609 * this is used to differentiate type of hardware 610 */ 611 sc->sc_hw_rev = IWH_READ(sc, CSR_HW_REV); 612 613 err = ddi_intr_get_supported_types(dip, &intr_type); 614 if ((err != DDI_SUCCESS) || (!(intr_type & DDI_INTR_TYPE_FIXED))) { 615 cmn_err(CE_WARN, "iwh_attach(): " 616 "fixed type interrupt is not supported\n"); 617 goto attach_fail4; 618 } 619 620 err = ddi_intr_get_nintrs(dip, DDI_INTR_TYPE_FIXED, &intr_count); 621 if ((err != DDI_SUCCESS) || (intr_count != 1)) { 622 cmn_err(CE_WARN, "iwh_attach(): " 623 "no fixed interrupts\n"); 624 goto attach_fail4; 625 } 626 627 sc->sc_intr_htable = kmem_zalloc(sizeof (ddi_intr_handle_t), KM_SLEEP); 628 629 err = ddi_intr_alloc(dip, sc->sc_intr_htable, DDI_INTR_TYPE_FIXED, 0, 630 intr_count, &intr_actual, 0); 631 if ((err != DDI_SUCCESS) || (intr_actual != 1)) { 632 cmn_err(CE_WARN, "iwh_attach(): " 633 "ddi_intr_alloc() failed 0x%x\n", err); 634 goto attach_fail5; 635 } 636 637 err = ddi_intr_get_pri(sc->sc_intr_htable[0], &sc->sc_intr_pri); 638 if (err != DDI_SUCCESS) { 639 cmn_err(CE_WARN, "iwh_attach(): " 640 "ddi_intr_get_pri() failed 0x%x\n", err); 641 goto attach_fail6; 642 } 643 644 mutex_init(&sc->sc_glock, NULL, MUTEX_DRIVER, 645 DDI_INTR_PRI(sc->sc_intr_pri)); 646 mutex_init(&sc->sc_tx_lock, NULL, MUTEX_DRIVER, 647 DDI_INTR_PRI(sc->sc_intr_pri)); 648 mutex_init(&sc->sc_mt_lock, NULL, MUTEX_DRIVER, 649 DDI_INTR_PRI(sc->sc_intr_pri)); 650 mutex_init(&sc->sc_suspend_lock, NULL, MUTEX_DRIVER, 651 DDI_INTR_PRI(sc->sc_intr_pri)); 652 653 cv_init(&sc->sc_fw_cv, NULL, CV_DRIVER, NULL); 654 cv_init(&sc->sc_cmd_cv, NULL, CV_DRIVER, NULL); 655 cv_init(&sc->sc_tx_cv, "tx-ring", CV_DRIVER, NULL); 656 cv_init(&sc->sc_put_seg_cv, NULL, CV_DRIVER, NULL); 657 cv_init(&sc->sc_ucode_cv, NULL, CV_DRIVER, NULL); 658 659 /* 660 * initialize the mfthread 661 */ 662 cv_init(&sc->sc_mt_cv, NULL, CV_DRIVER, NULL); 663 sc->sc_mf_thread = NULL; 664 sc->sc_mf_thread_switch = 0; 665 666 /* 667 * Allocate shared buffer for communication between driver and ucode. 668 */ 669 err = iwh_alloc_shared(sc); 670 if (err != DDI_SUCCESS) { 671 cmn_err(CE_WARN, "iwh_attach(): " 672 "failed to allocate shared page\n"); 673 goto attach_fail7; 674 } 675 676 (void) memset(sc->sc_shared, 0, sizeof (iwh_shared_t)); 677 678 /* 679 * Allocate keep warm page. 680 */ 681 err = iwh_alloc_kw(sc); 682 if (err != DDI_SUCCESS) { 683 cmn_err(CE_WARN, "iwh_attach(): " 684 "failed to allocate keep warm page\n"); 685 goto attach_fail8; 686 } 687 688 /* 689 * Do some necessary hardware initializations. 690 */ 691 err = iwh_preinit(sc); 692 if (err != IWH_SUCCESS) { 693 cmn_err(CE_WARN, "iwh_attach(): " 694 "failed to initialize hardware\n"); 695 goto attach_fail9; 696 } 697 698 /* 699 * get hardware configurations from eeprom 700 */ 701 err = iwh_eep_load(sc); 702 if (err != IWH_SUCCESS) { 703 cmn_err(CE_WARN, "iwh_attach(): " 704 "failed to load eeprom\n"); 705 goto attach_fail9; 706 } 707 708 if (IWH_READ_EEP_SHORT(sc, EEP_VERSION) < 0x011a) { 709 IWH_DBG((IWH_DEBUG_EEPROM, "iwh_attach(): " 710 "unsupported eeprom detected\n")); 711 goto attach_fail9; 712 } 713 714 /* 715 * get MAC address of this chipset 716 */ 717 iwh_get_mac_from_eep(sc); 718 719 /* 720 * calibration information from EEPROM 721 */ 722 sc->sc_eep_calib = (struct iwh_eep_calibration *) 723 iwh_eep_addr_trans(sc, EEP_CALIBRATION); 724 725 /* 726 * initialize TX and RX ring buffers 727 */ 728 err = iwh_ring_init(sc); 729 if (err != DDI_SUCCESS) { 730 cmn_err(CE_WARN, "iwh_attach(): " 731 "failed to allocate and initialize ring\n"); 732 goto attach_fail9; 733 } 734 735 sc->sc_hdr = (iwh_firmware_hdr_t *)iwh_fw_bin; 736 737 /* 738 * copy ucode to dma buffer 739 */ 740 err = iwh_alloc_fw_dma(sc); 741 if (err != DDI_SUCCESS) { 742 cmn_err(CE_WARN, "iwh_attach(): " 743 "failed to allocate firmware dma\n"); 744 goto attach_fail10; 745 } 746 747 /* 748 * Initialize the wifi part, which will be used by 749 * 802.11 module 750 */ 751 ic = &sc->sc_ic; 752 ic->ic_phytype = IEEE80211_T_HT; 753 ic->ic_opmode = IEEE80211_M_STA; /* default to BSS mode */ 754 ic->ic_state = IEEE80211_S_INIT; 755 ic->ic_maxrssi = 100; /* experimental number */ 756 ic->ic_caps = IEEE80211_C_SHPREAMBLE | IEEE80211_C_TXPMGT | 757 IEEE80211_C_PMGT | IEEE80211_C_SHSLOT; 758 759 /* 760 * Support WPA/WPA2 761 */ 762 ic->ic_caps |= IEEE80211_C_WPA; 763 764 /* 765 * Support QoS/WME 766 */ 767 ic->ic_caps |= IEEE80211_C_WME; 768 ic->ic_wme.wme_update = iwh_wme_update; 769 770 /* 771 * Support 802.11n/HT 772 */ 773 if (sc->sc_ht_conf.ht_support) { 774 ic->ic_htcaps = IEEE80211_HTC_HT | 775 IEEE80211_HTC_AMSDU; 776 ic->ic_htcaps |= IEEE80211_HTCAP_MAXAMSDU_7935; 777 } 778 779 /* 780 * set supported .11b and .11g rates 781 */ 782 ic->ic_sup_rates[IEEE80211_MODE_11B] = iwh_rateset_11b; 783 ic->ic_sup_rates[IEEE80211_MODE_11G] = iwh_rateset_11g; 784 785 /* 786 * set supported .11b and .11g channels (1 through 11) 787 */ 788 for (i = 1; i <= 11; i++) { 789 ic->ic_sup_channels[i].ich_freq = 790 ieee80211_ieee2mhz(i, IEEE80211_CHAN_2GHZ); 791 ic->ic_sup_channels[i].ich_flags = 792 IEEE80211_CHAN_CCK | IEEE80211_CHAN_OFDM | 793 IEEE80211_CHAN_DYN | IEEE80211_CHAN_2GHZ | 794 IEEE80211_CHAN_PASSIVE; 795 796 if (sc->sc_ht_conf.cap & HT_CAP_SUP_WIDTH) { 797 ic->ic_sup_channels[i].ich_flags |= 798 IEEE80211_CHAN_HT40; 799 } else { 800 ic->ic_sup_channels[i].ich_flags |= 801 IEEE80211_CHAN_HT20; 802 } 803 } 804 805 ic->ic_ibss_chan = &ic->ic_sup_channels[0]; 806 ic->ic_xmit = iwh_send; 807 808 /* 809 * attach to 802.11 module 810 */ 811 ieee80211_attach(ic); 812 813 /* 814 * different instance has different WPA door 815 */ 816 (void) snprintf(ic->ic_wpadoor, MAX_IEEE80211STR, "%s_%s%d", WPA_DOOR, 817 ddi_driver_name(dip), 818 ddi_get_instance(dip)); 819 820 /* 821 * Overwrite 80211 default configurations. 822 */ 823 iwh_overwrite_ic_default(sc); 824 825 /* 826 * initialize 802.11 module 827 */ 828 ieee80211_media_init(ic); 829 830 /* 831 * initialize default tx key 832 */ 833 ic->ic_def_txkey = 0; 834 835 err = ddi_intr_add_softint(dip, &sc->sc_soft_hdl, DDI_INTR_SOFTPRI_MAX, 836 iwh_rx_softintr, (caddr_t)sc); 837 if (err != DDI_SUCCESS) { 838 cmn_err(CE_WARN, "iwh_attach(): " 839 "add soft interrupt failed\n"); 840 goto attach_fail12; 841 } 842 843 err = ddi_intr_add_handler(sc->sc_intr_htable[0], iwh_intr, 844 (caddr_t)sc, NULL); 845 if (err != DDI_SUCCESS) { 846 cmn_err(CE_WARN, "iwh_attach(): " 847 "ddi_intr_add_handle() failed\n"); 848 goto attach_fail13; 849 } 850 851 err = ddi_intr_enable(sc->sc_intr_htable[0]); 852 if (err != DDI_SUCCESS) { 853 cmn_err(CE_WARN, "iwh_attach(): " 854 "ddi_intr_enable() failed\n"); 855 goto attach_fail14; 856 } 857 858 /* 859 * Initialize pointer to device specific functions 860 */ 861 wd.wd_secalloc = WIFI_SEC_NONE; 862 wd.wd_opmode = ic->ic_opmode; 863 IEEE80211_ADDR_COPY(wd.wd_bssid, ic->ic_macaddr); 864 865 /* 866 * create relation to GLD 867 */ 868 macp = mac_alloc(MAC_VERSION); 869 if (NULL == macp) { 870 cmn_err(CE_WARN, "iwh_attach(): " 871 "failed to do mac_alloc()\n"); 872 goto attach_fail15; 873 } 874 875 macp->m_type_ident = MAC_PLUGIN_IDENT_WIFI; 876 macp->m_driver = sc; 877 macp->m_dip = dip; 878 macp->m_src_addr = ic->ic_macaddr; 879 macp->m_callbacks = &iwh_m_callbacks; 880 macp->m_min_sdu = 0; 881 macp->m_max_sdu = IEEE80211_MTU; 882 macp->m_pdata = &wd; 883 macp->m_pdata_size = sizeof (wd); 884 885 /* 886 * Register the macp to mac 887 */ 888 err = mac_register(macp, &ic->ic_mach); 889 mac_free(macp); 890 if (err != DDI_SUCCESS) { 891 cmn_err(CE_WARN, "iwh_attach(): " 892 "failed to do mac_register()\n"); 893 goto attach_fail15; 894 } 895 896 /* 897 * Create minor node of type DDI_NT_NET_WIFI 898 */ 899 (void) snprintf(strbuf, sizeof (strbuf), DRV_NAME_SP"%d", instance); 900 err = ddi_create_minor_node(dip, strbuf, S_IFCHR, 901 instance + 1, DDI_NT_NET_WIFI, 0); 902 if (err != DDI_SUCCESS) { 903 cmn_err(CE_WARN, "iwh_attach(): " 904 "failed to do ddi_create_minor_node()\n"); 905 } 906 907 /* 908 * Notify link is down now 909 */ 910 mac_link_update(ic->ic_mach, LINK_STATE_DOWN); 911 912 /* 913 * create the mf thread to handle the link status, 914 * recovery fatal error, etc. 915 */ 916 sc->sc_mf_thread_switch = 1; 917 if (NULL == sc->sc_mf_thread) { 918 sc->sc_mf_thread = thread_create((caddr_t)NULL, 0, 919 iwh_thread, sc, 0, &p0, TS_RUN, minclsyspri); 920 } 921 922 sc->sc_flags |= IWH_F_ATTACHED; 923 924 return (DDI_SUCCESS); 925 926 attach_fail15: 927 (void) ddi_intr_disable(sc->sc_intr_htable[0]); 928 929 attach_fail14: 930 (void) ddi_intr_remove_handler(sc->sc_intr_htable[0]); 931 932 attach_fail13: 933 (void) ddi_intr_remove_softint(sc->sc_soft_hdl); 934 sc->sc_soft_hdl = NULL; 935 936 attach_fail12: 937 ieee80211_detach(ic); 938 939 attach_fail11: 940 iwh_free_fw_dma(sc); 941 942 attach_fail10: 943 iwh_ring_free(sc); 944 945 attach_fail9: 946 iwh_free_kw(sc); 947 948 attach_fail8: 949 iwh_free_shared(sc); 950 951 attach_fail7: 952 iwh_destroy_locks(sc); 953 954 attach_fail6: 955 (void) ddi_intr_free(sc->sc_intr_htable[0]); 956 957 attach_fail5: 958 kmem_free(sc->sc_intr_htable, sizeof (ddi_intr_handle_t)); 959 960 attach_fail4: 961 ddi_regs_map_free(&sc->sc_handle); 962 963 attach_fail3: 964 ddi_regs_map_free(&sc->sc_cfg_handle); 965 966 attach_fail2: 967 ddi_soft_state_free(iwh_soft_state_p, instance); 968 969 attach_fail1: 970 return (DDI_FAILURE); 971 } 972 973 int 974 iwh_detach(dev_info_t *dip, ddi_detach_cmd_t cmd) 975 { 976 iwh_sc_t *sc; 977 ieee80211com_t *ic; 978 int err; 979 980 sc = ddi_get_soft_state(iwh_soft_state_p, ddi_get_instance(dip)); 981 ASSERT(sc != NULL); 982 ic = &sc->sc_ic; 983 984 switch (cmd) { 985 case DDI_DETACH: 986 break; 987 988 case DDI_SUSPEND: 989 if (sc->sc_flags & IWH_F_RUNNING) { 990 ieee80211_new_state(ic, IEEE80211_S_INIT, -1); 991 iwh_stop(sc); 992 } 993 sc->sc_flags |= IWH_F_SUSPEND; 994 995 IWH_DBG((IWH_DEBUG_RESUME, "iwh_detach(): " 996 "suspend\n")); 997 return (DDI_SUCCESS); 998 999 default: 1000 return (DDI_FAILURE); 1001 } 1002 1003 if (!(sc->sc_flags & IWH_F_ATTACHED)) { 1004 return (DDI_FAILURE); 1005 } 1006 1007 /* 1008 * Destroy the mf_thread 1009 */ 1010 sc->sc_mf_thread_switch = 0; 1011 1012 mutex_enter(&sc->sc_mt_lock); 1013 while (sc->sc_mf_thread != NULL) { 1014 if (cv_wait_sig(&sc->sc_mt_cv, &sc->sc_mt_lock) == 0) { 1015 break; 1016 } 1017 } 1018 mutex_exit(&sc->sc_mt_lock); 1019 1020 err = mac_disable(sc->sc_ic.ic_mach); 1021 if (err != DDI_SUCCESS) { 1022 return (err); 1023 } 1024 1025 /* 1026 * stop chipset 1027 */ 1028 iwh_stop(sc); 1029 1030 DELAY(500000); 1031 1032 /* 1033 * release buffer for calibration 1034 */ 1035 iwh_release_calib_buffer(sc); 1036 1037 /* 1038 * Unregiste from GLD 1039 */ 1040 (void) mac_unregister(sc->sc_ic.ic_mach); 1041 1042 mutex_enter(&sc->sc_glock); 1043 iwh_free_fw_dma(sc); 1044 iwh_ring_free(sc); 1045 iwh_free_kw(sc); 1046 iwh_free_shared(sc); 1047 mutex_exit(&sc->sc_glock); 1048 1049 (void) ddi_intr_disable(sc->sc_intr_htable[0]); 1050 (void) ddi_intr_remove_handler(sc->sc_intr_htable[0]); 1051 (void) ddi_intr_free(sc->sc_intr_htable[0]); 1052 kmem_free(sc->sc_intr_htable, sizeof (ddi_intr_handle_t)); 1053 1054 (void) ddi_intr_remove_softint(sc->sc_soft_hdl); 1055 sc->sc_soft_hdl = NULL; 1056 1057 /* 1058 * detach from 80211 module 1059 */ 1060 ieee80211_detach(&sc->sc_ic); 1061 1062 iwh_destroy_locks(sc); 1063 1064 ddi_regs_map_free(&sc->sc_handle); 1065 ddi_regs_map_free(&sc->sc_cfg_handle); 1066 ddi_remove_minor_node(dip, NULL); 1067 ddi_soft_state_free(iwh_soft_state_p, ddi_get_instance(dip)); 1068 1069 return (DDI_SUCCESS); 1070 } 1071 1072 /* 1073 * destroy all locks 1074 */ 1075 static void 1076 iwh_destroy_locks(iwh_sc_t *sc) 1077 { 1078 cv_destroy(&sc->sc_mt_cv); 1079 cv_destroy(&sc->sc_tx_cv); 1080 cv_destroy(&sc->sc_cmd_cv); 1081 cv_destroy(&sc->sc_fw_cv); 1082 cv_destroy(&sc->sc_put_seg_cv); 1083 cv_destroy(&sc->sc_ucode_cv); 1084 mutex_destroy(&sc->sc_mt_lock); 1085 mutex_destroy(&sc->sc_tx_lock); 1086 mutex_destroy(&sc->sc_glock); 1087 mutex_destroy(&sc->sc_suspend_lock); 1088 } 1089 1090 /* 1091 * Allocate an area of memory and a DMA handle for accessing it 1092 */ 1093 static int 1094 iwh_alloc_dma_mem(iwh_sc_t *sc, size_t memsize, 1095 ddi_dma_attr_t *dma_attr_p, ddi_device_acc_attr_t *acc_attr_p, 1096 uint_t dma_flags, iwh_dma_t *dma_p) 1097 { 1098 caddr_t vaddr; 1099 int err = DDI_FAILURE; 1100 1101 /* 1102 * Allocate handle 1103 */ 1104 err = ddi_dma_alloc_handle(sc->sc_dip, dma_attr_p, 1105 DDI_DMA_SLEEP, NULL, &dma_p->dma_hdl); 1106 if (err != DDI_SUCCESS) { 1107 dma_p->dma_hdl = NULL; 1108 return (DDI_FAILURE); 1109 } 1110 1111 /* 1112 * Allocate memory 1113 */ 1114 err = ddi_dma_mem_alloc(dma_p->dma_hdl, memsize, acc_attr_p, 1115 dma_flags & (DDI_DMA_CONSISTENT | DDI_DMA_STREAMING), 1116 DDI_DMA_SLEEP, NULL, &vaddr, &dma_p->alength, &dma_p->acc_hdl); 1117 if (err != DDI_SUCCESS) { 1118 ddi_dma_free_handle(&dma_p->dma_hdl); 1119 dma_p->dma_hdl = NULL; 1120 dma_p->acc_hdl = NULL; 1121 return (DDI_FAILURE); 1122 } 1123 1124 /* 1125 * Bind the two together 1126 */ 1127 dma_p->mem_va = vaddr; 1128 err = ddi_dma_addr_bind_handle(dma_p->dma_hdl, NULL, 1129 vaddr, dma_p->alength, dma_flags, DDI_DMA_SLEEP, NULL, 1130 &dma_p->cookie, &dma_p->ncookies); 1131 if (err != DDI_DMA_MAPPED) { 1132 ddi_dma_mem_free(&dma_p->acc_hdl); 1133 ddi_dma_free_handle(&dma_p->dma_hdl); 1134 dma_p->acc_hdl = NULL; 1135 dma_p->dma_hdl = NULL; 1136 return (DDI_FAILURE); 1137 } 1138 1139 dma_p->nslots = ~0U; 1140 dma_p->size = ~0U; 1141 dma_p->token = ~0U; 1142 dma_p->offset = 0; 1143 return (DDI_SUCCESS); 1144 } 1145 1146 /* 1147 * Free one allocated area of DMAable memory 1148 */ 1149 static void 1150 iwh_free_dma_mem(iwh_dma_t *dma_p) 1151 { 1152 if (dma_p->dma_hdl != NULL) { 1153 if (dma_p->ncookies) { 1154 (void) ddi_dma_unbind_handle(dma_p->dma_hdl); 1155 dma_p->ncookies = 0; 1156 } 1157 ddi_dma_free_handle(&dma_p->dma_hdl); 1158 dma_p->dma_hdl = NULL; 1159 } 1160 1161 if (dma_p->acc_hdl != NULL) { 1162 ddi_dma_mem_free(&dma_p->acc_hdl); 1163 dma_p->acc_hdl = NULL; 1164 } 1165 } 1166 1167 /* 1168 * copy ucode into dma buffers 1169 */ 1170 static int 1171 iwh_alloc_fw_dma(iwh_sc_t *sc) 1172 { 1173 int err = DDI_FAILURE; 1174 iwh_dma_t *dma_p; 1175 char *t; 1176 1177 /* 1178 * firmware image layout: 1179 * |HDR|<-TEXT->|<-DATA->|<-INIT_TEXT->|<-INIT_DATA->|<-BOOT->| 1180 */ 1181 1182 /* 1183 * copy text of runtime ucode 1184 */ 1185 t = (char *)(sc->sc_hdr + 1); 1186 err = iwh_alloc_dma_mem(sc, LE_32(sc->sc_hdr->textsz), 1187 &fw_dma_attr, &iwh_dma_accattr, 1188 DDI_DMA_RDWR | DDI_DMA_CONSISTENT, 1189 &sc->sc_dma_fw_text); 1190 if (err != DDI_SUCCESS) { 1191 cmn_err(CE_WARN, "iwh_alloc_fw_dma(): " 1192 "failed to allocate text dma memory.\n"); 1193 goto fail; 1194 } 1195 1196 dma_p = &sc->sc_dma_fw_text; 1197 1198 IWH_DBG((IWH_DEBUG_DMA, "iwh_alloc_fw_dma(): " 1199 "text[ncookies:%d addr:%lx size:%lx]\n", 1200 dma_p->ncookies, dma_p->cookie.dmac_address, 1201 dma_p->cookie.dmac_size)); 1202 1203 (void) memcpy(dma_p->mem_va, t, LE_32(sc->sc_hdr->textsz)); 1204 1205 /* 1206 * copy data and bak-data of runtime ucode 1207 */ 1208 t += LE_32(sc->sc_hdr->textsz); 1209 err = iwh_alloc_dma_mem(sc, LE_32(sc->sc_hdr->datasz), 1210 &fw_dma_attr, &iwh_dma_accattr, 1211 DDI_DMA_RDWR | DDI_DMA_CONSISTENT, 1212 &sc->sc_dma_fw_data); 1213 if (err != DDI_SUCCESS) { 1214 cmn_err(CE_WARN, "iwh_alloc_fw_dma(): " 1215 "failed to allocate data dma memory\n"); 1216 goto fail; 1217 } 1218 1219 dma_p = &sc->sc_dma_fw_data; 1220 1221 IWH_DBG((IWH_DEBUG_DMA, "iwh_alloc_fw_dma(): " 1222 "data[ncookies:%d addr:%lx size:%lx]\n", 1223 dma_p->ncookies, dma_p->cookie.dmac_address, 1224 dma_p->cookie.dmac_size)); 1225 1226 (void) memcpy(dma_p->mem_va, t, LE_32(sc->sc_hdr->datasz)); 1227 1228 err = iwh_alloc_dma_mem(sc, LE_32(sc->sc_hdr->datasz), 1229 &fw_dma_attr, &iwh_dma_accattr, 1230 DDI_DMA_RDWR | DDI_DMA_CONSISTENT, 1231 &sc->sc_dma_fw_data_bak); 1232 if (err != DDI_SUCCESS) { 1233 cmn_err(CE_WARN, "iwh_alloc_fw_dma(): " 1234 "failed to allocate data bakup dma memory\n"); 1235 goto fail; 1236 } 1237 1238 dma_p = &sc->sc_dma_fw_data_bak; 1239 1240 IWH_DBG((IWH_DEBUG_DMA, "iwh_alloc_fw_dma(): " 1241 "data_bak[ncookies:%d addr:%lx " 1242 "size:%lx]\n", 1243 dma_p->ncookies, dma_p->cookie.dmac_address, 1244 dma_p->cookie.dmac_size)); 1245 1246 (void) memcpy(dma_p->mem_va, t, LE_32(sc->sc_hdr->datasz)); 1247 1248 /* 1249 * copy text of init ucode 1250 */ 1251 t += LE_32(sc->sc_hdr->datasz); 1252 err = iwh_alloc_dma_mem(sc, LE_32(sc->sc_hdr->init_textsz), 1253 &fw_dma_attr, &iwh_dma_accattr, 1254 DDI_DMA_RDWR | DDI_DMA_CONSISTENT, 1255 &sc->sc_dma_fw_init_text); 1256 if (err != DDI_SUCCESS) { 1257 cmn_err(CE_WARN, "iwh_alloc_fw_dma(): " 1258 "failed to allocate init text dma memory\n"); 1259 goto fail; 1260 } 1261 1262 dma_p = &sc->sc_dma_fw_init_text; 1263 1264 IWH_DBG((IWH_DEBUG_DMA, "iwh_alloc_fw_dma(): " 1265 "init_text[ncookies:%d addr:%lx " 1266 "size:%lx]\n", 1267 dma_p->ncookies, dma_p->cookie.dmac_address, 1268 dma_p->cookie.dmac_size)); 1269 1270 (void) memcpy(dma_p->mem_va, t, LE_32(sc->sc_hdr->init_textsz)); 1271 1272 /* 1273 * copy data of init ucode 1274 */ 1275 t += LE_32(sc->sc_hdr->init_textsz); 1276 err = iwh_alloc_dma_mem(sc, LE_32(sc->sc_hdr->init_datasz), 1277 &fw_dma_attr, &iwh_dma_accattr, 1278 DDI_DMA_RDWR | DDI_DMA_CONSISTENT, 1279 &sc->sc_dma_fw_init_data); 1280 if (err != DDI_SUCCESS) { 1281 cmn_err(CE_WARN, "iwh_alloc_fw_dma(): " 1282 "failed to allocate init data dma memory\n"); 1283 goto fail; 1284 } 1285 1286 dma_p = &sc->sc_dma_fw_init_data; 1287 1288 IWH_DBG((IWH_DEBUG_DMA, "iwh_alloc_fw_dma(): " 1289 "init_data[ncookies:%d addr:%lx " 1290 "size:%lx]\n", 1291 dma_p->ncookies, dma_p->cookie.dmac_address, 1292 dma_p->cookie.dmac_size)); 1293 1294 (void) memcpy(dma_p->mem_va, t, LE_32(sc->sc_hdr->init_datasz)); 1295 1296 sc->sc_boot = t + LE_32(sc->sc_hdr->init_datasz); 1297 fail: 1298 return (err); 1299 } 1300 1301 static void 1302 iwh_free_fw_dma(iwh_sc_t *sc) 1303 { 1304 iwh_free_dma_mem(&sc->sc_dma_fw_text); 1305 iwh_free_dma_mem(&sc->sc_dma_fw_data); 1306 iwh_free_dma_mem(&sc->sc_dma_fw_data_bak); 1307 iwh_free_dma_mem(&sc->sc_dma_fw_init_text); 1308 iwh_free_dma_mem(&sc->sc_dma_fw_init_data); 1309 } 1310 1311 /* 1312 * Allocate a shared buffer between host and NIC. 1313 */ 1314 static int 1315 iwh_alloc_shared(iwh_sc_t *sc) 1316 { 1317 #ifdef DEBUG 1318 iwh_dma_t *dma_p; 1319 #endif 1320 int err = DDI_FAILURE; 1321 1322 /* 1323 * must be aligned on a 4K-page boundary 1324 */ 1325 err = iwh_alloc_dma_mem(sc, sizeof (iwh_shared_t), 1326 &sh_dma_attr, &iwh_dma_descattr, 1327 DDI_DMA_RDWR | DDI_DMA_CONSISTENT, 1328 &sc->sc_dma_sh); 1329 if (err != DDI_SUCCESS) { 1330 goto fail; 1331 } 1332 1333 sc->sc_shared = (iwh_shared_t *)sc->sc_dma_sh.mem_va; 1334 1335 #ifdef DEBUG 1336 dma_p = &sc->sc_dma_sh; 1337 #endif 1338 IWH_DBG((IWH_DEBUG_DMA, "iwh_alloc_shared(): " 1339 "sh[ncookies:%d addr:%lx size:%lx]\n", 1340 dma_p->ncookies, dma_p->cookie.dmac_address, 1341 dma_p->cookie.dmac_size)); 1342 1343 return (err); 1344 fail: 1345 iwh_free_shared(sc); 1346 return (err); 1347 } 1348 1349 static void 1350 iwh_free_shared(iwh_sc_t *sc) 1351 { 1352 iwh_free_dma_mem(&sc->sc_dma_sh); 1353 } 1354 1355 /* 1356 * Allocate a keep warm page. 1357 */ 1358 static int 1359 iwh_alloc_kw(iwh_sc_t *sc) 1360 { 1361 #ifdef DEBUG 1362 iwh_dma_t *dma_p; 1363 #endif 1364 int err = DDI_FAILURE; 1365 1366 /* 1367 * must be aligned on a 4K-page boundary 1368 */ 1369 err = iwh_alloc_dma_mem(sc, IWH_KW_SIZE, 1370 &kw_dma_attr, &iwh_dma_descattr, 1371 DDI_DMA_RDWR | DDI_DMA_CONSISTENT, 1372 &sc->sc_dma_kw); 1373 if (err != DDI_SUCCESS) { 1374 goto fail; 1375 } 1376 1377 #ifdef DEBUG 1378 dma_p = &sc->sc_dma_kw; 1379 #endif 1380 IWH_DBG((IWH_DEBUG_DMA, "iwh_alloc_kw(): " 1381 "kw[ncookies:%d addr:%lx size:%lx]\n", 1382 dma_p->ncookies, dma_p->cookie.dmac_address, 1383 dma_p->cookie.dmac_size)); 1384 1385 return (err); 1386 fail: 1387 iwh_free_kw(sc); 1388 return (err); 1389 } 1390 1391 static void 1392 iwh_free_kw(iwh_sc_t *sc) 1393 { 1394 iwh_free_dma_mem(&sc->sc_dma_kw); 1395 } 1396 1397 /* 1398 * initialize RX ring buffers 1399 */ 1400 static int 1401 iwh_alloc_rx_ring(iwh_sc_t *sc) 1402 { 1403 iwh_rx_ring_t *ring; 1404 iwh_rx_data_t *data; 1405 #ifdef DEBUG 1406 iwh_dma_t *dma_p; 1407 #endif 1408 int i, err = DDI_FAILURE; 1409 1410 ring = &sc->sc_rxq; 1411 ring->cur = 0; 1412 1413 /* 1414 * allocate RX description ring buffer 1415 */ 1416 err = iwh_alloc_dma_mem(sc, RX_QUEUE_SIZE * sizeof (uint32_t), 1417 &ring_desc_dma_attr, &iwh_dma_descattr, 1418 DDI_DMA_RDWR | DDI_DMA_CONSISTENT, 1419 &ring->dma_desc); 1420 if (err != DDI_SUCCESS) { 1421 IWH_DBG((IWH_DEBUG_DMA, "iwh_alloc_rx_ring(): " 1422 "dma alloc rx ring desc " 1423 "failed\n")); 1424 goto fail; 1425 } 1426 1427 ring->desc = (uint32_t *)ring->dma_desc.mem_va; 1428 #ifdef DEBUG 1429 dma_p = &ring->dma_desc; 1430 #endif 1431 IWH_DBG((IWH_DEBUG_DMA, "iwh_alloc_rx_ring(): " 1432 "rx bd[ncookies:%d addr:%lx size:%lx]\n", 1433 dma_p->ncookies, dma_p->cookie.dmac_address, 1434 dma_p->cookie.dmac_size)); 1435 1436 /* 1437 * Allocate Rx frame buffers. 1438 */ 1439 for (i = 0; i < RX_QUEUE_SIZE; i++) { 1440 data = &ring->data[i]; 1441 err = iwh_alloc_dma_mem(sc, sc->sc_dmabuf_sz, 1442 &rx_buffer_dma_attr, &iwh_dma_accattr, 1443 DDI_DMA_READ | DDI_DMA_STREAMING, 1444 &data->dma_data); 1445 if (err != DDI_SUCCESS) { 1446 IWH_DBG((IWH_DEBUG_DMA, "iwh_alloc_rx_ring(): " 1447 "dma alloc rx ring " 1448 "buf[%d] failed\n", i)); 1449 goto fail; 1450 } 1451 /* 1452 * the physical address bit [8-36] are used, 1453 * instead of bit [0-31] in 3945. 1454 */ 1455 ring->desc[i] = (uint32_t) 1456 (data->dma_data.cookie.dmac_address >> 8); 1457 } 1458 1459 #ifdef DEBUG 1460 dma_p = &ring->data[0].dma_data; 1461 #endif 1462 IWH_DBG((IWH_DEBUG_DMA, "iwh_alloc_rx_ring(): " 1463 "rx buffer[0][ncookies:%d addr:%lx " 1464 "size:%lx]\n", 1465 dma_p->ncookies, dma_p->cookie.dmac_address, 1466 dma_p->cookie.dmac_size)); 1467 1468 IWH_DMA_SYNC(ring->dma_desc, DDI_DMA_SYNC_FORDEV); 1469 1470 return (err); 1471 1472 fail: 1473 iwh_free_rx_ring(sc); 1474 return (err); 1475 } 1476 1477 /* 1478 * disable RX ring 1479 */ 1480 static void 1481 iwh_reset_rx_ring(iwh_sc_t *sc) 1482 { 1483 int n; 1484 1485 iwh_mac_access_enter(sc); 1486 IWH_WRITE(sc, FH_MEM_RCSR_CHNL0_CONFIG_REG, 0); 1487 for (n = 0; n < 2000; n++) { 1488 if (IWH_READ(sc, FH_MEM_RSSR_RX_STATUS_REG) & (1 << 24)) { 1489 break; 1490 } 1491 DELAY(1000); 1492 } 1493 #ifdef DEBUG 1494 if (2000 == n) { 1495 IWH_DBG((IWH_DEBUG_DMA, "iwh_reset_rx_ring(): " 1496 "timeout resetting Rx ring\n")); 1497 } 1498 #endif 1499 iwh_mac_access_exit(sc); 1500 1501 sc->sc_rxq.cur = 0; 1502 } 1503 1504 static void 1505 iwh_free_rx_ring(iwh_sc_t *sc) 1506 { 1507 int i; 1508 1509 for (i = 0; i < RX_QUEUE_SIZE; i++) { 1510 if (sc->sc_rxq.data[i].dma_data.dma_hdl) { 1511 IWH_DMA_SYNC(sc->sc_rxq.data[i].dma_data, 1512 DDI_DMA_SYNC_FORCPU); 1513 } 1514 1515 iwh_free_dma_mem(&sc->sc_rxq.data[i].dma_data); 1516 } 1517 1518 if (sc->sc_rxq.dma_desc.dma_hdl) { 1519 IWH_DMA_SYNC(sc->sc_rxq.dma_desc, DDI_DMA_SYNC_FORDEV); 1520 } 1521 1522 iwh_free_dma_mem(&sc->sc_rxq.dma_desc); 1523 } 1524 1525 /* 1526 * initialize TX ring buffers 1527 */ 1528 static int 1529 iwh_alloc_tx_ring(iwh_sc_t *sc, iwh_tx_ring_t *ring, 1530 int slots, int qid) 1531 { 1532 iwh_tx_data_t *data; 1533 iwh_tx_desc_t *desc_h; 1534 uint32_t paddr_desc_h; 1535 iwh_cmd_t *cmd_h; 1536 uint32_t paddr_cmd_h; 1537 #ifdef DEBUG 1538 iwh_dma_t *dma_p; 1539 #endif 1540 int i, err = DDI_FAILURE; 1541 ring->qid = qid; 1542 ring->count = TFD_QUEUE_SIZE_MAX; 1543 ring->window = slots; 1544 ring->queued = 0; 1545 ring->cur = 0; 1546 1547 /* 1548 * allocate buffer for TX descriptor ring 1549 */ 1550 err = iwh_alloc_dma_mem(sc, 1551 TFD_QUEUE_SIZE_MAX * sizeof (iwh_tx_desc_t), 1552 &ring_desc_dma_attr, &iwh_dma_descattr, 1553 DDI_DMA_RDWR | DDI_DMA_CONSISTENT, 1554 &ring->dma_desc); 1555 if (err != DDI_SUCCESS) { 1556 IWH_DBG((IWH_DEBUG_DMA, "iwh_alloc_tx_ring(): " 1557 "dma alloc tx ring desc[%d] " 1558 "failed\n", qid)); 1559 goto fail; 1560 } 1561 1562 #ifdef DEBUG 1563 dma_p = &ring->dma_desc; 1564 #endif 1565 IWH_DBG((IWH_DEBUG_DMA, "iwh_alloc_tx_ring(): " 1566 "tx bd[ncookies:%d addr:%lx size:%lx]\n", 1567 dma_p->ncookies, dma_p->cookie.dmac_address, 1568 dma_p->cookie.dmac_size)); 1569 1570 desc_h = (iwh_tx_desc_t *)ring->dma_desc.mem_va; 1571 paddr_desc_h = ring->dma_desc.cookie.dmac_address; 1572 1573 /* 1574 * allocate buffer for ucode command 1575 */ 1576 err = iwh_alloc_dma_mem(sc, 1577 TFD_QUEUE_SIZE_MAX * sizeof (iwh_cmd_t), 1578 &cmd_dma_attr, &iwh_dma_accattr, 1579 DDI_DMA_RDWR | DDI_DMA_CONSISTENT, 1580 &ring->dma_cmd); 1581 if (err != DDI_SUCCESS) { 1582 IWH_DBG((IWH_DEBUG_DMA, "iwh_alloc_tx_ring(): " 1583 "dma alloc tx ring cmd[%d]" 1584 " failed\n", qid)); 1585 goto fail; 1586 } 1587 1588 #ifdef DEBUG 1589 dma_p = &ring->dma_cmd; 1590 #endif 1591 IWH_DBG((IWH_DEBUG_DMA, "iwh_alloc_tx_ring(): " 1592 "tx cmd[ncookies:%d addr:%lx size:%lx]\n", 1593 dma_p->ncookies, dma_p->cookie.dmac_address, 1594 dma_p->cookie.dmac_size)); 1595 1596 cmd_h = (iwh_cmd_t *)ring->dma_cmd.mem_va; 1597 paddr_cmd_h = ring->dma_cmd.cookie.dmac_address; 1598 1599 /* 1600 * Allocate Tx frame buffers. 1601 */ 1602 ring->data = kmem_zalloc(sizeof (iwh_tx_data_t) * TFD_QUEUE_SIZE_MAX, 1603 KM_NOSLEEP); 1604 if (NULL == ring->data) { 1605 IWH_DBG((IWH_DEBUG_DMA, "iwh_alloc_tx_ring(): " 1606 "could not allocate " 1607 "tx data slots\n")); 1608 goto fail; 1609 } 1610 1611 for (i = 0; i < TFD_QUEUE_SIZE_MAX; i++) { 1612 data = &ring->data[i]; 1613 err = iwh_alloc_dma_mem(sc, sc->sc_dmabuf_sz, 1614 &tx_buffer_dma_attr, &iwh_dma_accattr, 1615 DDI_DMA_WRITE | DDI_DMA_STREAMING, 1616 &data->dma_data); 1617 if (err != DDI_SUCCESS) { 1618 IWH_DBG((IWH_DEBUG_DMA, "iwh_alloc_tx_ring(): " 1619 "dma alloc tx " 1620 "ring buf[%d] failed\n", i)); 1621 goto fail; 1622 } 1623 1624 data->desc = desc_h + i; 1625 data->paddr_desc = paddr_desc_h + 1626 _PTRDIFF(data->desc, desc_h); 1627 data->cmd = cmd_h + i; 1628 data->paddr_cmd = paddr_cmd_h + 1629 _PTRDIFF(data->cmd, cmd_h); 1630 } 1631 #ifdef DEBUG 1632 dma_p = &ring->data[0].dma_data; 1633 #endif 1634 IWH_DBG((IWH_DEBUG_DMA, "iwh_alloc_tx_ring(): " 1635 "tx buffer[0][ncookies:%d addr:%lx " 1636 "size:%lx]\n", 1637 dma_p->ncookies, dma_p->cookie.dmac_address, 1638 dma_p->cookie.dmac_size)); 1639 1640 return (err); 1641 1642 fail: 1643 iwh_free_tx_ring(ring); 1644 1645 return (err); 1646 } 1647 1648 /* 1649 * disable TX ring 1650 */ 1651 static void 1652 iwh_reset_tx_ring(iwh_sc_t *sc, iwh_tx_ring_t *ring) 1653 { 1654 iwh_tx_data_t *data; 1655 int i, n; 1656 1657 iwh_mac_access_enter(sc); 1658 1659 IWH_WRITE(sc, IWH_FH_TCSR_CHNL_TX_CONFIG_REG(ring->qid), 0); 1660 for (n = 0; n < 200; n++) { 1661 if (IWH_READ(sc, IWH_FH_TSSR_TX_STATUS_REG) & 1662 IWH_FH_TSSR_TX_STATUS_REG_MSK_CHNL_IDLE(ring->qid)) { 1663 break; 1664 } 1665 DELAY(10); 1666 } 1667 1668 #ifdef DEBUG 1669 if (200 == n) { 1670 IWH_DBG((IWH_DEBUG_DMA, "iwh_reset_tx_ring(): " 1671 "timeout reset tx ring %d\n", 1672 ring->qid)); 1673 } 1674 #endif 1675 1676 iwh_mac_access_exit(sc); 1677 1678 /* by pass, if it's quiesce */ 1679 if (!(sc->sc_flags & IWH_F_QUIESCED)) { 1680 for (i = 0; i < ring->count; i++) { 1681 data = &ring->data[i]; 1682 IWH_DMA_SYNC(data->dma_data, DDI_DMA_SYNC_FORDEV); 1683 } 1684 } 1685 1686 ring->queued = 0; 1687 ring->cur = 0; 1688 } 1689 1690 static void 1691 iwh_free_tx_ring(iwh_tx_ring_t *ring) 1692 { 1693 int i; 1694 1695 if (ring->dma_desc.dma_hdl != NULL) { 1696 IWH_DMA_SYNC(ring->dma_desc, DDI_DMA_SYNC_FORDEV); 1697 } 1698 iwh_free_dma_mem(&ring->dma_desc); 1699 1700 if (ring->dma_cmd.dma_hdl != NULL) { 1701 IWH_DMA_SYNC(ring->dma_cmd, DDI_DMA_SYNC_FORDEV); 1702 } 1703 iwh_free_dma_mem(&ring->dma_cmd); 1704 1705 if (ring->data != NULL) { 1706 for (i = 0; i < ring->count; i++) { 1707 if (ring->data[i].dma_data.dma_hdl) { 1708 IWH_DMA_SYNC(ring->data[i].dma_data, 1709 DDI_DMA_SYNC_FORDEV); 1710 } 1711 iwh_free_dma_mem(&ring->data[i].dma_data); 1712 } 1713 kmem_free(ring->data, ring->count * sizeof (iwh_tx_data_t)); 1714 } 1715 } 1716 1717 /* 1718 * initialize TX and RX ring 1719 */ 1720 static int 1721 iwh_ring_init(iwh_sc_t *sc) 1722 { 1723 int i, err = DDI_FAILURE; 1724 1725 for (i = 0; i < IWH_NUM_QUEUES; i++) { 1726 if (IWH_CMD_QUEUE_NUM == i) { 1727 continue; 1728 } 1729 1730 err = iwh_alloc_tx_ring(sc, &sc->sc_txq[i], TFD_TX_CMD_SLOTS, 1731 i); 1732 if (err != DDI_SUCCESS) { 1733 goto fail; 1734 } 1735 } 1736 1737 /* 1738 * initialize command queue 1739 */ 1740 err = iwh_alloc_tx_ring(sc, &sc->sc_txq[IWH_CMD_QUEUE_NUM], 1741 TFD_CMD_SLOTS, IWH_CMD_QUEUE_NUM); 1742 if (err != DDI_SUCCESS) { 1743 goto fail; 1744 } 1745 1746 err = iwh_alloc_rx_ring(sc); 1747 if (err != DDI_SUCCESS) { 1748 goto fail; 1749 } 1750 1751 return (err); 1752 1753 fail: 1754 return (err); 1755 } 1756 1757 static void 1758 iwh_ring_free(iwh_sc_t *sc) 1759 { 1760 int i = IWH_NUM_QUEUES; 1761 1762 iwh_free_rx_ring(sc); 1763 while (--i >= 0) { 1764 iwh_free_tx_ring(&sc->sc_txq[i]); 1765 } 1766 } 1767 1768 /* ARGSUSED */ 1769 static ieee80211_node_t * 1770 iwh_node_alloc(ieee80211com_t *ic) 1771 { 1772 iwh_amrr_t *amrr; 1773 1774 amrr = kmem_zalloc(sizeof (iwh_amrr_t), KM_SLEEP); 1775 if (NULL == amrr) { 1776 cmn_err(CE_WARN, "iwh_node_alloc(): " 1777 "failed to allocate memory for amrr structure\n"); 1778 return (NULL); 1779 } 1780 1781 iwh_amrr_init(amrr); 1782 1783 return (&amrr->in); 1784 } 1785 1786 static void 1787 iwh_node_free(ieee80211_node_t *in) 1788 { 1789 ieee80211com_t *ic; 1790 1791 if ((NULL == in) || 1792 (NULL == in->in_ic)) { 1793 cmn_err(CE_WARN, "iwh_node_free() " 1794 "Got a NULL point from Net80211 module\n"); 1795 return; 1796 } 1797 ic = in->in_ic; 1798 1799 if (ic->ic_node_cleanup != NULL) { 1800 ic->ic_node_cleanup(in); 1801 } 1802 1803 if (in->in_wpa_ie != NULL) { 1804 ieee80211_free(in->in_wpa_ie); 1805 } 1806 1807 if (in->in_wme_ie != NULL) { 1808 ieee80211_free(in->in_wme_ie); 1809 } 1810 1811 if (in->in_htcap_ie != NULL) { 1812 ieee80211_free(in->in_htcap_ie); 1813 } 1814 1815 kmem_free(in, sizeof (iwh_amrr_t)); 1816 } 1817 1818 1819 /* 1820 * change station's state. this function will be invoked by 80211 module 1821 * when need to change staton's state. 1822 */ 1823 static int 1824 iwh_newstate(ieee80211com_t *ic, enum ieee80211_state nstate, int arg) 1825 { 1826 iwh_sc_t *sc; 1827 ieee80211_node_t *in; 1828 enum ieee80211_state ostate; 1829 iwh_add_sta_t node; 1830 iwh_amrr_t *amrr; 1831 uint8_t r; 1832 int i, err = IWH_FAIL; 1833 1834 if (NULL == ic) { 1835 return (err); 1836 } 1837 sc = (iwh_sc_t *)ic; 1838 in = ic->ic_bss; 1839 ostate = ic->ic_state; 1840 1841 mutex_enter(&sc->sc_glock); 1842 1843 switch (nstate) { 1844 case IEEE80211_S_SCAN: 1845 switch (ostate) { 1846 case IEEE80211_S_INIT: 1847 sc->sc_flags |= IWH_F_SCANNING; 1848 iwh_set_led(sc, 2, 10, 2); 1849 1850 /* 1851 * clear association to receive beacons from 1852 * all BSS'es 1853 */ 1854 sc->sc_config.assoc_id = 0; 1855 sc->sc_config.filter_flags &= 1856 ~LE_32(RXON_FILTER_ASSOC_MSK); 1857 1858 IWH_DBG((IWH_DEBUG_80211, "iwh_newstate(): " 1859 "config chan %d " 1860 "flags %x filter_flags %x\n", 1861 LE_16(sc->sc_config.chan), 1862 LE_32(sc->sc_config.flags), 1863 LE_32(sc->sc_config.filter_flags))); 1864 1865 err = iwh_cmd(sc, REPLY_RXON, &sc->sc_config, 1866 sizeof (iwh_rxon_cmd_t), 1); 1867 if (err != IWH_SUCCESS) { 1868 cmn_err(CE_WARN, "iwh_newstate(): " 1869 "could not clear association\n"); 1870 sc->sc_flags &= ~IWH_F_SCANNING; 1871 mutex_exit(&sc->sc_glock); 1872 return (err); 1873 } 1874 1875 /* add broadcast node to send probe request */ 1876 (void) memset(&node, 0, sizeof (node)); 1877 (void) memset(&node.sta.addr, 0xff, IEEE80211_ADDR_LEN); 1878 node.sta.sta_id = IWH_BROADCAST_ID; 1879 err = iwh_cmd(sc, REPLY_ADD_STA, &node, 1880 sizeof (node), 1); 1881 if (err != IWH_SUCCESS) { 1882 cmn_err(CE_WARN, "iwh_newstate(): " 1883 "could not add broadcast node\n"); 1884 sc->sc_flags &= ~IWH_F_SCANNING; 1885 mutex_exit(&sc->sc_glock); 1886 return (err); 1887 } 1888 break; 1889 case IEEE80211_S_SCAN: 1890 mutex_exit(&sc->sc_glock); 1891 /* step to next channel before actual FW scan */ 1892 err = sc->sc_newstate(ic, nstate, arg); 1893 mutex_enter(&sc->sc_glock); 1894 if ((err != 0) || ((err = iwh_scan(sc)) != 0)) { 1895 cmn_err(CE_WARN, "iwh_newstate(): " 1896 "could not initiate scan\n"); 1897 sc->sc_flags &= ~IWH_F_SCANNING; 1898 ieee80211_cancel_scan(ic); 1899 } 1900 mutex_exit(&sc->sc_glock); 1901 return (err); 1902 default: 1903 break; 1904 } 1905 sc->sc_clk = 0; 1906 break; 1907 1908 case IEEE80211_S_AUTH: 1909 if (ostate == IEEE80211_S_SCAN) { 1910 sc->sc_flags &= ~IWH_F_SCANNING; 1911 } 1912 1913 /* 1914 * reset state to handle reassociations correctly 1915 */ 1916 sc->sc_config.assoc_id = 0; 1917 sc->sc_config.filter_flags &= ~LE_32(RXON_FILTER_ASSOC_MSK); 1918 1919 /* 1920 * before sending authentication and association request frame, 1921 * we need do something in the hardware, such as setting the 1922 * channel same to the target AP... 1923 */ 1924 if ((err = iwh_hw_set_before_auth(sc)) != 0) { 1925 IWH_DBG((IWH_DEBUG_80211, "iwh_newstate(): " 1926 "could not send authentication request\n")); 1927 mutex_exit(&sc->sc_glock); 1928 return (err); 1929 } 1930 break; 1931 1932 case IEEE80211_S_RUN: 1933 if (ostate == IEEE80211_S_SCAN) { 1934 sc->sc_flags &= ~IWH_F_SCANNING; 1935 } 1936 1937 if (IEEE80211_M_MONITOR == ic->ic_opmode) { 1938 /* let LED blink when monitoring */ 1939 iwh_set_led(sc, 2, 10, 10); 1940 break; 1941 } 1942 1943 IWH_DBG((IWH_DEBUG_80211, "iwh_newstate(): " 1944 "associated.\n")); 1945 1946 err = iwh_run_state_config(sc); 1947 if (err != IWH_SUCCESS) { 1948 cmn_err(CE_WARN, "iwh_newstate(): " 1949 "failed to set up association\n"); 1950 mutex_exit(&sc->sc_glock); 1951 return (err); 1952 } 1953 1954 /* 1955 * start automatic rate control 1956 */ 1957 if ((in->in_flags & IEEE80211_NODE_HT) && 1958 (sc->sc_ht_conf.ht_support) && 1959 (in->in_htrates.rs_nrates > 0) && 1960 (in->in_htrates.rs_nrates <= IEEE80211_HTRATE_MAXSIZE)) { 1961 amrr = (iwh_amrr_t *)in; 1962 1963 for (i = in->in_htrates.rs_nrates - 1; i > 0; i--) { 1964 1965 r = in->in_htrates.rs_rates[i] & 1966 IEEE80211_RATE_VAL; 1967 if ((r != 0) && (r <= 0xd) && 1968 (sc->sc_ht_conf.tx_support_mcs[r/8] & 1969 (1 << (r%8)))) { 1970 amrr->ht_mcs_idx = r; 1971 sc->sc_flags |= IWH_F_RATE_AUTO_CTL; 1972 break; 1973 } 1974 } 1975 } else { 1976 if (IEEE80211_FIXED_RATE_NONE == ic->ic_fixed_rate) { 1977 sc->sc_flags |= IWH_F_RATE_AUTO_CTL; 1978 1979 /* 1980 * set rate to some reasonable initial value 1981 */ 1982 i = in->in_rates.ir_nrates - 1; 1983 while (i > 0 && IEEE80211_RATE(i) > 72) { 1984 i--; 1985 } 1986 in->in_txrate = i; 1987 1988 } else { 1989 sc->sc_flags &= ~IWH_F_RATE_AUTO_CTL; 1990 } 1991 } 1992 1993 /* 1994 * set LED on after associated 1995 */ 1996 iwh_set_led(sc, 2, 0, 1); 1997 break; 1998 1999 case IEEE80211_S_INIT: 2000 if (ostate == IEEE80211_S_SCAN) { 2001 sc->sc_flags &= ~IWH_F_SCANNING; 2002 } 2003 /* 2004 * set LED off after init 2005 */ 2006 iwh_set_led(sc, 2, 1, 0); 2007 break; 2008 2009 case IEEE80211_S_ASSOC: 2010 if (ostate == IEEE80211_S_SCAN) { 2011 sc->sc_flags &= ~IWH_F_SCANNING; 2012 } 2013 break; 2014 } 2015 2016 mutex_exit(&sc->sc_glock); 2017 2018 return (sc->sc_newstate(ic, nstate, arg)); 2019 } 2020 2021 /* 2022 * exclusive access to mac begin. 2023 */ 2024 static void 2025 iwh_mac_access_enter(iwh_sc_t *sc) 2026 { 2027 uint32_t tmp; 2028 int n; 2029 2030 tmp = IWH_READ(sc, CSR_GP_CNTRL); 2031 IWH_WRITE(sc, CSR_GP_CNTRL, 2032 tmp | CSR_GP_CNTRL_REG_FLAG_MAC_ACCESS_REQ); 2033 2034 /* wait until we succeed */ 2035 for (n = 0; n < 1000; n++) { 2036 if ((IWH_READ(sc, CSR_GP_CNTRL) & 2037 (CSR_GP_CNTRL_REG_FLAG_MAC_CLOCK_READY | 2038 CSR_GP_CNTRL_REG_FLAG_GOING_TO_SLEEP)) == 2039 CSR_GP_CNTRL_REG_VAL_MAC_ACCESS_EN) { 2040 break; 2041 } 2042 DELAY(10); 2043 } 2044 2045 #ifdef DEBUG 2046 if (1000 == n) { 2047 IWH_DBG((IWH_DEBUG_PIO, "iwh_mac_access_enter(): " 2048 "could not lock memory\n")); 2049 } 2050 #endif 2051 } 2052 2053 /* 2054 * exclusive access to mac end. 2055 */ 2056 static void 2057 iwh_mac_access_exit(iwh_sc_t *sc) 2058 { 2059 uint32_t tmp = IWH_READ(sc, CSR_GP_CNTRL); 2060 IWH_WRITE(sc, CSR_GP_CNTRL, 2061 tmp & ~CSR_GP_CNTRL_REG_FLAG_MAC_ACCESS_REQ); 2062 } 2063 2064 /* 2065 * this function defined here for future use. 2066 * static uint32_t 2067 * iwh_mem_read(iwh_sc_t *sc, uint32_t addr) 2068 * { 2069 * IWH_WRITE(sc, HBUS_TARG_MEM_RADDR, addr); 2070 * return (IWH_READ(sc, HBUS_TARG_MEM_RDAT)); 2071 * } 2072 */ 2073 2074 /* 2075 * write mac memory 2076 */ 2077 static void 2078 iwh_mem_write(iwh_sc_t *sc, uint32_t addr, uint32_t data) 2079 { 2080 IWH_WRITE(sc, HBUS_TARG_MEM_WADDR, addr); 2081 IWH_WRITE(sc, HBUS_TARG_MEM_WDAT, data); 2082 } 2083 2084 /* 2085 * read mac register 2086 */ 2087 static uint32_t 2088 iwh_reg_read(iwh_sc_t *sc, uint32_t addr) 2089 { 2090 IWH_WRITE(sc, HBUS_TARG_PRPH_RADDR, addr | (3 << 24)); 2091 return (IWH_READ(sc, HBUS_TARG_PRPH_RDAT)); 2092 } 2093 2094 /* 2095 * write mac register 2096 */ 2097 static void 2098 iwh_reg_write(iwh_sc_t *sc, uint32_t addr, uint32_t data) 2099 { 2100 IWH_WRITE(sc, HBUS_TARG_PRPH_WADDR, addr | (3 << 24)); 2101 IWH_WRITE(sc, HBUS_TARG_PRPH_WDAT, data); 2102 } 2103 2104 2105 /* 2106 * steps of loading ucode: 2107 * load init ucode=>init alive=>calibrate=> 2108 * receive calibration result=>reinitialize NIC=> 2109 * load runtime ucode=>runtime alive=> 2110 * send calibration result=>running. 2111 */ 2112 static int 2113 iwh_load_init_firmware(iwh_sc_t *sc) 2114 { 2115 int err = IWH_FAIL; 2116 clock_t clk; 2117 2118 sc->sc_flags &= ~IWH_F_PUT_SEG; 2119 2120 /* 2121 * load init_text section of uCode to hardware 2122 */ 2123 err = iwh_put_seg_fw(sc, sc->sc_dma_fw_init_text.cookie.dmac_address, 2124 RTC_INST_LOWER_BOUND, sc->sc_dma_fw_init_text.cookie.dmac_size); 2125 if (err != IWH_SUCCESS) { 2126 cmn_err(CE_WARN, "iwh_load_init_firmware(): " 2127 "failed to write init uCode.\n"); 2128 return (err); 2129 } 2130 2131 clk = ddi_get_lbolt() + drv_usectohz(1000000); 2132 2133 /* wait loading init_text until completed or timeout */ 2134 while (!(sc->sc_flags & IWH_F_PUT_SEG)) { 2135 if (cv_timedwait(&sc->sc_put_seg_cv, &sc->sc_glock, clk) < 0) { 2136 break; 2137 } 2138 } 2139 2140 if (!(sc->sc_flags & IWH_F_PUT_SEG)) { 2141 cmn_err(CE_WARN, "iwh_load_init_firmware(): " 2142 "timeout waiting for init uCode load.\n"); 2143 return (IWH_FAIL); 2144 } 2145 2146 sc->sc_flags &= ~IWH_F_PUT_SEG; 2147 2148 /* 2149 * load init_data section of uCode to hardware 2150 */ 2151 err = iwh_put_seg_fw(sc, sc->sc_dma_fw_init_data.cookie.dmac_address, 2152 RTC_DATA_LOWER_BOUND, sc->sc_dma_fw_init_data.cookie.dmac_size); 2153 if (err != IWH_SUCCESS) { 2154 cmn_err(CE_WARN, "iwh_load_init_firmware(): " 2155 "failed to write init_data uCode.\n"); 2156 return (err); 2157 } 2158 2159 clk = ddi_get_lbolt() + drv_usectohz(1000000); 2160 2161 /* 2162 * wait loading init_data until completed or timeout 2163 */ 2164 while (!(sc->sc_flags & IWH_F_PUT_SEG)) { 2165 if (cv_timedwait(&sc->sc_put_seg_cv, &sc->sc_glock, clk) < 0) { 2166 break; 2167 } 2168 } 2169 2170 if (!(sc->sc_flags & IWH_F_PUT_SEG)) { 2171 cmn_err(CE_WARN, "iwh_load_init_firmware(): " 2172 "timeout waiting for init_data uCode load.\n"); 2173 return (IWH_FAIL); 2174 } 2175 2176 sc->sc_flags &= ~IWH_F_PUT_SEG; 2177 2178 return (err); 2179 } 2180 2181 static int 2182 iwh_load_run_firmware(iwh_sc_t *sc) 2183 { 2184 int err = IWH_FAIL; 2185 clock_t clk; 2186 2187 sc->sc_flags &= ~IWH_F_PUT_SEG; 2188 2189 /* 2190 * load init_text section of uCode to hardware 2191 */ 2192 err = iwh_put_seg_fw(sc, sc->sc_dma_fw_text.cookie.dmac_address, 2193 RTC_INST_LOWER_BOUND, sc->sc_dma_fw_text.cookie.dmac_size); 2194 if (err != IWH_SUCCESS) { 2195 cmn_err(CE_WARN, "iwh_load_run_firmware(): " 2196 "failed to write run uCode.\n"); 2197 return (err); 2198 } 2199 2200 clk = ddi_get_lbolt() + drv_usectohz(1000000); 2201 2202 /* wait loading run_text until completed or timeout */ 2203 while (!(sc->sc_flags & IWH_F_PUT_SEG)) { 2204 if (cv_timedwait(&sc->sc_put_seg_cv, &sc->sc_glock, clk) < 0) { 2205 break; 2206 } 2207 } 2208 2209 if (!(sc->sc_flags & IWH_F_PUT_SEG)) { 2210 cmn_err(CE_WARN, "iwh_load_run_firmware(): " 2211 "timeout waiting for run uCode load.\n"); 2212 return (IWH_FAIL); 2213 } 2214 2215 sc->sc_flags &= ~IWH_F_PUT_SEG; 2216 2217 /* 2218 * load run_data section of uCode to hardware 2219 */ 2220 err = iwh_put_seg_fw(sc, sc->sc_dma_fw_data_bak.cookie.dmac_address, 2221 RTC_DATA_LOWER_BOUND, sc->sc_dma_fw_data.cookie.dmac_size); 2222 if (err != IWH_SUCCESS) { 2223 cmn_err(CE_WARN, "iwh_load_run_firmware(): " 2224 "failed to write run_data uCode.\n"); 2225 return (err); 2226 } 2227 2228 clk = ddi_get_lbolt() + drv_usectohz(1000000); 2229 2230 /* 2231 * wait loading run_data until completed or timeout 2232 */ 2233 while (!(sc->sc_flags & IWH_F_PUT_SEG)) { 2234 if (cv_timedwait(&sc->sc_put_seg_cv, &sc->sc_glock, clk) < 0) { 2235 break; 2236 } 2237 } 2238 2239 if (!(sc->sc_flags & IWH_F_PUT_SEG)) { 2240 cmn_err(CE_WARN, "iwh_load_run_firmware(): " 2241 "timeout waiting for run_data uCode load.\n"); 2242 return (IWH_FAIL); 2243 } 2244 2245 sc->sc_flags &= ~IWH_F_PUT_SEG; 2246 2247 return (err); 2248 } 2249 2250 /* 2251 * this function will be invoked to receive phy information 2252 * when a frame is received. 2253 */ 2254 static void 2255 iwh_rx_phy_intr(iwh_sc_t *sc, iwh_rx_desc_t *desc) 2256 { 2257 2258 sc->sc_rx_phy_res.flag = 1; 2259 2260 (void) memcpy(sc->sc_rx_phy_res.buf, (uint8_t *)(desc + 1), 2261 sizeof (iwh_rx_phy_res_t)); 2262 } 2263 2264 /* 2265 * this function will be invoked to receive body of frame when 2266 * a frame is received. 2267 */ 2268 static void 2269 iwh_rx_mpdu_intr(iwh_sc_t *sc, iwh_rx_desc_t *desc) 2270 { 2271 ieee80211com_t *ic = &sc->sc_ic; 2272 #ifdef DEBUG 2273 iwh_rx_ring_t *ring = &sc->sc_rxq; 2274 #endif 2275 struct ieee80211_frame *wh; 2276 struct iwh_rx_non_cfg_phy *phyinfo; 2277 struct iwh_rx_mpdu_body_size *mpdu_size; 2278 2279 mblk_t *mp; 2280 int16_t t; 2281 uint16_t len, rssi, agc; 2282 uint32_t temp, crc, *tail; 2283 uint32_t arssi, brssi, crssi, mrssi; 2284 iwh_rx_phy_res_t *stat; 2285 ieee80211_node_t *in; 2286 2287 /* 2288 * assuming not 11n here. cope with 11n in phase-II 2289 */ 2290 mpdu_size = (struct iwh_rx_mpdu_body_size *)(desc + 1); 2291 stat = (iwh_rx_phy_res_t *)sc->sc_rx_phy_res.buf; 2292 if (stat->cfg_phy_cnt > 20) { 2293 return; 2294 } 2295 2296 phyinfo = (struct iwh_rx_non_cfg_phy *)stat->non_cfg_phy; 2297 temp = LE_32(phyinfo->non_cfg_phy[IWH_RX_RES_AGC_IDX]); 2298 agc = (temp & IWH_OFDM_AGC_MSK) >> IWH_OFDM_AGC_BIT_POS; 2299 2300 temp = LE_32(phyinfo->non_cfg_phy[IWH_RX_RES_RSSI_AB_IDX]); 2301 arssi = (temp & IWH_OFDM_RSSI_A_MSK) >> IWH_OFDM_RSSI_A_BIT_POS; 2302 brssi = (temp & IWH_OFDM_RSSI_B_MSK) >> IWH_OFDM_RSSI_B_BIT_POS; 2303 2304 temp = LE_32(phyinfo->non_cfg_phy[IWH_RX_RES_RSSI_C_IDX]); 2305 crssi = (temp & IWH_OFDM_RSSI_C_MSK) >> IWH_OFDM_RSSI_C_BIT_POS; 2306 2307 mrssi = MAX(arssi, brssi); 2308 mrssi = MAX(mrssi, crssi); 2309 2310 t = mrssi - agc - IWH_RSSI_OFFSET; 2311 /* 2312 * convert dBm to percentage 2313 */ 2314 rssi = (100 * 75 * 75 - (-20 - t) * (15 * 75 + 62 * (-20 - t))) 2315 / (75 * 75); 2316 if (rssi > 100) { 2317 rssi = 100; 2318 } 2319 if (rssi < 1) { 2320 rssi = 1; 2321 } 2322 2323 /* 2324 * size of frame, not include FCS 2325 */ 2326 len = LE_16(mpdu_size->byte_count); 2327 tail = (uint32_t *)((uint8_t *)(desc + 1) + 2328 sizeof (struct iwh_rx_mpdu_body_size) + len); 2329 bcopy(tail, &crc, 4); 2330 2331 IWH_DBG((IWH_DEBUG_RX, "iwh_rx_mpdu_intr(): " 2332 "rx intr: idx=%d phy_len=%x len=%d " 2333 "rate=%x chan=%d tstamp=%x non_cfg_phy_count=%x " 2334 "cfg_phy_count=%x tail=%x", ring->cur, sizeof (*stat), 2335 len, stat->rate.r.s.rate, stat->channel, 2336 LE_32(stat->timestampl), stat->non_cfg_phy_cnt, 2337 stat->cfg_phy_cnt, LE_32(crc))); 2338 2339 if ((len < 16) || (len > sc->sc_dmabuf_sz)) { 2340 IWH_DBG((IWH_DEBUG_RX, "iwh_rx_mpdu_intr(): " 2341 "rx frame oversize\n")); 2342 return; 2343 } 2344 2345 /* 2346 * discard Rx frames with bad CRC 2347 */ 2348 if ((LE_32(crc) & 2349 (RX_RES_STATUS_NO_CRC32_ERROR | RX_RES_STATUS_NO_RXE_OVERFLOW)) != 2350 (RX_RES_STATUS_NO_CRC32_ERROR | RX_RES_STATUS_NO_RXE_OVERFLOW)) { 2351 IWH_DBG((IWH_DEBUG_RX, "iwh_rx_mpdu_intr(): " 2352 "rx crc error tail: %x\n", 2353 LE_32(crc))); 2354 sc->sc_rx_err++; 2355 return; 2356 } 2357 2358 wh = (struct ieee80211_frame *) 2359 ((uint8_t *)(desc + 1)+ sizeof (struct iwh_rx_mpdu_body_size)); 2360 2361 if (IEEE80211_FC0_SUBTYPE_ASSOC_RESP == *(uint8_t *)wh) { 2362 sc->sc_assoc_id = *((uint16_t *)(wh + 1) + 2); 2363 IWH_DBG((IWH_DEBUG_RX, "iwh_rx_mpdu_intr(): " 2364 "rx : association id = %x\n", 2365 sc->sc_assoc_id)); 2366 } 2367 2368 #ifdef DEBUG 2369 if (iwh_dbg_flags & IWH_DEBUG_RX) { 2370 ieee80211_dump_pkt((uint8_t *)wh, len, 0, 0); 2371 } 2372 #endif 2373 2374 in = ieee80211_find_rxnode(ic, wh); 2375 mp = allocb(len, BPRI_MED); 2376 if (mp) { 2377 (void) memcpy(mp->b_wptr, wh, len); 2378 mp->b_wptr += len; 2379 2380 /* 2381 * send the frame to the 802.11 layer 2382 */ 2383 (void) ieee80211_input(ic, mp, in, rssi, 0); 2384 } else { 2385 sc->sc_rx_nobuf++; 2386 IWH_DBG((IWH_DEBUG_RX, "iwh_rx_mpdu_intr(): " 2387 "alloc rx buf failed\n")); 2388 } 2389 2390 /* 2391 * release node reference 2392 */ 2393 ieee80211_free_node(in); 2394 } 2395 2396 /* 2397 * process correlative affairs after a frame is sent. 2398 */ 2399 static void 2400 iwh_tx_intr(iwh_sc_t *sc, iwh_rx_desc_t *desc) 2401 { 2402 ieee80211com_t *ic = &sc->sc_ic; 2403 iwh_tx_ring_t *ring = &sc->sc_txq[desc->hdr.qid & 0x3]; 2404 iwh_tx_stat_t *stat = (iwh_tx_stat_t *)(desc + 1); 2405 iwh_amrr_t *amrr; 2406 2407 if (NULL == ic->ic_bss) { 2408 return; 2409 } 2410 2411 amrr = (iwh_amrr_t *)ic->ic_bss; 2412 2413 amrr->txcnt++; 2414 IWH_DBG((IWH_DEBUG_RATECTL, "iwh_tx_intr(): " 2415 "tx: %d cnt\n", amrr->txcnt)); 2416 2417 if (stat->ntries > 0) { 2418 amrr->retrycnt++; 2419 sc->sc_tx_retries++; 2420 IWH_DBG((IWH_DEBUG_TX, "iwh_tx_intr(): " 2421 "tx: %d retries\n", 2422 sc->sc_tx_retries)); 2423 } 2424 2425 mutex_enter(&sc->sc_mt_lock); 2426 sc->sc_tx_timer = 0; 2427 mutex_exit(&sc->sc_mt_lock); 2428 2429 mutex_enter(&sc->sc_tx_lock); 2430 2431 ring->queued--; 2432 if (ring->queued < 0) { 2433 ring->queued = 0; 2434 } 2435 2436 if ((sc->sc_need_reschedule) && (ring->queued <= (ring->count >> 3))) { 2437 sc->sc_need_reschedule = 0; 2438 mutex_exit(&sc->sc_tx_lock); 2439 mac_tx_update(ic->ic_mach); 2440 mutex_enter(&sc->sc_tx_lock); 2441 } 2442 2443 mutex_exit(&sc->sc_tx_lock); 2444 } 2445 2446 /* 2447 * inform a given command has been executed 2448 */ 2449 static void 2450 iwh_cmd_intr(iwh_sc_t *sc, iwh_rx_desc_t *desc) 2451 { 2452 if ((desc->hdr.qid & 7) != 4) { 2453 return; 2454 } 2455 2456 if (sc->sc_cmd_accum > 0) { 2457 sc->sc_cmd_accum--; 2458 return; 2459 } 2460 2461 mutex_enter(&sc->sc_glock); 2462 2463 sc->sc_cmd_flag = SC_CMD_FLG_DONE; 2464 2465 cv_signal(&sc->sc_cmd_cv); 2466 2467 mutex_exit(&sc->sc_glock); 2468 2469 IWH_DBG((IWH_DEBUG_CMD, "iwh_cmd_intr(): " 2470 "qid=%x idx=%d flags=%x type=0x%x\n", 2471 desc->hdr.qid, desc->hdr.idx, desc->hdr.flags, 2472 desc->hdr.type)); 2473 } 2474 2475 /* 2476 * this function will be invoked when alive notification occur. 2477 */ 2478 static void 2479 iwh_ucode_alive(iwh_sc_t *sc, iwh_rx_desc_t *desc) 2480 { 2481 uint32_t rv; 2482 struct iwh_calib_cfg_cmd cmd; 2483 struct iwh_alive_resp *ar = 2484 (struct iwh_alive_resp *)(desc + 1); 2485 struct iwh_calib_results *res_p = &sc->sc_calib_results; 2486 2487 /* 2488 * the microcontroller is ready 2489 */ 2490 IWH_DBG((IWH_DEBUG_FW, "iwh_ucode_alive(): " 2491 "microcode alive notification minor: %x major: %x type: " 2492 "%x subtype: %x\n", 2493 ar->ucode_minor, ar->ucode_minor, ar->ver_type, ar->ver_subtype)); 2494 2495 #ifdef DEBUG 2496 if (LE_32(ar->is_valid) != UCODE_VALID_OK) { 2497 IWH_DBG((IWH_DEBUG_FW, "iwh_ucode_alive(): " 2498 "microcontroller initialization failed\n")); 2499 } 2500 #endif 2501 2502 /* 2503 * determine if init alive or runtime alive. 2504 */ 2505 if (INITIALIZE_SUBTYPE == ar->ver_subtype) { 2506 IWH_DBG((IWH_DEBUG_FW, "iwh_ucode_alive(): " 2507 "initialization alive received.\n")); 2508 2509 (void) memcpy(&sc->sc_card_alive_init, ar, 2510 sizeof (struct iwh_init_alive_resp)); 2511 2512 /* 2513 * necessary configuration to NIC 2514 */ 2515 mutex_enter(&sc->sc_glock); 2516 2517 rv = iwh_alive_common(sc); 2518 if (rv != IWH_SUCCESS) { 2519 cmn_err(CE_WARN, "iwh_ucode_alive(): " 2520 "common alive process failed in init alive.\n"); 2521 mutex_exit(&sc->sc_glock); 2522 return; 2523 } 2524 2525 (void) memset(&cmd, 0, sizeof (cmd)); 2526 2527 cmd.ucd_calib_cfg.once.is_enable = IWH_CALIB_INIT_CFG_ALL; 2528 cmd.ucd_calib_cfg.once.start = IWH_CALIB_INIT_CFG_ALL; 2529 cmd.ucd_calib_cfg.once.send_res = IWH_CALIB_INIT_CFG_ALL; 2530 cmd.ucd_calib_cfg.flags = IWH_CALIB_INIT_CFG_ALL; 2531 2532 /* 2533 * require ucode execute calibration 2534 */ 2535 rv = iwh_cmd(sc, CALIBRATION_CFG_CMD, &cmd, sizeof (cmd), 1); 2536 if (rv != IWH_SUCCESS) { 2537 cmn_err(CE_WARN, "iwh_ucode_alive(): " 2538 "failed to send calibration configure command.\n"); 2539 mutex_exit(&sc->sc_glock); 2540 return; 2541 } 2542 2543 mutex_exit(&sc->sc_glock); 2544 2545 } else { /* runtime alive */ 2546 2547 IWH_DBG((IWH_DEBUG_FW, "iwh_ucode_alive(): " 2548 "runtime alive received.\n")); 2549 2550 (void) memcpy(&sc->sc_card_alive_run, ar, 2551 sizeof (struct iwh_alive_resp)); 2552 2553 mutex_enter(&sc->sc_glock); 2554 2555 /* 2556 * necessary configuration to NIC 2557 */ 2558 rv = iwh_alive_common(sc); 2559 if (rv != IWH_SUCCESS) { 2560 cmn_err(CE_WARN, "iwh_ucode_alive(): " 2561 "common alive process failed in run alive.\n"); 2562 mutex_exit(&sc->sc_glock); 2563 return; 2564 } 2565 2566 /* 2567 * send the result of local oscilator calibration to uCode. 2568 */ 2569 if (res_p->lo_res != NULL) { 2570 rv = iwh_cmd(sc, REPLY_PHY_CALIBRATION_CMD, 2571 res_p->lo_res, res_p->lo_res_len, 1); 2572 if (rv != IWH_SUCCESS) { 2573 cmn_err(CE_WARN, "iwh_ucode_alive(): " 2574 "failed to send local" 2575 "oscilator calibration command.\n"); 2576 mutex_exit(&sc->sc_glock); 2577 return; 2578 } 2579 2580 DELAY(1000); 2581 } 2582 2583 /* 2584 * send the result of TX IQ calibration to uCode. 2585 */ 2586 if (res_p->tx_iq_res != NULL) { 2587 rv = iwh_cmd(sc, REPLY_PHY_CALIBRATION_CMD, 2588 res_p->tx_iq_res, res_p->tx_iq_res_len, 1); 2589 if (rv != IWH_SUCCESS) { 2590 cmn_err(CE_WARN, "iwh_ucode_alive(): " 2591 "failed to send TX IQ" 2592 "calibration command.\n"); 2593 mutex_exit(&sc->sc_glock); 2594 return; 2595 } 2596 2597 DELAY(1000); 2598 } 2599 2600 /* 2601 * sned the result of TX IQ perd calibration to uCode. 2602 */ 2603 if (res_p->tx_iq_perd_res != NULL) { 2604 rv = iwh_cmd(sc, REPLY_PHY_CALIBRATION_CMD, 2605 res_p->tx_iq_perd_res, 2606 res_p->tx_iq_perd_res_len, 1); 2607 if (rv != IWH_SUCCESS) { 2608 cmn_err(CE_WARN, "iwh_ucode_alive(): " 2609 "failed to send TX IQ perd" 2610 "calibration command.\n"); 2611 mutex_exit(&sc->sc_glock); 2612 return; 2613 } 2614 2615 DELAY(1000); 2616 } 2617 2618 sc->sc_flags |= IWH_F_FW_INIT; 2619 cv_signal(&sc->sc_ucode_cv); 2620 2621 mutex_exit(&sc->sc_glock); 2622 } 2623 2624 } 2625 2626 /* 2627 * deal with receiving frames, command response 2628 * and all notifications from ucode. 2629 */ 2630 /* ARGSUSED */ 2631 static uint_t 2632 iwh_rx_softintr(caddr_t arg, caddr_t unused) 2633 { 2634 iwh_sc_t *sc; 2635 ieee80211com_t *ic; 2636 iwh_rx_desc_t *desc; 2637 iwh_rx_data_t *data; 2638 uint32_t index; 2639 2640 if (NULL == arg) { 2641 return (DDI_INTR_UNCLAIMED); 2642 } 2643 sc = (iwh_sc_t *)arg; 2644 ic = &sc->sc_ic; 2645 2646 /* 2647 * firmware has moved the index of the rx queue, driver get it, 2648 * and deal with it. 2649 */ 2650 index = (sc->sc_shared->val0) & 0xfff; 2651 2652 while (sc->sc_rxq.cur != index) { 2653 data = &sc->sc_rxq.data[sc->sc_rxq.cur]; 2654 desc = (iwh_rx_desc_t *)data->dma_data.mem_va; 2655 2656 IWH_DBG((IWH_DEBUG_INTR, "iwh_rx_softintr(): " 2657 "rx notification index = %d" 2658 " cur = %d qid=%x idx=%d flags=%x type=%x len=%d\n", 2659 index, sc->sc_rxq.cur, desc->hdr.qid, desc->hdr.idx, 2660 desc->hdr.flags, desc->hdr.type, LE_32(desc->len))); 2661 2662 /* 2663 * a command other than a tx need to be replied 2664 */ 2665 if (!(desc->hdr.qid & 0x80) && 2666 (desc->hdr.type != REPLY_SCAN_CMD) && 2667 (desc->hdr.type != REPLY_TX)) { 2668 iwh_cmd_intr(sc, desc); 2669 } 2670 2671 switch (desc->hdr.type) { 2672 case REPLY_RX_PHY_CMD: 2673 iwh_rx_phy_intr(sc, desc); 2674 break; 2675 2676 case REPLY_RX_MPDU_CMD: 2677 iwh_rx_mpdu_intr(sc, desc); 2678 break; 2679 2680 case REPLY_TX: 2681 iwh_tx_intr(sc, desc); 2682 break; 2683 2684 case REPLY_ALIVE: 2685 iwh_ucode_alive(sc, desc); 2686 break; 2687 2688 case CARD_STATE_NOTIFICATION: 2689 { 2690 uint32_t *status = (uint32_t *)(desc + 1); 2691 2692 IWH_DBG((IWH_DEBUG_RADIO, "iwh_rx_softintr(): " 2693 "state changed to %x\n", 2694 LE_32(*status))); 2695 2696 if (LE_32(*status) & 1) { 2697 /* 2698 * the radio button has to be pushed(OFF). It 2699 * is considered as a hw error, the 2700 * iwh_thread() tries to recover it after the 2701 * button is pushed again(ON) 2702 */ 2703 cmn_err(CE_NOTE, "iwh_rx_softintr(): " 2704 "radio transmitter is off\n"); 2705 sc->sc_ostate = sc->sc_ic.ic_state; 2706 ieee80211_new_state(&sc->sc_ic, 2707 IEEE80211_S_INIT, -1); 2708 sc->sc_flags |= 2709 (IWH_F_HW_ERR_RECOVER | IWH_F_RADIO_OFF); 2710 } 2711 2712 break; 2713 } 2714 2715 case SCAN_START_NOTIFICATION: 2716 { 2717 iwh_start_scan_t *scan = 2718 (iwh_start_scan_t *)(desc + 1); 2719 2720 IWH_DBG((IWH_DEBUG_SCAN, "iwh_rx_softintr(): " 2721 "scanning channel %d status %x\n", 2722 scan->chan, LE_32(scan->status))); 2723 2724 ic->ic_curchan = &ic->ic_sup_channels[scan->chan]; 2725 break; 2726 } 2727 2728 case SCAN_COMPLETE_NOTIFICATION: 2729 { 2730 #ifdef DEBUG 2731 iwh_stop_scan_t *scan = 2732 (iwh_stop_scan_t *)(desc + 1); 2733 2734 IWH_DBG((IWH_DEBUG_SCAN, "iwh_rx_softintr(): " 2735 "completed channel %d (burst of %d) status %02x\n", 2736 scan->chan, scan->nchan, scan->status)); 2737 #endif 2738 2739 sc->sc_scan_pending++; 2740 break; 2741 } 2742 2743 case STATISTICS_NOTIFICATION: 2744 { 2745 /* 2746 * handle statistics notification 2747 */ 2748 break; 2749 } 2750 2751 case CALIBRATION_RES_NOTIFICATION: 2752 iwh_save_calib_result(sc, desc); 2753 break; 2754 2755 case CALIBRATION_COMPLETE_NOTIFICATION: 2756 mutex_enter(&sc->sc_glock); 2757 sc->sc_flags |= IWH_F_FW_INIT; 2758 cv_signal(&sc->sc_ucode_cv); 2759 mutex_exit(&sc->sc_glock); 2760 break; 2761 2762 case MISSED_BEACONS_NOTIFICATION: 2763 { 2764 struct iwh_beacon_missed *miss = 2765 (struct iwh_beacon_missed *)(desc + 1); 2766 2767 if ((ic->ic_state == IEEE80211_S_RUN) && 2768 (LE_32(miss->consecutive) > 50)) { 2769 cmn_err(CE_NOTE, "iwh: iwh_rx_softintr(): " 2770 "beacon missed %d/%d\n", 2771 LE_32(miss->consecutive), 2772 LE_32(miss->total)); 2773 (void) ieee80211_new_state(ic, 2774 IEEE80211_S_INIT, -1); 2775 } 2776 break; 2777 } 2778 } 2779 2780 sc->sc_rxq.cur = (sc->sc_rxq.cur + 1) % RX_QUEUE_SIZE; 2781 } 2782 2783 /* 2784 * driver dealt with what received in rx queue and tell the information 2785 * to the firmware. 2786 */ 2787 index = (0 == index) ? RX_QUEUE_SIZE - 1 : index - 1; 2788 IWH_WRITE(sc, FH_RSCSR_CHNL0_RBDCB_WPTR_REG, index & (~7)); 2789 2790 /* 2791 * re-enable interrupts 2792 */ 2793 IWH_WRITE(sc, CSR_INT_MASK, CSR_INI_SET_MASK); 2794 2795 return (DDI_INTR_CLAIMED); 2796 } 2797 2798 /* 2799 * the handle of interrupt 2800 */ 2801 /* ARGSUSED */ 2802 static uint_t 2803 iwh_intr(caddr_t arg, caddr_t unused) 2804 { 2805 iwh_sc_t *sc; 2806 uint32_t r, rfh; 2807 2808 if (NULL == arg) { 2809 return (DDI_INTR_UNCLAIMED); 2810 } 2811 sc = (iwh_sc_t *)arg; 2812 2813 mutex_enter(&sc->sc_suspend_lock); 2814 2815 if (sc->sc_flags & IWH_F_SUSPEND) { 2816 mutex_exit(&sc->sc_suspend_lock); 2817 return (DDI_INTR_UNCLAIMED); 2818 } 2819 2820 r = IWH_READ(sc, CSR_INT); 2821 if (0 == r || 0xffffffff == r) { 2822 mutex_exit(&sc->sc_suspend_lock); 2823 return (DDI_INTR_UNCLAIMED); 2824 } 2825 2826 IWH_DBG((IWH_DEBUG_INTR, "iwh_intr(): " 2827 "interrupt reg %x\n", r)); 2828 2829 rfh = IWH_READ(sc, CSR_FH_INT_STATUS); 2830 2831 IWH_DBG((IWH_DEBUG_INTR, "iwh_intr(): " 2832 "FH interrupt reg %x\n", rfh)); 2833 2834 /* 2835 * disable interrupts 2836 */ 2837 IWH_WRITE(sc, CSR_INT_MASK, 0); 2838 2839 /* 2840 * ack interrupts 2841 */ 2842 IWH_WRITE(sc, CSR_INT, r); 2843 IWH_WRITE(sc, CSR_FH_INT_STATUS, rfh); 2844 2845 if (r & (BIT_INT_SWERROR | BIT_INT_ERR)) { 2846 IWH_DBG((IWH_DEBUG_FW, "iwh_intr(): " 2847 "fatal firmware error\n")); 2848 mutex_exit(&sc->sc_suspend_lock); 2849 iwh_stop(sc); 2850 sc->sc_ostate = sc->sc_ic.ic_state; 2851 2852 /* notify upper layer */ 2853 if (!IWH_CHK_FAST_RECOVER(sc)) { 2854 ieee80211_new_state(&sc->sc_ic, IEEE80211_S_INIT, -1); 2855 } 2856 2857 sc->sc_flags |= IWH_F_HW_ERR_RECOVER; 2858 return (DDI_INTR_CLAIMED); 2859 } 2860 2861 if (r & BIT_INT_RF_KILL) { 2862 uint32_t tmp = IWH_READ(sc, CSR_GP_CNTRL); 2863 if (tmp & (1 << 27)) { 2864 cmn_err(CE_NOTE, "RF switch: radio on\n"); 2865 } 2866 } 2867 2868 if ((r & (BIT_INT_FH_RX | BIT_INT_SW_RX)) || 2869 (rfh & FH_INT_RX_MASK)) { 2870 (void) ddi_intr_trigger_softint(sc->sc_soft_hdl, NULL); 2871 mutex_exit(&sc->sc_suspend_lock); 2872 return (DDI_INTR_CLAIMED); 2873 } 2874 2875 if (r & BIT_INT_FH_TX) { 2876 mutex_enter(&sc->sc_glock); 2877 sc->sc_flags |= IWH_F_PUT_SEG; 2878 cv_signal(&sc->sc_put_seg_cv); 2879 mutex_exit(&sc->sc_glock); 2880 } 2881 2882 #ifdef DEBUG 2883 if (r & BIT_INT_ALIVE) { 2884 IWH_DBG((IWH_DEBUG_FW, "iwh_intr(): " 2885 "firmware initialized.\n")); 2886 } 2887 #endif 2888 2889 /* 2890 * re-enable interrupts 2891 */ 2892 IWH_WRITE(sc, CSR_INT_MASK, CSR_INI_SET_MASK); 2893 2894 mutex_exit(&sc->sc_suspend_lock); 2895 2896 return (DDI_INTR_CLAIMED); 2897 } 2898 2899 static uint8_t 2900 iwh_rate_to_plcp(int rate) 2901 { 2902 uint8_t ret; 2903 2904 switch (rate) { 2905 /* 2906 * CCK rates 2907 */ 2908 case 2: 2909 ret = 0xa; 2910 break; 2911 2912 case 4: 2913 ret = 0x14; 2914 break; 2915 2916 case 11: 2917 ret = 0x37; 2918 break; 2919 2920 case 22: 2921 ret = 0x6e; 2922 break; 2923 2924 /* 2925 * OFDM rates 2926 */ 2927 case 12: 2928 ret = 0xd; 2929 break; 2930 2931 case 18: 2932 ret = 0xf; 2933 break; 2934 2935 case 24: 2936 ret = 0x5; 2937 break; 2938 2939 case 36: 2940 ret = 0x7; 2941 break; 2942 2943 case 48: 2944 ret = 0x9; 2945 break; 2946 2947 case 72: 2948 ret = 0xb; 2949 break; 2950 2951 case 96: 2952 ret = 0x1; 2953 break; 2954 2955 case 108: 2956 ret = 0x3; 2957 break; 2958 2959 default: 2960 ret = 0; 2961 break; 2962 } 2963 2964 return (ret); 2965 } 2966 2967 /* 2968 * invoked by GLD send frames 2969 */ 2970 static mblk_t * 2971 iwh_m_tx(void *arg, mblk_t *mp) 2972 { 2973 iwh_sc_t *sc; 2974 ieee80211com_t *ic; 2975 mblk_t *next; 2976 2977 if (NULL == arg) { 2978 return (NULL); 2979 } 2980 sc = (iwh_sc_t *)arg; 2981 ic = &sc->sc_ic; 2982 2983 if (ic->ic_state != IEEE80211_S_RUN) { 2984 freemsgchain(mp); 2985 return (NULL); 2986 } 2987 2988 if ((sc->sc_flags & IWH_F_HW_ERR_RECOVER) && 2989 IWH_CHK_FAST_RECOVER(sc)) { 2990 IWH_DBG((IWH_DEBUG_FW, "iwh_m_tx(): " 2991 "hold queue\n")); 2992 return (mp); 2993 } 2994 2995 mutex_enter(&sc->sc_suspend_lock); 2996 if (sc->sc_flags & IWH_F_SUSPEND) { 2997 mutex_exit(&sc->sc_suspend_lock); 2998 freemsgchain(mp); 2999 return (NULL); 3000 } 3001 3002 while (mp != NULL) { 3003 next = mp->b_next; 3004 mp->b_next = NULL; 3005 if (iwh_send(ic, mp, IEEE80211_FC0_TYPE_DATA) != 0) { 3006 mp->b_next = next; 3007 break; 3008 } 3009 mp = next; 3010 } 3011 3012 if (mutex_owned(&sc->sc_suspend_lock)) { 3013 mutex_exit(&sc->sc_suspend_lock); 3014 } 3015 3016 return (mp); 3017 } 3018 3019 /* 3020 * send frames 3021 */ 3022 static int 3023 iwh_send(ieee80211com_t *ic, mblk_t *mp, uint8_t type) 3024 { 3025 iwh_sc_t *sc; 3026 iwh_tx_ring_t *ring; 3027 iwh_tx_desc_t *desc; 3028 iwh_tx_data_t *data; 3029 iwh_cmd_t *cmd; 3030 iwh_tx_cmd_t *tx; 3031 ieee80211_node_t *in; 3032 struct ieee80211_frame *wh; 3033 struct ieee80211_key *k = NULL; 3034 mblk_t *m, *m0; 3035 int hdrlen, len, len0, mblen, off, err = IWH_SUCCESS; 3036 uint16_t masks = 0; 3037 uint32_t rate, s_id = 0; 3038 int txq_id = NON_QOS_TXQ; 3039 struct ieee80211_qosframe *qwh = NULL; 3040 int tid = WME_TID_INVALID; 3041 3042 if (NULL == ic) { 3043 return (IWH_FAIL); 3044 } 3045 sc = (iwh_sc_t *)ic; 3046 3047 if (!mutex_owned(&sc->sc_suspend_lock)) { 3048 mutex_enter(&sc->sc_suspend_lock); 3049 } 3050 3051 if (sc->sc_flags & IWH_F_SUSPEND) { 3052 if ((type & IEEE80211_FC0_TYPE_MASK) != 3053 IEEE80211_FC0_TYPE_DATA) { 3054 freemsg(mp); 3055 } 3056 err = IWH_FAIL; 3057 goto exit; 3058 } 3059 3060 hdrlen = ieee80211_hdrspace(ic, mp->b_rptr); 3061 3062 m = allocb(msgdsize(mp) + 32, BPRI_MED); 3063 if (NULL == m) { /* can not alloc buf, drop this package */ 3064 cmn_err(CE_WARN, "iwh_send(): " 3065 "failed to allocate msgbuf\n"); 3066 freemsg(mp); 3067 err = IWH_SUCCESS; 3068 goto exit; 3069 } 3070 3071 for (off = 0, m0 = mp; m0 != NULL; m0 = m0->b_cont) { 3072 mblen = MBLKL(m0); 3073 (void) memcpy(m->b_rptr + off, m0->b_rptr, mblen); 3074 off += mblen; 3075 } 3076 3077 m->b_wptr += off; 3078 3079 wh = (struct ieee80211_frame *)m->b_rptr; 3080 3081 /* 3082 * determine send which AP or station in IBSS 3083 */ 3084 in = ieee80211_find_txnode(ic, wh->i_addr1); 3085 if (NULL == in) { 3086 cmn_err(CE_WARN, "iwh_send(): " 3087 "failed to find tx node\n"); 3088 freemsg(mp); 3089 freemsg(m); 3090 sc->sc_tx_err++; 3091 err = IWH_SUCCESS; 3092 goto exit; 3093 } 3094 3095 /* 3096 * Net80211 module encapsulate outbound data frames. 3097 * Add some feilds of 80211 frame. 3098 */ 3099 if ((type & IEEE80211_FC0_TYPE_MASK) == 3100 IEEE80211_FC0_TYPE_DATA) { 3101 (void) ieee80211_encap(ic, m, in); 3102 } 3103 3104 /* 3105 * Determine TX queue according to traffic ID in frame 3106 * if working in QoS mode. 3107 */ 3108 if (in->in_flags & IEEE80211_NODE_QOS) { 3109 3110 if ((type & IEEE80211_FC0_TYPE_MASK) == 3111 IEEE80211_FC0_TYPE_DATA) { 3112 3113 if (wh->i_fc[0] & IEEE80211_FC0_SUBTYPE_QOS) { 3114 qwh = (struct ieee80211_qosframe *)wh; 3115 3116 tid = qwh->i_qos[0] & IEEE80211_QOS_TID; 3117 txq_id = iwh_wme_tid_to_txq(tid); 3118 3119 if (txq_id < TXQ_FOR_AC_MIN || 3120 (txq_id > TXQ_FOR_AC_MAX)) { 3121 freemsg(m); 3122 freemsg(mp); 3123 sc->sc_tx_err++; 3124 err = IWH_SUCCESS; 3125 goto exit; 3126 } 3127 3128 } else { 3129 txq_id = NON_QOS_TXQ; 3130 } 3131 3132 } else if ((type & IEEE80211_FC0_TYPE_MASK) == 3133 IEEE80211_FC0_TYPE_MGT) { 3134 txq_id = QOS_TXQ_FOR_MGT; 3135 } else { 3136 txq_id = NON_QOS_TXQ; 3137 } 3138 3139 } else { 3140 txq_id = NON_QOS_TXQ; 3141 } 3142 3143 ring = &sc->sc_txq[txq_id]; 3144 data = &ring->data[ring->cur]; 3145 desc = data->desc; 3146 cmd = data->cmd; 3147 bzero(desc, sizeof (*desc)); 3148 bzero(cmd, sizeof (*cmd)); 3149 3150 mutex_enter(&sc->sc_tx_lock); 3151 3152 /* 3153 * Need reschedule TX if TX buffer is full. 3154 */ 3155 if (ring->queued > ring->count - IWH_MAX_WIN_SIZE) { 3156 IWH_DBG((IWH_DEBUG_TX, "iwh_send(): " 3157 "no txbuf\n")); 3158 3159 sc->sc_need_reschedule = 1; 3160 mutex_exit(&sc->sc_tx_lock); 3161 3162 freemsg(m); 3163 if ((type & IEEE80211_FC0_TYPE_MASK) != 3164 IEEE80211_FC0_TYPE_DATA) { 3165 freemsg(mp); 3166 } 3167 sc->sc_tx_nobuf++; 3168 err = IWH_FAIL; 3169 goto exit; 3170 } 3171 mutex_exit(&sc->sc_tx_lock); 3172 3173 freemsg(mp); 3174 3175 cmd->hdr.type = REPLY_TX; 3176 cmd->hdr.flags = 0; 3177 cmd->hdr.qid = ring->qid; 3178 cmd->hdr.idx = ring->cur; 3179 3180 tx = (iwh_tx_cmd_t *)cmd->data; 3181 tx->tx_flags = 0; 3182 3183 if (IEEE80211_IS_MULTICAST(wh->i_addr1)) { 3184 tx->tx_flags &= ~(LE_32(TX_CMD_FLG_ACK_MSK)); 3185 } else { 3186 tx->tx_flags |= LE_32(TX_CMD_FLG_ACK_MSK); 3187 } 3188 3189 if (wh->i_fc[1] & IEEE80211_FC1_WEP) { 3190 k = ieee80211_crypto_encap(ic, m); 3191 if (NULL == k) { 3192 freemsg(m); 3193 sc->sc_tx_err++; 3194 err = IWH_SUCCESS; 3195 goto exit; 3196 } 3197 3198 /* packet header may have moved, reset our local pointer */ 3199 wh = (struct ieee80211_frame *)m->b_rptr; 3200 } 3201 3202 len = msgdsize(m); 3203 3204 #ifdef DEBUG 3205 if (iwh_dbg_flags & IWH_DEBUG_TX) { 3206 ieee80211_dump_pkt((uint8_t *)wh, hdrlen, 0, 0); 3207 } 3208 #endif 3209 3210 tx->rts_retry_limit = IWH_TX_RTS_RETRY_LIMIT; 3211 tx->data_retry_limit = IWH_TX_DATA_RETRY_LIMIT; 3212 3213 /* 3214 * specific TX parameters for management frames 3215 */ 3216 if ((wh->i_fc[0] & IEEE80211_FC0_TYPE_MASK) == 3217 IEEE80211_FC0_TYPE_MGT) { 3218 /* 3219 * mgmt frames are sent at 1M 3220 */ 3221 if ((in->in_rates.ir_rates[0] & 3222 IEEE80211_RATE_VAL) != 0) { 3223 rate = in->in_rates.ir_rates[0] & IEEE80211_RATE_VAL; 3224 } else { 3225 rate = 2; 3226 } 3227 3228 tx->tx_flags |= LE_32(TX_CMD_FLG_SEQ_CTL_MSK); 3229 3230 /* 3231 * tell h/w to set timestamp in probe responses 3232 */ 3233 if ((wh->i_fc[0] & IEEE80211_FC0_SUBTYPE_MASK) == 3234 IEEE80211_FC0_SUBTYPE_PROBE_RESP) { 3235 tx->tx_flags |= LE_32(TX_CMD_FLG_TSF_MSK); 3236 3237 tx->data_retry_limit = 3; 3238 if (tx->data_retry_limit < tx->rts_retry_limit) { 3239 tx->rts_retry_limit = tx->data_retry_limit; 3240 } 3241 } 3242 3243 if (((wh->i_fc[0] & IEEE80211_FC0_SUBTYPE_MASK) == 3244 IEEE80211_FC0_SUBTYPE_ASSOC_REQ) || 3245 ((wh->i_fc[0] & IEEE80211_FC0_SUBTYPE_MASK) == 3246 IEEE80211_FC0_SUBTYPE_REASSOC_REQ)) { 3247 tx->timeout.pm_frame_timeout = LE_16(3); 3248 } else { 3249 tx->timeout.pm_frame_timeout = LE_16(2); 3250 } 3251 3252 } else { 3253 /* 3254 * do it here for the software way rate scaling. 3255 * later for rate scaling in hardware. 3256 * 3257 * now the txrate is determined in tx cmd flags, set to the 3258 * max value 54M for 11g and 11M for 11b and 96M for 11n 3259 * originally. 3260 */ 3261 if (ic->ic_fixed_rate != IEEE80211_FIXED_RATE_NONE) { 3262 rate = ic->ic_fixed_rate; 3263 } else { 3264 if ((in->in_flags & IEEE80211_NODE_HT) && 3265 (sc->sc_ht_conf.ht_support)) { 3266 iwh_amrr_t *amrr = (iwh_amrr_t *)in; 3267 rate = amrr->ht_mcs_idx; 3268 } else { 3269 if ((in->in_rates.ir_rates[in->in_txrate] & 3270 IEEE80211_RATE_VAL) != 0) { 3271 rate = in->in_rates. 3272 ir_rates[in->in_txrate] & 3273 IEEE80211_RATE_VAL; 3274 } 3275 } 3276 } 3277 3278 if (tid != WME_TID_INVALID) { 3279 tx->tid_tspec = (uint8_t)tid; 3280 tx->tx_flags &= LE_32(~TX_CMD_FLG_SEQ_CTL_MSK); 3281 } else { 3282 tx->tx_flags |= LE_32(TX_CMD_FLG_SEQ_CTL_MSK); 3283 } 3284 3285 tx->timeout.pm_frame_timeout = 0; 3286 } 3287 3288 IWH_DBG((IWH_DEBUG_TX, "iwh_send(): " 3289 "tx rate[%d of %d] = %x", 3290 in->in_txrate, in->in_rates.ir_nrates, rate)); 3291 3292 len0 = roundup(4 + sizeof (iwh_tx_cmd_t) + hdrlen, 4); 3293 if (len0 != (4 + sizeof (iwh_tx_cmd_t) + hdrlen)) { 3294 tx->tx_flags |= LE_32(TX_CMD_FLG_MH_PAD_MSK); 3295 } 3296 3297 /* 3298 * retrieve destination node's id 3299 */ 3300 if (IEEE80211_IS_MULTICAST(wh->i_addr1)) { 3301 tx->sta_id = IWH_BROADCAST_ID; 3302 } else { 3303 tx->sta_id = IWH_AP_ID; 3304 } 3305 3306 if ((in->in_flags & IEEE80211_NODE_HT) && 3307 (sc->sc_ht_conf.ht_support) && 3308 ((wh->i_fc[0] & IEEE80211_FC0_TYPE_MASK) == 3309 IEEE80211_FC0_TYPE_DATA)) { 3310 if (rate >= HT_2CHAIN_RATE_MIN_IDX) { 3311 rate |= LE_32(RATE_MCS_ANT_AB_MSK); 3312 } else { 3313 rate |= LE_32(RATE_MCS_ANT_B_MSK); 3314 } 3315 3316 rate |= LE_32((1 << RATE_MCS_HT_POS)); 3317 3318 tx->rate.r.rate_n_flags = rate; 3319 3320 } else { 3321 if (2 == rate || 4 == rate || 11 == rate || 22 == rate) { 3322 masks |= RATE_MCS_CCK_MSK; 3323 } 3324 3325 masks |= RATE_MCS_ANT_B_MSK; 3326 tx->rate.r.rate_n_flags = LE_32(iwh_rate_to_plcp(rate) | masks); 3327 } 3328 3329 IWH_DBG((IWH_DEBUG_TX, "iwh_send(): " 3330 "tx flag = %x", 3331 tx->tx_flags)); 3332 3333 tx->stop_time.life_time = LE_32(0xffffffff); 3334 3335 tx->len = LE_16(len); 3336 3337 tx->dram_lsb_ptr = 3338 LE_32(data->paddr_cmd + 4 + offsetof(iwh_tx_cmd_t, scratch)); 3339 tx->dram_msb_ptr = 0; 3340 tx->driver_txop = 0; 3341 tx->next_frame_len = 0; 3342 3343 (void) memcpy(tx + 1, m->b_rptr, hdrlen); 3344 m->b_rptr += hdrlen; 3345 (void) memcpy(data->dma_data.mem_va, m->b_rptr, len - hdrlen); 3346 3347 IWH_DBG((IWH_DEBUG_TX, "iwh_send(): " 3348 "sending data: qid=%d idx=%d len=%d", 3349 ring->qid, ring->cur, len)); 3350 3351 /* 3352 * first segment includes the tx cmd plus the 802.11 header, 3353 * the second includes the remaining of the 802.11 frame. 3354 */ 3355 desc->val0 = 2 << 24; 3356 desc->pa[0].tb1_addr = data->paddr_cmd; 3357 desc->pa[0].val1 = ((len0 << 4) & 0xfff0) | 3358 ((data->dma_data.cookie.dmac_address & 0xffff) << 16); 3359 desc->pa[0].val2 = 3360 ((data->dma_data.cookie.dmac_address & 0xffff0000) >> 16) | 3361 ((len - hdrlen) << 20); 3362 IWH_DBG((IWH_DEBUG_TX, "iwh_send(): " 3363 "phy addr1 = 0x%x phy addr2 = 0x%x " 3364 "len1 = 0x%x, len2 = 0x%x val1 = 0x%x val2 = 0x%x", 3365 data->paddr_cmd, data->dma_data.cookie.dmac_address, 3366 len0, len - hdrlen, desc->pa[0].val1, desc->pa[0].val2)); 3367 3368 mutex_enter(&sc->sc_tx_lock); 3369 ring->queued++; 3370 mutex_exit(&sc->sc_tx_lock); 3371 3372 /* 3373 * kick ring 3374 */ 3375 s_id = tx->sta_id; 3376 3377 sc->sc_shared->queues_byte_cnt_tbls[ring->qid]. 3378 tfd_offset[ring->cur].val = 3379 (8 + len) | (s_id << 12); 3380 if (ring->cur < IWH_MAX_WIN_SIZE) { 3381 sc->sc_shared->queues_byte_cnt_tbls[ring->qid]. 3382 tfd_offset[IWH_QUEUE_SIZE + ring->cur].val = 3383 (8 + len) | (s_id << 12); 3384 } 3385 3386 IWH_DMA_SYNC(data->dma_data, DDI_DMA_SYNC_FORDEV); 3387 IWH_DMA_SYNC(ring->dma_desc, DDI_DMA_SYNC_FORDEV); 3388 3389 ring->cur = (ring->cur + 1) % ring->count; 3390 IWH_WRITE(sc, HBUS_TARG_WRPTR, ring->qid << 8 | ring->cur); 3391 freemsg(m); 3392 3393 /* 3394 * release node reference 3395 */ 3396 ieee80211_free_node(in); 3397 3398 ic->ic_stats.is_tx_bytes += len; 3399 ic->ic_stats.is_tx_frags++; 3400 3401 mutex_enter(&sc->sc_mt_lock); 3402 if (0 == sc->sc_tx_timer) { 3403 sc->sc_tx_timer = 4; 3404 } 3405 mutex_exit(&sc->sc_mt_lock); 3406 3407 exit: 3408 if (mutex_owned(&sc->sc_suspend_lock)) { 3409 mutex_exit(&sc->sc_suspend_lock); 3410 } 3411 3412 return (err); 3413 } 3414 3415 /* 3416 * invoked by GLD to deal with IOCTL affaires 3417 */ 3418 static void 3419 iwh_m_ioctl(void* arg, queue_t *wq, mblk_t *mp) 3420 { 3421 iwh_sc_t *sc; 3422 ieee80211com_t *ic; 3423 int err = EINVAL; 3424 3425 if (NULL == arg) { 3426 return; 3427 } 3428 sc = (iwh_sc_t *)arg; 3429 ic = &sc->sc_ic; 3430 3431 err = ieee80211_ioctl(ic, wq, mp); 3432 if (ENETRESET == err) { 3433 /* 3434 * This is special for the hidden AP connection. 3435 * In any case, we should make sure only one 'scan' 3436 * in the driver for a 'connect' CLI command. So 3437 * when connecting to a hidden AP, the scan is just 3438 * sent out to the air when we know the desired 3439 * essid of the AP we want to connect. 3440 */ 3441 if (ic->ic_des_esslen) { 3442 if (sc->sc_flags & IWH_F_RUNNING) { 3443 iwh_m_stop(sc); 3444 (void) iwh_m_start(sc); 3445 (void) ieee80211_new_state(ic, 3446 IEEE80211_S_SCAN, -1); 3447 } 3448 } 3449 } 3450 } 3451 3452 /* 3453 * Call back functions for get/set proporty 3454 */ 3455 static int 3456 iwh_m_getprop(void *arg, const char *pr_name, mac_prop_id_t wldp_pr_num, 3457 uint_t pr_flags, uint_t wldp_length, void *wldp_buf, uint_t *perm) 3458 { 3459 iwh_sc_t *sc; 3460 int err = EINVAL; 3461 3462 if (NULL == arg) { 3463 return (EINVAL); 3464 } 3465 sc = (iwh_sc_t *)arg; 3466 3467 err = ieee80211_getprop(&sc->sc_ic, pr_name, wldp_pr_num, 3468 pr_flags, wldp_length, wldp_buf, perm); 3469 3470 return (err); 3471 } 3472 3473 static int 3474 iwh_m_setprop(void *arg, const char *pr_name, mac_prop_id_t wldp_pr_num, 3475 uint_t wldp_length, const void *wldp_buf) 3476 { 3477 iwh_sc_t *sc; 3478 ieee80211com_t *ic; 3479 int err = EINVAL; 3480 3481 if (NULL == arg) { 3482 return (EINVAL); 3483 } 3484 sc = (iwh_sc_t *)arg; 3485 ic = &sc->sc_ic; 3486 3487 err = ieee80211_setprop(ic, pr_name, wldp_pr_num, wldp_length, 3488 wldp_buf); 3489 3490 if (err == ENETRESET) { 3491 if (ic->ic_des_esslen) { 3492 if (sc->sc_flags & IWH_F_RUNNING) { 3493 iwh_m_stop(sc); 3494 (void) iwh_m_start(sc); 3495 (void) ieee80211_new_state(ic, 3496 IEEE80211_S_SCAN, -1); 3497 } 3498 } 3499 err = 0; 3500 } 3501 return (err); 3502 } 3503 3504 /* 3505 * invoked by GLD supply statistics NIC and driver 3506 */ 3507 static int 3508 iwh_m_stat(void *arg, uint_t stat, uint64_t *val) 3509 { 3510 iwh_sc_t *sc; 3511 ieee80211com_t *ic; 3512 ieee80211_node_t *in; 3513 3514 if (NULL == arg) { 3515 return (EINVAL); 3516 } 3517 sc = (iwh_sc_t *)arg; 3518 ic = &sc->sc_ic; 3519 3520 mutex_enter(&sc->sc_glock); 3521 3522 switch (stat) { 3523 case MAC_STAT_IFSPEED: 3524 in = ic->ic_bss; 3525 *val = ((IEEE80211_FIXED_RATE_NONE == ic->ic_fixed_rate) ? 3526 IEEE80211_RATE(in->in_txrate) : 3527 ic->ic_fixed_rate) / 2 * 1000000; 3528 break; 3529 3530 case MAC_STAT_NOXMTBUF: 3531 *val = sc->sc_tx_nobuf; 3532 break; 3533 3534 case MAC_STAT_NORCVBUF: 3535 *val = sc->sc_rx_nobuf; 3536 break; 3537 3538 case MAC_STAT_IERRORS: 3539 *val = sc->sc_rx_err; 3540 break; 3541 3542 case MAC_STAT_RBYTES: 3543 *val = ic->ic_stats.is_rx_bytes; 3544 break; 3545 3546 case MAC_STAT_IPACKETS: 3547 *val = ic->ic_stats.is_rx_frags; 3548 break; 3549 3550 case MAC_STAT_OBYTES: 3551 *val = ic->ic_stats.is_tx_bytes; 3552 break; 3553 3554 case MAC_STAT_OPACKETS: 3555 *val = ic->ic_stats.is_tx_frags; 3556 break; 3557 3558 case MAC_STAT_OERRORS: 3559 case WIFI_STAT_TX_FAILED: 3560 *val = sc->sc_tx_err; 3561 break; 3562 3563 case WIFI_STAT_TX_RETRANS: 3564 *val = sc->sc_tx_retries; 3565 break; 3566 3567 case WIFI_STAT_FCS_ERRORS: 3568 case WIFI_STAT_WEP_ERRORS: 3569 case WIFI_STAT_TX_FRAGS: 3570 case WIFI_STAT_MCAST_TX: 3571 case WIFI_STAT_RTS_SUCCESS: 3572 case WIFI_STAT_RTS_FAILURE: 3573 case WIFI_STAT_ACK_FAILURE: 3574 case WIFI_STAT_RX_FRAGS: 3575 case WIFI_STAT_MCAST_RX: 3576 case WIFI_STAT_RX_DUPS: 3577 mutex_exit(&sc->sc_glock); 3578 return (ieee80211_stat(ic, stat, val)); 3579 3580 default: 3581 mutex_exit(&sc->sc_glock); 3582 return (ENOTSUP); 3583 } 3584 3585 mutex_exit(&sc->sc_glock); 3586 3587 return (IWH_SUCCESS); 3588 3589 } 3590 3591 /* 3592 * invoked by GLD to start or open NIC 3593 */ 3594 static int 3595 iwh_m_start(void *arg) 3596 { 3597 iwh_sc_t *sc; 3598 ieee80211com_t *ic; 3599 int err = IWH_FAIL; 3600 3601 if (NULL == arg) { 3602 return (EINVAL); 3603 } 3604 sc = (iwh_sc_t *)arg; 3605 ic = &sc->sc_ic; 3606 3607 err = iwh_init(sc); 3608 if (err != IWH_SUCCESS) { 3609 /* 3610 * The hw init err(eg. RF is OFF). Return Success to make 3611 * the 'plumb' succeed. The iwh_thread() tries to re-init 3612 * background. 3613 */ 3614 sc->sc_flags |= IWH_F_HW_ERR_RECOVER; 3615 return (IWH_SUCCESS); 3616 } 3617 3618 ieee80211_new_state(ic, IEEE80211_S_INIT, -1); 3619 3620 sc->sc_flags |= IWH_F_RUNNING; 3621 3622 return (IWH_SUCCESS); 3623 } 3624 3625 /* 3626 * invoked by GLD to stop or down NIC 3627 */ 3628 static void 3629 iwh_m_stop(void *arg) 3630 { 3631 iwh_sc_t *sc; 3632 ieee80211com_t *ic; 3633 3634 if (NULL == arg) { 3635 return; 3636 } 3637 sc = (iwh_sc_t *)arg; 3638 ic = &sc->sc_ic; 3639 3640 iwh_stop(sc); 3641 3642 /* 3643 * release buffer for calibration 3644 */ 3645 iwh_release_calib_buffer(sc); 3646 3647 ieee80211_new_state(ic, IEEE80211_S_INIT, -1); 3648 3649 sc->sc_flags &= ~IWH_F_HW_ERR_RECOVER; 3650 sc->sc_flags &= ~IWH_F_RATE_AUTO_CTL; 3651 3652 sc->sc_flags &= ~IWH_F_RUNNING; 3653 sc->sc_flags &= ~IWH_F_SCANNING; 3654 } 3655 3656 /* 3657 * invoked by GLD to configure NIC 3658 */ 3659 static int 3660 iwh_m_unicst(void *arg, const uint8_t *macaddr) 3661 { 3662 iwh_sc_t *sc; 3663 ieee80211com_t *ic; 3664 int err = IWH_SUCCESS; 3665 3666 if (NULL == arg) { 3667 return (EINVAL); 3668 } 3669 sc = (iwh_sc_t *)arg; 3670 ic = &sc->sc_ic; 3671 3672 if (!IEEE80211_ADDR_EQ(ic->ic_macaddr, macaddr)) { 3673 IEEE80211_ADDR_COPY(ic->ic_macaddr, macaddr); 3674 mutex_enter(&sc->sc_glock); 3675 err = iwh_config(sc); 3676 mutex_exit(&sc->sc_glock); 3677 if (err != IWH_SUCCESS) { 3678 cmn_err(CE_WARN, "iwh_m_unicst(): " 3679 "failed to configure device\n"); 3680 goto fail; 3681 } 3682 } 3683 3684 return (err); 3685 3686 fail: 3687 return (err); 3688 } 3689 3690 /* ARGSUSED */ 3691 static int 3692 iwh_m_multicst(void *arg, boolean_t add, const uint8_t *m) 3693 { 3694 return (IWH_SUCCESS); 3695 } 3696 3697 /* ARGSUSED */ 3698 static int 3699 iwh_m_promisc(void *arg, boolean_t on) 3700 { 3701 return (IWH_SUCCESS); 3702 } 3703 3704 /* 3705 * kernel thread to deal with exceptional situation 3706 */ 3707 static void 3708 iwh_thread(iwh_sc_t *sc) 3709 { 3710 ieee80211com_t *ic = &sc->sc_ic; 3711 clock_t clk; 3712 int err, n = 0, timeout = 0; 3713 uint32_t tmp; 3714 #ifdef DEBUG 3715 int times = 0; 3716 #endif 3717 3718 while (sc->sc_mf_thread_switch) { 3719 tmp = IWH_READ(sc, CSR_GP_CNTRL); 3720 if (tmp & CSR_GP_CNTRL_REG_FLAG_HW_RF_KILL_SW) { 3721 sc->sc_flags &= ~IWH_F_RADIO_OFF; 3722 } else { 3723 sc->sc_flags |= IWH_F_RADIO_OFF; 3724 } 3725 3726 /* 3727 * If in SUSPEND or the RF is OFF, do nothing. 3728 */ 3729 if (sc->sc_flags & IWH_F_RADIO_OFF) { 3730 delay(drv_usectohz(100000)); 3731 continue; 3732 } 3733 3734 /* 3735 * recovery fatal error 3736 */ 3737 if (ic->ic_mach && 3738 (sc->sc_flags & IWH_F_HW_ERR_RECOVER)) { 3739 3740 IWH_DBG((IWH_DEBUG_FW, "iwh_thread(): " 3741 "try to recover fatal hw error: %d\n", times++)); 3742 3743 iwh_stop(sc); 3744 3745 if (IWH_CHK_FAST_RECOVER(sc)) { 3746 /* save runtime configuration */ 3747 bcopy(&sc->sc_config, &sc->sc_config_save, 3748 sizeof (sc->sc_config)); 3749 } else { 3750 ieee80211_new_state(ic, IEEE80211_S_INIT, -1); 3751 delay(drv_usectohz(2000000 + n*500000)); 3752 } 3753 3754 err = iwh_init(sc); 3755 if (err != IWH_SUCCESS) { 3756 n++; 3757 if (n < 20) { 3758 continue; 3759 } 3760 } 3761 3762 n = 0; 3763 if (!err) { 3764 sc->sc_flags |= IWH_F_RUNNING; 3765 } 3766 3767 3768 if (!IWH_CHK_FAST_RECOVER(sc) || 3769 iwh_fast_recover(sc) != IWH_SUCCESS) { 3770 sc->sc_flags &= ~IWH_F_HW_ERR_RECOVER; 3771 3772 delay(drv_usectohz(2000000)); 3773 if (sc->sc_ostate != IEEE80211_S_INIT) { 3774 ieee80211_new_state(ic, 3775 IEEE80211_S_SCAN, 0); 3776 } 3777 } 3778 } 3779 3780 if (ic->ic_mach && 3781 (sc->sc_flags & IWH_F_SCANNING) && sc->sc_scan_pending) { 3782 IWH_DBG((IWH_DEBUG_SCAN, "iwh_thread(): " 3783 "wait for probe response\n")); 3784 3785 sc->sc_scan_pending--; 3786 delay(drv_usectohz(200000)); 3787 ieee80211_next_scan(ic); 3788 } 3789 3790 /* 3791 * rate ctl 3792 */ 3793 if (ic->ic_mach && 3794 (sc->sc_flags & IWH_F_RATE_AUTO_CTL)) { 3795 clk = ddi_get_lbolt(); 3796 if (clk > sc->sc_clk + drv_usectohz(1000000)) { 3797 iwh_amrr_timeout(sc); 3798 } 3799 } 3800 3801 delay(drv_usectohz(100000)); 3802 3803 mutex_enter(&sc->sc_mt_lock); 3804 if (sc->sc_tx_timer) { 3805 timeout++; 3806 if (10 == timeout) { 3807 sc->sc_tx_timer--; 3808 if (0 == sc->sc_tx_timer) { 3809 sc->sc_flags |= IWH_F_HW_ERR_RECOVER; 3810 sc->sc_ostate = IEEE80211_S_RUN; 3811 IWH_DBG((IWH_DEBUG_FW, "iwh_thread(): " 3812 "try to recover from " 3813 "send fail\n")); 3814 } 3815 timeout = 0; 3816 } 3817 } 3818 mutex_exit(&sc->sc_mt_lock); 3819 } 3820 3821 mutex_enter(&sc->sc_mt_lock); 3822 sc->sc_mf_thread = NULL; 3823 cv_signal(&sc->sc_mt_cv); 3824 mutex_exit(&sc->sc_mt_lock); 3825 } 3826 3827 3828 /* 3829 * Send a command to the ucode. 3830 */ 3831 static int 3832 iwh_cmd(iwh_sc_t *sc, int code, const void *buf, int size, int async) 3833 { 3834 iwh_tx_ring_t *ring = &sc->sc_txq[IWH_CMD_QUEUE_NUM]; 3835 iwh_tx_desc_t *desc; 3836 iwh_cmd_t *cmd; 3837 3838 ASSERT(size <= sizeof (cmd->data)); 3839 ASSERT(mutex_owned(&sc->sc_glock)); 3840 3841 IWH_DBG((IWH_DEBUG_CMD, "iwh_cmd() " 3842 "code[%d]", code)); 3843 desc = ring->data[ring->cur].desc; 3844 cmd = ring->data[ring->cur].cmd; 3845 3846 cmd->hdr.type = (uint8_t)code; 3847 cmd->hdr.flags = 0; 3848 cmd->hdr.qid = ring->qid; 3849 cmd->hdr.idx = ring->cur; 3850 (void) memcpy(cmd->data, buf, size); 3851 (void) memset(desc, 0, sizeof (*desc)); 3852 3853 desc->val0 = 1 << 24; 3854 desc->pa[0].tb1_addr = 3855 (uint32_t)(ring->data[ring->cur].paddr_cmd & 0xffffffff); 3856 desc->pa[0].val1 = ((4 + size) << 4) & 0xfff0; 3857 3858 if (async) { 3859 sc->sc_cmd_accum++; 3860 } 3861 3862 /* 3863 * kick cmd ring XXX 3864 */ 3865 sc->sc_shared->queues_byte_cnt_tbls[ring->qid]. 3866 tfd_offset[ring->cur].val = 8; 3867 if (ring->cur < IWH_MAX_WIN_SIZE) { 3868 sc->sc_shared->queues_byte_cnt_tbls[ring->qid]. 3869 tfd_offset[IWH_QUEUE_SIZE + ring->cur].val = 8; 3870 } 3871 ring->cur = (ring->cur + 1) % ring->count; 3872 IWH_WRITE(sc, HBUS_TARG_WRPTR, ring->qid << 8 | ring->cur); 3873 3874 if (async) { 3875 return (IWH_SUCCESS); 3876 } else { 3877 clock_t clk; 3878 3879 clk = ddi_get_lbolt() + drv_usectohz(2000000); 3880 while (sc->sc_cmd_flag != SC_CMD_FLG_DONE) { 3881 if (cv_timedwait(&sc->sc_cmd_cv, 3882 &sc->sc_glock, clk) < 0) { 3883 break; 3884 } 3885 } 3886 3887 if (SC_CMD_FLG_DONE == sc->sc_cmd_flag) { 3888 sc->sc_cmd_flag = SC_CMD_FLG_NONE; 3889 return (IWH_SUCCESS); 3890 } else { 3891 sc->sc_cmd_flag = SC_CMD_FLG_NONE; 3892 return (IWH_FAIL); 3893 } 3894 } 3895 } 3896 3897 /* 3898 * require ucode seting led of NIC 3899 */ 3900 static void 3901 iwh_set_led(iwh_sc_t *sc, uint8_t id, uint8_t off, uint8_t on) 3902 { 3903 iwh_led_cmd_t led; 3904 3905 led.interval = LE_32(100000); /* unit: 100ms */ 3906 led.id = id; 3907 led.off = off; 3908 led.on = on; 3909 3910 (void) iwh_cmd(sc, REPLY_LEDS_CMD, &led, sizeof (led), 1); 3911 } 3912 3913 /* 3914 * necessary setting to NIC before authentication 3915 */ 3916 static int 3917 iwh_hw_set_before_auth(iwh_sc_t *sc) 3918 { 3919 ieee80211com_t *ic = &sc->sc_ic; 3920 ieee80211_node_t *in = ic->ic_bss; 3921 int err = IWH_FAIL; 3922 3923 /* 3924 * update adapter's configuration according 3925 * the info of target AP 3926 */ 3927 IEEE80211_ADDR_COPY(sc->sc_config.bssid, in->in_bssid); 3928 sc->sc_config.chan = LE_16(ieee80211_chan2ieee(ic, in->in_chan)); 3929 3930 if (ic->ic_curmode != IEEE80211_MODE_11NG) { 3931 3932 sc->sc_config.ofdm_ht_triple_stream_basic_rates = 0; 3933 sc->sc_config.ofdm_ht_dual_stream_basic_rates = 0; 3934 sc->sc_config.ofdm_ht_single_stream_basic_rates = 0; 3935 3936 if (IEEE80211_MODE_11B == ic->ic_curmode) { 3937 sc->sc_config.cck_basic_rates = 0x03; 3938 sc->sc_config.ofdm_basic_rates = 0; 3939 } else if ((in->in_chan != IEEE80211_CHAN_ANYC) && 3940 (IEEE80211_IS_CHAN_5GHZ(in->in_chan))) { 3941 sc->sc_config.cck_basic_rates = 0; 3942 sc->sc_config.ofdm_basic_rates = 0x15; 3943 } else { /* assume 802.11b/g */ 3944 sc->sc_config.cck_basic_rates = 0x0f; 3945 sc->sc_config.ofdm_basic_rates = 0xff; 3946 } 3947 } 3948 3949 sc->sc_config.flags &= ~LE_32(RXON_FLG_SHORT_PREAMBLE_MSK | 3950 RXON_FLG_SHORT_SLOT_MSK); 3951 3952 if (ic->ic_flags & IEEE80211_F_SHSLOT) { 3953 sc->sc_config.flags |= LE_32(RXON_FLG_SHORT_SLOT_MSK); 3954 } else { 3955 sc->sc_config.flags &= LE_32(~RXON_FLG_SHORT_SLOT_MSK); 3956 } 3957 3958 if (ic->ic_flags & IEEE80211_F_SHPREAMBLE) { 3959 sc->sc_config.flags |= LE_32(RXON_FLG_SHORT_PREAMBLE_MSK); 3960 } else { 3961 sc->sc_config.flags &= LE_32(~RXON_FLG_SHORT_PREAMBLE_MSK); 3962 } 3963 3964 IWH_DBG((IWH_DEBUG_80211, "iwh_hw_set_before_auth(): " 3965 "config chan %d flags %x " 3966 "filter_flags %x cck %x ofdm %x" 3967 " bssid:%02x:%02x:%02x:%02x:%02x:%2x\n", 3968 LE_16(sc->sc_config.chan), LE_32(sc->sc_config.flags), 3969 LE_32(sc->sc_config.filter_flags), 3970 sc->sc_config.cck_basic_rates, sc->sc_config.ofdm_basic_rates, 3971 sc->sc_config.bssid[0], sc->sc_config.bssid[1], 3972 sc->sc_config.bssid[2], sc->sc_config.bssid[3], 3973 sc->sc_config.bssid[4], sc->sc_config.bssid[5])); 3974 3975 err = iwh_cmd(sc, REPLY_RXON, &sc->sc_config, 3976 sizeof (iwh_rxon_cmd_t), 1); 3977 if (err != IWH_SUCCESS) { 3978 cmn_err(CE_WARN, "iwh_hw_set_before_auth(): " 3979 "failed to config chan%d\n", sc->sc_config.chan); 3980 return (err); 3981 } 3982 3983 err = iwh_tx_power_table(sc, 1); 3984 if (err != IWH_SUCCESS) { 3985 return (err); 3986 } 3987 3988 /* 3989 * add default AP node 3990 */ 3991 err = iwh_add_ap_sta(sc); 3992 if (err != IWH_SUCCESS) { 3993 return (err); 3994 } 3995 3996 /* 3997 * set up retry rate table for AP node 3998 */ 3999 err = iwh_ap_lq(sc); 4000 if (err != IWH_SUCCESS) { 4001 return (err); 4002 } 4003 4004 return (err); 4005 } 4006 4007 /* 4008 * Send a scan request(assembly scan cmd) to the firmware. 4009 */ 4010 static int 4011 iwh_scan(iwh_sc_t *sc) 4012 { 4013 ieee80211com_t *ic = &sc->sc_ic; 4014 iwh_tx_ring_t *ring = &sc->sc_txq[IWH_CMD_QUEUE_NUM]; 4015 iwh_tx_desc_t *desc; 4016 iwh_tx_data_t *data; 4017 iwh_cmd_t *cmd; 4018 iwh_scan_hdr_t *hdr; 4019 iwh_scan_chan_t chan; 4020 struct ieee80211_frame *wh; 4021 ieee80211_node_t *in = ic->ic_bss; 4022 uint8_t essid[IEEE80211_NWID_LEN+1]; 4023 struct ieee80211_rateset *rs; 4024 enum ieee80211_phymode mode; 4025 uint8_t *frm; 4026 int i, pktlen, nrates; 4027 4028 data = &ring->data[ring->cur]; 4029 desc = data->desc; 4030 cmd = (iwh_cmd_t *)data->dma_data.mem_va; 4031 4032 cmd->hdr.type = REPLY_SCAN_CMD; 4033 cmd->hdr.flags = 0; 4034 cmd->hdr.qid = ring->qid; 4035 cmd->hdr.idx = ring->cur | 0x40; 4036 4037 hdr = (iwh_scan_hdr_t *)cmd->data; 4038 (void) memset(hdr, 0, sizeof (iwh_scan_hdr_t)); 4039 hdr->nchan = 1; 4040 hdr->quiet_time = LE_16(50); 4041 hdr->quiet_plcp_th = LE_16(1); 4042 4043 hdr->flags = LE_32(RXON_FLG_BAND_24G_MSK); 4044 hdr->rx_chain = LE_16(RXON_RX_CHAIN_DRIVER_FORCE_MSK | 4045 (0x7 << RXON_RX_CHAIN_VALID_POS) | 4046 (0x2 << RXON_RX_CHAIN_FORCE_SEL_POS) | 4047 (0x2 << RXON_RX_CHAIN_FORCE_MIMO_SEL_POS)); 4048 4049 hdr->tx_cmd.tx_flags = LE_32(TX_CMD_FLG_SEQ_CTL_MSK); 4050 hdr->tx_cmd.sta_id = IWH_BROADCAST_ID; 4051 hdr->tx_cmd.stop_time.life_time = LE_32(0xffffffff); 4052 hdr->tx_cmd.rate.r.rate_n_flags = LE_32(iwh_rate_to_plcp(2)); 4053 hdr->tx_cmd.rate.r.rate_n_flags |= 4054 LE_32(RATE_MCS_ANT_B_MSK |RATE_MCS_CCK_MSK); 4055 hdr->direct_scan[0].len = ic->ic_des_esslen; 4056 hdr->direct_scan[0].id = IEEE80211_ELEMID_SSID; 4057 4058 hdr->filter_flags = LE_32(RXON_FILTER_ACCEPT_GRP_MSK | 4059 RXON_FILTER_BCON_AWARE_MSK); 4060 4061 if (ic->ic_des_esslen) { 4062 bcopy(ic->ic_des_essid, essid, ic->ic_des_esslen); 4063 essid[ic->ic_des_esslen] = '\0'; 4064 IWH_DBG((IWH_DEBUG_SCAN, "iwh_scan(): " 4065 "directed scan %s\n", essid)); 4066 4067 bcopy(ic->ic_des_essid, hdr->direct_scan[0].ssid, 4068 ic->ic_des_esslen); 4069 } else { 4070 bzero(hdr->direct_scan[0].ssid, 4071 sizeof (hdr->direct_scan[0].ssid)); 4072 } 4073 4074 /* 4075 * a probe request frame is required after the REPLY_SCAN_CMD 4076 */ 4077 wh = (struct ieee80211_frame *)(hdr + 1); 4078 wh->i_fc[0] = IEEE80211_FC0_VERSION_0 | IEEE80211_FC0_TYPE_MGT | 4079 IEEE80211_FC0_SUBTYPE_PROBE_REQ; 4080 wh->i_fc[1] = IEEE80211_FC1_DIR_NODS; 4081 (void) memset(wh->i_addr1, 0xff, 6); 4082 IEEE80211_ADDR_COPY(wh->i_addr2, ic->ic_macaddr); 4083 (void) memset(wh->i_addr3, 0xff, 6); 4084 *(uint16_t *)&wh->i_dur[0] = 0; 4085 *(uint16_t *)&wh->i_seq[0] = 0; 4086 4087 frm = (uint8_t *)(wh + 1); 4088 4089 /* 4090 * essid IE 4091 */ 4092 if (in->in_esslen) { 4093 bcopy(in->in_essid, essid, in->in_esslen); 4094 essid[in->in_esslen] = '\0'; 4095 IWH_DBG((IWH_DEBUG_SCAN, "iwh_scan(): " 4096 "probe with ESSID %s\n", 4097 essid)); 4098 } 4099 *frm++ = IEEE80211_ELEMID_SSID; 4100 *frm++ = in->in_esslen; 4101 (void) memcpy(frm, in->in_essid, in->in_esslen); 4102 frm += in->in_esslen; 4103 4104 mode = ieee80211_chan2mode(ic, ic->ic_curchan); 4105 rs = &ic->ic_sup_rates[mode]; 4106 4107 /* 4108 * supported rates IE 4109 */ 4110 *frm++ = IEEE80211_ELEMID_RATES; 4111 nrates = rs->ir_nrates; 4112 if (nrates > IEEE80211_RATE_SIZE) { 4113 nrates = IEEE80211_RATE_SIZE; 4114 } 4115 4116 *frm++ = (uint8_t)nrates; 4117 (void) memcpy(frm, rs->ir_rates, nrates); 4118 frm += nrates; 4119 4120 /* 4121 * supported xrates IE 4122 */ 4123 if (rs->ir_nrates > IEEE80211_RATE_SIZE) { 4124 nrates = rs->ir_nrates - IEEE80211_RATE_SIZE; 4125 *frm++ = IEEE80211_ELEMID_XRATES; 4126 *frm++ = (uint8_t)nrates; 4127 (void) memcpy(frm, rs->ir_rates + IEEE80211_RATE_SIZE, nrates); 4128 frm += nrates; 4129 } 4130 4131 /* 4132 * optionnal IE (usually for wpa) 4133 */ 4134 if (ic->ic_opt_ie != NULL) { 4135 (void) memcpy(frm, ic->ic_opt_ie, ic->ic_opt_ie_len); 4136 frm += ic->ic_opt_ie_len; 4137 } 4138 4139 /* setup length of probe request */ 4140 hdr->tx_cmd.len = LE_16(_PTRDIFF(frm, wh)); 4141 hdr->len = LE_16(hdr->nchan * sizeof (iwh_scan_chan_t) + 4142 LE_16(hdr->tx_cmd.len) + sizeof (iwh_scan_hdr_t)); 4143 4144 /* 4145 * the attribute of the scan channels are required after the probe 4146 * request frame. 4147 */ 4148 for (i = 1; i <= hdr->nchan; i++) { 4149 if (ic->ic_des_esslen) { 4150 chan.type = LE_32(3); 4151 } else { 4152 chan.type = LE_32(1); 4153 } 4154 4155 chan.chan = LE_16(ieee80211_chan2ieee(ic, ic->ic_curchan)); 4156 chan.tpc.tx_gain = 0x28; 4157 chan.tpc.dsp_atten = 110; 4158 chan.active_dwell = LE_16(50); 4159 chan.passive_dwell = LE_16(120); 4160 4161 bcopy(&chan, frm, sizeof (iwh_scan_chan_t)); 4162 frm += sizeof (iwh_scan_chan_t); 4163 } 4164 4165 pktlen = _PTRDIFF(frm, cmd); 4166 4167 (void) memset(desc, 0, sizeof (*desc)); 4168 desc->val0 = 1 << 24; 4169 desc->pa[0].tb1_addr = 4170 (uint32_t)(data->dma_data.cookie.dmac_address & 0xffffffff); 4171 desc->pa[0].val1 = (pktlen << 4) & 0xfff0; 4172 4173 /* 4174 * maybe for cmd, filling the byte cnt table is not necessary. 4175 * anyway, we fill it here. 4176 */ 4177 sc->sc_shared->queues_byte_cnt_tbls[ring->qid] 4178 .tfd_offset[ring->cur].val = 8; 4179 if (ring->cur < IWH_MAX_WIN_SIZE) { 4180 sc->sc_shared->queues_byte_cnt_tbls[ring->qid]. 4181 tfd_offset[IWH_QUEUE_SIZE + ring->cur].val = 8; 4182 } 4183 4184 /* 4185 * kick cmd ring 4186 */ 4187 ring->cur = (ring->cur + 1) % ring->count; 4188 IWH_WRITE(sc, HBUS_TARG_WRPTR, ring->qid << 8 | ring->cur); 4189 4190 return (IWH_SUCCESS); 4191 } 4192 4193 /* 4194 * configure NIC by using ucode commands after loading ucode. 4195 */ 4196 static int 4197 iwh_config(iwh_sc_t *sc) 4198 { 4199 ieee80211com_t *ic = &sc->sc_ic; 4200 iwh_powertable_cmd_t powertable; 4201 iwh_bt_cmd_t bt; 4202 iwh_add_sta_t node; 4203 iwh_rem_sta_t rm_sta; 4204 const uint8_t bcast[6] = {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF}; 4205 iwh_link_quality_cmd_t link_quality; 4206 int i, err = IWH_FAIL; 4207 uint16_t masks = 0; 4208 4209 /* 4210 * set power mode. Disable power management at present, do it later 4211 */ 4212 (void) memset(&powertable, 0, sizeof (powertable)); 4213 powertable.flags = LE_16(0x8); 4214 err = iwh_cmd(sc, POWER_TABLE_CMD, &powertable, 4215 sizeof (powertable), 0); 4216 if (err != IWH_SUCCESS) { 4217 cmn_err(CE_WARN, "iwh_config(): " 4218 "failed to set power mode\n"); 4219 return (err); 4220 } 4221 4222 /* 4223 * configure bt coexistence 4224 */ 4225 (void) memset(&bt, 0, sizeof (bt)); 4226 bt.flags = 3; 4227 bt.lead_time = 0xaa; 4228 bt.max_kill = 1; 4229 err = iwh_cmd(sc, REPLY_BT_CONFIG, &bt, 4230 sizeof (bt), 0); 4231 if (err != IWH_SUCCESS) { 4232 cmn_err(CE_WARN, "iwh_config(): " 4233 "failed to configurate bt coexistence\n"); 4234 return (err); 4235 } 4236 4237 /* 4238 * configure rxon 4239 */ 4240 (void) memset(&sc->sc_config, 0, sizeof (iwh_rxon_cmd_t)); 4241 IEEE80211_ADDR_COPY(sc->sc_config.node_addr, ic->ic_macaddr); 4242 IEEE80211_ADDR_COPY(sc->sc_config.wlap_bssid, ic->ic_macaddr); 4243 sc->sc_config.chan = LE_16(ieee80211_chan2ieee(ic, ic->ic_curchan)); 4244 sc->sc_config.flags = LE_32(RXON_FLG_BAND_24G_MSK); 4245 sc->sc_config.flags &= LE_32(~(RXON_FLG_CHANNEL_MODE_MIXED_MSK | 4246 RXON_FLG_CHANNEL_MODE_PURE_40_MSK)); 4247 4248 switch (ic->ic_opmode) { 4249 case IEEE80211_M_STA: 4250 sc->sc_config.dev_type = RXON_DEV_TYPE_ESS; 4251 sc->sc_config.filter_flags |= LE_32(RXON_FILTER_ACCEPT_GRP_MSK | 4252 RXON_FILTER_DIS_DECRYPT_MSK | 4253 RXON_FILTER_DIS_GRP_DECRYPT_MSK); 4254 break; 4255 4256 case IEEE80211_M_IBSS: 4257 case IEEE80211_M_AHDEMO: 4258 sc->sc_config.dev_type = RXON_DEV_TYPE_IBSS; 4259 4260 sc->sc_config.flags |= LE_32(RXON_FLG_SHORT_PREAMBLE_MSK); 4261 sc->sc_config.filter_flags = LE_32(RXON_FILTER_ACCEPT_GRP_MSK | 4262 RXON_FILTER_DIS_DECRYPT_MSK | 4263 RXON_FILTER_DIS_GRP_DECRYPT_MSK); 4264 break; 4265 4266 case IEEE80211_M_HOSTAP: 4267 sc->sc_config.dev_type = RXON_DEV_TYPE_AP; 4268 break; 4269 4270 case IEEE80211_M_MONITOR: 4271 sc->sc_config.dev_type = RXON_DEV_TYPE_SNIFFER; 4272 sc->sc_config.filter_flags |= LE_32(RXON_FILTER_ACCEPT_GRP_MSK | 4273 RXON_FILTER_CTL2HOST_MSK | RXON_FILTER_PROMISC_MSK); 4274 break; 4275 } 4276 4277 /* 4278 * Support all CCK rates. 4279 */ 4280 sc->sc_config.cck_basic_rates = 0x0f; 4281 4282 /* 4283 * Support all OFDM rates. 4284 */ 4285 sc->sc_config.ofdm_basic_rates = 0xff; 4286 4287 /* 4288 * Determine HT supported rates. 4289 */ 4290 switch (sc->sc_ht_conf.rx_stream_count) { 4291 case 3: 4292 sc->sc_config.ofdm_ht_triple_stream_basic_rates = 0xff; 4293 sc->sc_config.ofdm_ht_dual_stream_basic_rates = 0xff; 4294 sc->sc_config.ofdm_ht_single_stream_basic_rates = 0xff; 4295 break; 4296 case 2: 4297 sc->sc_config.ofdm_ht_dual_stream_basic_rates = 0xff; 4298 sc->sc_config.ofdm_ht_single_stream_basic_rates = 0xff; 4299 break; 4300 case 1: 4301 sc->sc_config.ofdm_ht_single_stream_basic_rates = 0xff; 4302 break; 4303 default: 4304 cmn_err(CE_WARN, "iwh_config(): " 4305 "RX stream count %d is not in suitable range\n", 4306 sc->sc_ht_conf.rx_stream_count); 4307 return (IWH_FAIL); 4308 } 4309 4310 /* 4311 * set RX chains/antennas. 4312 */ 4313 iwh_config_rxon_chain(sc); 4314 4315 err = iwh_cmd(sc, REPLY_RXON, &sc->sc_config, 4316 sizeof (iwh_rxon_cmd_t), 0); 4317 if (err != IWH_SUCCESS) { 4318 cmn_err(CE_WARN, "iwh_config(): " 4319 "failed to set configure command\n"); 4320 return (err); 4321 } 4322 4323 /* 4324 * remove all nodes in NIC 4325 */ 4326 (void) memset(&rm_sta, 0, sizeof (rm_sta)); 4327 rm_sta.num_sta = 1; 4328 (void) memcpy(rm_sta.addr, bcast, 6); 4329 4330 err = iwh_cmd(sc, REPLY_REMOVE_STA, &rm_sta, sizeof (iwh_rem_sta_t), 0); 4331 if (err != IWH_SUCCESS) { 4332 cmn_err(CE_WARN, "iwh_config(): " 4333 "failed to remove broadcast node in hardware.\n"); 4334 return (err); 4335 } 4336 4337 /* 4338 * configure TX power table 4339 */ 4340 err = iwh_tx_power_table(sc, 0); 4341 if (err != IWH_SUCCESS) { 4342 return (err); 4343 } 4344 4345 /* 4346 * add broadcast node so that we can send broadcast frame 4347 */ 4348 (void) memset(&node, 0, sizeof (node)); 4349 (void) memset(node.sta.addr, 0xff, 6); 4350 node.mode = 0; 4351 node.sta.sta_id = IWH_BROADCAST_ID; 4352 node.station_flags = 0; 4353 4354 err = iwh_cmd(sc, REPLY_ADD_STA, &node, sizeof (node), 0); 4355 if (err != IWH_SUCCESS) { 4356 cmn_err(CE_WARN, "iwh_config(): " 4357 "failed to add broadcast node\n"); 4358 return (err); 4359 } 4360 4361 /* 4362 * TX_LINK_QUALITY cmd 4363 */ 4364 (void) memset(&link_quality, 0, sizeof (link_quality)); 4365 for (i = 0; i < LINK_QUAL_MAX_RETRY_NUM; i++) { 4366 masks |= RATE_MCS_CCK_MSK; 4367 masks |= RATE_MCS_ANT_B_MSK; 4368 masks &= ~RATE_MCS_ANT_A_MSK; 4369 link_quality.rate_n_flags[i] = 4370 LE_32(iwh_rate_to_plcp(2) | masks); 4371 } 4372 4373 link_quality.general_params.single_stream_ant_msk = 2; 4374 link_quality.general_params.dual_stream_ant_msk = 3; 4375 link_quality.agg_params.agg_dis_start_th = 3; 4376 link_quality.agg_params.agg_time_limit = LE_16(4000); 4377 link_quality.sta_id = IWH_BROADCAST_ID; 4378 err = iwh_cmd(sc, REPLY_TX_LINK_QUALITY_CMD, &link_quality, 4379 sizeof (link_quality), 0); 4380 if (err != IWH_SUCCESS) { 4381 cmn_err(CE_WARN, "iwh_config(): " 4382 "failed to config link quality table\n"); 4383 return (err); 4384 } 4385 4386 return (err); 4387 } 4388 4389 /* 4390 * quiesce(9E) entry point. 4391 * This function is called when the system is single-threaded at high 4392 * PIL with preemption disabled. Therefore, this function must not be 4393 * blocked. 4394 * This function returns DDI_SUCCESS on success, or DDI_FAILURE on failure. 4395 * DDI_FAILURE indicates an error condition and should almost never happen. 4396 */ 4397 static int 4398 iwh_quiesce(dev_info_t *dip) 4399 { 4400 iwh_sc_t *sc; 4401 4402 sc = ddi_get_soft_state(iwh_soft_state_p, ddi_get_instance(dip)); 4403 if (sc == NULL) { 4404 return (DDI_FAILURE); 4405 } 4406 4407 #ifdef DEBUG 4408 /* by pass any messages, if it's quiesce */ 4409 iwh_dbg_flags = 0; 4410 #endif 4411 4412 /* 4413 * No more blocking is allowed while we are in the 4414 * quiesce(9E) entry point. 4415 */ 4416 sc->sc_flags |= IWH_F_QUIESCED; 4417 4418 /* 4419 * Disable and mask all interrupts. 4420 */ 4421 iwh_stop(sc); 4422 4423 return (DDI_SUCCESS); 4424 } 4425 4426 static void 4427 iwh_stop_master(iwh_sc_t *sc) 4428 { 4429 uint32_t tmp; 4430 int n; 4431 4432 tmp = IWH_READ(sc, CSR_RESET); 4433 IWH_WRITE(sc, CSR_RESET, tmp | CSR_RESET_REG_FLAG_STOP_MASTER); 4434 4435 tmp = IWH_READ(sc, CSR_GP_CNTRL); 4436 if ((tmp & CSR_GP_CNTRL_REG_MSK_POWER_SAVE_TYPE) == 4437 CSR_GP_CNTRL_REG_FLAG_MAC_POWER_SAVE) { 4438 return; 4439 } 4440 4441 for (n = 0; n < 2000; n++) { 4442 if (IWH_READ(sc, CSR_RESET) & 4443 CSR_RESET_REG_FLAG_MASTER_DISABLED) { 4444 break; 4445 } 4446 DELAY(1000); 4447 } 4448 4449 #ifdef DEBUG 4450 if (2000 == n) { 4451 IWH_DBG((IWH_DEBUG_HW, "iwh_stop_master(): " 4452 "timeout waiting for master stop\n")); 4453 } 4454 #endif 4455 } 4456 4457 static int 4458 iwh_power_up(iwh_sc_t *sc) 4459 { 4460 uint32_t tmp; 4461 4462 iwh_mac_access_enter(sc); 4463 tmp = iwh_reg_read(sc, ALM_APMG_PS_CTL); 4464 tmp &= ~APMG_PS_CTRL_REG_MSK_POWER_SRC; 4465 tmp |= APMG_PS_CTRL_REG_VAL_POWER_SRC_VMAIN; 4466 iwh_reg_write(sc, ALM_APMG_PS_CTL, tmp); 4467 iwh_mac_access_exit(sc); 4468 4469 DELAY(5000); 4470 return (IWH_SUCCESS); 4471 } 4472 4473 /* 4474 * hardware initialization 4475 */ 4476 static int 4477 iwh_preinit(iwh_sc_t *sc) 4478 { 4479 int n; 4480 uint8_t vlink; 4481 uint16_t radio_cfg; 4482 uint32_t tmp; 4483 4484 /* 4485 * clear any pending interrupts 4486 */ 4487 IWH_WRITE(sc, CSR_INT, 0xffffffff); 4488 4489 tmp = IWH_READ(sc, CSR_GIO_CHICKEN_BITS); 4490 IWH_WRITE(sc, CSR_GIO_CHICKEN_BITS, 4491 tmp | CSR_GIO_CHICKEN_BITS_REG_BIT_DIS_L0S_EXIT_TIMER); 4492 4493 tmp = IWH_READ(sc, CSR_ANA_PLL_CFG); 4494 IWH_WRITE(sc, CSR_ANA_PLL_CFG, tmp | IWH_CSR_ANA_PLL_CFG); 4495 4496 tmp = IWH_READ(sc, CSR_GP_CNTRL); 4497 IWH_WRITE(sc, CSR_GP_CNTRL, tmp | CSR_GP_CNTRL_REG_FLAG_INIT_DONE); 4498 4499 /* 4500 * wait for clock ready 4501 */ 4502 for (n = 0; n < 1000; n++) { 4503 if (IWH_READ(sc, CSR_GP_CNTRL) & 4504 CSR_GP_CNTRL_REG_FLAG_MAC_CLOCK_READY) { 4505 break; 4506 } 4507 DELAY(10); 4508 } 4509 4510 if (1000 == n) { 4511 return (ETIMEDOUT); 4512 } 4513 4514 iwh_mac_access_enter(sc); 4515 4516 iwh_reg_write(sc, ALM_APMG_CLK_EN, APMG_CLK_REG_VAL_DMA_CLK_RQT); 4517 4518 DELAY(20); 4519 tmp = iwh_reg_read(sc, ALM_APMG_PCIDEV_STT); 4520 iwh_reg_write(sc, ALM_APMG_PCIDEV_STT, tmp | 4521 APMG_DEV_STATE_REG_VAL_L1_ACTIVE_DISABLE); 4522 iwh_mac_access_exit(sc); 4523 4524 radio_cfg = IWH_READ_EEP_SHORT(sc, EEP_SP_RADIO_CONFIGURATION); 4525 if (SP_RADIO_TYPE_MSK(radio_cfg) < SP_RADIO_TYPE_MAX) { 4526 tmp = IWH_READ(sc, CSR_HW_IF_CONFIG_REG); 4527 IWH_WRITE(sc, CSR_HW_IF_CONFIG_REG, 4528 tmp | SP_RADIO_TYPE_MSK(radio_cfg) | 4529 SP_RADIO_STEP_MSK(radio_cfg) | 4530 SP_RADIO_DASH_MSK(radio_cfg)); 4531 } else { 4532 cmn_err(CE_WARN, "iwh_preinit(): " 4533 "radio configuration information in eeprom is wrong\n"); 4534 return (IWH_FAIL); 4535 } 4536 4537 4538 IWH_WRITE(sc, CSR_INT_COALESCING, 512 / 32); 4539 4540 (void) iwh_power_up(sc); 4541 4542 if ((sc->sc_rev & 0x80) == 0x80 && (sc->sc_rev & 0x7f) < 8) { 4543 tmp = ddi_get32(sc->sc_cfg_handle, 4544 (uint32_t *)(sc->sc_cfg_base + 0xe8)); 4545 ddi_put32(sc->sc_cfg_handle, 4546 (uint32_t *)(sc->sc_cfg_base + 0xe8), 4547 tmp & ~(1 << 11)); 4548 } 4549 4550 vlink = ddi_get8(sc->sc_cfg_handle, 4551 (uint8_t *)(sc->sc_cfg_base + 0xf0)); 4552 ddi_put8(sc->sc_cfg_handle, (uint8_t *)(sc->sc_cfg_base + 0xf0), 4553 vlink & ~2); 4554 4555 tmp = IWH_READ(sc, CSR_SW_VER); 4556 tmp |= CSR_HW_IF_CONFIG_REG_BIT_RADIO_SI | 4557 CSR_HW_IF_CONFIG_REG_BIT_MAC_SI; 4558 IWH_WRITE(sc, CSR_SW_VER, tmp); 4559 4560 /* 4561 * make sure power supply on each part of the hardware 4562 */ 4563 iwh_mac_access_enter(sc); 4564 tmp = iwh_reg_read(sc, ALM_APMG_PS_CTL); 4565 tmp |= APMG_PS_CTRL_REG_VAL_ALM_R_RESET_REQ; 4566 iwh_reg_write(sc, ALM_APMG_PS_CTL, tmp); 4567 DELAY(5); 4568 4569 tmp = iwh_reg_read(sc, ALM_APMG_PS_CTL); 4570 tmp &= ~APMG_PS_CTRL_REG_VAL_ALM_R_RESET_REQ; 4571 iwh_reg_write(sc, ALM_APMG_PS_CTL, tmp); 4572 iwh_mac_access_exit(sc); 4573 4574 return (IWH_SUCCESS); 4575 } 4576 4577 /* 4578 * set up semphore flag to own EEPROM 4579 */ 4580 static int 4581 iwh_eep_sem_down(iwh_sc_t *sc) 4582 { 4583 int count1, count2; 4584 uint32_t tmp; 4585 4586 for (count1 = 0; count1 < 1000; count1++) { 4587 tmp = IWH_READ(sc, CSR_HW_IF_CONFIG_REG); 4588 IWH_WRITE(sc, CSR_HW_IF_CONFIG_REG, 4589 tmp | CSR_HW_IF_CONFIG_REG_EEP_SEM); 4590 4591 for (count2 = 0; count2 < 2; count2++) { 4592 if (IWH_READ(sc, CSR_HW_IF_CONFIG_REG) & 4593 CSR_HW_IF_CONFIG_REG_EEP_SEM) { 4594 return (IWH_SUCCESS); 4595 } 4596 DELAY(10000); 4597 } 4598 } 4599 return (IWH_FAIL); 4600 } 4601 4602 /* 4603 * reset semphore flag to release EEPROM 4604 */ 4605 static void 4606 iwh_eep_sem_up(iwh_sc_t *sc) 4607 { 4608 uint32_t tmp; 4609 4610 tmp = IWH_READ(sc, CSR_HW_IF_CONFIG_REG); 4611 IWH_WRITE(sc, CSR_HW_IF_CONFIG_REG, 4612 tmp & (~CSR_HW_IF_CONFIG_REG_EEP_SEM)); 4613 } 4614 4615 /* 4616 * This function read all infomation from eeprom 4617 */ 4618 static int 4619 iwh_eep_load(iwh_sc_t *sc) 4620 { 4621 int i, rr; 4622 uint32_t rv, tmp, eep_gp; 4623 uint16_t addr, eep_sz = sizeof (sc->sc_eep_map); 4624 uint16_t *eep_p = (uint16_t *)&sc->sc_eep_map; 4625 4626 /* 4627 * read eeprom gp register in CSR 4628 */ 4629 eep_gp = IWH_READ(sc, CSR_EEPROM_GP); 4630 if ((eep_gp & CSR_EEPROM_GP_VALID_MSK) == 4631 CSR_EEPROM_GP_BAD_SIGNATURE) { 4632 IWH_DBG((IWH_DEBUG_EEPROM, "iwh_eep_load(): " 4633 "not find eeprom\n")); 4634 return (IWH_FAIL); 4635 } 4636 4637 rr = iwh_eep_sem_down(sc); 4638 if (rr != 0) { 4639 IWH_DBG((IWH_DEBUG_EEPROM, "iwh_eep_load(): " 4640 "driver failed to own EEPROM\n")); 4641 return (IWH_FAIL); 4642 } 4643 4644 for (addr = 0; addr < eep_sz; addr += 2) { 4645 IWH_WRITE(sc, CSR_EEPROM_REG, addr<<1); 4646 tmp = IWH_READ(sc, CSR_EEPROM_REG); 4647 IWH_WRITE(sc, CSR_EEPROM_REG, tmp & ~(0x2)); 4648 4649 for (i = 0; i < 10; i++) { 4650 rv = IWH_READ(sc, CSR_EEPROM_REG); 4651 if (rv & 1) { 4652 break; 4653 } 4654 DELAY(10); 4655 } 4656 4657 if (!(rv & 1)) { 4658 IWH_DBG((IWH_DEBUG_EEPROM, "iwh_eep_load(): " 4659 "time out when read eeprome\n")); 4660 iwh_eep_sem_up(sc); 4661 return (IWH_FAIL); 4662 } 4663 4664 eep_p[addr/2] = LE_16(rv >> 16); 4665 } 4666 4667 iwh_eep_sem_up(sc); 4668 return (IWH_SUCCESS); 4669 } 4670 4671 /* 4672 * initialize mac address in ieee80211com_t struct 4673 */ 4674 static void 4675 iwh_get_mac_from_eep(iwh_sc_t *sc) 4676 { 4677 ieee80211com_t *ic = &sc->sc_ic; 4678 4679 IEEE80211_ADDR_COPY(ic->ic_macaddr, &sc->sc_eep_map[EEP_MAC_ADDRESS]); 4680 4681 IWH_DBG((IWH_DEBUG_EEPROM, "iwh_get_mac_from_eep(): " 4682 "mac:%2x:%2x:%2x:%2x:%2x:%2x\n", 4683 ic->ic_macaddr[0], ic->ic_macaddr[1], ic->ic_macaddr[2], 4684 ic->ic_macaddr[3], ic->ic_macaddr[4], ic->ic_macaddr[5])); 4685 } 4686 4687 /* 4688 * main initialization function 4689 */ 4690 static int 4691 iwh_init(iwh_sc_t *sc) 4692 { 4693 int err = IWH_FAIL; 4694 clock_t clk; 4695 4696 /* 4697 * release buffer for calibration 4698 */ 4699 iwh_release_calib_buffer(sc); 4700 4701 mutex_enter(&sc->sc_glock); 4702 sc->sc_flags &= ~IWH_F_FW_INIT; 4703 4704 err = iwh_init_common(sc); 4705 if (err != IWH_SUCCESS) { 4706 mutex_exit(&sc->sc_glock); 4707 return (IWH_FAIL); 4708 } 4709 4710 /* 4711 * backup ucode data part for future use. 4712 */ 4713 (void) memcpy(sc->sc_dma_fw_data_bak.mem_va, 4714 sc->sc_dma_fw_data.mem_va, 4715 sc->sc_dma_fw_data.alength); 4716 4717 /* load firmware init segment into NIC */ 4718 err = iwh_load_init_firmware(sc); 4719 if (err != IWH_SUCCESS) { 4720 cmn_err(CE_WARN, "iwh_init(): " 4721 "failed to setup init firmware\n"); 4722 mutex_exit(&sc->sc_glock); 4723 return (IWH_FAIL); 4724 } 4725 4726 /* 4727 * now press "execute" start running 4728 */ 4729 IWH_WRITE(sc, CSR_RESET, 0); 4730 4731 clk = ddi_get_lbolt() + drv_usectohz(1000000); 4732 while (!(sc->sc_flags & IWH_F_FW_INIT)) { 4733 if (cv_timedwait(&sc->sc_ucode_cv, 4734 &sc->sc_glock, clk) < 0) { 4735 break; 4736 } 4737 } 4738 4739 if (!(sc->sc_flags & IWH_F_FW_INIT)) { 4740 cmn_err(CE_WARN, "iwh_init(): " 4741 "failed to process init alive.\n"); 4742 mutex_exit(&sc->sc_glock); 4743 return (IWH_FAIL); 4744 } 4745 4746 mutex_exit(&sc->sc_glock); 4747 4748 /* 4749 * stop chipset for initializing chipset again 4750 */ 4751 iwh_stop(sc); 4752 4753 mutex_enter(&sc->sc_glock); 4754 sc->sc_flags &= ~IWH_F_FW_INIT; 4755 4756 err = iwh_init_common(sc); 4757 if (err != IWH_SUCCESS) { 4758 mutex_exit(&sc->sc_glock); 4759 return (IWH_FAIL); 4760 } 4761 4762 /* 4763 * load firmware run segment into NIC 4764 */ 4765 err = iwh_load_run_firmware(sc); 4766 if (err != IWH_SUCCESS) { 4767 cmn_err(CE_WARN, "iwh_init(): " 4768 "failed to setup run firmware\n"); 4769 mutex_exit(&sc->sc_glock); 4770 return (IWH_FAIL); 4771 } 4772 4773 /* 4774 * now press "execute" start running 4775 */ 4776 IWH_WRITE(sc, CSR_RESET, 0); 4777 4778 clk = ddi_get_lbolt() + drv_usectohz(1000000); 4779 while (!(sc->sc_flags & IWH_F_FW_INIT)) { 4780 if (cv_timedwait(&sc->sc_ucode_cv, 4781 &sc->sc_glock, clk) < 0) { 4782 break; 4783 } 4784 } 4785 4786 if (!(sc->sc_flags & IWH_F_FW_INIT)) { 4787 cmn_err(CE_WARN, "iwh_init(): " 4788 "failed to process runtime alive.\n"); 4789 mutex_exit(&sc->sc_glock); 4790 return (IWH_FAIL); 4791 } 4792 4793 mutex_exit(&sc->sc_glock); 4794 4795 DELAY(1000); 4796 4797 mutex_enter(&sc->sc_glock); 4798 sc->sc_flags &= ~IWH_F_FW_INIT; 4799 4800 /* 4801 * at this point, the firmware is loaded OK, then config the hardware 4802 * with the ucode API, including rxon, txpower, etc. 4803 */ 4804 err = iwh_config(sc); 4805 if (err) { 4806 cmn_err(CE_WARN, "iwh_init(): " 4807 "failed to configure device\n"); 4808 mutex_exit(&sc->sc_glock); 4809 return (IWH_FAIL); 4810 } 4811 4812 /* 4813 * at this point, hardware may receive beacons :) 4814 */ 4815 mutex_exit(&sc->sc_glock); 4816 return (IWH_SUCCESS); 4817 } 4818 4819 /* 4820 * stop or disable NIC 4821 */ 4822 static void 4823 iwh_stop(iwh_sc_t *sc) 4824 { 4825 uint32_t tmp; 4826 int i; 4827 4828 /* by pass if it's quiesced */ 4829 if (!(sc->sc_flags & IWH_F_QUIESCED)) { 4830 mutex_enter(&sc->sc_glock); 4831 } 4832 4833 IWH_WRITE(sc, CSR_RESET, CSR_RESET_REG_FLAG_NEVO_RESET); 4834 /* 4835 * disable interrupts 4836 */ 4837 IWH_WRITE(sc, CSR_INT_MASK, 0); 4838 IWH_WRITE(sc, CSR_INT, CSR_INI_SET_MASK); 4839 IWH_WRITE(sc, CSR_FH_INT_STATUS, 0xffffffff); 4840 4841 /* 4842 * reset all Tx rings 4843 */ 4844 for (i = 0; i < IWH_NUM_QUEUES; i++) { 4845 iwh_reset_tx_ring(sc, &sc->sc_txq[i]); 4846 } 4847 4848 /* 4849 * reset Rx ring 4850 */ 4851 iwh_reset_rx_ring(sc); 4852 4853 iwh_mac_access_enter(sc); 4854 iwh_reg_write(sc, ALM_APMG_CLK_DIS, APMG_CLK_REG_VAL_DMA_CLK_RQT); 4855 iwh_mac_access_exit(sc); 4856 4857 DELAY(5); 4858 4859 iwh_stop_master(sc); 4860 4861 mutex_enter(&sc->sc_mt_lock); 4862 sc->sc_tx_timer = 0; 4863 mutex_exit(&sc->sc_mt_lock); 4864 4865 tmp = IWH_READ(sc, CSR_RESET); 4866 IWH_WRITE(sc, CSR_RESET, tmp | CSR_RESET_REG_FLAG_SW_RESET); 4867 4868 /* by pass if it's quiesced */ 4869 if (!(sc->sc_flags & IWH_F_QUIESCED)) { 4870 mutex_exit(&sc->sc_glock); 4871 } 4872 } 4873 4874 /* 4875 * Naive implementation of the Adaptive Multi Rate Retry algorithm: 4876 * "IEEE 802.11 Rate Adaptation: A Practical Approach" 4877 * Mathieu Lacage, Hossein Manshaei, Thierry Turletti 4878 * INRIA Sophia - Projet Planete 4879 * http://www-sop.inria.fr/rapports/sophia/RR-5208.html 4880 */ 4881 #define is_success(amrr) \ 4882 ((amrr)->retrycnt < (amrr)->txcnt / 10) 4883 #define is_failure(amrr) \ 4884 ((amrr)->retrycnt > (amrr)->txcnt / 3) 4885 #define is_enough(amrr) \ 4886 ((amrr)->txcnt > 200) 4887 #define not_very_few(amrr) \ 4888 ((amrr)->txcnt > 40) 4889 #define is_min_rate(in) \ 4890 (0 == (in)->in_txrate) 4891 #define is_max_rate(in) \ 4892 ((in)->in_rates.ir_nrates - 1 == (in)->in_txrate) 4893 #define increase_rate(in) \ 4894 ((in)->in_txrate++) 4895 #define decrease_rate(in) \ 4896 ((in)->in_txrate--) 4897 #define reset_cnt(amrr) \ 4898 { (amrr)->txcnt = (amrr)->retrycnt = 0; } 4899 4900 #define IWH_AMRR_MIN_SUCCESS_THRESHOLD 1 4901 #define IWH_AMRR_MAX_SUCCESS_THRESHOLD 15 4902 4903 static void 4904 iwh_amrr_init(iwh_amrr_t *amrr) 4905 { 4906 amrr->success = 0; 4907 amrr->recovery = 0; 4908 amrr->txcnt = amrr->retrycnt = 0; 4909 amrr->success_threshold = IWH_AMRR_MIN_SUCCESS_THRESHOLD; 4910 amrr->ht_mcs_idx = 0; /* 6Mbps */ 4911 } 4912 4913 static void 4914 iwh_amrr_timeout(iwh_sc_t *sc) 4915 { 4916 ieee80211com_t *ic = &sc->sc_ic; 4917 4918 IWH_DBG((IWH_DEBUG_RATECTL, "iwh_amrr_timeout(): " 4919 "enter\n")); 4920 4921 if (IEEE80211_M_STA == ic->ic_opmode) { 4922 iwh_amrr_ratectl(NULL, ic->ic_bss); 4923 } else { 4924 ieee80211_iterate_nodes(&ic->ic_sta, iwh_amrr_ratectl, NULL); 4925 } 4926 4927 sc->sc_clk = ddi_get_lbolt(); 4928 } 4929 4930 static int 4931 iwh_is_max_rate(ieee80211_node_t *in) 4932 { 4933 int i; 4934 iwh_amrr_t *amrr = (iwh_amrr_t *)in; 4935 uint8_t r = (uint8_t)amrr->ht_mcs_idx; 4936 ieee80211com_t *ic = in->in_ic; 4937 iwh_sc_t *sc = (iwh_sc_t *)ic; 4938 4939 if (in->in_flags & IEEE80211_NODE_HT) { 4940 for (i = in->in_htrates.rs_nrates - 1; i >= 0; i--) { 4941 r = in->in_htrates.rs_rates[i] & 4942 IEEE80211_RATE_VAL; 4943 if (sc->sc_ht_conf.tx_support_mcs[r/8] & 4944 (1 << (r%8))) { 4945 break; 4946 } 4947 } 4948 4949 return (r == (uint8_t)amrr->ht_mcs_idx); 4950 } else { 4951 return (is_max_rate(in)); 4952 } 4953 } 4954 4955 static int 4956 iwh_is_min_rate(ieee80211_node_t *in) 4957 { 4958 int i; 4959 uint8_t r = 0; 4960 iwh_amrr_t *amrr = (iwh_amrr_t *)in; 4961 ieee80211com_t *ic = in->in_ic; 4962 iwh_sc_t *sc = (iwh_sc_t *)ic; 4963 4964 if (in->in_flags & IEEE80211_NODE_HT) { 4965 for (i = 0; i < in->in_htrates.rs_nrates; i++) { 4966 r = in->in_htrates.rs_rates[i] & 4967 IEEE80211_RATE_VAL; 4968 if (sc->sc_ht_conf.tx_support_mcs[r/8] & 4969 (1 << (r%8))) { 4970 break; 4971 } 4972 } 4973 4974 return (r == (uint8_t)amrr->ht_mcs_idx); 4975 } else { 4976 return (is_min_rate(in)); 4977 } 4978 } 4979 4980 static void 4981 iwh_increase_rate(ieee80211_node_t *in) 4982 { 4983 int i; 4984 uint8_t r; 4985 iwh_amrr_t *amrr = (iwh_amrr_t *)in; 4986 ieee80211com_t *ic = in->in_ic; 4987 iwh_sc_t *sc = (iwh_sc_t *)ic; 4988 4989 if (in->in_flags & IEEE80211_NODE_HT) { 4990 again: 4991 amrr->ht_mcs_idx++; 4992 4993 for (i = 0; i < in->in_htrates.rs_nrates; i++) { 4994 r = in->in_htrates.rs_rates[i] & 4995 IEEE80211_RATE_VAL; 4996 if ((r == (uint8_t)amrr->ht_mcs_idx) && 4997 (sc->sc_ht_conf.tx_support_mcs[r/8] & 4998 (1 << (r%8)))) { 4999 break; 5000 } 5001 } 5002 5003 if (i >= in->in_htrates.rs_nrates) { 5004 goto again; 5005 } 5006 } else { 5007 increase_rate(in); 5008 } 5009 } 5010 5011 static void 5012 iwh_decrease_rate(ieee80211_node_t *in) 5013 { 5014 int i; 5015 uint8_t r; 5016 iwh_amrr_t *amrr = (iwh_amrr_t *)in; 5017 ieee80211com_t *ic = in->in_ic; 5018 iwh_sc_t *sc = (iwh_sc_t *)ic; 5019 5020 if (in->in_flags & IEEE80211_NODE_HT) { 5021 again: 5022 amrr->ht_mcs_idx--; 5023 5024 for (i = 0; i < in->in_htrates.rs_nrates; i++) { 5025 r = in->in_htrates.rs_rates[i] & 5026 IEEE80211_RATE_VAL; 5027 if ((r == (uint8_t)amrr->ht_mcs_idx) && 5028 (sc->sc_ht_conf.tx_support_mcs[r/8] & 5029 (1 << (r%8)))) { 5030 break; 5031 } 5032 } 5033 5034 if (i >= in->in_htrates.rs_nrates) { 5035 goto again; 5036 } 5037 } else { 5038 decrease_rate(in); 5039 } 5040 } 5041 5042 /* ARGSUSED */ 5043 static void 5044 iwh_amrr_ratectl(void *arg, ieee80211_node_t *in) 5045 { 5046 iwh_amrr_t *amrr = (iwh_amrr_t *)in; 5047 int need_change = 0; 5048 5049 if (is_success(amrr) && is_enough(amrr)) { 5050 amrr->success++; 5051 if (amrr->success >= amrr->success_threshold && 5052 !iwh_is_max_rate(in)) { 5053 amrr->recovery = 1; 5054 amrr->success = 0; 5055 iwh_increase_rate(in); 5056 IWH_DBG((IWH_DEBUG_RATECTL, "iwh_amrr_ratectl(): " 5057 "AMRR increasing rate %d " 5058 "(txcnt=%d retrycnt=%d), mcs_idx=%d\n", 5059 in->in_txrate, amrr->txcnt, 5060 amrr->retrycnt, amrr->ht_mcs_idx)); 5061 need_change = 1; 5062 } else { 5063 amrr->recovery = 0; 5064 } 5065 } else if (not_very_few(amrr) && is_failure(amrr)) { 5066 amrr->success = 0; 5067 if (!iwh_is_min_rate(in)) { 5068 if (amrr->recovery) { 5069 amrr->success_threshold++; 5070 if (amrr->success_threshold > 5071 IWH_AMRR_MAX_SUCCESS_THRESHOLD) { 5072 amrr->success_threshold = 5073 IWH_AMRR_MAX_SUCCESS_THRESHOLD; 5074 } 5075 } else { 5076 amrr->success_threshold = 5077 IWH_AMRR_MIN_SUCCESS_THRESHOLD; 5078 } 5079 iwh_decrease_rate(in); 5080 IWH_DBG((IWH_DEBUG_RATECTL, "iwh_amrr_ratectl(): " 5081 "AMRR decreasing rate %d " 5082 "(txcnt=%d retrycnt=%d), mcs_idx=%d\n", 5083 in->in_txrate, amrr->txcnt, 5084 amrr->retrycnt, amrr->ht_mcs_idx)); 5085 need_change = 1; 5086 } 5087 amrr->recovery = 0; /* paper is incorrect */ 5088 } 5089 5090 if (is_enough(amrr) || need_change) { 5091 reset_cnt(amrr); 5092 } 5093 } 5094 5095 /* 5096 * translate indirect address in eeprom to direct address 5097 * in eeprom and return address of entry whos indirect address 5098 * is indi_addr 5099 */ 5100 static uint8_t * 5101 iwh_eep_addr_trans(iwh_sc_t *sc, uint32_t indi_addr) 5102 { 5103 uint32_t di_addr; 5104 uint16_t temp; 5105 5106 if (!(indi_addr & INDIRECT_ADDRESS)) { 5107 di_addr = indi_addr; 5108 return (&sc->sc_eep_map[di_addr]); 5109 } 5110 5111 switch (indi_addr & INDIRECT_TYPE_MSK) { 5112 case INDIRECT_GENERAL: 5113 temp = IWH_READ_EEP_SHORT(sc, EEP_LINK_GENERAL); 5114 break; 5115 5116 case INDIRECT_HOST: 5117 temp = IWH_READ_EEP_SHORT(sc, EEP_LINK_HOST); 5118 break; 5119 5120 case INDIRECT_REGULATORY: 5121 temp = IWH_READ_EEP_SHORT(sc, EEP_LINK_REGULATORY); 5122 break; 5123 5124 case INDIRECT_CALIBRATION: 5125 temp = IWH_READ_EEP_SHORT(sc, EEP_LINK_CALIBRATION); 5126 break; 5127 5128 case INDIRECT_PROCESS_ADJST: 5129 temp = IWH_READ_EEP_SHORT(sc, EEP_LINK_PROCESS_ADJST); 5130 break; 5131 5132 case INDIRECT_OTHERS: 5133 temp = IWH_READ_EEP_SHORT(sc, EEP_LINK_OTHERS); 5134 break; 5135 5136 default: 5137 temp = 0; 5138 cmn_err(CE_WARN, "iwh_eep_addr_trans(): " 5139 "incorrect indirect eeprom address.\n"); 5140 break; 5141 } 5142 5143 di_addr = (indi_addr & ADDRESS_MSK) + (temp << 1); 5144 5145 return (&sc->sc_eep_map[di_addr]); 5146 } 5147 5148 /* 5149 * loade a section of ucode into NIC 5150 */ 5151 static int 5152 iwh_put_seg_fw(iwh_sc_t *sc, uint32_t addr_s, uint32_t addr_d, uint32_t len) 5153 { 5154 5155 iwh_mac_access_enter(sc); 5156 5157 IWH_WRITE(sc, IWH_FH_TCSR_CHNL_TX_CONFIG_REG(IWH_FH_SRVC_CHNL), 5158 IWH_FH_TCSR_TX_CONFIG_REG_VAL_DMA_CHNL_PAUSE); 5159 5160 IWH_WRITE(sc, IWH_FH_SRVC_CHNL_SRAM_ADDR_REG(IWH_FH_SRVC_CHNL), addr_d); 5161 5162 IWH_WRITE(sc, IWH_FH_TFDIB_CTRL0_REG(IWH_FH_SRVC_CHNL), 5163 (addr_s & FH_MEM_TFDIB_DRAM_ADDR_LSB_MASK)); 5164 5165 IWH_WRITE(sc, IWH_FH_TFDIB_CTRL1_REG(IWH_FH_SRVC_CHNL), len); 5166 5167 IWH_WRITE(sc, IWH_FH_TCSR_CHNL_TX_BUF_STS_REG(IWH_FH_SRVC_CHNL), 5168 (1 << IWH_FH_TCSR_CHNL_TX_BUF_STS_REG_POS_TB_NUM) | 5169 (1 << IWH_FH_TCSR_CHNL_TX_BUF_STS_REG_POS_TB_IDX) | 5170 IWH_FH_TCSR_CHNL_TX_BUF_STS_REG_VAL_TFDB_VALID); 5171 5172 IWH_WRITE(sc, IWH_FH_TCSR_CHNL_TX_CONFIG_REG(IWH_FH_SRVC_CHNL), 5173 IWH_FH_TCSR_TX_CONFIG_REG_VAL_DMA_CHNL_ENABLE | 5174 IWH_FH_TCSR_TX_CONFIG_REG_VAL_DMA_CREDIT_DISABLE_VAL | 5175 IWH_FH_TCSR_TX_CONFIG_REG_VAL_CIRQ_HOST_ENDTFD); 5176 5177 iwh_mac_access_exit(sc); 5178 5179 return (IWH_SUCCESS); 5180 } 5181 5182 /* 5183 * necessary setting during alive notification 5184 */ 5185 static int 5186 iwh_alive_common(iwh_sc_t *sc) 5187 { 5188 uint32_t base; 5189 uint32_t i; 5190 iwh_wimax_coex_cmd_t w_cmd; 5191 iwh_calibration_crystal_cmd_t c_cmd; 5192 uint32_t rv = IWH_FAIL; 5193 5194 /* 5195 * initialize SCD related registers to make TX work. 5196 */ 5197 iwh_mac_access_enter(sc); 5198 5199 /* 5200 * read sram address of data base. 5201 */ 5202 sc->sc_scd_base = iwh_reg_read(sc, IWH_SCD_SRAM_BASE_ADDR); 5203 5204 for (base = sc->sc_scd_base + IWH_SCD_CONTEXT_DATA_OFFSET; 5205 base < sc->sc_scd_base + IWH_SCD_TX_STTS_BITMAP_OFFSET; 5206 base += 4) { 5207 iwh_mem_write(sc, base, 0); 5208 } 5209 5210 for (; base < sc->sc_scd_base + IWH_SCD_TRANSLATE_TBL_OFFSET; 5211 base += 4) { 5212 iwh_mem_write(sc, base, 0); 5213 } 5214 5215 for (i = 0; i < sizeof (uint16_t) * IWH_NUM_QUEUES; i += 4) { 5216 iwh_mem_write(sc, base + i, 0); 5217 } 5218 5219 iwh_reg_write(sc, IWH_SCD_DRAM_BASE_ADDR, 5220 sc->sc_dma_sh.cookie.dmac_address >> 10); 5221 5222 iwh_reg_write(sc, IWH_SCD_QUEUECHAIN_SEL, 5223 IWH_SCD_QUEUECHAIN_SEL_ALL(IWH_NUM_QUEUES)); 5224 5225 iwh_reg_write(sc, IWH_SCD_AGGR_SEL, 0); 5226 5227 for (i = 0; i < IWH_NUM_QUEUES; i++) { 5228 iwh_reg_write(sc, IWH_SCD_QUEUE_RDPTR(i), 0); 5229 IWH_WRITE(sc, HBUS_TARG_WRPTR, 0 | (i << 8)); 5230 iwh_mem_write(sc, sc->sc_scd_base + 5231 IWH_SCD_CONTEXT_QUEUE_OFFSET(i), 0); 5232 iwh_mem_write(sc, sc->sc_scd_base + 5233 IWH_SCD_CONTEXT_QUEUE_OFFSET(i) + 5234 sizeof (uint32_t), 5235 ((SCD_WIN_SIZE << IWH_SCD_QUEUE_CTX_REG2_WIN_SIZE_POS) & 5236 IWH_SCD_QUEUE_CTX_REG2_WIN_SIZE_MSK) | 5237 ((SCD_FRAME_LIMIT << 5238 IWH_SCD_QUEUE_CTX_REG2_FRAME_LIMIT_POS) & 5239 IWH_SCD_QUEUE_CTX_REG2_FRAME_LIMIT_MSK)); 5240 } 5241 5242 iwh_reg_write(sc, IWH_SCD_INTERRUPT_MASK, (1 << IWH_NUM_QUEUES) - 1); 5243 5244 iwh_reg_write(sc, (IWH_SCD_BASE + 0x10), 5245 SCD_TXFACT_REG_TXFIFO_MASK(0, 7)); 5246 5247 IWH_WRITE(sc, HBUS_TARG_WRPTR, (IWH_CMD_QUEUE_NUM << 8)); 5248 iwh_reg_write(sc, IWH_SCD_QUEUE_RDPTR(IWH_CMD_QUEUE_NUM), 0); 5249 5250 /* 5251 * queue 0-7 map to FIFO 0-7 and 5252 * all queues work under FIFO mode(none-scheduler_ack) 5253 */ 5254 for (i = 0; i < 4; i++) { 5255 iwh_reg_write(sc, IWH_SCD_QUEUE_STATUS_BITS(i), 5256 (1 << IWH_SCD_QUEUE_STTS_REG_POS_ACTIVE) | 5257 ((3-i) << IWH_SCD_QUEUE_STTS_REG_POS_TXF) | 5258 (1 << IWH_SCD_QUEUE_STTS_REG_POS_WSL) | 5259 IWH_SCD_QUEUE_STTS_REG_MSK); 5260 } 5261 5262 iwh_reg_write(sc, IWH_SCD_QUEUE_STATUS_BITS(IWH_CMD_QUEUE_NUM), 5263 (1 << IWH_SCD_QUEUE_STTS_REG_POS_ACTIVE) | 5264 (IWH_CMD_FIFO_NUM << IWH_SCD_QUEUE_STTS_REG_POS_TXF) | 5265 (1 << IWH_SCD_QUEUE_STTS_REG_POS_WSL) | 5266 IWH_SCD_QUEUE_STTS_REG_MSK); 5267 5268 for (i = 5; i < 7; i++) { 5269 iwh_reg_write(sc, IWH_SCD_QUEUE_STATUS_BITS(i), 5270 (1 << IWH_SCD_QUEUE_STTS_REG_POS_ACTIVE) | 5271 (i << IWH_SCD_QUEUE_STTS_REG_POS_TXF) | 5272 (1 << IWH_SCD_QUEUE_STTS_REG_POS_WSL) | 5273 IWH_SCD_QUEUE_STTS_REG_MSK); 5274 } 5275 5276 iwh_mac_access_exit(sc); 5277 5278 (void) memset(&w_cmd, 0, sizeof (w_cmd)); 5279 5280 rv = iwh_cmd(sc, COEX_PRIORITY_TABLE_CMD, &w_cmd, sizeof (w_cmd), 1); 5281 if (rv != IWH_SUCCESS) { 5282 cmn_err(CE_WARN, "iwh_alive_common(): " 5283 "failed to send wimax coexist command.\n"); 5284 return (rv); 5285 } 5286 5287 (void) memset(&c_cmd, 0, sizeof (c_cmd)); 5288 5289 c_cmd.opCode = PHY_CALIBRATE_CRYSTAL_FRQ_CMD; 5290 c_cmd.data.cap_pin1 = LE_16(sc->sc_eep_calib->xtal_calib[0]); 5291 c_cmd.data.cap_pin2 = LE_16(sc->sc_eep_calib->xtal_calib[1]); 5292 5293 rv = iwh_cmd(sc, REPLY_PHY_CALIBRATION_CMD, &c_cmd, sizeof (c_cmd), 1); 5294 if (rv != IWH_SUCCESS) { 5295 cmn_err(CE_WARN, "iwh_alive_common(): " 5296 "failed to send crystal frq calibration command.\n"); 5297 return (rv); 5298 } 5299 5300 /* 5301 * make sure crystal frequency calibration ready 5302 * before next operations. 5303 */ 5304 DELAY(1000); 5305 5306 return (IWH_SUCCESS); 5307 } 5308 5309 /* 5310 * save results of calibration from ucode 5311 */ 5312 static void 5313 iwh_save_calib_result(iwh_sc_t *sc, iwh_rx_desc_t *desc) 5314 { 5315 struct iwh_calib_results *res_p = &sc->sc_calib_results; 5316 struct iwh_calib_hdr *calib_hdr = (struct iwh_calib_hdr *)(desc + 1); 5317 int len = LE_32(desc->len); 5318 5319 /* 5320 * ensure the size of buffer is not too big 5321 */ 5322 len = (len & FH_RSCSR_FRAME_SIZE_MASK) - 4; 5323 5324 switch (calib_hdr->op_code) { 5325 case PHY_CALIBRATE_LO_CMD: 5326 if (NULL == res_p->lo_res) { 5327 res_p->lo_res = kmem_alloc(len, KM_NOSLEEP); 5328 } 5329 5330 if (NULL == res_p->lo_res) { 5331 cmn_err(CE_WARN, "iwh_save_calib_result(): " 5332 "failed to allocate memory.\n"); 5333 return; 5334 } 5335 5336 res_p->lo_res_len = len; 5337 (void) memcpy(res_p->lo_res, calib_hdr, len); 5338 break; 5339 5340 case PHY_CALIBRATE_TX_IQ_CMD: 5341 if (NULL == res_p->tx_iq_res) { 5342 res_p->tx_iq_res = kmem_alloc(len, KM_NOSLEEP); 5343 } 5344 5345 if (NULL == res_p->tx_iq_res) { 5346 cmn_err(CE_WARN, "iwh_save_calib_result(): " 5347 "failed to allocate memory.\n"); 5348 return; 5349 } 5350 5351 res_p->tx_iq_res_len = len; 5352 (void) memcpy(res_p->tx_iq_res, calib_hdr, len); 5353 break; 5354 5355 case PHY_CALIBRATE_TX_IQ_PERD_CMD: 5356 if (NULL == res_p->tx_iq_perd_res) { 5357 res_p->tx_iq_perd_res = kmem_alloc(len, KM_NOSLEEP); 5358 } 5359 5360 if (NULL == res_p->tx_iq_perd_res) { 5361 cmn_err(CE_WARN, "iwh_save_calib_result(): " 5362 "failed to allocate memory.\n"); 5363 } 5364 5365 res_p->tx_iq_perd_res_len = len; 5366 (void) memcpy(res_p->tx_iq_perd_res, calib_hdr, len); 5367 break; 5368 5369 default: 5370 cmn_err(CE_WARN, "iwh_save_calib_result(): " 5371 "incorrect calibration type.\n"); 5372 break; 5373 } 5374 5375 } 5376 5377 /* 5378 * configure TX pwoer table 5379 */ 5380 static int 5381 iwh_tx_power_table(iwh_sc_t *sc, int async) 5382 { 5383 iwh_tx_power_table_cmd_t txpower; 5384 int i, err = IWH_FAIL; 5385 5386 (void) memset(&txpower, 0, sizeof (txpower)); 5387 5388 txpower.band = 1; /* for 2.4G */ 5389 txpower.channel = (uint8_t)LE_16(sc->sc_config.chan); 5390 txpower.pa_measurements = 1; 5391 txpower.max_mcs = 23; 5392 5393 for (i = 0; i < 24; i++) { 5394 txpower.db.ht_ofdm_power[i].s.radio_tx_gain[0] = 0x16; 5395 txpower.db.ht_ofdm_power[i].s.radio_tx_gain[1] = 0x16; 5396 txpower.db.ht_ofdm_power[i].s.radio_tx_gain[2] = 0x16; 5397 txpower.db.ht_ofdm_power[i].s.dsp_predis_atten[0] = 0x6E; 5398 txpower.db.ht_ofdm_power[i].s.dsp_predis_atten[1] = 0x6E; 5399 txpower.db.ht_ofdm_power[i].s.dsp_predis_atten[2] = 0x6E; 5400 } 5401 5402 for (i = 0; i < 2; i++) { 5403 txpower.db.cck_power[i].s.radio_tx_gain[0] = 0x16; 5404 txpower.db.cck_power[i].s.radio_tx_gain[1] = 0x16; 5405 txpower.db.cck_power[i].s.radio_tx_gain[2] = 0x16; 5406 txpower.db.cck_power[i].s.dsp_predis_atten[0] = 0x6E; 5407 txpower.db.cck_power[i].s.dsp_predis_atten[1] = 0x6E; 5408 txpower.db.cck_power[i].s.dsp_predis_atten[2] = 0x6E; 5409 } 5410 5411 err = iwh_cmd(sc, REPLY_TX_PWR_TABLE_CMD, &txpower, 5412 sizeof (txpower), async); 5413 if (err != IWH_SUCCESS) { 5414 cmn_err(CE_WARN, "iwh_tx_power_table(): " 5415 "failed to set tx power table.\n"); 5416 return (err); 5417 } 5418 5419 return (err); 5420 } 5421 5422 static void 5423 iwh_release_calib_buffer(iwh_sc_t *sc) 5424 { 5425 if (sc->sc_calib_results.lo_res != NULL) { 5426 kmem_free(sc->sc_calib_results.lo_res, 5427 sc->sc_calib_results.lo_res_len); 5428 sc->sc_calib_results.lo_res = NULL; 5429 } 5430 5431 if (sc->sc_calib_results.tx_iq_res != NULL) { 5432 kmem_free(sc->sc_calib_results.tx_iq_res, 5433 sc->sc_calib_results.tx_iq_res_len); 5434 sc->sc_calib_results.tx_iq_res = NULL; 5435 } 5436 5437 if (sc->sc_calib_results.tx_iq_perd_res != NULL) { 5438 kmem_free(sc->sc_calib_results.tx_iq_perd_res, 5439 sc->sc_calib_results.tx_iq_perd_res_len); 5440 sc->sc_calib_results.tx_iq_perd_res = NULL; 5441 } 5442 5443 } 5444 5445 /* 5446 * common section of intialization 5447 */ 5448 static int 5449 iwh_init_common(iwh_sc_t *sc) 5450 { 5451 int32_t qid; 5452 uint32_t tmp; 5453 5454 (void) iwh_preinit(sc); 5455 5456 tmp = IWH_READ(sc, CSR_GP_CNTRL); 5457 if (!(tmp & CSR_GP_CNTRL_REG_FLAG_HW_RF_KILL_SW)) { 5458 cmn_err(CE_NOTE, "iwh_init_common(): " 5459 "radio transmitter is off\n"); 5460 return (IWH_FAIL); 5461 } 5462 5463 /* 5464 * init Rx ring 5465 */ 5466 iwh_mac_access_enter(sc); 5467 IWH_WRITE(sc, FH_MEM_RCSR_CHNL0_CONFIG_REG, 0); 5468 5469 IWH_WRITE(sc, FH_RSCSR_CHNL0_RBDCB_WPTR_REG, 0); 5470 IWH_WRITE(sc, FH_RSCSR_CHNL0_RBDCB_BASE_REG, 5471 sc->sc_rxq.dma_desc.cookie.dmac_address >> 8); 5472 5473 IWH_WRITE(sc, FH_RSCSR_CHNL0_STTS_WPTR_REG, 5474 ((uint32_t)(sc->sc_dma_sh.cookie.dmac_address + 5475 offsetof(struct iwh_shared, val0)) >> 4)); 5476 5477 IWH_WRITE(sc, FH_MEM_RCSR_CHNL0_CONFIG_REG, 5478 FH_RCSR_RX_CONFIG_CHNL_EN_ENABLE_VAL | 5479 FH_RCSR_CHNL0_RX_CONFIG_IRQ_DEST_INT_HOST_VAL | 5480 IWH_FH_RCSR_RX_CONFIG_REG_VAL_RB_SIZE_8K | 5481 (RX_QUEUE_SIZE_LOG << 5482 FH_RCSR_RX_CONFIG_RBDCB_SIZE_BITSHIFT)); 5483 iwh_mac_access_exit(sc); 5484 IWH_WRITE(sc, FH_RSCSR_CHNL0_RBDCB_WPTR_REG, 5485 (RX_QUEUE_SIZE - 1) & ~0x7); 5486 5487 /* 5488 * init Tx rings 5489 */ 5490 iwh_mac_access_enter(sc); 5491 iwh_reg_write(sc, IWH_SCD_TXFACT, 0); 5492 5493 /* 5494 * keep warm page 5495 */ 5496 IWH_WRITE(sc, IWH_FH_KW_MEM_ADDR_REG, 5497 sc->sc_dma_kw.cookie.dmac_address >> 4); 5498 5499 for (qid = 0; qid < IWH_NUM_QUEUES; qid++) { 5500 IWH_WRITE(sc, FH_MEM_CBBC_QUEUE(qid), 5501 sc->sc_txq[qid].dma_desc.cookie.dmac_address >> 8); 5502 IWH_WRITE(sc, IWH_FH_TCSR_CHNL_TX_CONFIG_REG(qid), 5503 IWH_FH_TCSR_TX_CONFIG_REG_VAL_DMA_CHNL_ENABLE | 5504 IWH_FH_TCSR_TX_CONFIG_REG_VAL_DMA_CREDIT_ENABLE_VAL); 5505 } 5506 5507 iwh_mac_access_exit(sc); 5508 5509 /* 5510 * clear "radio off" and "disable command" bits 5511 */ 5512 IWH_WRITE(sc, CSR_UCODE_DRV_GP1_CLR, CSR_UCODE_SW_BIT_RFKILL); 5513 IWH_WRITE(sc, CSR_UCODE_DRV_GP1_CLR, 5514 CSR_UCODE_DRV_GP1_BIT_CMD_BLOCKED); 5515 5516 /* 5517 * clear any pending interrupts 5518 */ 5519 IWH_WRITE(sc, CSR_INT, 0xffffffff); 5520 5521 /* 5522 * enable interrupts 5523 */ 5524 IWH_WRITE(sc, CSR_INT_MASK, CSR_INI_SET_MASK); 5525 5526 IWH_WRITE(sc, CSR_UCODE_DRV_GP1_CLR, CSR_UCODE_SW_BIT_RFKILL); 5527 IWH_WRITE(sc, CSR_UCODE_DRV_GP1_CLR, CSR_UCODE_SW_BIT_RFKILL); 5528 5529 return (IWH_SUCCESS); 5530 } 5531 5532 static int 5533 iwh_fast_recover(iwh_sc_t *sc) 5534 { 5535 ieee80211com_t *ic = &sc->sc_ic; 5536 int err = IWH_FAIL; 5537 5538 mutex_enter(&sc->sc_glock); 5539 5540 /* restore runtime configuration */ 5541 bcopy(&sc->sc_config_save, &sc->sc_config, 5542 sizeof (sc->sc_config)); 5543 5544 sc->sc_config.assoc_id = 0; 5545 sc->sc_config.filter_flags &= ~LE_32(RXON_FILTER_ASSOC_MSK); 5546 5547 if ((err = iwh_hw_set_before_auth(sc)) != IWH_SUCCESS) { 5548 cmn_err(CE_WARN, "iwh_fast_recover(): " 5549 "could not setup authentication\n"); 5550 mutex_exit(&sc->sc_glock); 5551 return (err); 5552 } 5553 5554 bcopy(&sc->sc_config_save, &sc->sc_config, 5555 sizeof (sc->sc_config)); 5556 5557 /* update adapter's configuration */ 5558 err = iwh_run_state_config(sc); 5559 if (err != IWH_SUCCESS) { 5560 cmn_err(CE_WARN, "iwh_fast_recover(): " 5561 "failed to setup association\n"); 5562 mutex_exit(&sc->sc_glock); 5563 return (err); 5564 } 5565 /* set LED on */ 5566 iwh_set_led(sc, 2, 0, 1); 5567 5568 mutex_exit(&sc->sc_glock); 5569 5570 sc->sc_flags &= ~IWH_F_HW_ERR_RECOVER; 5571 5572 /* start queue */ 5573 IWH_DBG((IWH_DEBUG_FW, "iwh_fast_recover(): " 5574 "resume xmit\n")); 5575 mac_tx_update(ic->ic_mach); 5576 5577 return (IWH_SUCCESS); 5578 } 5579 5580 static int 5581 iwh_run_state_config(iwh_sc_t *sc) 5582 { 5583 struct ieee80211com *ic = &sc->sc_ic; 5584 ieee80211_node_t *in = ic->ic_bss; 5585 uint32_t ht_protec = (uint32_t)(-1); 5586 int err = IWH_FAIL; 5587 5588 /* 5589 * update adapter's configuration 5590 */ 5591 sc->sc_config.assoc_id = in->in_associd & 0x3fff; 5592 5593 /* 5594 * short preamble/slot time are 5595 * negotiated when associating 5596 */ 5597 sc->sc_config.flags &= 5598 ~LE_32(RXON_FLG_SHORT_PREAMBLE_MSK | 5599 RXON_FLG_SHORT_SLOT_MSK); 5600 5601 if (ic->ic_flags & IEEE80211_F_SHSLOT) { 5602 sc->sc_config.flags |= 5603 LE_32(RXON_FLG_SHORT_SLOT_MSK); 5604 } 5605 5606 if (ic->ic_flags & IEEE80211_F_SHPREAMBLE) { 5607 sc->sc_config.flags |= 5608 LE_32(RXON_FLG_SHORT_PREAMBLE_MSK); 5609 } 5610 5611 if (in->in_flags & IEEE80211_NODE_HT) { 5612 ht_protec = in->in_htopmode; 5613 if (ht_protec > 3) { 5614 cmn_err(CE_WARN, "iwh_run_state_config(): " 5615 "HT protection mode is not correct.\n"); 5616 return (IWH_FAIL); 5617 } else if (NO_HT_PROT == ht_protec) { 5618 ht_protec = sc->sc_ht_conf.ht_protection; 5619 } 5620 5621 sc->sc_config.flags |= 5622 LE_32(ht_protec << RXON_FLG_HT_OPERATING_MODE_POS); 5623 } 5624 5625 /* 5626 * set RX chains/antennas. 5627 */ 5628 iwh_config_rxon_chain(sc); 5629 5630 sc->sc_config.filter_flags |= 5631 LE_32(RXON_FILTER_ASSOC_MSK); 5632 5633 if (ic->ic_opmode != IEEE80211_M_STA) { 5634 sc->sc_config.filter_flags |= 5635 LE_32(RXON_FILTER_BCON_AWARE_MSK); 5636 } 5637 5638 IWH_DBG((IWH_DEBUG_80211, "iwh_run_state_config(): " 5639 "config chan %d flags %x" 5640 " filter_flags %x\n", 5641 sc->sc_config.chan, sc->sc_config.flags, 5642 sc->sc_config.filter_flags)); 5643 5644 err = iwh_cmd(sc, REPLY_RXON, &sc->sc_config, 5645 sizeof (iwh_rxon_cmd_t), 1); 5646 if (err != IWH_SUCCESS) { 5647 cmn_err(CE_WARN, "iwh_run_state_config(): " 5648 "could not update configuration\n"); 5649 return (err); 5650 } 5651 5652 /* 5653 * send tx power table command 5654 */ 5655 err = iwh_tx_power_table(sc, 1); 5656 if (err != IWH_SUCCESS) { 5657 return (err); 5658 } 5659 5660 /* 5661 * Not need to update retry rate table for AP node 5662 */ 5663 err = iwh_qosparam_to_hw(sc, 1); 5664 if (err != IWH_SUCCESS) { 5665 return (err); 5666 } 5667 5668 return (err); 5669 } 5670 5671 /* 5672 * This function is only for compatibility with Net80211 module. 5673 * iwh_qosparam_to_hw() is the actual function updating EDCA 5674 * parameters to hardware. 5675 */ 5676 /* ARGSUSED */ 5677 static int 5678 iwh_wme_update(ieee80211com_t *ic) 5679 { 5680 return (0); 5681 } 5682 5683 static int 5684 iwh_wme_to_qos_ac(int wme_ac) 5685 { 5686 int qos_ac = QOS_AC_INVALID; 5687 5688 if (wme_ac < WME_AC_BE || wme_ac > WME_AC_VO) { 5689 cmn_err(CE_WARN, "iwh_wme_to_qos_ac(): " 5690 "WME AC index is not in suitable range.\n"); 5691 return (qos_ac); 5692 } 5693 5694 switch (wme_ac) { 5695 case WME_AC_BE: 5696 qos_ac = QOS_AC_BK; 5697 break; 5698 case WME_AC_BK: 5699 qos_ac = QOS_AC_BE; 5700 break; 5701 case WME_AC_VI: 5702 qos_ac = QOS_AC_VI; 5703 break; 5704 case WME_AC_VO: 5705 qos_ac = QOS_AC_VO; 5706 break; 5707 } 5708 5709 return (qos_ac); 5710 } 5711 5712 static uint16_t 5713 iwh_cw_e_to_cw(uint8_t cw_e) 5714 { 5715 uint16_t cw = 1; 5716 5717 while (cw_e > 0) { 5718 cw <<= 1; 5719 cw_e--; 5720 } 5721 5722 cw -= 1; 5723 return (cw); 5724 } 5725 5726 static int 5727 iwh_wmeparam_check(struct wmeParams *wmeparam) 5728 { 5729 int i; 5730 5731 for (i = 0; i < WME_NUM_AC; i++) { 5732 5733 if ((wmeparam[i].wmep_logcwmax > QOS_CW_RANGE_MAX) || 5734 (wmeparam[i].wmep_logcwmin >= wmeparam[i].wmep_logcwmax)) { 5735 cmn_err(CE_WARN, "iwh_wmeparam_check(): " 5736 "Contention window is not in suitable range.\n"); 5737 return (IWH_FAIL); 5738 } 5739 5740 if ((wmeparam[i].wmep_aifsn < QOS_AIFSN_MIN) || 5741 (wmeparam[i].wmep_aifsn > QOS_AIFSN_MAX)) { 5742 cmn_err(CE_WARN, "iwh_wmeparam_check(): " 5743 "Arbitration interframe space number" 5744 "is not in suitable range.\n"); 5745 return (IWH_FAIL); 5746 } 5747 } 5748 5749 return (IWH_SUCCESS); 5750 } 5751 5752 /* 5753 * This function updates EDCA parameters into hardware. 5754 * FIFO0-background, FIFO1-best effort, FIFO2-viedo, FIFO3-voice. 5755 */ 5756 static int 5757 iwh_qosparam_to_hw(iwh_sc_t *sc, int async) 5758 { 5759 ieee80211com_t *ic = &sc->sc_ic; 5760 ieee80211_node_t *in = ic->ic_bss; 5761 struct wmeParams *wmeparam; 5762 iwh_qos_param_cmd_t qosparam_cmd; 5763 int i, j; 5764 int err = IWH_FAIL; 5765 5766 if ((in->in_flags & IEEE80211_NODE_QOS) && 5767 (IEEE80211_M_STA == ic->ic_opmode)) { 5768 wmeparam = ic->ic_wme.wme_chanParams.cap_wmeParams; 5769 } else { 5770 return (IWH_SUCCESS); 5771 } 5772 5773 (void) memset(&qosparam_cmd, 0, sizeof (qosparam_cmd)); 5774 5775 err = iwh_wmeparam_check(wmeparam); 5776 if (err != IWH_SUCCESS) { 5777 return (err); 5778 } 5779 5780 if (in->in_flags & IEEE80211_NODE_QOS) { 5781 qosparam_cmd.flags |= QOS_PARAM_FLG_UPDATE_EDCA; 5782 } 5783 5784 if (in->in_flags & (IEEE80211_NODE_QOS | IEEE80211_NODE_HT)) { 5785 qosparam_cmd.flags |= QOS_PARAM_FLG_TGN; 5786 } 5787 5788 for (i = 0; i < WME_NUM_AC; i++) { 5789 5790 j = iwh_wme_to_qos_ac(i); 5791 if (j < QOS_AC_BK || j > QOS_AC_VO) { 5792 return (IWH_FAIL); 5793 } 5794 5795 qosparam_cmd.ac[j].cw_min = 5796 iwh_cw_e_to_cw(wmeparam[i].wmep_logcwmin); 5797 qosparam_cmd.ac[j].cw_max = 5798 iwh_cw_e_to_cw(wmeparam[i].wmep_logcwmax); 5799 qosparam_cmd.ac[j].aifsn = 5800 wmeparam[i].wmep_aifsn; 5801 qosparam_cmd.ac[j].txop = 5802 (uint16_t)(wmeparam[i].wmep_txopLimit * 32); 5803 } 5804 5805 err = iwh_cmd(sc, REPLY_QOS_PARAM, &qosparam_cmd, 5806 sizeof (qosparam_cmd), async); 5807 if (err != IWH_SUCCESS) { 5808 cmn_err(CE_WARN, "iwh_qosparam_to_hw(): " 5809 "failed to update QoS parameters into hardware.\n"); 5810 return (err); 5811 } 5812 5813 #ifdef DEBUG 5814 IWH_DBG((IWH_DEBUG_QOS, "iwh_qosparam_to_hw(): " 5815 "EDCA parameters are as follows:\n")); 5816 5817 IWH_DBG((IWH_DEBUG_QOS, "BK parameters are: " 5818 "cw_min = %d, cw_max = %d, aifsn = %d, txop = %d\n", 5819 qosparam_cmd.ac[0].cw_min, qosparam_cmd.ac[0].cw_max, 5820 qosparam_cmd.ac[0].aifsn, qosparam_cmd.ac[0].txop)); 5821 5822 IWH_DBG((IWH_DEBUG_QOS, "BE parameters are: " 5823 "cw_min = %d, cw_max = %d, aifsn = %d, txop = %d\n", 5824 qosparam_cmd.ac[1].cw_min, qosparam_cmd.ac[1].cw_max, 5825 qosparam_cmd.ac[1].aifsn, qosparam_cmd.ac[1].txop)); 5826 5827 IWH_DBG((IWH_DEBUG_QOS, "VI parameters are: " 5828 "cw_min = %d, cw_max = %d, aifsn = %d, txop = %d\n", 5829 qosparam_cmd.ac[2].cw_min, qosparam_cmd.ac[2].cw_max, 5830 qosparam_cmd.ac[2].aifsn, qosparam_cmd.ac[2].txop)); 5831 5832 IWH_DBG((IWH_DEBUG_QOS, "VO parameters are: " 5833 "cw_min = %d, cw_max = %d, aifsn = %d, txop = %d\n", 5834 qosparam_cmd.ac[3].cw_min, qosparam_cmd.ac[3].cw_max, 5835 qosparam_cmd.ac[3].aifsn, qosparam_cmd.ac[3].txop)); 5836 #endif 5837 return (err); 5838 } 5839 5840 static inline int 5841 iwh_wme_tid_qos_ac(int tid) 5842 { 5843 switch (tid) { 5844 case 1: 5845 case 2: 5846 return (QOS_AC_BK); 5847 case 0: 5848 case 3: 5849 return (QOS_AC_BE); 5850 case 4: 5851 case 5: 5852 return (QOS_AC_VI); 5853 case 6: 5854 case 7: 5855 return (QOS_AC_VO); 5856 } 5857 5858 return (QOS_AC_BE); 5859 } 5860 5861 static inline int 5862 iwh_qos_ac_to_txq(int qos_ac) 5863 { 5864 switch (qos_ac) { 5865 case QOS_AC_BK: 5866 return (QOS_AC_BK_TO_TXQ); 5867 case QOS_AC_BE: 5868 return (QOS_AC_BE_TO_TXQ); 5869 case QOS_AC_VI: 5870 return (QOS_AC_VI_TO_TXQ); 5871 case QOS_AC_VO: 5872 return (QOS_AC_VO_TO_TXQ); 5873 } 5874 5875 return (QOS_AC_BE_TO_TXQ); 5876 } 5877 5878 static int 5879 iwh_wme_tid_to_txq(int tid) 5880 { 5881 int queue_n = TXQ_FOR_AC_INVALID; 5882 int qos_ac; 5883 5884 if (tid < WME_TID_MIN || 5885 tid > WME_TID_MAX) { 5886 cmn_err(CE_WARN, "wme_tid_to_txq(): " 5887 "TID is not in suitable range.\n"); 5888 return (queue_n); 5889 } 5890 5891 qos_ac = iwh_wme_tid_qos_ac(tid); 5892 queue_n = iwh_qos_ac_to_txq(qos_ac); 5893 5894 return (queue_n); 5895 } 5896 5897 /* 5898 * This function is used for intializing HT relevant configurations. 5899 */ 5900 static void 5901 iwh_init_ht_conf(iwh_sc_t *sc) 5902 { 5903 (void) memset(&sc->sc_ht_conf, 0, sizeof (iwh_ht_conf_t)); 5904 5905 if ((0x4235 == sc->sc_dev_id) || 5906 (0x4236 == sc->sc_dev_id) || 5907 (0x423a == sc->sc_dev_id)) { 5908 sc->sc_ht_conf.ht_support = 1; 5909 5910 sc->sc_ht_conf.valid_chains = 3; 5911 sc->sc_ht_conf.tx_stream_count = 2; 5912 sc->sc_ht_conf.rx_stream_count = 2; 5913 5914 sc->sc_ht_conf.tx_support_mcs[0] = 0xff; 5915 sc->sc_ht_conf.tx_support_mcs[1] = 0xff; 5916 sc->sc_ht_conf.rx_support_mcs[0] = 0xff; 5917 sc->sc_ht_conf.rx_support_mcs[1] = 0xff; 5918 } else { 5919 sc->sc_ht_conf.ht_support = 1; 5920 5921 sc->sc_ht_conf.valid_chains = 2; 5922 sc->sc_ht_conf.tx_stream_count = 1; 5923 sc->sc_ht_conf.rx_stream_count = 2; 5924 5925 sc->sc_ht_conf.tx_support_mcs[0] = 0xff; 5926 sc->sc_ht_conf.rx_support_mcs[0] = 0xff; 5927 sc->sc_ht_conf.rx_support_mcs[1] = 0xff; 5928 } 5929 5930 if (sc->sc_ht_conf.ht_support) { 5931 sc->sc_ht_conf.cap |= HT_CAP_GRN_FLD; 5932 sc->sc_ht_conf.cap |= HT_CAP_SGI_20; 5933 sc->sc_ht_conf.cap |= HT_CAP_MAX_AMSDU; 5934 /* should disable MIMO */ 5935 sc->sc_ht_conf.cap |= HT_CAP_MIMO_PS; 5936 5937 sc->sc_ht_conf.ampdu_p.factor = HT_RX_AMPDU_FACTOR; 5938 sc->sc_ht_conf.ampdu_p.density = HT_MPDU_DENSITY; 5939 5940 sc->sc_ht_conf.ht_protection = HT_PROT_CHAN_NON_HT; 5941 } 5942 } 5943 5944 /* 5945 * This function overwrites default ieee80211_rateset_11n struc. 5946 */ 5947 static void 5948 iwh_overwrite_11n_rateset(iwh_sc_t *sc) 5949 { 5950 uint8_t *ht_rs = sc->sc_ht_conf.rx_support_mcs; 5951 int mcs_idx, mcs_count = 0; 5952 int i, j; 5953 5954 for (i = 0; i < HT_RATESET_NUM; i++) { 5955 for (j = 0; j < 8; j++) { 5956 if (ht_rs[i] & (1 << j)) { 5957 mcs_idx = i * 8 + j; 5958 if (mcs_idx >= IEEE80211_HTRATE_MAXSIZE) { 5959 break; 5960 } 5961 5962 ieee80211_rateset_11n.rs_rates[mcs_idx] = 5963 (uint8_t)mcs_idx; 5964 mcs_count++; 5965 } 5966 } 5967 } 5968 5969 ieee80211_rateset_11n.rs_nrates = (uint8_t)mcs_count; 5970 5971 #ifdef DEBUG 5972 IWH_DBG((IWH_DEBUG_HTRATE, "iwh_overwrite_11n_rateset(): " 5973 "HT rates supported by this station is as follows:\n")); 5974 5975 for (i = 0; i < ieee80211_rateset_11n.rs_nrates; i++) { 5976 IWH_DBG((IWH_DEBUG_HTRATE, "Rate %d is %d\n", 5977 i, ieee80211_rateset_11n.rs_rates[i])); 5978 } 5979 #endif 5980 } 5981 5982 /* 5983 * This function overwrites default configurations of 5984 * ieee80211com structure in Net80211 module. 5985 */ 5986 static void 5987 iwh_overwrite_ic_default(iwh_sc_t *sc) 5988 { 5989 ieee80211com_t *ic = &sc->sc_ic; 5990 5991 sc->sc_newstate = ic->ic_newstate; 5992 ic->ic_newstate = iwh_newstate; 5993 ic->ic_node_alloc = iwh_node_alloc; 5994 ic->ic_node_free = iwh_node_free; 5995 5996 if (sc->sc_ht_conf.ht_support) { 5997 sc->sc_recv_action = ic->ic_recv_action; 5998 ic->ic_recv_action = iwh_recv_action; 5999 sc->sc_send_action = ic->ic_send_action; 6000 ic->ic_send_action = iwh_send_action; 6001 6002 ic->ic_ampdu_rxmax = sc->sc_ht_conf.ampdu_p.factor; 6003 ic->ic_ampdu_density = sc->sc_ht_conf.ampdu_p.density; 6004 ic->ic_ampdu_limit = ic->ic_ampdu_rxmax; 6005 } 6006 } 6007 6008 /* 6009 * This function sets "RX chain selection" feild 6010 * in RXON command during plumb driver. 6011 */ 6012 static void 6013 iwh_config_rxon_chain(iwh_sc_t *sc) 6014 { 6015 ieee80211com_t *ic = &sc->sc_ic; 6016 ieee80211_node_t *in = ic->ic_bss; 6017 6018 if (3 == sc->sc_ht_conf.valid_chains) { 6019 sc->sc_config.rx_chain = LE_16((RXON_RX_CHAIN_A_MSK | 6020 RXON_RX_CHAIN_B_MSK | RXON_RX_CHAIN_C_MSK) << 6021 RXON_RX_CHAIN_VALID_POS); 6022 6023 sc->sc_config.rx_chain |= LE_16((RXON_RX_CHAIN_A_MSK | 6024 RXON_RX_CHAIN_B_MSK | RXON_RX_CHAIN_C_MSK) << 6025 RXON_RX_CHAIN_FORCE_SEL_POS); 6026 6027 sc->sc_config.rx_chain |= LE_16((RXON_RX_CHAIN_A_MSK | 6028 RXON_RX_CHAIN_B_MSK | RXON_RX_CHAIN_C_MSK) << 6029 RXON_RX_CHAIN_FORCE_MIMO_SEL_POS); 6030 } else { 6031 sc->sc_config.rx_chain = LE_16((RXON_RX_CHAIN_A_MSK | 6032 RXON_RX_CHAIN_B_MSK) << RXON_RX_CHAIN_VALID_POS); 6033 6034 sc->sc_config.rx_chain |= LE_16((RXON_RX_CHAIN_A_MSK | 6035 RXON_RX_CHAIN_B_MSK) << RXON_RX_CHAIN_FORCE_SEL_POS); 6036 6037 sc->sc_config.rx_chain |= LE_16((RXON_RX_CHAIN_A_MSK | 6038 RXON_RX_CHAIN_B_MSK) << 6039 RXON_RX_CHAIN_FORCE_MIMO_SEL_POS); 6040 } 6041 6042 sc->sc_config.rx_chain |= LE_16(RXON_RX_CHAIN_DRIVER_FORCE_MSK); 6043 6044 if ((in != NULL) && 6045 (in->in_flags & IEEE80211_NODE_HT) && 6046 sc->sc_ht_conf.ht_support) { 6047 if (3 == sc->sc_ht_conf.valid_chains) { 6048 sc->sc_config.rx_chain |= LE_16(3 << 6049 RXON_RX_CHAIN_CNT_POS); 6050 sc->sc_config.rx_chain |= LE_16(3 << 6051 RXON_RX_CHAIN_MIMO_CNT_POS); 6052 } else { 6053 sc->sc_config.rx_chain |= LE_16(2 << 6054 RXON_RX_CHAIN_CNT_POS); 6055 sc->sc_config.rx_chain |= LE_16(2 << 6056 RXON_RX_CHAIN_MIMO_CNT_POS); 6057 } 6058 6059 sc->sc_config.rx_chain |= LE_16(1 << 6060 RXON_RX_CHAIN_MIMO_FORCE_POS); 6061 } 6062 6063 IWH_DBG((IWH_DEBUG_RXON, "iwh_config_rxon_chain(): " 6064 "rxon->rx_chain = %x\n", sc->sc_config.rx_chain)); 6065 } 6066 6067 /* 6068 * This function adds AP station into hardware. 6069 */ 6070 static int 6071 iwh_add_ap_sta(iwh_sc_t *sc) 6072 { 6073 ieee80211com_t *ic = &sc->sc_ic; 6074 ieee80211_node_t *in = ic->ic_bss; 6075 iwh_add_sta_t node; 6076 uint32_t ampdu_factor, ampdu_density; 6077 int err = IWH_FAIL; 6078 6079 /* 6080 * Add AP node into hardware. 6081 */ 6082 (void) memset(&node, 0, sizeof (node)); 6083 IEEE80211_ADDR_COPY(node.sta.addr, in->in_bssid); 6084 node.mode = STA_MODE_ADD_MSK; 6085 node.sta.sta_id = IWH_AP_ID; 6086 6087 if (sc->sc_ht_conf.ht_support && 6088 (in->in_htcap_ie != NULL) && 6089 (in->in_htcap != 0) && 6090 (in->in_htparam != 0)) { 6091 6092 if (((in->in_htcap & HT_CAP_MIMO_PS) >> 2) 6093 == HT_CAP_MIMO_PS_DYNAMIC) { 6094 node.station_flags |= LE_32(STA_FLG_RTS_MIMO_PROT); 6095 } 6096 6097 ampdu_factor = in->in_htparam & HT_RX_AMPDU_FACTOR_MSK; 6098 node.station_flags |= 6099 LE_32(ampdu_factor << STA_FLG_MAX_AMPDU_POS); 6100 6101 ampdu_density = (in->in_htparam & HT_MPDU_DENSITY_MSK) >> 6102 HT_MPDU_DENSITY_POS; 6103 node.station_flags |= 6104 LE_32(ampdu_density << STA_FLG_AMPDU_DENSITY_POS); 6105 6106 if (in->in_htcap & LE_16(HT_CAP_SUP_WIDTH)) { 6107 node.station_flags |= 6108 LE_32(STA_FLG_FAT_EN); 6109 } 6110 } 6111 6112 err = iwh_cmd(sc, REPLY_ADD_STA, &node, sizeof (node), 1); 6113 if (err != IWH_SUCCESS) { 6114 cmn_err(CE_WARN, "iwh_add_ap_lq(): " 6115 "failed to add AP node\n"); 6116 return (err); 6117 } 6118 6119 return (err); 6120 } 6121 6122 /* 6123 * Each station in the Shirley Peak's internal station table has 6124 * its own table of 16 TX rates and modulation modes for retrying 6125 * TX when an ACK is not received. This function replaces the entire 6126 * table for one station.Station must already be in Shirley Peak's 6127 * station talbe. 6128 */ 6129 static int 6130 iwh_ap_lq(iwh_sc_t *sc) 6131 { 6132 ieee80211com_t *ic = &sc->sc_ic; 6133 ieee80211_node_t *in = ic->ic_bss; 6134 iwh_link_quality_cmd_t link_quality; 6135 const struct ieee80211_rateset *rs_sup = NULL; 6136 uint32_t masks = 0, rate; 6137 int i, err = IWH_FAIL; 6138 6139 /* 6140 * TX_LINK_QUALITY cmd 6141 */ 6142 (void) memset(&link_quality, 0, sizeof (link_quality)); 6143 if (in->in_chan == IEEE80211_CHAN_ANYC) /* skip null node */ 6144 return (err); 6145 rs_sup = ieee80211_get_suprates(ic, in->in_chan); 6146 6147 for (i = 0; i < LINK_QUAL_MAX_RETRY_NUM; i++) { 6148 if (i < rs_sup->ir_nrates) { 6149 rate = rs_sup->ir_rates[rs_sup->ir_nrates - i] & 6150 IEEE80211_RATE_VAL; 6151 } else { 6152 rate = 2; 6153 } 6154 6155 if (2 == rate || 4 == rate || 6156 11 == rate || 22 == rate) { 6157 masks |= LE_32(RATE_MCS_CCK_MSK); 6158 } 6159 6160 masks |= LE_32(RATE_MCS_ANT_B_MSK); 6161 6162 link_quality.rate_n_flags[i] = 6163 LE_32(iwh_rate_to_plcp(rate) | masks); 6164 } 6165 6166 link_quality.general_params.single_stream_ant_msk = LINK_QUAL_ANT_B_MSK; 6167 link_quality.general_params.dual_stream_ant_msk = LINK_QUAL_ANT_MSK; 6168 link_quality.agg_params.agg_dis_start_th = 3; 6169 link_quality.agg_params.agg_time_limit = LE_16(4000); 6170 link_quality.sta_id = IWH_AP_ID; 6171 err = iwh_cmd(sc, REPLY_TX_LINK_QUALITY_CMD, &link_quality, 6172 sizeof (link_quality), 1); 6173 if (err != IWH_SUCCESS) { 6174 cmn_err(CE_WARN, "iwh_ap_lq(): " 6175 "failed to config link quality table\n"); 6176 return (err); 6177 } 6178 6179 #ifdef DEBUG 6180 IWH_DBG((IWH_DEBUG_HWRATE, "iwh_ap_lq(): " 6181 "Rates in HW are as follows:\n")); 6182 6183 for (i = 0; i < LINK_QUAL_MAX_RETRY_NUM; i++) { 6184 IWH_DBG((IWH_DEBUG_HWRATE, 6185 "Rate %d in HW is %x\n", i, link_quality.rate_n_flags[i])); 6186 } 6187 #endif 6188 6189 return (err); 6190 } 6191 6192 /* 6193 * When block ACK agreement has been set up between station and AP, 6194 * Net80211 module will call this function to inform hardware about 6195 * informations of this BA agreement. 6196 * When AP wants to delete BA agreement that was originated by it, 6197 * Net80211 modele will call this function to clean up relevant 6198 * information in hardware. 6199 */ 6200 static void 6201 iwh_recv_action(struct ieee80211_node *in, 6202 const uint8_t *frm, const uint8_t *efrm) 6203 { 6204 struct ieee80211com *ic; 6205 iwh_sc_t *sc; 6206 const struct ieee80211_action *ia; 6207 uint16_t baparamset, baseqctl; 6208 uint32_t tid, ssn; 6209 iwh_add_sta_t node; 6210 int err = IWH_FAIL; 6211 6212 if ((NULL == in) || (NULL == frm)) { 6213 return; 6214 } 6215 6216 ic = in->in_ic; 6217 if (NULL == ic) { 6218 return; 6219 } 6220 6221 sc = (iwh_sc_t *)ic; 6222 6223 sc->sc_recv_action(in, frm, efrm); 6224 6225 ia = (const struct ieee80211_action *)frm; 6226 if (ia->ia_category != IEEE80211_ACTION_CAT_BA) { 6227 return; 6228 } 6229 6230 switch (ia->ia_action) { 6231 case IEEE80211_ACTION_BA_ADDBA_REQUEST: 6232 baparamset = *(uint16_t *)(frm + 3); 6233 baseqctl = *(uint16_t *)(frm + 7); 6234 6235 tid = MS(baparamset, IEEE80211_BAPS_TID); 6236 ssn = MS(baseqctl, IEEE80211_BASEQ_START); 6237 6238 (void) memset(&node, 0, sizeof (node)); 6239 IEEE80211_ADDR_COPY(node.sta.addr, in->in_bssid); 6240 node.mode = STA_MODE_MODIFY_MSK; 6241 node.sta.sta_id = IWH_AP_ID; 6242 6243 node.station_flags_msk = 0; 6244 node.sta.modify_mask = STA_MODIFY_ADDBA_TID_MSK; 6245 node.add_immediate_ba_tid = (uint8_t)tid; 6246 node.add_immediate_ba_ssn = LE_16(ssn); 6247 6248 mutex_enter(&sc->sc_glock); 6249 err = iwh_cmd(sc, REPLY_ADD_STA, &node, sizeof (node), 1); 6250 if (err != IWH_SUCCESS) { 6251 cmn_err(CE_WARN, "iwh_recv_action(): " 6252 "failed to setup RX block ACK\n"); 6253 mutex_exit(&sc->sc_glock); 6254 return; 6255 } 6256 mutex_exit(&sc->sc_glock); 6257 6258 IWH_DBG((IWH_DEBUG_BA, "iwh_recv_action(): " 6259 "RX block ACK " 6260 "was setup on TID %d and SSN is %d.\n", tid, ssn)); 6261 6262 return; 6263 6264 case IEEE80211_ACTION_BA_DELBA: 6265 baparamset = *(uint16_t *)(frm + 2); 6266 6267 if ((baparamset & IEEE80211_DELBAPS_INIT) == 0) { 6268 return; 6269 } 6270 6271 tid = MS(baparamset, IEEE80211_DELBAPS_TID); 6272 6273 (void) memset(&node, 0, sizeof (node)); 6274 IEEE80211_ADDR_COPY(node.sta.addr, in->in_bssid); 6275 node.mode = STA_MODE_MODIFY_MSK; 6276 node.sta.sta_id = IWH_AP_ID; 6277 6278 node.station_flags_msk = 0; 6279 node.sta.modify_mask = STA_MODIFY_DELBA_TID_MSK; 6280 node.add_immediate_ba_tid = (uint8_t)tid; 6281 6282 mutex_enter(&sc->sc_glock); 6283 err = iwh_cmd(sc, REPLY_ADD_STA, &node, sizeof (node), 1); 6284 if (err != IWH_SUCCESS) { 6285 cmn_err(CE_WARN, "iwh_recv_action(): " 6286 "failed to delete RX block ACK\n"); 6287 mutex_exit(&sc->sc_glock); 6288 return; 6289 } 6290 mutex_exit(&sc->sc_glock); 6291 6292 IWH_DBG((IWH_DEBUG_BA, "iwh_recv_action(): " 6293 "RX block ACK " 6294 "was deleted on TID %d.\n", tid)); 6295 6296 return; 6297 } 6298 } 6299 6300 /* 6301 * When local station wants to delete BA agreement that was originated by AP, 6302 * Net80211 module will call this function to clean up relevant information 6303 * in hardware. 6304 */ 6305 static int 6306 iwh_send_action(struct ieee80211_node *in, 6307 int category, int action, uint16_t args[4]) 6308 { 6309 struct ieee80211com *ic; 6310 iwh_sc_t *sc; 6311 uint32_t tid; 6312 iwh_add_sta_t node; 6313 int ret = EIO; 6314 int err = IWH_FAIL; 6315 6316 6317 if (NULL == in) { 6318 return (ret); 6319 } 6320 6321 ic = in->in_ic; 6322 if (NULL == ic) { 6323 return (ret); 6324 } 6325 6326 sc = (iwh_sc_t *)ic; 6327 6328 ret = sc->sc_send_action(in, category, action, args); 6329 6330 if (category != IEEE80211_ACTION_CAT_BA) { 6331 return (ret); 6332 } 6333 6334 switch (action) { 6335 case IEEE80211_ACTION_BA_DELBA: 6336 if (IEEE80211_DELBAPS_INIT == args[1]) { 6337 return (ret); 6338 } 6339 6340 tid = args[0]; 6341 6342 (void) memset(&node, 0, sizeof (node)); 6343 IEEE80211_ADDR_COPY(node.sta.addr, in->in_bssid); 6344 node.mode = STA_MODE_MODIFY_MSK; 6345 node.sta.sta_id = IWH_AP_ID; 6346 6347 node.station_flags_msk = 0; 6348 node.sta.modify_mask = STA_MODIFY_DELBA_TID_MSK; 6349 node.add_immediate_ba_tid = (uint8_t)tid; 6350 6351 mutex_enter(&sc->sc_glock); 6352 err = iwh_cmd(sc, REPLY_ADD_STA, &node, sizeof (node), 1); 6353 if (err != IWH_SUCCESS) { 6354 cmn_err(CE_WARN, "iwh_send_action(): " 6355 "failed to delete RX balock ACK\n"); 6356 mutex_exit(&sc->sc_glock); 6357 return (EIO); 6358 } 6359 mutex_exit(&sc->sc_glock); 6360 6361 IWH_DBG((IWH_DEBUG_BA, "iwh_send_action(): " 6362 "RX block ACK " 6363 "was deleted on TID %d.\n", tid)); 6364 6365 break; 6366 } 6367 6368 return (ret); 6369 } 6370