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