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