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