1 /*
   2  * Copyright 2010 Sun Microsystems, Inc.  All rights reserved.
   3  * Use is subject to license terms.
   4  */
   5 
   6 /*
   7  * Copyright (c) 2007-2009 Sam Leffler, Errno Consulting
   8  * Copyright (c) 2007-2008 Marvell Semiconductor, Inc.
   9  * All rights reserved.
  10  *
  11  * Redistribution and use in source and binary forms, with or without
  12  * modification, are permitted provided that the following conditions
  13  * are met:
  14  * 1. Redistributions of source code must retain the above copyright
  15  *    notice, this list of conditions and the following disclaimer,
  16  *    without modification.
  17  * 2. Redistributions in binary form must reproduce at minimum a disclaimer
  18  *    similar to the "NO WARRANTY" disclaimer below ("Disclaimer") and any
  19  *    redistribution must be conditioned upon including a substantially
  20  *    similar Disclaimer requirement for further binary redistribution.
  21  *
  22  * NO WARRANTY
  23  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
  24  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
  25  * LIMITED TO, THE IMPLIED WARRANTIES OF NONINFRINGEMENT, MERCHANTIBILITY
  26  * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
  27  * THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY,
  28  * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
  29  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
  30  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
  31  * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
  32  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
  33  * THE POSSIBILITY OF SUCH DAMAGES.
  34  */
  35 
  36 /*
  37  * Driver for the Marvell 88W8363 Wireless LAN controller.
  38  */
  39 #include <sys/stat.h>
  40 #include <sys/dlpi.h>
  41 #include <inet/common.h>
  42 #include <inet/mi.h>
  43 #include <sys/stream.h>
  44 #include <sys/errno.h>
  45 #include <sys/stropts.h>
  46 #include <sys/stat.h>
  47 #include <sys/sunddi.h>
  48 #include <sys/strsubr.h>
  49 #include <sys/strsun.h>
  50 #include <sys/pci.h>
  51 #include <sys/mac_provider.h>
  52 #include <sys/mac_wifi.h>
  53 #include <sys/net80211.h>
  54 #include <inet/wifi_ioctl.h>
  55 
  56 #include "mwl_var.h"
  57 
  58 static int mwl_attach(dev_info_t *devinfo, ddi_attach_cmd_t cmd);
  59 static int mwl_detach(dev_info_t *devinfo, ddi_detach_cmd_t cmd);
  60 static int mwl_quiesce(dev_info_t *devinfo);
  61 
  62 DDI_DEFINE_STREAM_OPS(mwl_dev_ops, nulldev, nulldev, mwl_attach, mwl_detach,
  63     nodev, NULL, D_MP, NULL, mwl_quiesce);
  64 
  65 static struct modldrv mwl_modldrv = {
  66         &mod_driverops,     /* Type of module.  This one is a driver */
  67         "Marvell 88W8363 WiFi driver v1.1",     /* short description */
  68         &mwl_dev_ops        /* driver specific ops */
  69 };
  70 
  71 static struct modlinkage modlinkage = {
  72         MODREV_1, { (void *)&mwl_modldrv, NULL }
  73 };
  74 
  75 static void *mwl_soft_state_p = NULL;
  76 
  77 static int      mwl_m_stat(void *,  uint_t, uint64_t *);
  78 static int      mwl_m_start(void *);
  79 static void     mwl_m_stop(void *);
  80 static int      mwl_m_promisc(void *, boolean_t);
  81 static int      mwl_m_multicst(void *, boolean_t, const uint8_t *);
  82 static int      mwl_m_unicst(void *, const uint8_t *);
  83 static mblk_t   *mwl_m_tx(void *, mblk_t *);
  84 static void     mwl_m_ioctl(void *, queue_t *, mblk_t *);
  85 static int      mwl_m_setprop(void *arg, const char *pr_name,
  86                     mac_prop_id_t wldp_pr_num,
  87                     uint_t wldp_length, const void *wldp_buf);
  88 static int      mwl_m_getprop(void *arg, const char *pr_name,
  89                     mac_prop_id_t wldp_pr_num, uint_t wldp_length,
  90                     void *wldp_buf);
  91 static void     mwl_m_propinfo(void *, const char *, mac_prop_id_t,
  92     mac_prop_info_handle_t);
  93 
  94 static mac_callbacks_t mwl_m_callbacks = {
  95         MC_IOCTL | MC_SETPROP | MC_GETPROP | MC_PROPINFO,
  96         mwl_m_stat,
  97         mwl_m_start,
  98         mwl_m_stop,
  99         mwl_m_promisc,
 100         mwl_m_multicst,
 101         mwl_m_unicst,
 102         mwl_m_tx,
 103         NULL,
 104         mwl_m_ioctl,
 105         NULL,
 106         NULL,
 107         NULL,
 108         mwl_m_setprop,
 109         mwl_m_getprop,
 110         mwl_m_propinfo
 111 };
 112 
 113 #define MWL_DBG_ATTACH          (1 << 0)
 114 #define MWL_DBG_DMA             (1 << 1)
 115 #define MWL_DBG_FW              (1 << 2)
 116 #define MWL_DBG_HW              (1 << 3)
 117 #define MWL_DBG_INTR            (1 << 4)
 118 #define MWL_DBG_RX              (1 << 5)
 119 #define MWL_DBG_TX              (1 << 6)
 120 #define MWL_DBG_CMD             (1 << 7)
 121 #define MWL_DBG_CRYPTO          (1 << 8)
 122 #define MWL_DBG_SR              (1 << 9)
 123 #define MWL_DBG_MSG             (1 << 10)
 124 
 125 uint32_t mwl_dbg_flags = 0x0;
 126 
 127 #ifdef DEBUG
 128 #define MWL_DBG \
 129         mwl_debug
 130 #else
 131 #define MWL_DBG
 132 #endif
 133 
 134 /*
 135  * PIO access attributes for registers
 136  */
 137 static ddi_device_acc_attr_t mwl_reg_accattr = {
 138         DDI_DEVICE_ATTR_V0,
 139         DDI_STRUCTURE_LE_ACC,
 140         DDI_STRICTORDER_ACC,
 141         DDI_DEFAULT_ACC
 142 };
 143 
 144 static ddi_device_acc_attr_t mwl_cmdbuf_accattr = {
 145         DDI_DEVICE_ATTR_V0,
 146         DDI_NEVERSWAP_ACC,
 147         DDI_STRICTORDER_ACC,
 148         DDI_DEFAULT_ACC
 149 };
 150 
 151 /*
 152  * DMA access attributes for descriptors and bufs: NOT to be byte swapped.
 153  */
 154 static ddi_device_acc_attr_t mwl_desc_accattr = {
 155         DDI_DEVICE_ATTR_V0,
 156         DDI_NEVERSWAP_ACC,
 157         DDI_STRICTORDER_ACC,
 158         DDI_DEFAULT_ACC
 159 };
 160 
 161 static ddi_device_acc_attr_t mwl_buf_accattr = {
 162         DDI_DEVICE_ATTR_V0,
 163         DDI_NEVERSWAP_ACC,
 164         DDI_STRICTORDER_ACC,
 165         DDI_DEFAULT_ACC
 166 };
 167 
 168 /*
 169  * Describes the chip's DMA engine
 170  */
 171 static ddi_dma_attr_t mwl_dma_attr = {
 172         DMA_ATTR_V0,                    /* dma_attr version */
 173         0x0000000000000000ull,          /* dma_attr_addr_lo */
 174         0xFFFFFFFF,                     /* dma_attr_addr_hi */
 175         0x00000000FFFFFFFFull,          /* dma_attr_count_max */
 176         0x0000000000000001ull,          /* dma_attr_align */
 177         0x00000FFF,                     /* dma_attr_burstsizes */
 178         0x00000001,                     /* dma_attr_minxfer */
 179         0x000000000000FFFFull,          /* dma_attr_maxxfer */
 180         0xFFFFFFFFFFFFFFFFull,          /* dma_attr_seg */
 181         1,                              /* dma_attr_sgllen */
 182         0x00000001,                     /* dma_attr_granular */
 183         0                               /* dma_attr_flags */
 184 };
 185 
 186 /*
 187  * Supported rates for 802.11a/b/g modes (in 500Kbps unit).
 188  */
 189 static const struct ieee80211_rateset mwl_rateset_11b =
 190         { 4, { 2, 4, 11, 22 } };
 191 
 192 static const struct ieee80211_rateset mwl_rateset_11g =
 193         { 12, { 2, 4, 11, 22, 12, 18, 24, 36, 48, 72, 96, 108 } };
 194 
 195 static int      mwl_alloc_dma_mem(dev_info_t *, ddi_dma_attr_t *, size_t,
 196                     ddi_device_acc_attr_t *, uint_t, uint_t,
 197                     struct dma_area *);
 198 static void     mwl_free_dma_mem(struct dma_area *);
 199 static int      mwl_alloc_cmdbuf(struct mwl_softc *);
 200 static void     mwl_free_cmdbuf(struct mwl_softc *);
 201 static int      mwl_alloc_rx_ring(struct mwl_softc *, int);
 202 static void     mwl_free_rx_ring(struct mwl_softc *);
 203 static int      mwl_alloc_tx_ring(struct mwl_softc *, struct mwl_tx_ring *,
 204                     int);
 205 static void     mwl_free_tx_ring(struct mwl_softc *, struct mwl_tx_ring *);
 206 static int      mwl_setupdma(struct mwl_softc *);
 207 static void     mwl_txq_init(struct mwl_softc *, struct mwl_tx_ring *, int);
 208 static int      mwl_tx_setup(struct mwl_softc *, int, int);
 209 static int      mwl_setup_txq(struct mwl_softc *);
 210 static int      mwl_fwload(struct mwl_softc *, void *);
 211 static int      mwl_loadsym(ddi_modhandle_t, char *, char **, size_t *);
 212 static void     mwlFwReset(struct mwl_softc *);
 213 static void     mwlPokeSdramController(struct mwl_softc *, int);
 214 static void     mwlTriggerPciCmd(struct mwl_softc *);
 215 static int      mwlWaitFor(struct mwl_softc *, uint32_t);
 216 static int      mwlSendBlock(struct mwl_softc *, int, const void *, size_t);
 217 static int      mwlSendBlock2(struct mwl_softc *, const void *, size_t);
 218 static void     mwlSendCmd(struct mwl_softc *);
 219 static int      mwlExecuteCmd(struct mwl_softc *, unsigned short);
 220 static int      mwlWaitForCmdComplete(struct mwl_softc *, uint16_t);
 221 static void     dumpresult(struct mwl_softc *, int);
 222 static int      mwlResetHalState(struct mwl_softc *);
 223 static int      mwlGetPwrCalTable(struct mwl_softc *);
 224 static int      mwlGetCalTable(struct mwl_softc *, uint8_t, uint8_t);
 225 static int      mwlGetPwrCalTable(struct mwl_softc *);
 226 static void     dumpcaldata(const char *, const uint8_t *, int);
 227 static void     get2Ghz(MWL_HAL_CHANNELINFO *, const uint8_t *, int);
 228 static void     get5Ghz(MWL_HAL_CHANNELINFO *, const uint8_t *, int);
 229 static void     setmaxtxpow(struct mwl_hal_channel *, int, int);
 230 static uint16_t ieee2mhz(int);
 231 static const char *
 232                 mwlcmdname(int);
 233 static int      mwl_gethwspecs(struct mwl_softc *);
 234 static int      mwl_getchannels(struct mwl_softc *);
 235 static void     getchannels(struct mwl_softc *, int, int *,
 236                     struct mwl_channel *);
 237 static void     addchannels(struct mwl_channel *, int, int *,
 238                     const MWL_HAL_CHANNELINFO *, int);
 239 static void     addht40channels(struct mwl_channel *, int, int *,
 240                     const MWL_HAL_CHANNELINFO *, int);
 241 static const struct mwl_channel *
 242                 findchannel(const struct mwl_channel *, int,
 243                     int, int);
 244 static void     addchan(struct mwl_channel *, int, int, int, int);
 245 
 246 static int      mwl_chan_set(struct mwl_softc *, struct mwl_channel *);
 247 static void     mwl_mapchan(MWL_HAL_CHANNEL *, const struct mwl_channel *);
 248 static int      mwl_setcurchanrates(struct mwl_softc *);
 249 const struct ieee80211_rateset *
 250                 mwl_get_suprates(struct ieee80211com *,
 251                     const struct mwl_channel *);
 252 static uint32_t cvtChannelFlags(const MWL_HAL_CHANNEL *);
 253 static const struct mwl_hal_channel *
 254                 findhalchannel(const struct mwl_softc *,
 255                     const MWL_HAL_CHANNEL *);
 256 enum ieee80211_phymode
 257                 mwl_chan2mode(const struct mwl_channel *);
 258 static int      mwl_map2regioncode(const struct mwl_regdomain *);
 259 static int      mwl_startrecv(struct mwl_softc *);
 260 static int      mwl_mode_init(struct mwl_softc *);
 261 static void     mwl_hal_intrset(struct mwl_softc *, uint32_t);
 262 static void     mwl_hal_getisr(struct mwl_softc *, uint32_t *);
 263 static int      mwl_hal_sethwdma(struct mwl_softc *,
 264                     const struct mwl_hal_txrxdma *);
 265 static int      mwl_hal_getchannelinfo(struct mwl_softc *, int, int,
 266                     const MWL_HAL_CHANNELINFO **);
 267 static int      mwl_hal_setmac_locked(struct mwl_softc *, const uint8_t *);
 268 static int      mwl_hal_keyreset(struct mwl_softc *, const MWL_HAL_KEYVAL *,
 269                     const uint8_t mac[IEEE80211_ADDR_LEN]);
 270 static int      mwl_hal_keyset(struct mwl_softc *, const MWL_HAL_KEYVAL *,
 271                     const uint8_t mac[IEEE80211_ADDR_LEN]);
 272 static int      mwl_hal_newstation(struct mwl_softc *, const uint8_t *,
 273                     uint16_t, uint16_t, const MWL_HAL_PEERINFO *, int, int);
 274 static int      mwl_hal_setantenna(struct mwl_softc *, MWL_HAL_ANTENNA, int);
 275 static int      mwl_hal_setradio(struct mwl_softc *, int, MWL_HAL_PREAMBLE);
 276 static int      mwl_hal_setwmm(struct mwl_softc *, int);
 277 static int      mwl_hal_setchannel(struct mwl_softc *, const MWL_HAL_CHANNEL *);
 278 static int      mwl_hal_settxpower(struct mwl_softc *, const MWL_HAL_CHANNEL *,
 279                     uint8_t);
 280 static int      mwl_hal_settxrate(struct mwl_softc *, MWL_HAL_TXRATE_HANDLING,
 281                     const MWL_HAL_TXRATE *);
 282 static int      mwl_hal_settxrate_auto(struct mwl_softc *,
 283                     const MWL_HAL_TXRATE *);
 284 static int      mwl_hal_setrateadaptmode(struct mwl_softc *, uint16_t);
 285 static int      mwl_hal_setoptimizationlevel(struct mwl_softc *, int);
 286 static int      mwl_hal_setregioncode(struct mwl_softc *, int);
 287 static int      mwl_hal_setassocid(struct mwl_softc *, const uint8_t *,
 288                     uint16_t);
 289 static int      mwl_setrates(struct ieee80211com *);
 290 static int      mwl_hal_setrtsthreshold(struct mwl_softc *, int);
 291 static int      mwl_hal_setcsmode(struct mwl_softc *, MWL_HAL_CSMODE);
 292 static int      mwl_hal_setpromisc(struct mwl_softc *, int);
 293 static int      mwl_hal_start(struct mwl_softc *);
 294 static int      mwl_hal_setinframode(struct mwl_softc *);
 295 static int      mwl_hal_stop(struct mwl_softc *);
 296 static struct ieee80211_node *
 297                 mwl_node_alloc(struct ieee80211com *);
 298 static void     mwl_node_free(struct ieee80211_node *);
 299 static int      mwl_key_alloc(struct ieee80211com *,
 300                     const struct ieee80211_key *,
 301                     ieee80211_keyix *, ieee80211_keyix *);
 302 static int      mwl_key_delete(struct ieee80211com *,
 303                     const struct ieee80211_key *);
 304 static int      mwl_key_set(struct ieee80211com *, const struct ieee80211_key *,
 305                     const uint8_t mac[IEEE80211_ADDR_LEN]);
 306 static void     mwl_setanywepkey(struct ieee80211com *, const uint8_t *);
 307 static void     mwl_setglobalkeys(struct ieee80211com *c);
 308 static int      addgroupflags(MWL_HAL_KEYVAL *, const struct ieee80211_key *);
 309 static void     mwl_hal_txstart(struct mwl_softc *, int);
 310 static int      mwl_send(ieee80211com_t *, mblk_t *, uint8_t);
 311 static void     mwl_next_scan(void *);
 312 static MWL_HAL_PEERINFO *
 313                 mkpeerinfo(MWL_HAL_PEERINFO *, const struct ieee80211_node *);
 314 static uint32_t get_rate_bitmap(const struct ieee80211_rateset *);
 315 static int      mwl_newstate(struct ieee80211com *, enum ieee80211_state, int);
 316 static int      cvtrssi(uint8_t);
 317 static uint_t   mwl_intr(caddr_t, caddr_t);
 318 static uint_t   mwl_softintr(caddr_t, caddr_t);
 319 static void     mwl_tx_intr(struct mwl_softc *);
 320 static void     mwl_rx_intr(struct mwl_softc *);
 321 static int      mwl_init(struct mwl_softc *);
 322 static void     mwl_stop(struct mwl_softc *);
 323 static int      mwl_resume(struct mwl_softc *);
 324 
 325 
 326 #ifdef DEBUG
 327 static void
 328 mwl_debug(uint32_t dbg_flags, const int8_t *fmt, ...)
 329 {
 330         va_list args;
 331 
 332         if (dbg_flags & mwl_dbg_flags) {
 333                 va_start(args, fmt);
 334                 vcmn_err(CE_CONT, fmt, args);
 335                 va_end(args);
 336         }
 337 }
 338 #endif
 339 
 340 /*
 341  * Allocate an DMA memory and a DMA handle for accessing it
 342  */
 343 static int
 344 mwl_alloc_dma_mem(dev_info_t *devinfo, ddi_dma_attr_t *dma_attr,
 345         size_t memsize, ddi_device_acc_attr_t *attr_p, uint_t alloc_flags,
 346         uint_t bind_flags, struct dma_area *dma_p)
 347 {
 348         int err;
 349 
 350         /*
 351          * Allocate handle
 352          */
 353         err = ddi_dma_alloc_handle(devinfo, dma_attr,
 354             DDI_DMA_SLEEP, NULL, &dma_p->dma_hdl);
 355         if (err != DDI_SUCCESS) {
 356                 MWL_DBG(MWL_DBG_DMA, "mwl: mwl_alloc_dma_mem(): "
 357                     "failed to alloc handle\n");
 358                 goto fail1;
 359         }
 360 
 361         /*
 362          * Allocate memory
 363          */
 364         err = ddi_dma_mem_alloc(dma_p->dma_hdl, memsize, attr_p,
 365             alloc_flags, DDI_DMA_SLEEP, NULL, &dma_p->mem_va,
 366             &dma_p->alength, &dma_p->acc_hdl);
 367         if (err != DDI_SUCCESS) {
 368                 MWL_DBG(MWL_DBG_DMA, "mwl: mwl_alloc_dma_mem(): "
 369                     "failed to alloc mem\n");
 370                 goto fail2;
 371         }
 372 
 373         /*
 374          * Bind the two together
 375          */
 376         err = ddi_dma_addr_bind_handle(dma_p->dma_hdl, NULL,
 377             dma_p->mem_va, dma_p->alength, bind_flags,
 378             DDI_DMA_SLEEP, NULL, &dma_p->cookie, &dma_p->ncookies);
 379         if (err != DDI_DMA_MAPPED) {
 380                 MWL_DBG(MWL_DBG_DMA, "mwl: mwl_alloc_dma_mem(): "
 381                     "failed to bind handle\n");
 382                 goto fail3;
 383         }
 384 
 385         if (dma_p->ncookies != 1) {
 386                 MWL_DBG(MWL_DBG_DMA, "mwl: mwl_alloc_dma_mem(): "
 387                     "failed to alloc cookies\n");
 388                 goto fail4;
 389         }
 390 
 391         dma_p->nslots = ~0U;
 392         dma_p->size = ~0U;
 393         dma_p->token = ~0U;
 394         dma_p->offset = 0;
 395 
 396         return (DDI_SUCCESS);
 397 
 398 fail4:
 399         (void) ddi_dma_unbind_handle(dma_p->dma_hdl);
 400 fail3:
 401         ddi_dma_mem_free(&dma_p->acc_hdl);
 402 fail2:
 403         ddi_dma_free_handle(&dma_p->dma_hdl);
 404 fail1:
 405         return (err);
 406 }
 407 
 408 static void
 409 mwl_free_dma_mem(struct dma_area *dma_p)
 410 {
 411         if (dma_p->dma_hdl != NULL) {
 412                 (void) ddi_dma_unbind_handle(dma_p->dma_hdl);
 413                 if (dma_p->acc_hdl != NULL) {
 414                         ddi_dma_mem_free(&dma_p->acc_hdl);
 415                         dma_p->acc_hdl = NULL;
 416                 }
 417                 ddi_dma_free_handle(&dma_p->dma_hdl);
 418                 dma_p->ncookies = 0;
 419                 dma_p->dma_hdl = NULL;
 420         }
 421 }
 422 
 423 static int
 424 mwl_alloc_cmdbuf(struct mwl_softc *sc)
 425 {
 426         int err;
 427         size_t size;
 428 
 429         size = MWL_CMDBUF_SIZE;
 430 
 431         err = mwl_alloc_dma_mem(sc->sc_dev, &mwl_dma_attr, size,
 432             &mwl_cmdbuf_accattr, DDI_DMA_CONSISTENT,
 433             DDI_DMA_RDWR | DDI_DMA_CONSISTENT,
 434             &sc->sc_cmd_dma);
 435         if (err != DDI_SUCCESS) {
 436                 MWL_DBG(MWL_DBG_DMA, "mwl: mwl_alloc_cmdbuf(): "
 437                     "failed to alloc dma mem\n");
 438                 return (DDI_FAILURE);
 439         }
 440 
 441         sc->sc_cmd_mem = (uint16_t *)sc->sc_cmd_dma.mem_va;
 442         sc->sc_cmd_dmaaddr = sc->sc_cmd_dma.cookie.dmac_address;
 443 
 444         return (DDI_SUCCESS);
 445 }
 446 
 447 static void
 448 mwl_free_cmdbuf(struct mwl_softc *sc)
 449 {
 450         if (sc->sc_cmd_mem != NULL)
 451                 mwl_free_dma_mem(&sc->sc_cmd_dma);
 452 }
 453 
 454 static int
 455 mwl_alloc_rx_ring(struct mwl_softc *sc, int count)
 456 {
 457         struct mwl_rx_ring *ring;
 458         struct mwl_rxdesc *ds;
 459         struct mwl_rxbuf *bf;
 460         int i, err, datadlen;
 461 
 462         ring = &sc->sc_rxring;
 463         ring->count = count;
 464         ring->cur = ring->next = 0;
 465         err = mwl_alloc_dma_mem(sc->sc_dev, &mwl_dma_attr,
 466             count * sizeof (struct mwl_rxdesc),
 467             &mwl_desc_accattr,
 468             DDI_DMA_CONSISTENT, DDI_DMA_RDWR | DDI_DMA_CONSISTENT,
 469             &ring->rxdesc_dma);
 470         if (err) {
 471                 MWL_DBG(MWL_DBG_DMA, "mwl: mwl_alloc_rxring(): "
 472                     "alloc tx ring failed, size %d\n",
 473                     (uint32_t)(count * sizeof (struct mwl_rxdesc)));
 474                 return (DDI_FAILURE);
 475         }
 476 
 477         MWL_DBG(MWL_DBG_DMA, "mwl: mwl_alloc_rx_ring(): "
 478             "dma len = %d\n", (uint32_t)(ring->rxdesc_dma.alength));
 479         ring->desc = (struct mwl_rxdesc *)ring->rxdesc_dma.mem_va;
 480         ring->physaddr = ring->rxdesc_dma.cookie.dmac_address;
 481         bzero(ring->desc, count * sizeof (struct mwl_rxdesc));
 482 
 483         datadlen = count * sizeof (struct mwl_rxbuf);
 484         ring->buf = (struct mwl_rxbuf *)kmem_zalloc(datadlen, KM_SLEEP);
 485         if (ring->buf == NULL) {
 486                 MWL_DBG(MWL_DBG_DMA, "mwl: mwl_alloc_rxring(): "
 487                     "could not alloc rx ring data buffer\n");
 488                 return (DDI_FAILURE);
 489         }
 490         bzero(ring->buf, count * sizeof (struct mwl_rxbuf));
 491 
 492         /*
 493          * Pre-allocate Rx buffers and populate Rx ring.
 494          */
 495         for (i = 0; i < count; i++) {
 496                 ds = &ring->desc[i];
 497                 bf = &ring->buf[i];
 498                 /* alloc DMA memory */
 499                 (void) mwl_alloc_dma_mem(sc->sc_dev, &mwl_dma_attr,
 500                     sc->sc_dmabuf_size,
 501                     &mwl_buf_accattr,
 502                     DDI_DMA_STREAMING,
 503                     DDI_DMA_READ | DDI_DMA_STREAMING,
 504                     &bf->rxbuf_dma);
 505                 bf->bf_mem = (uint8_t *)(bf->rxbuf_dma.mem_va);
 506                 bf->bf_baddr = bf->rxbuf_dma.cookie.dmac_address;
 507                 bf->bf_desc = ds;
 508                 bf->bf_daddr = ring->physaddr + _PTRDIFF(ds, ring->desc);
 509         }
 510 
 511         (void) ddi_dma_sync(ring->rxdesc_dma.dma_hdl,
 512             0,
 513             ring->rxdesc_dma.alength,
 514             DDI_DMA_SYNC_FORDEV);
 515 
 516         return (0);
 517 }
 518 
 519 static void
 520 mwl_free_rx_ring(struct mwl_softc *sc)
 521 {
 522         struct mwl_rx_ring *ring;
 523         struct mwl_rxbuf *bf;
 524         int i;
 525 
 526         ring = &sc->sc_rxring;
 527 
 528         if (ring->desc != NULL) {
 529                 mwl_free_dma_mem(&ring->rxdesc_dma);
 530         }
 531 
 532         if (ring->buf != NULL) {
 533                 for (i = 0; i < ring->count; i++) {
 534                         bf = &ring->buf[i];
 535                         mwl_free_dma_mem(&bf->rxbuf_dma);
 536                 }
 537                 kmem_free(ring->buf,
 538                     (ring->count * sizeof (struct mwl_rxbuf)));
 539         }
 540 }
 541 
 542 static int
 543 mwl_alloc_tx_ring(struct mwl_softc *sc, struct mwl_tx_ring *ring,
 544     int count)
 545 {
 546         struct mwl_txdesc *ds;
 547         struct mwl_txbuf *bf;
 548         int i, err, datadlen;
 549 
 550         ring->count = count;
 551         ring->queued = 0;
 552         ring->cur = ring->next = ring->stat = 0;
 553         err = mwl_alloc_dma_mem(sc->sc_dev, &mwl_dma_attr,
 554             count * sizeof (struct mwl_txdesc), &mwl_desc_accattr,
 555             DDI_DMA_CONSISTENT, DDI_DMA_RDWR | DDI_DMA_CONSISTENT,
 556             &ring->txdesc_dma);
 557         if (err) {
 558                 MWL_DBG(MWL_DBG_DMA, "mwl: mwl_alloc_tx_ring(): "
 559                     "alloc tx ring failed, size %d\n",
 560                     (uint32_t)(count * sizeof (struct mwl_txdesc)));
 561                 return (DDI_FAILURE);
 562         }
 563 
 564         MWL_DBG(MWL_DBG_DMA, "mwl: mwl_alloc_tx_ring(): "
 565             "dma len = %d\n", (uint32_t)(ring->txdesc_dma.alength));
 566         ring->desc = (struct mwl_txdesc *)ring->txdesc_dma.mem_va;
 567         ring->physaddr = ring->txdesc_dma.cookie.dmac_address;
 568         bzero(ring->desc, count * sizeof (struct mwl_txdesc));
 569 
 570         datadlen = count * sizeof (struct mwl_txbuf);
 571         ring->buf = kmem_zalloc(datadlen, KM_SLEEP);
 572         if (ring->buf == NULL) {
 573                 MWL_DBG(MWL_DBG_DMA, "mwl: mwl_alloc_tx_ring(): "
 574                     "could not alloc tx ring data buffer\n");
 575                 return (DDI_FAILURE);
 576         }
 577         bzero(ring->buf, count * sizeof (struct mwl_txbuf));
 578 
 579         for (i = 0; i < count; i++) {
 580                 ds = &ring->desc[i];
 581                 bf = &ring->buf[i];
 582                 /* alloc DMA memory */
 583                 (void) mwl_alloc_dma_mem(sc->sc_dev, &mwl_dma_attr,
 584                     sc->sc_dmabuf_size,
 585                     &mwl_buf_accattr,
 586                     DDI_DMA_STREAMING,
 587                     DDI_DMA_WRITE | DDI_DMA_STREAMING,
 588                     &bf->txbuf_dma);
 589                 bf->bf_baddr = bf->txbuf_dma.cookie.dmac_address;
 590                 bf->bf_mem = (uint8_t *)(bf->txbuf_dma.mem_va);
 591                 bf->bf_daddr = ring->physaddr + _PTRDIFF(ds, ring->desc);
 592                 bf->bf_desc = ds;
 593         }
 594 
 595         (void) ddi_dma_sync(ring->txdesc_dma.dma_hdl,
 596             0,
 597             ring->txdesc_dma.alength,
 598             DDI_DMA_SYNC_FORDEV);
 599 
 600         return (0);
 601 }
 602 
 603 /* ARGSUSED */
 604 static void
 605 mwl_free_tx_ring(struct mwl_softc *sc, struct mwl_tx_ring *ring)
 606 {
 607         struct mwl_txbuf *bf;
 608         int i;
 609 
 610         if (ring->desc != NULL) {
 611                 mwl_free_dma_mem(&ring->txdesc_dma);
 612         }
 613 
 614         if (ring->buf != NULL) {
 615                 for (i = 0; i < ring->count; i++) {
 616                         bf = &ring->buf[i];
 617                         mwl_free_dma_mem(&bf->txbuf_dma);
 618                 }
 619                 kmem_free(ring->buf,
 620                     (ring->count * sizeof (struct mwl_txbuf)));
 621         }
 622 }
 623 
 624 /*
 625  * Inform the f/w about location of the tx/rx dma data structures
 626  * and related state.  This cmd must be done immediately after a
 627  * mwl_hal_gethwspecs call or the f/w will lockup.
 628  */
 629 static int
 630 mwl_hal_sethwdma(struct mwl_softc *sc, const struct mwl_hal_txrxdma *dma)
 631 {
 632         HostCmd_DS_SET_HW_SPEC *pCmd;
 633         int retval;
 634 
 635         _CMD_SETUP(pCmd, HostCmd_DS_SET_HW_SPEC, HostCmd_CMD_SET_HW_SPEC);
 636         pCmd->WcbBase[0] = LE_32(dma->wcbBase[0]);
 637         pCmd->WcbBase[1] = LE_32(dma->wcbBase[1]);
 638         pCmd->WcbBase[2] = LE_32(dma->wcbBase[2]);
 639         pCmd->WcbBase[3] = LE_32(dma->wcbBase[3]);
 640         pCmd->TxWcbNumPerQueue = LE_32(dma->maxNumTxWcb);
 641         pCmd->NumTxQueues = LE_32(dma->maxNumWCB);
 642         pCmd->TotalRxWcb = LE_32(1);         /* XXX */
 643         pCmd->RxPdWrPtr = LE_32(dma->rxDescRead);
 644         /*
 645          * pCmd->Flags = LE_32(SET_HW_SPEC_HOSTFORM_BEACON
 646          * #ifdef MWL_HOST_PS_SUPPORT
 647          * | SET_HW_SPEC_HOST_POWERSAVE
 648          * #endif
 649          * | SET_HW_SPEC_HOSTFORM_PROBERESP);
 650          */
 651         pCmd->Flags = 0;
 652         /* disable multi-bss operation for A1-A4 parts */
 653         if (sc->sc_revs.mh_macRev < 5)
 654                 pCmd->Flags |= LE_32(SET_HW_SPEC_DISABLEMBSS);
 655 
 656         retval = mwlExecuteCmd(sc, HostCmd_CMD_SET_HW_SPEC);
 657         if (retval == 0) {
 658                 if (pCmd->Flags & LE_32(SET_HW_SPEC_DISABLEMBSS))
 659                         sc->sc_hw_flags &= ~MHF_MBSS;
 660                 else
 661                         sc->sc_hw_flags |= MHF_MBSS;
 662         }
 663 
 664         return (retval);
 665 }
 666 
 667 /*
 668  * Inform firmware of our tx/rx dma setup.  The BAR 0
 669  * writes below are for compatibility with older firmware.
 670  * For current firmware we send this information with a
 671  * cmd block via mwl_hal_sethwdma.
 672  */
 673 static int
 674 mwl_setupdma(struct mwl_softc *sc)
 675 {
 676         int i, err;
 677 
 678         sc->sc_hwdma.rxDescRead = sc->sc_rxring.physaddr;
 679         mwl_mem_write4(sc, sc->sc_hwspecs.rxDescRead, sc->sc_hwdma.rxDescRead);
 680         mwl_mem_write4(sc, sc->sc_hwspecs.rxDescWrite, sc->sc_hwdma.rxDescRead);
 681 
 682         for (i = 0; i < MWL_NUM_TX_QUEUES - MWL_NUM_ACK_QUEUES; i++) {
 683                 struct mwl_tx_ring *txring = &sc->sc_txring[i];
 684                 sc->sc_hwdma.wcbBase[i] = txring->physaddr;
 685                 mwl_mem_write4(sc, sc->sc_hwspecs.wcbBase[i],
 686                     sc->sc_hwdma.wcbBase[i]);
 687         }
 688         sc->sc_hwdma.maxNumTxWcb = MWL_TX_RING_COUNT;
 689         sc->sc_hwdma.maxNumWCB = MWL_NUM_TX_QUEUES - MWL_NUM_ACK_QUEUES;
 690 
 691         err = mwl_hal_sethwdma(sc, &sc->sc_hwdma);
 692         if (err != 0) {
 693                 MWL_DBG(MWL_DBG_DMA, "mwl: mwl_setupdma(): "
 694                     "unable to setup tx/rx dma; hal status %u\n", err);
 695                 /* XXX */
 696         }
 697 
 698         return (err);
 699 }
 700 
 701 /* ARGSUSED */
 702 static void
 703 mwl_txq_init(struct mwl_softc *sc, struct mwl_tx_ring *txring, int qnum)
 704 {
 705         struct mwl_txbuf *bf;
 706         struct mwl_txdesc *ds;
 707         int i;
 708 
 709         txring->qnum = qnum;
 710         txring->txpri = 0;   /* XXX */
 711 
 712         bf = txring->buf;
 713         ds = txring->desc;
 714         for (i = 0; i < MWL_TX_RING_COUNT - 1; i++) {
 715                 bf++;
 716                 ds->pPhysNext = bf->bf_daddr;
 717                 ds++;
 718         }
 719         bf = txring->buf;
 720         ds->pPhysNext = LE_32(bf->bf_daddr);
 721 }
 722 
 723 /*
 724  * Setup a hardware data transmit queue for the specified
 725  * access control.  We record the mapping from ac's
 726  * to h/w queues for use by mwl_tx_start.
 727  */
 728 static int
 729 mwl_tx_setup(struct mwl_softc *sc, int ac, int mvtype)
 730 {
 731 #define N(a)    (sizeof (a)/sizeof (a[0]))
 732         struct mwl_tx_ring *txring;
 733 
 734         if (ac >= N(sc->sc_ac2q)) {
 735                 MWL_DBG(MWL_DBG_DMA, "mwl: mwl_tx_setup(): "
 736                     "AC %u out of range, max %u!\n",
 737                     ac, (uint_t)N(sc->sc_ac2q));
 738                 return (0);
 739         }
 740         if (mvtype >= MWL_NUM_TX_QUEUES) {
 741                 MWL_DBG(MWL_DBG_DMA, "mwl: mwl_tx_setup(): "
 742                     "mvtype %u out of range, max %u!\n",
 743                     mvtype, MWL_NUM_TX_QUEUES);
 744                 return (0);
 745         }
 746         txring = &sc->sc_txring[mvtype];
 747         mwl_txq_init(sc, txring, mvtype);
 748         sc->sc_ac2q[ac] = txring;
 749         return (1);
 750 #undef N
 751 }
 752 
 753 static int
 754 mwl_setup_txq(struct mwl_softc *sc)
 755 {
 756         int err = 0;
 757 
 758         /* NB: insure BK queue is the lowest priority h/w queue */
 759         if (!mwl_tx_setup(sc, WME_AC_BK, MWL_WME_AC_BK)) {
 760                 MWL_DBG(MWL_DBG_DMA, "mwl: mwl_setup_txq(): "
 761                     "unable to setup xmit queue for %s traffic!\n",
 762                     mwl_wme_acnames[WME_AC_BK]);
 763                 err = EIO;
 764                 return (err);
 765         }
 766         if (!mwl_tx_setup(sc, WME_AC_BE, MWL_WME_AC_BE) ||
 767             !mwl_tx_setup(sc, WME_AC_VI, MWL_WME_AC_VI) ||
 768             !mwl_tx_setup(sc, WME_AC_VO, MWL_WME_AC_VO)) {
 769                 /*
 770                  * Not enough hardware tx queues to properly do WME;
 771                  * just punt and assign them all to the same h/w queue.
 772                  * We could do a better job of this if, for example,
 773                  * we allocate queues when we switch from station to
 774                  * AP mode.
 775                  */
 776                 sc->sc_ac2q[WME_AC_BE] = sc->sc_ac2q[WME_AC_BK];
 777                 sc->sc_ac2q[WME_AC_VI] = sc->sc_ac2q[WME_AC_BK];
 778                 sc->sc_ac2q[WME_AC_VO] = sc->sc_ac2q[WME_AC_BK];
 779         }
 780 
 781         return (err);
 782 }
 783 
 784 /*
 785  * find mwl firmware module's "_start" "_end" symbols
 786  * and get its size.
 787  */
 788 static int
 789 mwl_loadsym(ddi_modhandle_t modp, char *sym, char **start, size_t *len)
 790 {
 791         char start_sym[64];
 792         char end_sym[64];
 793         char *p, *end;
 794         int rv;
 795         size_t n;
 796 
 797         (void) snprintf(start_sym, sizeof (start_sym), "%s_start", sym);
 798         (void) snprintf(end_sym, sizeof (end_sym), "%s_end", sym);
 799 
 800         p = (char *)ddi_modsym(modp, start_sym, &rv);
 801         if (p == NULL || rv != 0) {
 802                 MWL_DBG(MWL_DBG_FW, "mwl: mwl_loadsym(): "
 803                     "mod %s: symbol %s not found\n", sym, start_sym);
 804                 return (-1);
 805         }
 806 
 807         end = (char *)ddi_modsym(modp, end_sym, &rv);
 808         if (end == NULL || rv != 0) {
 809                 MWL_DBG(MWL_DBG_FW, "mwl: mwl_loadsym(): "
 810                     "mod %s: symbol %s not found\n", sym, end_sym);
 811                 return (-1);
 812         }
 813 
 814         n = _PTRDIFF(end, p);
 815         *start = p;
 816         *len = n;
 817 
 818         return (0);
 819 }
 820 
 821 static void
 822 mwlFwReset(struct mwl_softc *sc)
 823 {
 824         if (mwl_ctl_read4(sc,  MACREG_REG_INT_CODE) == 0xffffffff) {
 825                 MWL_DBG(MWL_DBG_FW, "mwl: mwlFWReset(): "
 826                     "device not present!\n");
 827                 return;
 828         }
 829 
 830         mwl_ctl_write4(sc, MACREG_REG_H2A_INTERRUPT_EVENTS, ISR_RESET);
 831         sc->sc_hw_flags &= ~MHF_FWHANG;
 832 }
 833 
 834 static void
 835 mwlPokeSdramController(struct mwl_softc *sc, int SDRAMSIZE_Addr)
 836 {
 837         /* Set up sdram controller for superflyv2 */
 838         mwl_ctl_write4(sc, 0x00006014, 0x33);
 839         mwl_ctl_write4(sc, 0x00006018, 0xa3a2632);
 840         mwl_ctl_write4(sc, 0x00006010, SDRAMSIZE_Addr);
 841 }
 842 
 843 static void
 844 mwlTriggerPciCmd(struct mwl_softc *sc)
 845 {
 846         (void) ddi_dma_sync(sc->sc_cmd_dma.dma_hdl,
 847             0,
 848             sc->sc_cmd_dma.alength,
 849             DDI_DMA_SYNC_FORDEV);
 850 
 851         mwl_ctl_write4(sc, MACREG_REG_GEN_PTR, sc->sc_cmd_dmaaddr);
 852         (void) mwl_ctl_read4(sc, MACREG_REG_INT_CODE);
 853 
 854         mwl_ctl_write4(sc, MACREG_REG_INT_CODE, 0x00);
 855         (void) mwl_ctl_read4(sc, MACREG_REG_INT_CODE);
 856 
 857         mwl_ctl_write4(sc, MACREG_REG_H2A_INTERRUPT_EVENTS,
 858             MACREG_H2ARIC_BIT_DOOR_BELL);
 859         (void) mwl_ctl_read4(sc, MACREG_REG_INT_CODE);
 860 }
 861 
 862 static int
 863 mwlWaitFor(struct mwl_softc *sc, uint32_t val)
 864 {
 865         int i;
 866 
 867         for (i = 0; i < FW_MAX_NUM_CHECKS; i++) {
 868                 DELAY(FW_CHECK_USECS);
 869                 if (mwl_ctl_read4(sc, MACREG_REG_INT_CODE) == val)
 870                         return (1);
 871         }
 872         return (0);
 873 }
 874 
 875 /*
 876  * Firmware block xmit when talking to the boot-rom.
 877  */
 878 static int
 879 mwlSendBlock(struct mwl_softc *sc, int bsize, const void *data, size_t dsize)
 880 {
 881         sc->sc_cmd_mem[0] = LE_16(HostCmd_CMD_CODE_DNLD);
 882         sc->sc_cmd_mem[1] = LE_16(bsize);
 883         (void) memcpy(&sc->sc_cmd_mem[4], data, dsize);
 884         mwlTriggerPciCmd(sc);
 885         /* XXX 2000 vs 200 */
 886         if (mwlWaitFor(sc, MACREG_INT_CODE_CMD_FINISHED)) {
 887                 mwl_ctl_write4(sc, MACREG_REG_INT_CODE, 0);
 888                 return (1);
 889         }
 890 
 891         MWL_DBG(MWL_DBG_FW, "mwl: mwlSendBlock(): "
 892             "timeout waiting for CMD_FINISHED, INT_CODE 0x%x\n",
 893             mwl_ctl_read4(sc, MACREG_REG_INT_CODE));
 894         return (0);
 895 }
 896 
 897 /*
 898  * Firmware block xmit when talking to the 1st-stage loader.
 899  */
 900 static int
 901 mwlSendBlock2(struct mwl_softc *sc, const void *data, size_t dsize)
 902 {
 903         (void) memcpy(&sc->sc_cmd_mem[0], data, dsize);
 904         mwlTriggerPciCmd(sc);
 905         if (mwlWaitFor(sc, MACREG_INT_CODE_CMD_FINISHED)) {
 906                 mwl_ctl_write4(sc, MACREG_REG_INT_CODE, 0);
 907                 return (1);
 908         }
 909 
 910         MWL_DBG(MWL_DBG_FW, "mwl: mwlSendBlock2(): "
 911             "timeout waiting for CMD_FINISHED, INT_CODE 0x%x\n",
 912             mwl_ctl_read4(sc, MACREG_REG_INT_CODE));
 913         return (0);
 914 }
 915 
 916 /* ARGSUSED */
 917 static int
 918 mwl_fwload(struct mwl_softc *sc, void *fwargs)
 919 {
 920         char *fwname = "mwlfw";
 921         char *fwbootname = "mwlboot";
 922         char *fwbinname = "mw88W8363fw";
 923         char *fwboot_index, *fw_index;
 924         uint8_t *fw, *fwboot;
 925         ddi_modhandle_t modfw;
 926         /* XXX get from firmware header */
 927         uint32_t FwReadySignature = HostCmd_SOFTAP_FWRDY_SIGNATURE;
 928         uint32_t OpMode = HostCmd_SOFTAP_MODE;
 929         const uint8_t *fp, *ep;
 930         size_t fw_size, fwboot_size;
 931         uint32_t blocksize, nbytes;
 932         int i, rv, err, ntries;
 933 
 934         rv = err = 0;
 935         fw = fwboot = NULL;
 936         fw_index = fwboot_index = NULL;
 937 
 938         modfw = ddi_modopen(fwname, KRTLD_MODE_FIRST, &rv);
 939         if (modfw == NULL) {
 940                 MWL_DBG(MWL_DBG_FW, "mwl: mwl_fwload(): "
 941                     "module %s not found\n", fwname);
 942                 err = -1;
 943                 goto bad2;
 944         }
 945 
 946         err = mwl_loadsym(modfw, fwbootname, &fwboot_index, &fwboot_size);
 947         if (err != 0) {
 948                 MWL_DBG(MWL_DBG_FW, "mwl: mwl_fwload(): "
 949                     "could not get boot firmware\n");
 950                 err = -1;
 951                 goto bad2;
 952         }
 953 
 954         err = mwl_loadsym(modfw, fwbinname, &fw_index, &fw_size);
 955         if (err != 0) {
 956                 MWL_DBG(MWL_DBG_FW, "mwl: mwl_fwload(): "
 957                     "could not get firmware\n");
 958                 err = -1;
 959                 goto bad2;
 960         }
 961 
 962         fwboot = (uint8_t *)kmem_alloc(fwboot_size, KM_SLEEP);
 963         if (fwboot == NULL) {
 964                 MWL_DBG(MWL_DBG_FW, "mwl: mwl_loadfirmware(): "
 965                     "failed to alloc boot firmware memory\n");
 966                 err = -1;
 967                 goto bad2;
 968         }
 969         (void) memcpy(fwboot, fwboot_index, fwboot_size);
 970 
 971         fw = (uint8_t *)kmem_alloc(fw_size, KM_SLEEP);
 972         if (fw == NULL) {
 973                 MWL_DBG(MWL_DBG_FW, "mwl: mwl_loadfirmware(): "
 974                     "failed to alloc firmware memory\n");
 975                 err = -1;
 976                 goto bad2;
 977         }
 978         (void) memcpy(fw, fw_index, fw_size);
 979 
 980         if (modfw != NULL)
 981                 (void) ddi_modclose(modfw);
 982 
 983         if (fw_size < 4) {
 984                 MWL_DBG(MWL_DBG_FW, "mwl: mwl_fwload(): "
 985                     "could not load firmware image %s\n",
 986                     fwname);
 987                 err = ENXIO;
 988                 goto bad2;
 989         }
 990 
 991         if (fw[0] == 0x01 && fw[1] == 0x00 &&
 992             fw[2] == 0x00 && fw[3] == 0x00) {
 993                 /*
 994                  * 2-stage load, get the boot firmware.
 995                  */
 996                 if (fwboot == NULL) {
 997                         MWL_DBG(MWL_DBG_FW, "mwl: mwl_fwload(): "
 998                             "could not load firmware image %s\n",
 999                             fwbootname);
1000                         err = ENXIO;
1001                         goto bad2;
1002                 }
1003         } else
1004                 fwboot = NULL;
1005 
1006         mwlFwReset(sc);
1007 
1008         mwl_ctl_write4(sc, MACREG_REG_A2H_INTERRUPT_CLEAR_SEL,
1009             MACREG_A2HRIC_BIT_MASK);
1010         mwl_ctl_write4(sc, MACREG_REG_A2H_INTERRUPT_CAUSE, 0x00);
1011         mwl_ctl_write4(sc, MACREG_REG_A2H_INTERRUPT_MASK, 0x00);
1012         mwl_ctl_write4(sc, MACREG_REG_A2H_INTERRUPT_STATUS_MASK,
1013             MACREG_A2HRIC_BIT_MASK);
1014         if (sc->sc_SDRAMSIZE_Addr != 0) {
1015                 /* Set up sdram controller for superflyv2 */
1016                 mwlPokeSdramController(sc, sc->sc_SDRAMSIZE_Addr);
1017         }
1018 
1019         MWL_DBG(MWL_DBG_FW, "mwl: mwl_fwload(): "
1020             "load %s firmware image (%u bytes)\n",
1021             fwname, (unsigned int)fw_size);
1022 
1023         if (fwboot != NULL) {
1024                 /*
1025                  * Do 2-stage load.  The 1st stage loader is setup
1026                  * with the bootrom loader then we load the real
1027                  * image using a different handshake. With this
1028                  * mechanism the firmware is segmented into chunks
1029                  * that have a CRC.  If a chunk is incorrect we'll
1030                  * be told to retransmit.
1031                  */
1032                 /* XXX assumes hlpimage fits in a block */
1033                 /* NB: zero size block indicates download is finished */
1034                 if (!mwlSendBlock(sc, fwboot_size, fwboot, fwboot_size) ||
1035                     !mwlSendBlock(sc, 0, NULL, 0)) {
1036                         err = ETIMEDOUT;
1037                         goto bad;
1038                 }
1039                 DELAY(200 * FW_CHECK_USECS);
1040                 if (sc->sc_SDRAMSIZE_Addr != 0) {
1041                         /* Set up sdram controller for superflyv2 */
1042                         mwlPokeSdramController(sc, sc->sc_SDRAMSIZE_Addr);
1043                 }
1044                 nbytes = ntries = 0;            /* NB: silence compiler */
1045                 for (fp = fw, ep = fp + fw_size; fp < ep; ) {
1046                         mwl_ctl_write4(sc, MACREG_REG_INT_CODE, 0);
1047                         blocksize = mwl_ctl_read4(sc, MACREG_REG_SCRATCH);
1048                         if (blocksize == 0)     /* download complete */
1049                                 break;
1050                         if (blocksize > 0x00000c00) {
1051                                 err = EINVAL;
1052                                 goto bad;
1053                         }
1054                         if ((blocksize & 0x1) == 0) {
1055                                 /* block successfully downloaded, advance */
1056                                 fp += nbytes;
1057                                 ntries = 0;
1058                         } else {
1059                                 if (++ntries > 2) {
1060                                         /*
1061                                          * Guard against f/w telling us to
1062                                          * retry infinitely.
1063                                          */
1064                                         err = ELOOP;
1065                                         goto bad;
1066                                 }
1067                                 /* clear NAK bit/flag */
1068                                 blocksize &= ~0x1;
1069                         }
1070                         if (blocksize > _PTRDIFF(ep, fp)) {
1071                                 /* XXX this should not happen, what to do? */
1072                                 blocksize = _PTRDIFF(ep, fp);
1073                         }
1074                         nbytes = blocksize;
1075                         if (!mwlSendBlock2(sc, fp, nbytes)) {
1076                                 err = ETIMEDOUT;
1077                                 goto bad;
1078                         }
1079                 }
1080         } else {
1081                 for (fp = fw, ep = fp + fw_size; fp < ep; ) {
1082                         nbytes = _PTRDIFF(ep, fp);
1083                         if (nbytes > FW_DOWNLOAD_BLOCK_SIZE)
1084                                 nbytes = FW_DOWNLOAD_BLOCK_SIZE;
1085                         if (!mwlSendBlock(sc, FW_DOWNLOAD_BLOCK_SIZE, fp,
1086                             nbytes)) {
1087                                 err = EIO;
1088                                 goto bad;
1089                         }
1090                         fp += nbytes;
1091                 }
1092         }
1093 
1094         /*
1095          * Wait for firmware to startup; we monitor the
1096          * INT_CODE register waiting for a signature to
1097          * written back indicating it's ready to go.
1098          */
1099         sc->sc_cmd_mem[1] = 0;
1100         /*
1101          * XXX WAR for mfg fw download
1102          */
1103         if (OpMode != HostCmd_STA_MODE)
1104                 mwlTriggerPciCmd(sc);
1105         for (i = 0; i < FW_MAX_NUM_CHECKS; i++) {
1106                 mwl_ctl_write4(sc, MACREG_REG_GEN_PTR, OpMode);
1107                 DELAY(FW_CHECK_USECS);
1108                 if (mwl_ctl_read4(sc, MACREG_REG_INT_CODE) ==
1109                     FwReadySignature) {
1110                         mwl_ctl_write4(sc, MACREG_REG_INT_CODE, 0x00);
1111                         return (mwlResetHalState(sc));
1112                 }
1113         }
1114         MWL_DBG(MWL_DBG_FW, "mwl: mwl_fwload(): "
1115             "firmware download timeout\n");
1116         return (ETIMEDOUT);
1117 bad:
1118         mwlFwReset(sc);
1119 bad2:
1120         if (fw != NULL)
1121                 kmem_free(fw, fw_size);
1122         if (fwboot != NULL)
1123                 kmem_free(fwboot, fwboot_size);
1124         fwboot = fw = NULL;
1125         fwboot_index = fw_index = NULL;
1126         if (modfw != NULL)
1127                 (void) ddi_modclose(modfw);
1128         return (err);
1129 }
1130 
1131 /*
1132  * Low level firmware cmd block handshake support.
1133  */
1134 static void
1135 mwlSendCmd(struct mwl_softc *sc)
1136 {
1137         (void) ddi_dma_sync(sc->sc_cmd_dma.dma_hdl,
1138             0,
1139             sc->sc_cmd_dma.alength,
1140             DDI_DMA_SYNC_FORDEV);
1141 
1142         mwl_ctl_write4(sc, MACREG_REG_GEN_PTR, sc->sc_cmd_dmaaddr);
1143         (void) mwl_ctl_read4(sc, MACREG_REG_INT_CODE);
1144 
1145         mwl_ctl_write4(sc, MACREG_REG_H2A_INTERRUPT_EVENTS,
1146             MACREG_H2ARIC_BIT_DOOR_BELL);
1147 }
1148 
1149 static int
1150 mwlExecuteCmd(struct mwl_softc *sc, unsigned short cmd)
1151 {
1152         if (mwl_ctl_read4(sc,  MACREG_REG_INT_CODE) == 0xffffffff) {
1153                 MWL_DBG(MWL_DBG_CMD, "mwl: mwlExecuteCmd(): "
1154                     "device not present!\n");
1155                 return (EIO);
1156         }
1157         mwlSendCmd(sc);
1158         if (!mwlWaitForCmdComplete(sc, 0x8000 | cmd)) {
1159                 MWL_DBG(MWL_DBG_CMD, "mwl: mwlExecuteCmd(): "
1160                     "timeout waiting for f/w cmd %s\n", mwlcmdname(cmd));
1161                 return (ETIMEDOUT);
1162         }
1163         (void) ddi_dma_sync(sc->sc_cmd_dma.dma_hdl,
1164             0,
1165             sc->sc_cmd_dma.alength,
1166             DDI_DMA_SYNC_FORDEV);
1167 
1168         MWL_DBG(MWL_DBG_CMD, "mwl: mwlExecuteCmd(): "
1169             "send cmd %s\n", mwlcmdname(cmd));
1170 
1171         if (mwl_dbg_flags & MWL_DBG_CMD)
1172                 dumpresult(sc, 1);
1173 
1174         return (0);
1175 }
1176 
1177 static int
1178 mwlWaitForCmdComplete(struct mwl_softc *sc, uint16_t cmdCode)
1179 {
1180 #define MAX_WAIT_FW_COMPLETE_ITERATIONS 10000
1181         int i;
1182 
1183         for (i = 0; i < MAX_WAIT_FW_COMPLETE_ITERATIONS; i++) {
1184                 if (sc->sc_cmd_mem[0] == LE_16(cmdCode))
1185                         return (1);
1186                 DELAY(1 * 1000);
1187         }
1188         return (0);
1189 #undef MAX_WAIT_FW_COMPLETE_ITERATIONS
1190 }
1191 
1192 static const char *
1193 mwlcmdname(int cmd)
1194 {
1195         static char buf[12];
1196 #define CMD(x)  case HostCmd_CMD_##x: return #x
1197         switch (cmd) {
1198         CMD(CODE_DNLD);
1199         CMD(GET_HW_SPEC);
1200         CMD(SET_HW_SPEC);
1201         CMD(MAC_MULTICAST_ADR);
1202         CMD(802_11_GET_STAT);
1203         CMD(MAC_REG_ACCESS);
1204         CMD(BBP_REG_ACCESS);
1205         CMD(RF_REG_ACCESS);
1206         CMD(802_11_RADIO_CONTROL);
1207         CMD(802_11_RF_TX_POWER);
1208         CMD(802_11_RF_ANTENNA);
1209         CMD(SET_BEACON);
1210         CMD(SET_RF_CHANNEL);
1211         CMD(SET_AID);
1212         CMD(SET_INFRA_MODE);
1213         CMD(SET_G_PROTECT_FLAG);
1214         CMD(802_11_RTS_THSD);
1215         CMD(802_11_SET_SLOT);
1216         CMD(SET_EDCA_PARAMS);
1217         CMD(802_11H_DETECT_RADAR);
1218         CMD(SET_WMM_MODE);
1219         CMD(HT_GUARD_INTERVAL);
1220         CMD(SET_FIXED_RATE);
1221         CMD(SET_LINKADAPT_CS_MODE);
1222         CMD(SET_MAC_ADDR);
1223         CMD(SET_RATE_ADAPT_MODE);
1224         CMD(BSS_START);
1225         CMD(SET_NEW_STN);
1226         CMD(SET_KEEP_ALIVE);
1227         CMD(SET_APMODE);
1228         CMD(SET_SWITCH_CHANNEL);
1229         CMD(UPDATE_ENCRYPTION);
1230         CMD(BASTREAM);
1231         CMD(SET_RIFS);
1232         CMD(SET_N_PROTECT_FLAG);
1233         CMD(SET_N_PROTECT_OPMODE);
1234         CMD(SET_OPTIMIZATION_LEVEL);
1235         CMD(GET_CALTABLE);
1236         CMD(SET_MIMOPSHT);
1237         CMD(GET_BEACON);
1238         CMD(SET_REGION_CODE);
1239         CMD(SET_POWERSAVESTATION);
1240         CMD(SET_TIM);
1241         CMD(GET_TIM);
1242         CMD(GET_SEQNO);
1243         CMD(DWDS_ENABLE);
1244         CMD(AMPDU_RETRY_RATEDROP_MODE);
1245         CMD(CFEND_ENABLE);
1246         }
1247         (void) snprintf(buf, sizeof (buf), "0x%x", cmd);
1248         return (buf);
1249 #undef CMD
1250 }
1251 
1252 static void
1253 dumpresult(struct mwl_softc *sc, int showresult)
1254 {
1255         const FWCmdHdr *h = (const FWCmdHdr *)sc->sc_cmd_mem;
1256         int len;
1257 
1258         len = LE_16(h->Length);
1259 #ifdef MWL_MBSS_SUPPORT
1260         MWL_DBG(MWL_DBG_CMD, "mwl: mwl_dumpresult(): "
1261             "Cmd %s Length %d SeqNum %d MacId %d",
1262             mwlcmdname(LE_16(h->Cmd) & ~0x8000), len, h->SeqNum, h->MacId);
1263 #else
1264         MWL_DBG(MWL_DBG_CMD, "mwl: mwl_dumpresult(): "
1265             "Cmd %s Length %d SeqNum %d",
1266             mwlcmdname(LE_16(h->Cmd) & ~0x8000), len, LE_16(h->SeqNum));
1267 #endif
1268         if (showresult) {
1269                 const char *results[] =
1270                     { "OK", "ERROR", "NOT_SUPPORT", "PENDING", "BUSY",
1271                     "PARTIAL_DATA" };
1272                 int result = LE_16(h->Result);
1273 
1274                 if (result <= HostCmd_RESULT_PARTIAL_DATA)
1275                         MWL_DBG(MWL_DBG_CMD, "mwl: dumpresult(): "
1276                             "Result %s", results[result]);
1277                 else
1278                         MWL_DBG(MWL_DBG_CMD, "mwl: dumpresult(): "
1279                             "Result %d", result);
1280         }
1281 }
1282 
1283 static int
1284 mwlGetCalTable(struct mwl_softc *sc, uint8_t annex, uint8_t index)
1285 {
1286         HostCmd_FW_GET_CALTABLE *pCmd;
1287         int retval;
1288 
1289         _CMD_SETUP(pCmd, HostCmd_FW_GET_CALTABLE, HostCmd_CMD_GET_CALTABLE);
1290         pCmd->annex = annex;
1291         pCmd->index = index;
1292         (void) memset(pCmd->calTbl, 0, sizeof (pCmd->calTbl));
1293 
1294         retval = mwlExecuteCmd(sc, HostCmd_CMD_GET_CALTABLE);
1295         if (retval == 0 &&
1296             pCmd->calTbl[0] != annex && annex != 0 && annex != 255)
1297                 retval = EIO;
1298         return (retval);
1299 }
1300 
1301 /*
1302  * Construct channel info for 2.4GHz channels from cal data.
1303  */
1304 static void
1305 get2Ghz(MWL_HAL_CHANNELINFO *ci, const uint8_t table[], int len)
1306 {
1307         int i, j;
1308 
1309         j = 0;
1310         for (i = 0; i < len; i += 4) {
1311                 struct mwl_hal_channel *hc = &ci->channels[j];
1312                 hc->ieee = 1+j;
1313                 hc->freq = ieee2mhz(1+j);
1314                 (void) memcpy(hc->targetPowers, &table[i], 4);
1315                 setmaxtxpow(hc, 0, 4);
1316                 j++;
1317         }
1318         ci->nchannels = j;
1319         ci->freqLow = ieee2mhz(1);
1320         ci->freqHigh = ieee2mhz(j);
1321 }
1322 
1323 /*
1324  * Construct channel info for 5GHz channels from cal data.
1325  */
1326 static void
1327 get5Ghz(MWL_HAL_CHANNELINFO *ci, const uint8_t table[], int len)
1328 {
1329         int i, j, f, l, h;
1330 
1331         l = 32000;
1332         h = 0;
1333         j = 0;
1334         for (i = 0; i < len; i += 4) {
1335                 struct mwl_hal_channel *hc;
1336 
1337                 if (table[i] == 0)
1338                         continue;
1339                 f = 5000 + 5*table[i];
1340                 if (f < l)
1341                         l = f;
1342                 if (f > h)
1343                         h = f;
1344                 hc = &ci->channels[j];
1345                 hc->freq = (uint16_t)f;
1346                 hc->ieee = table[i];
1347                 (void) memcpy(hc->targetPowers, &table[i], 4);
1348                 setmaxtxpow(hc, 1, 4);  /* NB: col 1 is the freq, skip */
1349                 j++;
1350         }
1351         ci->nchannels = j;
1352         ci->freqLow = (uint16_t)((l == 32000) ? 0 : l);
1353         ci->freqHigh = (uint16_t)h;
1354 }
1355 
1356 /*
1357  * Calculate the max tx power from the channel's cal data.
1358  */
1359 static void
1360 setmaxtxpow(struct mwl_hal_channel *hc, int i, int maxix)
1361 {
1362         hc->maxTxPow = hc->targetPowers[i];
1363         for (i++; i < maxix; i++)
1364                 if (hc->targetPowers[i] > hc->maxTxPow)
1365                         hc->maxTxPow = hc->targetPowers[i];
1366 }
1367 
1368 static uint16_t
1369 ieee2mhz(int chan)
1370 {
1371         if (chan == 14)
1372                 return (2484);
1373         if (chan < 14)
1374                 return (2407 + chan * 5);
1375         return (2512 + (chan - 15) * 20);
1376 }
1377 
1378 static void
1379 dumpcaldata(const char *name, const uint8_t *table, int n)
1380 {
1381         int i;
1382         MWL_DBG(MWL_DBG_HW, "\n%s:\n", name);
1383         for (i = 0; i < n; i += 4)
1384                 MWL_DBG(MWL_DBG_HW, "[%2d] %3d %3d %3d %3d\n",
1385                     i/4, table[i+0], table[i+1], table[i+2], table[i+3]);
1386 }
1387 
1388 static int
1389 mwlGetPwrCalTable(struct mwl_softc *sc)
1390 {
1391         const uint8_t *data;
1392         MWL_HAL_CHANNELINFO *ci;
1393         int len;
1394 
1395         /* NB: we hold the lock so it's ok to use cmdbuf */
1396         data = ((const HostCmd_FW_GET_CALTABLE *) sc->sc_cmd_mem)->calTbl;
1397         if (mwlGetCalTable(sc, 33, 0) == 0) {
1398                 len = (data[2] | (data[3] << 8)) - 12;
1399                 if (len > PWTAGETRATETABLE20M)
1400                         len = PWTAGETRATETABLE20M;
1401                 dumpcaldata("2.4G 20M", &data[12], len);
1402                 get2Ghz(&sc->sc_20M, &data[12], len);
1403         }
1404         if (mwlGetCalTable(sc, 34, 0) == 0) {
1405                 len = (data[2] | (data[3] << 8)) - 12;
1406                 if (len > PWTAGETRATETABLE40M)
1407                         len = PWTAGETRATETABLE40M;
1408                 dumpcaldata("2.4G 40M", &data[12], len);
1409                 ci = &sc->sc_40M;
1410                 get2Ghz(ci, &data[12], len);
1411         }
1412         if (mwlGetCalTable(sc, 35, 0) == 0) {
1413                 len = (data[2] | (data[3] << 8)) - 20;
1414                 if (len > PWTAGETRATETABLE20M_5G)
1415                         len = PWTAGETRATETABLE20M_5G;
1416                 dumpcaldata("5G 20M", &data[20], len);
1417                 get5Ghz(&sc->sc_20M_5G, &data[20], len);
1418         }
1419         if (mwlGetCalTable(sc, 36, 0) == 0) {
1420                 len = (data[2] | (data[3] << 8)) - 20;
1421                 if (len > PWTAGETRATETABLE40M_5G)
1422                         len = PWTAGETRATETABLE40M_5G;
1423                 dumpcaldata("5G 40M", &data[20], len);
1424                 ci = &sc->sc_40M_5G;
1425                 get5Ghz(ci, &data[20], len);
1426         }
1427         sc->sc_hw_flags |= MHF_CALDATA;
1428         return (0);
1429 }
1430 
1431 /*
1432  * Reset internal state after a firmware download.
1433  */
1434 static int
1435 mwlResetHalState(struct mwl_softc *sc)
1436 {
1437         int err = 0;
1438 
1439         /*
1440          * Fetch cal data for later use.
1441          * XXX may want to fetch other stuff too.
1442          */
1443         /* XXX check return */
1444         if ((sc->sc_hw_flags & MHF_CALDATA) == 0)
1445                 err = mwlGetPwrCalTable(sc);
1446         return (err);
1447 }
1448 
1449 #define IEEE80211_CHAN_HTG      (IEEE80211_CHAN_HT|IEEE80211_CHAN_G)
1450 #define IEEE80211_CHAN_HTA      (IEEE80211_CHAN_HT|IEEE80211_CHAN_A)
1451 
1452 static void
1453 addchan(struct mwl_channel *c, int freq, int flags, int ieee, int txpow)
1454 {
1455         c->ic_freq = (uint16_t)freq;
1456         c->ic_flags = flags;
1457         c->ic_ieee = (uint8_t)ieee;
1458         c->ic_minpower = 0;
1459         c->ic_maxpower = 2*txpow;
1460         c->ic_maxregpower = (uint8_t)txpow;
1461 }
1462 
1463 static const struct mwl_channel *
1464 findchannel(const struct mwl_channel chans[], int nchans,
1465         int freq, int flags)
1466 {
1467         const struct mwl_channel *c;
1468         int i;
1469 
1470         for (i = 0; i < nchans; i++) {
1471                 c = &chans[i];
1472                 if (c->ic_freq == freq && c->ic_flags == flags)
1473                         return (c);
1474         }
1475         return (NULL);
1476 }
1477 
1478 static void
1479 addht40channels(struct mwl_channel chans[], int maxchans, int *nchans,
1480         const MWL_HAL_CHANNELINFO *ci, int flags)
1481 {
1482         struct mwl_channel *c;
1483         const struct mwl_channel *extc;
1484         const struct mwl_hal_channel *hc;
1485         int i;
1486 
1487         c = &chans[*nchans];
1488 
1489         flags &= ~IEEE80211_CHAN_HT;
1490         for (i = 0; i < ci->nchannels; i++) {
1491                 /*
1492                  * Each entry defines an HT40 channel pair; find the
1493                  * extension channel above and the insert the pair.
1494                  */
1495                 hc = &ci->channels[i];
1496                 extc = findchannel(chans, *nchans, hc->freq+20,
1497                     flags | IEEE80211_CHAN_HT20);
1498                 if (extc != NULL) {
1499                         if (*nchans >= maxchans)
1500                                 break;
1501                         addchan(c, hc->freq, flags | IEEE80211_CHAN_HT40U,
1502                             hc->ieee, hc->maxTxPow);
1503                         c->ic_extieee = extc->ic_ieee;
1504                         c++, (*nchans)++;
1505                         if (*nchans >= maxchans)
1506                                 break;
1507                         addchan(c, extc->ic_freq, flags | IEEE80211_CHAN_HT40D,
1508                             extc->ic_ieee, hc->maxTxPow);
1509                         c->ic_extieee = hc->ieee;
1510                         c++, (*nchans)++;
1511                 }
1512         }
1513 }
1514 
1515 static void
1516 addchannels(struct mwl_channel chans[], int maxchans, int *nchans,
1517         const MWL_HAL_CHANNELINFO *ci, int flags)
1518 {
1519         struct mwl_channel *c;
1520         int i;
1521 
1522         c = &chans[*nchans];
1523 
1524         for (i = 0; i < ci->nchannels; i++) {
1525                 const struct mwl_hal_channel *hc;
1526 
1527                 hc = &ci->channels[i];
1528                 if (*nchans >= maxchans)
1529                         break;
1530                 addchan(c, hc->freq, flags, hc->ieee, hc->maxTxPow);
1531                 c++, (*nchans)++;
1532 
1533                 if (flags == IEEE80211_CHAN_G || flags == IEEE80211_CHAN_HTG) {
1534                         /* g channel have a separate b-only entry */
1535                         if (*nchans >= maxchans)
1536                                 break;
1537                         c[0] = c[-1];
1538                         c[-1].ic_flags = IEEE80211_CHAN_B;
1539                         c++, (*nchans)++;
1540                 }
1541                 if (flags == IEEE80211_CHAN_HTG) {
1542                         /* HT g channel have a separate g-only entry */
1543                         if (*nchans >= maxchans)
1544                                 break;
1545                         c[-1].ic_flags = IEEE80211_CHAN_G;
1546                         c[0] = c[-1];
1547                         c[0].ic_flags &= ~IEEE80211_CHAN_HT;
1548                         c[0].ic_flags |= IEEE80211_CHAN_HT20;   /* HT20 */
1549                         c++, (*nchans)++;
1550                 }
1551                 if (flags == IEEE80211_CHAN_HTA) {
1552                         /* HT a channel have a separate a-only entry */
1553                         if (*nchans >= maxchans)
1554                                 break;
1555                         c[-1].ic_flags = IEEE80211_CHAN_A;
1556                         c[0] = c[-1];
1557                         c[0].ic_flags &= ~IEEE80211_CHAN_HT;
1558                         c[0].ic_flags |= IEEE80211_CHAN_HT20;   /* HT20 */
1559                         c++, (*nchans)++;
1560                 }
1561         }
1562 }
1563 
1564 static int
1565 mwl_hal_getchannelinfo(struct mwl_softc *sc, int band, int chw,
1566         const MWL_HAL_CHANNELINFO **ci)
1567 {
1568         switch (band) {
1569         case MWL_FREQ_BAND_2DOT4GHZ:
1570                 *ci = (chw == MWL_CH_20_MHz_WIDTH) ? &sc->sc_20M : &sc->sc_40M;
1571                 break;
1572         case MWL_FREQ_BAND_5GHZ:
1573                 *ci = (chw == MWL_CH_20_MHz_WIDTH) ?
1574                     &sc->sc_20M_5G : &sc->sc_40M_5G;
1575                 break;
1576         default:
1577                 return (EINVAL);
1578         }
1579         return (((*ci)->freqLow == (*ci)->freqHigh) ? EINVAL : 0);
1580 }
1581 
1582 static void
1583 getchannels(struct mwl_softc *sc, int maxchans, int *nchans,
1584         struct mwl_channel chans[])
1585 {
1586         const MWL_HAL_CHANNELINFO *ci;
1587 
1588         /*
1589          * Use the channel info from the hal to craft the
1590          * channel list.  Note that we pass back an unsorted
1591          * list; the caller is required to sort it for us
1592          * (if desired).
1593          */
1594         *nchans = 0;
1595         if (mwl_hal_getchannelinfo(sc,
1596             MWL_FREQ_BAND_2DOT4GHZ, MWL_CH_20_MHz_WIDTH, &ci) == 0)
1597                 addchannels(chans, maxchans, nchans, ci, IEEE80211_CHAN_HTG);
1598         if (mwl_hal_getchannelinfo(sc,
1599             MWL_FREQ_BAND_5GHZ, MWL_CH_20_MHz_WIDTH, &ci) == 0)
1600                 addchannels(chans, maxchans, nchans, ci, IEEE80211_CHAN_HTA);
1601         if (mwl_hal_getchannelinfo(sc,
1602             MWL_FREQ_BAND_2DOT4GHZ, MWL_CH_40_MHz_WIDTH, &ci) == 0)
1603                 addht40channels(chans, maxchans, nchans, ci,
1604                     IEEE80211_CHAN_HTG);
1605         if (mwl_hal_getchannelinfo(sc,
1606             MWL_FREQ_BAND_5GHZ, MWL_CH_40_MHz_WIDTH, &ci) == 0)
1607                 addht40channels(chans, maxchans, nchans, ci,
1608                     IEEE80211_CHAN_HTA);
1609 }
1610 
1611 static int
1612 mwl_getchannels(struct mwl_softc *sc)
1613 {
1614         /*
1615          * Use the channel info from the hal to craft the
1616          * channel list for net80211.  Note that we pass up
1617          * an unsorted list; net80211 will sort it for us.
1618          */
1619         (void) memset(sc->sc_channels, 0, sizeof (sc->sc_channels));
1620         sc->sc_nchans = 0;
1621         getchannels(sc, IEEE80211_CHAN_MAX, &sc->sc_nchans, sc->sc_channels);
1622 
1623         sc->sc_regdomain.regdomain = SKU_DEBUG;
1624         sc->sc_regdomain.country = CTRY_DEFAULT;
1625         sc->sc_regdomain.location = 'I';
1626         sc->sc_regdomain.isocc[0] = ' ';     /* XXX? */
1627         sc->sc_regdomain.isocc[1] = ' ';
1628         return (sc->sc_nchans == 0 ? EIO : 0);
1629 }
1630 
1631 #undef IEEE80211_CHAN_HTA
1632 #undef IEEE80211_CHAN_HTG
1633 
1634 /*
1635  * Return "hw specs".  Note this must be the first
1636  * cmd MUST be done after a firmware download or the
1637  * f/w will lockup.
1638  * XXX move into the hal so driver doesn't need to be responsible
1639  */
1640 static int
1641 mwl_gethwspecs(struct mwl_softc *sc)
1642 {
1643         struct mwl_hal_hwspec *hw;
1644         HostCmd_DS_GET_HW_SPEC *pCmd;
1645         int retval;
1646 
1647         hw = &sc->sc_hwspecs;
1648         _CMD_SETUP(pCmd, HostCmd_DS_GET_HW_SPEC, HostCmd_CMD_GET_HW_SPEC);
1649         (void) memset(&pCmd->PermanentAddr[0], 0xff, IEEE80211_ADDR_LEN);
1650         pCmd->ulFwAwakeCookie = LE_32((unsigned int)sc->sc_cmd_dmaaddr + 2048);
1651 
1652         retval = mwlExecuteCmd(sc, HostCmd_CMD_GET_HW_SPEC);
1653         if (retval == 0) {
1654                 IEEE80211_ADDR_COPY(hw->macAddr, pCmd->PermanentAddr);
1655                 hw->wcbBase[0] = LE_32(pCmd->WcbBase0) & 0x0000ffff;
1656                 hw->wcbBase[1] = LE_32(pCmd->WcbBase1[0]) & 0x0000ffff;
1657                 hw->wcbBase[2] = LE_32(pCmd->WcbBase1[1]) & 0x0000ffff;
1658                 hw->wcbBase[3] = LE_32(pCmd->WcbBase1[2]) & 0x0000ffff;
1659                 hw->rxDescRead = LE_32(pCmd->RxPdRdPtr)& 0x0000ffff;
1660                 hw->rxDescWrite = LE_32(pCmd->RxPdWrPtr)& 0x0000ffff;
1661                 hw->regionCode = LE_16(pCmd->RegionCode) & 0x00ff;
1662                 hw->fwReleaseNumber = LE_32(pCmd->FWReleaseNumber);
1663                 hw->maxNumWCB = LE_16(pCmd->NumOfWCB);
1664                 hw->maxNumMCAddr = LE_16(pCmd->NumOfMCastAddr);
1665                 hw->numAntennas = LE_16(pCmd->NumberOfAntenna);
1666                 hw->hwVersion = pCmd->Version;
1667                 hw->hostInterface = pCmd->HostIf;
1668 
1669                 sc->sc_revs.mh_macRev = hw->hwVersion;            /* XXX */
1670                 sc->sc_revs.mh_phyRev = hw->hostInterface;        /* XXX */
1671         }
1672 
1673         return (retval);
1674 }
1675 
1676 static int
1677 mwl_hal_setmac_locked(struct mwl_softc *sc,
1678         const uint8_t addr[IEEE80211_ADDR_LEN])
1679 {
1680         HostCmd_DS_SET_MAC *pCmd;
1681 
1682         _VCMD_SETUP(pCmd, HostCmd_DS_SET_MAC, HostCmd_CMD_SET_MAC_ADDR);
1683         IEEE80211_ADDR_COPY(&pCmd->MacAddr[0], addr);
1684 #ifdef MWL_MBSS_SUPPORT
1685         /* NB: already byte swapped */
1686         pCmd->MacType = WL_MAC_TYPE_PRIMARY_CLIENT;
1687 #endif
1688         return (mwlExecuteCmd(sc, HostCmd_CMD_SET_MAC_ADDR));
1689 }
1690 
1691 static void
1692 cvtPeerInfo(PeerInfo_t *to, const MWL_HAL_PEERINFO *from)
1693 {
1694         to->LegacyRateBitMap = LE_32(from->LegacyRateBitMap);
1695         to->HTRateBitMap = LE_32(from->HTRateBitMap);
1696         to->CapInfo = LE_16(from->CapInfo);
1697         to->HTCapabilitiesInfo = LE_16(from->HTCapabilitiesInfo);
1698         to->MacHTParamInfo = from->MacHTParamInfo;
1699         to->AddHtInfo.ControlChan = from->AddHtInfo.ControlChan;
1700         to->AddHtInfo.AddChan = from->AddHtInfo.AddChan;
1701         to->AddHtInfo.OpMode = LE_16(from->AddHtInfo.OpMode);
1702         to->AddHtInfo.stbc = LE_16(from->AddHtInfo.stbc);
1703 }
1704 
1705 /* XXX station id must be in [0..63] */
1706 static int
1707 mwl_hal_newstation(struct mwl_softc *sc,
1708         const uint8_t addr[IEEE80211_ADDR_LEN], uint16_t aid, uint16_t sid,
1709         const MWL_HAL_PEERINFO *peer, int isQosSta, int wmeInfo)
1710 {
1711         HostCmd_FW_SET_NEW_STN *pCmd;
1712         int retval;
1713 
1714         _VCMD_SETUP(pCmd, HostCmd_FW_SET_NEW_STN, HostCmd_CMD_SET_NEW_STN);
1715         pCmd->AID = LE_16(aid);
1716         pCmd->StnId = LE_16(sid);
1717         pCmd->Action = LE_16(0);     /* SET */
1718         if (peer != NULL) {
1719                 /* NB: must fix up byte order */
1720                 cvtPeerInfo(&pCmd->PeerInfo, peer);
1721         }
1722         IEEE80211_ADDR_COPY(&pCmd->MacAddr[0], addr);
1723         pCmd->Qosinfo = (uint8_t)wmeInfo;
1724         pCmd->isQosSta = (isQosSta != 0);
1725 
1726         MWL_DBG(MWL_DBG_HW, "mwl: mwl_hal_newstation(): "
1727             "LegacyRateBitMap %x, CapInfo %x\n",
1728             pCmd->PeerInfo.LegacyRateBitMap, pCmd->PeerInfo.CapInfo);
1729 
1730         retval = mwlExecuteCmd(sc, HostCmd_CMD_SET_NEW_STN);
1731         return (retval);
1732 }
1733 
1734 /*
1735  * Configure antenna use.
1736  * Takes effect immediately.
1737  * XXX tx antenna setting ignored
1738  * XXX rx antenna setting should always be 3 (for now)
1739  */
1740 static int
1741 mwl_hal_setantenna(struct mwl_softc *sc, MWL_HAL_ANTENNA dirSet, int ant)
1742 {
1743         HostCmd_DS_802_11_RF_ANTENNA *pCmd;
1744         int retval;
1745 
1746         if (!(dirSet == WL_ANTENNATYPE_RX || dirSet == WL_ANTENNATYPE_TX))
1747                 return (EINVAL);
1748 
1749         _CMD_SETUP(pCmd, HostCmd_DS_802_11_RF_ANTENNA,
1750             HostCmd_CMD_802_11_RF_ANTENNA);
1751         pCmd->Action = LE_16(dirSet);
1752         if (ant == 0)                   /* default to all/both antennae */
1753                 ant = 3;
1754         pCmd->AntennaMode = LE_16(ant);
1755 
1756         retval = mwlExecuteCmd(sc, HostCmd_CMD_802_11_RF_ANTENNA);
1757         return (retval);
1758 }
1759 
1760 /*
1761  * Configure radio.
1762  * Takes effect immediately.
1763  * XXX preamble installed after set fixed rate cmd
1764  */
1765 static int
1766 mwl_hal_setradio(struct mwl_softc *sc, int onoff, MWL_HAL_PREAMBLE preamble)
1767 {
1768         HostCmd_DS_802_11_RADIO_CONTROL *pCmd;
1769         int retval;
1770 
1771         _CMD_SETUP(pCmd, HostCmd_DS_802_11_RADIO_CONTROL,
1772             HostCmd_CMD_802_11_RADIO_CONTROL);
1773         pCmd->Action = LE_16(HostCmd_ACT_GEN_SET);
1774         if (onoff == 0)
1775                 pCmd->Control = 0;
1776         else
1777                 pCmd->Control = LE_16(preamble);
1778         pCmd->RadioOn = LE_16(onoff);
1779 
1780         retval = mwlExecuteCmd(sc, HostCmd_CMD_802_11_RADIO_CONTROL);
1781         return (retval);
1782 }
1783 
1784 static int
1785 mwl_hal_setwmm(struct mwl_softc *sc, int onoff)
1786 {
1787         HostCmd_FW_SetWMMMode *pCmd;
1788         int retval;
1789 
1790         _CMD_SETUP(pCmd, HostCmd_FW_SetWMMMode,
1791             HostCmd_CMD_SET_WMM_MODE);
1792         pCmd->Action = LE_16(onoff);
1793 
1794         retval = mwlExecuteCmd(sc, HostCmd_CMD_SET_WMM_MODE);
1795         return (retval);
1796 }
1797 
1798 /*
1799  * Convert public channel flags definition to a
1800  * value suitable for feeding to the firmware.
1801  * Note this includes byte swapping.
1802  */
1803 static uint32_t
1804 cvtChannelFlags(const MWL_HAL_CHANNEL *chan)
1805 {
1806         uint32_t w;
1807 
1808         /*
1809          * NB: f/w only understands FREQ_BAND_5GHZ, supplying the more
1810          * precise band info causes it to lockup (sometimes).
1811          */
1812         w = (chan->channelFlags.FreqBand == MWL_FREQ_BAND_2DOT4GHZ) ?
1813             FREQ_BAND_2DOT4GHZ : FREQ_BAND_5GHZ;
1814         switch (chan->channelFlags.ChnlWidth) {
1815         case MWL_CH_10_MHz_WIDTH:
1816                 w |= CH_10_MHz_WIDTH;
1817                 break;
1818         case MWL_CH_20_MHz_WIDTH:
1819                 w |= CH_20_MHz_WIDTH;
1820                 break;
1821         case MWL_CH_40_MHz_WIDTH:
1822         default:
1823                 w |= CH_40_MHz_WIDTH;
1824                 break;
1825         }
1826         switch (chan->channelFlags.ExtChnlOffset) {
1827         case MWL_EXT_CH_NONE:
1828                 w |= EXT_CH_NONE;
1829                 break;
1830         case MWL_EXT_CH_ABOVE_CTRL_CH:
1831                 w |= EXT_CH_ABOVE_CTRL_CH;
1832                 break;
1833         case MWL_EXT_CH_BELOW_CTRL_CH:
1834                 w |= EXT_CH_BELOW_CTRL_CH;
1835                 break;
1836         }
1837         return (LE_32(w));
1838 }
1839 
1840 static int
1841 mwl_hal_setchannel(struct mwl_softc *sc, const MWL_HAL_CHANNEL *chan)
1842 {
1843         HostCmd_FW_SET_RF_CHANNEL *pCmd;
1844         int retval;
1845 
1846         _CMD_SETUP(pCmd, HostCmd_FW_SET_RF_CHANNEL, HostCmd_CMD_SET_RF_CHANNEL);
1847         pCmd->Action = LE_16(HostCmd_ACT_GEN_SET);
1848         pCmd->CurrentChannel = chan->channel;
1849         pCmd->ChannelFlags = cvtChannelFlags(chan);  /* NB: byte-swapped */
1850 
1851         retval = mwlExecuteCmd(sc, HostCmd_CMD_SET_RF_CHANNEL);
1852         return (retval);
1853 }
1854 
1855 static int
1856 mwl_hal_settxpower(struct mwl_softc *sc,
1857     const MWL_HAL_CHANNEL *c, uint8_t maxtxpow)
1858 {
1859         HostCmd_DS_802_11_RF_TX_POWER *pCmd;
1860         const struct mwl_hal_channel *hc;
1861         int i = 0, retval;
1862 
1863         hc = findhalchannel(sc, c);
1864         if (hc == NULL) {
1865                 /* XXX temp while testing */
1866                 MWL_DBG(MWL_DBG_HW, "mwl: mwl_hal_settxpower(): "
1867                     "no cal data for channel %u band %u width %u ext %u\n",
1868                     c->channel, c->channelFlags.FreqBand,
1869                     c->channelFlags.ChnlWidth, c->channelFlags.ExtChnlOffset);
1870                 return (EINVAL);
1871         }
1872 
1873         _CMD_SETUP(pCmd, HostCmd_DS_802_11_RF_TX_POWER,
1874             HostCmd_CMD_802_11_RF_TX_POWER);
1875         pCmd->Action = LE_16(HostCmd_ACT_GEN_SET_LIST);
1876         /* NB: 5Ghz cal data have the channel # in [0]; don't truncate */
1877         if (c->channelFlags.FreqBand == MWL_FREQ_BAND_5GHZ)
1878                 pCmd->PowerLevelList[i++] = LE_16(hc->targetPowers[0]);
1879         for (; i < 4; i++) {
1880                 uint16_t pow = hc->targetPowers[i];
1881                 if (pow > maxtxpow)
1882                         pow = maxtxpow;
1883                 pCmd->PowerLevelList[i] = LE_16(pow);
1884         }
1885         retval = mwlExecuteCmd(sc, HostCmd_CMD_802_11_RF_TX_POWER);
1886         return (retval);
1887 }
1888 
1889 #define RATEVAL(r)      ((r) &~ RATE_MCS)
1890 #define RATETYPE(r)     (((r) & RATE_MCS) ? HT_RATE_TYPE : LEGACY_RATE_TYPE)
1891 
1892 static int
1893 mwl_hal_settxrate(struct mwl_softc *sc, MWL_HAL_TXRATE_HANDLING handling,
1894         const MWL_HAL_TXRATE *rate)
1895 {
1896         HostCmd_FW_USE_FIXED_RATE *pCmd;
1897         FIXED_RATE_ENTRY *fp;
1898         int retval, i, n;
1899 
1900         _VCMD_SETUP(pCmd, HostCmd_FW_USE_FIXED_RATE,
1901             HostCmd_CMD_SET_FIXED_RATE);
1902 
1903         pCmd->MulticastRate = RATEVAL(rate->McastRate);
1904         pCmd->MultiRateTxType = RATETYPE(rate->McastRate);
1905         /* NB: no rate type field */
1906         pCmd->ManagementRate = RATEVAL(rate->MgtRate);
1907         (void) memset(pCmd->FixedRateTable, 0, sizeof (pCmd->FixedRateTable));
1908         if (handling == RATE_FIXED) {
1909                 pCmd->Action = LE_32(HostCmd_ACT_GEN_SET);
1910                 pCmd->AllowRateDrop = LE_32(FIXED_RATE_WITHOUT_AUTORATE_DROP);
1911                 fp = pCmd->FixedRateTable;
1912                 fp->FixedRate =
1913                     LE_32(RATEVAL(rate->RateSeries[0].Rate));
1914                 fp->FixRateTypeFlags.FixRateType =
1915                     LE_32(RATETYPE(rate->RateSeries[0].Rate));
1916                 pCmd->EntryCount = LE_32(1);
1917         } else if (handling == RATE_FIXED_DROP) {
1918                 pCmd->Action = LE_32(HostCmd_ACT_GEN_SET);
1919                 pCmd->AllowRateDrop = LE_32(FIXED_RATE_WITH_AUTO_RATE_DROP);
1920                 n = 0;
1921                 fp = pCmd->FixedRateTable;
1922                 for (i = 0; i < 4; i++) {
1923                         if (rate->RateSeries[0].TryCount == 0)
1924                                 break;
1925                         fp->FixRateTypeFlags.FixRateType =
1926                             LE_32(RATETYPE(rate->RateSeries[i].Rate));
1927                         fp->FixedRate =
1928                             LE_32(RATEVAL(rate->RateSeries[i].Rate));
1929                         fp->FixRateTypeFlags.RetryCountValid =
1930                             LE_32(RETRY_COUNT_VALID);
1931                         fp->RetryCount =
1932                             LE_32(rate->RateSeries[i].TryCount-1);
1933                         n++;
1934                 }
1935                 pCmd->EntryCount = LE_32(n);
1936         } else
1937                 pCmd->Action = LE_32(HostCmd_ACT_NOT_USE_FIXED_RATE);
1938 
1939         retval = mwlExecuteCmd(sc, HostCmd_CMD_SET_FIXED_RATE);
1940         return (retval);
1941 }
1942 
1943 static int
1944 mwl_hal_settxrate_auto(struct mwl_softc *sc, const MWL_HAL_TXRATE *rate)
1945 {
1946         HostCmd_FW_USE_FIXED_RATE *pCmd;
1947         int retval;
1948 
1949         _CMD_SETUP(pCmd, HostCmd_FW_USE_FIXED_RATE,
1950             HostCmd_CMD_SET_FIXED_RATE);
1951 
1952         pCmd->MulticastRate = RATEVAL(rate->McastRate);
1953         pCmd->MultiRateTxType = RATETYPE(rate->McastRate);
1954         /* NB: no rate type field */
1955         pCmd->ManagementRate = RATEVAL(rate->MgtRate);
1956         (void) memset(pCmd->FixedRateTable, 0, sizeof (pCmd->FixedRateTable));
1957         pCmd->Action = LE_32(HostCmd_ACT_NOT_USE_FIXED_RATE);
1958 
1959         retval = mwlExecuteCmd(sc, HostCmd_CMD_SET_FIXED_RATE);
1960         return (retval);
1961 }
1962 
1963 #undef RATEVAL
1964 #undef RATETYPE
1965 
1966 /* XXX 0 = indoor, 1 = outdoor */
1967 static int
1968 mwl_hal_setrateadaptmode(struct mwl_softc *sc, uint16_t mode)
1969 {
1970         HostCmd_DS_SET_RATE_ADAPT_MODE *pCmd;
1971         int retval;
1972 
1973         _CMD_SETUP(pCmd, HostCmd_DS_SET_RATE_ADAPT_MODE,
1974             HostCmd_CMD_SET_RATE_ADAPT_MODE);
1975         pCmd->Action = LE_16(HostCmd_ACT_GEN_SET);
1976         pCmd->RateAdaptMode = LE_16(mode);
1977 
1978         retval = mwlExecuteCmd(sc, HostCmd_CMD_SET_RATE_ADAPT_MODE);
1979         return (retval);
1980 }
1981 
1982 static int
1983 mwl_hal_setoptimizationlevel(struct mwl_softc *sc, int level)
1984 {
1985         HostCmd_FW_SET_OPTIMIZATION_LEVEL *pCmd;
1986         int retval;
1987 
1988         _CMD_SETUP(pCmd, HostCmd_FW_SET_OPTIMIZATION_LEVEL,
1989             HostCmd_CMD_SET_OPTIMIZATION_LEVEL);
1990         pCmd->OptLevel = (uint8_t)level;
1991 
1992         retval = mwlExecuteCmd(sc, HostCmd_CMD_SET_OPTIMIZATION_LEVEL);
1993         return (retval);
1994 }
1995 
1996 /*
1997  * Set the region code that selects the radar bin'ing agorithm.
1998  */
1999 static int
2000 mwl_hal_setregioncode(struct mwl_softc *sc, int regionCode)
2001 {
2002         HostCmd_SET_REGIONCODE_INFO *pCmd;
2003         int retval;
2004 
2005         _CMD_SETUP(pCmd, HostCmd_SET_REGIONCODE_INFO,
2006             HostCmd_CMD_SET_REGION_CODE);
2007         /* XXX map pseudo-codes to fw codes */
2008         switch (regionCode) {
2009         case DOMAIN_CODE_ETSI_131:
2010                 pCmd->regionCode = LE_16(DOMAIN_CODE_ETSI);
2011                 break;
2012         default:
2013                 pCmd->regionCode = LE_16(regionCode);
2014                 break;
2015         }
2016 
2017         retval = mwlExecuteCmd(sc, HostCmd_CMD_SET_REGION_CODE);
2018         return (retval);
2019 }
2020 
2021 static int
2022 mwl_hal_setassocid(struct mwl_softc *sc,
2023         const uint8_t bssId[IEEE80211_ADDR_LEN], uint16_t assocId)
2024 {
2025         HostCmd_FW_SET_AID *pCmd = (HostCmd_FW_SET_AID *) &sc->sc_cmd_mem[0];
2026         int retval;
2027 
2028         _VCMD_SETUP(pCmd, HostCmd_FW_SET_AID, HostCmd_CMD_SET_AID);
2029         pCmd->AssocID = LE_16(assocId);
2030         IEEE80211_ADDR_COPY(&pCmd->MacAddr[0], bssId);
2031 
2032         retval = mwlExecuteCmd(sc, HostCmd_CMD_SET_AID);
2033         return (retval);
2034 }
2035 
2036 /*
2037  * Inform firmware of tx rate parameters.  Called whenever
2038  * user-settable params change and after a channel change.
2039  */
2040 static int
2041 mwl_setrates(struct ieee80211com *ic)
2042 {
2043         struct mwl_softc *sc = (struct mwl_softc *)ic;
2044         MWL_HAL_TXRATE rates;
2045 
2046         const struct ieee80211_rateset *rs;
2047         rs = &ic->ic_bss->in_rates;
2048 
2049         /*
2050          * Update the h/w rate map.
2051          * NB: 0x80 for MCS is passed through unchanged
2052          */
2053         (void) memset(&rates, 0, sizeof (rates));
2054         /* rate used to send management frames */
2055         rates.MgtRate = rs->ir_rates[0] & IEEE80211_RATE_VAL;
2056         /* rate used to send multicast frames */
2057         rates.McastRate = rates.MgtRate;
2058 
2059         return (mwl_hal_settxrate(sc, RATE_AUTO, &rates));
2060 }
2061 
2062 /*
2063  * Set packet size threshold for implicit use of RTS.
2064  * Takes effect immediately.
2065  * XXX packet length > threshold =>'s RTS
2066  */
2067 static int
2068 mwl_hal_setrtsthreshold(struct mwl_softc *sc, int threshold)
2069 {
2070         HostCmd_DS_802_11_RTS_THSD *pCmd;
2071         int retval;
2072 
2073         _VCMD_SETUP(pCmd, HostCmd_DS_802_11_RTS_THSD,
2074             HostCmd_CMD_802_11_RTS_THSD);
2075         pCmd->Action  = LE_16(HostCmd_ACT_GEN_SET);
2076         pCmd->Threshold = LE_16(threshold);
2077 
2078         retval = mwlExecuteCmd(sc, HostCmd_CMD_802_11_RTS_THSD);
2079         return (retval);
2080 }
2081 
2082 static int
2083 mwl_hal_setcsmode(struct mwl_softc *sc, MWL_HAL_CSMODE csmode)
2084 {
2085         HostCmd_DS_SET_LINKADAPT_CS_MODE *pCmd;
2086         int retval;
2087 
2088         _CMD_SETUP(pCmd, HostCmd_DS_SET_LINKADAPT_CS_MODE,
2089             HostCmd_CMD_SET_LINKADAPT_CS_MODE);
2090         pCmd->Action = LE_16(HostCmd_ACT_GEN_SET);
2091         pCmd->CSMode = LE_16(csmode);
2092 
2093         retval = mwlExecuteCmd(sc, HostCmd_CMD_SET_LINKADAPT_CS_MODE);
2094         return (retval);
2095 }
2096 
2097 static int
2098 mwl_hal_setpromisc(struct mwl_softc *sc, int ena)
2099 {
2100         uint32_t v;
2101 
2102         v = mwl_ctl_read4(sc, MACREG_REG_PROMISCUOUS);
2103         mwl_ctl_write4(sc, MACREG_REG_PROMISCUOUS, ena ? v | 1 : v & ~1);
2104 
2105         return (0);
2106 }
2107 
2108 static int
2109 mwl_hal_start(struct mwl_softc *sc)
2110 {
2111         HostCmd_DS_BSS_START *pCmd;
2112         int retval;
2113 
2114         _VCMD_SETUP(pCmd, HostCmd_DS_BSS_START, HostCmd_CMD_BSS_START);
2115         pCmd->Enable = LE_32(HostCmd_ACT_GEN_ON);
2116 
2117         retval = mwlExecuteCmd(sc, HostCmd_CMD_BSS_START);
2118         return (retval);
2119 }
2120 
2121 /*
2122  * Enable sta-mode operation (disables beacon frame xmit).
2123  */
2124 static int
2125 mwl_hal_setinframode(struct mwl_softc *sc)
2126 {
2127         HostCmd_FW_SET_INFRA_MODE *pCmd;
2128         int retval;
2129 
2130         _VCMD_SETUP(pCmd, HostCmd_FW_SET_INFRA_MODE,
2131             HostCmd_CMD_SET_INFRA_MODE);
2132 
2133         retval = mwlExecuteCmd(sc, HostCmd_CMD_SET_INFRA_MODE);
2134         return (retval);
2135 }
2136 
2137 static int
2138 mwl_hal_stop(struct mwl_softc *sc)
2139 {
2140         HostCmd_DS_BSS_START *pCmd;
2141         int retval;
2142 
2143         _VCMD_SETUP(pCmd, HostCmd_DS_BSS_START,
2144             HostCmd_CMD_BSS_START);
2145         pCmd->Enable = LE_32(HostCmd_ACT_GEN_OFF);
2146         retval = mwlExecuteCmd(sc, HostCmd_CMD_BSS_START);
2147 
2148         return (retval);
2149 }
2150 
2151 static int
2152 mwl_hal_keyset(struct mwl_softc *sc, const MWL_HAL_KEYVAL *kv,
2153         const uint8_t mac[IEEE80211_ADDR_LEN])
2154 {
2155         HostCmd_FW_UPDATE_ENCRYPTION_SET_KEY *pCmd;
2156         int retval;
2157 
2158         _VCMD_SETUP(pCmd, HostCmd_FW_UPDATE_ENCRYPTION_SET_KEY,
2159             HostCmd_CMD_UPDATE_ENCRYPTION);
2160         if (kv->keyFlags & (KEY_FLAG_TXGROUPKEY|KEY_FLAG_RXGROUPKEY))
2161                 pCmd->ActionType = LE_32(EncrActionTypeSetGroupKey);
2162         else
2163                 pCmd->ActionType = LE_32(EncrActionTypeSetKey);
2164         pCmd->KeyParam.Length = LE_16(sizeof (pCmd->KeyParam));
2165         pCmd->KeyParam.KeyTypeId = LE_16(kv->keyTypeId);
2166         pCmd->KeyParam.KeyInfo = LE_32(kv->keyFlags);
2167         pCmd->KeyParam.KeyIndex = LE_32(kv->keyIndex);
2168         /* NB: includes TKIP MIC keys */
2169         (void) memcpy(&pCmd->KeyParam.Key, &kv->key, kv->keyLen);
2170         switch (kv->keyTypeId) {
2171         case KEY_TYPE_ID_WEP:
2172                 pCmd->KeyParam.KeyLen = LE_16(kv->keyLen);
2173                 break;
2174         case KEY_TYPE_ID_TKIP:
2175                 pCmd->KeyParam.KeyLen = LE_16(sizeof (TKIP_TYPE_KEY));
2176                 pCmd->KeyParam.Key.TkipKey.TkipRsc.low =
2177                     LE_16(kv->key.tkip.rsc.low);
2178                 pCmd->KeyParam.Key.TkipKey.TkipRsc.high =
2179                     LE_32(kv->key.tkip.rsc.high);
2180                 pCmd->KeyParam.Key.TkipKey.TkipTsc.low =
2181                     LE_16(kv->key.tkip.tsc.low);
2182                 pCmd->KeyParam.Key.TkipKey.TkipTsc.high =
2183                     LE_32(kv->key.tkip.tsc.high);
2184                 break;
2185         case KEY_TYPE_ID_AES:
2186                 pCmd->KeyParam.KeyLen = LE_16(sizeof (AES_TYPE_KEY));
2187                 break;
2188         }
2189 #ifdef MWL_MBSS_SUPPORT
2190         IEEE80211_ADDR_COPY(pCmd->KeyParam.Macaddr, mac);
2191 #else
2192         IEEE80211_ADDR_COPY(pCmd->Macaddr, mac);
2193 #endif
2194 
2195         retval = mwlExecuteCmd(sc, HostCmd_CMD_UPDATE_ENCRYPTION);
2196         return (retval);
2197 }
2198 
2199 static int
2200 mwl_hal_keyreset(struct mwl_softc *sc, const MWL_HAL_KEYVAL *kv,
2201     const uint8_t mac[IEEE80211_ADDR_LEN])
2202 {
2203         HostCmd_FW_UPDATE_ENCRYPTION_SET_KEY *pCmd;
2204         int retval;
2205 
2206         _VCMD_SETUP(pCmd, HostCmd_FW_UPDATE_ENCRYPTION_SET_KEY,
2207             HostCmd_CMD_UPDATE_ENCRYPTION);
2208         pCmd->ActionType = LE_16(EncrActionTypeRemoveKey);
2209         pCmd->KeyParam.Length = LE_16(sizeof (pCmd->KeyParam));
2210         pCmd->KeyParam.KeyTypeId = LE_16(kv->keyTypeId);
2211         pCmd->KeyParam.KeyInfo = LE_32(kv->keyFlags);
2212         pCmd->KeyParam.KeyIndex = LE_32(kv->keyIndex);
2213 #ifdef MWL_MBSS_SUPPORT
2214         IEEE80211_ADDR_COPY(pCmd->KeyParam.Macaddr, mac);
2215 #else
2216         IEEE80211_ADDR_COPY(pCmd->Macaddr, mac);
2217 #endif
2218         retval = mwlExecuteCmd(sc, HostCmd_CMD_UPDATE_ENCRYPTION);
2219         return (retval);
2220 }
2221 
2222 /* ARGSUSED */
2223 static struct ieee80211_node *
2224 mwl_node_alloc(struct ieee80211com *ic)
2225 {
2226         struct mwl_node *mn;
2227 
2228         mn = kmem_zalloc(sizeof (struct mwl_node), KM_SLEEP);
2229         if (mn == NULL) {
2230                 /* XXX stat+msg */
2231                 MWL_DBG(MWL_DBG_MSG, "mwl: mwl_node_alloc(): "
2232                     "alloc node failed\n");
2233                 return (NULL);
2234         }
2235         return (&mn->mn_node);
2236 }
2237 
2238 static void
2239 mwl_node_free(struct ieee80211_node *ni)
2240 {
2241         struct ieee80211com *ic = ni->in_ic;
2242         struct mwl_node *mn = MWL_NODE(ni);
2243 
2244         if (mn->mn_staid != 0) {
2245                 // mwl_hal_delstation(mn->mn_hvap, vap->iv_myaddr);
2246                 // delstaid(sc, mn->mn_staid);
2247                 mn->mn_staid = 0;
2248         }
2249         ic->ic_node_cleanup(ni);
2250         kmem_free(ni, sizeof (struct mwl_node));
2251 }
2252 
2253 /*
2254  * Allocate a key cache slot for a unicast key.  The
2255  * firmware handles key allocation and every station is
2256  * guaranteed key space so we are always successful.
2257  */
2258 static int
2259 mwl_key_alloc(struct ieee80211com *ic, const struct ieee80211_key *k,
2260         ieee80211_keyix *keyix, ieee80211_keyix *rxkeyix)
2261 {
2262         if (k->wk_keyix != IEEE80211_KEYIX_NONE ||
2263             (k->wk_flags & IEEE80211_KEY_GROUP)) {
2264                 if (!(&ic->ic_nw_keys[0] <= k &&
2265                     k < &ic->ic_nw_keys[IEEE80211_WEP_NKID])) {
2266                         /* should not happen */
2267                         MWL_DBG(MWL_DBG_CRYPTO, "mwl: mwl_key_alloc(): "
2268                             "bogus group key\n");
2269                         return (0);
2270                 }
2271                 /* give the caller what they requested */
2272                 *keyix = *rxkeyix = k - ic->ic_nw_keys;
2273                 MWL_DBG(MWL_DBG_CRYPTO, "mwl: mwl_key_alloc(): "
2274                     "alloc GROUP key keyix %x, rxkeyix %x\n",
2275                     *keyix, *rxkeyix);
2276         } else {
2277                 /*
2278                  * Firmware handles key allocation.
2279                  */
2280                 *keyix = *rxkeyix = 0;
2281                 MWL_DBG(MWL_DBG_CRYPTO, "mwl: mwl_key_alloc(): "
2282                     "reset key index in key allocation\n");
2283         }
2284 
2285         return (1);
2286 }
2287 
2288 /*
2289  * Delete a key entry allocated by mwl_key_alloc.
2290  */
2291 static int
2292 mwl_key_delete(struct ieee80211com *ic, const struct ieee80211_key *k)
2293 {
2294         struct mwl_softc *sc = (struct mwl_softc *)ic;
2295         MWL_HAL_KEYVAL hk;
2296         const uint8_t bcastaddr[IEEE80211_ADDR_LEN] =
2297             { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
2298 
2299         (void) memset(&hk, 0, sizeof (hk));
2300         hk.keyIndex = k->wk_keyix;
2301         switch (k->wk_cipher->ic_cipher) {
2302         case IEEE80211_CIPHER_WEP:
2303                 hk.keyTypeId = KEY_TYPE_ID_WEP;
2304                 break;
2305         case IEEE80211_CIPHER_TKIP:
2306                 hk.keyTypeId = KEY_TYPE_ID_TKIP;
2307                 break;
2308         case IEEE80211_CIPHER_AES_CCM:
2309                 hk.keyTypeId = KEY_TYPE_ID_AES;
2310                 break;
2311         default:
2312                 /* XXX should not happen */
2313                 MWL_DBG(MWL_DBG_CRYPTO, "mwl: mwl_key_delete(): "
2314                     "unknown cipher %d\n", k->wk_cipher->ic_cipher);
2315                 return (0);
2316         }
2317         return (mwl_hal_keyreset(sc, &hk, bcastaddr) == 0);
2318 }
2319 
2320 /*
2321  * Set the key cache contents for the specified key.  Key cache
2322  * slot(s) must already have been allocated by mwl_key_alloc.
2323  */
2324 /* ARGSUSED */
2325 static int
2326 mwl_key_set(struct ieee80211com *ic, const struct ieee80211_key *k,
2327         const uint8_t mac[IEEE80211_ADDR_LEN])
2328 {
2329 #define GRPXMIT (IEEE80211_KEY_XMIT | IEEE80211_KEY_GROUP)
2330 /* NB: static wep keys are marked GROUP+tx/rx; GTK will be tx or rx */
2331 #define IEEE80211_IS_STATICKEY(k) \
2332         (((k)->wk_flags & (GRPXMIT|IEEE80211_KEY_RECV)) == \
2333         (GRPXMIT|IEEE80211_KEY_RECV))
2334         struct mwl_softc *sc = (struct mwl_softc *)ic;
2335         const struct ieee80211_cipher *cip = k->wk_cipher;
2336         const uint8_t *macaddr;
2337         MWL_HAL_KEYVAL hk;
2338 
2339         (void) memset(&hk, 0, sizeof (hk));
2340         hk.keyIndex = k->wk_keyix;
2341         switch (cip->ic_cipher) {
2342         case IEEE80211_CIPHER_WEP:
2343                 hk.keyTypeId = KEY_TYPE_ID_WEP;
2344                 hk.keyLen = k->wk_keylen;
2345                 if (k->wk_keyix == ic->ic_def_txkey)
2346                         hk.keyFlags = KEY_FLAG_WEP_TXKEY;
2347                 if (!IEEE80211_IS_STATICKEY(k)) {
2348                         /* NB: WEP is never used for the PTK */
2349                         (void) addgroupflags(&hk, k);
2350                 }
2351                 break;
2352         case IEEE80211_CIPHER_TKIP:
2353                 hk.keyTypeId = KEY_TYPE_ID_TKIP;
2354                 hk.key.tkip.tsc.high = (uint32_t)(k->wk_keytsc >> 16);
2355                 hk.key.tkip.tsc.low = (uint16_t)k->wk_keytsc;
2356                 hk.keyFlags = KEY_FLAG_TSC_VALID | KEY_FLAG_MICKEY_VALID;
2357                 hk.keyLen = k->wk_keylen + IEEE80211_MICBUF_SIZE;
2358                 if (!addgroupflags(&hk, k))
2359                         hk.keyFlags |= KEY_FLAG_PAIRWISE;
2360                 break;
2361         case IEEE80211_CIPHER_AES_CCM:
2362                 hk.keyTypeId = KEY_TYPE_ID_AES;
2363                 hk.keyLen = k->wk_keylen;
2364                 if (!addgroupflags(&hk, k))
2365                         hk.keyFlags |= KEY_FLAG_PAIRWISE;
2366                 break;
2367         default:
2368                 /* XXX should not happen */
2369                 MWL_DBG(MWL_DBG_CRYPTO, "mwl: mwl_key_set(): "
2370                     "unknown cipher %d\n",
2371                     k->wk_cipher->ic_cipher);
2372                 return (0);
2373         }
2374         /*
2375          * NB: tkip mic keys get copied here too; the layout
2376          * just happens to match that in ieee80211_key.
2377          */
2378         (void) memcpy(hk.key.aes, k->wk_key, hk.keyLen);
2379 
2380         /*
2381          * Locate address of sta db entry for writing key;
2382          * the convention unfortunately is somewhat different
2383          * than how net80211, hostapd, and wpa_supplicant think.
2384          */
2385 
2386         /*
2387          * NB: keys plumbed before the sta reaches AUTH state
2388          * will be discarded or written to the wrong sta db
2389          * entry because iv_bss is meaningless.  This is ok
2390          * (right now) because we handle deferred plumbing of
2391          * WEP keys when the sta reaches AUTH state.
2392          */
2393         macaddr = ic->ic_bss->in_bssid;
2394         if (k->wk_flags & IEEE80211_KEY_XMIT) {
2395                 /* XXX plumb to local sta db too for static key wep */
2396                 (void) mwl_hal_keyset(sc, &hk, ic->ic_macaddr);
2397         }
2398         return (mwl_hal_keyset(sc, &hk, macaddr) == 0);
2399 #undef IEEE80211_IS_STATICKEY
2400 #undef GRPXMIT
2401 }
2402 
2403 /*
2404  * Plumb any static WEP key for the station.  This is
2405  * necessary as we must propagate the key from the
2406  * global key table of the vap to each sta db entry.
2407  */
2408 static void
2409 mwl_setanywepkey(struct ieee80211com *ic, const uint8_t mac[IEEE80211_ADDR_LEN])
2410 {
2411         if ((ic->ic_flags & (IEEE80211_F_PRIVACY|IEEE80211_F_WPA)) ==
2412             IEEE80211_F_PRIVACY &&
2413             ic->ic_def_txkey != IEEE80211_KEYIX_NONE &&
2414             ic->ic_nw_keys[ic->ic_def_txkey].wk_keyix != IEEE80211_KEYIX_NONE)
2415                 (void) mwl_key_set(ic, &ic->ic_nw_keys[ic->ic_def_txkey], mac);
2416 }
2417 
2418 static void
2419 mwl_setglobalkeys(struct ieee80211com *ic)
2420 {
2421         struct ieee80211_key *wk;
2422 
2423         wk = &ic->ic_nw_keys[0];
2424         for (; wk < &ic->ic_nw_keys[IEEE80211_WEP_NKID]; wk++)
2425                 if (wk->wk_keyix != IEEE80211_KEYIX_NONE)
2426                         (void) mwl_key_set(ic, wk, ic->ic_macaddr);
2427 }
2428 
2429 static int
2430 addgroupflags(MWL_HAL_KEYVAL *hk, const struct ieee80211_key *k)
2431 {
2432         if (k->wk_flags & IEEE80211_KEY_GROUP) {
2433                 if (k->wk_flags & IEEE80211_KEY_XMIT)
2434                         hk->keyFlags |= KEY_FLAG_TXGROUPKEY;
2435                 if (k->wk_flags & IEEE80211_KEY_RECV)
2436                         hk->keyFlags |= KEY_FLAG_RXGROUPKEY;
2437                 return (1);
2438         } else
2439                 return (0);
2440 }
2441 
2442 /*
2443  * Set/change channels.
2444  */
2445 static int
2446 mwl_chan_set(struct mwl_softc *sc, struct mwl_channel *chan)
2447 {
2448         MWL_HAL_CHANNEL hchan;
2449         int maxtxpow;
2450 
2451         MWL_DBG(MWL_DBG_HW, "mwl: mwl_chan_set(): "
2452             "chan %u MHz/flags 0x%x\n",
2453             chan->ic_freq, chan->ic_flags);
2454 
2455         /*
2456          * Convert to a HAL channel description with
2457          * the flags constrained to reflect the current
2458          * operating mode.
2459          */
2460         mwl_mapchan(&hchan, chan);
2461         mwl_hal_intrset(sc, 0);         /* disable interrupts */
2462 
2463         (void) mwl_hal_setchannel(sc, &hchan);
2464         /*
2465          * Tx power is cap'd by the regulatory setting and
2466          * possibly a user-set limit.  We pass the min of
2467          * these to the hal to apply them to the cal data
2468          * for this channel.
2469          * XXX min bound?
2470          */
2471         maxtxpow = 2 * chan->ic_maxregpower;
2472         if (maxtxpow > 100)
2473                 maxtxpow = 100;
2474         (void) mwl_hal_settxpower(sc, &hchan, maxtxpow / 2);
2475         /* NB: potentially change mcast/mgt rates */
2476         (void) mwl_setcurchanrates(sc);
2477 
2478         sc->sc_curchan = hchan;
2479         mwl_hal_intrset(sc, sc->sc_imask);
2480 
2481         return (0);
2482 }
2483 
2484 /*
2485  * Convert net80211 channel to a HAL channel.
2486  */
2487 static void
2488 mwl_mapchan(MWL_HAL_CHANNEL *hc, const struct mwl_channel *chan)
2489 {
2490         hc->channel = chan->ic_ieee;
2491 
2492         *(uint32_t *)&hc->channelFlags = 0;
2493         if (((chan)->ic_flags & IEEE80211_CHAN_2GHZ) != 0)
2494                 hc->channelFlags.FreqBand = MWL_FREQ_BAND_2DOT4GHZ;
2495         else if (((chan)->ic_flags & IEEE80211_CHAN_5GHZ) != 0)
2496                 hc->channelFlags.FreqBand = MWL_FREQ_BAND_5GHZ;
2497         if (((chan)->ic_flags & IEEE80211_CHAN_HT40) != 0) {
2498                 hc->channelFlags.ChnlWidth = MWL_CH_40_MHz_WIDTH;
2499                 if (((chan)->ic_flags & IEEE80211_CHAN_HT40U) != 0)
2500                         hc->channelFlags.ExtChnlOffset =
2501                             MWL_EXT_CH_ABOVE_CTRL_CH;
2502                 else
2503                         hc->channelFlags.ExtChnlOffset =
2504                             MWL_EXT_CH_BELOW_CTRL_CH;
2505         } else
2506                 hc->channelFlags.ChnlWidth = MWL_CH_20_MHz_WIDTH;
2507         /* XXX 10MHz channels */
2508 }
2509 
2510 /*
2511  * Return the phy mode for with the specified channel.
2512  */
2513 enum ieee80211_phymode
2514 mwl_chan2mode(const struct mwl_channel *chan)
2515 {
2516 
2517         if (IEEE80211_IS_CHAN_HTA(chan))
2518                 return (IEEE80211_MODE_11NA);
2519         else if (IEEE80211_IS_CHAN_HTG(chan))
2520                 return (IEEE80211_MODE_11NG);
2521         else if (IEEE80211_IS_CHAN_108G(chan))
2522                 return (IEEE80211_MODE_TURBO_G);
2523         else if (IEEE80211_IS_CHAN_ST(chan))
2524                 return (IEEE80211_MODE_STURBO_A);
2525         else if (IEEE80211_IS_CHAN_TURBO(chan))
2526                 return (IEEE80211_MODE_TURBO_A);
2527         else if (IEEE80211_IS_CHAN_HALF(chan))
2528                 return (IEEE80211_MODE_HALF);
2529         else if (IEEE80211_IS_CHAN_QUARTER(chan))
2530                 return (IEEE80211_MODE_QUARTER);
2531         else if (IEEE80211_IS_CHAN_A(chan))
2532                 return (IEEE80211_MODE_11A);
2533         else if (IEEE80211_IS_CHAN_ANYG(chan))
2534                 return (IEEE80211_MODE_11G);
2535         else if (IEEE80211_IS_CHAN_B(chan))
2536                 return (IEEE80211_MODE_11B);
2537         else if (IEEE80211_IS_CHAN_FHSS(chan))
2538                 return (IEEE80211_MODE_FH);
2539 
2540         /* NB: should not get here */
2541         MWL_DBG(MWL_DBG_HW, "mwl: mwl_chan2mode(): "
2542             "cannot map channel to mode; freq %u flags 0x%x\n",
2543             chan->ic_freq, chan->ic_flags);
2544         return (IEEE80211_MODE_11B);
2545 }
2546 
2547 /* XXX inline or eliminate? */
2548 const struct ieee80211_rateset *
2549 mwl_get_suprates(struct ieee80211com *ic, const struct mwl_channel *c)
2550 {
2551         /* XXX does this work for 11ng basic rates? */
2552         return (&ic->ic_sup_rates[mwl_chan2mode(c)]);
2553 }
2554 
2555 /*
2556  * Inform firmware of tx rate parameters.
2557  * Called after a channel change.
2558  */
2559 static int
2560 mwl_setcurchanrates(struct mwl_softc *sc)
2561 {
2562         struct ieee80211com *ic = &sc->sc_ic;
2563         const struct ieee80211_rateset *rs;
2564         MWL_HAL_TXRATE rates;
2565 
2566         (void) memset(&rates, 0, sizeof (rates));
2567         rs = mwl_get_suprates(ic, sc->sc_cur_chan);
2568         /* rate used to send management frames */
2569         rates.MgtRate = rs->ir_rates[0] & IEEE80211_RATE_VAL;
2570         /* rate used to send multicast frames */
2571         rates.McastRate = rates.MgtRate;
2572 
2573         return (mwl_hal_settxrate_auto(sc, &rates));
2574 }
2575 
2576 static const struct mwl_hal_channel *
2577 findhalchannel(const struct mwl_softc *sc, const MWL_HAL_CHANNEL *c)
2578 {
2579         const struct mwl_hal_channel *hc;
2580         const MWL_HAL_CHANNELINFO *ci;
2581         int chan = c->channel, i;
2582 
2583         if (c->channelFlags.FreqBand == MWL_FREQ_BAND_2DOT4GHZ) {
2584                 i = chan - 1;
2585                 if (c->channelFlags.ChnlWidth == MWL_CH_40_MHz_WIDTH) {
2586                         ci = &sc->sc_40M;
2587                         if (c->channelFlags.ExtChnlOffset ==
2588                             MWL_EXT_CH_BELOW_CTRL_CH)
2589                                 i -= 4;
2590                 } else
2591                         ci = &sc->sc_20M;
2592                 /* 2.4G channel table is directly indexed */
2593                 hc = ((unsigned)i < ci->nchannels) ? &ci->channels[i] : NULL;
2594         } else if (c->channelFlags.FreqBand == MWL_FREQ_BAND_5GHZ) {
2595                 if (c->channelFlags.ChnlWidth == MWL_CH_40_MHz_WIDTH) {
2596                         ci = &sc->sc_40M_5G;
2597                         if (c->channelFlags.ExtChnlOffset ==
2598                             MWL_EXT_CH_BELOW_CTRL_CH)
2599                                 chan -= 4;
2600                 } else
2601                         ci = &sc->sc_20M_5G;
2602                 /* 5GHz channel table is sparse and must be searched */
2603                 for (i = 0; i < ci->nchannels; i++)
2604                         if (ci->channels[i].ieee == chan)
2605                                 break;
2606                 hc = (i < ci->nchannels) ? &ci->channels[i] : NULL;
2607         } else
2608                 hc = NULL;
2609         return (hc);
2610 }
2611 
2612 /*
2613  * Map SKU+country code to region code for radar bin'ing.
2614  */
2615 static int
2616 mwl_map2regioncode(const struct mwl_regdomain *rd)
2617 {
2618         switch (rd->regdomain) {
2619         case SKU_FCC:
2620         case SKU_FCC3:
2621                 return (DOMAIN_CODE_FCC);
2622         case SKU_CA:
2623                 return (DOMAIN_CODE_IC);
2624         case SKU_ETSI:
2625         case SKU_ETSI2:
2626         case SKU_ETSI3:
2627                 if (rd->country == CTRY_SPAIN)
2628                         return (DOMAIN_CODE_SPAIN);
2629                 if (rd->country == CTRY_FRANCE || rd->country == CTRY_FRANCE2)
2630                         return (DOMAIN_CODE_FRANCE);
2631                 /* XXX force 1.3.1 radar type */
2632                 return (DOMAIN_CODE_ETSI_131);
2633         case SKU_JAPAN:
2634                 return (DOMAIN_CODE_MKK);
2635         case SKU_ROW:
2636                 return (DOMAIN_CODE_DGT);       /* Taiwan */
2637         case SKU_APAC:
2638         case SKU_APAC2:
2639         case SKU_APAC3:
2640                 return (DOMAIN_CODE_AUS);       /* Australia */
2641         }
2642         /* XXX KOREA? */
2643         return (DOMAIN_CODE_FCC);                       /* XXX? */
2644 }
2645 
2646 /*
2647  * Setup the rx data structures.  This should only be
2648  * done once or we may get out of sync with the firmware.
2649  */
2650 static int
2651 mwl_startrecv(struct mwl_softc *sc)
2652 {
2653         struct mwl_rx_ring *ring;
2654         struct mwl_rxdesc *ds;
2655         struct mwl_rxbuf *bf, *prev;
2656 
2657         int i;
2658 
2659         ring = &sc->sc_rxring;
2660         bf = ring->buf;
2661 
2662         prev = NULL;
2663         for (i = 0; i < MWL_RX_RING_COUNT; i++, bf++) {
2664                 ds = bf->bf_desc;
2665                 /*
2666                  * NB: DMA buffer contents is known to be unmodified
2667                  * so there's no need to flush the data cache.
2668                  */
2669 
2670                 /*
2671                  * Setup descriptor.
2672                  */
2673                 ds->QosCtrl = 0;
2674                 ds->RSSI = 0;
2675                 ds->Status = EAGLE_RXD_STATUS_IDLE;
2676                 ds->Channel = 0;
2677                 ds->PktLen = LE_16(MWL_AGGR_SIZE);
2678                 ds->SQ2 = 0;
2679                 ds->pPhysBuffData = LE_32(bf->bf_baddr);
2680                 /* NB: don't touch pPhysNext, set once */
2681                 ds->RxControl = EAGLE_RXD_CTRL_DRIVER_OWN;
2682 
2683                 (void) ddi_dma_sync(ring->rxdesc_dma.dma_hdl,
2684                     i * sizeof (struct mwl_rxdesc),
2685                     sizeof (struct mwl_rxdesc),
2686                     DDI_DMA_SYNC_FORDEV);
2687 
2688                 if (prev != NULL) {
2689                         ds = prev->bf_desc;
2690                         ds->pPhysNext = LE_32(bf->bf_daddr);
2691                 }
2692                 prev = bf;
2693         }
2694 
2695         if (prev != NULL) {
2696                 ds = prev->bf_desc;
2697                 ds->pPhysNext = ring->physaddr;
2698         }
2699 
2700         /* set filters, etc. */
2701         (void) mwl_mode_init(sc);
2702 
2703         return (0);
2704 }
2705 
2706 static int
2707 mwl_mode_init(struct mwl_softc *sc)
2708 {
2709         /*
2710          * NB: Ignore promisc in hostap mode; it's set by the
2711          * bridge.  This is wrong but we have no way to
2712          * identify internal requests (from the bridge)
2713          * versus external requests such as for tcpdump.
2714          */
2715         /* mwl_setmcastfilter - not support now */
2716         (void) mwl_hal_setpromisc(sc, 0);
2717 
2718         return (0);
2719 }
2720 
2721 /*
2722  * Kick the firmware to tell it there are new tx descriptors
2723  * for processing.  The driver says what h/w q has work in
2724  * case the f/w ever gets smarter.
2725  */
2726 /* ARGSUSED */
2727 static void
2728 mwl_hal_txstart(struct mwl_softc *sc, int qnum)
2729 {
2730 
2731         mwl_ctl_write4(sc, MACREG_REG_H2A_INTERRUPT_EVENTS,
2732             MACREG_H2ARIC_BIT_PPA_READY);
2733         (void) mwl_ctl_read4(sc, MACREG_REG_INT_CODE);
2734 }
2735 
2736 static int
2737 mwl_send(ieee80211com_t *ic, mblk_t *mp, uint8_t type)
2738 {
2739         struct mwl_softc *sc = (struct mwl_softc *)ic;
2740         struct mwl_tx_ring *ring;
2741         struct mwl_txdesc *ds;
2742         struct mwl_txbuf *bf;
2743         struct ieee80211_frame *wh, *wh1;
2744         struct ieee80211_node *ni = NULL;
2745 
2746         int err, off;
2747         int mblen, pktlen, hdrlen;
2748         mblk_t *m, *m0;
2749         uint8_t *addr_4, *txbuf;
2750         uint16_t *pfwlen;
2751 
2752         MWL_TXLOCK(sc);
2753 
2754         err = DDI_SUCCESS;
2755         if (!MWL_IS_RUNNING(sc) || MWL_IS_SUSPEND(sc)) {
2756                 err = ENXIO;
2757                 goto fail1;
2758         }
2759 
2760         ring = &sc->sc_txring[1];
2761         if (ring->queued > 15) {
2762                 MWL_DBG(MWL_DBG_TX, "mwl: mwl_send(): "
2763                     "no txbuf, %d\n", ring->queued);
2764                 sc->sc_need_sched = 1;
2765                 sc->sc_tx_nobuf++;
2766                 err = ENOMEM;
2767                 goto fail1;
2768         }
2769 
2770         m = allocb(msgdsize(mp) + 32, BPRI_MED);
2771         if (m == NULL) {
2772                 MWL_DBG(MWL_DBG_TX, "mwl: mwl_send():"
2773                     "can't alloc mblk.\n");
2774                 err = DDI_FAILURE;
2775                 goto fail1;
2776         }
2777 
2778         for (off = 0, m0 = mp; m0 != NULL; m0 = m0->b_cont) {
2779                 mblen = MBLKL(m0);
2780                 (void) bcopy(m0->b_rptr, m->b_rptr + off, mblen);
2781                 off += mblen;
2782         }
2783         m->b_wptr += off;
2784 
2785         wh = (struct ieee80211_frame *)m->b_rptr;
2786         ni = ieee80211_find_txnode(ic, wh->i_addr1);
2787         if (ni == NULL) {
2788                 err = DDI_FAILURE;
2789                 sc->sc_tx_err++;
2790                 goto fail2;
2791         }
2792 
2793         hdrlen = sizeof (*wh);
2794         pktlen = msgdsize(m);
2795 
2796         (void) ieee80211_encap(ic, m, ni);
2797 
2798         if (wh->i_fc[1] & IEEE80211_FC1_WEP) {
2799                 const struct ieee80211_cipher *cip;
2800                 struct ieee80211_key *k;
2801                 k = ieee80211_crypto_encap(ic, m);
2802                 if (k == NULL) {
2803                         sc->sc_tx_err++;
2804                         err = DDI_FAILURE;
2805                         goto fail3;
2806                 }
2807 
2808                 /*
2809                  * Adjust the packet length for the crypto additions
2810                  * done during encap and any other bits that the f/w
2811                  * will add later on.
2812                  */
2813                 cip = k->wk_cipher;
2814                 pktlen += cip->ic_header + cip->ic_miclen + cip->ic_trailer;
2815                 /* packet header may have moved, reset our local pointer */
2816                 wh = (struct ieee80211_frame *)m->b_rptr;
2817         }
2818 
2819         ds = &ring->desc[ring->cur];
2820         bf = &ring->buf[ring->cur];
2821 
2822         bf->bf_node = ieee80211_ref_node(ni);
2823         txbuf = (uint8_t *)bf->bf_mem;
2824 
2825         /*
2826          * inject FW specific fields into the 802.11 frame
2827          *
2828          *  2   bytes FW len (inject)
2829          *  24 bytes 802.11 frame header
2830          *  6   bytes addr4 (inject)
2831          *  n   bytes 802.11 frame body
2832          */
2833         pfwlen = (uint16_t *)txbuf;
2834         *pfwlen = pktlen - hdrlen;
2835         wh1 = (struct ieee80211_frame *)(txbuf + 2);
2836         bcopy(wh, wh1, sizeof (struct ieee80211_frame));
2837         addr_4 = txbuf + (sizeof (struct ieee80211_frame) + sizeof (uint16_t));
2838         (void) memset(addr_4, 0, 6);
2839         bcopy(m->b_rptr + sizeof (struct ieee80211_frame), txbuf + 32, *pfwlen);
2840         pktlen += 8;
2841 
2842         (void) ddi_dma_sync(bf->txbuf_dma.dma_hdl,
2843             0,
2844             pktlen,
2845             DDI_DMA_SYNC_FORDEV);
2846 
2847         ds->QosCtrl = 0;
2848         ds->PktLen = (uint16_t)pktlen;
2849         ds->PktPtr = bf->bf_baddr;
2850         ds->Status = LE_32(EAGLE_TXD_STATUS_FW_OWNED);
2851         ds->Format = 0;
2852         ds->pad = 0;
2853         ds->ack_wcb_addr = 0;
2854         ds->TxPriority = 1;
2855 
2856         MWL_DBG(MWL_DBG_TX, "mwl: mwl_send(): "
2857             "tx desc Status %x, DataRate %x, TxPriority %x, QosCtrl %x, "
2858             "PktLen %x, SapPktInfo %x, Format %x, Pad %x, ack_wcb_addr %x\n",
2859             ds->Status, ds->DataRate, ds->TxPriority, ds->QosCtrl, ds->PktLen,
2860             ds->SapPktInfo, ds->Format, ds->pad, ds->ack_wcb_addr);
2861 
2862         (void) ddi_dma_sync(ring->txdesc_dma.dma_hdl,
2863             ring->cur * sizeof (struct mwl_txdesc),
2864             sizeof (struct mwl_txdesc),
2865             DDI_DMA_SYNC_FORDEV);
2866 
2867         MWL_DBG(MWL_DBG_TX, "mwl: mwl_send(): "
2868             "pktlen = %u, slot = %u, queued = %x\n",
2869             mblen, ring->cur, ring->queued);
2870 
2871         ring->queued++;
2872         ring->cur = (ring->cur + 1) % MWL_TX_RING_COUNT;
2873 
2874         /*
2875          * NB: We don't need to lock against tx done because
2876          * this just prods the firmware to check the transmit
2877          * descriptors.  The firmware will also start fetching
2878          * descriptors by itself if it notices new ones are
2879          * present when it goes to deliver a tx done interrupt
2880          * to the host. So if we race with tx done processing
2881          * it's ok.  Delivering the kick here rather than in
2882          * mwl_tx_start is an optimization to avoid poking the
2883          * firmware for each packet.
2884          *
2885          * NB: the queue id isn't used so 0 is ok.
2886          */
2887         mwl_hal_txstart(sc, 0);
2888 
2889         ic->ic_stats.is_tx_frags++;
2890         ic->ic_stats.is_tx_bytes += pktlen;
2891 
2892 fail3:
2893         ieee80211_free_node(ni);
2894 fail2:
2895         freemsg(m);
2896 fail1:
2897         if ((type & IEEE80211_FC0_TYPE_MASK) != IEEE80211_FC0_TYPE_DATA ||
2898             err == DDI_SUCCESS)
2899                 freemsg(mp);
2900         MWL_TXUNLOCK(sc);
2901         return (err);
2902 }
2903 
2904 /*
2905  * This function is called periodically (every 200ms) during scanning to
2906  * switch from one channel to another.
2907  */
2908 static void
2909 mwl_next_scan(void *arg)
2910 {
2911         struct mwl_softc *sc = (struct mwl_softc *)arg;
2912         struct ieee80211com *ic = &sc->sc_ic;
2913 
2914         if (ic->ic_state == IEEE80211_S_SCAN)
2915                 (void) ieee80211_next_scan(ic);
2916 
2917         sc->sc_scan_id = 0;
2918 }
2919 
2920 /*
2921  * Convert a legacy rate set to a firmware bitmask.
2922  */
2923 static uint32_t
2924 get_rate_bitmap(const struct ieee80211_rateset *rs)
2925 {
2926         uint32_t rates;
2927         int i;
2928 
2929         rates = 0;
2930         for (i = 0; i < rs->ir_nrates; i++)
2931                 switch (rs->ir_rates[i] & IEEE80211_RATE_VAL) {
2932                 case 2:   rates |= 0x001; break;
2933                 case 4:   rates |= 0x002; break;
2934                 case 11:  rates |= 0x004; break;
2935                 case 22:  rates |= 0x008; break;
2936                 case 44:  rates |= 0x010; break;
2937                 case 12:  rates |= 0x020; break;
2938                 case 18:  rates |= 0x040; break;
2939                 case 24:  rates |= 0x080; break;
2940                 case 36:  rates |= 0x100; break;
2941                 case 48:  rates |= 0x200; break;
2942                 case 72:  rates |= 0x400; break;
2943                 case 96:  rates |= 0x800; break;
2944                 case 108: rates |= 0x1000; break;
2945                 }
2946         return (rates);
2947 }
2948 
2949 /*
2950  * Craft station database entry for station.
2951  * NB: use host byte order here, the hal handles byte swapping.
2952  */
2953 static MWL_HAL_PEERINFO *
2954 mkpeerinfo(MWL_HAL_PEERINFO *pi, const struct ieee80211_node *ni)
2955 {
2956         (void) memset(pi, 0, sizeof (*pi));
2957         pi->LegacyRateBitMap = get_rate_bitmap(&ni->in_rates);
2958         pi->CapInfo = ni->in_capinfo;
2959         return (pi);
2960 }
2961 
2962 static int
2963 mwl_newstate(struct ieee80211com *ic, enum ieee80211_state nstate, int arg)
2964 {
2965         struct mwl_softc *sc = (struct mwl_softc *)ic;
2966         enum ieee80211_state ostate;
2967         struct ieee80211_channel *ic_chan;
2968         struct ieee80211_node *ni = NULL;
2969         MWL_HAL_PEERINFO pi;
2970         uint32_t chan;
2971 
2972         if (sc->sc_scan_id != 0) {
2973                 (void) untimeout(sc->sc_scan_id);
2974                 sc->sc_scan_id = 0;
2975         }
2976 
2977         MWL_GLOCK(sc);
2978 
2979         ostate = ic->ic_state;
2980         MWL_DBG(MWL_DBG_MSG, "mwl: mwl_newstate(): "
2981             "ostate %x -> nstate %x\n",
2982             ostate, nstate);
2983 
2984         switch (nstate) {
2985         case IEEE80211_S_INIT:
2986                 break;
2987         case IEEE80211_S_SCAN:
2988                 if (ostate != IEEE80211_S_INIT) {
2989                         ic_chan = ic->ic_curchan;
2990                         chan = ieee80211_chan2ieee(ic, ic_chan);
2991                         if (chan != 0 && chan != IEEE80211_CHAN_ANY) {
2992                                 sc->sc_cur_chan =
2993                                     &sc->sc_channels[3 * chan - 2];
2994                                 MWL_DBG(MWL_DBG_MSG, "mwl: mwl_newstate(): "
2995                                     "chan num is %u, sc chan is %u\n",
2996                                     chan, sc->sc_cur_chan->ic_ieee);
2997                                 (void) mwl_chan_set(sc, sc->sc_cur_chan);
2998                         }
2999                 }
3000                 sc->sc_scan_id = timeout(mwl_next_scan, (void *)sc,
3001                     drv_usectohz(250000));
3002                 break;
3003         case IEEE80211_S_AUTH:
3004                 ic_chan = ic->ic_curchan;
3005                 chan = ieee80211_chan2ieee(ic, ic_chan);
3006                 sc->sc_cur_chan = &sc->sc_channels[3 * chan - 2];
3007                 MWL_DBG(MWL_DBG_MSG, "mwl: mwl_newstate(): "
3008                     "chan num is %u, sc chan is %u\n",
3009                     chan, sc->sc_cur_chan->ic_ieee);
3010                 (void) mwl_chan_set(sc, sc->sc_cur_chan);
3011                 ni = ic->ic_bss;
3012                 (void) mwl_hal_newstation(sc, ic->ic_macaddr, 0, 0, NULL, 0, 0);
3013                 mwl_setanywepkey(ic, ni->in_macaddr);
3014                 break;
3015         case IEEE80211_S_ASSOC:
3016                 break;
3017         case IEEE80211_S_RUN:
3018                 ni = ic->ic_bss;
3019                 (void) mwl_hal_newstation(sc,
3020                     ic->ic_macaddr, 0, 0, mkpeerinfo(&pi, ni), 0, 0);
3021                 mwl_setglobalkeys(ic);
3022                 (void) mwl_hal_setassocid(sc,
3023                     ic->ic_bss->in_bssid, ic->ic_bss->in_associd);
3024                 (void) mwl_setrates(ic);
3025                 (void) mwl_hal_setrtsthreshold(sc, ic->ic_rtsthreshold);
3026                 (void) mwl_hal_setcsmode(sc, CSMODE_AUTO_ENA);
3027                 break;
3028         default:
3029                 break;
3030         }
3031 
3032         MWL_GUNLOCK(sc);
3033 
3034         return (sc->sc_newstate(ic, nstate, arg));
3035 }
3036 
3037 /*
3038  * Set the interrupt mask.
3039  */
3040 static void
3041 mwl_hal_intrset(struct mwl_softc *sc, uint32_t mask)
3042 {
3043         mwl_ctl_write4(sc, MACREG_REG_A2H_INTERRUPT_MASK, 0);
3044         (void) mwl_ctl_read4(sc, MACREG_REG_INT_CODE);
3045 
3046         sc->sc_hal_imask = mask;
3047         mwl_ctl_write4(sc, MACREG_REG_A2H_INTERRUPT_MASK, mask);
3048         (void) mwl_ctl_read4(sc, MACREG_REG_INT_CODE);
3049 }
3050 
3051 /*
3052  * Return the current ISR setting and clear the cause.
3053  */
3054 static void
3055 mwl_hal_getisr(struct mwl_softc *sc, uint32_t *status)
3056 {
3057         uint32_t cause;
3058 
3059         cause = mwl_ctl_read4(sc, MACREG_REG_A2H_INTERRUPT_CAUSE);
3060         if (cause == 0xffffffff) {      /* card removed */
3061                 cause = 0;
3062         } else if (cause != 0) {
3063                 /* clear cause bits */
3064                 mwl_ctl_write4(sc, MACREG_REG_A2H_INTERRUPT_CAUSE,
3065                     cause & ~sc->sc_hal_imask);
3066                 (void) mwl_ctl_read4(sc, MACREG_REG_INT_CODE);
3067                 cause &= sc->sc_hal_imask;
3068         }
3069         *status = cause;
3070 }
3071 
3072 static void
3073 mwl_tx_intr(struct mwl_softc *sc)
3074 {
3075         struct ieee80211com *ic = &sc->sc_ic;
3076         struct mwl_tx_ring *ring;
3077         struct mwl_txdesc *ds;
3078 
3079         uint32_t status;
3080 
3081         MWL_TXLOCK(sc);
3082 
3083         ring = &sc->sc_txring[1];
3084 
3085         if (!(ring->queued)) {
3086                 MWL_TXUNLOCK(sc);
3087                 return;
3088         }
3089 
3090         (void) ddi_dma_sync(ring->txdesc_dma.dma_hdl,
3091             0,
3092             ring->txdesc_dma.alength,
3093             DDI_DMA_SYNC_FORCPU);
3094 
3095         for (;;) {
3096                 ds = &ring->desc[ring->next];
3097 
3098                 status = LE_32(ds->Status);
3099 
3100                 if (status & LE_32(EAGLE_TXD_STATUS_FW_OWNED)) {
3101                         break;
3102                 }
3103 
3104                 if (status == LE_32(EAGLE_TXD_STATUS_IDLE)) {
3105                         break;
3106                 }
3107 
3108                 MWL_DBG(MWL_DBG_TX, "mwl: mwl_tx_intr(): "
3109                     "recv tx desc status %x, datarate %x, txpriority %x, "
3110                     "QosCtrl %x, pktLen %x, SapPktInfo %x, Format %x, "
3111                     "pad %x, ack_wcb_addr %x\n",
3112                     ds->Status, ds->DataRate, ds->TxPriority,
3113                     ds->QosCtrl, ds->PktLen, ds->SapPktInfo,
3114                     ds->Format, ds->pad, ds->ack_wcb_addr);
3115 
3116                 /* descriptor is no longer valid */
3117                 ds->Status = LE_32(EAGLE_TXD_STATUS_IDLE);
3118 
3119                 (void) ddi_dma_sync(ring->txdesc_dma.dma_hdl,
3120                     ring->next * sizeof (struct mwl_txdesc),
3121                     sizeof (struct mwl_txdesc),
3122                     DDI_DMA_SYNC_FORDEV);
3123 
3124                 ring->queued--;
3125                 ring->next = (ring->next + 1) % MWL_TX_RING_COUNT;
3126                 MWL_DBG(MWL_DBG_TX, "mwl: mwl_tx_intr(): "
3127                     " tx done idx=%u, queued= %d\n",
3128                     ring->next, ring->queued);
3129 
3130                 if (sc->sc_need_sched &&
3131                     (ring->queued < MWL_TX_RING_COUNT)) {
3132                         sc->sc_need_sched = 0;
3133                         mac_tx_update(ic->ic_mach);
3134                 }
3135 
3136         }
3137 
3138         MWL_TXUNLOCK(sc);
3139 }
3140 
3141 /*
3142  * Convert hardware signal strength to rssi.  The value
3143  * provided by the device has the noise floor added in;
3144  * we need to compensate for this but we don't have that
3145  * so we use a fixed value.
3146  *
3147  * The offset of 8 is good for both 2.4 and 5GHz.  The LNA
3148  * offset is already set as part of the initial gain.  This
3149  * will give at least +/- 3dB for 2.4GHz and +/- 5dB for 5GHz.
3150  */
3151 static int
3152 cvtrssi(uint8_t ssi)
3153 {
3154         int rssi = (int)ssi + 8;
3155         /* XXX hack guess until we have a real noise floor */
3156         rssi = 2 * (87 - rssi); /* NB: .5 dBm units */
3157         return (rssi < 0 ? 0 : rssi > 127 ? 127 : rssi);
3158 }
3159 
3160 static void
3161 mwl_rx_intr(struct mwl_softc *sc)
3162 {
3163         struct ieee80211com     *ic = &sc->sc_ic;
3164         struct mwl_rx_ring *ring;
3165         struct ieee80211_node   *ni;
3166         struct ieee80211_frame *wh;
3167 
3168         struct mwl_rxbuf *bf;
3169         struct mwl_rxdesc *ds;
3170         mblk_t  *mp0;
3171 
3172         int ntodo, len, rssi;
3173         uint8_t *data, status;
3174 
3175         MWL_RXLOCK(sc);
3176 
3177         ring = &sc->sc_rxring;
3178         for (ntodo = MWL_RX_RING_COUNT; ntodo > 0; ntodo--) {
3179                 bf = &ring->buf[ring->cur];
3180                 ds = bf->bf_desc;
3181                 data = bf->bf_mem;
3182 
3183                 (void) ddi_dma_sync(ring->rxdesc_dma.dma_hdl,
3184                     ring->cur * sizeof (struct mwl_rxdesc),
3185                     sizeof (struct mwl_rxdesc),
3186                     DDI_DMA_SYNC_FORCPU);
3187 
3188                 if (ds->RxControl != EAGLE_RXD_CTRL_DMA_OWN)
3189                         break;
3190 
3191                 status = ds->Status;
3192                 if (status & EAGLE_RXD_STATUS_DECRYPT_ERR_MASK) {
3193                         MWL_DBG(MWL_DBG_CRYPTO, "mwl: mwl_rx_intr(): "
3194                             "rx decrypt error\n");
3195                         sc->sc_rx_err++;
3196                 }
3197 
3198                 /*
3199                  * Sync the data buffer.
3200                  */
3201                 len = LE_16(ds->PktLen);
3202 
3203                 (void) ddi_dma_sync(bf->rxbuf_dma.dma_hdl,
3204                     0,
3205                     bf->rxbuf_dma.alength,
3206                     DDI_DMA_SYNC_FORCPU);
3207 
3208                 if (len < 32 || len > sc->sc_dmabuf_size) {
3209                         MWL_DBG(MWL_DBG_RX, "mwl: mwl_rx_intr(): "
3210                             "packet len error %d\n", len);
3211                         sc->sc_rx_err++;
3212                         goto rxnext;
3213                 }
3214 
3215                 mp0 = allocb(sc->sc_dmabuf_size, BPRI_MED);
3216                 if (mp0 == NULL) {
3217                         MWL_DBG(MWL_DBG_RX, "mwl: mwl_rx_intr(): "
3218                             "alloc mblk error\n");
3219                         sc->sc_rx_nobuf++;
3220                         goto rxnext;
3221                 }
3222                 bcopy(data+ 2, mp0->b_wptr, 24);
3223                 mp0->b_wptr += 24;
3224                 bcopy(data + 32, mp0->b_wptr, len - 32);
3225                 mp0->b_wptr += (len - 32);
3226 
3227                 wh = (struct ieee80211_frame *)mp0->b_rptr;
3228                 if ((wh->i_fc[0] & IEEE80211_FC0_TYPE_MASK) ==
3229                     IEEE80211_FC0_TYPE_CTL) {
3230                         freemsg(mp0);
3231                         goto rxnext;
3232                 }
3233 
3234                 /*
3235                  * The f/w strips WEP header but doesn't clear
3236                  * the WEP bit; mark the packet with M_WEP so
3237                  * net80211 will treat the data as decrypted.
3238                  * While here also clear the PWR_MGT bit since
3239                  * power save is handled by the firmware and
3240                  * passing this up will potentially cause the
3241                  * upper layer to put a station in power save
3242                  * (except when configured with MWL_HOST_PS_SUPPORT).
3243                  */
3244 #ifdef MWL_HOST_PS_SUPPORT
3245                 wh->i_fc[1] &= ~IEEE80211_FC1_WEP;
3246 #else
3247                 wh->i_fc[1] &= ~(IEEE80211_FC1_WEP | IEEE80211_FC1_PWR_MGT);
3248 #endif
3249 
3250                 /* calculate rssi early so we can re-use for each aggregate */
3251                 rssi = cvtrssi(ds->RSSI);
3252 
3253                 ni = ieee80211_find_rxnode(ic, wh);
3254 
3255                 /* send the frame to the 802.11 layer */
3256                 (void) ieee80211_input(ic, mp0, ni, rssi, 0);
3257                 ieee80211_free_node(ni);
3258 rxnext:
3259                 /*
3260                  * Setup descriptor.
3261                  */
3262                 ds->QosCtrl = 0;
3263                 ds->RSSI = 0;
3264                 ds->Status = EAGLE_RXD_STATUS_IDLE;
3265                 ds->Channel = 0;
3266                 ds->PktLen = LE_16(MWL_AGGR_SIZE);
3267                 ds->SQ2 = 0;
3268                 ds->pPhysBuffData = bf->bf_baddr;
3269                 /* NB: don't touch pPhysNext, set once */
3270                 ds->RxControl = EAGLE_RXD_CTRL_DRIVER_OWN;
3271 
3272                 (void) ddi_dma_sync(ring->rxdesc_dma.dma_hdl,
3273                     ring->cur * sizeof (struct mwl_rxdesc),
3274                     sizeof (struct mwl_rxdesc),
3275                     DDI_DMA_SYNC_FORDEV);
3276 
3277                 /* NB: ignore ENOMEM so we process more descriptors */
3278                 ring->cur = (ring->cur + 1) % MWL_RX_RING_COUNT;
3279         }
3280 
3281         MWL_RXUNLOCK(sc);
3282 }
3283 
3284 /*ARGSUSED*/
3285 static uint_t
3286 mwl_softintr(caddr_t data, caddr_t unused)
3287 {
3288         struct mwl_softc *sc = (struct mwl_softc *)data;
3289 
3290         /*
3291          * Check if the soft interrupt is triggered by another
3292          * driver at the same level.
3293          */
3294         MWL_GLOCK(sc);
3295         if (sc->sc_rx_pend) {
3296                 sc->sc_rx_pend = 0;
3297                 MWL_GUNLOCK(sc);
3298                 mwl_rx_intr(sc);
3299                 return (DDI_INTR_CLAIMED);
3300         }
3301         MWL_GUNLOCK(sc);
3302 
3303         return (DDI_INTR_UNCLAIMED);
3304 }
3305 
3306 /*ARGSUSED*/
3307 static uint_t
3308 mwl_intr(caddr_t arg, caddr_t unused)
3309 {
3310         struct mwl_softc *sc = (struct mwl_softc *)arg;
3311         uint32_t status;
3312 
3313         MWL_GLOCK(sc);
3314 
3315         if (!MWL_IS_RUNNING(sc) || MWL_IS_SUSPEND(sc)) {
3316                 MWL_GUNLOCK(sc);
3317                 return (DDI_INTR_UNCLAIMED);
3318         }
3319 
3320         /*
3321          * Figure out the reason(s) for the interrupt.
3322          */
3323         mwl_hal_getisr(sc, &status);                /* NB: clears ISR too */
3324         if (status == 0) {
3325                 MWL_GUNLOCK(sc);
3326                 return (DDI_INTR_UNCLAIMED);
3327         }
3328 
3329         if (status & MACREG_A2HRIC_BIT_RX_RDY) {
3330                 sc->sc_rx_pend = 1;
3331                 (void) ddi_intr_trigger_softint(sc->sc_softintr_hdl, NULL);
3332         }
3333         if (status & MACREG_A2HRIC_BIT_TX_DONE) {
3334                 mwl_tx_intr(sc);
3335         }
3336         if (status & MACREG_A2HRIC_BIT_BA_WATCHDOG) {
3337                 MWL_DBG(MWL_DBG_INTR, "mwl: mwl_intr(): "
3338                     "ba watchdog\n");
3339         }
3340         if (status & MACREG_A2HRIC_BIT_OPC_DONE) {
3341                 MWL_DBG(MWL_DBG_INTR, "mwl: mwl_intr(): "
3342                     "opc done\n");
3343         }
3344         if (status & MACREG_A2HRIC_BIT_MAC_EVENT) {
3345                 MWL_DBG(MWL_DBG_INTR, "mwl: mwl_intr(): "
3346                     "mac event\n");
3347         }
3348         if (status & MACREG_A2HRIC_BIT_ICV_ERROR) {
3349                 MWL_DBG(MWL_DBG_INTR, "mwl: mwl_intr(): "
3350                     "ICV error\n");
3351         }
3352         if (status & MACREG_A2HRIC_BIT_QUEUE_EMPTY) {
3353                 MWL_DBG(MWL_DBG_INTR, "mwl: mwl_intr(): "
3354                     "queue empty\n");
3355         }
3356         if (status & MACREG_A2HRIC_BIT_QUEUE_FULL) {
3357                 MWL_DBG(MWL_DBG_INTR, "mwl: mwl_intr(): "
3358                     "queue full\n");
3359         }
3360         if (status & MACREG_A2HRIC_BIT_RADAR_DETECT) {
3361                 MWL_DBG(MWL_DBG_INTR, "mwl: mwl_intr(): "
3362                     "radar detect\n");
3363         }
3364         if (status & MACREG_A2HRIC_BIT_CHAN_SWITCH) {
3365                 MWL_DBG(MWL_DBG_INTR, "mwl: mwl_intr(): "
3366                     "chan switch\n");
3367         }
3368 
3369         MWL_GUNLOCK(sc);
3370 
3371         return (DDI_INTR_CLAIMED);
3372 }
3373 
3374 static int
3375 mwl_init(struct mwl_softc *sc)
3376 {
3377         struct ieee80211com *ic = &sc->sc_ic;
3378         int err = 0;
3379 
3380         mwl_hal_intrset(sc, 0);
3381 
3382         sc->sc_txantenna = 0;                /* h/w default */
3383         sc->sc_rxantenna = 0;                /* h/w default */
3384 
3385         err = mwl_hal_setantenna(sc, WL_ANTENNATYPE_RX, sc->sc_rxantenna);
3386         if (err != 0) {
3387                 MWL_DBG(MWL_DBG_HW, "mwl: mwl_init(): "
3388                     "could not set rx antenna\n");
3389                 goto fail;
3390         }
3391 
3392         err = mwl_hal_setantenna(sc, WL_ANTENNATYPE_TX, sc->sc_txantenna);
3393         if (err != 0) {
3394                 MWL_DBG(MWL_DBG_HW, "mwl: init(): "
3395                     "could not set tx antenna\n");
3396                 goto fail;
3397         }
3398 
3399         err = mwl_hal_setradio(sc, 1, WL_AUTO_PREAMBLE);
3400         if (err != 0) {
3401                 MWL_DBG(MWL_DBG_HW, "mwl: init(): "
3402                     "could not set radio\n");
3403                 goto fail;
3404         }
3405 
3406         err = mwl_hal_setwmm(sc, (ic->ic_flags & IEEE80211_F_WME) != 0);
3407         if (err != 0) {
3408                 MWL_DBG(MWL_DBG_HW, "mwl: init(): "
3409                     "could not set wme\n");
3410                 goto fail;
3411         }
3412 
3413         /* select default channel */
3414         ic->ic_ibss_chan = &ic->ic_sup_channels[0];
3415         ic->ic_curchan = ic->ic_ibss_chan;
3416         sc->sc_cur_chan = &sc->sc_channels[1];
3417 
3418         err = mwl_chan_set(sc, sc->sc_cur_chan);
3419         if (err != 0) {
3420                 MWL_DBG(MWL_DBG_HW, "mwl: init(): "
3421                     "could not set wme\n");
3422                 goto fail;
3423         }
3424 
3425         err = mwl_hal_setrateadaptmode(sc, 0);
3426         if (err != 0) {
3427                 MWL_DBG(MWL_DBG_HW, "mwl: init(): "
3428                     "could not set rate adapt mode\n");
3429                 goto fail;
3430         }
3431 
3432         err = mwl_hal_setoptimizationlevel(sc,
3433             (ic->ic_flags & IEEE80211_F_BURST) != 0);
3434         if (err != 0) {
3435                 MWL_DBG(MWL_DBG_HW, "mwl: init(): "
3436                     "could not set optimization level\n");
3437                 goto fail;
3438         }
3439 
3440         err = mwl_hal_setregioncode(sc, mwl_map2regioncode(&sc->sc_regdomain));
3441         if (err != 0) {
3442                 MWL_DBG(MWL_DBG_HW, "mwl: init(): "
3443                     "could not set regioncode\n");
3444                 goto fail;
3445         }
3446 
3447         err = mwl_startrecv(sc);
3448         if (err != 0) {
3449                 MWL_DBG(MWL_DBG_HW, "mwl: init(): "
3450                     "could not set start recv logic\n");
3451                 goto fail;
3452         }
3453 
3454         /*
3455          * Enable interrupts.
3456          */
3457         sc->sc_imask = MACREG_A2HRIC_BIT_RX_RDY
3458             | MACREG_A2HRIC_BIT_TX_DONE
3459             | MACREG_A2HRIC_BIT_OPC_DONE
3460             | MACREG_A2HRIC_BIT_ICV_ERROR
3461             | MACREG_A2HRIC_BIT_RADAR_DETECT
3462             | MACREG_A2HRIC_BIT_CHAN_SWITCH
3463             | MACREG_A2HRIC_BIT_BA_WATCHDOG
3464             | MACREQ_A2HRIC_BIT_TX_ACK;
3465 
3466         mwl_hal_intrset(sc, sc->sc_imask);
3467 
3468         err = mwl_hal_start(sc);
3469         if (err != 0) {
3470                 MWL_DBG(MWL_DBG_HW, "mwl: init(): "
3471                     "could not get hal start\n");
3472                 goto fail;
3473         }
3474 
3475         err = mwl_hal_setinframode(sc);
3476         if (err != 0) {
3477                 MWL_DBG(MWL_DBG_HW, "mwl: init(): "
3478                     "could not set infra mode\n");
3479                 goto fail;
3480         }
3481 
3482 fail:
3483         return (err);
3484 }
3485 
3486 static int
3487 mwl_resume(struct mwl_softc *sc)
3488 {
3489         int qid, err = 0;
3490 
3491         err = mwl_fwload(sc, NULL);
3492         if (err != 0) {
3493                 MWL_DBG(MWL_DBG_SR, "mwl: mwl_resume(): "
3494                     "failed to load fw\n");
3495                 goto fail;
3496         }
3497 
3498         err = mwl_gethwspecs(sc);
3499         if (err != 0) {
3500                 MWL_DBG(MWL_DBG_SR, "mwl: mwl_resume(): "
3501                     "failed to get hw spec\n");
3502                 goto fail;
3503         }
3504 
3505         err = mwl_alloc_rx_ring(sc, MWL_RX_RING_COUNT);
3506         if (err != 0) {
3507                 MWL_DBG(MWL_DBG_SR, "mwl: mwl_resume(): "
3508                     "could not alloc cmd dma buffer\n");
3509                 goto fail;
3510         }
3511 
3512         for (qid = 0; qid < MWL_NUM_TX_QUEUES; qid++) {
3513                 err = mwl_alloc_tx_ring(sc,
3514                     &sc->sc_txring[qid], MWL_TX_RING_COUNT);
3515                 if (err != 0) {
3516                         MWL_DBG(MWL_DBG_SR, "mwl: mwl_resume(): "
3517                             "could not alloc tx ring %d\n", qid);
3518                         goto fail;
3519                 }
3520         }
3521 
3522         err = mwl_setupdma(sc);
3523         if (err != 0) {
3524                 MWL_DBG(MWL_DBG_SR, "mwl: mwl_resume(): "
3525                     "could not setup dma\n");
3526                 goto fail;
3527         }
3528 
3529         err = mwl_setup_txq(sc);
3530         if (err != 0) {
3531                 MWL_DBG(MWL_DBG_SR, "mwl: mwl_resume(): "
3532                     "could not setup txq\n");
3533                 goto fail;
3534         }
3535 
3536 fail:
3537         return (err);
3538 }
3539 
3540 static void
3541 mwl_stop(struct mwl_softc *sc)
3542 {
3543         int err;
3544 
3545         /* by pass if it's quiesced */
3546         if (!MWL_IS_QUIESCE(sc))
3547                 MWL_GLOCK(sc);
3548 
3549         err = mwl_hal_stop(sc);
3550         if (err != 0) {
3551                 MWL_DBG(MWL_DBG_HW, "mwl: mwl_stop(): "
3552                     "could not stop hw\n");
3553         }
3554 
3555         /* by pass if it's quiesced */
3556         if (!MWL_IS_QUIESCE(sc))
3557                 MWL_GUNLOCK(sc);
3558 }
3559 
3560 static int
3561 mwl_m_stat(void *arg, uint_t stat, uint64_t *val)
3562 {
3563         struct mwl_softc *sc  = (struct mwl_softc *)arg;
3564         struct ieee80211com *ic = &sc->sc_ic;
3565         struct ieee80211_node *ni = NULL;
3566         struct ieee80211_rateset *rs = NULL;
3567 
3568         MWL_GLOCK(sc);
3569         switch (stat) {
3570         case MAC_STAT_IFSPEED:
3571                 ni = ic->ic_bss;
3572                 rs = &ni->in_rates;
3573                 *val = ((ic->ic_fixed_rate == IEEE80211_FIXED_RATE_NONE) ?
3574                     (rs->ir_rates[ni->in_txrate] & IEEE80211_RATE_VAL)
3575                     : ic->ic_fixed_rate) / 2 * 1000000;
3576                 break;
3577         case MAC_STAT_NOXMTBUF:
3578                 *val = sc->sc_tx_nobuf;
3579                 break;
3580         case MAC_STAT_NORCVBUF:
3581                 *val = sc->sc_rx_nobuf;
3582                 break;
3583         case MAC_STAT_IERRORS:
3584                 *val = sc->sc_rx_err;
3585                 break;
3586         case MAC_STAT_RBYTES:
3587                 *val = ic->ic_stats.is_rx_bytes;
3588                 break;
3589         case MAC_STAT_IPACKETS:
3590                 *val = ic->ic_stats.is_rx_frags;
3591                 break;
3592         case MAC_STAT_OBYTES:
3593                 *val = ic->ic_stats.is_tx_bytes;
3594                 break;
3595         case MAC_STAT_OPACKETS:
3596                 *val = ic->ic_stats.is_tx_frags;
3597                 break;
3598         case MAC_STAT_OERRORS:
3599         case WIFI_STAT_TX_FAILED:
3600                 *val = sc->sc_tx_err;
3601                 break;
3602         case WIFI_STAT_TX_RETRANS:
3603                 *val = sc->sc_tx_retries;
3604                 break;
3605         case WIFI_STAT_FCS_ERRORS:
3606         case WIFI_STAT_WEP_ERRORS:
3607         case WIFI_STAT_TX_FRAGS:
3608         case WIFI_STAT_MCAST_TX:
3609         case WIFI_STAT_RTS_SUCCESS:
3610         case WIFI_STAT_RTS_FAILURE:
3611         case WIFI_STAT_ACK_FAILURE:
3612         case WIFI_STAT_RX_FRAGS:
3613         case WIFI_STAT_MCAST_RX:
3614         case WIFI_STAT_RX_DUPS:
3615                 MWL_GUNLOCK(sc);
3616                 return (ieee80211_stat(ic, stat, val));
3617         default:
3618                 MWL_GUNLOCK(sc);
3619                 return (ENOTSUP);
3620         }
3621 
3622         MWL_GUNLOCK(sc);
3623         return (0);
3624 }
3625 
3626 static int
3627 mwl_m_start(void *arg)
3628 {
3629         struct mwl_softc *sc = (struct mwl_softc *)arg;
3630         struct ieee80211com *ic = &sc->sc_ic;
3631         int err;
3632 
3633         err = mwl_init(sc);
3634         if (err != DDI_SUCCESS) {
3635                 MWL_DBG(MWL_DBG_HW, "mwl: mwl_m_start():"
3636                     "Hardware initialization failed\n");
3637                 goto fail1;
3638         }
3639 
3640         ieee80211_new_state(ic, IEEE80211_S_INIT, -1);
3641 
3642         MWL_GLOCK(sc);
3643         sc->sc_flags |= MWL_F_RUNNING;
3644         MWL_GUNLOCK(sc);
3645 
3646         return (0);
3647 fail1:
3648         mwl_stop(sc);
3649         return (err);
3650 }
3651 
3652 static void
3653 mwl_m_stop(void *arg)
3654 {
3655         struct mwl_softc *sc = (struct mwl_softc *)arg;
3656 
3657         mwl_stop(sc);
3658 
3659         ieee80211_new_state(&sc->sc_ic, IEEE80211_S_INIT, -1);
3660 
3661         MWL_GLOCK(sc);
3662         sc->sc_flags &= ~MWL_F_RUNNING;
3663         MWL_GUNLOCK(sc);
3664 }
3665 
3666 /*ARGSUSED*/
3667 static int
3668 mwl_m_promisc(void *arg, boolean_t on)
3669 {
3670         struct mwl_softc *sc = (struct mwl_softc *)arg;
3671         int err;
3672 
3673         err = mwl_hal_setpromisc(sc, on);
3674 
3675         return (err);
3676 }
3677 
3678 /*ARGSUSED*/
3679 static int
3680 mwl_m_multicst(void *arg, boolean_t add, const uint8_t *mca)
3681 {
3682         return (ENOTSUP);
3683 }
3684 
3685 /*ARGSUSED*/
3686 static int
3687 mwl_m_unicst(void *arg, const uint8_t *macaddr)
3688 {
3689         return (ENOTSUP);
3690 }
3691 
3692 static mblk_t *
3693 mwl_m_tx(void *arg, mblk_t *mp)
3694 {
3695         struct mwl_softc *sc = (struct mwl_softc *)arg;
3696         struct ieee80211com *ic = &sc->sc_ic;
3697         mblk_t *next;
3698 
3699         if (MWL_IS_SUSPEND(sc)) {
3700                 freemsgchain(mp);
3701                 return (NULL);
3702         }
3703 
3704         /*
3705          * No data frames go out unless we're associated; this
3706          * should not happen as the 802.11 layer does not enable
3707          * the xmit queue until we enter the RUN state.
3708          */
3709         if (ic->ic_state != IEEE80211_S_RUN) {
3710                 MWL_DBG(MWL_DBG_TX, "mwl: mwl_m_tx(): "
3711                     "discard, state %u\n", ic->ic_state);
3712                 freemsgchain(mp);
3713                 return (NULL);
3714         }
3715 
3716         while (mp != NULL) {
3717                 next = mp->b_next;
3718                 mp->b_next = NULL;
3719                 if (mwl_send(ic, mp, IEEE80211_FC0_TYPE_DATA) !=
3720                     DDI_SUCCESS) {
3721                         mp->b_next = next;
3722                         break;
3723                 }
3724                 mp = next;
3725         }
3726         return (mp);
3727 }
3728 
3729 static void
3730 mwl_m_ioctl(void* arg, queue_t *wq, mblk_t *mp)
3731 {
3732         struct mwl_softc *sc = (struct mwl_softc *)arg;
3733         struct ieee80211com *ic = &sc->sc_ic;
3734         int err;
3735 
3736         err = ieee80211_ioctl(ic, wq, mp);
3737         if (err == ENETRESET) {
3738                 if (ic->ic_des_esslen) {
3739                         if (MWL_IS_RUNNING(sc)) {
3740                                 (void) mwl_init(sc);
3741                                 (void) ieee80211_new_state(ic,
3742                                     IEEE80211_S_SCAN, -1);
3743                         }
3744                 }
3745         }
3746 }
3747 
3748 /*
3749  * Call back function for get/set proporty
3750  */
3751 static int
3752 mwl_m_getprop(void *arg, const char *pr_name, mac_prop_id_t wldp_pr_num,
3753     uint_t wldp_length, void *wldp_buf)
3754 {
3755         struct mwl_softc *sc = (struct mwl_softc *)arg;
3756         int err = 0;
3757 
3758         err = ieee80211_getprop(&sc->sc_ic, pr_name, wldp_pr_num,
3759             wldp_length, wldp_buf);
3760 
3761         return (err);
3762 }
3763 
3764 static void
3765 mwl_m_propinfo(void *arg, const char *pr_name, mac_prop_id_t wldp_pr_num,
3766     mac_prop_info_handle_t prh)
3767 {
3768         struct mwl_softc *sc = (struct mwl_softc *)arg;
3769 
3770         ieee80211_propinfo(&sc->sc_ic, pr_name, wldp_pr_num, prh);
3771 }
3772 
3773 static int
3774 mwl_m_setprop(void *arg, const char *pr_name, mac_prop_id_t wldp_pr_num,
3775     uint_t wldp_length, const void *wldp_buf)
3776 {
3777         struct mwl_softc *sc = (struct mwl_softc *)arg;
3778         ieee80211com_t *ic = &sc->sc_ic;
3779         int err;
3780 
3781         err = ieee80211_setprop(ic, pr_name, wldp_pr_num, wldp_length,
3782             wldp_buf);
3783         if (err == ENETRESET) {
3784                 if (ic->ic_des_esslen) {
3785                         if (MWL_IS_RUNNING(sc)) {
3786                                 (void) mwl_init(sc);
3787                                 (void) ieee80211_new_state(ic,
3788                                     IEEE80211_S_SCAN, -1);
3789                         }
3790                 }
3791                 err = 0;
3792         }
3793         return (err);
3794 }
3795 
3796 static int
3797 mwl_attach(dev_info_t *devinfo, ddi_attach_cmd_t cmd)
3798 {
3799         struct mwl_softc *sc;
3800         struct ieee80211com *ic;
3801         int i, err, qid, instance;
3802         int intr_type, intr_count, intr_actual;
3803         char strbuf[32];
3804         uint8_t csz;
3805         uint16_t vendor_id, device_id, command;
3806 
3807         wifi_data_t wd = { 0 };
3808         mac_register_t *macp;
3809 
3810         switch (cmd) {
3811         case DDI_ATTACH:
3812                 break;
3813         case DDI_RESUME:
3814                 sc = ddi_get_soft_state(mwl_soft_state_p,
3815                     ddi_get_instance(devinfo));
3816                 ASSERT(sc != NULL);
3817                 MWL_GLOCK(sc);
3818                 sc->sc_flags &= ~MWL_F_SUSPEND;
3819                 MWL_GUNLOCK(sc);
3820                 if (mwl_resume(sc) != 0) {
3821                         MWL_DBG(MWL_DBG_SR, "mwl: mwl_attach(): "
3822                             "failed to resume\n");
3823                         return (DDI_FAILURE);
3824                 }
3825                 if (MWL_IS_RUNNING(sc)) {
3826                         (void) mwl_init(sc);
3827                         ieee80211_new_state(&sc->sc_ic, IEEE80211_S_INIT, -1);
3828                 }
3829                 MWL_DBG(MWL_DBG_SR, "mwl: mwl_attach(): "
3830                     "resume now\n");
3831                 return (DDI_SUCCESS);
3832         default:
3833                 return (DDI_FAILURE);
3834         }
3835 
3836         instance = ddi_get_instance(devinfo);
3837         if (ddi_soft_state_zalloc(mwl_soft_state_p,
3838             ddi_get_instance(devinfo)) != DDI_SUCCESS) {
3839                 MWL_DBG(MWL_DBG_ATTACH, "mwl: mwl_attach(): "
3840                     "Unable to alloc soft state\n");
3841                 return (DDI_FAILURE);
3842         }
3843 
3844         sc = ddi_get_soft_state(mwl_soft_state_p, ddi_get_instance(devinfo));
3845         ic = &sc->sc_ic;
3846         sc->sc_dev = devinfo;
3847 
3848         /* PCI configuration space */
3849         err = ddi_regs_map_setup(devinfo, 0, (caddr_t *)&sc->sc_cfg_base, 0, 0,
3850             &mwl_reg_accattr, &sc->sc_cfg_handle);
3851         if (err != DDI_SUCCESS) {
3852                 MWL_DBG(MWL_DBG_ATTACH, "mwl: mwl_attach(): "
3853                     "ddi_regs_map_setup() failed");
3854                 goto attach_fail0;
3855         }
3856         csz = ddi_get8(sc->sc_cfg_handle,
3857             (uint8_t *)(sc->sc_cfg_base + PCI_CONF_CACHE_LINESZ));
3858         if (!csz)
3859                 csz = 16;
3860         sc->sc_cachelsz = csz << 2;
3861         sc->sc_dmabuf_size = roundup(IEEE80211_MAX_LEN, sc->sc_cachelsz);
3862         vendor_id = ddi_get16(sc->sc_cfg_handle,
3863             (uint16_t *)(sc->sc_cfg_base + PCI_CONF_VENID));
3864         device_id = ddi_get16(sc->sc_cfg_handle,
3865             (uint16_t *)(sc->sc_cfg_base + PCI_CONF_DEVID));
3866         MWL_DBG(MWL_DBG_ATTACH, "mwl: mwl_attach(): "
3867             "vendor 0x%x, device id 0x%x, cache size %d\n",
3868             vendor_id, device_id, csz);
3869 
3870         /*
3871          * Enable response to memory space accesses,
3872          * and enabe bus master.
3873          */
3874         command = PCI_COMM_MAE | PCI_COMM_ME;
3875         ddi_put16(sc->sc_cfg_handle,
3876             (uint16_t *)((uintptr_t)(sc->sc_cfg_base) + PCI_CONF_COMM),
3877             command);
3878         ddi_put8(sc->sc_cfg_handle,
3879             (uint8_t *)(sc->sc_cfg_base + PCI_CONF_LATENCY_TIMER), 0xa8);
3880         ddi_put8(sc->sc_cfg_handle,
3881             (uint8_t *)(sc->sc_cfg_base + PCI_CONF_ILINE), 0x10);
3882 
3883         /* BAR0 */
3884         err = ddi_regs_map_setup(devinfo, 1,
3885             &sc->sc_mem_base, 0, 0, &mwl_reg_accattr, &sc->sc_mem_handle);
3886         if (err != DDI_SUCCESS) {
3887                 MWL_DBG(MWL_DBG_ATTACH, "mwl: mwl_attach(): "
3888                     "i/o space failed");
3889                 goto attach_fail1;
3890         }
3891 
3892         /* BAR1 */
3893         err = ddi_regs_map_setup(devinfo, 2,
3894             &sc->sc_io_base, 0, 0, &mwl_reg_accattr, &sc->sc_io_handle);
3895         if (err != DDI_SUCCESS) {
3896                 MWL_DBG(MWL_DBG_ATTACH, "mwl: mwl_attach(): "
3897                     "memory space failed");
3898                 goto attach_fail2;
3899         }
3900 
3901         MWL_DBG(MWL_DBG_ATTACH, "mwl: mwl_attach(): "
3902             "PCI configuration is done successfully\n");
3903 
3904         /*
3905          * Alloc cmd DMA buffer for firmware download
3906          */
3907         err = mwl_alloc_cmdbuf(sc);
3908         if (err != 0) {
3909                 MWL_DBG(MWL_DBG_ATTACH, "mwl: mwl_attach(): "
3910                     "could not alloc cmd dma buffer\n");
3911                 goto attach_fail3;
3912         }
3913 
3914         sc->sc_imask = 0;
3915         sc->sc_hw_flags = 0;
3916         sc->sc_flags = 0;
3917 
3918         /*
3919          * Some cards have SDRAM.  When loading firmware we need
3920          * to reset the SDRAM controller prior to doing this.
3921          * When the SDRAMSIZE is non-zero we do that work in
3922          * mwl_hal_fwload.
3923          */
3924         switch (device_id) {
3925         case 0x2a02:            /* CB82 */
3926         case 0x2a03:            /* CB85 */
3927         case 0x2a08:            /* MC85_B1 */
3928         case 0x2a0b:            /* CB85AP */
3929         case 0x2a24:
3930                 sc->sc_SDRAMSIZE_Addr = 0x40fe70b7;  /* 8M SDRAM */
3931                 break;
3932         case 0x2a04:            /* MC85 */
3933                 sc->sc_SDRAMSIZE_Addr = 0x40fc70b7;  /* 16M SDRAM */
3934                 break;
3935         default:
3936                 break;
3937         }
3938 
3939         err = mwl_fwload(sc, NULL);
3940         if (err != 0) {
3941                 MWL_DBG(MWL_DBG_ATTACH, "mwl: mwl_attach(): "
3942                     "firmware download failed\n");
3943                 goto attach_fail4;
3944         }
3945 
3946         MWL_DBG(MWL_DBG_ATTACH, "mwl: mwl_attach(): "
3947             "firmware download successfully\n");
3948 
3949         err = mwl_gethwspecs(sc);
3950         if (err != 0) {
3951                 MWL_DBG(MWL_DBG_ATTACH, "mwl: mwl_attach(): "
3952                     "failed to get hw spec\n");
3953                 goto attach_fail4;
3954         }
3955 
3956         err = mwl_getchannels(sc);
3957         if (err != 0) {
3958                 MWL_DBG(MWL_DBG_ATTACH, "mwl: mwl_attach(): "
3959                     "failed to get channels\n");
3960                 goto attach_fail4;
3961         }
3962 
3963         /*
3964          * Alloc rx DMA buffer
3965          */
3966         err = mwl_alloc_rx_ring(sc, MWL_RX_RING_COUNT);
3967         if (err != 0) {
3968                 MWL_DBG(MWL_DBG_ATTACH, "mwl: mwl_attach(): "
3969                     "could not alloc cmd dma buffer\n");
3970                 goto attach_fail5;
3971         }
3972 
3973         /*
3974          * Alloc rx DMA buffer
3975          */
3976         for (qid = 0; qid < MWL_NUM_TX_QUEUES; qid++) {
3977                 err = mwl_alloc_tx_ring(sc,
3978                     &sc->sc_txring[qid], MWL_TX_RING_COUNT);
3979                 if (err != 0) {
3980                         MWL_DBG(MWL_DBG_ATTACH, "mwl: mwl_attach(): "
3981                             "could not alloc tx ring %d\n", qid);
3982                         goto attach_fail6;
3983                 }
3984         }
3985 
3986         err = mwl_setupdma(sc);
3987         if (err != 0) {
3988                 MWL_DBG(MWL_DBG_ATTACH, "mwl: mwl_attach(): "
3989                     "could not setup dma\n");
3990                 goto attach_fail6;
3991         }
3992 
3993         err = mwl_setup_txq(sc);
3994         if (err != 0) {
3995                 MWL_DBG(MWL_DBG_ATTACH, "mwl: mwl_attach(): "
3996                     "could not setup txq\n");
3997                 goto attach_fail6;
3998         }
3999 
4000         IEEE80211_ADDR_COPY(ic->ic_macaddr, sc->sc_hwspecs.macAddr);
4001         MWL_DBG(MWL_DBG_ATTACH, "mwl: mwl_attach(): "
4002             "mwl MAC:%2x:%2x:%2x:%2x:%2x:%2x\n",
4003             ic->ic_macaddr[0],
4004             ic->ic_macaddr[1],
4005             ic->ic_macaddr[2],
4006             ic->ic_macaddr[3],
4007             ic->ic_macaddr[4],
4008             ic->ic_macaddr[5]);
4009 
4010         err = mwl_hal_setmac_locked(sc, ic->ic_macaddr);
4011         if (err != 0) {                 /* NB: mwl_setupdma prints msg */
4012                 MWL_DBG(MWL_DBG_ATTACH, "mwl: attach(): "
4013                     "could not set mac\n");
4014                 goto attach_fail6;
4015         }
4016 
4017         mutex_init(&sc->sc_glock, NULL, MUTEX_DRIVER, NULL);
4018         mutex_init(&sc->sc_rxlock, NULL, MUTEX_DRIVER, NULL);
4019         mutex_init(&sc->sc_txlock, NULL, MUTEX_DRIVER, NULL);
4020 
4021 
4022         /* set supported rates */
4023         ic->ic_sup_rates[IEEE80211_MODE_11B] = mwl_rateset_11b;
4024         ic->ic_sup_rates[IEEE80211_MODE_11G] = mwl_rateset_11g;
4025 
4026         /* set supported .11b and .11g channels (1 through 14) */
4027         for (i = 1; i <= 14; i++) {
4028                 ic->ic_sup_channels[i].ich_freq =
4029                     ieee80211_ieee2mhz(i, IEEE80211_CHAN_2GHZ);
4030                 ic->ic_sup_channels[i].ich_flags =
4031                     IEEE80211_CHAN_DYN | IEEE80211_CHAN_2GHZ;
4032         }
4033 
4034         ic->ic_phytype = IEEE80211_T_OFDM; /* not only, but not used */
4035         ic->ic_opmode = IEEE80211_M_STA; /* default to BSS mode */
4036         ic->ic_state = IEEE80211_S_INIT;
4037 
4038         /* set device capabilities */
4039         ic->ic_caps =
4040             IEEE80211_C_TXPMGT |        /* tx power management */
4041             IEEE80211_C_SHPREAMBLE |    /* short preamble supported */
4042             IEEE80211_C_SHSLOT;         /* short slot time supported */
4043 
4044         /* WPA/WPA2 support */
4045         ic->ic_caps |= IEEE80211_C_WPA; /* Support WPA/WPA2 */
4046 
4047         /* Enable hardware encryption */
4048         ic->ic_caps |= IEEE80211_C_WEP | IEEE80211_C_TKIP | IEEE80211_C_AES_CCM;
4049 
4050         ic->ic_xmit = mwl_send;
4051 
4052         ieee80211_attach(ic);
4053 
4054         /* register WPA door */
4055         ieee80211_register_door(ic, ddi_driver_name(devinfo),
4056             ddi_get_instance(devinfo));
4057 
4058         /* override state transition machine */
4059         sc->sc_newstate = ic->ic_newstate;
4060         ic->ic_newstate = mwl_newstate;
4061         ic->ic_node_alloc = mwl_node_alloc;
4062         ic->ic_node_free = mwl_node_free;
4063         ic->ic_crypto.cs_max_keyix = 0;
4064         ic->ic_crypto.cs_key_alloc = mwl_key_alloc;
4065         ic->ic_crypto.cs_key_delete = mwl_key_delete;
4066         ic->ic_crypto.cs_key_set = mwl_key_set;
4067 
4068         ieee80211_media_init(ic);
4069 
4070         ic->ic_def_txkey = 0;
4071 
4072         err = mwl_hal_newstation(sc, ic->ic_macaddr, 0, 0, NULL, 0, 0);
4073         if (err != 0) {
4074                 MWL_DBG(MWL_DBG_ATTACH, "mwl: attach(): "
4075                     "could not create new station\n");
4076                 goto attach_fail7;
4077         }
4078 
4079         IEEE80211_ADDR_COPY(ic->ic_bss->in_bssid, ic->ic_macaddr);
4080         // mwl_setglobalkeys(ic);
4081 
4082         err = ddi_intr_get_supported_types(devinfo, &intr_type);
4083         if ((err != DDI_SUCCESS) || (!(intr_type & DDI_INTR_TYPE_FIXED))) {
4084                 MWL_DBG(MWL_DBG_ATTACH, "mwl: mwl_attach(): "
4085                     "fixed type interrupt is not supported\n");
4086                 goto attach_fail7;
4087         }
4088 
4089         err = ddi_intr_get_nintrs(devinfo, DDI_INTR_TYPE_FIXED, &intr_count);
4090         if ((err != DDI_SUCCESS) || (intr_count != 1)) {
4091                 MWL_DBG(MWL_DBG_ATTACH, "mwl: mwl_attach(): "
4092                     "no fixed interrupts\n");
4093                 goto attach_fail7;
4094         }
4095 
4096         sc->sc_intr_htable = kmem_zalloc(sizeof (ddi_intr_handle_t), KM_SLEEP);
4097 
4098         err = ddi_intr_alloc(devinfo, sc->sc_intr_htable,
4099             DDI_INTR_TYPE_FIXED, 0, intr_count, &intr_actual, 0);
4100         if ((err != DDI_SUCCESS) || (intr_actual != 1)) {
4101                 MWL_DBG(MWL_DBG_ATTACH, "mwl: mwl_attach(): "
4102                     "ddi_intr_alloc() failed 0x%x\n", err);
4103                 goto attach_fail8;
4104         }
4105 
4106         err = ddi_intr_get_pri(sc->sc_intr_htable[0], &sc->sc_intr_pri);
4107         if (err != DDI_SUCCESS) {
4108                 MWL_DBG(MWL_DBG_ATTACH, "mwl: mwl_attach(): "
4109                     "ddi_intr_get_pri() failed 0x%x\n", err);
4110                 goto attach_fail9;
4111         }
4112 
4113         err = ddi_intr_add_softint(devinfo, &sc->sc_softintr_hdl,
4114             DDI_INTR_SOFTPRI_MAX, mwl_softintr, (caddr_t)sc);
4115         if (err != DDI_SUCCESS) {
4116                 MWL_DBG(MWL_DBG_ATTACH, "mwl: mwl_attach(): "
4117                     "ddi_add_softintr() failed");
4118                 goto attach_fail9;
4119         }
4120 
4121         err = ddi_intr_add_handler(sc->sc_intr_htable[0], mwl_intr,
4122             (caddr_t)sc, NULL);
4123         if (err != DDI_SUCCESS) {
4124                 MWL_DBG(MWL_DBG_ATTACH, "mwl: mwl_attach(): "
4125                     "ddi_intr_addr_handle() failed\n");
4126                 goto attach_fail10;
4127         }
4128 
4129         err = ddi_intr_enable(sc->sc_intr_htable[0]);
4130         if (err != DDI_SUCCESS) {
4131                 MWL_DBG(MWL_DBG_ATTACH, "mwl: mwl_attach(): "
4132                     "ddi_intr_enable() failed\n");
4133                 goto attach_fail11;
4134         }
4135 
4136         /*
4137          * Provide initial settings for the WiFi plugin; whenever this
4138          * information changes, we need to call mac_plugindata_update()
4139          */
4140         wd.wd_opmode = ic->ic_opmode;
4141         wd.wd_secalloc = WIFI_SEC_NONE;
4142         IEEE80211_ADDR_COPY(wd.wd_bssid, ic->ic_bss->in_bssid);
4143 
4144         if ((macp = mac_alloc(MAC_VERSION)) == NULL) {
4145                 MWL_DBG(MWL_DBG_ATTACH, "mwl: mwl_attach(): "
4146                     "MAC version mismatch\n");
4147                 goto attach_fail12;
4148         }
4149 
4150         macp->m_type_ident   = MAC_PLUGIN_IDENT_WIFI;
4151         macp->m_driver               = sc;
4152         macp->m_dip          = devinfo;
4153         macp->m_src_addr     = ic->ic_macaddr;
4154         macp->m_callbacks    = &mwl_m_callbacks;
4155         macp->m_min_sdu              = 0;
4156         macp->m_max_sdu              = IEEE80211_MTU;
4157         macp->m_pdata                = &wd;
4158         macp->m_pdata_size   = sizeof (wd);
4159 
4160         err = mac_register(macp, &ic->ic_mach);
4161         mac_free(macp);
4162         if (err != 0) {
4163                 MWL_DBG(MWL_DBG_ATTACH, "mwl: mwl_attach(): "
4164                     "mac_register err %x\n", err);
4165                 goto attach_fail12;
4166         }
4167 
4168         /*
4169          * Create minor node of type DDI_NT_NET_WIFI
4170          */
4171         (void) snprintf(strbuf, sizeof (strbuf), "%s%d",
4172             "mwl", instance);
4173         err = ddi_create_minor_node(devinfo, strbuf, S_IFCHR,
4174             instance + 1, DDI_NT_NET_WIFI, 0);
4175         if (err != 0) {
4176                 MWL_DBG(MWL_DBG_ATTACH, "mwl: mwl_attach(): "
4177                     "create minor node error\n");
4178                 goto attach_fail13;
4179         }
4180 
4181         /*
4182          * Notify link is down now
4183          */
4184         mac_link_update(ic->ic_mach, LINK_STATE_DOWN);
4185 
4186         MWL_DBG(MWL_DBG_ATTACH, "mwl: mwl_attach(): "
4187             "driver attach successfully\n");
4188         return (DDI_SUCCESS);
4189 
4190 attach_fail13:
4191         (void) mac_disable(ic->ic_mach);
4192         (void) mac_unregister(ic->ic_mach);
4193 attach_fail12:
4194         (void) ddi_intr_disable(sc->sc_intr_htable[0]);
4195 attach_fail11:
4196         (void) ddi_intr_remove_handler(sc->sc_intr_htable[0]);
4197 attach_fail10:
4198         (void) ddi_intr_remove_softint(sc->sc_softintr_hdl);
4199         sc->sc_softintr_hdl = NULL;
4200 attach_fail9:
4201         (void) ddi_intr_free(sc->sc_intr_htable[0]);
4202 attach_fail8:
4203         kmem_free(sc->sc_intr_htable, sizeof (ddi_intr_handle_t));
4204 attach_fail7:
4205         mutex_destroy(&sc->sc_txlock);
4206         mutex_destroy(&sc->sc_rxlock);
4207         mutex_destroy(&sc->sc_glock);
4208 attach_fail6:
4209         while (--qid >= 0)
4210                 mwl_free_tx_ring(sc, &sc->sc_txring[qid]);
4211 attach_fail5:
4212         mwl_free_rx_ring(sc);
4213 attach_fail4:
4214         mwl_free_cmdbuf(sc);
4215 attach_fail3:
4216         ddi_regs_map_free(&sc->sc_mem_handle);
4217 attach_fail2:
4218         ddi_regs_map_free(&sc->sc_io_handle);
4219 attach_fail1:
4220         ddi_regs_map_free(&sc->sc_cfg_handle);
4221 attach_fail0:
4222         ddi_soft_state_free(mwl_soft_state_p, ddi_get_instance(devinfo));
4223         return (DDI_FAILURE);
4224 }
4225 
4226 static int32_t
4227 mwl_detach(dev_info_t *devinfo, ddi_detach_cmd_t cmd)
4228 {
4229         struct mwl_softc *sc;
4230         int qid;
4231 
4232         sc = ddi_get_soft_state(mwl_soft_state_p, ddi_get_instance(devinfo));
4233         ASSERT(sc != NULL);
4234 
4235         switch (cmd) {
4236         case DDI_DETACH:
4237                 break;
4238         case DDI_SUSPEND:
4239                 if (MWL_IS_RUNNING(sc))
4240                         mwl_stop(sc);
4241                 for (qid = 0; qid < MWL_NUM_TX_QUEUES; qid++)
4242                         mwl_free_tx_ring(sc, &sc->sc_txring[qid]);
4243                 mwl_free_rx_ring(sc);
4244                 MWL_GLOCK(sc);
4245                 sc->sc_flags |= MWL_F_SUSPEND;
4246                 MWL_GUNLOCK(sc);
4247                 MWL_DBG(MWL_DBG_SR, "mwl: mwl_detach(): "
4248                     "suspend now\n");
4249                 return (DDI_SUCCESS);
4250         default:
4251                 return (DDI_FAILURE);
4252         }
4253 
4254         if (mac_disable(sc->sc_ic.ic_mach) != 0)
4255                 return (DDI_FAILURE);
4256 
4257         /*
4258          * Unregister from the MAC layer subsystem
4259          */
4260         (void) mac_unregister(sc->sc_ic.ic_mach);
4261 
4262         (void) ddi_intr_remove_softint(sc->sc_softintr_hdl);
4263         sc->sc_softintr_hdl = NULL;
4264         (void) ddi_intr_disable(sc->sc_intr_htable[0]);
4265         (void) ddi_intr_remove_handler(sc->sc_intr_htable[0]);
4266         (void) ddi_intr_free(sc->sc_intr_htable[0]);
4267         kmem_free(sc->sc_intr_htable, sizeof (ddi_intr_handle_t));
4268 
4269         /*
4270          * detach ieee80211 layer
4271          */
4272         ieee80211_detach(&sc->sc_ic);
4273 
4274 
4275         for (qid = 0; qid < MWL_NUM_TX_QUEUES; qid++)
4276                 mwl_free_tx_ring(sc, &sc->sc_txring[qid]);
4277         mwl_free_rx_ring(sc);
4278         mwl_free_cmdbuf(sc);
4279 
4280         mutex_destroy(&sc->sc_txlock);
4281         mutex_destroy(&sc->sc_rxlock);
4282         mutex_destroy(&sc->sc_glock);
4283 
4284         ddi_regs_map_free(&sc->sc_mem_handle);
4285         ddi_regs_map_free(&sc->sc_io_handle);
4286         ddi_regs_map_free(&sc->sc_cfg_handle);
4287 
4288         ddi_remove_minor_node(devinfo, NULL);
4289         ddi_soft_state_free(mwl_soft_state_p, ddi_get_instance(devinfo));
4290 
4291         MWL_DBG(MWL_DBG_ATTACH, "mwl: mwl_detach(): "
4292             "detach successfully\n");
4293         return (DDI_SUCCESS);
4294 }
4295 
4296 /*
4297  * quiesce(9E) entry point.
4298  *
4299  * This function is called when the system is single-threaded at high
4300  * PIL with preemption disabled. Therefore, this function must not be
4301  * blocked.
4302  *
4303  * This function returns DDI_SUCCESS on success, or DDI_FAILURE on failure.
4304  * DDI_FAILURE indicates an error condition and should almost never happen.
4305  */
4306 int
4307 mwl_quiesce(dev_info_t *dip)
4308 {
4309         struct mwl_softc *sc;
4310 
4311         sc = ddi_get_soft_state(mwl_soft_state_p, ddi_get_instance(dip));
4312         if (sc == NULL)
4313                 return (DDI_FAILURE);
4314 
4315 #ifdef DEBUG
4316         mwl_dbg_flags = 0;
4317 #endif
4318 
4319         /*
4320          * No more blocking is allowed while we are in quiesce(9E) entry point
4321          */
4322         sc->sc_flags |= MWL_F_QUIESCE;
4323 
4324         /*
4325          * Disable all interrupts
4326          */
4327         mwl_stop(sc);
4328         return (DDI_SUCCESS);
4329 }
4330 
4331 int
4332 _init(void)
4333 {
4334         int status;
4335 
4336         status = ddi_soft_state_init(&mwl_soft_state_p,
4337             sizeof (struct mwl_softc), 1);
4338         if (status != 0)
4339                 return (status);
4340 
4341         mac_init_ops(&mwl_dev_ops, "mwl");
4342         status = mod_install(&modlinkage);
4343         if (status != 0) {
4344                 mac_fini_ops(&mwl_dev_ops);
4345                 ddi_soft_state_fini(&mwl_soft_state_p);
4346         }
4347         return (status);
4348 }
4349 
4350 int
4351 _info(struct modinfo *modinfop)
4352 {
4353         return (mod_info(&modlinkage, modinfop));
4354 }
4355 
4356 int
4357 _fini(void)
4358 {
4359         int status;
4360 
4361         status = mod_remove(&modlinkage);
4362         if (status == 0) {
4363                 mac_fini_ops(&mwl_dev_ops);
4364                 ddi_soft_state_fini(&mwl_soft_state_p);
4365         }
4366         return (status);
4367 }