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