1 /*
   2  * Copyright 2010 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 6000 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/varargs.h>
  56 #include <sys/policy.h>
  57 #include <sys/pci.h>
  58 
  59 #include "iwp_calibration.h"
  60 #include "iwp_hw.h"
  61 #include "iwp_eeprom.h"
  62 #include "iwp_var.h"
  63 #include <inet/wifi_ioctl.h>
  64 
  65 #ifdef DEBUG
  66 #define IWP_DEBUG_80211         (1 << 0)
  67 #define IWP_DEBUG_CMD           (1 << 1)
  68 #define IWP_DEBUG_DMA           (1 << 2)
  69 #define IWP_DEBUG_EEPROM        (1 << 3)
  70 #define IWP_DEBUG_FW            (1 << 4)
  71 #define IWP_DEBUG_HW            (1 << 5)
  72 #define IWP_DEBUG_INTR          (1 << 6)
  73 #define IWP_DEBUG_MRR           (1 << 7)
  74 #define IWP_DEBUG_PIO           (1 << 8)
  75 #define IWP_DEBUG_RX            (1 << 9)
  76 #define IWP_DEBUG_SCAN          (1 << 10)
  77 #define IWP_DEBUG_TX            (1 << 11)
  78 #define IWP_DEBUG_RATECTL       (1 << 12)
  79 #define IWP_DEBUG_RADIO         (1 << 13)
  80 #define IWP_DEBUG_RESUME        (1 << 14)
  81 #define IWP_DEBUG_CALIBRATION   (1 << 15)
  82 /*
  83  * if want to see debug message of a given section,
  84  * please set this flag to one of above values
  85  */
  86 uint32_t iwp_dbg_flags = 0;
  87 #define IWP_DBG(x) \
  88         iwp_dbg x
  89 #else
  90 #define IWP_DBG(x)
  91 #endif
  92 
  93 static void     *iwp_soft_state_p = NULL;
  94 
  95 /*
  96  * ucode will be compiled into driver image
  97  */
  98 static uint8_t iwp_fw_bin [] = {
  99 #include "fw-iw/iwp.ucode"
 100 };
 101 
 102 /*
 103  * DMA attributes for a shared page
 104  */
 105 static ddi_dma_attr_t sh_dma_attr = {
 106         DMA_ATTR_V0,    /* version of this structure */
 107         0,              /* lowest usable address */
 108         0xffffffffU,    /* highest usable address */
 109         0xffffffffU,    /* maximum DMAable byte count */
 110         0x1000,         /* alignment in bytes */
 111         0x1000,         /* burst sizes (any?) */
 112         1,              /* minimum transfer */
 113         0xffffffffU,    /* maximum transfer */
 114         0xffffffffU,    /* maximum segment length */
 115         1,              /* maximum number of segments */
 116         1,              /* granularity */
 117         0,              /* flags (reserved) */
 118 };
 119 
 120 /*
 121  * DMA attributes for a keep warm DRAM descriptor
 122  */
 123 static ddi_dma_attr_t kw_dma_attr = {
 124         DMA_ATTR_V0,    /* version of this structure */
 125         0,              /* lowest usable address */
 126         0xffffffffU,    /* highest usable address */
 127         0xffffffffU,    /* maximum DMAable byte count */
 128         0x1000,         /* alignment in bytes */
 129         0x1000,         /* burst sizes (any?) */
 130         1,              /* minimum transfer */
 131         0xffffffffU,    /* maximum transfer */
 132         0xffffffffU,    /* maximum segment length */
 133         1,              /* maximum number of segments */
 134         1,              /* granularity */
 135         0,              /* flags (reserved) */
 136 };
 137 
 138 /*
 139  * DMA attributes for a ring descriptor
 140  */
 141 static ddi_dma_attr_t ring_desc_dma_attr = {
 142         DMA_ATTR_V0,    /* version of this structure */
 143         0,              /* lowest usable address */
 144         0xffffffffU,    /* highest usable address */
 145         0xffffffffU,    /* maximum DMAable byte count */
 146         0x100,          /* alignment in bytes */
 147         0x100,          /* burst sizes (any?) */
 148         1,              /* minimum transfer */
 149         0xffffffffU,    /* maximum transfer */
 150         0xffffffffU,    /* maximum segment length */
 151         1,              /* maximum number of segments */
 152         1,              /* granularity */
 153         0,              /* flags (reserved) */
 154 };
 155 
 156 /*
 157  * DMA attributes for a cmd
 158  */
 159 static ddi_dma_attr_t cmd_dma_attr = {
 160         DMA_ATTR_V0,    /* version of this structure */
 161         0,              /* lowest usable address */
 162         0xffffffffU,    /* highest usable address */
 163         0xffffffffU,    /* maximum DMAable byte count */
 164         4,              /* alignment in bytes */
 165         0x100,          /* burst sizes (any?) */
 166         1,              /* minimum transfer */
 167         0xffffffffU,    /* maximum transfer */
 168         0xffffffffU,    /* maximum segment length */
 169         1,              /* maximum number of segments */
 170         1,              /* granularity */
 171         0,              /* flags (reserved) */
 172 };
 173 
 174 /*
 175  * DMA attributes for a rx buffer
 176  */
 177 static ddi_dma_attr_t rx_buffer_dma_attr = {
 178         DMA_ATTR_V0,    /* version of this structure */
 179         0,              /* lowest usable address */
 180         0xffffffffU,    /* highest usable address */
 181         0xffffffffU,    /* maximum DMAable byte count */
 182         0x100,          /* alignment in bytes */
 183         0x100,          /* burst sizes (any?) */
 184         1,              /* minimum transfer */
 185         0xffffffffU,    /* maximum transfer */
 186         0xffffffffU,    /* maximum segment length */
 187         1,              /* maximum number of segments */
 188         1,              /* granularity */
 189         0,              /* flags (reserved) */
 190 };
 191 
 192 /*
 193  * DMA attributes for a tx buffer.
 194  * the maximum number of segments is 4 for the hardware.
 195  * now all the wifi drivers put the whole frame in a single
 196  * descriptor, so we define the maximum  number of segments 1,
 197  * just the same as the rx_buffer. we consider leverage the HW
 198  * ability in the future, that is why we don't define rx and tx
 199  * buffer_dma_attr as the same.
 200  */
 201 static ddi_dma_attr_t tx_buffer_dma_attr = {
 202         DMA_ATTR_V0,    /* version of this structure */
 203         0,              /* lowest usable address */
 204         0xffffffffU,    /* highest usable address */
 205         0xffffffffU,    /* maximum DMAable byte count */
 206         4,              /* alignment in bytes */
 207         0x100,          /* burst sizes (any?) */
 208         1,              /* minimum transfer */
 209         0xffffffffU,    /* maximum transfer */
 210         0xffffffffU,    /* maximum segment length */
 211         1,              /* maximum number of segments */
 212         1,              /* granularity */
 213         0,              /* flags (reserved) */
 214 };
 215 
 216 /*
 217  * DMA attributes for text and data part in the firmware
 218  */
 219 static ddi_dma_attr_t fw_dma_attr = {
 220         DMA_ATTR_V0,    /* version of this structure */
 221         0,              /* lowest usable address */
 222         0xffffffffU,    /* highest usable address */
 223         0x7fffffff,     /* maximum DMAable byte count */
 224         0x10,           /* alignment in bytes */
 225         0x100,          /* burst sizes (any?) */
 226         1,              /* minimum transfer */
 227         0xffffffffU,    /* maximum transfer */
 228         0xffffffffU,    /* maximum segment length */
 229         1,              /* maximum number of segments */
 230         1,              /* granularity */
 231         0,              /* flags (reserved) */
 232 };
 233 
 234 /*
 235  * regs access attributes
 236  */
 237 static ddi_device_acc_attr_t iwp_reg_accattr = {
 238         DDI_DEVICE_ATTR_V0,
 239         DDI_STRUCTURE_LE_ACC,
 240         DDI_STRICTORDER_ACC,
 241         DDI_DEFAULT_ACC
 242 };
 243 
 244 /*
 245  * DMA access attributes for descriptor
 246  */
 247 static ddi_device_acc_attr_t iwp_dma_descattr = {
 248         DDI_DEVICE_ATTR_V0,
 249         DDI_STRUCTURE_LE_ACC,
 250         DDI_STRICTORDER_ACC,
 251         DDI_DEFAULT_ACC
 252 };
 253 
 254 /*
 255  * DMA access attributes
 256  */
 257 static ddi_device_acc_attr_t iwp_dma_accattr = {
 258         DDI_DEVICE_ATTR_V0,
 259         DDI_NEVERSWAP_ACC,
 260         DDI_STRICTORDER_ACC,
 261         DDI_DEFAULT_ACC
 262 };
 263 
 264 static int      iwp_ring_init(iwp_sc_t *);
 265 static void     iwp_ring_free(iwp_sc_t *);
 266 static int      iwp_alloc_shared(iwp_sc_t *);
 267 static void     iwp_free_shared(iwp_sc_t *);
 268 static int      iwp_alloc_kw(iwp_sc_t *);
 269 static void     iwp_free_kw(iwp_sc_t *);
 270 static int      iwp_alloc_fw_dma(iwp_sc_t *);
 271 static void     iwp_free_fw_dma(iwp_sc_t *);
 272 static int      iwp_alloc_rx_ring(iwp_sc_t *);
 273 static void     iwp_reset_rx_ring(iwp_sc_t *);
 274 static void     iwp_free_rx_ring(iwp_sc_t *);
 275 static int      iwp_alloc_tx_ring(iwp_sc_t *, iwp_tx_ring_t *,
 276     int, int);
 277 static void     iwp_reset_tx_ring(iwp_sc_t *, iwp_tx_ring_t *);
 278 static void     iwp_free_tx_ring(iwp_tx_ring_t *);
 279 static ieee80211_node_t *iwp_node_alloc(ieee80211com_t *);
 280 static void     iwp_node_free(ieee80211_node_t *);
 281 static int      iwp_newstate(ieee80211com_t *, enum ieee80211_state, int);
 282 static void     iwp_mac_access_enter(iwp_sc_t *);
 283 static void     iwp_mac_access_exit(iwp_sc_t *);
 284 static uint32_t iwp_reg_read(iwp_sc_t *, uint32_t);
 285 static void     iwp_reg_write(iwp_sc_t *, uint32_t, uint32_t);
 286 static int      iwp_load_init_firmware(iwp_sc_t *);
 287 static int      iwp_load_run_firmware(iwp_sc_t *);
 288 static void     iwp_tx_intr(iwp_sc_t *, iwp_rx_desc_t *);
 289 static void     iwp_cmd_intr(iwp_sc_t *, iwp_rx_desc_t *);
 290 static uint_t   iwp_intr(caddr_t, caddr_t);
 291 static int      iwp_eep_load(iwp_sc_t *);
 292 static void     iwp_get_mac_from_eep(iwp_sc_t *);
 293 static int      iwp_eep_sem_down(iwp_sc_t *);
 294 static void     iwp_eep_sem_up(iwp_sc_t *);
 295 static uint_t   iwp_rx_softintr(caddr_t, caddr_t);
 296 static uint8_t  iwp_rate_to_plcp(int);
 297 static int      iwp_cmd(iwp_sc_t *, int, const void *, int, int);
 298 static void     iwp_set_led(iwp_sc_t *, uint8_t, uint8_t, uint8_t);
 299 static int      iwp_hw_set_before_auth(iwp_sc_t *);
 300 static int      iwp_scan(iwp_sc_t *);
 301 static int      iwp_config(iwp_sc_t *);
 302 static void     iwp_stop_master(iwp_sc_t *);
 303 static int      iwp_power_up(iwp_sc_t *);
 304 static int      iwp_preinit(iwp_sc_t *);
 305 static int      iwp_init(iwp_sc_t *);
 306 static void     iwp_stop(iwp_sc_t *);
 307 static int      iwp_quiesce(dev_info_t *t);
 308 static void     iwp_amrr_init(iwp_amrr_t *);
 309 static void     iwp_amrr_timeout(iwp_sc_t *);
 310 static void     iwp_amrr_ratectl(void *, ieee80211_node_t *);
 311 static void     iwp_ucode_alive(iwp_sc_t *, iwp_rx_desc_t *);
 312 static void     iwp_rx_phy_intr(iwp_sc_t *, iwp_rx_desc_t *);
 313 static void     iwp_rx_mpdu_intr(iwp_sc_t *, iwp_rx_desc_t *);
 314 static void     iwp_release_calib_buffer(iwp_sc_t *);
 315 static int      iwp_init_common(iwp_sc_t *);
 316 static uint8_t  *iwp_eep_addr_trans(iwp_sc_t *, uint32_t);
 317 static int      iwp_put_seg_fw(iwp_sc_t *, uint32_t, uint32_t, uint32_t);
 318 static  int     iwp_alive_common(iwp_sc_t *);
 319 static void     iwp_save_calib_result(iwp_sc_t *, iwp_rx_desc_t *);
 320 static int      iwp_attach(dev_info_t *, ddi_attach_cmd_t);
 321 static int      iwp_detach(dev_info_t *, ddi_detach_cmd_t);
 322 static void     iwp_destroy_locks(iwp_sc_t *);
 323 static int      iwp_send(ieee80211com_t *, mblk_t *, uint8_t);
 324 static void     iwp_thread(iwp_sc_t *);
 325 static int      iwp_run_state_config(iwp_sc_t *);
 326 static int      iwp_fast_recover(iwp_sc_t *);
 327 static void     iwp_overwrite_ic_default(iwp_sc_t *);
 328 static int      iwp_add_ap_sta(iwp_sc_t *);
 329 static int      iwp_alloc_dma_mem(iwp_sc_t *, size_t,
 330     ddi_dma_attr_t *, ddi_device_acc_attr_t *,
 331     uint_t, iwp_dma_t *);
 332 static void     iwp_free_dma_mem(iwp_dma_t *);
 333 static int      iwp_eep_ver_chk(iwp_sc_t *);
 334 static void     iwp_set_chip_param(iwp_sc_t *);
 335 
 336 /*
 337  * GLD specific operations
 338  */
 339 static int      iwp_m_stat(void *, uint_t, uint64_t *);
 340 static int      iwp_m_start(void *);
 341 static void     iwp_m_stop(void *);
 342 static int      iwp_m_unicst(void *, const uint8_t *);
 343 static int      iwp_m_multicst(void *, boolean_t, const uint8_t *);
 344 static int      iwp_m_promisc(void *, boolean_t);
 345 static mblk_t   *iwp_m_tx(void *, mblk_t *);
 346 static void     iwp_m_ioctl(void *, queue_t *, mblk_t *);
 347 static int      iwp_m_setprop(void *arg, const char *pr_name,
 348     mac_prop_id_t wldp_pr_num, uint_t wldp_length, const void *wldp_buf);
 349 static int      iwp_m_getprop(void *arg, const char *pr_name,
 350     mac_prop_id_t wldp_pr_num, uint_t wldp_length, void *wldp_buf);
 351 static void     iwp_m_propinfo(void *, const char *, mac_prop_id_t,
 352     mac_prop_info_handle_t);
 353 
 354 /*
 355  * Supported rates for 802.11b/g modes (in 500Kbps unit).
 356  */
 357 static const struct ieee80211_rateset iwp_rateset_11b =
 358         { 4, { 2, 4, 11, 22 } };
 359 
 360 static const struct ieee80211_rateset iwp_rateset_11g =
 361         { 12, { 2, 4, 11, 22, 12, 18, 24, 36, 48, 72, 96, 108 } };
 362 
 363 /*
 364  * For mfthread only
 365  */
 366 extern pri_t minclsyspri;
 367 
 368 #define DRV_NAME_SP     "iwp"
 369 
 370 /*
 371  * Module Loading Data & Entry Points
 372  */
 373 DDI_DEFINE_STREAM_OPS(iwp_devops, nulldev, nulldev, iwp_attach,
 374     iwp_detach, nodev, NULL, D_MP, NULL, iwp_quiesce);
 375 
 376 static struct modldrv iwp_modldrv = {
 377         &mod_driverops,
 378         "Intel(R) PumaPeak driver(N)",
 379         &iwp_devops
 380 };
 381 
 382 static struct modlinkage iwp_modlinkage = {
 383         MODREV_1,
 384         { &iwp_modldrv, NULL }
 385 };
 386 
 387 int
 388 _init(void)
 389 {
 390         int     status;
 391 
 392         status = ddi_soft_state_init(&iwp_soft_state_p,
 393             sizeof (iwp_sc_t), 1);
 394         if (status != DDI_SUCCESS) {
 395                 return (status);
 396         }
 397 
 398         mac_init_ops(&iwp_devops, DRV_NAME_SP);
 399         status = mod_install(&iwp_modlinkage);
 400         if (status != DDI_SUCCESS) {
 401                 mac_fini_ops(&iwp_devops);
 402                 ddi_soft_state_fini(&iwp_soft_state_p);
 403         }
 404 
 405         return (status);
 406 }
 407 
 408 int
 409 _fini(void)
 410 {
 411         int status;
 412 
 413         status = mod_remove(&iwp_modlinkage);
 414         if (DDI_SUCCESS == status) {
 415                 mac_fini_ops(&iwp_devops);
 416                 ddi_soft_state_fini(&iwp_soft_state_p);
 417         }
 418 
 419         return (status);
 420 }
 421 
 422 int
 423 _info(struct modinfo *mip)
 424 {
 425         return (mod_info(&iwp_modlinkage, mip));
 426 }
 427 
 428 /*
 429  * Mac Call Back entries
 430  */
 431 mac_callbacks_t iwp_m_callbacks = {
 432         MC_IOCTL | MC_SETPROP | MC_GETPROP | MC_PROPINFO,
 433         iwp_m_stat,
 434         iwp_m_start,
 435         iwp_m_stop,
 436         iwp_m_promisc,
 437         iwp_m_multicst,
 438         iwp_m_unicst,
 439         iwp_m_tx,
 440         NULL,
 441         iwp_m_ioctl,
 442         NULL,
 443         NULL,
 444         NULL,
 445         iwp_m_setprop,
 446         iwp_m_getprop,
 447         iwp_m_propinfo
 448 };
 449 
 450 #ifdef DEBUG
 451 void
 452 iwp_dbg(uint32_t flags, const char *fmt, ...)
 453 {
 454         va_list ap;
 455 
 456         if (flags & iwp_dbg_flags) {
 457                 va_start(ap, fmt);
 458                 vcmn_err(CE_NOTE, fmt, ap);
 459                 va_end(ap);
 460         }
 461 }
 462 #endif  /* DEBUG */
 463 
 464 /*
 465  * device operations
 466  */
 467 int
 468 iwp_attach(dev_info_t *dip, ddi_attach_cmd_t cmd)
 469 {
 470         iwp_sc_t                *sc;
 471         ieee80211com_t          *ic;
 472         int                     instance, i;
 473         char                    strbuf[32];
 474         wifi_data_t             wd = { 0 };
 475         mac_register_t          *macp;
 476         int                     intr_type;
 477         int                     intr_count;
 478         int                     intr_actual;
 479         int                     err = DDI_FAILURE;
 480 
 481         switch (cmd) {
 482         case DDI_ATTACH:
 483                 break;
 484         case DDI_RESUME:
 485                 instance = ddi_get_instance(dip);
 486                 sc = ddi_get_soft_state(iwp_soft_state_p,
 487                     instance);
 488                 ASSERT(sc != NULL);
 489 
 490                 if (sc->sc_flags & IWP_F_RUNNING) {
 491                         (void) iwp_init(sc);
 492                 }
 493 
 494                 atomic_and_32(&sc->sc_flags, ~IWP_F_SUSPEND);
 495 
 496                 IWP_DBG((IWP_DEBUG_RESUME, "iwp_attach(): "
 497                     "resume\n"));
 498                 return (DDI_SUCCESS);
 499         default:
 500                 goto attach_fail1;
 501         }
 502 
 503         instance = ddi_get_instance(dip);
 504         err = ddi_soft_state_zalloc(iwp_soft_state_p, instance);
 505         if (err != DDI_SUCCESS) {
 506                 cmn_err(CE_WARN, "iwp_attach(): "
 507                     "failed to allocate soft state\n");
 508                 goto attach_fail1;
 509         }
 510 
 511         sc = ddi_get_soft_state(iwp_soft_state_p, instance);
 512         ASSERT(sc != NULL);
 513 
 514         sc->sc_dip = dip;
 515 
 516         /*
 517          * map configure space
 518          */
 519         err = ddi_regs_map_setup(dip, 0, &sc->sc_cfg_base, 0, 0,
 520             &iwp_reg_accattr, &sc->sc_cfg_handle);
 521         if (err != DDI_SUCCESS) {
 522                 cmn_err(CE_WARN, "iwp_attach(): "
 523                     "failed to map config spaces regs\n");
 524                 goto attach_fail2;
 525         }
 526 
 527         sc->sc_dev_id = ddi_get16(sc->sc_cfg_handle,
 528             (uint16_t *)(sc->sc_cfg_base + PCI_CONF_DEVID));
 529         if ((sc->sc_dev_id != 0x422B) &&
 530             (sc->sc_dev_id != 0x422C) &&
 531             (sc->sc_dev_id != 0x4238) &&
 532             (sc->sc_dev_id != 0x4239) &&
 533             (sc->sc_dev_id != 0x008d) &&
 534             (sc->sc_dev_id != 0x008e)) {
 535                 cmn_err(CE_WARN, "iwp_attach(): "
 536                     "Do not support this device\n");
 537                 goto attach_fail3;
 538         }
 539 
 540         iwp_set_chip_param(sc);
 541 
 542         sc->sc_rev = ddi_get8(sc->sc_cfg_handle,
 543             (uint8_t *)(sc->sc_cfg_base + PCI_CONF_REVID));
 544 
 545         /*
 546          * keep from disturbing C3 state of CPU
 547          */
 548         ddi_put8(sc->sc_cfg_handle, (uint8_t *)(sc->sc_cfg_base +
 549             PCI_CFG_RETRY_TIMEOUT), 0);
 550 
 551         /*
 552          * determine the size of buffer for frame and command to ucode
 553          */
 554         sc->sc_clsz = ddi_get16(sc->sc_cfg_handle,
 555             (uint16_t *)(sc->sc_cfg_base + PCI_CONF_CACHE_LINESZ));
 556         if (!sc->sc_clsz) {
 557                 sc->sc_clsz = 16;
 558         }
 559         sc->sc_clsz = (sc->sc_clsz << 2);
 560 
 561         sc->sc_dmabuf_sz = roundup(0x1000 + sizeof (struct ieee80211_frame) +
 562             IEEE80211_MTU + IEEE80211_CRC_LEN +
 563             (IEEE80211_WEP_IVLEN + IEEE80211_WEP_KIDLEN +
 564             IEEE80211_WEP_CRCLEN), sc->sc_clsz);
 565 
 566         /*
 567          * Map operating registers
 568          */
 569         err = ddi_regs_map_setup(dip, 1, &sc->sc_base,
 570             0, 0, &iwp_reg_accattr, &sc->sc_handle);
 571         if (err != DDI_SUCCESS) {
 572                 cmn_err(CE_WARN, "iwp_attach(): "
 573                     "failed to map device regs\n");
 574                 goto attach_fail3;
 575         }
 576 
 577         /*
 578          * this is used to differentiate type of hardware
 579          */
 580         sc->sc_hw_rev = IWP_READ(sc, CSR_HW_REV);
 581 
 582         err = ddi_intr_get_supported_types(dip, &intr_type);
 583         if ((err != DDI_SUCCESS) || (!(intr_type & DDI_INTR_TYPE_FIXED))) {
 584                 cmn_err(CE_WARN, "iwp_attach(): "
 585                     "fixed type interrupt is not supported\n");
 586                 goto attach_fail4;
 587         }
 588 
 589         err = ddi_intr_get_nintrs(dip, DDI_INTR_TYPE_FIXED, &intr_count);
 590         if ((err != DDI_SUCCESS) || (intr_count != 1)) {
 591                 cmn_err(CE_WARN, "iwp_attach(): "
 592                     "no fixed interrupts\n");
 593                 goto attach_fail4;
 594         }
 595 
 596         sc->sc_intr_htable = kmem_zalloc(sizeof (ddi_intr_handle_t), KM_SLEEP);
 597 
 598         err = ddi_intr_alloc(dip, sc->sc_intr_htable, DDI_INTR_TYPE_FIXED, 0,
 599             intr_count, &intr_actual, 0);
 600         if ((err != DDI_SUCCESS) || (intr_actual != 1)) {
 601                 cmn_err(CE_WARN, "iwp_attach(): "
 602                     "ddi_intr_alloc() failed 0x%x\n", err);
 603                 goto attach_fail5;
 604         }
 605 
 606         err = ddi_intr_get_pri(sc->sc_intr_htable[0], &sc->sc_intr_pri);
 607         if (err != DDI_SUCCESS) {
 608                 cmn_err(CE_WARN, "iwp_attach(): "
 609                     "ddi_intr_get_pri() failed 0x%x\n", err);
 610                 goto attach_fail6;
 611         }
 612 
 613         mutex_init(&sc->sc_glock, NULL, MUTEX_DRIVER,
 614             DDI_INTR_PRI(sc->sc_intr_pri));
 615         mutex_init(&sc->sc_tx_lock, NULL, MUTEX_DRIVER,
 616             DDI_INTR_PRI(sc->sc_intr_pri));
 617         mutex_init(&sc->sc_mt_lock, NULL, MUTEX_DRIVER,
 618             DDI_INTR_PRI(sc->sc_intr_pri));
 619 
 620         cv_init(&sc->sc_cmd_cv, NULL, CV_DRIVER, NULL);
 621         cv_init(&sc->sc_put_seg_cv, NULL, CV_DRIVER, NULL);
 622         cv_init(&sc->sc_ucode_cv, NULL, CV_DRIVER, NULL);
 623 
 624         /*
 625          * initialize the mfthread
 626          */
 627         cv_init(&sc->sc_mt_cv, NULL, CV_DRIVER, NULL);
 628         sc->sc_mf_thread = NULL;
 629         sc->sc_mf_thread_switch = 0;
 630 
 631         /*
 632          * Allocate shared buffer for communication between driver and ucode.
 633          */
 634         err = iwp_alloc_shared(sc);
 635         if (err != DDI_SUCCESS) {
 636                 cmn_err(CE_WARN, "iwp_attach(): "
 637                     "failed to allocate shared page\n");
 638                 goto attach_fail7;
 639         }
 640 
 641         (void) memset(sc->sc_shared, 0, sizeof (iwp_shared_t));
 642 
 643         /*
 644          * Allocate keep warm page.
 645          */
 646         err = iwp_alloc_kw(sc);
 647         if (err != DDI_SUCCESS) {
 648                 cmn_err(CE_WARN, "iwp_attach(): "
 649                     "failed to allocate keep warm page\n");
 650                 goto attach_fail8;
 651         }
 652 
 653         /*
 654          * Do some necessary hardware initializations.
 655          */
 656         err = iwp_preinit(sc);
 657         if (err != IWP_SUCCESS) {
 658                 cmn_err(CE_WARN, "iwp_attach(): "
 659                     "failed to initialize hardware\n");
 660                 goto attach_fail9;
 661         }
 662 
 663         /*
 664          * get hardware configurations from eeprom
 665          */
 666         err = iwp_eep_load(sc);
 667         if (err != IWP_SUCCESS) {
 668                 cmn_err(CE_WARN, "iwp_attach(): "
 669                     "failed to load eeprom\n");
 670                 goto attach_fail9;
 671         }
 672 
 673         /*
 674          * calibration information from EEPROM
 675          */
 676         sc->sc_eep_calib = (struct iwp_eep_calibration *)
 677             iwp_eep_addr_trans(sc, EEP_CALIBRATION);
 678 
 679         err = iwp_eep_ver_chk(sc);
 680         if (err != IWP_SUCCESS) {
 681                 goto attach_fail9;
 682         }
 683 
 684         /*
 685          * get MAC address of this chipset
 686          */
 687         iwp_get_mac_from_eep(sc);
 688 
 689 
 690         /*
 691          * initialize TX and RX ring buffers
 692          */
 693         err = iwp_ring_init(sc);
 694         if (err != DDI_SUCCESS) {
 695                 cmn_err(CE_WARN, "iwp_attach(): "
 696                     "failed to allocate and initialize ring\n");
 697                 goto attach_fail9;
 698         }
 699 
 700         sc->sc_hdr = (iwp_firmware_hdr_t *)iwp_fw_bin;
 701 
 702         /*
 703          * copy ucode to dma buffer
 704          */
 705         err = iwp_alloc_fw_dma(sc);
 706         if (err != DDI_SUCCESS) {
 707                 cmn_err(CE_WARN, "iwp_attach(): "
 708                     "failed to allocate firmware dma\n");
 709                 goto attach_fail10;
 710         }
 711 
 712         /*
 713          * Initialize the wifi part, which will be used by
 714          * 802.11 module
 715          */
 716         ic = &sc->sc_ic;
 717         ic->ic_phytype  = IEEE80211_T_OFDM;
 718         ic->ic_opmode   = IEEE80211_M_STA; /* default to BSS mode */
 719         ic->ic_state    = IEEE80211_S_INIT;
 720         ic->ic_maxrssi  = 100; /* experimental number */
 721         ic->ic_caps = IEEE80211_C_SHPREAMBLE | IEEE80211_C_TXPMGT |
 722             IEEE80211_C_PMGT | IEEE80211_C_SHSLOT;
 723 
 724         /*
 725          * Support WPA/WPA2
 726          */
 727         ic->ic_caps |= IEEE80211_C_WPA;
 728 
 729         /*
 730          * set supported .11b and .11g rates
 731          */
 732         ic->ic_sup_rates[IEEE80211_MODE_11B] = iwp_rateset_11b;
 733         ic->ic_sup_rates[IEEE80211_MODE_11G] = iwp_rateset_11g;
 734 
 735         /*
 736          * set supported .11b and .11g channels (1 through 11)
 737          */
 738         for (i = 1; i <= 11; i++) {
 739                 ic->ic_sup_channels[i].ich_freq =
 740                     ieee80211_ieee2mhz(i, IEEE80211_CHAN_2GHZ);
 741                 ic->ic_sup_channels[i].ich_flags =
 742                     IEEE80211_CHAN_CCK | IEEE80211_CHAN_OFDM |
 743                     IEEE80211_CHAN_DYN | IEEE80211_CHAN_2GHZ |
 744                     IEEE80211_CHAN_PASSIVE;
 745         }
 746 
 747         ic->ic_ibss_chan = &ic->ic_sup_channels[0];
 748         ic->ic_xmit = iwp_send;
 749 
 750         /*
 751          * attach to 802.11 module
 752          */
 753         ieee80211_attach(ic);
 754 
 755         /*
 756          * different instance has different WPA door
 757          */
 758         (void) snprintf(ic->ic_wpadoor, MAX_IEEE80211STR, "%s_%s%d", WPA_DOOR,
 759             ddi_driver_name(dip),
 760             ddi_get_instance(dip));
 761 
 762         /*
 763          * Overwrite 80211 default configurations.
 764          */
 765         iwp_overwrite_ic_default(sc);
 766 
 767         /*
 768          * initialize 802.11 module
 769          */
 770         ieee80211_media_init(ic);
 771 
 772         /*
 773          * initialize default tx key
 774          */
 775         ic->ic_def_txkey = 0;
 776 
 777         err = ddi_intr_add_softint(dip, &sc->sc_soft_hdl, DDI_INTR_SOFTPRI_MAX,
 778             iwp_rx_softintr, (caddr_t)sc);
 779         if (err != DDI_SUCCESS) {
 780                 cmn_err(CE_WARN, "iwp_attach(): "
 781                     "add soft interrupt failed\n");
 782                 goto attach_fail12;
 783         }
 784 
 785         err = ddi_intr_add_handler(sc->sc_intr_htable[0], iwp_intr,
 786             (caddr_t)sc, NULL);
 787         if (err != DDI_SUCCESS) {
 788                 cmn_err(CE_WARN, "iwp_attach(): "
 789                     "ddi_intr_add_handle() failed\n");
 790                 goto attach_fail13;
 791         }
 792 
 793         err = ddi_intr_enable(sc->sc_intr_htable[0]);
 794         if (err != DDI_SUCCESS) {
 795                 cmn_err(CE_WARN, "iwp_attach(): "
 796                     "ddi_intr_enable() failed\n");
 797                 goto attach_fail14;
 798         }
 799 
 800         /*
 801          * Initialize pointer to device specific functions
 802          */
 803         wd.wd_secalloc = WIFI_SEC_NONE;
 804         wd.wd_opmode = ic->ic_opmode;
 805         IEEE80211_ADDR_COPY(wd.wd_bssid, ic->ic_macaddr);
 806 
 807         /*
 808          * create relation to GLD
 809          */
 810         macp = mac_alloc(MAC_VERSION);
 811         if (NULL == macp) {
 812                 cmn_err(CE_WARN, "iwp_attach(): "
 813                     "failed to do mac_alloc()\n");
 814                 goto attach_fail15;
 815         }
 816 
 817         macp->m_type_ident   = MAC_PLUGIN_IDENT_WIFI;
 818         macp->m_driver               = sc;
 819         macp->m_dip          = dip;
 820         macp->m_src_addr     = ic->ic_macaddr;
 821         macp->m_callbacks    = &iwp_m_callbacks;
 822         macp->m_min_sdu              = 0;
 823         macp->m_max_sdu              = IEEE80211_MTU;
 824         macp->m_pdata                = &wd;
 825         macp->m_pdata_size   = sizeof (wd);
 826 
 827         /*
 828          * Register the macp to mac
 829          */
 830         err = mac_register(macp, &ic->ic_mach);
 831         mac_free(macp);
 832         if (err != DDI_SUCCESS) {
 833                 cmn_err(CE_WARN, "iwp_attach(): "
 834                     "failed to do mac_register()\n");
 835                 goto attach_fail15;
 836         }
 837 
 838         /*
 839          * Create minor node of type DDI_NT_NET_WIFI
 840          */
 841         (void) snprintf(strbuf, sizeof (strbuf), DRV_NAME_SP"%d", instance);
 842         err = ddi_create_minor_node(dip, strbuf, S_IFCHR,
 843             instance + 1, DDI_NT_NET_WIFI, 0);
 844         if (err != DDI_SUCCESS) {
 845                 cmn_err(CE_WARN, "iwp_attach(): "
 846                     "failed to do ddi_create_minor_node()\n");
 847         }
 848 
 849         /*
 850          * Notify link is down now
 851          */
 852         mac_link_update(ic->ic_mach, LINK_STATE_DOWN);
 853 
 854         /*
 855          * create the mf thread to handle the link status,
 856          * recovery fatal error, etc.
 857          */
 858         sc->sc_mf_thread_switch = 1;
 859         if (NULL == sc->sc_mf_thread) {
 860                 sc->sc_mf_thread = thread_create((caddr_t)NULL, 0,
 861                     iwp_thread, sc, 0, &p0, TS_RUN, minclsyspri);
 862         }
 863 
 864         atomic_or_32(&sc->sc_flags, IWP_F_ATTACHED);
 865 
 866         return (DDI_SUCCESS);
 867 
 868 attach_fail15:
 869         (void) ddi_intr_disable(sc->sc_intr_htable[0]);
 870 attach_fail14:
 871         (void) ddi_intr_remove_handler(sc->sc_intr_htable[0]);
 872 attach_fail13:
 873         (void) ddi_intr_remove_softint(sc->sc_soft_hdl);
 874         sc->sc_soft_hdl = NULL;
 875 attach_fail12:
 876         ieee80211_detach(ic);
 877 attach_fail11:
 878         iwp_free_fw_dma(sc);
 879 attach_fail10:
 880         iwp_ring_free(sc);
 881 attach_fail9:
 882         iwp_free_kw(sc);
 883 attach_fail8:
 884         iwp_free_shared(sc);
 885 attach_fail7:
 886         iwp_destroy_locks(sc);
 887 attach_fail6:
 888         (void) ddi_intr_free(sc->sc_intr_htable[0]);
 889 attach_fail5:
 890         kmem_free(sc->sc_intr_htable, sizeof (ddi_intr_handle_t));
 891 attach_fail4:
 892         ddi_regs_map_free(&sc->sc_handle);
 893 attach_fail3:
 894         ddi_regs_map_free(&sc->sc_cfg_handle);
 895 attach_fail2:
 896         ddi_soft_state_free(iwp_soft_state_p, instance);
 897 attach_fail1:
 898         return (DDI_FAILURE);
 899 }
 900 
 901 int
 902 iwp_detach(dev_info_t *dip, ddi_detach_cmd_t cmd)
 903 {
 904         iwp_sc_t *sc;
 905         ieee80211com_t  *ic;
 906         int err;
 907 
 908         sc = ddi_get_soft_state(iwp_soft_state_p, ddi_get_instance(dip));
 909         ASSERT(sc != NULL);
 910         ic = &sc->sc_ic;
 911 
 912         switch (cmd) {
 913         case DDI_DETACH:
 914                 break;
 915         case DDI_SUSPEND:
 916                 atomic_and_32(&sc->sc_flags, ~IWP_F_HW_ERR_RECOVER);
 917                 atomic_and_32(&sc->sc_flags, ~IWP_F_RATE_AUTO_CTL);
 918 
 919                 atomic_or_32(&sc->sc_flags, IWP_F_SUSPEND);
 920 
 921                 if (sc->sc_flags & IWP_F_RUNNING) {
 922                         iwp_stop(sc);
 923                         ieee80211_new_state(ic, IEEE80211_S_INIT, -1);
 924 
 925                 }
 926 
 927                 IWP_DBG((IWP_DEBUG_RESUME, "iwp_detach(): "
 928                     "suspend\n"));
 929                 return (DDI_SUCCESS);
 930         default:
 931                 return (DDI_FAILURE);
 932         }
 933 
 934         if (!(sc->sc_flags & IWP_F_ATTACHED)) {
 935                 return (DDI_FAILURE);
 936         }
 937 
 938         /*
 939          * Destroy the mf_thread
 940          */
 941         sc->sc_mf_thread_switch = 0;
 942 
 943         mutex_enter(&sc->sc_mt_lock);
 944         while (sc->sc_mf_thread != NULL) {
 945                 if (cv_wait_sig(&sc->sc_mt_cv, &sc->sc_mt_lock) == 0) {
 946                         break;
 947                 }
 948         }
 949         mutex_exit(&sc->sc_mt_lock);
 950 
 951         err = mac_disable(sc->sc_ic.ic_mach);
 952         if (err != DDI_SUCCESS) {
 953                 return (err);
 954         }
 955 
 956         /*
 957          * stop chipset
 958          */
 959         iwp_stop(sc);
 960 
 961         DELAY(500000);
 962 
 963         /*
 964          * release buffer for calibration
 965          */
 966         iwp_release_calib_buffer(sc);
 967 
 968         /*
 969          * Unregiste from GLD
 970          */
 971         (void) mac_unregister(sc->sc_ic.ic_mach);
 972 
 973         mutex_enter(&sc->sc_glock);
 974         iwp_free_fw_dma(sc);
 975         iwp_ring_free(sc);
 976         iwp_free_kw(sc);
 977         iwp_free_shared(sc);
 978         mutex_exit(&sc->sc_glock);
 979 
 980         (void) ddi_intr_disable(sc->sc_intr_htable[0]);
 981         (void) ddi_intr_remove_handler(sc->sc_intr_htable[0]);
 982         (void) ddi_intr_free(sc->sc_intr_htable[0]);
 983         kmem_free(sc->sc_intr_htable, sizeof (ddi_intr_handle_t));
 984 
 985         (void) ddi_intr_remove_softint(sc->sc_soft_hdl);
 986         sc->sc_soft_hdl = NULL;
 987 
 988         /*
 989          * detach from 80211 module
 990          */
 991         ieee80211_detach(&sc->sc_ic);
 992 
 993         iwp_destroy_locks(sc);
 994 
 995         ddi_regs_map_free(&sc->sc_handle);
 996         ddi_regs_map_free(&sc->sc_cfg_handle);
 997         ddi_remove_minor_node(dip, NULL);
 998         ddi_soft_state_free(iwp_soft_state_p, ddi_get_instance(dip));
 999 
1000         return (DDI_SUCCESS);
1001 }
1002 
1003 /*
1004  * destroy all locks
1005  */
1006 static void
1007 iwp_destroy_locks(iwp_sc_t *sc)
1008 {
1009         cv_destroy(&sc->sc_mt_cv);
1010         cv_destroy(&sc->sc_cmd_cv);
1011         cv_destroy(&sc->sc_put_seg_cv);
1012         cv_destroy(&sc->sc_ucode_cv);
1013         mutex_destroy(&sc->sc_mt_lock);
1014         mutex_destroy(&sc->sc_tx_lock);
1015         mutex_destroy(&sc->sc_glock);
1016 }
1017 
1018 /*
1019  * Allocate an area of memory and a DMA handle for accessing it
1020  */
1021 static int
1022 iwp_alloc_dma_mem(iwp_sc_t *sc, size_t memsize,
1023     ddi_dma_attr_t *dma_attr_p, ddi_device_acc_attr_t *acc_attr_p,
1024     uint_t dma_flags, iwp_dma_t *dma_p)
1025 {
1026         caddr_t vaddr;
1027         int err = DDI_FAILURE;
1028 
1029         /*
1030          * Allocate handle
1031          */
1032         err = ddi_dma_alloc_handle(sc->sc_dip, dma_attr_p,
1033             DDI_DMA_SLEEP, NULL, &dma_p->dma_hdl);
1034         if (err != DDI_SUCCESS) {
1035                 dma_p->dma_hdl = NULL;
1036                 return (DDI_FAILURE);
1037         }
1038 
1039         /*
1040          * Allocate memory
1041          */
1042         err = ddi_dma_mem_alloc(dma_p->dma_hdl, memsize, acc_attr_p,
1043             dma_flags & (DDI_DMA_CONSISTENT | DDI_DMA_STREAMING),
1044             DDI_DMA_SLEEP, NULL, &vaddr, &dma_p->alength, &dma_p->acc_hdl);
1045         if (err != DDI_SUCCESS) {
1046                 ddi_dma_free_handle(&dma_p->dma_hdl);
1047                 dma_p->dma_hdl = NULL;
1048                 dma_p->acc_hdl = NULL;
1049                 return (DDI_FAILURE);
1050         }
1051 
1052         /*
1053          * Bind the two together
1054          */
1055         dma_p->mem_va = vaddr;
1056         err = ddi_dma_addr_bind_handle(dma_p->dma_hdl, NULL,
1057             vaddr, dma_p->alength, dma_flags, DDI_DMA_SLEEP, NULL,
1058             &dma_p->cookie, &dma_p->ncookies);
1059         if (err != DDI_DMA_MAPPED) {
1060                 ddi_dma_mem_free(&dma_p->acc_hdl);
1061                 ddi_dma_free_handle(&dma_p->dma_hdl);
1062                 dma_p->acc_hdl = NULL;
1063                 dma_p->dma_hdl = NULL;
1064                 return (DDI_FAILURE);
1065         }
1066 
1067         dma_p->nslots = ~0U;
1068         dma_p->size = ~0U;
1069         dma_p->token = ~0U;
1070         dma_p->offset = 0;
1071         return (DDI_SUCCESS);
1072 }
1073 
1074 /*
1075  * Free one allocated area of DMAable memory
1076  */
1077 static void
1078 iwp_free_dma_mem(iwp_dma_t *dma_p)
1079 {
1080         if (dma_p->dma_hdl != NULL) {
1081                 if (dma_p->ncookies) {
1082                         (void) ddi_dma_unbind_handle(dma_p->dma_hdl);
1083                         dma_p->ncookies = 0;
1084                 }
1085                 ddi_dma_free_handle(&dma_p->dma_hdl);
1086                 dma_p->dma_hdl = NULL;
1087         }
1088 
1089         if (dma_p->acc_hdl != NULL) {
1090                 ddi_dma_mem_free(&dma_p->acc_hdl);
1091                 dma_p->acc_hdl = NULL;
1092         }
1093 }
1094 
1095 /*
1096  * copy ucode into dma buffers
1097  */
1098 static int
1099 iwp_alloc_fw_dma(iwp_sc_t *sc)
1100 {
1101         int err = DDI_FAILURE;
1102         iwp_dma_t *dma_p;
1103         char *t;
1104 
1105         /*
1106          * firmware image layout:
1107          * |HDR|<-TEXT->|<-DATA->|<-INIT_TEXT->|<-INIT_DATA->|<-BOOT->|
1108          */
1109 
1110         /*
1111          * Check firmware image size.
1112          */
1113         if (LE_32(sc->sc_hdr->init_textsz) > RTC_INST_SIZE) {
1114                 cmn_err(CE_WARN, "iwp_alloc_fw_dma(): "
1115                     "firmware init text size 0x%x is too large\n",
1116                     LE_32(sc->sc_hdr->init_textsz));
1117 
1118                 goto fail;
1119         }
1120 
1121         if (LE_32(sc->sc_hdr->init_datasz) > RTC_DATA_SIZE) {
1122                 cmn_err(CE_WARN, "iwp_alloc_fw_dma(): "
1123                     "firmware init data size 0x%x is too large\n",
1124                     LE_32(sc->sc_hdr->init_datasz));
1125 
1126                 goto fail;
1127         }
1128 
1129         if (LE_32(sc->sc_hdr->textsz) > RTC_INST_SIZE) {
1130                 cmn_err(CE_WARN, "iwp_alloc_fw_dma(): "
1131                     "firmware text size 0x%x is too large\n",
1132                     LE_32(sc->sc_hdr->textsz));
1133 
1134                 goto fail;
1135         }
1136 
1137         if (LE_32(sc->sc_hdr->datasz) > RTC_DATA_SIZE) {
1138                 cmn_err(CE_WARN, "iwp_alloc_fw_dma(): "
1139                     "firmware data size 0x%x is too large\n",
1140                     LE_32(sc->sc_hdr->datasz));
1141 
1142                 goto fail;
1143         }
1144 
1145         /*
1146          * copy text of runtime ucode
1147          */
1148         t = (char *)(sc->sc_hdr + 1);
1149         err = iwp_alloc_dma_mem(sc, LE_32(sc->sc_hdr->textsz),
1150             &fw_dma_attr, &iwp_dma_accattr,
1151             DDI_DMA_RDWR | DDI_DMA_CONSISTENT,
1152             &sc->sc_dma_fw_text);
1153         if (err != DDI_SUCCESS) {
1154                 cmn_err(CE_WARN, "iwp_alloc_fw_dma(): "
1155                     "failed to allocate text dma memory.\n");
1156                 goto fail;
1157         }
1158 
1159         dma_p = &sc->sc_dma_fw_text;
1160 
1161         IWP_DBG((IWP_DEBUG_DMA, "iwp_alloc_fw_dma(): "
1162             "text[ncookies:%d addr:%lx size:%lx]\n",
1163             dma_p->ncookies, dma_p->cookie.dmac_address,
1164             dma_p->cookie.dmac_size));
1165 
1166         (void) memcpy(dma_p->mem_va, t, LE_32(sc->sc_hdr->textsz));
1167 
1168         /*
1169          * copy data and bak-data of runtime ucode
1170          */
1171         t += LE_32(sc->sc_hdr->textsz);
1172         err = iwp_alloc_dma_mem(sc, LE_32(sc->sc_hdr->datasz),
1173             &fw_dma_attr, &iwp_dma_accattr,
1174             DDI_DMA_RDWR | DDI_DMA_CONSISTENT,
1175             &sc->sc_dma_fw_data);
1176         if (err != DDI_SUCCESS) {
1177                 cmn_err(CE_WARN, "iwp_alloc_fw_dma(): "
1178                     "failed to allocate data dma memory\n");
1179                 goto fail;
1180         }
1181 
1182         dma_p = &sc->sc_dma_fw_data;
1183 
1184         IWP_DBG((IWP_DEBUG_DMA, "iwp_alloc_fw_dma(): "
1185             "data[ncookies:%d addr:%lx size:%lx]\n",
1186             dma_p->ncookies, dma_p->cookie.dmac_address,
1187             dma_p->cookie.dmac_size));
1188 
1189         (void) memcpy(dma_p->mem_va, t, LE_32(sc->sc_hdr->datasz));
1190 
1191         err = iwp_alloc_dma_mem(sc, LE_32(sc->sc_hdr->datasz),
1192             &fw_dma_attr, &iwp_dma_accattr,
1193             DDI_DMA_RDWR | DDI_DMA_CONSISTENT,
1194             &sc->sc_dma_fw_data_bak);
1195         if (err != DDI_SUCCESS) {
1196                 cmn_err(CE_WARN, "iwp_alloc_fw_dma(): "
1197                     "failed to allocate data bakup dma memory\n");
1198                 goto fail;
1199         }
1200 
1201         dma_p = &sc->sc_dma_fw_data_bak;
1202 
1203         IWP_DBG((IWP_DEBUG_DMA, "iwp_alloc_fw_dma(): "
1204             "data_bak[ncookies:%d addr:%lx "
1205             "size:%lx]\n",
1206             dma_p->ncookies, dma_p->cookie.dmac_address,
1207             dma_p->cookie.dmac_size));
1208 
1209         (void) memcpy(dma_p->mem_va, t, LE_32(sc->sc_hdr->datasz));
1210 
1211         /*
1212          * copy text of init ucode
1213          */
1214         t += LE_32(sc->sc_hdr->datasz);
1215         err = iwp_alloc_dma_mem(sc, LE_32(sc->sc_hdr->init_textsz),
1216             &fw_dma_attr, &iwp_dma_accattr,
1217             DDI_DMA_RDWR | DDI_DMA_CONSISTENT,
1218             &sc->sc_dma_fw_init_text);
1219         if (err != DDI_SUCCESS) {
1220                 cmn_err(CE_WARN, "iwp_alloc_fw_dma(): "
1221                     "failed to allocate init text dma memory\n");
1222                 goto fail;
1223         }
1224 
1225         dma_p = &sc->sc_dma_fw_init_text;
1226 
1227         IWP_DBG((IWP_DEBUG_DMA, "iwp_alloc_fw_dma(): "
1228             "init_text[ncookies:%d addr:%lx "
1229             "size:%lx]\n",
1230             dma_p->ncookies, dma_p->cookie.dmac_address,
1231             dma_p->cookie.dmac_size));
1232 
1233         (void) memcpy(dma_p->mem_va, t, LE_32(sc->sc_hdr->init_textsz));
1234 
1235         /*
1236          * copy data of init ucode
1237          */
1238         t += LE_32(sc->sc_hdr->init_textsz);
1239         err = iwp_alloc_dma_mem(sc, LE_32(sc->sc_hdr->init_datasz),
1240             &fw_dma_attr, &iwp_dma_accattr,
1241             DDI_DMA_RDWR | DDI_DMA_CONSISTENT,
1242             &sc->sc_dma_fw_init_data);
1243         if (err != DDI_SUCCESS) {
1244                 cmn_err(CE_WARN, "iwp_alloc_fw_dma(): "
1245                     "failed to allocate init data dma memory\n");
1246                 goto fail;
1247         }
1248 
1249         dma_p = &sc->sc_dma_fw_init_data;
1250 
1251         IWP_DBG((IWP_DEBUG_DMA, "iwp_alloc_fw_dma(): "
1252             "init_data[ncookies:%d addr:%lx "
1253             "size:%lx]\n",
1254             dma_p->ncookies, dma_p->cookie.dmac_address,
1255             dma_p->cookie.dmac_size));
1256 
1257         (void) memcpy(dma_p->mem_va, t, LE_32(sc->sc_hdr->init_datasz));
1258 
1259         sc->sc_boot = t + LE_32(sc->sc_hdr->init_datasz);
1260 fail:
1261         return (err);
1262 }
1263 
1264 static void
1265 iwp_free_fw_dma(iwp_sc_t *sc)
1266 {
1267         iwp_free_dma_mem(&sc->sc_dma_fw_text);
1268         iwp_free_dma_mem(&sc->sc_dma_fw_data);
1269         iwp_free_dma_mem(&sc->sc_dma_fw_data_bak);
1270         iwp_free_dma_mem(&sc->sc_dma_fw_init_text);
1271         iwp_free_dma_mem(&sc->sc_dma_fw_init_data);
1272 }
1273 
1274 /*
1275  * Allocate a shared buffer between host and NIC.
1276  */
1277 static int
1278 iwp_alloc_shared(iwp_sc_t *sc)
1279 {
1280 #ifdef  DEBUG
1281         iwp_dma_t *dma_p;
1282 #endif
1283         int err = DDI_FAILURE;
1284 
1285         /*
1286          * must be aligned on a 4K-page boundary
1287          */
1288         err = iwp_alloc_dma_mem(sc, sizeof (iwp_shared_t),
1289             &sh_dma_attr, &iwp_dma_descattr,
1290             DDI_DMA_RDWR | DDI_DMA_CONSISTENT,
1291             &sc->sc_dma_sh);
1292         if (err != DDI_SUCCESS) {
1293                 goto fail;
1294         }
1295 
1296         sc->sc_shared = (iwp_shared_t *)sc->sc_dma_sh.mem_va;
1297 
1298 #ifdef  DEBUG
1299         dma_p = &sc->sc_dma_sh;
1300 #endif
1301         IWP_DBG((IWP_DEBUG_DMA, "iwp_alloc_shared(): "
1302             "sh[ncookies:%d addr:%lx size:%lx]\n",
1303             dma_p->ncookies, dma_p->cookie.dmac_address,
1304             dma_p->cookie.dmac_size));
1305 
1306         return (err);
1307 fail:
1308         iwp_free_shared(sc);
1309         return (err);
1310 }
1311 
1312 static void
1313 iwp_free_shared(iwp_sc_t *sc)
1314 {
1315         iwp_free_dma_mem(&sc->sc_dma_sh);
1316 }
1317 
1318 /*
1319  * Allocate a keep warm page.
1320  */
1321 static int
1322 iwp_alloc_kw(iwp_sc_t *sc)
1323 {
1324 #ifdef  DEBUG
1325         iwp_dma_t *dma_p;
1326 #endif
1327         int err = DDI_FAILURE;
1328 
1329         /*
1330          * must be aligned on a 4K-page boundary
1331          */
1332         err = iwp_alloc_dma_mem(sc, IWP_KW_SIZE,
1333             &kw_dma_attr, &iwp_dma_descattr,
1334             DDI_DMA_RDWR | DDI_DMA_CONSISTENT,
1335             &sc->sc_dma_kw);
1336         if (err != DDI_SUCCESS) {
1337                 goto fail;
1338         }
1339 
1340 #ifdef  DEBUG
1341         dma_p = &sc->sc_dma_kw;
1342 #endif
1343         IWP_DBG((IWP_DEBUG_DMA, "iwp_alloc_kw(): "
1344             "kw[ncookies:%d addr:%lx size:%lx]\n",
1345             dma_p->ncookies, dma_p->cookie.dmac_address,
1346             dma_p->cookie.dmac_size));
1347 
1348         return (err);
1349 fail:
1350         iwp_free_kw(sc);
1351         return (err);
1352 }
1353 
1354 static void
1355 iwp_free_kw(iwp_sc_t *sc)
1356 {
1357         iwp_free_dma_mem(&sc->sc_dma_kw);
1358 }
1359 
1360 /*
1361  * initialize RX ring buffers
1362  */
1363 static int
1364 iwp_alloc_rx_ring(iwp_sc_t *sc)
1365 {
1366         iwp_rx_ring_t *ring;
1367         iwp_rx_data_t *data;
1368 #ifdef  DEBUG
1369         iwp_dma_t *dma_p;
1370 #endif
1371         int i, err = DDI_FAILURE;
1372 
1373         ring = &sc->sc_rxq;
1374         ring->cur = 0;
1375 
1376         /*
1377          * allocate RX description ring buffer
1378          */
1379         err = iwp_alloc_dma_mem(sc, RX_QUEUE_SIZE * sizeof (uint32_t),
1380             &ring_desc_dma_attr, &iwp_dma_descattr,
1381             DDI_DMA_RDWR | DDI_DMA_CONSISTENT,
1382             &ring->dma_desc);
1383         if (err != DDI_SUCCESS) {
1384                 IWP_DBG((IWP_DEBUG_DMA, "iwp_alloc_rx_ring(): "
1385                     "dma alloc rx ring desc "
1386                     "failed\n"));
1387                 goto fail;
1388         }
1389 
1390         ring->desc = (uint32_t *)ring->dma_desc.mem_va;
1391 #ifdef  DEBUG
1392         dma_p = &ring->dma_desc;
1393 #endif
1394         IWP_DBG((IWP_DEBUG_DMA, "iwp_alloc_rx_ring(): "
1395             "rx bd[ncookies:%d addr:%lx size:%lx]\n",
1396             dma_p->ncookies, dma_p->cookie.dmac_address,
1397             dma_p->cookie.dmac_size));
1398 
1399         /*
1400          * Allocate Rx frame buffers.
1401          */
1402         for (i = 0; i < RX_QUEUE_SIZE; i++) {
1403                 data = &ring->data[i];
1404                 err = iwp_alloc_dma_mem(sc, sc->sc_dmabuf_sz,
1405                     &rx_buffer_dma_attr, &iwp_dma_accattr,
1406                     DDI_DMA_READ | DDI_DMA_STREAMING,
1407                     &data->dma_data);
1408                 if (err != DDI_SUCCESS) {
1409                         IWP_DBG((IWP_DEBUG_DMA, "iwp_alloc_rx_ring(): "
1410                             "dma alloc rx ring "
1411                             "buf[%d] failed\n", i));
1412                         goto fail;
1413                 }
1414                 /*
1415                  * the physical address bit [8-36] are used,
1416                  * instead of bit [0-31] in 3945.
1417                  */
1418                 ring->desc[i] = (uint32_t)
1419                     (data->dma_data.cookie.dmac_address >> 8);
1420         }
1421 
1422 #ifdef  DEBUG
1423         dma_p = &ring->data[0].dma_data;
1424 #endif
1425         IWP_DBG((IWP_DEBUG_DMA, "iwp_alloc_rx_ring(): "
1426             "rx buffer[0][ncookies:%d addr:%lx "
1427             "size:%lx]\n",
1428             dma_p->ncookies, dma_p->cookie.dmac_address,
1429             dma_p->cookie.dmac_size));
1430 
1431         IWP_DMA_SYNC(ring->dma_desc, DDI_DMA_SYNC_FORDEV);
1432 
1433         return (err);
1434 
1435 fail:
1436         iwp_free_rx_ring(sc);
1437         return (err);
1438 }
1439 
1440 /*
1441  * disable RX ring
1442  */
1443 static void
1444 iwp_reset_rx_ring(iwp_sc_t *sc)
1445 {
1446         int n;
1447 
1448         iwp_mac_access_enter(sc);
1449         IWP_WRITE(sc, FH_MEM_RCSR_CHNL0_CONFIG_REG, 0);
1450         for (n = 0; n < 2000; n++) {
1451                 if (IWP_READ(sc, FH_MEM_RSSR_RX_STATUS_REG) & (1 << 24)) {
1452                         break;
1453                 }
1454                 DELAY(1000);
1455         }
1456 #ifdef DEBUG
1457         if (2000 == n) {
1458                 IWP_DBG((IWP_DEBUG_DMA, "iwp_reset_rx_ring(): "
1459                     "timeout resetting Rx ring\n"));
1460         }
1461 #endif
1462         iwp_mac_access_exit(sc);
1463 
1464         sc->sc_rxq.cur = 0;
1465 }
1466 
1467 static void
1468 iwp_free_rx_ring(iwp_sc_t *sc)
1469 {
1470         int i;
1471 
1472         for (i = 0; i < RX_QUEUE_SIZE; i++) {
1473                 if (sc->sc_rxq.data[i].dma_data.dma_hdl) {
1474                         IWP_DMA_SYNC(sc->sc_rxq.data[i].dma_data,
1475                             DDI_DMA_SYNC_FORCPU);
1476                 }
1477 
1478                 iwp_free_dma_mem(&sc->sc_rxq.data[i].dma_data);
1479         }
1480 
1481         if (sc->sc_rxq.dma_desc.dma_hdl) {
1482                 IWP_DMA_SYNC(sc->sc_rxq.dma_desc, DDI_DMA_SYNC_FORDEV);
1483         }
1484 
1485         iwp_free_dma_mem(&sc->sc_rxq.dma_desc);
1486 }
1487 
1488 /*
1489  * initialize TX ring buffers
1490  */
1491 static int
1492 iwp_alloc_tx_ring(iwp_sc_t *sc, iwp_tx_ring_t *ring,
1493     int slots, int qid)
1494 {
1495         iwp_tx_data_t *data;
1496         iwp_tx_desc_t *desc_h;
1497         uint32_t paddr_desc_h;
1498         iwp_cmd_t *cmd_h;
1499         uint32_t paddr_cmd_h;
1500 #ifdef  DEBUG
1501         iwp_dma_t *dma_p;
1502 #endif
1503         int i, err = DDI_FAILURE;
1504         ring->qid = qid;
1505         ring->count = TFD_QUEUE_SIZE_MAX;
1506         ring->window = slots;
1507         ring->queued = 0;
1508         ring->cur = 0;
1509         ring->desc_cur = 0;
1510 
1511         /*
1512          * allocate buffer for TX descriptor ring
1513          */
1514         err = iwp_alloc_dma_mem(sc,
1515             TFD_QUEUE_SIZE_MAX * sizeof (iwp_tx_desc_t),
1516             &ring_desc_dma_attr, &iwp_dma_descattr,
1517             DDI_DMA_RDWR | DDI_DMA_CONSISTENT,
1518             &ring->dma_desc);
1519         if (err != DDI_SUCCESS) {
1520                 IWP_DBG((IWP_DEBUG_DMA, "iwp_alloc_tx_ring(): "
1521                     "dma alloc tx ring desc[%d] "
1522                     "failed\n", qid));
1523                 goto fail;
1524         }
1525 
1526 #ifdef  DEBUG
1527         dma_p = &ring->dma_desc;
1528 #endif
1529         IWP_DBG((IWP_DEBUG_DMA, "iwp_alloc_tx_ring(): "
1530             "tx bd[ncookies:%d addr:%lx size:%lx]\n",
1531             dma_p->ncookies, dma_p->cookie.dmac_address,
1532             dma_p->cookie.dmac_size));
1533 
1534         desc_h = (iwp_tx_desc_t *)ring->dma_desc.mem_va;
1535         paddr_desc_h = ring->dma_desc.cookie.dmac_address;
1536 
1537         /*
1538          * allocate buffer for ucode command
1539          */
1540         err = iwp_alloc_dma_mem(sc,
1541             TFD_QUEUE_SIZE_MAX * sizeof (iwp_cmd_t),
1542             &cmd_dma_attr, &iwp_dma_accattr,
1543             DDI_DMA_RDWR | DDI_DMA_CONSISTENT,
1544             &ring->dma_cmd);
1545         if (err != DDI_SUCCESS) {
1546                 IWP_DBG((IWP_DEBUG_DMA, "iwp_alloc_tx_ring(): "
1547                     "dma alloc tx ring cmd[%d]"
1548                     " failed\n", qid));
1549                 goto fail;
1550         }
1551 
1552 #ifdef  DEBUG
1553         dma_p = &ring->dma_cmd;
1554 #endif
1555         IWP_DBG((IWP_DEBUG_DMA, "iwp_alloc_tx_ring(): "
1556             "tx cmd[ncookies:%d addr:%lx size:%lx]\n",
1557             dma_p->ncookies, dma_p->cookie.dmac_address,
1558             dma_p->cookie.dmac_size));
1559 
1560         cmd_h = (iwp_cmd_t *)ring->dma_cmd.mem_va;
1561         paddr_cmd_h = ring->dma_cmd.cookie.dmac_address;
1562 
1563         /*
1564          * Allocate Tx frame buffers.
1565          */
1566         ring->data = kmem_zalloc(sizeof (iwp_tx_data_t) * TFD_QUEUE_SIZE_MAX,
1567             KM_NOSLEEP);
1568         if (NULL == ring->data) {
1569                 IWP_DBG((IWP_DEBUG_DMA, "iwp_alloc_tx_ring(): "
1570                     "could not allocate "
1571                     "tx data slots\n"));
1572                 goto fail;
1573         }
1574 
1575         for (i = 0; i < TFD_QUEUE_SIZE_MAX; i++) {
1576                 data = &ring->data[i];
1577                 err = iwp_alloc_dma_mem(sc, sc->sc_dmabuf_sz,
1578                     &tx_buffer_dma_attr, &iwp_dma_accattr,
1579                     DDI_DMA_WRITE | DDI_DMA_STREAMING,
1580                     &data->dma_data);
1581                 if (err != DDI_SUCCESS) {
1582                         IWP_DBG((IWP_DEBUG_DMA, "iwp_alloc_tx_ring(): "
1583                             "dma alloc tx "
1584                             "ring buf[%d] failed\n", i));
1585                         goto fail;
1586                 }
1587 
1588                 data->desc = desc_h + i;
1589                 data->paddr_desc = paddr_desc_h +
1590                     _PTRDIFF(data->desc, desc_h);
1591                 data->cmd = cmd_h +  i;
1592                 data->paddr_cmd = paddr_cmd_h +
1593                     _PTRDIFF(data->cmd, cmd_h);
1594         }
1595 #ifdef  DEBUG
1596         dma_p = &ring->data[0].dma_data;
1597 #endif
1598         IWP_DBG((IWP_DEBUG_DMA, "iwp_alloc_tx_ring(): "
1599             "tx buffer[0][ncookies:%d addr:%lx "
1600             "size:%lx]\n",
1601             dma_p->ncookies, dma_p->cookie.dmac_address,
1602             dma_p->cookie.dmac_size));
1603 
1604         return (err);
1605 
1606 fail:
1607         iwp_free_tx_ring(ring);
1608 
1609         return (err);
1610 }
1611 
1612 /*
1613  * disable TX ring
1614  */
1615 static void
1616 iwp_reset_tx_ring(iwp_sc_t *sc, iwp_tx_ring_t *ring)
1617 {
1618         iwp_tx_data_t *data;
1619         int i, n;
1620 
1621         iwp_mac_access_enter(sc);
1622 
1623         IWP_WRITE(sc, IWP_FH_TCSR_CHNL_TX_CONFIG_REG(ring->qid), 0);
1624         for (n = 0; n < 200; n++) {
1625                 if (IWP_READ(sc, IWP_FH_TSSR_TX_STATUS_REG) &
1626                     IWP_FH_TSSR_TX_STATUS_REG_MSK_CHNL_IDLE(ring->qid)) {
1627                         break;
1628                 }
1629                 DELAY(10);
1630         }
1631 
1632 #ifdef  DEBUG
1633         if (200 == n) {
1634                 IWP_DBG((IWP_DEBUG_DMA, "iwp_reset_tx_ring(): "
1635                     "timeout reset tx ring %d\n",
1636                     ring->qid));
1637         }
1638 #endif
1639 
1640         iwp_mac_access_exit(sc);
1641 
1642         /* by pass, if it's quiesce */
1643         if (!(sc->sc_flags & IWP_F_QUIESCED)) {
1644                 for (i = 0; i < ring->count; i++) {
1645                         data = &ring->data[i];
1646                         IWP_DMA_SYNC(data->dma_data, DDI_DMA_SYNC_FORDEV);
1647                 }
1648         }
1649 
1650         ring->queued = 0;
1651         ring->cur = 0;
1652         ring->desc_cur = 0;
1653 }
1654 
1655 static void
1656 iwp_free_tx_ring(iwp_tx_ring_t *ring)
1657 {
1658         int i;
1659 
1660         if (ring->dma_desc.dma_hdl != NULL) {
1661                 IWP_DMA_SYNC(ring->dma_desc, DDI_DMA_SYNC_FORDEV);
1662         }
1663         iwp_free_dma_mem(&ring->dma_desc);
1664 
1665         if (ring->dma_cmd.dma_hdl != NULL) {
1666                 IWP_DMA_SYNC(ring->dma_cmd, DDI_DMA_SYNC_FORDEV);
1667         }
1668         iwp_free_dma_mem(&ring->dma_cmd);
1669 
1670         if (ring->data != NULL) {
1671                 for (i = 0; i < ring->count; i++) {
1672                         if (ring->data[i].dma_data.dma_hdl) {
1673                                 IWP_DMA_SYNC(ring->data[i].dma_data,
1674                                     DDI_DMA_SYNC_FORDEV);
1675                         }
1676                         iwp_free_dma_mem(&ring->data[i].dma_data);
1677                 }
1678                 kmem_free(ring->data, ring->count * sizeof (iwp_tx_data_t));
1679         }
1680 }
1681 
1682 /*
1683  * initialize TX and RX ring
1684  */
1685 static int
1686 iwp_ring_init(iwp_sc_t *sc)
1687 {
1688         int i, err = DDI_FAILURE;
1689 
1690         for (i = 0; i < IWP_NUM_QUEUES; i++) {
1691                 if (IWP_CMD_QUEUE_NUM == i) {
1692                         continue;
1693                 }
1694 
1695                 err = iwp_alloc_tx_ring(sc, &sc->sc_txq[i], TFD_TX_CMD_SLOTS,
1696                     i);
1697                 if (err != DDI_SUCCESS) {
1698                         goto fail;
1699                 }
1700         }
1701 
1702         /*
1703          * initialize command queue
1704          */
1705         err = iwp_alloc_tx_ring(sc, &sc->sc_txq[IWP_CMD_QUEUE_NUM],
1706             TFD_CMD_SLOTS, IWP_CMD_QUEUE_NUM);
1707         if (err != DDI_SUCCESS) {
1708                 goto fail;
1709         }
1710 
1711         err = iwp_alloc_rx_ring(sc);
1712         if (err != DDI_SUCCESS) {
1713                 goto fail;
1714         }
1715 
1716 fail:
1717         return (err);
1718 }
1719 
1720 static void
1721 iwp_ring_free(iwp_sc_t *sc)
1722 {
1723         int i = IWP_NUM_QUEUES;
1724 
1725         iwp_free_rx_ring(sc);
1726         while (--i >= 0) {
1727                 iwp_free_tx_ring(&sc->sc_txq[i]);
1728         }
1729 }
1730 
1731 /* ARGSUSED */
1732 static ieee80211_node_t *
1733 iwp_node_alloc(ieee80211com_t *ic)
1734 {
1735         iwp_amrr_t *amrr;
1736 
1737         amrr = kmem_zalloc(sizeof (iwp_amrr_t), KM_SLEEP);
1738         if (NULL == amrr) {
1739                 cmn_err(CE_WARN, "iwp_node_alloc(): "
1740                     "failed to allocate memory for amrr structure\n");
1741                 return (NULL);
1742         }
1743 
1744         iwp_amrr_init(amrr);
1745 
1746         return (&amrr->in);
1747 }
1748 
1749 static void
1750 iwp_node_free(ieee80211_node_t *in)
1751 {
1752         ieee80211com_t *ic;
1753 
1754         if ((NULL == in) ||
1755             (NULL == in->in_ic)) {
1756                 cmn_err(CE_WARN, "iwp_node_free() "
1757                     "Got a NULL point from Net80211 module\n");
1758                 return;
1759         }
1760         ic = in->in_ic;
1761 
1762         if (ic->ic_node_cleanup != NULL) {
1763                 ic->ic_node_cleanup(in);
1764         }
1765 
1766         if (in->in_wpa_ie != NULL) {
1767                 ieee80211_free(in->in_wpa_ie);
1768         }
1769 
1770         if (in->in_wme_ie != NULL) {
1771                 ieee80211_free(in->in_wme_ie);
1772         }
1773 
1774         if (in->in_htcap_ie != NULL) {
1775                 ieee80211_free(in->in_htcap_ie);
1776         }
1777 
1778         kmem_free(in, sizeof (iwp_amrr_t));
1779 }
1780 
1781 
1782 /*
1783  * change station's state. this function will be invoked by 80211 module
1784  * when need to change staton's state.
1785  */
1786 static int
1787 iwp_newstate(ieee80211com_t *ic, enum ieee80211_state nstate, int arg)
1788 {
1789         iwp_sc_t *sc;
1790         ieee80211_node_t *in;
1791         enum ieee80211_state ostate;
1792         iwp_add_sta_t node;
1793         int i, err = IWP_FAIL;
1794 
1795         if (NULL == ic) {
1796                 return (err);
1797         }
1798         sc = (iwp_sc_t *)ic;
1799         in = ic->ic_bss;
1800         ostate = ic->ic_state;
1801 
1802         mutex_enter(&sc->sc_glock);
1803 
1804         switch (nstate) {
1805         case IEEE80211_S_SCAN:
1806                 switch (ostate) {
1807                 case IEEE80211_S_INIT:
1808                         atomic_or_32(&sc->sc_flags, IWP_F_SCANNING);
1809                         iwp_set_led(sc, 2, 10, 2);
1810 
1811                         /*
1812                          * clear association to receive beacons from
1813                          * all BSS'es
1814                          */
1815                         sc->sc_config.assoc_id = 0;
1816                         sc->sc_config.filter_flags &=
1817                             ~LE_32(RXON_FILTER_ASSOC_MSK);
1818 
1819                         IWP_DBG((IWP_DEBUG_80211, "iwp_newstate(): "
1820                             "config chan %d "
1821                             "flags %x filter_flags %x\n",
1822                             LE_16(sc->sc_config.chan),
1823                             LE_32(sc->sc_config.flags),
1824                             LE_32(sc->sc_config.filter_flags)));
1825 
1826                         err = iwp_cmd(sc, REPLY_RXON, &sc->sc_config,
1827                             sizeof (iwp_rxon_cmd_t), 1);
1828                         if (err != IWP_SUCCESS) {
1829                                 cmn_err(CE_WARN, "iwp_newstate(): "
1830                                     "could not clear association\n");
1831                                 atomic_and_32(&sc->sc_flags, ~IWP_F_SCANNING);
1832                                 mutex_exit(&sc->sc_glock);
1833                                 return (err);
1834                         }
1835 
1836                         /* add broadcast node to send probe request */
1837                         (void) memset(&node, 0, sizeof (node));
1838                         (void) memset(&node.sta.addr, 0xff, IEEE80211_ADDR_LEN);
1839                         node.sta.sta_id = IWP_BROADCAST_ID;
1840                         err = iwp_cmd(sc, REPLY_ADD_STA, &node,
1841                             sizeof (node), 1);
1842                         if (err != IWP_SUCCESS) {
1843                                 cmn_err(CE_WARN, "iwp_newstate(): "
1844                                     "could not add broadcast node\n");
1845                                 atomic_and_32(&sc->sc_flags, ~IWP_F_SCANNING);
1846                                 mutex_exit(&sc->sc_glock);
1847                                 return (err);
1848                         }
1849                         break;
1850                 case IEEE80211_S_SCAN:
1851                         mutex_exit(&sc->sc_glock);
1852                         /* step to next channel before actual FW scan */
1853                         err = sc->sc_newstate(ic, nstate, arg);
1854                         mutex_enter(&sc->sc_glock);
1855                         if ((err != 0) || ((err = iwp_scan(sc)) != 0)) {
1856                                 cmn_err(CE_WARN, "iwp_newstate(): "
1857                                     "could not initiate scan\n");
1858                                 atomic_and_32(&sc->sc_flags, ~IWP_F_SCANNING);
1859                                 ieee80211_cancel_scan(ic);
1860                         }
1861                         mutex_exit(&sc->sc_glock);
1862                         return (err);
1863                 default:
1864                         break;
1865                 }
1866                 sc->sc_clk = 0;
1867                 break;
1868 
1869         case IEEE80211_S_AUTH:
1870                 if (ostate == IEEE80211_S_SCAN) {
1871                         atomic_and_32(&sc->sc_flags, ~IWP_F_SCANNING);
1872                 }
1873 
1874                 /*
1875                  * reset state to handle reassociations correctly
1876                  */
1877                 sc->sc_config.assoc_id = 0;
1878                 sc->sc_config.filter_flags &= ~LE_32(RXON_FILTER_ASSOC_MSK);
1879 
1880                 /*
1881                  * before sending authentication and association request frame,
1882                  * we need do something in the hardware, such as setting the
1883                  * channel same to the target AP...
1884                  */
1885                 if ((err = iwp_hw_set_before_auth(sc)) != 0) {
1886                         IWP_DBG((IWP_DEBUG_80211, "iwp_newstate(): "
1887                             "could not send authentication request\n"));
1888                         mutex_exit(&sc->sc_glock);
1889                         return (err);
1890                 }
1891                 break;
1892 
1893         case IEEE80211_S_RUN:
1894                 if (ostate == IEEE80211_S_SCAN) {
1895                         atomic_and_32(&sc->sc_flags, ~IWP_F_SCANNING);
1896                 }
1897 
1898                 if (IEEE80211_M_MONITOR == ic->ic_opmode) {
1899                         /* let LED blink when monitoring */
1900                         iwp_set_led(sc, 2, 10, 10);
1901                         break;
1902                 }
1903 
1904                 IWP_DBG((IWP_DEBUG_80211, "iwp_newstate(): "
1905                     "associated.\n"));
1906 
1907                 err = iwp_run_state_config(sc);
1908                 if (err != IWP_SUCCESS) {
1909                         cmn_err(CE_WARN, "iwp_newstate(): "
1910                             "failed to set up association\n");
1911                         mutex_exit(&sc->sc_glock);
1912                         return (err);
1913                 }
1914 
1915                 /*
1916                  * start automatic rate control
1917                  */
1918                 if (IEEE80211_FIXED_RATE_NONE == ic->ic_fixed_rate) {
1919                         atomic_or_32(&sc->sc_flags, IWP_F_RATE_AUTO_CTL);
1920 
1921                         /*
1922                          * set rate to some reasonable initial value
1923                          */
1924                         i = in->in_rates.ir_nrates - 1;
1925                         while (i > 0 && IEEE80211_RATE(i) > 72) {
1926                                 i--;
1927                         }
1928                         in->in_txrate = i;
1929 
1930                 } else {
1931                         atomic_and_32(&sc->sc_flags, ~IWP_F_RATE_AUTO_CTL);
1932                 }
1933 
1934                 /*
1935                  * set LED on after associated
1936                  */
1937                 iwp_set_led(sc, 2, 0, 1);
1938                 break;
1939 
1940         case IEEE80211_S_INIT:
1941                 if (ostate == IEEE80211_S_SCAN) {
1942                         atomic_and_32(&sc->sc_flags, ~IWP_F_SCANNING);
1943                 }
1944                 /*
1945                  * set LED off after init
1946                  */
1947                 iwp_set_led(sc, 2, 1, 0);
1948                 break;
1949 
1950         case IEEE80211_S_ASSOC:
1951                 if (ostate == IEEE80211_S_SCAN) {
1952                         atomic_and_32(&sc->sc_flags, ~IWP_F_SCANNING);
1953                 }
1954                 break;
1955         }
1956 
1957         mutex_exit(&sc->sc_glock);
1958 
1959         return (sc->sc_newstate(ic, nstate, arg));
1960 }
1961 
1962 /*
1963  * exclusive access to mac begin.
1964  */
1965 static void
1966 iwp_mac_access_enter(iwp_sc_t *sc)
1967 {
1968         uint32_t tmp;
1969         int n;
1970 
1971         tmp = IWP_READ(sc, CSR_GP_CNTRL);
1972         IWP_WRITE(sc, CSR_GP_CNTRL,
1973             tmp | CSR_GP_CNTRL_REG_FLAG_MAC_ACCESS_REQ);
1974 
1975         /* wait until we succeed */
1976         for (n = 0; n < 1000; n++) {
1977                 if ((IWP_READ(sc, CSR_GP_CNTRL) &
1978                     (CSR_GP_CNTRL_REG_FLAG_MAC_CLOCK_READY |
1979                     CSR_GP_CNTRL_REG_FLAG_GOING_TO_SLEEP)) ==
1980                     CSR_GP_CNTRL_REG_VAL_MAC_ACCESS_EN) {
1981                         break;
1982                 }
1983                 DELAY(10);
1984         }
1985 
1986 #ifdef  DEBUG
1987         if (1000 == n) {
1988                 IWP_DBG((IWP_DEBUG_PIO, "iwp_mac_access_enter(): "
1989                     "could not lock memory\n"));
1990         }
1991 #endif
1992 }
1993 
1994 /*
1995  * exclusive access to mac end.
1996  */
1997 static void
1998 iwp_mac_access_exit(iwp_sc_t *sc)
1999 {
2000         uint32_t tmp = IWP_READ(sc, CSR_GP_CNTRL);
2001         IWP_WRITE(sc, CSR_GP_CNTRL,
2002             tmp & ~CSR_GP_CNTRL_REG_FLAG_MAC_ACCESS_REQ);
2003 }
2004 
2005 /*
2006  * this function defined here for future use.
2007  * static uint32_t
2008  * iwp_mem_read(iwp_sc_t *sc, uint32_t addr)
2009  * {
2010  *      IWP_WRITE(sc, HBUS_TARG_MEM_RADDR, addr);
2011  *      return (IWP_READ(sc, HBUS_TARG_MEM_RDAT));
2012  * }
2013  */
2014 
2015 /*
2016  * write mac memory
2017  */
2018 static void
2019 iwp_mem_write(iwp_sc_t *sc, uint32_t addr, uint32_t data)
2020 {
2021         IWP_WRITE(sc, HBUS_TARG_MEM_WADDR, addr);
2022         IWP_WRITE(sc, HBUS_TARG_MEM_WDAT, data);
2023 }
2024 
2025 /*
2026  * read mac register
2027  */
2028 static uint32_t
2029 iwp_reg_read(iwp_sc_t *sc, uint32_t addr)
2030 {
2031         IWP_WRITE(sc, HBUS_TARG_PRPH_RADDR, addr | (3 << 24));
2032         return (IWP_READ(sc, HBUS_TARG_PRPH_RDAT));
2033 }
2034 
2035 /*
2036  * write mac register
2037  */
2038 static void
2039 iwp_reg_write(iwp_sc_t *sc, uint32_t addr, uint32_t data)
2040 {
2041         IWP_WRITE(sc, HBUS_TARG_PRPH_WADDR, addr | (3 << 24));
2042         IWP_WRITE(sc, HBUS_TARG_PRPH_WDAT, data);
2043 }
2044 
2045 
2046 /*
2047  * steps of loading ucode:
2048  * load init ucode=>init alive=>calibrate=>
2049  * receive calibration result=>reinitialize NIC=>
2050  * load runtime ucode=>runtime alive=>
2051  * send calibration result=>running.
2052  */
2053 static int
2054 iwp_load_init_firmware(iwp_sc_t *sc)
2055 {
2056         int     err = IWP_FAIL;
2057         clock_t clk;
2058 
2059         atomic_and_32(&sc->sc_flags, ~IWP_F_PUT_SEG);
2060 
2061         /*
2062          * load init_text section of uCode to hardware
2063          */
2064         err = iwp_put_seg_fw(sc, sc->sc_dma_fw_init_text.cookie.dmac_address,
2065             RTC_INST_LOWER_BOUND, sc->sc_dma_fw_init_text.cookie.dmac_size);
2066         if (err != IWP_SUCCESS) {
2067                 cmn_err(CE_WARN, "iwp_load_init_firmware(): "
2068                     "failed to write init uCode.\n");
2069                 return (err);
2070         }
2071 
2072         clk = ddi_get_lbolt() + drv_usectohz(1000000);
2073 
2074         /* wait loading init_text until completed or timeout */
2075         while (!(sc->sc_flags & IWP_F_PUT_SEG)) {
2076                 if (cv_timedwait(&sc->sc_put_seg_cv, &sc->sc_glock, clk) < 0) {
2077                         break;
2078                 }
2079         }
2080 
2081         if (!(sc->sc_flags & IWP_F_PUT_SEG)) {
2082                 cmn_err(CE_WARN, "iwp_load_init_firmware(): "
2083                     "timeout waiting for init uCode load.\n");
2084                 return (IWP_FAIL);
2085         }
2086 
2087         atomic_and_32(&sc->sc_flags, ~IWP_F_PUT_SEG);
2088 
2089         /*
2090          * load init_data section of uCode to hardware
2091          */
2092         err = iwp_put_seg_fw(sc, sc->sc_dma_fw_init_data.cookie.dmac_address,
2093             RTC_DATA_LOWER_BOUND, sc->sc_dma_fw_init_data.cookie.dmac_size);
2094         if (err != IWP_SUCCESS) {
2095                 cmn_err(CE_WARN, "iwp_load_init_firmware(): "
2096                     "failed to write init_data uCode.\n");
2097                 return (err);
2098         }
2099 
2100         clk = ddi_get_lbolt() + drv_usectohz(1000000);
2101 
2102         /*
2103          * wait loading init_data until completed or timeout
2104          */
2105         while (!(sc->sc_flags & IWP_F_PUT_SEG)) {
2106                 if (cv_timedwait(&sc->sc_put_seg_cv, &sc->sc_glock, clk) < 0) {
2107                         break;
2108                 }
2109         }
2110 
2111         if (!(sc->sc_flags & IWP_F_PUT_SEG)) {
2112                 cmn_err(CE_WARN, "iwp_load_init_firmware(): "
2113                     "timeout waiting for init_data uCode load.\n");
2114                 return (IWP_FAIL);
2115         }
2116 
2117         atomic_and_32(&sc->sc_flags, ~IWP_F_PUT_SEG);
2118 
2119         return (err);
2120 }
2121 
2122 static int
2123 iwp_load_run_firmware(iwp_sc_t *sc)
2124 {
2125         int     err = IWP_FAIL;
2126         clock_t clk;
2127 
2128         atomic_and_32(&sc->sc_flags, ~IWP_F_PUT_SEG);
2129 
2130         /*
2131          * load init_text section of uCode to hardware
2132          */
2133         err = iwp_put_seg_fw(sc, sc->sc_dma_fw_text.cookie.dmac_address,
2134             RTC_INST_LOWER_BOUND, sc->sc_dma_fw_text.cookie.dmac_size);
2135         if (err != IWP_SUCCESS) {
2136                 cmn_err(CE_WARN, "iwp_load_run_firmware(): "
2137                     "failed to write run uCode.\n");
2138                 return (err);
2139         }
2140 
2141         clk = ddi_get_lbolt() + drv_usectohz(1000000);
2142 
2143         /* wait loading run_text until completed or timeout */
2144         while (!(sc->sc_flags & IWP_F_PUT_SEG)) {
2145                 if (cv_timedwait(&sc->sc_put_seg_cv, &sc->sc_glock, clk) < 0) {
2146                         break;
2147                 }
2148         }
2149 
2150         if (!(sc->sc_flags & IWP_F_PUT_SEG)) {
2151                 cmn_err(CE_WARN, "iwp_load_run_firmware(): "
2152                     "timeout waiting for run uCode load.\n");
2153                 return (IWP_FAIL);
2154         }
2155 
2156         atomic_and_32(&sc->sc_flags, ~IWP_F_PUT_SEG);
2157 
2158         /*
2159          * load run_data section of uCode to hardware
2160          */
2161         err = iwp_put_seg_fw(sc, sc->sc_dma_fw_data_bak.cookie.dmac_address,
2162             RTC_DATA_LOWER_BOUND, sc->sc_dma_fw_data.cookie.dmac_size);
2163         if (err != IWP_SUCCESS) {
2164                 cmn_err(CE_WARN, "iwp_load_run_firmware(): "
2165                     "failed to write run_data uCode.\n");
2166                 return (err);
2167         }
2168 
2169         clk = ddi_get_lbolt() + drv_usectohz(1000000);
2170 
2171         /*
2172          * wait loading run_data until completed or timeout
2173          */
2174         while (!(sc->sc_flags & IWP_F_PUT_SEG)) {
2175                 if (cv_timedwait(&sc->sc_put_seg_cv, &sc->sc_glock, clk) < 0) {
2176                         break;
2177                 }
2178         }
2179 
2180         if (!(sc->sc_flags & IWP_F_PUT_SEG)) {
2181                 cmn_err(CE_WARN, "iwp_load_run_firmware(): "
2182                     "timeout waiting for run_data uCode load.\n");
2183                 return (IWP_FAIL);
2184         }
2185 
2186         atomic_and_32(&sc->sc_flags, ~IWP_F_PUT_SEG);
2187 
2188         return (err);
2189 }
2190 
2191 /*
2192  * this function will be invoked to receive phy information
2193  * when a frame is received.
2194  */
2195 static void
2196 iwp_rx_phy_intr(iwp_sc_t *sc, iwp_rx_desc_t *desc)
2197 {
2198 
2199         sc->sc_rx_phy_res.flag = 1;
2200 
2201         (void) memcpy(sc->sc_rx_phy_res.buf, (uint8_t *)(desc + 1),
2202             sizeof (iwp_rx_phy_res_t));
2203 }
2204 
2205 /*
2206  * this function will be invoked to receive body of frame when
2207  * a frame is received.
2208  */
2209 static void
2210 iwp_rx_mpdu_intr(iwp_sc_t *sc, iwp_rx_desc_t *desc)
2211 {
2212         ieee80211com_t  *ic = &sc->sc_ic;
2213 #ifdef  DEBUG
2214         iwp_rx_ring_t   *ring = &sc->sc_rxq;
2215 #endif
2216         struct ieee80211_frame          *wh;
2217         struct iwp_rx_non_cfg_phy       *phyinfo;
2218         struct  iwp_rx_mpdu_body_size   *mpdu_size;
2219 
2220         mblk_t                  *mp;
2221         int16_t                 t;
2222         uint16_t                len, rssi, agc;
2223         uint32_t                temp, crc, *tail;
2224         uint32_t                arssi, brssi, crssi, mrssi;
2225         iwp_rx_phy_res_t        *stat;
2226         ieee80211_node_t        *in;
2227 
2228         /*
2229          * assuming not 11n here. cope with 11n in phase-II
2230          */
2231         mpdu_size = (struct iwp_rx_mpdu_body_size *)(desc + 1);
2232         stat = (iwp_rx_phy_res_t *)sc->sc_rx_phy_res.buf;
2233         if (stat->cfg_phy_cnt > 20) {
2234                 return;
2235         }
2236 
2237         phyinfo = (struct iwp_rx_non_cfg_phy *)stat->non_cfg_phy;
2238         temp = LE_32(phyinfo->non_cfg_phy[IWP_RX_RES_AGC_IDX]);
2239         agc = (temp & IWP_OFDM_AGC_MSK) >> IWP_OFDM_AGC_BIT_POS;
2240 
2241         temp = LE_32(phyinfo->non_cfg_phy[IWP_RX_RES_RSSI_AB_IDX]);
2242         arssi = (temp & IWP_OFDM_RSSI_A_MSK) >> IWP_OFDM_RSSI_A_BIT_POS;
2243         brssi = (temp & IWP_OFDM_RSSI_B_MSK) >> IWP_OFDM_RSSI_B_BIT_POS;
2244 
2245         temp = LE_32(phyinfo->non_cfg_phy[IWP_RX_RES_RSSI_C_IDX]);
2246         crssi = (temp & IWP_OFDM_RSSI_C_MSK) >> IWP_OFDM_RSSI_C_BIT_POS;
2247 
2248         mrssi = MAX(arssi, brssi);
2249         mrssi = MAX(mrssi, crssi);
2250 
2251         t = mrssi - agc - IWP_RSSI_OFFSET;
2252         /*
2253          * convert dBm to percentage
2254          */
2255         rssi = (100 * 75 * 75 - (-20 - t) * (15 * 75 + 62 * (-20 - t)))
2256             / (75 * 75);
2257         if (rssi > 100) {
2258                 rssi = 100;
2259         }
2260         if (rssi < 1) {
2261                 rssi = 1;
2262         }
2263 
2264         /*
2265          * size of frame, not include FCS
2266          */
2267         len = LE_16(mpdu_size->byte_count);
2268         tail = (uint32_t *)((uint8_t *)(desc + 1) +
2269             sizeof (struct iwp_rx_mpdu_body_size) + len);
2270         bcopy(tail, &crc, 4);
2271 
2272         IWP_DBG((IWP_DEBUG_RX, "iwp_rx_mpdu_intr(): "
2273             "rx intr: idx=%d phy_len=%x len=%d "
2274             "rate=%x chan=%d tstamp=%x non_cfg_phy_count=%x "
2275             "cfg_phy_count=%x tail=%x", ring->cur, sizeof (*stat),
2276             len, stat->rate.r.s.rate, stat->channel,
2277             LE_32(stat->timestampl), stat->non_cfg_phy_cnt,
2278             stat->cfg_phy_cnt, LE_32(crc)));
2279 
2280         if ((len < 16) || (len > sc->sc_dmabuf_sz)) {
2281                 IWP_DBG((IWP_DEBUG_RX, "iwp_rx_mpdu_intr(): "
2282                     "rx frame oversize\n"));
2283                 return;
2284         }
2285 
2286         /*
2287          * discard Rx frames with bad CRC
2288          */
2289         if ((LE_32(crc) &
2290             (RX_RES_STATUS_NO_CRC32_ERROR | RX_RES_STATUS_NO_RXE_OVERFLOW)) !=
2291             (RX_RES_STATUS_NO_CRC32_ERROR | RX_RES_STATUS_NO_RXE_OVERFLOW)) {
2292                 IWP_DBG((IWP_DEBUG_RX, "iwp_rx_mpdu_intr(): "
2293                     "rx crc error tail: %x\n",
2294                     LE_32(crc)));
2295                 sc->sc_rx_err++;
2296                 return;
2297         }
2298 
2299         wh = (struct ieee80211_frame *)
2300             ((uint8_t *)(desc + 1)+ sizeof (struct iwp_rx_mpdu_body_size));
2301 
2302         if (IEEE80211_FC0_SUBTYPE_ASSOC_RESP == *(uint8_t *)wh) {
2303                 sc->sc_assoc_id = *((uint16_t *)(wh + 1) + 2);
2304                 IWP_DBG((IWP_DEBUG_RX, "iwp_rx_mpdu_intr(): "
2305                     "rx : association id = %x\n",
2306                     sc->sc_assoc_id));
2307         }
2308 
2309 #ifdef DEBUG
2310         if (iwp_dbg_flags & IWP_DEBUG_RX) {
2311                 ieee80211_dump_pkt((uint8_t *)wh, len, 0, 0);
2312         }
2313 #endif
2314 
2315         in = ieee80211_find_rxnode(ic, wh);
2316         mp = allocb(len, BPRI_MED);
2317         if (mp) {
2318                 (void) memcpy(mp->b_wptr, wh, len);
2319                 mp->b_wptr += len;
2320 
2321                 /*
2322                  * send the frame to the 802.11 layer
2323                  */
2324                 (void) ieee80211_input(ic, mp, in, rssi, 0);
2325         } else {
2326                 sc->sc_rx_nobuf++;
2327                 IWP_DBG((IWP_DEBUG_RX, "iwp_rx_mpdu_intr(): "
2328                     "alloc rx buf failed\n"));
2329         }
2330 
2331         /*
2332          * release node reference
2333          */
2334         ieee80211_free_node(in);
2335 }
2336 
2337 /*
2338  * process correlative affairs after a frame is sent.
2339  */
2340 static void
2341 iwp_tx_intr(iwp_sc_t *sc, iwp_rx_desc_t *desc)
2342 {
2343         ieee80211com_t *ic = &sc->sc_ic;
2344         iwp_tx_ring_t *ring = &sc->sc_txq[desc->hdr.qid & 0x3];
2345         iwp_tx_stat_t *stat = (iwp_tx_stat_t *)(desc + 1);
2346         iwp_amrr_t *amrr;
2347 
2348         if (NULL == ic->ic_bss) {
2349                 return;
2350         }
2351 
2352         amrr = (iwp_amrr_t *)ic->ic_bss;
2353 
2354         amrr->txcnt++;
2355         IWP_DBG((IWP_DEBUG_RATECTL, "iwp_tx_intr(): "
2356             "tx: %d cnt\n", amrr->txcnt));
2357 
2358         if (stat->ntries > 0) {
2359                 amrr->retrycnt++;
2360                 sc->sc_tx_retries++;
2361                 IWP_DBG((IWP_DEBUG_TX, "iwp_tx_intr(): "
2362                     "tx: %d retries\n",
2363                     sc->sc_tx_retries));
2364         }
2365 
2366         mutex_enter(&sc->sc_mt_lock);
2367         sc->sc_tx_timer = 0;
2368         mutex_exit(&sc->sc_mt_lock);
2369 
2370         mutex_enter(&sc->sc_tx_lock);
2371 
2372         ring->queued--;
2373         if (ring->queued < 0) {
2374                 ring->queued = 0;
2375         }
2376 
2377         if ((sc->sc_need_reschedule) && (ring->queued <= (ring->count >> 3))) {
2378                 sc->sc_need_reschedule = 0;
2379                 mutex_exit(&sc->sc_tx_lock);
2380                 mac_tx_update(ic->ic_mach);
2381                 mutex_enter(&sc->sc_tx_lock);
2382         }
2383 
2384         mutex_exit(&sc->sc_tx_lock);
2385 }
2386 
2387 /*
2388  * inform a given command has been executed
2389  */
2390 static void
2391 iwp_cmd_intr(iwp_sc_t *sc, iwp_rx_desc_t *desc)
2392 {
2393         if ((desc->hdr.qid & 7) != 4) {
2394                 return;
2395         }
2396 
2397         if (sc->sc_cmd_accum > 0) {
2398                 sc->sc_cmd_accum--;
2399                 return;
2400         }
2401 
2402         mutex_enter(&sc->sc_glock);
2403 
2404         sc->sc_cmd_flag = SC_CMD_FLG_DONE;
2405 
2406         cv_signal(&sc->sc_cmd_cv);
2407 
2408         mutex_exit(&sc->sc_glock);
2409 
2410         IWP_DBG((IWP_DEBUG_CMD, "iwp_cmd_intr(): "
2411             "qid=%x idx=%d flags=%x type=0x%x\n",
2412             desc->hdr.qid, desc->hdr.idx, desc->hdr.flags,
2413             desc->hdr.type));
2414 }
2415 
2416 /*
2417  * this function will be invoked when alive notification occur.
2418  */
2419 static void
2420 iwp_ucode_alive(iwp_sc_t *sc, iwp_rx_desc_t *desc)
2421 {
2422         uint32_t rv;
2423         struct iwp_calib_cfg_cmd cmd;
2424         struct iwp_alive_resp *ar =
2425             (struct iwp_alive_resp *)(desc + 1);
2426         struct iwp_calib_results *res_p = &sc->sc_calib_results;
2427 
2428         /*
2429          * the microcontroller is ready
2430          */
2431         IWP_DBG((IWP_DEBUG_FW, "iwp_ucode_alive(): "
2432             "microcode alive notification minor: %x major: %x type: "
2433             "%x subtype: %x\n",
2434             ar->ucode_minor, ar->ucode_minor, ar->ver_type, ar->ver_subtype));
2435 
2436 #ifdef  DEBUG
2437         if (LE_32(ar->is_valid) != UCODE_VALID_OK) {
2438                 IWP_DBG((IWP_DEBUG_FW, "iwp_ucode_alive(): "
2439                     "microcontroller initialization failed\n"));
2440         }
2441 #endif
2442 
2443         /*
2444          * determine if init alive or runtime alive.
2445          */
2446         if (INITIALIZE_SUBTYPE == ar->ver_subtype) {
2447                 IWP_DBG((IWP_DEBUG_FW, "iwp_ucode_alive(): "
2448                     "initialization alive received.\n"));
2449 
2450                 (void) memcpy(&sc->sc_card_alive_init, ar,
2451                     sizeof (struct iwp_init_alive_resp));
2452 
2453                 /*
2454                  * necessary configuration to NIC
2455                  */
2456                 mutex_enter(&sc->sc_glock);
2457 
2458                 rv = iwp_alive_common(sc);
2459                 if (rv != IWP_SUCCESS) {
2460                         cmn_err(CE_WARN, "iwp_ucode_alive(): "
2461                             "common alive process failed in init alive.\n");
2462                         mutex_exit(&sc->sc_glock);
2463                         return;
2464                 }
2465 
2466                 (void) memset(&cmd, 0, sizeof (cmd));
2467 
2468                 cmd.ucd_calib_cfg.once.is_enable = IWP_CALIB_INIT_CFG_ALL;
2469                 cmd.ucd_calib_cfg.once.start = IWP_CALIB_INIT_CFG_ALL;
2470                 cmd.ucd_calib_cfg.once.send_res = IWP_CALIB_INIT_CFG_ALL;
2471                 cmd.ucd_calib_cfg.flags = IWP_CALIB_INIT_CFG_ALL;
2472 
2473                 /*
2474                  * require ucode execute calibration
2475                  */
2476                 rv = iwp_cmd(sc, CALIBRATION_CFG_CMD, &cmd, sizeof (cmd), 1);
2477                 if (rv != IWP_SUCCESS) {
2478                         cmn_err(CE_WARN, "iwp_ucode_alive(): "
2479                             "failed to send calibration configure command.\n");
2480                         mutex_exit(&sc->sc_glock);
2481                         return;
2482                 }
2483 
2484                 mutex_exit(&sc->sc_glock);
2485 
2486         } else {        /* runtime alive */
2487 
2488                 IWP_DBG((IWP_DEBUG_FW, "iwp_ucode_alive(): "
2489                     "runtime alive received.\n"));
2490 
2491                 (void) memcpy(&sc->sc_card_alive_run, ar,
2492                     sizeof (struct iwp_alive_resp));
2493 
2494                 mutex_enter(&sc->sc_glock);
2495 
2496                 /*
2497                  * necessary configuration to NIC
2498                  */
2499                 rv = iwp_alive_common(sc);
2500                 if (rv != IWP_SUCCESS) {
2501                         cmn_err(CE_WARN, "iwp_ucode_alive(): "
2502                             "common alive process failed in run alive.\n");
2503                         mutex_exit(&sc->sc_glock);
2504                         return;
2505                 }
2506 
2507                 /*
2508                  * send the result of local oscilator calibration to uCode.
2509                  */
2510                 if (res_p->lo_res != NULL) {
2511                         rv = iwp_cmd(sc, REPLY_PHY_CALIBRATION_CMD,
2512                             res_p->lo_res, res_p->lo_res_len, 1);
2513                         if (rv != IWP_SUCCESS) {
2514                                 cmn_err(CE_WARN, "iwp_ucode_alive(): "
2515                                     "failed to send local"
2516                                     "oscilator calibration command.\n");
2517                                 mutex_exit(&sc->sc_glock);
2518                                 return;
2519                         }
2520 
2521                         DELAY(1000);
2522                 }
2523 
2524                 /*
2525                  * send the result of TX IQ calibration to uCode.
2526                  */
2527                 if (res_p->tx_iq_res != NULL) {
2528                         rv = iwp_cmd(sc, REPLY_PHY_CALIBRATION_CMD,
2529                             res_p->tx_iq_res, res_p->tx_iq_res_len, 1);
2530                         if (rv != IWP_SUCCESS) {
2531                                 cmn_err(CE_WARN, "iwp_ucode_alive(): "
2532                                     "failed to send TX IQ"
2533                                     "calibration command.\n");
2534                                 mutex_exit(&sc->sc_glock);
2535                                 return;
2536                         }
2537 
2538                         DELAY(1000);
2539                 }
2540 
2541                 /*
2542                  * send the result of TX IQ perd calibration to uCode.
2543                  */
2544                 if (res_p->tx_iq_perd_res != NULL) {
2545                         rv = iwp_cmd(sc, REPLY_PHY_CALIBRATION_CMD,
2546                             res_p->tx_iq_perd_res,
2547                             res_p->tx_iq_perd_res_len, 1);
2548                         if (rv != IWP_SUCCESS) {
2549                                 cmn_err(CE_WARN, "iwp_ucode_alive(): "
2550                                     "failed to send TX IQ perd"
2551                                     "calibration command.\n");
2552                                 mutex_exit(&sc->sc_glock);
2553                                 return;
2554                         }
2555 
2556                         DELAY(1000);
2557                 }
2558 
2559                 /*
2560                  * send the result of Base Band calibration to uCode.
2561                  */
2562                 if (res_p->base_band_res != NULL) {
2563                         rv = iwp_cmd(sc, REPLY_PHY_CALIBRATION_CMD,
2564                             res_p->base_band_res,
2565                             res_p->base_band_res_len, 1);
2566                         if (rv != IWP_SUCCESS) {
2567                                 cmn_err(CE_WARN, "iwp_ucode_alive(): "
2568                                     "failed to send Base Band"
2569                                     "calibration command.\n");
2570                                 mutex_exit(&sc->sc_glock);
2571                                 return;
2572                         }
2573 
2574                         DELAY(1000);
2575                 }
2576 
2577                 atomic_or_32(&sc->sc_flags, IWP_F_FW_INIT);
2578                 cv_signal(&sc->sc_ucode_cv);
2579 
2580                 mutex_exit(&sc->sc_glock);
2581         }
2582 
2583 }
2584 
2585 /*
2586  * deal with receiving frames, command response
2587  * and all notifications from ucode.
2588  */
2589 /* ARGSUSED */
2590 static uint_t
2591 iwp_rx_softintr(caddr_t arg, caddr_t unused)
2592 {
2593         iwp_sc_t *sc;
2594         ieee80211com_t *ic;
2595         iwp_rx_desc_t *desc;
2596         iwp_rx_data_t *data;
2597         uint32_t index;
2598 
2599         if (NULL == arg) {
2600                 return (DDI_INTR_UNCLAIMED);
2601         }
2602         sc = (iwp_sc_t *)arg;
2603         ic = &sc->sc_ic;
2604 
2605         /*
2606          * firmware has moved the index of the rx queue, driver get it,
2607          * and deal with it.
2608          */
2609         index = (sc->sc_shared->val0) & 0xfff;
2610 
2611         while (sc->sc_rxq.cur != index) {
2612                 data = &sc->sc_rxq.data[sc->sc_rxq.cur];
2613                 desc = (iwp_rx_desc_t *)data->dma_data.mem_va;
2614 
2615                 IWP_DBG((IWP_DEBUG_INTR, "iwp_rx_softintr(): "
2616                     "rx notification index = %d"
2617                     " cur = %d qid=%x idx=%d flags=%x type=%x len=%d\n",
2618                     index, sc->sc_rxq.cur, desc->hdr.qid, desc->hdr.idx,
2619                     desc->hdr.flags, desc->hdr.type, LE_32(desc->len)));
2620 
2621                 /*
2622                  * a command other than a tx need to be replied
2623                  */
2624                 if (!(desc->hdr.qid & 0x80) &&
2625                     (desc->hdr.type != REPLY_SCAN_CMD) &&
2626                     (desc->hdr.type != REPLY_TX)) {
2627                         iwp_cmd_intr(sc, desc);
2628                 }
2629 
2630                 switch (desc->hdr.type) {
2631                 case REPLY_RX_PHY_CMD:
2632                         iwp_rx_phy_intr(sc, desc);
2633                         break;
2634 
2635                 case REPLY_RX_MPDU_CMD:
2636                         iwp_rx_mpdu_intr(sc, desc);
2637                         break;
2638 
2639                 case REPLY_TX:
2640                         iwp_tx_intr(sc, desc);
2641                         break;
2642 
2643                 case REPLY_ALIVE:
2644                         iwp_ucode_alive(sc, desc);
2645                         break;
2646 
2647                 case CARD_STATE_NOTIFICATION:
2648                 {
2649                         uint32_t *status = (uint32_t *)(desc + 1);
2650 
2651                         IWP_DBG((IWP_DEBUG_RADIO, "iwp_rx_softintr(): "
2652                             "state changed to %x\n",
2653                             LE_32(*status)));
2654 
2655                         if (LE_32(*status) & 1) {
2656                                 /*
2657                                  * the radio button has to be pushed(OFF). It
2658                                  * is considered as a hw error, the
2659                                  * iwp_thread() tries to recover it after the
2660                                  * button is pushed again(ON)
2661                                  */
2662                                 cmn_err(CE_NOTE, "iwp_rx_softintr(): "
2663                                     "radio transmitter is off\n");
2664                                 sc->sc_ostate = sc->sc_ic.ic_state;
2665                                 ieee80211_new_state(&sc->sc_ic,
2666                                     IEEE80211_S_INIT, -1);
2667                                 atomic_or_32(&sc->sc_flags,
2668                                     IWP_F_HW_ERR_RECOVER | IWP_F_RADIO_OFF);
2669                         }
2670 
2671                         break;
2672                 }
2673 
2674                 case SCAN_START_NOTIFICATION:
2675                 {
2676                         iwp_start_scan_t *scan =
2677                             (iwp_start_scan_t *)(desc + 1);
2678 
2679                         IWP_DBG((IWP_DEBUG_SCAN, "iwp_rx_softintr(): "
2680                             "scanning channel %d status %x\n",
2681                             scan->chan, LE_32(scan->status)));
2682 
2683                         ic->ic_curchan = &ic->ic_sup_channels[scan->chan];
2684                         break;
2685                 }
2686 
2687                 case SCAN_COMPLETE_NOTIFICATION:
2688                 {
2689 #ifdef  DEBUG
2690                         iwp_stop_scan_t *scan =
2691                             (iwp_stop_scan_t *)(desc + 1);
2692 
2693                         IWP_DBG((IWP_DEBUG_SCAN, "iwp_rx_softintr(): "
2694                             "completed channel %d (burst of %d) status %02x\n",
2695                             scan->chan, scan->nchan, scan->status));
2696 #endif
2697 
2698                         sc->sc_scan_pending++;
2699                         break;
2700                 }
2701 
2702                 case STATISTICS_NOTIFICATION:
2703                 {
2704                         /*
2705                          * handle statistics notification
2706                          */
2707                         break;
2708                 }
2709 
2710                 case CALIBRATION_RES_NOTIFICATION:
2711                         iwp_save_calib_result(sc, desc);
2712                         break;
2713 
2714                 case CALIBRATION_COMPLETE_NOTIFICATION:
2715                         mutex_enter(&sc->sc_glock);
2716                         atomic_or_32(&sc->sc_flags, IWP_F_FW_INIT);
2717                         cv_signal(&sc->sc_ucode_cv);
2718                         mutex_exit(&sc->sc_glock);
2719                         break;
2720 
2721                 case MISSED_BEACONS_NOTIFICATION:
2722                 {
2723                         struct iwp_beacon_missed *miss =
2724                             (struct iwp_beacon_missed *)(desc + 1);
2725 
2726                         if ((ic->ic_state == IEEE80211_S_RUN) &&
2727                             (LE_32(miss->consecutive) > 50)) {
2728                                 cmn_err(CE_NOTE, "iwp: iwp_rx_softintr(): "
2729                                     "beacon missed %d/%d\n",
2730                                     LE_32(miss->consecutive),
2731                                     LE_32(miss->total));
2732                                 (void) ieee80211_new_state(ic,
2733                                     IEEE80211_S_INIT, -1);
2734                         }
2735                         break;
2736                 }
2737                 }
2738 
2739                 sc->sc_rxq.cur = (sc->sc_rxq.cur + 1) % RX_QUEUE_SIZE;
2740         }
2741 
2742         /*
2743          * driver dealt with what received in rx queue and tell the information
2744          * to the firmware.
2745          */
2746         index = (0 == index) ? RX_QUEUE_SIZE - 1 : index - 1;
2747         IWP_WRITE(sc, FH_RSCSR_CHNL0_RBDCB_WPTR_REG, index & (~7));
2748 
2749         /*
2750          * re-enable interrupts
2751          */
2752         IWP_WRITE(sc, CSR_INT_MASK, CSR_INI_SET_MASK);
2753 
2754         return (DDI_INTR_CLAIMED);
2755 }
2756 
2757 /*
2758  * the handle of interrupt
2759  */
2760 /* ARGSUSED */
2761 static uint_t
2762 iwp_intr(caddr_t arg, caddr_t unused)
2763 {
2764         iwp_sc_t *sc;
2765         uint32_t r, rfh;
2766 
2767         if (NULL == arg) {
2768                 return (DDI_INTR_UNCLAIMED);
2769         }
2770         sc = (iwp_sc_t *)arg;
2771 
2772         r = IWP_READ(sc, CSR_INT);
2773         if (0 == r || 0xffffffff == r) {
2774                 return (DDI_INTR_UNCLAIMED);
2775         }
2776 
2777         IWP_DBG((IWP_DEBUG_INTR, "iwp_intr(): "
2778             "interrupt reg %x\n", r));
2779 
2780         rfh = IWP_READ(sc, CSR_FH_INT_STATUS);
2781 
2782         IWP_DBG((IWP_DEBUG_INTR, "iwp_intr(): "
2783             "FH interrupt reg %x\n", rfh));
2784 
2785         /*
2786          * disable interrupts
2787          */
2788         IWP_WRITE(sc, CSR_INT_MASK, 0);
2789 
2790         /*
2791          * ack interrupts
2792          */
2793         IWP_WRITE(sc, CSR_INT, r);
2794         IWP_WRITE(sc, CSR_FH_INT_STATUS, rfh);
2795 
2796         if (r & (BIT_INT_SWERROR | BIT_INT_ERR)) {
2797                 IWP_DBG((IWP_DEBUG_FW, "iwp_intr(): "
2798                     "fatal firmware error\n"));
2799                 iwp_stop(sc);
2800                 sc->sc_ostate = sc->sc_ic.ic_state;
2801 
2802                 /* notify upper layer */
2803                 if (!IWP_CHK_FAST_RECOVER(sc)) {
2804                         ieee80211_new_state(&sc->sc_ic, IEEE80211_S_INIT, -1);
2805                 }
2806 
2807                 atomic_or_32(&sc->sc_flags, IWP_F_HW_ERR_RECOVER);
2808                 return (DDI_INTR_CLAIMED);
2809         }
2810 
2811         if (r & BIT_INT_RF_KILL) {
2812                 uint32_t tmp = IWP_READ(sc, CSR_GP_CNTRL);
2813                 if (tmp & (1 << 27)) {
2814                         cmn_err(CE_NOTE, "RF switch: radio on\n");
2815                 }
2816         }
2817 
2818         if ((r & (BIT_INT_FH_RX | BIT_INT_SW_RX)) ||
2819             (rfh & FH_INT_RX_MASK)) {
2820                 (void) ddi_intr_trigger_softint(sc->sc_soft_hdl, NULL);
2821                 return (DDI_INTR_CLAIMED);
2822         }
2823 
2824         if (r & BIT_INT_FH_TX) {
2825                 mutex_enter(&sc->sc_glock);
2826                 atomic_or_32(&sc->sc_flags, IWP_F_PUT_SEG);
2827                 cv_signal(&sc->sc_put_seg_cv);
2828                 mutex_exit(&sc->sc_glock);
2829         }
2830 
2831 #ifdef  DEBUG
2832         if (r & BIT_INT_ALIVE)      {
2833                 IWP_DBG((IWP_DEBUG_FW, "iwp_intr(): "
2834                     "firmware initialized.\n"));
2835         }
2836 #endif
2837 
2838         /*
2839          * re-enable interrupts
2840          */
2841         IWP_WRITE(sc, CSR_INT_MASK, CSR_INI_SET_MASK);
2842 
2843         return (DDI_INTR_CLAIMED);
2844 }
2845 
2846 static uint8_t
2847 iwp_rate_to_plcp(int rate)
2848 {
2849         uint8_t ret;
2850 
2851         switch (rate) {
2852         /*
2853          * CCK rates
2854          */
2855         case 2:
2856                 ret = 0xa;
2857                 break;
2858 
2859         case 4:
2860                 ret = 0x14;
2861                 break;
2862 
2863         case 11:
2864                 ret = 0x37;
2865                 break;
2866 
2867         case 22:
2868                 ret = 0x6e;
2869                 break;
2870 
2871         /*
2872          * OFDM rates
2873          */
2874         case 12:
2875                 ret = 0xd;
2876                 break;
2877 
2878         case 18:
2879                 ret = 0xf;
2880                 break;
2881 
2882         case 24:
2883                 ret = 0x5;
2884                 break;
2885 
2886         case 36:
2887                 ret = 0x7;
2888                 break;
2889 
2890         case 48:
2891                 ret = 0x9;
2892                 break;
2893 
2894         case 72:
2895                 ret = 0xb;
2896                 break;
2897 
2898         case 96:
2899                 ret = 0x1;
2900                 break;
2901 
2902         case 108:
2903                 ret = 0x3;
2904                 break;
2905 
2906         default:
2907                 ret = 0;
2908                 break;
2909         }
2910 
2911         return (ret);
2912 }
2913 
2914 /*
2915  * invoked by GLD send frames
2916  */
2917 static mblk_t *
2918 iwp_m_tx(void *arg, mblk_t *mp)
2919 {
2920         iwp_sc_t        *sc;
2921         ieee80211com_t  *ic;
2922         mblk_t          *next;
2923 
2924         if (NULL == arg) {
2925                 return (NULL);
2926         }
2927         sc = (iwp_sc_t *)arg;
2928         ic = &sc->sc_ic;
2929 
2930         if (sc->sc_flags & IWP_F_SUSPEND) {
2931                 freemsgchain(mp);
2932                 return (NULL);
2933         }
2934 
2935         if (ic->ic_state != IEEE80211_S_RUN) {
2936                 freemsgchain(mp);
2937                 return (NULL);
2938         }
2939 
2940         if ((sc->sc_flags & IWP_F_HW_ERR_RECOVER) &&
2941             IWP_CHK_FAST_RECOVER(sc)) {
2942                 IWP_DBG((IWP_DEBUG_FW, "iwp_m_tx(): "
2943                     "hold queue\n"));
2944                 return (mp);
2945         }
2946 
2947 
2948         while (mp != NULL) {
2949                 next = mp->b_next;
2950                 mp->b_next = NULL;
2951                 if (iwp_send(ic, mp, IEEE80211_FC0_TYPE_DATA) != 0) {
2952                         mp->b_next = next;
2953                         break;
2954                 }
2955                 mp = next;
2956         }
2957 
2958         return (mp);
2959 }
2960 
2961 /*
2962  * send frames
2963  */
2964 static int
2965 iwp_send(ieee80211com_t *ic, mblk_t *mp, uint8_t type)
2966 {
2967         iwp_sc_t *sc;
2968         iwp_tx_ring_t *ring;
2969         iwp_tx_desc_t *desc;
2970         iwp_tx_data_t *data;
2971         iwp_tx_data_t *desc_data;
2972         iwp_cmd_t *cmd;
2973         iwp_tx_cmd_t *tx;
2974         ieee80211_node_t *in;
2975         struct ieee80211_frame *wh;
2976         struct ieee80211_key *k = NULL;
2977         mblk_t *m, *m0;
2978         int hdrlen, len, len0, mblen, off, err = IWP_SUCCESS;
2979         uint16_t masks = 0;
2980         uint32_t rate, s_id = 0;
2981 
2982         if (NULL == ic) {
2983                 return (IWP_FAIL);
2984         }
2985         sc = (iwp_sc_t *)ic;
2986 
2987         if (sc->sc_flags & IWP_F_SUSPEND) {
2988                 if ((type & IEEE80211_FC0_TYPE_MASK) !=
2989                     IEEE80211_FC0_TYPE_DATA) {
2990                         freemsg(mp);
2991                 }
2992                 err = IWP_FAIL;
2993                 goto exit;
2994         }
2995 
2996         mutex_enter(&sc->sc_tx_lock);
2997         ring = &sc->sc_txq[0];
2998         data = &ring->data[ring->cur];
2999         cmd = data->cmd;
3000         bzero(cmd, sizeof (*cmd));
3001 
3002         ring->cur = (ring->cur + 1) % ring->count;
3003 
3004         /*
3005          * Need reschedule TX if TX buffer is full.
3006          */
3007         if (ring->queued > ring->count - IWP_MAX_WIN_SIZE) {
3008                 IWP_DBG((IWP_DEBUG_TX, "iwp_send(): "
3009                 "no txbuf\n"));
3010 
3011                 sc->sc_need_reschedule = 1;
3012                 mutex_exit(&sc->sc_tx_lock);
3013 
3014                 if ((type & IEEE80211_FC0_TYPE_MASK) !=
3015                     IEEE80211_FC0_TYPE_DATA) {
3016                         freemsg(mp);
3017                 }
3018                 sc->sc_tx_nobuf++;
3019                 err = IWP_FAIL;
3020                 goto exit;
3021         }
3022 
3023         ring->queued++;
3024 
3025         mutex_exit(&sc->sc_tx_lock);
3026 
3027         hdrlen = ieee80211_hdrspace(ic, mp->b_rptr);
3028 
3029         m = allocb(msgdsize(mp) + 32, BPRI_MED);
3030         if (NULL == m) { /* can not alloc buf, drop this package */
3031                 cmn_err(CE_WARN, "iwp_send(): "
3032                     "failed to allocate msgbuf\n");
3033                 freemsg(mp);
3034 
3035                 mutex_enter(&sc->sc_tx_lock);
3036                 ring->queued--;
3037                 if ((sc->sc_need_reschedule) && (ring->queued <= 0)) {
3038                         sc->sc_need_reschedule = 0;
3039                         mutex_exit(&sc->sc_tx_lock);
3040                         mac_tx_update(ic->ic_mach);
3041                         mutex_enter(&sc->sc_tx_lock);
3042                 }
3043                 mutex_exit(&sc->sc_tx_lock);
3044 
3045                 err = IWP_SUCCESS;
3046                 goto exit;
3047         }
3048 
3049         for (off = 0, m0 = mp; m0 != NULL; m0 = m0->b_cont) {
3050                 mblen = MBLKL(m0);
3051                 (void) memcpy(m->b_rptr + off, m0->b_rptr, mblen);
3052                 off += mblen;
3053         }
3054 
3055         m->b_wptr += off;
3056 
3057         wh = (struct ieee80211_frame *)m->b_rptr;
3058 
3059         /*
3060          * determine send which AP or station in IBSS
3061          */
3062         in = ieee80211_find_txnode(ic, wh->i_addr1);
3063         if (NULL == in) {
3064                 cmn_err(CE_WARN, "iwp_send(): "
3065                     "failed to find tx node\n");
3066                 freemsg(mp);
3067                 freemsg(m);
3068                 sc->sc_tx_err++;
3069 
3070                 mutex_enter(&sc->sc_tx_lock);
3071                 ring->queued--;
3072                 if ((sc->sc_need_reschedule) && (ring->queued <= 0)) {
3073                         sc->sc_need_reschedule = 0;
3074                         mutex_exit(&sc->sc_tx_lock);
3075                         mac_tx_update(ic->ic_mach);
3076                         mutex_enter(&sc->sc_tx_lock);
3077                 }
3078                 mutex_exit(&sc->sc_tx_lock);
3079 
3080                 err = IWP_SUCCESS;
3081                 goto exit;
3082         }
3083 
3084         /*
3085          * Net80211 module encapsulate outbound data frames.
3086          * Add some feilds of 80211 frame.
3087          */
3088         if ((type & IEEE80211_FC0_TYPE_MASK) ==
3089             IEEE80211_FC0_TYPE_DATA) {
3090                 (void) ieee80211_encap(ic, m, in);
3091         }
3092 
3093         freemsg(mp);
3094 
3095         cmd->hdr.type = REPLY_TX;
3096         cmd->hdr.flags = 0;
3097         cmd->hdr.qid = ring->qid;
3098 
3099         tx = (iwp_tx_cmd_t *)cmd->data;
3100         tx->tx_flags = 0;
3101 
3102         if (IEEE80211_IS_MULTICAST(wh->i_addr1)) {
3103                 tx->tx_flags &= ~(LE_32(TX_CMD_FLG_ACK_MSK));
3104         } else {
3105                 tx->tx_flags |= LE_32(TX_CMD_FLG_ACK_MSK);
3106         }
3107 
3108         if (wh->i_fc[1] & IEEE80211_FC1_WEP) {
3109                 k = ieee80211_crypto_encap(ic, m);
3110                 if (NULL == k) {
3111                         freemsg(m);
3112                         sc->sc_tx_err++;
3113 
3114                         mutex_enter(&sc->sc_tx_lock);
3115                         ring->queued--;
3116                         if ((sc->sc_need_reschedule) && (ring->queued <= 0)) {
3117                                 sc->sc_need_reschedule = 0;
3118                                 mutex_exit(&sc->sc_tx_lock);
3119                                 mac_tx_update(ic->ic_mach);
3120                                 mutex_enter(&sc->sc_tx_lock);
3121                         }
3122                         mutex_exit(&sc->sc_tx_lock);
3123 
3124                         err = IWP_SUCCESS;
3125                         goto exit;
3126                 }
3127 
3128                 /* packet header may have moved, reset our local pointer */
3129                 wh = (struct ieee80211_frame *)m->b_rptr;
3130         }
3131 
3132         len = msgdsize(m);
3133 
3134 #ifdef DEBUG
3135         if (iwp_dbg_flags & IWP_DEBUG_TX) {
3136                 ieee80211_dump_pkt((uint8_t *)wh, hdrlen, 0, 0);
3137         }
3138 #endif
3139 
3140         tx->rts_retry_limit = IWP_TX_RTS_RETRY_LIMIT;
3141         tx->data_retry_limit = IWP_TX_DATA_RETRY_LIMIT;
3142 
3143         /*
3144          * specific TX parameters for management frames
3145          */
3146         if ((wh->i_fc[0] & IEEE80211_FC0_TYPE_MASK) ==
3147             IEEE80211_FC0_TYPE_MGT) {
3148                 /*
3149                  * mgmt frames are sent at 1M
3150                  */
3151                 if ((in->in_rates.ir_rates[0] &
3152                     IEEE80211_RATE_VAL) != 0) {
3153                         rate = in->in_rates.ir_rates[0] & IEEE80211_RATE_VAL;
3154                 } else {
3155                         rate = 2;
3156                 }
3157 
3158                 tx->tx_flags |= LE_32(TX_CMD_FLG_SEQ_CTL_MSK);
3159 
3160                 /*
3161                  * tell h/w to set timestamp in probe responses
3162                  */
3163                 if ((wh->i_fc[0] & IEEE80211_FC0_SUBTYPE_MASK) ==
3164                     IEEE80211_FC0_SUBTYPE_PROBE_RESP) {
3165                         tx->tx_flags |= LE_32(TX_CMD_FLG_TSF_MSK);
3166 
3167                         tx->data_retry_limit = 3;
3168                         if (tx->data_retry_limit < tx->rts_retry_limit) {
3169                                 tx->rts_retry_limit = tx->data_retry_limit;
3170                         }
3171                 }
3172 
3173                 if (((wh->i_fc[0] & IEEE80211_FC0_SUBTYPE_MASK) ==
3174                     IEEE80211_FC0_SUBTYPE_ASSOC_REQ) ||
3175                     ((wh->i_fc[0] & IEEE80211_FC0_SUBTYPE_MASK) ==
3176                     IEEE80211_FC0_SUBTYPE_REASSOC_REQ)) {
3177                         tx->timeout.pm_frame_timeout = LE_16(3);
3178                 } else {
3179                         tx->timeout.pm_frame_timeout = LE_16(2);
3180                 }
3181 
3182         } else {
3183                 /*
3184                  * do it here for the software way rate scaling.
3185                  * later for rate scaling in hardware.
3186                  *
3187                  * now the txrate is determined in tx cmd flags, set to the
3188                  * max value 54M for 11g and 11M for 11b originally.
3189                  */
3190                 if (ic->ic_fixed_rate != IEEE80211_FIXED_RATE_NONE) {
3191                         rate = ic->ic_fixed_rate;
3192                 } else {
3193                         if ((in->in_rates.ir_rates[in->in_txrate] &
3194                             IEEE80211_RATE_VAL) != 0) {
3195                                 rate = in->in_rates.
3196                                     ir_rates[in->in_txrate] &
3197                                     IEEE80211_RATE_VAL;
3198                         }
3199                 }
3200 
3201                 tx->tx_flags |= LE_32(TX_CMD_FLG_SEQ_CTL_MSK);
3202 
3203                 tx->timeout.pm_frame_timeout = 0;
3204         }
3205 
3206         IWP_DBG((IWP_DEBUG_TX, "iwp_send(): "
3207             "tx rate[%d of %d] = %x",
3208             in->in_txrate, in->in_rates.ir_nrates, rate));
3209 
3210         len0 = roundup(4 + sizeof (iwp_tx_cmd_t) + hdrlen, 4);
3211         if (len0 != (4 + sizeof (iwp_tx_cmd_t) + hdrlen)) {
3212                 tx->tx_flags |= LE_32(TX_CMD_FLG_MH_PAD_MSK);
3213         }
3214 
3215         /*
3216          * retrieve destination node's id
3217          */
3218         if (IEEE80211_IS_MULTICAST(wh->i_addr1)) {
3219                 tx->sta_id = IWP_BROADCAST_ID;
3220         } else {
3221                 tx->sta_id = IWP_AP_ID;
3222         }
3223 
3224         if (2 == rate || 4 == rate || 11 == rate || 22 == rate) {
3225                 masks |= RATE_MCS_CCK_MSK;
3226         }
3227 
3228         masks |= RATE_MCS_ANT_B_MSK;
3229         tx->rate.r.rate_n_flags = LE_32(iwp_rate_to_plcp(rate) | masks);
3230 
3231         IWP_DBG((IWP_DEBUG_TX, "iwp_send(): "
3232             "tx flag = %x",
3233             tx->tx_flags));
3234 
3235         tx->stop_time.life_time  = LE_32(0xffffffff);
3236 
3237         tx->len = LE_16(len);
3238 
3239         tx->dram_lsb_ptr =
3240             LE_32(data->paddr_cmd + 4 + offsetof(iwp_tx_cmd_t, scratch));
3241         tx->dram_msb_ptr = 0;
3242         tx->driver_txop = 0;
3243         tx->next_frame_len = 0;
3244 
3245         (void) memcpy(tx + 1, m->b_rptr, hdrlen);
3246         m->b_rptr += hdrlen;
3247         (void) memcpy(data->dma_data.mem_va, m->b_rptr, len - hdrlen);
3248 
3249         IWP_DBG((IWP_DEBUG_TX, "iwp_send(): "
3250             "sending data: qid=%d idx=%d len=%d",
3251             ring->qid, ring->cur, len));
3252 
3253         /*
3254          * first segment includes the tx cmd plus the 802.11 header,
3255          * the second includes the remaining of the 802.11 frame.
3256          */
3257         mutex_enter(&sc->sc_tx_lock);
3258 
3259         cmd->hdr.idx = ring->desc_cur;
3260 
3261         desc_data = &ring->data[ring->desc_cur];
3262         desc = desc_data->desc;
3263         bzero(desc, sizeof (*desc));
3264         desc->val0 = 2 << 24;
3265         desc->pa[0].tb1_addr = data->paddr_cmd;
3266         desc->pa[0].val1 = ((len0 << 4) & 0xfff0) |
3267             ((data->dma_data.cookie.dmac_address & 0xffff) << 16);
3268         desc->pa[0].val2 =
3269             ((data->dma_data.cookie.dmac_address & 0xffff0000) >> 16) |
3270             ((len - hdrlen) << 20);
3271         IWP_DBG((IWP_DEBUG_TX, "iwp_send(): "
3272             "phy addr1 = 0x%x phy addr2 = 0x%x "
3273             "len1 = 0x%x, len2 = 0x%x val1 = 0x%x val2 = 0x%x",
3274             data->paddr_cmd, data->dma_data.cookie.dmac_address,
3275             len0, len - hdrlen, desc->pa[0].val1, desc->pa[0].val2));
3276 
3277         /*
3278          * kick ring
3279          */
3280         s_id = tx->sta_id;
3281 
3282         sc->sc_shared->queues_byte_cnt_tbls[ring->qid].
3283             tfd_offset[ring->desc_cur].val =
3284             (8 + len) | (s_id << 12);
3285         if (ring->desc_cur < IWP_MAX_WIN_SIZE) {
3286                 sc->sc_shared->queues_byte_cnt_tbls[ring->qid].
3287                     tfd_offset[IWP_QUEUE_SIZE + ring->desc_cur].val =
3288                     (8 + len) | (s_id << 12);
3289         }
3290 
3291         IWP_DMA_SYNC(data->dma_data, DDI_DMA_SYNC_FORDEV);
3292         IWP_DMA_SYNC(ring->dma_desc, DDI_DMA_SYNC_FORDEV);
3293 
3294         ring->desc_cur = (ring->desc_cur + 1) % ring->count;
3295         IWP_WRITE(sc, HBUS_TARG_WRPTR, ring->qid << 8 | ring->desc_cur);
3296 
3297         mutex_exit(&sc->sc_tx_lock);
3298         freemsg(m);
3299 
3300         /*
3301          * release node reference
3302          */
3303         ieee80211_free_node(in);
3304 
3305         ic->ic_stats.is_tx_bytes += len;
3306         ic->ic_stats.is_tx_frags++;
3307 
3308         mutex_enter(&sc->sc_mt_lock);
3309         if (0 == sc->sc_tx_timer) {
3310                 sc->sc_tx_timer = 4;
3311         }
3312         mutex_exit(&sc->sc_mt_lock);
3313 
3314 exit:
3315         return (err);
3316 }
3317 
3318 /*
3319  * invoked by GLD to deal with IOCTL affaires
3320  */
3321 static void
3322 iwp_m_ioctl(void* arg, queue_t *wq, mblk_t *mp)
3323 {
3324         iwp_sc_t        *sc;
3325         ieee80211com_t  *ic;
3326         int             err = EINVAL;
3327 
3328         if (NULL == arg) {
3329                 return;
3330         }
3331         sc = (iwp_sc_t *)arg;
3332         ic = &sc->sc_ic;
3333 
3334         err = ieee80211_ioctl(ic, wq, mp);
3335         if (ENETRESET == err) {
3336                 /*
3337                  * This is special for the hidden AP connection.
3338                  * In any case, we should make sure only one 'scan'
3339                  * in the driver for a 'connect' CLI command. So
3340                  * when connecting to a hidden AP, the scan is just
3341                  * sent out to the air when we know the desired
3342                  * essid of the AP we want to connect.
3343                  */
3344                 if (ic->ic_des_esslen) {
3345                         if (sc->sc_flags & IWP_F_RUNNING) {
3346                                 iwp_m_stop(sc);
3347                                 (void) iwp_m_start(sc);
3348                                 (void) ieee80211_new_state(ic,
3349                                     IEEE80211_S_SCAN, -1);
3350                         }
3351                 }
3352         }
3353 }
3354 
3355 /*
3356  * Call back functions for get/set proporty
3357  */
3358 static int
3359 iwp_m_getprop(void *arg, const char *pr_name, mac_prop_id_t wldp_pr_num,
3360     uint_t wldp_length, void *wldp_buf)
3361 {
3362         iwp_sc_t        *sc;
3363         int             err = EINVAL;
3364 
3365         if (NULL == arg) {
3366                 return (EINVAL);
3367         }
3368         sc = (iwp_sc_t *)arg;
3369 
3370         err = ieee80211_getprop(&sc->sc_ic, pr_name, wldp_pr_num,
3371             wldp_length, wldp_buf);
3372 
3373         return (err);
3374 }
3375 
3376 static void
3377 iwp_m_propinfo(void *arg, const char *pr_name, mac_prop_id_t wldp_pr_num,
3378     mac_prop_info_handle_t prh)
3379 {
3380         iwp_sc_t        *sc;
3381 
3382         sc = (iwp_sc_t *)arg;
3383         ieee80211_propinfo(&sc->sc_ic, pr_name, wldp_pr_num, prh);
3384 }
3385 
3386 static int
3387 iwp_m_setprop(void *arg, const char *pr_name, mac_prop_id_t wldp_pr_num,
3388     uint_t wldp_length, const void *wldp_buf)
3389 {
3390         iwp_sc_t                *sc;
3391         ieee80211com_t          *ic;
3392         int                     err = EINVAL;
3393 
3394         if (NULL == arg) {
3395                 return (EINVAL);
3396         }
3397         sc = (iwp_sc_t *)arg;
3398         ic = &sc->sc_ic;
3399 
3400         err = ieee80211_setprop(ic, pr_name, wldp_pr_num, wldp_length,
3401             wldp_buf);
3402 
3403         if (err == ENETRESET) {
3404                 if (ic->ic_des_esslen) {
3405                         if (sc->sc_flags & IWP_F_RUNNING) {
3406                                 iwp_m_stop(sc);
3407                                 (void) iwp_m_start(sc);
3408                                 (void) ieee80211_new_state(ic,
3409                                     IEEE80211_S_SCAN, -1);
3410                         }
3411                 }
3412                 err = 0;
3413         }
3414         return (err);
3415 }
3416 
3417 /*
3418  * invoked by GLD supply statistics NIC and driver
3419  */
3420 static int
3421 iwp_m_stat(void *arg, uint_t stat, uint64_t *val)
3422 {
3423         iwp_sc_t        *sc;
3424         ieee80211com_t  *ic;
3425         ieee80211_node_t *in;
3426 
3427         if (NULL == arg) {
3428                 return (EINVAL);
3429         }
3430         sc = (iwp_sc_t *)arg;
3431         ic = &sc->sc_ic;
3432 
3433         mutex_enter(&sc->sc_glock);
3434 
3435         switch (stat) {
3436         case MAC_STAT_IFSPEED:
3437                 in = ic->ic_bss;
3438                 *val = ((IEEE80211_FIXED_RATE_NONE == ic->ic_fixed_rate) ?
3439                     IEEE80211_RATE(in->in_txrate) :
3440                     ic->ic_fixed_rate) / 2 * 1000000;
3441                 break;
3442         case MAC_STAT_NOXMTBUF:
3443                 *val = sc->sc_tx_nobuf;
3444                 break;
3445         case MAC_STAT_NORCVBUF:
3446                 *val = sc->sc_rx_nobuf;
3447                 break;
3448         case MAC_STAT_IERRORS:
3449                 *val = sc->sc_rx_err;
3450                 break;
3451         case MAC_STAT_RBYTES:
3452                 *val = ic->ic_stats.is_rx_bytes;
3453                 break;
3454         case MAC_STAT_IPACKETS:
3455                 *val = ic->ic_stats.is_rx_frags;
3456                 break;
3457         case MAC_STAT_OBYTES:
3458                 *val = ic->ic_stats.is_tx_bytes;
3459                 break;
3460         case MAC_STAT_OPACKETS:
3461                 *val = ic->ic_stats.is_tx_frags;
3462                 break;
3463         case MAC_STAT_OERRORS:
3464         case WIFI_STAT_TX_FAILED:
3465                 *val = sc->sc_tx_err;
3466                 break;
3467         case WIFI_STAT_TX_RETRANS:
3468                 *val = sc->sc_tx_retries;
3469                 break;
3470         case WIFI_STAT_FCS_ERRORS:
3471         case WIFI_STAT_WEP_ERRORS:
3472         case WIFI_STAT_TX_FRAGS:
3473         case WIFI_STAT_MCAST_TX:
3474         case WIFI_STAT_RTS_SUCCESS:
3475         case WIFI_STAT_RTS_FAILURE:
3476         case WIFI_STAT_ACK_FAILURE:
3477         case WIFI_STAT_RX_FRAGS:
3478         case WIFI_STAT_MCAST_RX:
3479         case WIFI_STAT_RX_DUPS:
3480                 mutex_exit(&sc->sc_glock);
3481                 return (ieee80211_stat(ic, stat, val));
3482         default:
3483                 mutex_exit(&sc->sc_glock);
3484                 return (ENOTSUP);
3485         }
3486 
3487         mutex_exit(&sc->sc_glock);
3488 
3489         return (IWP_SUCCESS);
3490 
3491 }
3492 
3493 /*
3494  * invoked by GLD to start or open NIC
3495  */
3496 static int
3497 iwp_m_start(void *arg)
3498 {
3499         iwp_sc_t *sc;
3500         ieee80211com_t  *ic;
3501         int err = IWP_FAIL;
3502 
3503         if (NULL == arg) {
3504                 return (EINVAL);
3505         }
3506         sc = (iwp_sc_t *)arg;
3507         ic = &sc->sc_ic;
3508 
3509         err = iwp_init(sc);
3510         if (err != IWP_SUCCESS) {
3511                 /*
3512                  * The hw init err(eg. RF is OFF). Return Success to make
3513                  * the 'plumb' succeed. The iwp_thread() tries to re-init
3514                  * background.
3515                  */
3516                 atomic_or_32(&sc->sc_flags, IWP_F_HW_ERR_RECOVER);
3517                 return (IWP_SUCCESS);
3518         }
3519 
3520         ieee80211_new_state(ic, IEEE80211_S_INIT, -1);
3521 
3522         atomic_or_32(&sc->sc_flags, IWP_F_RUNNING);
3523 
3524         return (IWP_SUCCESS);
3525 }
3526 
3527 /*
3528  * invoked by GLD to stop or down NIC
3529  */
3530 static void
3531 iwp_m_stop(void *arg)
3532 {
3533         iwp_sc_t *sc;
3534         ieee80211com_t  *ic;
3535 
3536         if (NULL == arg) {
3537                 return;
3538         }
3539         sc = (iwp_sc_t *)arg;
3540         ic = &sc->sc_ic;
3541 
3542         iwp_stop(sc);
3543 
3544         /*
3545          * release buffer for calibration
3546          */
3547         iwp_release_calib_buffer(sc);
3548 
3549         ieee80211_new_state(ic, IEEE80211_S_INIT, -1);
3550 
3551         atomic_and_32(&sc->sc_flags, ~IWP_F_HW_ERR_RECOVER);
3552         atomic_and_32(&sc->sc_flags, ~IWP_F_RATE_AUTO_CTL);
3553 
3554         atomic_and_32(&sc->sc_flags, ~IWP_F_RUNNING);
3555         atomic_and_32(&sc->sc_flags, ~IWP_F_SCANNING);
3556 }
3557 
3558 /*
3559  * invoked by GLD to configure NIC
3560  */
3561 static int
3562 iwp_m_unicst(void *arg, const uint8_t *macaddr)
3563 {
3564         iwp_sc_t *sc;
3565         ieee80211com_t  *ic;
3566         int err = IWP_SUCCESS;
3567 
3568         if (NULL == arg) {
3569                 return (EINVAL);
3570         }
3571         sc = (iwp_sc_t *)arg;
3572         ic = &sc->sc_ic;
3573 
3574         if (!IEEE80211_ADDR_EQ(ic->ic_macaddr, macaddr)) {
3575                 IEEE80211_ADDR_COPY(ic->ic_macaddr, macaddr);
3576                 mutex_enter(&sc->sc_glock);
3577                 err = iwp_config(sc);
3578                 mutex_exit(&sc->sc_glock);
3579                 if (err != IWP_SUCCESS) {
3580                         cmn_err(CE_WARN, "iwp_m_unicst(): "
3581                             "failed to configure device\n");
3582                         goto fail;
3583                 }
3584         }
3585 
3586         return (err);
3587 
3588 fail:
3589         return (err);
3590 }
3591 
3592 /* ARGSUSED */
3593 static int
3594 iwp_m_multicst(void *arg, boolean_t add, const uint8_t *m)
3595 {
3596         return (IWP_SUCCESS);
3597 }
3598 
3599 /* ARGSUSED */
3600 static int
3601 iwp_m_promisc(void *arg, boolean_t on)
3602 {
3603         return (IWP_SUCCESS);
3604 }
3605 
3606 /*
3607  * kernel thread to deal with exceptional situation
3608  */
3609 static void
3610 iwp_thread(iwp_sc_t *sc)
3611 {
3612         ieee80211com_t  *ic = &sc->sc_ic;
3613         clock_t clk;
3614         int err, n = 0, timeout = 0;
3615         uint32_t tmp;
3616 #ifdef  DEBUG
3617         int times = 0;
3618 #endif
3619 
3620         while (sc->sc_mf_thread_switch) {
3621                 tmp = IWP_READ(sc, CSR_GP_CNTRL);
3622                 if (tmp & CSR_GP_CNTRL_REG_FLAG_HW_RF_KILL_SW) {
3623                         atomic_and_32(&sc->sc_flags, ~IWP_F_RADIO_OFF);
3624                 } else {
3625                         atomic_or_32(&sc->sc_flags, IWP_F_RADIO_OFF);
3626                 }
3627 
3628                 /*
3629                  * If  in SUSPEND or the RF is OFF, do nothing.
3630                  */
3631                 if (sc->sc_flags & IWP_F_RADIO_OFF) {
3632                         delay(drv_usectohz(100000));
3633                         continue;
3634                 }
3635 
3636                 /*
3637                  * recovery fatal error
3638                  */
3639                 if (ic->ic_mach &&
3640                     (sc->sc_flags & IWP_F_HW_ERR_RECOVER)) {
3641 
3642                         IWP_DBG((IWP_DEBUG_FW, "iwp_thread(): "
3643                             "try to recover fatal hw error: %d\n", times++));
3644 
3645                         iwp_stop(sc);
3646 
3647                         if (IWP_CHK_FAST_RECOVER(sc)) {
3648                                 /* save runtime configuration */
3649                                 bcopy(&sc->sc_config, &sc->sc_config_save,
3650                                     sizeof (sc->sc_config));
3651                         } else {
3652                                 ieee80211_new_state(ic, IEEE80211_S_INIT, -1);
3653                                 delay(drv_usectohz(2000000 + n*500000));
3654                         }
3655 
3656                         err = iwp_init(sc);
3657                         if (err != IWP_SUCCESS) {
3658                                 n++;
3659                                 if (n < 20) {
3660                                         continue;
3661                                 }
3662                         }
3663 
3664                         n = 0;
3665                         if (!err) {
3666                                 atomic_or_32(&sc->sc_flags, IWP_F_RUNNING);
3667                         }
3668 
3669 
3670                         if (!IWP_CHK_FAST_RECOVER(sc) ||
3671                             iwp_fast_recover(sc) != IWP_SUCCESS) {
3672                                 atomic_and_32(&sc->sc_flags,
3673                                     ~IWP_F_HW_ERR_RECOVER);
3674 
3675                                 delay(drv_usectohz(2000000));
3676                                 if (sc->sc_ostate != IEEE80211_S_INIT) {
3677                                         ieee80211_new_state(ic,
3678                                             IEEE80211_S_SCAN, 0);
3679                                 }
3680                         }
3681                 }
3682 
3683                 if (ic->ic_mach &&
3684                     (sc->sc_flags & IWP_F_SCANNING) && sc->sc_scan_pending) {
3685                         IWP_DBG((IWP_DEBUG_SCAN, "iwp_thread(): "
3686                             "wait for probe response\n"));
3687 
3688                         sc->sc_scan_pending--;
3689                         delay(drv_usectohz(200000));
3690                         ieee80211_next_scan(ic);
3691                 }
3692 
3693                 /*
3694                  * rate ctl
3695                  */
3696                 if (ic->ic_mach &&
3697                     (sc->sc_flags & IWP_F_RATE_AUTO_CTL)) {
3698                         clk = ddi_get_lbolt();
3699                         if (clk > sc->sc_clk + drv_usectohz(1000000)) {
3700                                 iwp_amrr_timeout(sc);
3701                         }
3702                 }
3703 
3704                 delay(drv_usectohz(100000));
3705 
3706                 mutex_enter(&sc->sc_mt_lock);
3707                 if (sc->sc_tx_timer) {
3708                         timeout++;
3709                         if (10 == timeout) {
3710                                 sc->sc_tx_timer--;
3711                                 if (0 == sc->sc_tx_timer) {
3712                                         atomic_or_32(&sc->sc_flags,
3713                                             IWP_F_HW_ERR_RECOVER);
3714                                         sc->sc_ostate = IEEE80211_S_RUN;
3715                                         IWP_DBG((IWP_DEBUG_FW, "iwp_thread(): "
3716                                             "try to recover from "
3717                                             "send fail\n"));
3718                                 }
3719                                 timeout = 0;
3720                         }
3721                 }
3722                 mutex_exit(&sc->sc_mt_lock);
3723         }
3724 
3725         mutex_enter(&sc->sc_mt_lock);
3726         sc->sc_mf_thread = NULL;
3727         cv_signal(&sc->sc_mt_cv);
3728         mutex_exit(&sc->sc_mt_lock);
3729 }
3730 
3731 
3732 /*
3733  * Send a command to the ucode.
3734  */
3735 static int
3736 iwp_cmd(iwp_sc_t *sc, int code, const void *buf, int size, int async)
3737 {
3738         iwp_tx_ring_t *ring = &sc->sc_txq[IWP_CMD_QUEUE_NUM];
3739         iwp_tx_desc_t *desc;
3740         iwp_cmd_t *cmd;
3741 
3742         ASSERT(size <= sizeof (cmd->data));
3743         ASSERT(mutex_owned(&sc->sc_glock));
3744 
3745         IWP_DBG((IWP_DEBUG_CMD, "iwp_cmd() "
3746             "code[%d]", code));
3747         desc = ring->data[ring->cur].desc;
3748         cmd = ring->data[ring->cur].cmd;
3749 
3750         cmd->hdr.type = (uint8_t)code;
3751         cmd->hdr.flags = 0;
3752         cmd->hdr.qid = ring->qid;
3753         cmd->hdr.idx = ring->cur;
3754         (void) memcpy(cmd->data, buf, size);
3755         (void) memset(desc, 0, sizeof (*desc));
3756 
3757         desc->val0 = 1 << 24;
3758         desc->pa[0].tb1_addr =
3759             (uint32_t)(ring->data[ring->cur].paddr_cmd & 0xffffffff);
3760         desc->pa[0].val1 = ((4 + size) << 4) & 0xfff0;
3761 
3762         if (async) {
3763                 sc->sc_cmd_accum++;
3764         }
3765 
3766         /*
3767          * kick cmd ring XXX
3768          */
3769         sc->sc_shared->queues_byte_cnt_tbls[ring->qid].
3770             tfd_offset[ring->cur].val = 8;
3771         if (ring->cur < IWP_MAX_WIN_SIZE) {
3772                 sc->sc_shared->queues_byte_cnt_tbls[ring->qid].
3773                     tfd_offset[IWP_QUEUE_SIZE + ring->cur].val = 8;
3774         }
3775         ring->cur = (ring->cur + 1) % ring->count;
3776         IWP_WRITE(sc, HBUS_TARG_WRPTR, ring->qid << 8 | ring->cur);
3777 
3778         if (async) {
3779                 return (IWP_SUCCESS);
3780         } else {
3781                 clock_t clk;
3782 
3783                 clk = ddi_get_lbolt() + drv_usectohz(2000000);
3784                 while (sc->sc_cmd_flag != SC_CMD_FLG_DONE) {
3785                         if (cv_timedwait(&sc->sc_cmd_cv,
3786                             &sc->sc_glock, clk) < 0) {
3787                                 break;
3788                         }
3789                 }
3790 
3791                 if (SC_CMD_FLG_DONE == sc->sc_cmd_flag) {
3792                         sc->sc_cmd_flag = SC_CMD_FLG_NONE;
3793                         return (IWP_SUCCESS);
3794                 } else {
3795                         sc->sc_cmd_flag = SC_CMD_FLG_NONE;
3796                         return (IWP_FAIL);
3797                 }
3798         }
3799 }
3800 
3801 /*
3802  * require ucode seting led of NIC
3803  */
3804 static void
3805 iwp_set_led(iwp_sc_t *sc, uint8_t id, uint8_t off, uint8_t on)
3806 {
3807         iwp_led_cmd_t led;
3808 
3809         led.interval = LE_32(100000);   /* unit: 100ms */
3810         led.id = id;
3811         led.off = off;
3812         led.on = on;
3813 
3814         (void) iwp_cmd(sc, REPLY_LEDS_CMD, &led, sizeof (led), 1);
3815 }
3816 
3817 /*
3818  * necessary setting to NIC before authentication
3819  */
3820 static int
3821 iwp_hw_set_before_auth(iwp_sc_t *sc)
3822 {
3823         ieee80211com_t *ic = &sc->sc_ic;
3824         ieee80211_node_t *in = ic->ic_bss;
3825         int err = IWP_FAIL;
3826 
3827         /*
3828          * update adapter's configuration according
3829          * the info of target AP
3830          */
3831         IEEE80211_ADDR_COPY(sc->sc_config.bssid, in->in_bssid);
3832         sc->sc_config.chan = LE_16(ieee80211_chan2ieee(ic, in->in_chan));
3833 
3834                 sc->sc_config.ofdm_ht_triple_stream_basic_rates = 0;
3835                 sc->sc_config.ofdm_ht_dual_stream_basic_rates = 0;
3836                 sc->sc_config.ofdm_ht_single_stream_basic_rates = 0;
3837 
3838                 if (IEEE80211_MODE_11B == ic->ic_curmode) {
3839                         sc->sc_config.cck_basic_rates  = 0x03;
3840                         sc->sc_config.ofdm_basic_rates = 0;
3841                 } else if ((in->in_chan != IEEE80211_CHAN_ANYC) &&
3842                     (IEEE80211_IS_CHAN_5GHZ(in->in_chan))) {
3843                         sc->sc_config.cck_basic_rates  = 0;
3844                         sc->sc_config.ofdm_basic_rates = 0x15;
3845                 } else { /* assume 802.11b/g */
3846                         sc->sc_config.cck_basic_rates  = 0x0f;
3847                         sc->sc_config.ofdm_basic_rates = 0xff;
3848                 }
3849 
3850         sc->sc_config.flags &= ~LE_32(RXON_FLG_SHORT_PREAMBLE_MSK |
3851             RXON_FLG_SHORT_SLOT_MSK);
3852 
3853         if (ic->ic_flags & IEEE80211_F_SHSLOT) {
3854                 sc->sc_config.flags |= LE_32(RXON_FLG_SHORT_SLOT_MSK);
3855         } else {
3856                 sc->sc_config.flags &= LE_32(~RXON_FLG_SHORT_SLOT_MSK);
3857         }
3858 
3859         if (ic->ic_flags & IEEE80211_F_SHPREAMBLE) {
3860                 sc->sc_config.flags |= LE_32(RXON_FLG_SHORT_PREAMBLE_MSK);
3861         } else {
3862                 sc->sc_config.flags &= LE_32(~RXON_FLG_SHORT_PREAMBLE_MSK);
3863         }
3864 
3865         IWP_DBG((IWP_DEBUG_80211, "iwp_hw_set_before_auth(): "
3866             "config chan %d flags %x "
3867             "filter_flags %x  cck %x ofdm %x"
3868             " bssid:%02x:%02x:%02x:%02x:%02x:%2x\n",
3869             LE_16(sc->sc_config.chan), LE_32(sc->sc_config.flags),
3870             LE_32(sc->sc_config.filter_flags),
3871             sc->sc_config.cck_basic_rates, sc->sc_config.ofdm_basic_rates,
3872             sc->sc_config.bssid[0], sc->sc_config.bssid[1],
3873             sc->sc_config.bssid[2], sc->sc_config.bssid[3],
3874             sc->sc_config.bssid[4], sc->sc_config.bssid[5]));
3875 
3876         err = iwp_cmd(sc, REPLY_RXON, &sc->sc_config,
3877             sizeof (iwp_rxon_cmd_t), 1);
3878         if (err != IWP_SUCCESS) {
3879                 cmn_err(CE_WARN, "iwp_hw_set_before_auth(): "
3880                     "failed to config chan%d\n", sc->sc_config.chan);
3881                 return (err);
3882         }
3883 
3884         /*
3885          * add default AP node
3886          */
3887         err = iwp_add_ap_sta(sc);
3888         if (err != IWP_SUCCESS) {
3889                 return (err);
3890         }
3891 
3892 
3893         return (err);
3894 }
3895 
3896 /*
3897  * Send a scan request(assembly scan cmd) to the firmware.
3898  */
3899 static int
3900 iwp_scan(iwp_sc_t *sc)
3901 {
3902         ieee80211com_t *ic = &sc->sc_ic;
3903         iwp_tx_ring_t *ring = &sc->sc_txq[IWP_CMD_QUEUE_NUM];
3904         iwp_tx_desc_t *desc;
3905         iwp_tx_data_t *data;
3906         iwp_cmd_t *cmd;
3907         iwp_scan_hdr_t *hdr;
3908         iwp_scan_chan_t chan;
3909         struct ieee80211_frame *wh;
3910         ieee80211_node_t *in = ic->ic_bss;
3911         uint8_t essid[IEEE80211_NWID_LEN+1];
3912         struct ieee80211_rateset *rs;
3913         enum ieee80211_phymode mode;
3914         uint8_t *frm;
3915         int i, pktlen, nrates;
3916 
3917         data = &ring->data[ring->cur];
3918         desc = data->desc;
3919         cmd = (iwp_cmd_t *)data->dma_data.mem_va;
3920 
3921         cmd->hdr.type = REPLY_SCAN_CMD;
3922         cmd->hdr.flags = 0;
3923         cmd->hdr.qid = ring->qid;
3924         cmd->hdr.idx = ring->cur | 0x40;
3925 
3926         hdr = (iwp_scan_hdr_t *)cmd->data;
3927         (void) memset(hdr, 0, sizeof (iwp_scan_hdr_t));
3928         hdr->nchan = 1;
3929         hdr->quiet_time = LE_16(50);
3930         hdr->quiet_plcp_th = LE_16(1);
3931 
3932         hdr->flags = LE_32(RXON_FLG_BAND_24G_MSK);
3933         hdr->rx_chain = LE_16(RXON_RX_CHAIN_DRIVER_FORCE_MSK |
3934             (0x7 << RXON_RX_CHAIN_VALID_POS) |
3935             (0x2 << RXON_RX_CHAIN_FORCE_SEL_POS) |
3936             (0x2 << RXON_RX_CHAIN_FORCE_MIMO_SEL_POS));
3937 
3938         hdr->tx_cmd.tx_flags = LE_32(TX_CMD_FLG_SEQ_CTL_MSK);
3939         hdr->tx_cmd.sta_id = IWP_BROADCAST_ID;
3940         hdr->tx_cmd.stop_time.life_time = LE_32(0xffffffff);
3941         hdr->tx_cmd.rate.r.rate_n_flags = LE_32(iwp_rate_to_plcp(2));
3942         hdr->tx_cmd.rate.r.rate_n_flags |=
3943             LE_32(RATE_MCS_ANT_B_MSK |RATE_MCS_CCK_MSK);
3944         hdr->direct_scan[0].len = ic->ic_des_esslen;
3945         hdr->direct_scan[0].id  = IEEE80211_ELEMID_SSID;
3946 
3947         hdr->filter_flags = LE_32(RXON_FILTER_ACCEPT_GRP_MSK |
3948             RXON_FILTER_BCON_AWARE_MSK);
3949 
3950         if (ic->ic_des_esslen) {
3951                 bcopy(ic->ic_des_essid, essid, ic->ic_des_esslen);
3952                 essid[ic->ic_des_esslen] = '\0';
3953                 IWP_DBG((IWP_DEBUG_SCAN, "iwp_scan(): "
3954                     "directed scan %s\n", essid));
3955 
3956                 bcopy(ic->ic_des_essid, hdr->direct_scan[0].ssid,
3957                     ic->ic_des_esslen);
3958         } else {
3959                 bzero(hdr->direct_scan[0].ssid,
3960                     sizeof (hdr->direct_scan[0].ssid));
3961         }
3962 
3963         /*
3964          * a probe request frame is required after the REPLY_SCAN_CMD
3965          */
3966         wh = (struct ieee80211_frame *)(hdr + 1);
3967         wh->i_fc[0] = IEEE80211_FC0_VERSION_0 | IEEE80211_FC0_TYPE_MGT |
3968             IEEE80211_FC0_SUBTYPE_PROBE_REQ;
3969         wh->i_fc[1] = IEEE80211_FC1_DIR_NODS;
3970         (void) memset(wh->i_addr1, 0xff, 6);
3971         IEEE80211_ADDR_COPY(wh->i_addr2, ic->ic_macaddr);
3972         (void) memset(wh->i_addr3, 0xff, 6);
3973         *(uint16_t *)&wh->i_dur[0] = 0;
3974         *(uint16_t *)&wh->i_seq[0] = 0;
3975 
3976         frm = (uint8_t *)(wh + 1);
3977 
3978         /*
3979          * essid IE
3980          */
3981         if (in->in_esslen) {
3982                 bcopy(in->in_essid, essid, in->in_esslen);
3983                 essid[in->in_esslen] = '\0';
3984                 IWP_DBG((IWP_DEBUG_SCAN, "iwp_scan(): "
3985                     "probe with ESSID %s\n",
3986                     essid));
3987         }
3988         *frm++ = IEEE80211_ELEMID_SSID;
3989         *frm++ = in->in_esslen;
3990         (void) memcpy(frm, in->in_essid, in->in_esslen);
3991         frm += in->in_esslen;
3992 
3993         mode = ieee80211_chan2mode(ic, ic->ic_curchan);
3994         rs = &ic->ic_sup_rates[mode];
3995 
3996         /*
3997          * supported rates IE
3998          */
3999         *frm++ = IEEE80211_ELEMID_RATES;
4000         nrates = rs->ir_nrates;
4001         if (nrates > IEEE80211_RATE_SIZE) {
4002                 nrates = IEEE80211_RATE_SIZE;
4003         }
4004 
4005         *frm++ = (uint8_t)nrates;
4006         (void) memcpy(frm, rs->ir_rates, nrates);
4007         frm += nrates;
4008 
4009         /*
4010          * supported xrates IE
4011          */
4012         if (rs->ir_nrates > IEEE80211_RATE_SIZE) {
4013                 nrates = rs->ir_nrates - IEEE80211_RATE_SIZE;
4014                 *frm++ = IEEE80211_ELEMID_XRATES;
4015                 *frm++ = (uint8_t)nrates;
4016                 (void) memcpy(frm, rs->ir_rates + IEEE80211_RATE_SIZE, nrates);
4017                 frm += nrates;
4018         }
4019 
4020         /*
4021          * optionnal IE (usually for wpa)
4022          */
4023         if (ic->ic_opt_ie != NULL) {
4024                 (void) memcpy(frm, ic->ic_opt_ie, ic->ic_opt_ie_len);
4025                 frm += ic->ic_opt_ie_len;
4026         }
4027 
4028         /* setup length of probe request */
4029         hdr->tx_cmd.len = LE_16(_PTRDIFF(frm, wh));
4030         hdr->len = LE_16(hdr->nchan * sizeof (iwp_scan_chan_t) +
4031             LE_16(hdr->tx_cmd.len) + sizeof (iwp_scan_hdr_t));
4032 
4033         /*
4034          * the attribute of the scan channels are required after the probe
4035          * request frame.
4036          */
4037         for (i = 1; i <= hdr->nchan; i++) {
4038                 if (ic->ic_des_esslen) {
4039                         chan.type = LE_32(3);
4040                 } else {
4041                         chan.type = LE_32(1);
4042                 }
4043 
4044                 chan.chan = LE_16(ieee80211_chan2ieee(ic, ic->ic_curchan));
4045                 chan.tpc.tx_gain = 0x28;
4046                 chan.tpc.dsp_atten = 110;
4047                 chan.active_dwell = LE_16(50);
4048                 chan.passive_dwell = LE_16(120);
4049 
4050                 bcopy(&chan, frm, sizeof (iwp_scan_chan_t));
4051                 frm += sizeof (iwp_scan_chan_t);
4052         }
4053 
4054         pktlen = _PTRDIFF(frm, cmd);
4055 
4056         (void) memset(desc, 0, sizeof (*desc));
4057         desc->val0 = 1 << 24;
4058         desc->pa[0].tb1_addr =
4059             (uint32_t)(data->dma_data.cookie.dmac_address & 0xffffffff);
4060         desc->pa[0].val1 = (pktlen << 4) & 0xfff0;
4061 
4062         /*
4063          * maybe for cmd, filling the byte cnt table is not necessary.
4064          * anyway, we fill it here.
4065          */
4066         sc->sc_shared->queues_byte_cnt_tbls[ring->qid]
4067             .tfd_offset[ring->cur].val = 8;
4068         if (ring->cur < IWP_MAX_WIN_SIZE) {
4069                 sc->sc_shared->queues_byte_cnt_tbls[ring->qid].
4070                     tfd_offset[IWP_QUEUE_SIZE + ring->cur].val = 8;
4071         }
4072 
4073         /*
4074          * kick cmd ring
4075          */
4076         ring->cur = (ring->cur + 1) % ring->count;
4077         IWP_WRITE(sc, HBUS_TARG_WRPTR, ring->qid << 8 | ring->cur);
4078 
4079         return (IWP_SUCCESS);
4080 }
4081 
4082 /*
4083  * configure NIC by using ucode commands after loading ucode.
4084  */
4085 static int
4086 iwp_config(iwp_sc_t *sc)
4087 {
4088         ieee80211com_t *ic = &sc->sc_ic;
4089         iwp_powertable_cmd_t powertable;
4090         iwp_bt_cmd_t bt;
4091         iwp_add_sta_t node;
4092         iwp_rem_sta_t   rm_sta;
4093         const uint8_t bcast[6] = {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF};
4094         int err = IWP_FAIL;
4095 
4096         /*
4097          * set power mode. Disable power management at present, do it later
4098          */
4099         (void) memset(&powertable, 0, sizeof (powertable));
4100         powertable.flags = LE_16(0x8);
4101         err = iwp_cmd(sc, POWER_TABLE_CMD, &powertable,
4102             sizeof (powertable), 0);
4103         if (err != IWP_SUCCESS) {
4104                 cmn_err(CE_WARN, "iwp_config(): "
4105                     "failed to set power mode\n");
4106                 return (err);
4107         }
4108 
4109         /*
4110          * configure bt coexistence
4111          */
4112         (void) memset(&bt, 0, sizeof (bt));
4113         bt.flags = 3;
4114         bt.lead_time = 0xaa;
4115         bt.max_kill = 1;
4116         err = iwp_cmd(sc, REPLY_BT_CONFIG, &bt,
4117             sizeof (bt), 0);
4118         if (err != IWP_SUCCESS) {
4119                 cmn_err(CE_WARN, "iwp_config(): "
4120                     "failed to configurate bt coexistence\n");
4121                 return (err);
4122         }
4123 
4124         /*
4125          * configure rxon
4126          */
4127         (void) memset(&sc->sc_config, 0, sizeof (iwp_rxon_cmd_t));
4128         IEEE80211_ADDR_COPY(sc->sc_config.node_addr, ic->ic_macaddr);
4129         IEEE80211_ADDR_COPY(sc->sc_config.wlap_bssid, ic->ic_macaddr);
4130         sc->sc_config.chan = LE_16(ieee80211_chan2ieee(ic, ic->ic_curchan));
4131         sc->sc_config.flags = LE_32(RXON_FLG_BAND_24G_MSK);
4132         sc->sc_config.flags &= LE_32(~(RXON_FLG_CHANNEL_MODE_MIXED_MSK |
4133             RXON_FLG_CHANNEL_MODE_PURE_40_MSK));
4134 
4135         switch (ic->ic_opmode) {
4136         case IEEE80211_M_STA:
4137                 sc->sc_config.dev_type = RXON_DEV_TYPE_ESS;
4138                 sc->sc_config.filter_flags |= LE_32(RXON_FILTER_ACCEPT_GRP_MSK |
4139                     RXON_FILTER_DIS_DECRYPT_MSK |
4140                     RXON_FILTER_DIS_GRP_DECRYPT_MSK);
4141                 break;
4142         case IEEE80211_M_IBSS:
4143         case IEEE80211_M_AHDEMO:
4144                 sc->sc_config.dev_type = RXON_DEV_TYPE_IBSS;
4145 
4146                 sc->sc_config.flags |= LE_32(RXON_FLG_SHORT_PREAMBLE_MSK);
4147                 sc->sc_config.filter_flags = LE_32(RXON_FILTER_ACCEPT_GRP_MSK |
4148                     RXON_FILTER_DIS_DECRYPT_MSK |
4149                     RXON_FILTER_DIS_GRP_DECRYPT_MSK);
4150                 break;
4151         case IEEE80211_M_HOSTAP:
4152                 sc->sc_config.dev_type = RXON_DEV_TYPE_AP;
4153                 break;
4154         case IEEE80211_M_MONITOR:
4155                 sc->sc_config.dev_type = RXON_DEV_TYPE_SNIFFER;
4156                 sc->sc_config.filter_flags |= LE_32(RXON_FILTER_ACCEPT_GRP_MSK |
4157                     RXON_FILTER_CTL2HOST_MSK | RXON_FILTER_PROMISC_MSK);
4158                 break;
4159         }
4160 
4161         /*
4162          * Support all CCK rates.
4163          */
4164         sc->sc_config.cck_basic_rates  = 0x0f;
4165 
4166         /*
4167          * Support all OFDM rates.
4168          */
4169         sc->sc_config.ofdm_basic_rates = 0xff;
4170 
4171         sc->sc_config.rx_chain = LE_16(RXON_RX_CHAIN_DRIVER_FORCE_MSK |
4172             (0x7 << RXON_RX_CHAIN_VALID_POS) |
4173             (0x2 << RXON_RX_CHAIN_FORCE_SEL_POS) |
4174             (0x2 << RXON_RX_CHAIN_FORCE_MIMO_SEL_POS));
4175 
4176         err = iwp_cmd(sc, REPLY_RXON, &sc->sc_config,
4177             sizeof (iwp_rxon_cmd_t), 0);
4178         if (err != IWP_SUCCESS) {
4179                 cmn_err(CE_WARN, "iwp_config(): "
4180                     "failed to set configure command\n");
4181                 return (err);
4182         }
4183 
4184         /*
4185          * remove all nodes in NIC
4186          */
4187         (void) memset(&rm_sta, 0, sizeof (rm_sta));
4188         rm_sta.num_sta = 1;
4189         (void) memcpy(rm_sta.addr, bcast, 6);
4190 
4191         err = iwp_cmd(sc, REPLY_REMOVE_STA, &rm_sta, sizeof (iwp_rem_sta_t), 0);
4192         if (err != IWP_SUCCESS) {
4193                 cmn_err(CE_WARN, "iwp_config(): "
4194                     "failed to remove broadcast node in hardware.\n");
4195                 return (err);
4196         }
4197 
4198         /*
4199          * add broadcast node so that we can send broadcast frame
4200          */
4201         (void) memset(&node, 0, sizeof (node));
4202         (void) memset(node.sta.addr, 0xff, 6);
4203         node.mode = 0;
4204         node.sta.sta_id = IWP_BROADCAST_ID;
4205         node.station_flags = 0;
4206 
4207         err = iwp_cmd(sc, REPLY_ADD_STA, &node, sizeof (node), 0);
4208         if (err != IWP_SUCCESS) {
4209                 cmn_err(CE_WARN, "iwp_config(): "
4210                     "failed to add broadcast node\n");
4211                 return (err);
4212         }
4213 
4214         return (err);
4215 }
4216 
4217 /*
4218  * quiesce(9E) entry point.
4219  * This function is called when the system is single-threaded at high
4220  * PIL with preemption disabled. Therefore, this function must not be
4221  * blocked.
4222  * This function returns DDI_SUCCESS on success, or DDI_FAILURE on failure.
4223  * DDI_FAILURE indicates an error condition and should almost never happen.
4224  */
4225 static int
4226 iwp_quiesce(dev_info_t *dip)
4227 {
4228         iwp_sc_t *sc;
4229 
4230         sc = ddi_get_soft_state(iwp_soft_state_p, ddi_get_instance(dip));
4231         if (NULL == sc) {
4232                 return (DDI_FAILURE);
4233         }
4234 
4235 #ifdef DEBUG
4236         /* by pass any messages, if it's quiesce */
4237         iwp_dbg_flags = 0;
4238 #endif
4239 
4240         /*
4241          * No more blocking is allowed while we are in the
4242          * quiesce(9E) entry point.
4243          */
4244         atomic_or_32(&sc->sc_flags, IWP_F_QUIESCED);
4245 
4246         /*
4247          * Disable and mask all interrupts.
4248          */
4249         iwp_stop(sc);
4250 
4251         return (DDI_SUCCESS);
4252 }
4253 
4254 static void
4255 iwp_stop_master(iwp_sc_t *sc)
4256 {
4257         uint32_t tmp;
4258         int n;
4259 
4260         tmp = IWP_READ(sc, CSR_RESET);
4261         IWP_WRITE(sc, CSR_RESET, tmp | CSR_RESET_REG_FLAG_STOP_MASTER);
4262 
4263         tmp = IWP_READ(sc, CSR_GP_CNTRL);
4264         if ((tmp & CSR_GP_CNTRL_REG_MSK_POWER_SAVE_TYPE) ==
4265             CSR_GP_CNTRL_REG_FLAG_MAC_POWER_SAVE) {
4266                 return;
4267         }
4268 
4269         for (n = 0; n < 2000; n++) {
4270                 if (IWP_READ(sc, CSR_RESET) &
4271                     CSR_RESET_REG_FLAG_MASTER_DISABLED) {
4272                         break;
4273                 }
4274                 DELAY(1000);
4275         }
4276 
4277 #ifdef  DEBUG
4278         if (2000 == n) {
4279                 IWP_DBG((IWP_DEBUG_HW, "iwp_stop_master(): "
4280                     "timeout waiting for master stop\n"));
4281         }
4282 #endif
4283 }
4284 
4285 static int
4286 iwp_power_up(iwp_sc_t *sc)
4287 {
4288         uint32_t tmp;
4289 
4290         iwp_mac_access_enter(sc);
4291         tmp = iwp_reg_read(sc, ALM_APMG_PS_CTL);
4292         tmp &= ~APMG_PS_CTRL_REG_MSK_POWER_SRC;
4293         tmp |= APMG_PS_CTRL_REG_VAL_POWER_SRC_VMAIN;
4294         iwp_reg_write(sc, ALM_APMG_PS_CTL, tmp);
4295         iwp_mac_access_exit(sc);
4296 
4297         DELAY(5000);
4298         return (IWP_SUCCESS);
4299 }
4300 
4301 /*
4302  * hardware initialization
4303  */
4304 static int
4305 iwp_preinit(iwp_sc_t *sc)
4306 {
4307         int             n;
4308         uint8_t         vlink;
4309         uint16_t        radio_cfg;
4310         uint32_t        tmp;
4311 
4312         /*
4313          * clear any pending interrupts
4314          */
4315         IWP_WRITE(sc, CSR_INT, 0xffffffff);
4316 
4317         tmp = IWP_READ(sc, CSR_GIO_CHICKEN_BITS);
4318         IWP_WRITE(sc, CSR_GIO_CHICKEN_BITS,
4319             tmp | CSR_GIO_CHICKEN_BITS_REG_BIT_DIS_L0S_EXIT_TIMER);
4320 
4321         tmp = IWP_READ(sc, CSR_GP_CNTRL);
4322         IWP_WRITE(sc, CSR_GP_CNTRL, tmp | CSR_GP_CNTRL_REG_FLAG_INIT_DONE);
4323 
4324         /*
4325          * wait for clock ready
4326          */
4327         for (n = 0; n < 1000; n++) {
4328                 if (IWP_READ(sc, CSR_GP_CNTRL) &
4329                     CSR_GP_CNTRL_REG_FLAG_MAC_CLOCK_READY) {
4330                         break;
4331                 }
4332                 DELAY(10);
4333         }
4334 
4335         if (1000 == n) {
4336                 return (ETIMEDOUT);
4337         }
4338 
4339         iwp_mac_access_enter(sc);
4340 
4341         iwp_reg_write(sc, ALM_APMG_CLK_EN, APMG_CLK_REG_VAL_DMA_CLK_RQT);
4342 
4343         DELAY(20);
4344         tmp = iwp_reg_read(sc, ALM_APMG_PCIDEV_STT);
4345         iwp_reg_write(sc, ALM_APMG_PCIDEV_STT, tmp |
4346             APMG_DEV_STATE_REG_VAL_L1_ACTIVE_DISABLE);
4347         iwp_mac_access_exit(sc);
4348 
4349         radio_cfg = IWP_READ_EEP_SHORT(sc, EEP_SP_RADIO_CONFIGURATION);
4350         if (SP_RADIO_TYPE_MSK(radio_cfg) < SP_RADIO_TYPE_MAX) {
4351                 tmp = IWP_READ(sc, CSR_HW_IF_CONFIG_REG);
4352                 IWP_WRITE(sc, CSR_HW_IF_CONFIG_REG,
4353                     tmp | SP_RADIO_TYPE_MSK(radio_cfg) |
4354                     SP_RADIO_STEP_MSK(radio_cfg) |
4355                     SP_RADIO_DASH_MSK(radio_cfg));
4356         } else {
4357                 cmn_err(CE_WARN, "iwp_preinit(): "
4358                     "radio configuration information in eeprom is wrong\n");
4359                 return (IWP_FAIL);
4360         }
4361 
4362 
4363         IWP_WRITE(sc, CSR_INT_COALESCING, 512 / 32);
4364 
4365         (void) iwp_power_up(sc);
4366 
4367         if ((sc->sc_rev & 0x80) == 0x80 && (sc->sc_rev & 0x7f) < 8) {
4368                 tmp = ddi_get32(sc->sc_cfg_handle,
4369                     (uint32_t *)(sc->sc_cfg_base + 0xe8));
4370                 ddi_put32(sc->sc_cfg_handle,
4371                     (uint32_t *)(sc->sc_cfg_base + 0xe8),
4372                     tmp & ~(1 << 11));
4373         }
4374 
4375         vlink = ddi_get8(sc->sc_cfg_handle,
4376             (uint8_t *)(sc->sc_cfg_base + 0xf0));
4377         ddi_put8(sc->sc_cfg_handle, (uint8_t *)(sc->sc_cfg_base + 0xf0),
4378             vlink & ~2);
4379 
4380         tmp = IWP_READ(sc, CSR_HW_IF_CONFIG_REG);
4381         tmp |= CSR_HW_IF_CONFIG_REG_BIT_RADIO_SI |
4382             CSR_HW_IF_CONFIG_REG_BIT_MAC_SI;
4383         IWP_WRITE(sc, CSR_HW_IF_CONFIG_REG, tmp);
4384 
4385         /*
4386          * make sure power supply on each part of the hardware
4387          */
4388         iwp_mac_access_enter(sc);
4389         tmp = iwp_reg_read(sc, ALM_APMG_PS_CTL);
4390         tmp |= APMG_PS_CTRL_REG_VAL_ALM_R_RESET_REQ;
4391         iwp_reg_write(sc, ALM_APMG_PS_CTL, tmp);
4392         DELAY(5);
4393 
4394         tmp = iwp_reg_read(sc, ALM_APMG_PS_CTL);
4395         tmp &= ~APMG_PS_CTRL_REG_VAL_ALM_R_RESET_REQ;
4396         iwp_reg_write(sc, ALM_APMG_PS_CTL, tmp);
4397         iwp_mac_access_exit(sc);
4398 
4399         if (PA_TYPE_MIX == sc->sc_chip_param.pa_type) {
4400                 IWP_WRITE(sc, CSR_GP_DRIVER_REG,
4401                     CSR_GP_DRIVER_REG_BIT_RADIO_SKU_2x2_MIX);
4402         }
4403 
4404         if (PA_TYPE_INTER == sc->sc_chip_param.pa_type) {
4405 
4406                 IWP_WRITE(sc, CSR_GP_DRIVER_REG,
4407                     CSR_GP_DRIVER_REG_BIT_RADIO_SKU_2x2_IPA);
4408         }
4409 
4410         return (IWP_SUCCESS);
4411 }
4412 
4413 /*
4414  * set up semphore flag to own EEPROM
4415  */
4416 static int
4417 iwp_eep_sem_down(iwp_sc_t *sc)
4418 {
4419         int count1, count2;
4420         uint32_t tmp;
4421 
4422         for (count1 = 0; count1 < 1000; count1++) {
4423                 tmp = IWP_READ(sc, CSR_HW_IF_CONFIG_REG);
4424                 IWP_WRITE(sc, CSR_HW_IF_CONFIG_REG,
4425                     tmp | CSR_HW_IF_CONFIG_REG_EEP_SEM);
4426 
4427                 for (count2 = 0; count2 < 2; count2++) {
4428                         if (IWP_READ(sc, CSR_HW_IF_CONFIG_REG) &
4429                             CSR_HW_IF_CONFIG_REG_EEP_SEM) {
4430                                 return (IWP_SUCCESS);
4431                         }
4432                         DELAY(10000);
4433                 }
4434         }
4435         return (IWP_FAIL);
4436 }
4437 
4438 /*
4439  * reset semphore flag to release EEPROM
4440  */
4441 static void
4442 iwp_eep_sem_up(iwp_sc_t *sc)
4443 {
4444         uint32_t tmp;
4445 
4446         tmp = IWP_READ(sc, CSR_HW_IF_CONFIG_REG);
4447         IWP_WRITE(sc, CSR_HW_IF_CONFIG_REG,
4448             tmp & (~CSR_HW_IF_CONFIG_REG_EEP_SEM));
4449 }
4450 
4451 /*
4452  * This function read all infomation from eeprom
4453  */
4454 static int
4455 iwp_eep_load(iwp_sc_t *sc)
4456 {
4457         int i, rr;
4458         uint32_t rv, tmp, eep_gp;
4459         uint16_t addr, eep_sz = sizeof (sc->sc_eep_map);
4460         uint16_t *eep_p = (uint16_t *)&sc->sc_eep_map;
4461 
4462         /*
4463          * read eeprom gp register in CSR
4464          */
4465         eep_gp = IWP_READ(sc, CSR_EEPROM_GP);
4466         if ((eep_gp & CSR_EEPROM_GP_VALID_MSK) ==
4467             CSR_EEPROM_GP_BAD_SIGNATURE) {
4468                 IWP_DBG((IWP_DEBUG_EEPROM, "iwp_eep_load(): "
4469                     "not find eeprom\n"));
4470                 return (IWP_FAIL);
4471         }
4472 
4473         rr = iwp_eep_sem_down(sc);
4474         if (rr != 0) {
4475                 IWP_DBG((IWP_DEBUG_EEPROM, "iwp_eep_load(): "
4476                     "driver failed to own EEPROM\n"));
4477                 return (IWP_FAIL);
4478         }
4479 
4480         for (addr = 0; addr < eep_sz; addr += 2) {
4481                 IWP_WRITE(sc, CSR_EEPROM_REG, addr<<1);
4482                 tmp = IWP_READ(sc, CSR_EEPROM_REG);
4483                 IWP_WRITE(sc, CSR_EEPROM_REG, tmp & ~(0x2));
4484 
4485                 for (i = 0; i < 10; i++) {
4486                         rv = IWP_READ(sc, CSR_EEPROM_REG);
4487                         if (rv & 1) {
4488                                 break;
4489                         }
4490                         DELAY(10);
4491                 }
4492 
4493                 if (!(rv & 1)) {
4494                         IWP_DBG((IWP_DEBUG_EEPROM, "iwp_eep_load(): "
4495                             "time out when read eeprome\n"));
4496                         iwp_eep_sem_up(sc);
4497                         return (IWP_FAIL);
4498                 }
4499 
4500                 eep_p[addr/2] = LE_16(rv >> 16);
4501         }
4502 
4503         iwp_eep_sem_up(sc);
4504         return (IWP_SUCCESS);
4505 }
4506 
4507 /*
4508  * initialize mac address in ieee80211com_t struct
4509  */
4510 static void
4511 iwp_get_mac_from_eep(iwp_sc_t *sc)
4512 {
4513         ieee80211com_t *ic = &sc->sc_ic;
4514 
4515         IEEE80211_ADDR_COPY(ic->ic_macaddr, &sc->sc_eep_map[EEP_MAC_ADDRESS]);
4516 
4517         IWP_DBG((IWP_DEBUG_EEPROM, "iwp_get_mac_from_eep(): "
4518             "mac:%2x:%2x:%2x:%2x:%2x:%2x\n",
4519             ic->ic_macaddr[0], ic->ic_macaddr[1], ic->ic_macaddr[2],
4520             ic->ic_macaddr[3], ic->ic_macaddr[4], ic->ic_macaddr[5]));
4521 }
4522 
4523 /*
4524  * main initialization function
4525  */
4526 static int
4527 iwp_init(iwp_sc_t *sc)
4528 {
4529         int err = IWP_FAIL;
4530         clock_t clk;
4531 
4532         /*
4533          * release buffer for calibration
4534          */
4535         iwp_release_calib_buffer(sc);
4536 
4537         mutex_enter(&sc->sc_glock);
4538         atomic_and_32(&sc->sc_flags, ~IWP_F_FW_INIT);
4539 
4540         err = iwp_init_common(sc);
4541         if (err != IWP_SUCCESS) {
4542                 mutex_exit(&sc->sc_glock);
4543                 return (IWP_FAIL);
4544         }
4545 
4546         /*
4547          * backup ucode data part for future use.
4548          */
4549         (void) memcpy(sc->sc_dma_fw_data_bak.mem_va,
4550             sc->sc_dma_fw_data.mem_va,
4551             sc->sc_dma_fw_data.alength);
4552 
4553         /* load firmware init segment into NIC */
4554         err = iwp_load_init_firmware(sc);
4555         if (err != IWP_SUCCESS) {
4556                 cmn_err(CE_WARN, "iwp_init(): "
4557                     "failed to setup init firmware\n");
4558                 mutex_exit(&sc->sc_glock);
4559                 return (IWP_FAIL);
4560         }
4561 
4562         /*
4563          * now press "execute" start running
4564          */
4565         IWP_WRITE(sc, CSR_RESET, 0);
4566 
4567         clk = ddi_get_lbolt() + drv_usectohz(1000000);
4568         while (!(sc->sc_flags & IWP_F_FW_INIT)) {
4569                 if (cv_timedwait(&sc->sc_ucode_cv,
4570                     &sc->sc_glock, clk) < 0) {
4571                         break;
4572                 }
4573         }
4574 
4575         if (!(sc->sc_flags & IWP_F_FW_INIT)) {
4576                 cmn_err(CE_WARN, "iwp_init(): "
4577                     "failed to process init alive.\n");
4578                 mutex_exit(&sc->sc_glock);
4579                 return (IWP_FAIL);
4580         }
4581 
4582         mutex_exit(&sc->sc_glock);
4583 
4584         /*
4585          * stop chipset for initializing chipset again
4586          */
4587         iwp_stop(sc);
4588 
4589         mutex_enter(&sc->sc_glock);
4590         atomic_and_32(&sc->sc_flags, ~IWP_F_FW_INIT);
4591 
4592         err = iwp_init_common(sc);
4593         if (err != IWP_SUCCESS) {
4594                 mutex_exit(&sc->sc_glock);
4595                 return (IWP_FAIL);
4596         }
4597 
4598         /*
4599          * load firmware run segment into NIC
4600          */
4601         err = iwp_load_run_firmware(sc);
4602         if (err != IWP_SUCCESS) {
4603                 cmn_err(CE_WARN, "iwp_init(): "
4604                     "failed to setup run firmware\n");
4605                 mutex_exit(&sc->sc_glock);
4606                 return (IWP_FAIL);
4607         }
4608 
4609         /*
4610          * now press "execute" start running
4611          */
4612         IWP_WRITE(sc, CSR_RESET, 0);
4613 
4614         clk = ddi_get_lbolt() + drv_usectohz(1000000);
4615         while (!(sc->sc_flags & IWP_F_FW_INIT)) {
4616                 if (cv_timedwait(&sc->sc_ucode_cv,
4617                     &sc->sc_glock, clk) < 0) {
4618                         break;
4619                 }
4620         }
4621 
4622         if (!(sc->sc_flags & IWP_F_FW_INIT)) {
4623                 cmn_err(CE_WARN, "iwp_init(): "
4624                     "failed to process runtime alive.\n");
4625                 mutex_exit(&sc->sc_glock);
4626                 return (IWP_FAIL);
4627         }
4628 
4629         mutex_exit(&sc->sc_glock);
4630 
4631         DELAY(1000);
4632 
4633         mutex_enter(&sc->sc_glock);
4634         atomic_and_32(&sc->sc_flags, ~IWP_F_FW_INIT);
4635 
4636         /*
4637          * at this point, the firmware is loaded OK, then config the hardware
4638          * with the ucode API, including rxon, txpower, etc.
4639          */
4640         err = iwp_config(sc);
4641         if (err) {
4642                 cmn_err(CE_WARN, "iwp_init(): "
4643                     "failed to configure device\n");
4644                 mutex_exit(&sc->sc_glock);
4645                 return (IWP_FAIL);
4646         }
4647 
4648         /*
4649          * at this point, hardware may receive beacons :)
4650          */
4651         mutex_exit(&sc->sc_glock);
4652         return (IWP_SUCCESS);
4653 }
4654 
4655 /*
4656  * stop or disable NIC
4657  */
4658 static void
4659 iwp_stop(iwp_sc_t *sc)
4660 {
4661         uint32_t tmp;
4662         int i;
4663 
4664         /* by pass if it's quiesced */
4665         if (!(sc->sc_flags & IWP_F_QUIESCED)) {
4666                 mutex_enter(&sc->sc_glock);
4667         }
4668 
4669         IWP_WRITE(sc, CSR_RESET, CSR_RESET_REG_FLAG_NEVO_RESET);
4670         /*
4671          * disable interrupts
4672          */
4673         IWP_WRITE(sc, CSR_INT_MASK, 0);
4674         IWP_WRITE(sc, CSR_INT, CSR_INI_SET_MASK);
4675         IWP_WRITE(sc, CSR_FH_INT_STATUS, 0xffffffff);
4676 
4677         /*
4678          * reset all Tx rings
4679          */
4680         for (i = 0; i < IWP_NUM_QUEUES; i++) {
4681                 iwp_reset_tx_ring(sc, &sc->sc_txq[i]);
4682         }
4683 
4684         /*
4685          * reset Rx ring
4686          */
4687         iwp_reset_rx_ring(sc);
4688 
4689         iwp_mac_access_enter(sc);
4690         iwp_reg_write(sc, ALM_APMG_CLK_DIS, APMG_CLK_REG_VAL_DMA_CLK_RQT);
4691         iwp_mac_access_exit(sc);
4692 
4693         DELAY(5);
4694 
4695         iwp_stop_master(sc);
4696 
4697         mutex_enter(&sc->sc_mt_lock);
4698         sc->sc_tx_timer = 0;
4699         mutex_exit(&sc->sc_mt_lock);
4700 
4701         tmp = IWP_READ(sc, CSR_RESET);
4702         IWP_WRITE(sc, CSR_RESET, tmp | CSR_RESET_REG_FLAG_SW_RESET);
4703 
4704         /* by pass if it's quiesced */
4705         if (!(sc->sc_flags & IWP_F_QUIESCED)) {
4706                 mutex_exit(&sc->sc_glock);
4707         }
4708 }
4709 
4710 /*
4711  * Naive implementation of the Adaptive Multi Rate Retry algorithm:
4712  * "IEEE 802.11 Rate Adaptation: A Practical Approach"
4713  * Mathieu Lacage, Hossein Manshaei, Thierry Turletti
4714  * INRIA Sophia - Projet Planete
4715  * http://www-sop.inria.fr/rapports/sophia/RR-5208.html
4716  */
4717 #define is_success(amrr)        \
4718         ((amrr)->retrycnt < (amrr)->txcnt / 10)
4719 #define is_failure(amrr)        \
4720         ((amrr)->retrycnt > (amrr)->txcnt / 3)
4721 #define is_enough(amrr)         \
4722         ((amrr)->txcnt > 200)
4723 #define not_very_few(amrr)      \
4724         ((amrr)->txcnt > 40)
4725 #define is_min_rate(in)         \
4726         (0 == (in)->in_txrate)
4727 #define is_max_rate(in)         \
4728         ((in)->in_rates.ir_nrates - 1 == (in)->in_txrate)
4729 #define increase_rate(in)       \
4730         ((in)->in_txrate++)
4731 #define decrease_rate(in)       \
4732         ((in)->in_txrate--)
4733 #define reset_cnt(amrr)         \
4734         { (amrr)->txcnt = (amrr)->retrycnt = 0; }
4735 
4736 #define IWP_AMRR_MIN_SUCCESS_THRESHOLD   1
4737 #define IWP_AMRR_MAX_SUCCESS_THRESHOLD  15
4738 
4739 static void
4740 iwp_amrr_init(iwp_amrr_t *amrr)
4741 {
4742         amrr->success = 0;
4743         amrr->recovery = 0;
4744         amrr->txcnt = amrr->retrycnt = 0;
4745         amrr->success_threshold = IWP_AMRR_MIN_SUCCESS_THRESHOLD;
4746 }
4747 
4748 static void
4749 iwp_amrr_timeout(iwp_sc_t *sc)
4750 {
4751         ieee80211com_t *ic = &sc->sc_ic;
4752 
4753         IWP_DBG((IWP_DEBUG_RATECTL, "iwp_amrr_timeout(): "
4754             "enter\n"));
4755 
4756         if (IEEE80211_M_STA == ic->ic_opmode) {
4757                 iwp_amrr_ratectl(NULL, ic->ic_bss);
4758         } else {
4759                 ieee80211_iterate_nodes(&ic->ic_sta, iwp_amrr_ratectl, NULL);
4760         }
4761 
4762         sc->sc_clk = ddi_get_lbolt();
4763 }
4764 
4765 /* ARGSUSED */
4766 static void
4767 iwp_amrr_ratectl(void *arg, ieee80211_node_t *in)
4768 {
4769         iwp_amrr_t *amrr = (iwp_amrr_t *)in;
4770         int need_change = 0;
4771 
4772         if (is_success(amrr) && is_enough(amrr)) {
4773                 amrr->success++;
4774                 if (amrr->success >= amrr->success_threshold &&
4775                     !is_max_rate(in)) {
4776                         amrr->recovery = 1;
4777                         amrr->success = 0;
4778                         increase_rate(in);
4779                         IWP_DBG((IWP_DEBUG_RATECTL, "iwp_amrr_ratectl(): "
4780                             "AMRR increasing rate %d "
4781                             "(txcnt=%d retrycnt=%d)\n",
4782                             in->in_txrate, amrr->txcnt,
4783                             amrr->retrycnt));
4784                         need_change = 1;
4785                 } else {
4786                         amrr->recovery = 0;
4787                 }
4788         } else if (not_very_few(amrr) && is_failure(amrr)) {
4789                 amrr->success = 0;
4790                 if (!is_min_rate(in)) {
4791                         if (amrr->recovery) {
4792                                 amrr->success_threshold++;
4793                                 if (amrr->success_threshold >
4794                                     IWP_AMRR_MAX_SUCCESS_THRESHOLD) {
4795                                         amrr->success_threshold =
4796                                             IWP_AMRR_MAX_SUCCESS_THRESHOLD;
4797                                 }
4798                         } else {
4799                                 amrr->success_threshold =
4800                                     IWP_AMRR_MIN_SUCCESS_THRESHOLD;
4801                         }
4802                         decrease_rate(in);
4803                         IWP_DBG((IWP_DEBUG_RATECTL, "iwp_amrr_ratectl(): "
4804                             "AMRR decreasing rate %d "
4805                             "(txcnt=%d retrycnt=%d)\n",
4806                             in->in_txrate, amrr->txcnt,
4807                             amrr->retrycnt));
4808                         need_change = 1;
4809                 }
4810                 amrr->recovery = 0;  /* paper is incorrect */
4811         }
4812 
4813         if (is_enough(amrr) || need_change) {
4814                 reset_cnt(amrr);
4815         }
4816 }
4817 
4818 /*
4819  * translate indirect address in eeprom to direct address
4820  * in eeprom and return address of entry whos indirect address
4821  * is indi_addr
4822  */
4823 static uint8_t *
4824 iwp_eep_addr_trans(iwp_sc_t *sc, uint32_t indi_addr)
4825 {
4826         uint32_t        di_addr;
4827         uint16_t        temp;
4828 
4829         if (!(indi_addr & INDIRECT_ADDRESS)) {
4830                 di_addr = indi_addr;
4831                 return (&sc->sc_eep_map[di_addr]);
4832         }
4833 
4834         switch (indi_addr & INDIRECT_TYPE_MSK) {
4835         case INDIRECT_GENERAL:
4836                 temp = IWP_READ_EEP_SHORT(sc, EEP_LINK_GENERAL);
4837                 break;
4838         case    INDIRECT_HOST:
4839                 temp = IWP_READ_EEP_SHORT(sc, EEP_LINK_HOST);
4840                 break;
4841         case    INDIRECT_REGULATORY:
4842                 temp = IWP_READ_EEP_SHORT(sc, EEP_LINK_REGULATORY);
4843                 break;
4844         case    INDIRECT_CALIBRATION:
4845                 temp = IWP_READ_EEP_SHORT(sc, EEP_LINK_CALIBRATION);
4846                 break;
4847         case    INDIRECT_PROCESS_ADJST:
4848                 temp = IWP_READ_EEP_SHORT(sc, EEP_LINK_PROCESS_ADJST);
4849                 break;
4850         case    INDIRECT_OTHERS:
4851                 temp = IWP_READ_EEP_SHORT(sc, EEP_LINK_OTHERS);
4852                 break;
4853         default:
4854                 temp = 0;
4855                 cmn_err(CE_WARN, "iwp_eep_addr_trans(): "
4856                     "incorrect indirect eeprom address.\n");
4857                 break;
4858         }
4859 
4860         di_addr = (indi_addr & ADDRESS_MSK) + (temp << 1);
4861 
4862         return (&sc->sc_eep_map[di_addr]);
4863 }
4864 
4865 /*
4866  * loade a section of ucode into NIC
4867  */
4868 static int
4869 iwp_put_seg_fw(iwp_sc_t *sc, uint32_t addr_s, uint32_t addr_d, uint32_t len)
4870 {
4871 
4872         iwp_mac_access_enter(sc);
4873 
4874         IWP_WRITE(sc, IWP_FH_TCSR_CHNL_TX_CONFIG_REG(IWP_FH_SRVC_CHNL),
4875             IWP_FH_TCSR_TX_CONFIG_REG_VAL_DMA_CHNL_PAUSE);
4876 
4877         IWP_WRITE(sc, IWP_FH_SRVC_CHNL_SRAM_ADDR_REG(IWP_FH_SRVC_CHNL), addr_d);
4878 
4879         IWP_WRITE(sc, IWP_FH_TFDIB_CTRL0_REG(IWP_FH_SRVC_CHNL),
4880             (addr_s & FH_MEM_TFDIB_DRAM_ADDR_LSB_MASK));
4881 
4882         IWP_WRITE(sc, IWP_FH_TFDIB_CTRL1_REG(IWP_FH_SRVC_CHNL), len);
4883 
4884         IWP_WRITE(sc, IWP_FH_TCSR_CHNL_TX_BUF_STS_REG(IWP_FH_SRVC_CHNL),
4885             (1 << IWP_FH_TCSR_CHNL_TX_BUF_STS_REG_POS_TB_NUM) |
4886             (1 << IWP_FH_TCSR_CHNL_TX_BUF_STS_REG_POS_TB_IDX) |
4887             IWP_FH_TCSR_CHNL_TX_BUF_STS_REG_VAL_TFDB_VALID);
4888 
4889         IWP_WRITE(sc, IWP_FH_TCSR_CHNL_TX_CONFIG_REG(IWP_FH_SRVC_CHNL),
4890             IWP_FH_TCSR_TX_CONFIG_REG_VAL_DMA_CHNL_ENABLE |
4891             IWP_FH_TCSR_TX_CONFIG_REG_VAL_DMA_CREDIT_DISABLE_VAL |
4892             IWP_FH_TCSR_TX_CONFIG_REG_VAL_CIRQ_HOST_ENDTFD);
4893 
4894         iwp_mac_access_exit(sc);
4895 
4896         return (IWP_SUCCESS);
4897 }
4898 
4899 /*
4900  * necessary setting during alive notification
4901  */
4902 static int
4903 iwp_alive_common(iwp_sc_t *sc)
4904 {
4905         uint32_t        base;
4906         uint32_t        i;
4907         iwp_wimax_coex_cmd_t    w_cmd;
4908         iwp_calibration_crystal_cmd_t   c_cmd;
4909         uint32_t        rv = IWP_FAIL;
4910 
4911         /*
4912          * initialize SCD related registers to make TX work.
4913          */
4914         iwp_mac_access_enter(sc);
4915 
4916         /*
4917          * read sram address of data base.
4918          */
4919         sc->sc_scd_base = iwp_reg_read(sc, IWP_SCD_SRAM_BASE_ADDR);
4920 
4921         for (base = sc->sc_scd_base + IWP_SCD_CONTEXT_DATA_OFFSET;
4922             base < sc->sc_scd_base + IWP_SCD_TX_STTS_BITMAP_OFFSET;
4923             base += 4) {
4924                 iwp_mem_write(sc, base, 0);
4925         }
4926 
4927         for (; base < sc->sc_scd_base + IWP_SCD_TRANSLATE_TBL_OFFSET;
4928             base += 4) {
4929                 iwp_mem_write(sc, base, 0);
4930         }
4931 
4932         for (i = 0; i < sizeof (uint16_t) * IWP_NUM_QUEUES; i += 4) {
4933                 iwp_mem_write(sc, base + i, 0);
4934         }
4935 
4936         iwp_reg_write(sc, IWP_SCD_DRAM_BASE_ADDR,
4937             sc->sc_dma_sh.cookie.dmac_address >> 10);
4938 
4939         iwp_reg_write(sc, IWP_SCD_QUEUECHAIN_SEL,
4940             IWP_SCD_QUEUECHAIN_SEL_ALL(IWP_NUM_QUEUES));
4941 
4942         iwp_reg_write(sc, IWP_SCD_AGGR_SEL, 0);
4943 
4944         for (i = 0; i < IWP_NUM_QUEUES; i++) {
4945                 iwp_reg_write(sc, IWP_SCD_QUEUE_RDPTR(i), 0);
4946                 IWP_WRITE(sc, HBUS_TARG_WRPTR, 0 | (i << 8));
4947                 iwp_mem_write(sc, sc->sc_scd_base +
4948                     IWP_SCD_CONTEXT_QUEUE_OFFSET(i), 0);
4949                 iwp_mem_write(sc, sc->sc_scd_base +
4950                     IWP_SCD_CONTEXT_QUEUE_OFFSET(i) +
4951                     sizeof (uint32_t),
4952                     ((SCD_WIN_SIZE << IWP_SCD_QUEUE_CTX_REG2_WIN_SIZE_POS) &
4953                     IWP_SCD_QUEUE_CTX_REG2_WIN_SIZE_MSK) |
4954                     ((SCD_FRAME_LIMIT <<
4955                     IWP_SCD_QUEUE_CTX_REG2_FRAME_LIMIT_POS) &
4956                     IWP_SCD_QUEUE_CTX_REG2_FRAME_LIMIT_MSK));
4957         }
4958 
4959         iwp_reg_write(sc, IWP_SCD_INTERRUPT_MASK, (1 << IWP_NUM_QUEUES) - 1);
4960 
4961         iwp_reg_write(sc, (IWP_SCD_BASE + 0x10),
4962             SCD_TXFACT_REG_TXFIFO_MASK(0, 7));
4963 
4964         IWP_WRITE(sc, HBUS_TARG_WRPTR, (IWP_CMD_QUEUE_NUM << 8));
4965         iwp_reg_write(sc, IWP_SCD_QUEUE_RDPTR(IWP_CMD_QUEUE_NUM), 0);
4966 
4967         /*
4968          * queue 0-7 map to FIFO 0-7 and
4969          * all queues work under FIFO mode(none-scheduler_ack)
4970          */
4971         for (i = 0; i < 4; i++) {
4972                 iwp_reg_write(sc, IWP_SCD_QUEUE_STATUS_BITS(i),
4973                     (1 << IWP_SCD_QUEUE_STTS_REG_POS_ACTIVE) |
4974                     ((3-i) << IWP_SCD_QUEUE_STTS_REG_POS_TXF) |
4975                     (1 << IWP_SCD_QUEUE_STTS_REG_POS_WSL) |
4976                     IWP_SCD_QUEUE_STTS_REG_MSK);
4977         }
4978 
4979         iwp_reg_write(sc, IWP_SCD_QUEUE_STATUS_BITS(IWP_CMD_QUEUE_NUM),
4980             (1 << IWP_SCD_QUEUE_STTS_REG_POS_ACTIVE) |
4981             (IWP_CMD_FIFO_NUM << IWP_SCD_QUEUE_STTS_REG_POS_TXF) |
4982             (1 << IWP_SCD_QUEUE_STTS_REG_POS_WSL) |
4983             IWP_SCD_QUEUE_STTS_REG_MSK);
4984 
4985         for (i = 5; i < 7; i++) {
4986                 iwp_reg_write(sc, IWP_SCD_QUEUE_STATUS_BITS(i),
4987                     (1 << IWP_SCD_QUEUE_STTS_REG_POS_ACTIVE) |
4988                     (i << IWP_SCD_QUEUE_STTS_REG_POS_TXF) |
4989                     (1 << IWP_SCD_QUEUE_STTS_REG_POS_WSL) |
4990                     IWP_SCD_QUEUE_STTS_REG_MSK);
4991         }
4992 
4993         iwp_mac_access_exit(sc);
4994 
4995         (void) memset(&w_cmd, 0, sizeof (w_cmd));
4996 
4997         rv = iwp_cmd(sc, COEX_PRIORITY_TABLE_CMD, &w_cmd, sizeof (w_cmd), 1);
4998         if (rv != IWP_SUCCESS) {
4999                 cmn_err(CE_WARN, "iwp_alive_common(): "
5000                     "failed to send wimax coexist command.\n");
5001                 return (rv);
5002         }
5003 
5004         (void) memset(&c_cmd, 0, sizeof (c_cmd));
5005 
5006         c_cmd.opCode = PHY_CALIBRATE_CRYSTAL_FRQ_CMD;
5007         c_cmd.data.cap_pin1 = LE_16(sc->sc_eep_calib->xtal_calib[0]);
5008         c_cmd.data.cap_pin2 = LE_16(sc->sc_eep_calib->xtal_calib[1]);
5009 
5010         rv = iwp_cmd(sc, REPLY_PHY_CALIBRATION_CMD, &c_cmd, sizeof (c_cmd), 1);
5011         if (rv != IWP_SUCCESS) {
5012                 cmn_err(CE_WARN, "iwp_alive_common(): "
5013                     "failed to send crystal frq calibration command.\n");
5014                 return (rv);
5015         }
5016 
5017         /*
5018          * make sure crystal frequency calibration ready
5019          * before next operations.
5020          */
5021         DELAY(1000);
5022 
5023         return (IWP_SUCCESS);
5024 }
5025 
5026 /*
5027  * save results of calibration from ucode
5028  */
5029 static void
5030 iwp_save_calib_result(iwp_sc_t *sc, iwp_rx_desc_t *desc)
5031 {
5032         struct iwp_calib_results *res_p = &sc->sc_calib_results;
5033         struct iwp_calib_hdr *calib_hdr = (struct iwp_calib_hdr *)(desc + 1);
5034         int len = LE_32(desc->len);
5035 
5036         /*
5037          * ensure the size of buffer is not too big
5038          */
5039         len = (len & FH_RSCSR_FRAME_SIZE_MASK) - 4;
5040 
5041         switch (calib_hdr->op_code) {
5042         case PHY_CALIBRATE_LO_CMD:
5043                 if (NULL == res_p->lo_res) {
5044                         res_p->lo_res = kmem_alloc(len, KM_NOSLEEP);
5045                 }
5046 
5047                 if (NULL == res_p->lo_res) {
5048                         cmn_err(CE_WARN, "iwp_save_calib_result(): "
5049                             "failed to allocate memory.\n");
5050                         return;
5051                 }
5052 
5053                 res_p->lo_res_len = len;
5054                 (void) memcpy(res_p->lo_res, calib_hdr, len);
5055                 break;
5056         case PHY_CALIBRATE_TX_IQ_CMD:
5057                 if (NULL == res_p->tx_iq_res) {
5058                         res_p->tx_iq_res = kmem_alloc(len, KM_NOSLEEP);
5059                 }
5060 
5061                 if (NULL == res_p->tx_iq_res) {
5062                         cmn_err(CE_WARN, "iwp_save_calib_result(): "
5063                             "failed to allocate memory.\n");
5064                         return;
5065                 }
5066 
5067                 res_p->tx_iq_res_len = len;
5068                 (void) memcpy(res_p->tx_iq_res, calib_hdr, len);
5069                 break;
5070         case PHY_CALIBRATE_TX_IQ_PERD_CMD:
5071                 if (NULL == res_p->tx_iq_perd_res) {
5072                         res_p->tx_iq_perd_res = kmem_alloc(len, KM_NOSLEEP);
5073                 }
5074 
5075                 if (NULL == res_p->tx_iq_perd_res) {
5076                         cmn_err(CE_WARN, "iwp_save_calib_result(): "
5077                             "failed to allocate memory.\n");
5078                 }
5079 
5080                 res_p->tx_iq_perd_res_len = len;
5081                 (void) memcpy(res_p->tx_iq_perd_res, calib_hdr, len);
5082                 break;
5083         case PHY_CALIBRATE_BASE_BAND_CMD:
5084                 if (NULL == res_p->base_band_res) {
5085                         res_p->base_band_res = kmem_alloc(len, KM_NOSLEEP);
5086                 }
5087 
5088                 if (NULL == res_p->base_band_res) {
5089                         cmn_err(CE_WARN, "iwp_save_calib_result(): "
5090                             "failed to allocate memory.\n");
5091                 }
5092 
5093                 res_p->base_band_res_len = len;
5094                 (void) memcpy(res_p->base_band_res, calib_hdr, len);
5095                 break;
5096         default:
5097                 cmn_err(CE_WARN, "iwp_save_calib_result(): "
5098                     "incorrect calibration type(%d).\n", calib_hdr->op_code);
5099                 break;
5100         }
5101 
5102 }
5103 
5104 static void
5105 iwp_release_calib_buffer(iwp_sc_t *sc)
5106 {
5107         if (sc->sc_calib_results.lo_res != NULL) {
5108                 kmem_free(sc->sc_calib_results.lo_res,
5109                     sc->sc_calib_results.lo_res_len);
5110                 sc->sc_calib_results.lo_res = NULL;
5111         }
5112 
5113         if (sc->sc_calib_results.tx_iq_res != NULL) {
5114                 kmem_free(sc->sc_calib_results.tx_iq_res,
5115                     sc->sc_calib_results.tx_iq_res_len);
5116                 sc->sc_calib_results.tx_iq_res = NULL;
5117         }
5118 
5119         if (sc->sc_calib_results.tx_iq_perd_res != NULL) {
5120                 kmem_free(sc->sc_calib_results.tx_iq_perd_res,
5121                     sc->sc_calib_results.tx_iq_perd_res_len);
5122                 sc->sc_calib_results.tx_iq_perd_res = NULL;
5123         }
5124 
5125         if (sc->sc_calib_results.base_band_res != NULL) {
5126                 kmem_free(sc->sc_calib_results.base_band_res,
5127                     sc->sc_calib_results.base_band_res_len);
5128                 sc->sc_calib_results.base_band_res = NULL;
5129         }
5130 
5131 }
5132 
5133 /*
5134  * common section of intialization
5135  */
5136 static int
5137 iwp_init_common(iwp_sc_t *sc)
5138 {
5139         int32_t qid;
5140         uint32_t tmp;
5141 
5142         (void) iwp_preinit(sc);
5143 
5144         tmp = IWP_READ(sc, CSR_GP_CNTRL);
5145         if (!(tmp & CSR_GP_CNTRL_REG_FLAG_HW_RF_KILL_SW)) {
5146                 cmn_err(CE_NOTE, "iwp_init_common(): "
5147                     "radio transmitter is off\n");
5148                 return (IWP_FAIL);
5149         }
5150 
5151         /*
5152          * init Rx ring
5153          */
5154         iwp_mac_access_enter(sc);
5155         IWP_WRITE(sc, FH_MEM_RCSR_CHNL0_CONFIG_REG, 0);
5156 
5157         IWP_WRITE(sc, FH_RSCSR_CHNL0_RBDCB_WPTR_REG, 0);
5158         IWP_WRITE(sc, FH_RSCSR_CHNL0_RBDCB_BASE_REG,
5159             sc->sc_rxq.dma_desc.cookie.dmac_address >> 8);
5160 
5161         IWP_WRITE(sc, FH_RSCSR_CHNL0_STTS_WPTR_REG,
5162             ((uint32_t)(sc->sc_dma_sh.cookie.dmac_address +
5163             offsetof(struct iwp_shared, val0)) >> 4));
5164 
5165         IWP_WRITE(sc, FH_MEM_RCSR_CHNL0_CONFIG_REG,
5166             FH_RCSR_RX_CONFIG_CHNL_EN_ENABLE_VAL |
5167             FH_RCSR_CHNL0_RX_CONFIG_IRQ_DEST_INT_HOST_VAL |
5168             IWP_FH_RCSR_RX_CONFIG_REG_VAL_RB_SIZE_4K |
5169             (RX_QUEUE_SIZE_LOG <<
5170             FH_RCSR_RX_CONFIG_RBDCB_SIZE_BITSHIFT));
5171         iwp_mac_access_exit(sc);
5172         IWP_WRITE(sc, FH_RSCSR_CHNL0_RBDCB_WPTR_REG,
5173             (RX_QUEUE_SIZE - 1) & ~0x7);
5174 
5175         /*
5176          * init Tx rings
5177          */
5178         iwp_mac_access_enter(sc);
5179         iwp_reg_write(sc, IWP_SCD_TXFACT, 0);
5180 
5181         /*
5182          * keep warm page
5183          */
5184         IWP_WRITE(sc, IWP_FH_KW_MEM_ADDR_REG,
5185             sc->sc_dma_kw.cookie.dmac_address >> 4);
5186 
5187         for (qid = 0; qid < IWP_NUM_QUEUES; qid++) {
5188                 IWP_WRITE(sc, FH_MEM_CBBC_QUEUE(qid),
5189                     sc->sc_txq[qid].dma_desc.cookie.dmac_address >> 8);
5190                 IWP_WRITE(sc, IWP_FH_TCSR_CHNL_TX_CONFIG_REG(qid),
5191                     IWP_FH_TCSR_TX_CONFIG_REG_VAL_DMA_CHNL_ENABLE |
5192                     IWP_FH_TCSR_TX_CONFIG_REG_VAL_DMA_CREDIT_ENABLE_VAL);
5193         }
5194 
5195         iwp_mac_access_exit(sc);
5196 
5197         /*
5198          * clear "radio off" and "disable command" bits
5199          */
5200         IWP_WRITE(sc, CSR_UCODE_DRV_GP1_CLR, CSR_UCODE_SW_BIT_RFKILL);
5201         IWP_WRITE(sc, CSR_UCODE_DRV_GP1_CLR,
5202             CSR_UCODE_DRV_GP1_BIT_CMD_BLOCKED);
5203 
5204         /*
5205          * clear any pending interrupts
5206          */
5207         IWP_WRITE(sc, CSR_INT, 0xffffffff);
5208 
5209         /*
5210          * enable interrupts
5211          */
5212         IWP_WRITE(sc, CSR_INT_MASK, CSR_INI_SET_MASK);
5213 
5214         IWP_WRITE(sc, CSR_UCODE_DRV_GP1_CLR, CSR_UCODE_SW_BIT_RFKILL);
5215         IWP_WRITE(sc, CSR_UCODE_DRV_GP1_CLR, CSR_UCODE_SW_BIT_RFKILL);
5216 
5217         return (IWP_SUCCESS);
5218 }
5219 
5220 static int
5221 iwp_fast_recover(iwp_sc_t *sc)
5222 {
5223         ieee80211com_t *ic = &sc->sc_ic;
5224         int err = IWP_FAIL;
5225 
5226         mutex_enter(&sc->sc_glock);
5227 
5228         /* restore runtime configuration */
5229         bcopy(&sc->sc_config_save, &sc->sc_config,
5230             sizeof (sc->sc_config));
5231 
5232         sc->sc_config.assoc_id = 0;
5233         sc->sc_config.filter_flags &= ~LE_32(RXON_FILTER_ASSOC_MSK);
5234 
5235         if ((err = iwp_hw_set_before_auth(sc)) != IWP_SUCCESS) {
5236                 cmn_err(CE_WARN, "iwp_fast_recover(): "
5237                     "could not setup authentication\n");
5238                 mutex_exit(&sc->sc_glock);
5239                 return (err);
5240         }
5241 
5242         bcopy(&sc->sc_config_save, &sc->sc_config,
5243             sizeof (sc->sc_config));
5244 
5245         /* update adapter's configuration */
5246         err = iwp_run_state_config(sc);
5247         if (err != IWP_SUCCESS) {
5248                 cmn_err(CE_WARN, "iwp_fast_recover(): "
5249                     "failed to setup association\n");
5250                 mutex_exit(&sc->sc_glock);
5251                 return (err);
5252         }
5253         /* set LED on */
5254         iwp_set_led(sc, 2, 0, 1);
5255 
5256         mutex_exit(&sc->sc_glock);
5257 
5258         atomic_and_32(&sc->sc_flags, ~IWP_F_HW_ERR_RECOVER);
5259 
5260         /* start queue */
5261         IWP_DBG((IWP_DEBUG_FW, "iwp_fast_recover(): "
5262             "resume xmit\n"));
5263         mac_tx_update(ic->ic_mach);
5264 
5265         return (IWP_SUCCESS);
5266 }
5267 
5268 static int
5269 iwp_run_state_config(iwp_sc_t *sc)
5270 {
5271         struct ieee80211com *ic = &sc->sc_ic;
5272         ieee80211_node_t *in = ic->ic_bss;
5273         int err = IWP_FAIL;
5274 
5275         /*
5276          * update adapter's configuration
5277          */
5278         sc->sc_config.assoc_id = in->in_associd & 0x3fff;
5279 
5280         /*
5281          * short preamble/slot time are
5282          * negotiated when associating
5283          */
5284         sc->sc_config.flags &=
5285             ~LE_32(RXON_FLG_SHORT_PREAMBLE_MSK |
5286             RXON_FLG_SHORT_SLOT_MSK);
5287 
5288         if (ic->ic_flags & IEEE80211_F_SHSLOT) {
5289                 sc->sc_config.flags |=
5290                     LE_32(RXON_FLG_SHORT_SLOT_MSK);
5291         }
5292 
5293         if (ic->ic_flags & IEEE80211_F_SHPREAMBLE) {
5294                 sc->sc_config.flags |=
5295                     LE_32(RXON_FLG_SHORT_PREAMBLE_MSK);
5296         }
5297 
5298         sc->sc_config.filter_flags |=
5299             LE_32(RXON_FILTER_ASSOC_MSK);
5300 
5301         if (ic->ic_opmode != IEEE80211_M_STA) {
5302                 sc->sc_config.filter_flags |=
5303                     LE_32(RXON_FILTER_BCON_AWARE_MSK);
5304         }
5305 
5306         IWP_DBG((IWP_DEBUG_80211, "iwp_run_state_config(): "
5307             "config chan %d flags %x"
5308             " filter_flags %x\n",
5309             sc->sc_config.chan, sc->sc_config.flags,
5310             sc->sc_config.filter_flags));
5311 
5312         err = iwp_cmd(sc, REPLY_RXON, &sc->sc_config,
5313             sizeof (iwp_rxon_cmd_t), 1);
5314         if (err != IWP_SUCCESS) {
5315                 cmn_err(CE_WARN, "iwp_run_state_config(): "
5316                     "could not update configuration\n");
5317                 return (err);
5318         }
5319 
5320         return (err);
5321 }
5322 
5323 /*
5324  * This function overwrites default configurations of
5325  * ieee80211com structure in Net80211 module.
5326  */
5327 static void
5328 iwp_overwrite_ic_default(iwp_sc_t *sc)
5329 {
5330         ieee80211com_t *ic = &sc->sc_ic;
5331 
5332         sc->sc_newstate = ic->ic_newstate;
5333         ic->ic_newstate = iwp_newstate;
5334         ic->ic_node_alloc = iwp_node_alloc;
5335         ic->ic_node_free = iwp_node_free;
5336 }
5337 
5338 
5339 /*
5340  * This function adds AP station into hardware.
5341  */
5342 static int
5343 iwp_add_ap_sta(iwp_sc_t *sc)
5344 {
5345         ieee80211com_t *ic = &sc->sc_ic;
5346         ieee80211_node_t *in = ic->ic_bss;
5347         iwp_add_sta_t node;
5348         int err = IWP_FAIL;
5349 
5350         /*
5351          * Add AP node into hardware.
5352          */
5353         (void) memset(&node, 0, sizeof (node));
5354         IEEE80211_ADDR_COPY(node.sta.addr, in->in_bssid);
5355         node.mode = STA_MODE_ADD_MSK;
5356         node.sta.sta_id = IWP_AP_ID;
5357 
5358         err = iwp_cmd(sc, REPLY_ADD_STA, &node, sizeof (node), 1);
5359         if (err != IWP_SUCCESS) {
5360                 cmn_err(CE_WARN, "iwp_add_ap_sta(): "
5361                     "failed to add AP node\n");
5362                 return (err);
5363         }
5364 
5365         return (err);
5366 }
5367 
5368 /*
5369  * Check EEPROM version and Calibration version.
5370  */
5371 static int
5372 iwp_eep_ver_chk(iwp_sc_t *sc)
5373 {
5374         if ((IWP_READ_EEP_SHORT(sc, EEP_VERSION) < 0x011a) ||
5375             (sc->sc_eep_calib->tx_pow_calib_hdr.calib_version < 4)) {
5376                 cmn_err(CE_WARN, "iwp_eep_ver_chk(): "
5377                     "unsupported eeprom detected\n");
5378                 return (IWP_FAIL);
5379         }
5380 
5381         return (IWP_SUCCESS);
5382 }
5383 
5384 /*
5385  * Determine parameters for all supported chips.
5386  */
5387 static void
5388 iwp_set_chip_param(iwp_sc_t *sc)
5389 {
5390         if ((0x008d == sc->sc_dev_id) ||
5391             (0x008e == sc->sc_dev_id)) {
5392                 sc->sc_chip_param.phy_mode = PHY_MODE_G |
5393                     PHY_MODE_A | PHY_MODE_N;
5394 
5395                 sc->sc_chip_param.tx_ant = ANT_A | ANT_B;
5396                 sc->sc_chip_param.rx_ant = ANT_A | ANT_B;
5397 
5398                 sc->sc_chip_param.pa_type = PA_TYPE_MIX;
5399         }
5400 
5401         if ((0x422c == sc->sc_dev_id) ||
5402             (0x4239 == sc->sc_dev_id)) {
5403                 sc->sc_chip_param.phy_mode = PHY_MODE_G |
5404                     PHY_MODE_A | PHY_MODE_N;
5405 
5406                 sc->sc_chip_param.tx_ant = ANT_B | ANT_C;
5407                 sc->sc_chip_param.rx_ant = ANT_B | ANT_C;
5408 
5409                 sc->sc_chip_param.pa_type = PA_TYPE_INTER;
5410         }
5411 
5412         if ((0x422b == sc->sc_dev_id) ||
5413             (0x4238 == sc->sc_dev_id)) {
5414                 sc->sc_chip_param.phy_mode = PHY_MODE_G |
5415                     PHY_MODE_A | PHY_MODE_N;
5416 
5417                 sc->sc_chip_param.tx_ant = ANT_A | ANT_B | ANT_C;
5418                 sc->sc_chip_param.rx_ant = ANT_A | ANT_B | ANT_C;
5419 
5420                 sc->sc_chip_param.pa_type = PA_TYPE_SYSTEM;
5421         }
5422 }