1 /*- 2 * Copyright (c) 2007-2009 Sam Leffler, Errno Consulting 3 * Copyright (c) 2007-2009 Marvell Semiconductor, Inc. 4 * All rights reserved. 5 * 6 * Redistribution and use in source and binary forms, with or without 7 * modification, are permitted provided that the following conditions 8 * are met: 9 * 1. Redistributions of source code must retain the above copyright 10 * notice, this list of conditions and the following disclaimer, 11 * without modification. 12 * 2. Redistributions in binary form must reproduce at minimum a disclaimer 13 * similar to the "NO WARRANTY" disclaimer below ("Disclaimer") and any 14 * redistribution must be conditioned upon including a substantially 15 * similar Disclaimer requirement for further binary redistribution. 16 * 17 * NO WARRANTY 18 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 19 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 20 * LIMITED TO, THE IMPLIED WARRANTIES OF NONINFRINGEMENT, MERCHANTIBILITY 21 * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL 22 * THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, 23 * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 24 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 25 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER 26 * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 27 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF 28 * THE POSSIBILITY OF SUCH DAMAGES. 29 * 30 * $FreeBSD$ 31 */ 32 33 #include <sys/param.h> 34 #include <sys/systm.h> 35 #include <sys/sysctl.h> 36 #include <sys/malloc.h> 37 #include <sys/lock.h> 38 #include <sys/mutex.h> 39 #include <sys/kernel.h> 40 #include <sys/errno.h> 41 #include <sys/bus.h> 42 #include <sys/endian.h> 43 44 #include <sys/linker.h> 45 #include <sys/firmware.h> 46 47 #include <machine/bus.h> 48 49 #include <dev/mwl/mwlhal.h> 50 #include <dev/mwl/mwlreg.h> 51 52 #include <sys/socket.h> 53 #include <sys/sockio.h> 54 #include <net/if.h> 55 #include <dev/mwl/mwldiag.h> 56 57 #define MWLHAL_DEBUG /* debug msgs */ 58 59 typedef enum { 60 WL_ANTENNAMODE_RX = 0xffff, 61 WL_ANTENNAMODE_TX = 2, 62 } wlantennamode_e; 63 64 typedef enum { 65 WL_TX_POWERLEVEL_LOW = 5, 66 WL_TX_POWERLEVEL_MEDIUM = 10, 67 WL_TX_POWERLEVEL_HIGH = 15, 68 } wltxpowerlevel_e; 69 70 #define MWL_CMDBUF_SIZE 0x4000 /* size of f/w command buffer */ 71 #define MWL_BASTREAMS_MAX 7 /* max BA streams (NB: fw >3.3.5.9) */ 72 #define MWL_BAQID_MAX 8 /* max BA Q id's (NB: fw >3.3.5.9) */ 73 #define MWL_MBSS_AP_MAX 8 /* max ap vap's */ 74 #define MWL_MBSS_STA_MAX 24 /* max station/client vap's */ 75 #define MWL_MBSS_MAX (MWL_MBSS_AP_MAX+MWL_MBSS_STA_MAX) 76 77 /* 78 * BA stream -> queue ID mapping 79 * 80 * The first 2 streams map to h/w; the remaining streams are 81 * implemented in firmware. 82 */ 83 static const int ba2qid[MWL_BASTREAMS_MAX] = { 84 5, 6 /* h/w supported */ 85 #if MWL_BASTREAMS_MAX == 7 86 , 7, 0, 1, 2, 3 /* f/w supported */ 87 #endif 88 }; 89 static int qid2ba[MWL_BAQID_MAX]; 90 91 #define IEEE80211_ADDR_LEN 6 /* XXX */ 92 #define IEEE80211_ADDR_COPY(_dst, _src) \ 93 memcpy(_dst, _src, IEEE80211_ADDR_LEN) 94 #define IEEE80211_ADDR_EQ(_dst, _src) \ 95 (memcmp(_dst, _src, IEEE80211_ADDR_LEN) == 0) 96 97 #define _CMD_SETUP(pCmd, type, cmd) do { \ 98 pCmd = (type *)&mh->mh_cmdbuf[0]; \ 99 memset(pCmd, 0, sizeof(type)); \ 100 pCmd->CmdHdr.Cmd = htole16(cmd); \ 101 pCmd->CmdHdr.Length = htole16(sizeof(type)); \ 102 } while (0) 103 104 #define _VCMD_SETUP(vap, pCmd, type, cmd) do { \ 105 _CMD_SETUP(pCmd, type, cmd); \ 106 pCmd->CmdHdr.MacId = vap->macid; \ 107 } while (0) 108 109 #define PWTAGETRATETABLE20M 14*4 110 #define PWTAGETRATETABLE40M 9*4 111 #define PWTAGETRATETABLE20M_5G 35*4 112 #define PWTAGETRATETABLE40M_5G 16*4 113 114 struct mwl_hal_bastream { 115 MWL_HAL_BASTREAM public; /* public state */ 116 uint8_t stream; /* stream # */ 117 uint8_t setup; /* f/w cmd sent */ 118 uint8_t ba_policy; /* direct/delayed BA policy */ 119 uint8_t tid; 120 uint8_t paraminfo; 121 uint8_t macaddr[IEEE80211_ADDR_LEN]; 122 }; 123 124 struct mwl_hal_priv; 125 126 struct mwl_hal_vap { 127 struct mwl_hal_priv *mh; /* back pointer */ 128 uint16_t bss_type; /* f/w type */ 129 uint8_t vap_type; /* MWL_HAL_BSSTYPE */ 130 uint8_t macid; /* for passing to f/w */ 131 uint8_t flags; 132 #define MVF_RUNNING 0x01 /* BSS_START issued */ 133 #define MVF_STATION 0x02 /* sta db entry created */ 134 uint8_t mac[IEEE80211_ADDR_LEN];/* mac address */ 135 }; 136 #define MWLVAP(_vap) ((_vap)->mh) 137 138 /* 139 * Per-device state. We allocate a single cmd buffer for 140 * submitting operations to the firmware. Access to this 141 * buffer (and the f/w) are single-threaded. At present 142 * we spin waiting for cmds to complete which is bad. Not 143 * sure if it's possible to submit multiple requests or 144 * control when we get cmd done interrupts. There's no 145 * documentation and no example code to indicate what can 146 * or cannot be done so all we can do right now is follow the 147 * linux driver logic. This falls apart when the f/w fails; 148 * the system comes to a crawl as we spin waiting for operations 149 * to finish. 150 */ 151 struct mwl_hal_priv { 152 struct mwl_hal public; /* public area */ 153 device_t mh_dev; 154 char mh_mtxname[12]; 155 struct mtx mh_mtx; 156 bus_dma_tag_t mh_dmat; /* bus DMA tag for cmd buffer */ 157 bus_dma_segment_t mh_seg; /* segment for cmd buffer */ 158 bus_dmamap_t mh_dmamap; /* DMA map for cmd buffer */ 159 uint16_t *mh_cmdbuf; /* f/w cmd buffer */ 160 bus_addr_t mh_cmdaddr; /* physaddr of cmd buffer */ 161 int mh_flags; 162 #define MHF_CALDATA 0x0001 /* cal data retrieved */ 163 #define MHF_FWHANG 0x0002 /* fw appears hung */ 164 #define MHF_MBSS 0x0004 /* mbss enabled */ 165 struct mwl_hal_vap mh_vaps[MWL_MBSS_MAX+1]; 166 int mh_bastreams; /* bit mask of available BA streams */ 167 int mh_regioncode; /* XXX last region code sent to fw */ 168 struct mwl_hal_bastream mh_streams[MWL_BASTREAMS_MAX]; 169 int mh_debug; 170 MWL_HAL_CHANNELINFO mh_20M; 171 MWL_HAL_CHANNELINFO mh_40M; 172 MWL_HAL_CHANNELINFO mh_20M_5G; 173 MWL_HAL_CHANNELINFO mh_40M_5G; 174 int mh_SDRAMSIZE_Addr; 175 uint32_t mh_RTSSuccesses;/* cumulative stats for read-on-clear */ 176 uint32_t mh_RTSFailures; 177 uint32_t mh_RxDuplicateFrames; 178 uint32_t mh_FCSErrorCount; 179 MWL_DIAG_REVS mh_revs; 180 }; 181 #define MWLPRIV(_mh) ((struct mwl_hal_priv *)(_mh)) 182 183 static int mwl_hal_setmac_locked(struct mwl_hal_vap *, 184 const uint8_t addr[IEEE80211_ADDR_LEN]); 185 static int mwlExecuteCmd(struct mwl_hal_priv *, unsigned short cmd); 186 static int mwlGetPwrCalTable(struct mwl_hal_priv *); 187 #ifdef MWLHAL_DEBUG 188 static const char *mwlcmdname(int cmd); 189 static void dumpresult(struct mwl_hal_priv *, int showresult); 190 #endif /* MWLHAL_DEBUG */ 191 192 SYSCTL_DECL(_hw_mwl); 193 static SYSCTL_NODE(_hw_mwl, OID_AUTO, hal, CTLFLAG_RD, 0, 194 "Marvell HAL parameters"); 195 196 static __inline void 197 MWL_HAL_LOCK(struct mwl_hal_priv *mh) 198 { 199 mtx_lock(&mh->mh_mtx); 200 } 201 202 static __inline void 203 MWL_HAL_LOCK_ASSERT(struct mwl_hal_priv *mh) 204 { 205 mtx_assert(&mh->mh_mtx, MA_OWNED); 206 } 207 208 static __inline void 209 MWL_HAL_UNLOCK(struct mwl_hal_priv *mh) 210 { 211 mtx_unlock(&mh->mh_mtx); 212 } 213 214 static __inline uint32_t 215 RD4(struct mwl_hal_priv *mh, bus_size_t off) 216 { 217 return bus_space_read_4(mh->public.mh_iot, mh->public.mh_ioh, off); 218 } 219 220 static __inline void 221 WR4(struct mwl_hal_priv *mh, bus_size_t off, uint32_t val) 222 { 223 bus_space_write_4(mh->public.mh_iot, mh->public.mh_ioh, off, val); 224 } 225 226 static void 227 mwl_hal_load_cb(void *arg, bus_dma_segment_t *segs, int nsegs, int error) 228 { 229 bus_addr_t *paddr = (bus_addr_t*) arg; 230 KASSERT(error == 0, ("error %u on bus_dma callback", error)); 231 *paddr = segs->ds_addr; 232 } 233 234 /* 235 * Setup for communication with the device. We allocate 236 * a command buffer and map it for bus dma use. The pci 237 * device id is used to identify whether the device has 238 * SRAM on it (in which case f/w download must include a 239 * memory controller reset). All bus i/o operations happen 240 * in BAR 1; the driver passes in the tag and handle we need. 241 */ 242 struct mwl_hal * 243 mwl_hal_attach(device_t dev, uint16_t devid, 244 bus_space_handle_t ioh, bus_space_tag_t iot, bus_dma_tag_t tag) 245 { 246 struct mwl_hal_priv *mh; 247 struct mwl_hal_vap *hvap; 248 int error, i; 249 250 mh = malloc(sizeof(struct mwl_hal_priv), M_DEVBUF, M_NOWAIT | M_ZERO); 251 if (mh == NULL) 252 return NULL; 253 mh->mh_dev = dev; 254 mh->public.mh_ioh = ioh; 255 mh->public.mh_iot = iot; 256 for (i = 0; i < MWL_BASTREAMS_MAX; i++) { 257 mh->mh_streams[i].public.txq = ba2qid[i]; 258 mh->mh_streams[i].stream = i; 259 /* construct back-mapping while we're at it */ 260 if (mh->mh_streams[i].public.txq < MWL_BAQID_MAX) 261 qid2ba[mh->mh_streams[i].public.txq] = i; 262 else 263 device_printf(dev, "unexpected BA tx qid %d for " 264 "stream %d\n", mh->mh_streams[i].public.txq, i); 265 } 266 /* setup constant portion of vap state */ 267 /* XXX should get max ap/client vap's from f/w */ 268 i = 0; 269 hvap = &mh->mh_vaps[i]; 270 hvap->vap_type = MWL_HAL_AP; 271 hvap->bss_type = htole16(WL_MAC_TYPE_PRIMARY_AP); 272 hvap->macid = 0; 273 for (i++; i < MWL_MBSS_AP_MAX; i++) { 274 hvap = &mh->mh_vaps[i]; 275 hvap->vap_type = MWL_HAL_AP; 276 hvap->bss_type = htole16(WL_MAC_TYPE_SECONDARY_AP); 277 hvap->macid = i; 278 } 279 hvap = &mh->mh_vaps[i]; 280 hvap->vap_type = MWL_HAL_STA; 281 hvap->bss_type = htole16(WL_MAC_TYPE_PRIMARY_CLIENT); 282 hvap->macid = i; 283 for (i++; i < MWL_MBSS_MAX; i++) { 284 hvap = &mh->mh_vaps[i]; 285 hvap->vap_type = MWL_HAL_STA; 286 hvap->bss_type = htole16(WL_MAC_TYPE_SECONDARY_CLIENT); 287 hvap->macid = i; 288 } 289 mh->mh_revs.mh_devid = devid; 290 snprintf(mh->mh_mtxname, sizeof(mh->mh_mtxname), 291 "%s_hal", device_get_nameunit(dev)); 292 mtx_init(&mh->mh_mtx, mh->mh_mtxname, NULL, MTX_DEF); 293 294 /* 295 * Allocate the command buffer and map into the address 296 * space of the h/w. We request "coherent" memory which 297 * will be uncached on some architectures. 298 */ 299 error = bus_dma_tag_create(tag, /* parent */ 300 PAGE_SIZE, 0, /* alignment, bounds */ 301 BUS_SPACE_MAXADDR_32BIT, /* lowaddr */ 302 BUS_SPACE_MAXADDR, /* highaddr */ 303 NULL, NULL, /* filter, filterarg */ 304 MWL_CMDBUF_SIZE, /* maxsize */ 305 1, /* nsegments */ 306 MWL_CMDBUF_SIZE, /* maxsegsize */ 307 BUS_DMA_ALLOCNOW, /* flags */ 308 NULL, /* lockfunc */ 309 NULL, /* lockarg */ 310 &mh->mh_dmat); 311 if (error != 0) { 312 device_printf(dev, "unable to allocate memory for cmd buffer, " 313 "error %u\n", error); 314 goto fail0; 315 } 316 317 /* allocate descriptors */ 318 error = bus_dmamap_create(mh->mh_dmat, BUS_DMA_NOWAIT, &mh->mh_dmamap); 319 if (error != 0) { 320 device_printf(dev, "unable to create dmamap for cmd buffers, " 321 "error %u\n", error); 322 goto fail0; 323 } 324 325 error = bus_dmamem_alloc(mh->mh_dmat, (void**) &mh->mh_cmdbuf, 326 BUS_DMA_NOWAIT | BUS_DMA_COHERENT, 327 &mh->mh_dmamap); 328 if (error != 0) { 329 device_printf(dev, "unable to allocate memory for cmd buffer, " 330 "error %u\n", error); 331 goto fail1; 332 } 333 334 error = bus_dmamap_load(mh->mh_dmat, mh->mh_dmamap, 335 mh->mh_cmdbuf, MWL_CMDBUF_SIZE, 336 mwl_hal_load_cb, &mh->mh_cmdaddr, 337 BUS_DMA_NOWAIT); 338 if (error != 0) { 339 device_printf(dev, "unable to load cmd buffer, error %u\n", 340 error); 341 goto fail2; 342 } 343 344 /* 345 * Some cards have SDRAM. When loading firmware we need 346 * to reset the SDRAM controller prior to doing this. 347 * When the SDRAMSIZE is non-zero we do that work in 348 * mwl_hal_fwload. 349 */ 350 switch (devid) { 351 case 0x2a02: /* CB82 */ 352 case 0x2a03: /* CB85 */ 353 case 0x2a08: /* MC85_B1 */ 354 case 0x2a0b: /* CB85AP */ 355 case 0x2a24: 356 mh->mh_SDRAMSIZE_Addr = 0x40fe70b7; /* 8M SDRAM */ 357 break; 358 case 0x2a04: /* MC85 */ 359 mh->mh_SDRAMSIZE_Addr = 0x40fc70b7; /* 16M SDRAM */ 360 break; 361 default: 362 break; 363 } 364 return &mh->public; 365 fail2: 366 bus_dmamem_free(mh->mh_dmat, mh->mh_cmdbuf, mh->mh_dmamap); 367 fail1: 368 bus_dmamap_destroy(mh->mh_dmat, mh->mh_dmamap); 369 fail0: 370 bus_dma_tag_destroy(mh->mh_dmat); 371 mtx_destroy(&mh->mh_mtx); 372 free(mh, M_DEVBUF); 373 return NULL; 374 } 375 376 void 377 mwl_hal_detach(struct mwl_hal *mh0) 378 { 379 struct mwl_hal_priv *mh = MWLPRIV(mh0); 380 381 bus_dmamem_free(mh->mh_dmat, mh->mh_cmdbuf, mh->mh_dmamap); 382 bus_dmamap_destroy(mh->mh_dmat, mh->mh_dmamap); 383 bus_dma_tag_destroy(mh->mh_dmat); 384 mtx_destroy(&mh->mh_mtx); 385 free(mh, M_DEVBUF); 386 } 387 388 /* 389 * Reset internal state after a firmware download. 390 */ 391 static int 392 mwlResetHalState(struct mwl_hal_priv *mh) 393 { 394 int i; 395 396 /* XXX get from f/w */ 397 mh->mh_bastreams = (1<<MWL_BASTREAMS_MAX)-1; 398 for (i = 0; i < MWL_MBSS_MAX; i++) 399 mh->mh_vaps[i].mh = NULL; 400 /* 401 * Clear cumulative stats. 402 */ 403 mh->mh_RTSSuccesses = 0; 404 mh->mh_RTSFailures = 0; 405 mh->mh_RxDuplicateFrames = 0; 406 mh->mh_FCSErrorCount = 0; 407 /* 408 * Fetch cal data for later use. 409 * XXX may want to fetch other stuff too. 410 */ 411 /* XXX check return */ 412 if ((mh->mh_flags & MHF_CALDATA) == 0) 413 mwlGetPwrCalTable(mh); 414 return 0; 415 } 416 417 struct mwl_hal_vap * 418 mwl_hal_newvap(struct mwl_hal *mh0, MWL_HAL_BSSTYPE type, 419 const uint8_t mac[IEEE80211_ADDR_LEN]) 420 { 421 struct mwl_hal_priv *mh = MWLPRIV(mh0); 422 struct mwl_hal_vap *vap; 423 int i; 424 425 MWL_HAL_LOCK(mh); 426 /* NB: could optimize but not worth it w/ max 32 bss */ 427 for (i = 0; i < MWL_MBSS_MAX; i++) { 428 vap = &mh->mh_vaps[i]; 429 if (vap->vap_type == type && vap->mh == NULL) { 430 vap->mh = mh; 431 mwl_hal_setmac_locked(vap, mac); 432 break; 433 } 434 } 435 MWL_HAL_UNLOCK(mh); 436 return (i < MWL_MBSS_MAX) ? vap : NULL; 437 } 438 439 void 440 mwl_hal_delvap(struct mwl_hal_vap *vap) 441 { 442 /* NB: locking not needed for single write */ 443 vap->mh = NULL; 444 } 445 446 /* 447 * Manipulate the debug mask. Note debug 448 * msgs are only provided when this code is 449 * compiled with MWLHAL_DEBUG defined. 450 */ 451 452 void 453 mwl_hal_setdebug(struct mwl_hal *mh, int debug) 454 { 455 MWLPRIV(mh)->mh_debug = debug; 456 } 457 458 int 459 mwl_hal_getdebug(struct mwl_hal *mh) 460 { 461 return MWLPRIV(mh)->mh_debug; 462 } 463 464 void 465 mwl_hal_setbastreams(struct mwl_hal *mh, int mask) 466 { 467 MWLPRIV(mh)->mh_bastreams = mask & ((1<<MWL_BASTREAMS_MAX)-1); 468 } 469 470 int 471 mwl_hal_getbastreams(struct mwl_hal *mh) 472 { 473 return MWLPRIV(mh)->mh_bastreams; 474 } 475 476 int 477 mwl_hal_ismbsscapable(struct mwl_hal *mh) 478 { 479 return (MWLPRIV(mh)->mh_flags & MHF_MBSS) != 0; 480 } 481 482 #if 0 483 /* XXX inlined */ 484 /* 485 * Return the current ISR setting and clear the cause. 486 * XXX maybe make inline 487 */ 488 void 489 mwl_hal_getisr(struct mwl_hal *mh0, uint32_t *status) 490 { 491 struct mwl_hal_priv *mh = MWLPRIV(mh0); 492 uint32_t cause; 493 494 cause = RD4(mh, MACREG_REG_A2H_INTERRUPT_CAUSE); 495 if (cause == 0xffffffff) { /* card removed */ 496 device_printf(mh->mh_dev, "%s: cause 0x%x\n", __func__, cause); 497 cause = 0; 498 } else if (cause != 0) { 499 /* clear cause bits */ 500 WR4(mh, MACREG_REG_A2H_INTERRUPT_CAUSE, 501 cause &~ mh->public.mh_imask); 502 RD4(mh, MACREG_REG_INT_CODE); /* XXX flush write? */ 503 } 504 *status = cause; 505 } 506 #endif 507 508 /* 509 * Set the interrupt mask. 510 */ 511 void 512 mwl_hal_intrset(struct mwl_hal *mh0, uint32_t mask) 513 { 514 struct mwl_hal_priv *mh = MWLPRIV(mh0); 515 516 WR4(mh, MACREG_REG_A2H_INTERRUPT_MASK, 0); 517 RD4(mh, MACREG_REG_INT_CODE); 518 519 mh->public.mh_imask = mask; 520 WR4(mh, MACREG_REG_A2H_INTERRUPT_MASK, mask); 521 RD4(mh, MACREG_REG_INT_CODE); 522 } 523 524 #if 0 525 /* XXX inlined */ 526 /* 527 * Kick the firmware to tell it there are new tx descriptors 528 * for processing. The driver says what h/w q has work in 529 * case the f/w ever gets smarter. 530 */ 531 void 532 mwl_hal_txstart(struct mwl_hal *mh0, int qnum) 533 { 534 struct mwl_hal_priv *mh = MWLPRIV(mh0); 535 uint32_t dummy; 536 537 WR4(mh, MACREG_REG_H2A_INTERRUPT_EVENTS, MACREG_H2ARIC_BIT_PPA_READY); 538 dummy = RD4(mh, MACREG_REG_INT_CODE); 539 } 540 #endif 541 542 /* 543 * Callback from the driver on a cmd done interrupt. 544 * Nothing to do right now as we spin waiting for 545 * cmd completion. 546 */ 547 void 548 mwl_hal_cmddone(struct mwl_hal *mh0) 549 { 550 #if 0 551 struct mwl_hal_priv *mh = MWLPRIV(mh0); 552 553 if (mh->mh_debug & MWL_HAL_DEBUG_CMDDONE) { 554 device_printf(mh->mh_dev, "cmd done interrupt:\n"); 555 dumpresult(mh, 1); 556 } 557 #endif 558 } 559 560 /* 561 * Return "hw specs". Note this must be the first 562 * cmd MUST be done after a firmware download or the 563 * f/w will lockup. 564 * XXX move into the hal so driver doesn't need to be responsible 565 */ 566 int 567 mwl_hal_gethwspecs(struct mwl_hal *mh0, struct mwl_hal_hwspec *hw) 568 { 569 struct mwl_hal_priv *mh = MWLPRIV(mh0); 570 HostCmd_DS_GET_HW_SPEC *pCmd; 571 int retval, minrev; 572 573 MWL_HAL_LOCK(mh); 574 _CMD_SETUP(pCmd, HostCmd_DS_GET_HW_SPEC, HostCmd_CMD_GET_HW_SPEC); 575 memset(&pCmd->PermanentAddr[0], 0xff, IEEE80211_ADDR_LEN); 576 pCmd->ulFwAwakeCookie = htole32((unsigned int)mh->mh_cmdaddr+2048); 577 578 retval = mwlExecuteCmd(mh, HostCmd_CMD_GET_HW_SPEC); 579 if (retval == 0) { 580 IEEE80211_ADDR_COPY(hw->macAddr, pCmd->PermanentAddr); 581 hw->wcbBase[0] = le32toh(pCmd->WcbBase0) & 0x0000ffff; 582 hw->wcbBase[1] = le32toh(pCmd->WcbBase1[0]) & 0x0000ffff; 583 hw->wcbBase[2] = le32toh(pCmd->WcbBase1[1]) & 0x0000ffff; 584 hw->wcbBase[3] = le32toh(pCmd->WcbBase1[2]) & 0x0000ffff; 585 hw->rxDescRead = le32toh(pCmd->RxPdRdPtr)& 0x0000ffff; 586 hw->rxDescWrite = le32toh(pCmd->RxPdWrPtr)& 0x0000ffff; 587 hw->regionCode = le16toh(pCmd->RegionCode) & 0x00ff; 588 hw->fwReleaseNumber = le32toh(pCmd->FWReleaseNumber); 589 hw->maxNumWCB = le16toh(pCmd->NumOfWCB); 590 hw->maxNumMCAddr = le16toh(pCmd->NumOfMCastAddr); 591 hw->numAntennas = le16toh(pCmd->NumberOfAntenna); 592 hw->hwVersion = pCmd->Version; 593 hw->hostInterface = pCmd->HostIf; 594 595 mh->mh_revs.mh_macRev = hw->hwVersion; /* XXX */ 596 mh->mh_revs.mh_phyRev = hw->hostInterface; /* XXX */ 597 598 minrev = ((hw->fwReleaseNumber) >> 16) & 0xff; 599 if (minrev >= 4) { 600 /* starting with 3.4.x.x s/w BA streams supported */ 601 mh->mh_bastreams &= (1<<MWL_BASTREAMS_MAX)-1; 602 } else 603 mh->mh_bastreams &= (1<<2)-1; 604 } 605 MWL_HAL_UNLOCK(mh); 606 return retval; 607 } 608 609 /* 610 * Inform the f/w about location of the tx/rx dma data structures 611 * and related state. This cmd must be done immediately after a 612 * mwl_hal_gethwspecs call or the f/w will lockup. 613 */ 614 int 615 mwl_hal_sethwdma(struct mwl_hal *mh0, const struct mwl_hal_txrxdma *dma) 616 { 617 struct mwl_hal_priv *mh = MWLPRIV(mh0); 618 HostCmd_DS_SET_HW_SPEC *pCmd; 619 int retval; 620 621 MWL_HAL_LOCK(mh); 622 _CMD_SETUP(pCmd, HostCmd_DS_SET_HW_SPEC, HostCmd_CMD_SET_HW_SPEC); 623 pCmd->WcbBase[0] = htole32(dma->wcbBase[0]); 624 pCmd->WcbBase[1] = htole32(dma->wcbBase[1]); 625 pCmd->WcbBase[2] = htole32(dma->wcbBase[2]); 626 pCmd->WcbBase[3] = htole32(dma->wcbBase[3]); 627 pCmd->TxWcbNumPerQueue = htole32(dma->maxNumTxWcb); 628 pCmd->NumTxQueues = htole32(dma->maxNumWCB); 629 pCmd->TotalRxWcb = htole32(1); /* XXX */ 630 pCmd->RxPdWrPtr = htole32(dma->rxDescRead); 631 pCmd->Flags = htole32(SET_HW_SPEC_HOSTFORM_BEACON 632 #ifdef MWL_HOST_PS_SUPPORT 633 | SET_HW_SPEC_HOST_POWERSAVE 634 #endif 635 | SET_HW_SPEC_HOSTFORM_PROBERESP); 636 /* disable multi-bss operation for A1-A4 parts */ 637 if (mh->mh_revs.mh_macRev < 5) 638 pCmd->Flags |= htole32(SET_HW_SPEC_DISABLEMBSS); 639 640 retval = mwlExecuteCmd(mh, HostCmd_CMD_SET_HW_SPEC); 641 if (retval == 0) { 642 if (pCmd->Flags & htole32(SET_HW_SPEC_DISABLEMBSS)) 643 mh->mh_flags &= ~MHF_MBSS; 644 else 645 mh->mh_flags |= MHF_MBSS; 646 } 647 MWL_HAL_UNLOCK(mh); 648 return retval; 649 } 650 651 /* 652 * Retrieve statistics from the f/w. 653 * XXX should be in memory shared w/ driver 654 */ 655 int 656 mwl_hal_gethwstats(struct mwl_hal *mh0, struct mwl_hal_hwstats *stats) 657 { 658 struct mwl_hal_priv *mh = MWLPRIV(mh0); 659 HostCmd_DS_802_11_GET_STAT *pCmd; 660 int retval; 661 662 MWL_HAL_LOCK(mh); 663 _CMD_SETUP(pCmd, HostCmd_DS_802_11_GET_STAT, 664 HostCmd_CMD_802_11_GET_STAT); 665 666 retval = mwlExecuteCmd(mh, HostCmd_CMD_802_11_GET_STAT); 667 if (retval == 0) { 668 const uint32_t *sp = (const uint32_t *)&pCmd->TxRetrySuccesses; 669 uint32_t *dp = (uint32_t *)&stats->TxRetrySuccesses; 670 int i; 671 672 for (i = 0; i < sizeof(*stats)/sizeof(uint32_t); i++) 673 dp[i] = le32toh(sp[i]); 674 /* 675 * Update stats not returned by f/w but available 676 * through public registers. Note these registers 677 * are "clear on read" so we maintain cumulative data. 678 * XXX register defines 679 */ 680 mh->mh_RTSSuccesses += RD4(mh, 0xa834); 681 mh->mh_RTSFailures += RD4(mh, 0xa830); 682 mh->mh_RxDuplicateFrames += RD4(mh, 0xa84c); 683 mh->mh_FCSErrorCount += RD4(mh, 0xa840); 684 } 685 MWL_HAL_UNLOCK(mh); 686 687 stats->RTSSuccesses = mh->mh_RTSSuccesses; 688 stats->RTSFailures = mh->mh_RTSFailures; 689 stats->RxDuplicateFrames = mh->mh_RxDuplicateFrames; 690 stats->FCSErrorCount = mh->mh_FCSErrorCount; 691 return retval; 692 } 693 694 /* 695 * Set HT guard interval handling. 696 * Takes effect immediately. 697 */ 698 int 699 mwl_hal_sethtgi(struct mwl_hal_vap *vap, int GIType) 700 { 701 struct mwl_hal_priv *mh = MWLVAP(vap); 702 HostCmd_FW_HT_GUARD_INTERVAL *pCmd; 703 int retval; 704 705 MWL_HAL_LOCK(mh); 706 _VCMD_SETUP(vap, pCmd, HostCmd_FW_HT_GUARD_INTERVAL, 707 HostCmd_CMD_HT_GUARD_INTERVAL); 708 pCmd->Action = htole32(HostCmd_ACT_GEN_SET); 709 710 if (GIType == 0) { 711 pCmd->GIType = htole32(GI_TYPE_LONG); 712 } else if (GIType == 1) { 713 pCmd->GIType = htole32(GI_TYPE_LONG | GI_TYPE_SHORT); 714 } else { 715 pCmd->GIType = htole32(GI_TYPE_LONG); 716 } 717 718 retval = mwlExecuteCmd(mh, HostCmd_CMD_HT_GUARD_INTERVAL); 719 MWL_HAL_UNLOCK(mh); 720 return retval; 721 } 722 723 /* 724 * Configure radio. 725 * Takes effect immediately. 726 * XXX preamble installed after set fixed rate cmd 727 */ 728 int 729 mwl_hal_setradio(struct mwl_hal *mh0, int onoff, MWL_HAL_PREAMBLE preamble) 730 { 731 struct mwl_hal_priv *mh = MWLPRIV(mh0); 732 HostCmd_DS_802_11_RADIO_CONTROL *pCmd; 733 int retval; 734 735 MWL_HAL_LOCK(mh); 736 _CMD_SETUP(pCmd, HostCmd_DS_802_11_RADIO_CONTROL, 737 HostCmd_CMD_802_11_RADIO_CONTROL); 738 pCmd->Action = htole16(HostCmd_ACT_GEN_SET); 739 if (onoff == 0) 740 pCmd->Control = 0; 741 else 742 pCmd->Control = htole16(preamble); 743 pCmd->RadioOn = htole16(onoff); 744 745 retval = mwlExecuteCmd(mh, HostCmd_CMD_802_11_RADIO_CONTROL); 746 MWL_HAL_UNLOCK(mh); 747 return retval; 748 } 749 750 /* 751 * Configure antenna use. 752 * Takes effect immediately. 753 * XXX tx antenna setting ignored 754 * XXX rx antenna setting should always be 3 (for now) 755 */ 756 int 757 mwl_hal_setantenna(struct mwl_hal *mh0, MWL_HAL_ANTENNA dirSet, int ant) 758 { 759 struct mwl_hal_priv *mh = MWLPRIV(mh0); 760 HostCmd_DS_802_11_RF_ANTENNA *pCmd; 761 int retval; 762 763 if (!(dirSet == WL_ANTENNATYPE_RX || dirSet == WL_ANTENNATYPE_TX)) 764 return EINVAL; 765 766 MWL_HAL_LOCK(mh); 767 _CMD_SETUP(pCmd, HostCmd_DS_802_11_RF_ANTENNA, 768 HostCmd_CMD_802_11_RF_ANTENNA); 769 pCmd->Action = htole16(dirSet); 770 if (ant == 0) /* default to all/both antennae */ 771 ant = 3; 772 pCmd->AntennaMode = htole16(ant); 773 774 retval = mwlExecuteCmd(mh, HostCmd_CMD_802_11_RF_ANTENNA); 775 MWL_HAL_UNLOCK(mh); 776 return retval; 777 } 778 779 /* 780 * Set packet size threshold for implicit use of RTS. 781 * Takes effect immediately. 782 * XXX packet length > threshold =>'s RTS 783 */ 784 int 785 mwl_hal_setrtsthreshold(struct mwl_hal_vap *vap, int threshold) 786 { 787 struct mwl_hal_priv *mh = MWLVAP(vap); 788 HostCmd_DS_802_11_RTS_THSD *pCmd; 789 int retval; 790 791 MWL_HAL_LOCK(mh); 792 _VCMD_SETUP(vap, pCmd, HostCmd_DS_802_11_RTS_THSD, 793 HostCmd_CMD_802_11_RTS_THSD); 794 pCmd->Action = htole16(HostCmd_ACT_GEN_SET); 795 pCmd->Threshold = htole16(threshold); 796 797 retval = mwlExecuteCmd(mh, HostCmd_CMD_802_11_RTS_THSD); 798 MWL_HAL_UNLOCK(mh); 799 return retval; 800 } 801 802 /* 803 * Enable sta-mode operation (disables beacon frame xmit). 804 */ 805 int 806 mwl_hal_setinframode(struct mwl_hal_vap *vap) 807 { 808 struct mwl_hal_priv *mh = MWLVAP(vap); 809 HostCmd_FW_SET_INFRA_MODE *pCmd; 810 int retval; 811 812 MWL_HAL_LOCK(mh); 813 _VCMD_SETUP(vap, pCmd, HostCmd_FW_SET_INFRA_MODE, 814 HostCmd_CMD_SET_INFRA_MODE); 815 816 retval = mwlExecuteCmd(mh, HostCmd_CMD_SET_INFRA_MODE); 817 MWL_HAL_UNLOCK(mh); 818 return retval; 819 } 820 821 /* 822 * Configure radar detection in support of 802.11h. 823 */ 824 int 825 mwl_hal_setradardetection(struct mwl_hal *mh0, MWL_HAL_RADAR action) 826 { 827 struct mwl_hal_priv *mh = MWLPRIV(mh0); 828 HostCmd_802_11h_Detect_Radar *pCmd; 829 int retval; 830 831 MWL_HAL_LOCK(mh); 832 _CMD_SETUP(pCmd, HostCmd_802_11h_Detect_Radar, 833 HostCmd_CMD_802_11H_DETECT_RADAR); 834 pCmd->CmdHdr.Length = htole16(sizeof(HostCmd_802_11h_Detect_Radar)); 835 pCmd->Action = htole16(action); 836 if (mh->mh_regioncode == DOMAIN_CODE_ETSI_131) 837 pCmd->RadarTypeCode = htole16(131); 838 839 retval = mwlExecuteCmd(mh, HostCmd_CMD_802_11H_DETECT_RADAR); 840 MWL_HAL_UNLOCK(mh); 841 return retval; 842 } 843 844 /* 845 * Convert public channel flags definition to a 846 * value suitable for feeding to the firmware. 847 * Note this includes byte swapping. 848 */ 849 static uint32_t 850 cvtChannelFlags(const MWL_HAL_CHANNEL *chan) 851 { 852 uint32_t w; 853 854 /* 855 * NB: f/w only understands FREQ_BAND_5GHZ, supplying the more 856 * precise band info causes it to lockup (sometimes). 857 */ 858 w = (chan->channelFlags.FreqBand == MWL_FREQ_BAND_2DOT4GHZ) ? 859 FREQ_BAND_2DOT4GHZ : FREQ_BAND_5GHZ; 860 switch (chan->channelFlags.ChnlWidth) { 861 case MWL_CH_10_MHz_WIDTH: 862 w |= CH_10_MHz_WIDTH; 863 break; 864 case MWL_CH_20_MHz_WIDTH: 865 w |= CH_20_MHz_WIDTH; 866 break; 867 case MWL_CH_40_MHz_WIDTH: 868 default: 869 w |= CH_40_MHz_WIDTH; 870 break; 871 } 872 switch (chan->channelFlags.ExtChnlOffset) { 873 case MWL_EXT_CH_NONE: 874 w |= EXT_CH_NONE; 875 break; 876 case MWL_EXT_CH_ABOVE_CTRL_CH: 877 w |= EXT_CH_ABOVE_CTRL_CH; 878 break; 879 case MWL_EXT_CH_BELOW_CTRL_CH: 880 w |= EXT_CH_BELOW_CTRL_CH; 881 break; 882 } 883 return htole32(w); 884 } 885 886 /* 887 * Start a channel switch announcement countdown. The IE 888 * in the beacon frame is allowed to go out and the firmware 889 * counts down and notifies the host when it's time to switch 890 * channels. 891 */ 892 int 893 mwl_hal_setchannelswitchie(struct mwl_hal *mh0, 894 const MWL_HAL_CHANNEL *nextchan, uint32_t mode, uint32_t count) 895 { 896 struct mwl_hal_priv *mh = MWLPRIV(mh0); 897 HostCmd_SET_SWITCH_CHANNEL *pCmd; 898 int retval; 899 900 MWL_HAL_LOCK(mh); 901 _CMD_SETUP(pCmd, HostCmd_SET_SWITCH_CHANNEL, 902 HostCmd_CMD_SET_SWITCH_CHANNEL); 903 pCmd->Next11hChannel = htole32(nextchan->channel); 904 pCmd->Mode = htole32(mode); 905 pCmd->InitialCount = htole32(count+1); 906 pCmd->ChannelFlags = cvtChannelFlags(nextchan); 907 908 retval = mwlExecuteCmd(mh, HostCmd_CMD_SET_SWITCH_CHANNEL); 909 MWL_HAL_UNLOCK(mh); 910 return retval; 911 } 912 913 /* 914 * Set the region code that selects the radar bin'ing agorithm. 915 */ 916 int 917 mwl_hal_setregioncode(struct mwl_hal *mh0, int regionCode) 918 { 919 struct mwl_hal_priv *mh = MWLPRIV(mh0); 920 HostCmd_SET_REGIONCODE_INFO *pCmd; 921 int retval; 922 923 MWL_HAL_LOCK(mh); 924 _CMD_SETUP(pCmd, HostCmd_SET_REGIONCODE_INFO, 925 HostCmd_CMD_SET_REGION_CODE); 926 /* XXX map pseudo-codes to fw codes */ 927 switch (regionCode) { 928 case DOMAIN_CODE_ETSI_131: 929 pCmd->regionCode = htole16(DOMAIN_CODE_ETSI); 930 break; 931 default: 932 pCmd->regionCode = htole16(regionCode); 933 break; 934 } 935 936 retval = mwlExecuteCmd(mh, HostCmd_CMD_SET_REGION_CODE); 937 if (retval == 0) 938 mh->mh_regioncode = regionCode; 939 MWL_HAL_UNLOCK(mh); 940 return retval; 941 } 942 943 #define RATEVAL(r) ((r) &~ RATE_MCS) 944 #define RATETYPE(r) (((r) & RATE_MCS) ? HT_RATE_TYPE : LEGACY_RATE_TYPE) 945 946 int 947 mwl_hal_settxrate(struct mwl_hal_vap *vap, MWL_HAL_TXRATE_HANDLING handling, 948 const MWL_HAL_TXRATE *rate) 949 { 950 struct mwl_hal_priv *mh = MWLVAP(vap); 951 HostCmd_FW_USE_FIXED_RATE *pCmd; 952 FIXED_RATE_ENTRY *fp; 953 int retval, i, n; 954 955 MWL_HAL_LOCK(mh); 956 _VCMD_SETUP(vap, pCmd, HostCmd_FW_USE_FIXED_RATE, 957 HostCmd_CMD_SET_FIXED_RATE); 958 959 pCmd->MulticastRate = RATEVAL(rate->McastRate); 960 pCmd->MultiRateTxType = RATETYPE(rate->McastRate); 961 /* NB: no rate type field */ 962 pCmd->ManagementRate = RATEVAL(rate->MgtRate); 963 memset(pCmd->FixedRateTable, 0, sizeof(pCmd->FixedRateTable)); 964 if (handling == RATE_FIXED) { 965 pCmd->Action = htole32(HostCmd_ACT_GEN_SET); 966 pCmd->AllowRateDrop = htole32(FIXED_RATE_WITHOUT_AUTORATE_DROP); 967 fp = pCmd->FixedRateTable; 968 fp->FixedRate = 969 htole32(RATEVAL(rate->RateSeries[0].Rate)); 970 fp->FixRateTypeFlags.FixRateType = 971 htole32(RATETYPE(rate->RateSeries[0].Rate)); 972 pCmd->EntryCount = htole32(1); 973 } else if (handling == RATE_FIXED_DROP) { 974 pCmd->Action = htole32(HostCmd_ACT_GEN_SET); 975 pCmd->AllowRateDrop = htole32(FIXED_RATE_WITH_AUTO_RATE_DROP); 976 n = 0; 977 fp = pCmd->FixedRateTable; 978 for (i = 0; i < 4; i++) { 979 if (rate->RateSeries[0].TryCount == 0) 980 break; 981 fp->FixRateTypeFlags.FixRateType = 982 htole32(RATETYPE(rate->RateSeries[i].Rate)); 983 fp->FixedRate = 984 htole32(RATEVAL(rate->RateSeries[i].Rate)); 985 fp->FixRateTypeFlags.RetryCountValid = 986 htole32(RETRY_COUNT_VALID); 987 fp->RetryCount = 988 htole32(rate->RateSeries[i].TryCount-1); 989 n++; 990 } 991 pCmd->EntryCount = htole32(n); 992 } else 993 pCmd->Action = htole32(HostCmd_ACT_NOT_USE_FIXED_RATE); 994 995 retval = mwlExecuteCmd(mh, HostCmd_CMD_SET_FIXED_RATE); 996 MWL_HAL_UNLOCK(mh); 997 return retval; 998 } 999 1000 int 1001 mwl_hal_settxrate_auto(struct mwl_hal *mh0, const MWL_HAL_TXRATE *rate) 1002 { 1003 struct mwl_hal_priv *mh = MWLPRIV(mh0); 1004 HostCmd_FW_USE_FIXED_RATE *pCmd; 1005 int retval; 1006 1007 MWL_HAL_LOCK(mh); 1008 _CMD_SETUP(pCmd, HostCmd_FW_USE_FIXED_RATE, 1009 HostCmd_CMD_SET_FIXED_RATE); 1010 1011 pCmd->MulticastRate = RATEVAL(rate->McastRate); 1012 pCmd->MultiRateTxType = RATETYPE(rate->McastRate); 1013 /* NB: no rate type field */ 1014 pCmd->ManagementRate = RATEVAL(rate->MgtRate); 1015 memset(pCmd->FixedRateTable, 0, sizeof(pCmd->FixedRateTable)); 1016 pCmd->Action = htole32(HostCmd_ACT_NOT_USE_FIXED_RATE); 1017 1018 retval = mwlExecuteCmd(mh, HostCmd_CMD_SET_FIXED_RATE); 1019 MWL_HAL_UNLOCK(mh); 1020 return retval; 1021 } 1022 1023 #undef RATEVAL 1024 #undef RATETYPE 1025 1026 int 1027 mwl_hal_setslottime(struct mwl_hal *mh0, int usecs) 1028 { 1029 struct mwl_hal_priv *mh = MWLPRIV(mh0); 1030 HostCmd_FW_SET_SLOT *pCmd; 1031 int retval; 1032 1033 if (usecs != 9 && usecs != 20) 1034 return EINVAL; 1035 1036 MWL_HAL_LOCK(mh); 1037 _CMD_SETUP(pCmd, HostCmd_FW_SET_SLOT, 1038 HostCmd_CMD_802_11_SET_SLOT); 1039 pCmd->Action = htole16(HostCmd_ACT_GEN_SET); 1040 pCmd->Slot = (usecs == 9 ? 1 : 0); 1041 1042 retval = mwlExecuteCmd(mh, HostCmd_CMD_802_11_SET_SLOT); 1043 MWL_HAL_UNLOCK(mh); 1044 return retval; 1045 } 1046 1047 int 1048 mwl_hal_adjusttxpower(struct mwl_hal *mh0, uint32_t level) 1049 { 1050 struct mwl_hal_priv *mh = MWLPRIV(mh0); 1051 HostCmd_DS_802_11_RF_TX_POWER *pCmd; 1052 int retval; 1053 1054 MWL_HAL_LOCK(mh); 1055 _CMD_SETUP(pCmd, HostCmd_DS_802_11_RF_TX_POWER, 1056 HostCmd_CMD_802_11_RF_TX_POWER); 1057 pCmd->Action = htole16(HostCmd_ACT_GEN_SET); 1058 1059 if (level < 30) { 1060 pCmd->SupportTxPowerLevel = htole16(WL_TX_POWERLEVEL_LOW); 1061 } else if (level >= 30 && level < 60) { 1062 pCmd->SupportTxPowerLevel = htole16(WL_TX_POWERLEVEL_MEDIUM); 1063 } else { 1064 pCmd->SupportTxPowerLevel = htole16(WL_TX_POWERLEVEL_HIGH); 1065 } 1066 1067 retval = mwlExecuteCmd(mh, HostCmd_CMD_802_11_RF_TX_POWER); 1068 MWL_HAL_UNLOCK(mh); 1069 return retval; 1070 } 1071 1072 static const struct mwl_hal_channel * 1073 findchannel(const struct mwl_hal_priv *mh, const MWL_HAL_CHANNEL *c) 1074 { 1075 const struct mwl_hal_channel *hc; 1076 const MWL_HAL_CHANNELINFO *ci; 1077 int chan = c->channel, i; 1078 1079 if (c->channelFlags.FreqBand == MWL_FREQ_BAND_2DOT4GHZ) { 1080 i = chan - 1; 1081 if (c->channelFlags.ChnlWidth == MWL_CH_40_MHz_WIDTH) { 1082 ci = &mh->mh_40M; 1083 if (c->channelFlags.ExtChnlOffset == MWL_EXT_CH_BELOW_CTRL_CH) 1084 i -= 4; 1085 } else 1086 ci = &mh->mh_20M; 1087 /* 2.4G channel table is directly indexed */ 1088 hc = ((unsigned)i < ci->nchannels) ? &ci->channels[i] : NULL; 1089 } else if (c->channelFlags.FreqBand == MWL_FREQ_BAND_5GHZ) { 1090 if (c->channelFlags.ChnlWidth == MWL_CH_40_MHz_WIDTH) { 1091 ci = &mh->mh_40M_5G; 1092 if (c->channelFlags.ExtChnlOffset == MWL_EXT_CH_BELOW_CTRL_CH) 1093 chan -= 4; 1094 } else 1095 ci = &mh->mh_20M_5G; 1096 /* 5GHz channel table is sparse and must be searched */ 1097 for (i = 0; i < ci->nchannels; i++) 1098 if (ci->channels[i].ieee == chan) 1099 break; 1100 hc = (i < ci->nchannels) ? &ci->channels[i] : NULL; 1101 } else 1102 hc = NULL; 1103 return hc; 1104 } 1105 1106 int 1107 mwl_hal_settxpower(struct mwl_hal *mh0, const MWL_HAL_CHANNEL *c, uint8_t maxtxpow) 1108 { 1109 struct mwl_hal_priv *mh = MWLPRIV(mh0); 1110 HostCmd_DS_802_11_RF_TX_POWER *pCmd; 1111 const struct mwl_hal_channel *hc; 1112 int i, retval; 1113 1114 hc = findchannel(mh, c); 1115 if (hc == NULL) { 1116 /* XXX temp while testing */ 1117 device_printf(mh->mh_dev, 1118 "%s: no cal data for channel %u band %u width %u ext %u\n", 1119 __func__, c->channel, c->channelFlags.FreqBand, 1120 c->channelFlags.ChnlWidth, c->channelFlags.ExtChnlOffset); 1121 return EINVAL; 1122 } 1123 1124 MWL_HAL_LOCK(mh); 1125 _CMD_SETUP(pCmd, HostCmd_DS_802_11_RF_TX_POWER, 1126 HostCmd_CMD_802_11_RF_TX_POWER); 1127 pCmd->Action = htole16(HostCmd_ACT_GEN_SET_LIST); 1128 i = 0; 1129 /* NB: 5Ghz cal data have the channel # in [0]; don't truncate */ 1130 if (c->channelFlags.FreqBand == MWL_FREQ_BAND_5GHZ) 1131 pCmd->PowerLevelList[i++] = htole16(hc->targetPowers[0]); 1132 for (; i < 4; i++) { 1133 uint16_t pow = hc->targetPowers[i]; 1134 if (pow > maxtxpow) 1135 pow = maxtxpow; 1136 pCmd->PowerLevelList[i] = htole16(pow); 1137 } 1138 retval = mwlExecuteCmd(mh, HostCmd_CMD_802_11_RF_TX_POWER); 1139 MWL_HAL_UNLOCK(mh); 1140 return retval; 1141 } 1142 1143 int 1144 mwl_hal_getchannelinfo(struct mwl_hal *mh0, int band, int chw, 1145 const MWL_HAL_CHANNELINFO **ci) 1146 { 1147 struct mwl_hal_priv *mh = MWLPRIV(mh0); 1148 1149 switch (band) { 1150 case MWL_FREQ_BAND_2DOT4GHZ: 1151 *ci = (chw == MWL_CH_20_MHz_WIDTH) ? &mh->mh_20M : &mh->mh_40M; 1152 break; 1153 case MWL_FREQ_BAND_5GHZ: 1154 *ci = (chw == MWL_CH_20_MHz_WIDTH) ? 1155 &mh->mh_20M_5G : &mh->mh_40M_5G; 1156 break; 1157 default: 1158 return EINVAL; 1159 } 1160 return ((*ci)->freqLow == (*ci)->freqHigh) ? EINVAL : 0; 1161 } 1162 1163 int 1164 mwl_hal_setmcast(struct mwl_hal *mh0, int nmc, const uint8_t macs[]) 1165 { 1166 struct mwl_hal_priv *mh = MWLPRIV(mh0); 1167 HostCmd_DS_MAC_MULTICAST_ADR *pCmd; 1168 int retval; 1169 1170 if (nmc > MWL_HAL_MCAST_MAX) 1171 return EINVAL; 1172 1173 MWL_HAL_LOCK(mh); 1174 _CMD_SETUP(pCmd, HostCmd_DS_MAC_MULTICAST_ADR, 1175 HostCmd_CMD_MAC_MULTICAST_ADR); 1176 memcpy(pCmd->MACList, macs, nmc*IEEE80211_ADDR_LEN); 1177 pCmd->NumOfAdrs = htole16(nmc); 1178 pCmd->Action = htole16(0xffff); 1179 1180 retval = mwlExecuteCmd(mh, HostCmd_CMD_MAC_MULTICAST_ADR); 1181 MWL_HAL_UNLOCK(mh); 1182 return retval; 1183 } 1184 1185 int 1186 mwl_hal_keyset(struct mwl_hal_vap *vap, const MWL_HAL_KEYVAL *kv, 1187 const uint8_t mac[IEEE80211_ADDR_LEN]) 1188 { 1189 struct mwl_hal_priv *mh = MWLVAP(vap); 1190 HostCmd_FW_UPDATE_ENCRYPTION_SET_KEY *pCmd; 1191 int retval; 1192 1193 MWL_HAL_LOCK(mh); 1194 _VCMD_SETUP(vap, pCmd, HostCmd_FW_UPDATE_ENCRYPTION_SET_KEY, 1195 HostCmd_CMD_UPDATE_ENCRYPTION); 1196 if (kv->keyFlags & (KEY_FLAG_TXGROUPKEY|KEY_FLAG_RXGROUPKEY)) 1197 pCmd->ActionType = htole32(EncrActionTypeSetGroupKey); 1198 else 1199 pCmd->ActionType = htole32(EncrActionTypeSetKey); 1200 pCmd->KeyParam.Length = htole16(sizeof(pCmd->KeyParam)); 1201 pCmd->KeyParam.KeyTypeId = htole16(kv->keyTypeId); 1202 pCmd->KeyParam.KeyInfo = htole32(kv->keyFlags); 1203 pCmd->KeyParam.KeyIndex = htole32(kv->keyIndex); 1204 /* NB: includes TKIP MIC keys */ 1205 memcpy(&pCmd->KeyParam.Key, &kv->key, kv->keyLen); 1206 switch (kv->keyTypeId) { 1207 case KEY_TYPE_ID_WEP: 1208 pCmd->KeyParam.KeyLen = htole16(kv->keyLen); 1209 break; 1210 case KEY_TYPE_ID_TKIP: 1211 pCmd->KeyParam.KeyLen = htole16(sizeof(TKIP_TYPE_KEY)); 1212 pCmd->KeyParam.Key.TkipKey.TkipRsc.low = 1213 htole16(kv->key.tkip.rsc.low); 1214 pCmd->KeyParam.Key.TkipKey.TkipRsc.high = 1215 htole32(kv->key.tkip.rsc.high); 1216 pCmd->KeyParam.Key.TkipKey.TkipTsc.low = 1217 htole16(kv->key.tkip.tsc.low); 1218 pCmd->KeyParam.Key.TkipKey.TkipTsc.high = 1219 htole32(kv->key.tkip.tsc.high); 1220 break; 1221 case KEY_TYPE_ID_AES: 1222 pCmd->KeyParam.KeyLen = htole16(sizeof(AES_TYPE_KEY)); 1223 break; 1224 } 1225 #ifdef MWL_MBSS_SUPPORT 1226 IEEE80211_ADDR_COPY(pCmd->KeyParam.Macaddr, mac); 1227 #else 1228 IEEE80211_ADDR_COPY(pCmd->Macaddr, mac); 1229 #endif 1230 retval = mwlExecuteCmd(mh, HostCmd_CMD_UPDATE_ENCRYPTION); 1231 MWL_HAL_UNLOCK(mh); 1232 return retval; 1233 } 1234 1235 int 1236 mwl_hal_keyreset(struct mwl_hal_vap *vap, const MWL_HAL_KEYVAL *kv, const uint8_t mac[IEEE80211_ADDR_LEN]) 1237 { 1238 struct mwl_hal_priv *mh = MWLVAP(vap); 1239 HostCmd_FW_UPDATE_ENCRYPTION_SET_KEY *pCmd; 1240 int retval; 1241 1242 MWL_HAL_LOCK(mh); 1243 _VCMD_SETUP(vap, pCmd, HostCmd_FW_UPDATE_ENCRYPTION_SET_KEY, 1244 HostCmd_CMD_UPDATE_ENCRYPTION); 1245 pCmd->ActionType = htole16(EncrActionTypeRemoveKey); 1246 pCmd->KeyParam.Length = htole16(sizeof(pCmd->KeyParam)); 1247 pCmd->KeyParam.KeyTypeId = htole16(kv->keyTypeId); 1248 pCmd->KeyParam.KeyInfo = htole32(kv->keyFlags); 1249 pCmd->KeyParam.KeyIndex = htole32(kv->keyIndex); 1250 #ifdef MWL_MBSS_SUPPORT 1251 IEEE80211_ADDR_COPY(pCmd->KeyParam.Macaddr, mac); 1252 #else 1253 IEEE80211_ADDR_COPY(pCmd->Macaddr, mac); 1254 #endif 1255 retval = mwlExecuteCmd(mh, HostCmd_CMD_UPDATE_ENCRYPTION); 1256 MWL_HAL_UNLOCK(mh); 1257 return retval; 1258 } 1259 1260 static int 1261 mwl_hal_setmac_locked(struct mwl_hal_vap *vap, 1262 const uint8_t addr[IEEE80211_ADDR_LEN]) 1263 { 1264 struct mwl_hal_priv *mh = MWLVAP(vap); 1265 HostCmd_DS_SET_MAC *pCmd; 1266 1267 _VCMD_SETUP(vap, pCmd, HostCmd_DS_SET_MAC, HostCmd_CMD_SET_MAC_ADDR); 1268 IEEE80211_ADDR_COPY(&pCmd->MacAddr[0], addr); 1269 #ifdef MWL_MBSS_SUPPORT 1270 pCmd->MacType = vap->bss_type; /* NB: already byte swapped */ 1271 IEEE80211_ADDR_COPY(vap->mac, addr); /* XXX do only if success */ 1272 #endif 1273 return mwlExecuteCmd(mh, HostCmd_CMD_SET_MAC_ADDR); 1274 } 1275 1276 int 1277 mwl_hal_setmac(struct mwl_hal_vap *vap, const uint8_t addr[IEEE80211_ADDR_LEN]) 1278 { 1279 struct mwl_hal_priv *mh = MWLVAP(vap); 1280 int retval; 1281 1282 MWL_HAL_LOCK(mh); 1283 retval = mwl_hal_setmac_locked(vap, addr); 1284 MWL_HAL_UNLOCK(mh); 1285 return retval; 1286 } 1287 1288 int 1289 mwl_hal_setbeacon(struct mwl_hal_vap *vap, const void *frame, size_t frameLen) 1290 { 1291 struct mwl_hal_priv *mh = MWLVAP(vap); 1292 HostCmd_DS_SET_BEACON *pCmd; 1293 int retval; 1294 1295 /* XXX verify frameLen fits */ 1296 MWL_HAL_LOCK(mh); 1297 _VCMD_SETUP(vap, pCmd, HostCmd_DS_SET_BEACON, HostCmd_CMD_SET_BEACON); 1298 /* XXX override _VCMD_SETUP */ 1299 pCmd->CmdHdr.Length = htole16(sizeof(HostCmd_DS_SET_BEACON)-1+frameLen); 1300 pCmd->FrmBodyLen = htole16(frameLen); 1301 memcpy(pCmd->FrmBody, frame, frameLen); 1302 1303 retval = mwlExecuteCmd(mh, HostCmd_CMD_SET_BEACON); 1304 MWL_HAL_UNLOCK(mh); 1305 return retval; 1306 } 1307 1308 int 1309 mwl_hal_setpowersave_bss(struct mwl_hal_vap *vap, uint8_t nsta) 1310 { 1311 struct mwl_hal_priv *mh = MWLVAP(vap); 1312 HostCmd_SET_POWERSAVESTATION *pCmd; 1313 int retval; 1314 1315 MWL_HAL_LOCK(mh); 1316 _VCMD_SETUP(vap, pCmd, HostCmd_SET_POWERSAVESTATION, 1317 HostCmd_CMD_SET_POWERSAVESTATION); 1318 pCmd->NumberOfPowersave = nsta; 1319 1320 retval = mwlExecuteCmd(mh, HostCmd_CMD_SET_POWERSAVESTATION); 1321 MWL_HAL_UNLOCK(mh); 1322 return retval; 1323 } 1324 1325 int 1326 mwl_hal_setpowersave_sta(struct mwl_hal_vap *vap, uint16_t aid, int ena) 1327 { 1328 struct mwl_hal_priv *mh = MWLVAP(vap); 1329 HostCmd_SET_TIM *pCmd; 1330 int retval; 1331 1332 MWL_HAL_LOCK(mh); 1333 _VCMD_SETUP(vap, pCmd, HostCmd_SET_TIM, HostCmd_CMD_SET_TIM); 1334 pCmd->Aid = htole16(aid); 1335 pCmd->Set = htole32(ena); 1336 1337 retval = mwlExecuteCmd(mh, HostCmd_CMD_SET_TIM); 1338 MWL_HAL_UNLOCK(mh); 1339 return retval; 1340 } 1341 1342 int 1343 mwl_hal_setassocid(struct mwl_hal_vap *vap, 1344 const uint8_t bssId[IEEE80211_ADDR_LEN], uint16_t assocId) 1345 { 1346 struct mwl_hal_priv *mh = MWLVAP(vap); 1347 HostCmd_FW_SET_AID *pCmd = (HostCmd_FW_SET_AID *) &mh->mh_cmdbuf[0]; 1348 int retval; 1349 1350 MWL_HAL_LOCK(mh); 1351 _VCMD_SETUP(vap, pCmd, HostCmd_FW_SET_AID, HostCmd_CMD_SET_AID); 1352 pCmd->AssocID = htole16(assocId); 1353 IEEE80211_ADDR_COPY(&pCmd->MacAddr[0], bssId); 1354 1355 retval = mwlExecuteCmd(mh, HostCmd_CMD_SET_AID); 1356 MWL_HAL_UNLOCK(mh); 1357 return retval; 1358 } 1359 1360 int 1361 mwl_hal_setchannel(struct mwl_hal *mh0, const MWL_HAL_CHANNEL *chan) 1362 { 1363 struct mwl_hal_priv *mh = MWLPRIV(mh0); 1364 HostCmd_FW_SET_RF_CHANNEL *pCmd; 1365 int retval; 1366 1367 MWL_HAL_LOCK(mh); 1368 _CMD_SETUP(pCmd, HostCmd_FW_SET_RF_CHANNEL, HostCmd_CMD_SET_RF_CHANNEL); 1369 pCmd->Action = htole16(HostCmd_ACT_GEN_SET); 1370 pCmd->CurrentChannel = chan->channel; 1371 pCmd->ChannelFlags = cvtChannelFlags(chan); /* NB: byte-swapped */ 1372 1373 retval = mwlExecuteCmd(mh, HostCmd_CMD_SET_RF_CHANNEL); 1374 MWL_HAL_UNLOCK(mh); 1375 return retval; 1376 } 1377 1378 static int 1379 bastream_check_available(struct mwl_hal_vap *vap, int qid, 1380 const uint8_t Macaddr[IEEE80211_ADDR_LEN], 1381 uint8_t Tid, uint8_t ParamInfo) 1382 { 1383 struct mwl_hal_priv *mh = MWLVAP(vap); 1384 HostCmd_FW_BASTREAM *pCmd; 1385 int retval; 1386 1387 MWL_HAL_LOCK_ASSERT(mh); 1388 1389 _VCMD_SETUP(vap, pCmd, HostCmd_FW_BASTREAM, HostCmd_CMD_BASTREAM); 1390 pCmd->ActionType = htole32(BaCheckCreateStream); 1391 pCmd->BaInfo.CreateParams.BarThrs = htole32(63); 1392 pCmd->BaInfo.CreateParams.WindowSize = htole32(64); 1393 pCmd->BaInfo.CreateParams.IdleThrs = htole32(0x22000); 1394 IEEE80211_ADDR_COPY(&pCmd->BaInfo.CreateParams.PeerMacAddr[0], Macaddr); 1395 pCmd->BaInfo.CreateParams.DialogToken = 10; 1396 pCmd->BaInfo.CreateParams.Tid = Tid; 1397 pCmd->BaInfo.CreateParams.QueueId = qid; 1398 pCmd->BaInfo.CreateParams.ParamInfo = (uint8_t) ParamInfo; 1399 #if 0 1400 cvtBAFlags(&pCmd->BaInfo.CreateParams.Flags, sp->ba_policy, 0); 1401 #else 1402 pCmd->BaInfo.CreateParams.Flags = 1403 htole32(BASTREAM_FLAG_IMMEDIATE_TYPE) 1404 | htole32(BASTREAM_FLAG_DIRECTION_UPSTREAM) 1405 ; 1406 #endif 1407 1408 retval = mwlExecuteCmd(mh, HostCmd_CMD_BASTREAM); 1409 if (retval == 0) { 1410 /* 1411 * NB: BA stream create may fail when the stream is 1412 * h/w backed under some (as yet not understood) conditions. 1413 * Check the result code to catch this. 1414 */ 1415 if (le16toh(pCmd->CmdHdr.Result) != HostCmd_RESULT_OK) 1416 retval = EIO; 1417 } 1418 return retval; 1419 } 1420 1421 const MWL_HAL_BASTREAM * 1422 mwl_hal_bastream_alloc(struct mwl_hal_vap *vap, int ba_policy, 1423 const uint8_t Macaddr[IEEE80211_ADDR_LEN], 1424 uint8_t Tid, uint8_t ParamInfo, void *a1, void *a2) 1425 { 1426 struct mwl_hal_priv *mh = MWLVAP(vap); 1427 struct mwl_hal_bastream *sp; 1428 int s; 1429 1430 MWL_HAL_LOCK(mh); 1431 if (mh->mh_bastreams == 0) { 1432 /* no streams available */ 1433 MWL_HAL_UNLOCK(mh); 1434 return NULL; 1435 } 1436 for (s = 0; (mh->mh_bastreams & (1<<s)) == 0; s++) 1437 ; 1438 if (bastream_check_available(vap, s, Macaddr, Tid, ParamInfo)) { 1439 MWL_HAL_UNLOCK(mh); 1440 return NULL; 1441 } 1442 sp = &mh->mh_streams[s]; 1443 mh->mh_bastreams &= ~(1<<s); 1444 sp->public.data[0] = a1; 1445 sp->public.data[1] = a2; 1446 IEEE80211_ADDR_COPY(sp->macaddr, Macaddr); 1447 sp->tid = Tid; 1448 sp->paraminfo = ParamInfo; 1449 sp->setup = 0; 1450 sp->ba_policy = ba_policy; 1451 MWL_HAL_UNLOCK(mh); 1452 return sp != NULL ? &sp->public : NULL; 1453 } 1454 1455 const MWL_HAL_BASTREAM * 1456 mwl_hal_bastream_lookup(struct mwl_hal *mh0, int s) 1457 { 1458 struct mwl_hal_priv *mh = MWLPRIV(mh0); 1459 1460 if (!(0 <= s && s < MWL_BASTREAMS_MAX)) 1461 return NULL; 1462 if (mh->mh_bastreams & (1<<s)) 1463 return NULL; 1464 return &mh->mh_streams[s].public; 1465 } 1466 1467 #ifndef __DECONST 1468 #define __DECONST(type, var) ((type)(uintptr_t)(const void *)(var)) 1469 #endif 1470 1471 int 1472 mwl_hal_bastream_create(struct mwl_hal_vap *vap, 1473 const MWL_HAL_BASTREAM *s, int BarThrs, int WindowSize, uint16_t seqno) 1474 { 1475 struct mwl_hal_priv *mh = MWLVAP(vap); 1476 struct mwl_hal_bastream *sp = __DECONST(struct mwl_hal_bastream *, s); 1477 HostCmd_FW_BASTREAM *pCmd; 1478 int retval; 1479 1480 MWL_HAL_LOCK(mh); 1481 _VCMD_SETUP(vap, pCmd, HostCmd_FW_BASTREAM, HostCmd_CMD_BASTREAM); 1482 pCmd->ActionType = htole32(BaCreateStream); 1483 pCmd->BaInfo.CreateParams.BarThrs = htole32(BarThrs); 1484 pCmd->BaInfo.CreateParams.WindowSize = htole32(WindowSize); 1485 pCmd->BaInfo.CreateParams.IdleThrs = htole32(0x22000); 1486 IEEE80211_ADDR_COPY(&pCmd->BaInfo.CreateParams.PeerMacAddr[0], 1487 sp->macaddr); 1488 /* XXX proxy STA */ 1489 memset(&pCmd->BaInfo.CreateParams.StaSrcMacAddr, 0, IEEE80211_ADDR_LEN); 1490 #if 0 1491 pCmd->BaInfo.CreateParams.DialogToken = DialogToken; 1492 #else 1493 pCmd->BaInfo.CreateParams.DialogToken = 10; 1494 #endif 1495 pCmd->BaInfo.CreateParams.Tid = sp->tid; 1496 pCmd->BaInfo.CreateParams.QueueId = sp->stream; 1497 pCmd->BaInfo.CreateParams.ParamInfo = sp->paraminfo; 1498 /* NB: ResetSeqNo known to be zero */ 1499 pCmd->BaInfo.CreateParams.StartSeqNo = htole16(seqno); 1500 #if 0 1501 cvtBAFlags(&pCmd->BaInfo.CreateParams.Flags, sp->ba_policy, 0); 1502 #else 1503 pCmd->BaInfo.CreateParams.Flags = 1504 htole32(BASTREAM_FLAG_IMMEDIATE_TYPE) 1505 | htole32(BASTREAM_FLAG_DIRECTION_UPSTREAM) 1506 ; 1507 #endif 1508 1509 retval = mwlExecuteCmd(mh, HostCmd_CMD_BASTREAM); 1510 if (retval == 0) { 1511 /* 1512 * NB: BA stream create may fail when the stream is 1513 * h/w backed under some (as yet not understood) conditions. 1514 * Check the result code to catch this. 1515 */ 1516 if (le16toh(pCmd->CmdHdr.Result) != HostCmd_RESULT_OK) 1517 retval = EIO; 1518 else 1519 sp->setup = 1; 1520 } 1521 MWL_HAL_UNLOCK(mh); 1522 return retval; 1523 } 1524 1525 int 1526 mwl_hal_bastream_destroy(struct mwl_hal *mh0, const MWL_HAL_BASTREAM *s) 1527 { 1528 struct mwl_hal_priv *mh = MWLPRIV(mh0); 1529 struct mwl_hal_bastream *sp = __DECONST(struct mwl_hal_bastream *, s); 1530 HostCmd_FW_BASTREAM *pCmd; 1531 int retval; 1532 1533 if (sp->stream >= MWL_BASTREAMS_MAX) { 1534 /* XXX */ 1535 return EINVAL; 1536 } 1537 MWL_HAL_LOCK(mh); 1538 if (sp->setup) { 1539 _CMD_SETUP(pCmd, HostCmd_FW_BASTREAM, HostCmd_CMD_BASTREAM); 1540 pCmd->ActionType = htole32(BaDestroyStream); 1541 pCmd->BaInfo.DestroyParams.FwBaContext.Context = 1542 htole32(sp->stream); 1543 1544 retval = mwlExecuteCmd(mh, HostCmd_CMD_BASTREAM); 1545 } else 1546 retval = 0; 1547 /* NB: always reclaim stream */ 1548 mh->mh_bastreams |= 1<<sp->stream; 1549 sp->public.data[0] = NULL; 1550 sp->public.data[1] = NULL; 1551 sp->setup = 0; 1552 MWL_HAL_UNLOCK(mh); 1553 return retval; 1554 } 1555 1556 int 1557 mwl_hal_bastream_get_seqno(struct mwl_hal *mh0, 1558 const MWL_HAL_BASTREAM *s, const uint8_t Macaddr[IEEE80211_ADDR_LEN], 1559 uint16_t *pseqno) 1560 { 1561 struct mwl_hal_priv *mh = MWLPRIV(mh0); 1562 struct mwl_hal_bastream *sp = __DECONST(struct mwl_hal_bastream *, s); 1563 HostCmd_GET_SEQNO *pCmd; 1564 int retval; 1565 1566 MWL_HAL_LOCK(mh); 1567 _CMD_SETUP(pCmd, HostCmd_GET_SEQNO, HostCmd_CMD_GET_SEQNO); 1568 IEEE80211_ADDR_COPY(pCmd->MacAddr, Macaddr); 1569 pCmd->TID = sp->tid; 1570 1571 retval = mwlExecuteCmd(mh, HostCmd_CMD_GET_SEQNO); 1572 if (retval == 0) 1573 *pseqno = le16toh(pCmd->SeqNo); 1574 MWL_HAL_UNLOCK(mh); 1575 return retval; 1576 } 1577 1578 int 1579 mwl_hal_getwatchdogbitmap(struct mwl_hal *mh0, uint8_t bitmap[1]) 1580 { 1581 struct mwl_hal_priv *mh = MWLPRIV(mh0); 1582 HostCmd_FW_GET_WATCHDOG_BITMAP *pCmd; 1583 int retval; 1584 1585 MWL_HAL_LOCK(mh); 1586 _CMD_SETUP(pCmd, HostCmd_FW_GET_WATCHDOG_BITMAP, 1587 HostCmd_CMD_GET_WATCHDOG_BITMAP); 1588 1589 retval = mwlExecuteCmd(mh, HostCmd_CMD_GET_WATCHDOG_BITMAP); 1590 if (retval == 0) { 1591 bitmap[0] = pCmd->Watchdogbitmap; 1592 /* fw returns qid, map it to BA stream */ 1593 if (bitmap[0] < MWL_BAQID_MAX) 1594 bitmap[0] = qid2ba[bitmap[0]]; 1595 } 1596 MWL_HAL_UNLOCK(mh); 1597 return retval; 1598 } 1599 1600 /* 1601 * Configure aggressive Ampdu rate mode. 1602 */ 1603 int 1604 mwl_hal_setaggampduratemode(struct mwl_hal *mh0, int mode, int threshold) 1605 { 1606 struct mwl_hal_priv *mh = MWLPRIV(mh0); 1607 HostCmd_FW_AMPDU_RETRY_RATEDROP_MODE *pCmd; 1608 int retval; 1609 1610 MWL_HAL_LOCK(mh); 1611 _CMD_SETUP(pCmd, HostCmd_FW_AMPDU_RETRY_RATEDROP_MODE, 1612 HostCmd_CMD_AMPDU_RETRY_RATEDROP_MODE); 1613 pCmd->Action = htole16(1); 1614 pCmd->Option = htole32(mode); 1615 pCmd->Threshold = htole32(threshold); 1616 1617 retval = mwlExecuteCmd(mh, HostCmd_CMD_AMPDU_RETRY_RATEDROP_MODE); 1618 MWL_HAL_UNLOCK(mh); 1619 return retval; 1620 } 1621 1622 int 1623 mwl_hal_getaggampduratemode(struct mwl_hal *mh0, int *mode, int *threshold) 1624 { 1625 struct mwl_hal_priv *mh = MWLPRIV(mh0); 1626 HostCmd_FW_AMPDU_RETRY_RATEDROP_MODE *pCmd; 1627 int retval; 1628 1629 MWL_HAL_LOCK(mh); 1630 _CMD_SETUP(pCmd, HostCmd_FW_AMPDU_RETRY_RATEDROP_MODE, 1631 HostCmd_CMD_AMPDU_RETRY_RATEDROP_MODE); 1632 pCmd->Action = htole16(0); 1633 1634 retval = mwlExecuteCmd(mh, HostCmd_CMD_AMPDU_RETRY_RATEDROP_MODE); 1635 MWL_HAL_UNLOCK(mh); 1636 *mode = le32toh(pCmd->Option); 1637 *threshold = le32toh(pCmd->Threshold); 1638 return retval; 1639 } 1640 1641 /* 1642 * Set CFEND status Enable/Disable 1643 */ 1644 int 1645 mwl_hal_setcfend(struct mwl_hal *mh0, int ena) 1646 { 1647 struct mwl_hal_priv *mh = MWLPRIV(mh0); 1648 HostCmd_CFEND_ENABLE *pCmd; 1649 int retval; 1650 1651 MWL_HAL_LOCK(mh); 1652 _CMD_SETUP(pCmd, HostCmd_CFEND_ENABLE, 1653 HostCmd_CMD_CFEND_ENABLE); 1654 pCmd->Enable = htole32(ena); 1655 1656 retval = mwlExecuteCmd(mh, HostCmd_CMD_CFEND_ENABLE); 1657 MWL_HAL_UNLOCK(mh); 1658 return retval; 1659 } 1660 1661 int 1662 mwl_hal_setdwds(struct mwl_hal *mh0, int ena) 1663 { 1664 HostCmd_DWDS_ENABLE *pCmd; 1665 struct mwl_hal_priv *mh = MWLPRIV(mh0); 1666 int retval; 1667 1668 MWL_HAL_LOCK(mh); 1669 _CMD_SETUP(pCmd, HostCmd_DWDS_ENABLE, HostCmd_CMD_DWDS_ENABLE); 1670 pCmd->Enable = htole32(ena); 1671 retval = mwlExecuteCmd(mh, HostCmd_CMD_DWDS_ENABLE); 1672 MWL_HAL_UNLOCK(mh); 1673 return retval; 1674 } 1675 1676 static void 1677 cvtPeerInfo(PeerInfo_t *to, const MWL_HAL_PEERINFO *from) 1678 { 1679 to->LegacyRateBitMap = htole32(from->LegacyRateBitMap); 1680 to->HTRateBitMap = htole32(from->HTRateBitMap); 1681 to->CapInfo = htole16(from->CapInfo); 1682 to->HTCapabilitiesInfo = htole16(from->HTCapabilitiesInfo); 1683 to->MacHTParamInfo = from->MacHTParamInfo; 1684 to->AddHtInfo.ControlChan = from->AddHtInfo.ControlChan; 1685 to->AddHtInfo.AddChan = from->AddHtInfo.AddChan; 1686 to->AddHtInfo.OpMode = htole16(from->AddHtInfo.OpMode); 1687 to->AddHtInfo.stbc = htole16(from->AddHtInfo.stbc); 1688 } 1689 1690 /* XXX station id must be in [0..63] */ 1691 int 1692 mwl_hal_newstation(struct mwl_hal_vap *vap, 1693 const uint8_t addr[IEEE80211_ADDR_LEN], uint16_t aid, uint16_t sid, 1694 const MWL_HAL_PEERINFO *peer, int isQosSta, int wmeInfo) 1695 { 1696 struct mwl_hal_priv *mh = MWLVAP(vap); 1697 HostCmd_FW_SET_NEW_STN *pCmd; 1698 int retval; 1699 1700 MWL_HAL_LOCK(mh); 1701 _VCMD_SETUP(vap, pCmd, HostCmd_FW_SET_NEW_STN, HostCmd_CMD_SET_NEW_STN); 1702 pCmd->AID = htole16(aid); 1703 pCmd->StnId = htole16(sid); 1704 pCmd->Action = htole16(0); /* SET */ 1705 if (peer != NULL) { 1706 /* NB: must fix up byte order */ 1707 cvtPeerInfo(&pCmd->PeerInfo, peer); 1708 } 1709 IEEE80211_ADDR_COPY(&pCmd->MacAddr[0], addr); 1710 pCmd->Qosinfo = wmeInfo; 1711 pCmd->isQosSta = (isQosSta != 0); 1712 1713 retval = mwlExecuteCmd(mh, HostCmd_CMD_SET_NEW_STN); 1714 if (retval == 0 && IEEE80211_ADDR_EQ(vap->mac, addr)) 1715 vap->flags |= MVF_STATION; 1716 MWL_HAL_UNLOCK(mh); 1717 return retval; 1718 } 1719 1720 int 1721 mwl_hal_delstation(struct mwl_hal_vap *vap, 1722 const uint8_t addr[IEEE80211_ADDR_LEN]) 1723 { 1724 struct mwl_hal_priv *mh = MWLVAP(vap); 1725 HostCmd_FW_SET_NEW_STN *pCmd; 1726 int retval, islocal; 1727 1728 MWL_HAL_LOCK(mh); 1729 islocal = IEEE80211_ADDR_EQ(vap->mac, addr); 1730 if (!islocal || (vap->flags & MVF_STATION)) { 1731 _VCMD_SETUP(vap, pCmd, HostCmd_FW_SET_NEW_STN, 1732 HostCmd_CMD_SET_NEW_STN); 1733 pCmd->Action = htole16(2); /* REMOVE */ 1734 IEEE80211_ADDR_COPY(&pCmd->MacAddr[0], addr); 1735 retval = mwlExecuteCmd(mh, HostCmd_CMD_SET_NEW_STN); 1736 if (islocal) 1737 vap->flags &= ~MVF_STATION; 1738 } else 1739 retval = 0; 1740 MWL_HAL_UNLOCK(mh); 1741 return retval; 1742 } 1743 1744 /* 1745 * Prod the firmware to age packets on station power 1746 * save queues and reap frames on the tx aggregation q's. 1747 */ 1748 int 1749 mwl_hal_setkeepalive(struct mwl_hal *mh0) 1750 { 1751 struct mwl_hal_priv *mh = MWLPRIV(mh0); 1752 HostCmd_FW_SET_KEEP_ALIVE_TICK *pCmd; 1753 int retval; 1754 1755 MWL_HAL_LOCK(mh); 1756 _CMD_SETUP(pCmd, HostCmd_FW_SET_KEEP_ALIVE_TICK, 1757 HostCmd_CMD_SET_KEEP_ALIVE); 1758 /* 1759 * NB: tick must be 0 to prod the f/w; 1760 * a non-zero value is a noop. 1761 */ 1762 pCmd->tick = 0; 1763 1764 retval = mwlExecuteCmd(mh, HostCmd_CMD_SET_KEEP_ALIVE); 1765 MWL_HAL_UNLOCK(mh); 1766 return retval; 1767 } 1768 1769 int 1770 mwl_hal_setapmode(struct mwl_hal_vap *vap, MWL_HAL_APMODE ApMode) 1771 { 1772 struct mwl_hal_priv *mh = MWLVAP(vap); 1773 HostCmd_FW_SET_APMODE *pCmd; 1774 int retval; 1775 1776 /* XXX validate ApMode? */ 1777 1778 MWL_HAL_LOCK(mh); 1779 _VCMD_SETUP(vap, pCmd, HostCmd_FW_SET_APMODE, HostCmd_CMD_SET_APMODE); 1780 pCmd->ApMode = ApMode; 1781 1782 retval = mwlExecuteCmd(mh, HostCmd_CMD_SET_APMODE); 1783 MWL_HAL_UNLOCK(mh); 1784 return retval; 1785 } 1786 1787 int 1788 mwl_hal_stop(struct mwl_hal_vap *vap) 1789 { 1790 struct mwl_hal_priv *mh = MWLVAP(vap); 1791 HostCmd_DS_BSS_START *pCmd; 1792 int retval; 1793 1794 MWL_HAL_LOCK(mh); 1795 if (vap->flags & MVF_RUNNING) { 1796 _VCMD_SETUP(vap, pCmd, HostCmd_DS_BSS_START, 1797 HostCmd_CMD_BSS_START); 1798 pCmd->Enable = htole32(HostCmd_ACT_GEN_OFF); 1799 retval = mwlExecuteCmd(mh, HostCmd_CMD_BSS_START); 1800 } else 1801 retval = 0; 1802 /* NB: mark !running regardless */ 1803 vap->flags &= ~MVF_RUNNING; 1804 MWL_HAL_UNLOCK(mh); 1805 return retval; 1806 } 1807 1808 int 1809 mwl_hal_start(struct mwl_hal_vap *vap) 1810 { 1811 struct mwl_hal_priv *mh = MWLVAP(vap); 1812 HostCmd_DS_BSS_START *pCmd; 1813 int retval; 1814 1815 MWL_HAL_LOCK(mh); 1816 _VCMD_SETUP(vap, pCmd, HostCmd_DS_BSS_START, HostCmd_CMD_BSS_START); 1817 pCmd->Enable = htole32(HostCmd_ACT_GEN_ON); 1818 1819 retval = mwlExecuteCmd(mh, HostCmd_CMD_BSS_START); 1820 if (retval == 0) 1821 vap->flags |= MVF_RUNNING; 1822 MWL_HAL_UNLOCK(mh); 1823 return retval; 1824 } 1825 1826 int 1827 mwl_hal_setgprot(struct mwl_hal *mh0, int prot) 1828 { 1829 struct mwl_hal_priv *mh = MWLPRIV(mh0); 1830 HostCmd_FW_SET_G_PROTECT_FLAG *pCmd; 1831 int retval; 1832 1833 MWL_HAL_LOCK(mh); 1834 _CMD_SETUP(pCmd, HostCmd_FW_SET_G_PROTECT_FLAG, 1835 HostCmd_CMD_SET_G_PROTECT_FLAG); 1836 pCmd->GProtectFlag = htole32(prot); 1837 1838 retval = mwlExecuteCmd(mh, HostCmd_CMD_SET_G_PROTECT_FLAG); 1839 MWL_HAL_UNLOCK(mh); 1840 return retval; 1841 } 1842 1843 int 1844 mwl_hal_setwmm(struct mwl_hal *mh0, int onoff) 1845 { 1846 struct mwl_hal_priv *mh = MWLPRIV(mh0); 1847 HostCmd_FW_SetWMMMode *pCmd; 1848 int retval; 1849 1850 MWL_HAL_LOCK(mh); 1851 _CMD_SETUP(pCmd, HostCmd_FW_SetWMMMode, 1852 HostCmd_CMD_SET_WMM_MODE); 1853 pCmd->Action = htole16(onoff); 1854 1855 retval = mwlExecuteCmd(mh, HostCmd_CMD_SET_WMM_MODE); 1856 MWL_HAL_UNLOCK(mh); 1857 return retval; 1858 } 1859 1860 int 1861 mwl_hal_setedcaparams(struct mwl_hal *mh0, uint8_t qnum, 1862 uint32_t CWmin, uint32_t CWmax, uint8_t AIFSN, uint16_t TXOPLimit) 1863 { 1864 struct mwl_hal_priv *mh = MWLPRIV(mh0); 1865 HostCmd_FW_SET_EDCA_PARAMS *pCmd; 1866 int retval; 1867 1868 MWL_HAL_LOCK(mh); 1869 _CMD_SETUP(pCmd, HostCmd_FW_SET_EDCA_PARAMS, 1870 HostCmd_CMD_SET_EDCA_PARAMS); 1871 /* 1872 * NB: CWmin and CWmax are always set. 1873 * TxOpLimit is set if bit 0x2 is marked in Action 1874 * AIFSN is set if bit 0x4 is marked in Action 1875 */ 1876 pCmd->Action = htole16(0xffff); /* NB: set everything */ 1877 pCmd->TxOP = htole16(TXOPLimit); 1878 pCmd->CWMax = htole32(CWmax); 1879 pCmd->CWMin = htole32(CWmin); 1880 pCmd->AIFSN = AIFSN; 1881 pCmd->TxQNum = qnum; /* XXX check */ 1882 1883 retval = mwlExecuteCmd(mh, HostCmd_CMD_SET_EDCA_PARAMS); 1884 MWL_HAL_UNLOCK(mh); 1885 return retval; 1886 } 1887 1888 /* XXX 0 = indoor, 1 = outdoor */ 1889 int 1890 mwl_hal_setrateadaptmode(struct mwl_hal *mh0, uint16_t mode) 1891 { 1892 struct mwl_hal_priv *mh = MWLPRIV(mh0); 1893 HostCmd_DS_SET_RATE_ADAPT_MODE *pCmd; 1894 int retval; 1895 1896 MWL_HAL_LOCK(mh); 1897 _CMD_SETUP(pCmd, HostCmd_DS_SET_RATE_ADAPT_MODE, 1898 HostCmd_CMD_SET_RATE_ADAPT_MODE); 1899 pCmd->Action = htole16(HostCmd_ACT_GEN_SET); 1900 pCmd->RateAdaptMode = htole16(mode); 1901 1902 retval = mwlExecuteCmd(mh, HostCmd_CMD_SET_RATE_ADAPT_MODE); 1903 MWL_HAL_UNLOCK(mh); 1904 return retval; 1905 } 1906 1907 int 1908 mwl_hal_setcsmode(struct mwl_hal *mh0, MWL_HAL_CSMODE csmode) 1909 { 1910 struct mwl_hal_priv *mh = MWLPRIV(mh0); 1911 HostCmd_DS_SET_LINKADAPT_CS_MODE *pCmd; 1912 int retval; 1913 1914 MWL_HAL_LOCK(mh); 1915 _CMD_SETUP(pCmd, HostCmd_DS_SET_LINKADAPT_CS_MODE, 1916 HostCmd_CMD_SET_LINKADAPT_CS_MODE); 1917 pCmd->Action = htole16(HostCmd_ACT_GEN_SET); 1918 pCmd->CSMode = htole16(csmode); 1919 1920 retval = mwlExecuteCmd(mh, HostCmd_CMD_SET_LINKADAPT_CS_MODE); 1921 MWL_HAL_UNLOCK(mh); 1922 return retval; 1923 } 1924 1925 int 1926 mwl_hal_setnprot(struct mwl_hal_vap *vap, MWL_HAL_HTPROTECT mode) 1927 { 1928 struct mwl_hal_priv *mh = MWLVAP(vap); 1929 HostCmd_FW_SET_N_PROTECT_FLAG *pCmd; 1930 int retval; 1931 1932 /* XXX validate mode */ 1933 MWL_HAL_LOCK(mh); 1934 _VCMD_SETUP(vap, pCmd, HostCmd_FW_SET_N_PROTECT_FLAG, 1935 HostCmd_CMD_SET_N_PROTECT_FLAG); 1936 pCmd->NProtectFlag = htole32(mode); 1937 1938 retval = mwlExecuteCmd(mh, HostCmd_CMD_SET_N_PROTECT_FLAG); 1939 MWL_HAL_UNLOCK(mh); 1940 return retval; 1941 } 1942 1943 int 1944 mwl_hal_setnprotmode(struct mwl_hal_vap *vap, uint8_t mode) 1945 { 1946 struct mwl_hal_priv *mh = MWLVAP(vap); 1947 HostCmd_FW_SET_N_PROTECT_OPMODE *pCmd; 1948 int retval; 1949 1950 MWL_HAL_LOCK(mh); 1951 _VCMD_SETUP(vap, pCmd, HostCmd_FW_SET_N_PROTECT_OPMODE, 1952 HostCmd_CMD_SET_N_PROTECT_OPMODE); 1953 pCmd->NProtectOpMode = mode; 1954 1955 retval = mwlExecuteCmd(mh, HostCmd_CMD_SET_N_PROTECT_OPMODE); 1956 MWL_HAL_UNLOCK(mh); 1957 return retval; 1958 } 1959 1960 int 1961 mwl_hal_setoptimizationlevel(struct mwl_hal *mh0, int level) 1962 { 1963 struct mwl_hal_priv *mh = MWLPRIV(mh0); 1964 HostCmd_FW_SET_OPTIMIZATION_LEVEL *pCmd; 1965 int retval; 1966 1967 MWL_HAL_LOCK(mh); 1968 _CMD_SETUP(pCmd, HostCmd_FW_SET_OPTIMIZATION_LEVEL, 1969 HostCmd_CMD_SET_OPTIMIZATION_LEVEL); 1970 pCmd->OptLevel = level; 1971 1972 retval = mwlExecuteCmd(mh, HostCmd_CMD_SET_OPTIMIZATION_LEVEL); 1973 MWL_HAL_UNLOCK(mh); 1974 return retval; 1975 } 1976 1977 int 1978 mwl_hal_setmimops(struct mwl_hal *mh0, const uint8_t addr[IEEE80211_ADDR_LEN], 1979 uint8_t enable, uint8_t mode) 1980 { 1981 struct mwl_hal_priv *mh = MWLPRIV(mh0); 1982 HostCmd_FW_SET_MIMOPSHT *pCmd; 1983 int retval; 1984 1985 MWL_HAL_LOCK(mh); 1986 _CMD_SETUP(pCmd, HostCmd_FW_SET_MIMOPSHT, HostCmd_CMD_SET_MIMOPSHT); 1987 IEEE80211_ADDR_COPY(pCmd->Addr, addr); 1988 pCmd->Enable = enable; 1989 pCmd->Mode = mode; 1990 1991 retval = mwlExecuteCmd(mh, HostCmd_CMD_SET_MIMOPSHT); 1992 MWL_HAL_UNLOCK(mh); 1993 return retval; 1994 } 1995 1996 static int 1997 mwlGetCalTable(struct mwl_hal_priv *mh, uint8_t annex, uint8_t index) 1998 { 1999 HostCmd_FW_GET_CALTABLE *pCmd; 2000 int retval; 2001 2002 MWL_HAL_LOCK_ASSERT(mh); 2003 2004 _CMD_SETUP(pCmd, HostCmd_FW_GET_CALTABLE, HostCmd_CMD_GET_CALTABLE); 2005 pCmd->annex = annex; 2006 pCmd->index = index; 2007 memset(pCmd->calTbl, 0, sizeof(pCmd->calTbl)); 2008 2009 retval = mwlExecuteCmd(mh, HostCmd_CMD_GET_CALTABLE); 2010 if (retval == 0 && 2011 pCmd->calTbl[0] != annex && annex != 0 && annex != 255) 2012 retval = EIO; 2013 return retval; 2014 } 2015 2016 /* 2017 * Calculate the max tx power from the channel's cal data. 2018 */ 2019 static void 2020 setmaxtxpow(struct mwl_hal_channel *hc, int i, int maxix) 2021 { 2022 hc->maxTxPow = hc->targetPowers[i]; 2023 for (i++; i < maxix; i++) 2024 if (hc->targetPowers[i] > hc->maxTxPow) 2025 hc->maxTxPow = hc->targetPowers[i]; 2026 } 2027 2028 /* 2029 * Construct channel info for 5GHz channels from cal data. 2030 */ 2031 static void 2032 get5Ghz(MWL_HAL_CHANNELINFO *ci, const uint8_t table[], int len) 2033 { 2034 int i, j, f, l, h; 2035 2036 l = 32000; 2037 h = 0; 2038 j = 0; 2039 for (i = 0; i < len; i += 4) { 2040 struct mwl_hal_channel *hc; 2041 2042 if (table[i] == 0) 2043 continue; 2044 f = 5000 + 5*table[i]; 2045 if (f < l) 2046 l = f; 2047 if (f > h) 2048 h = f; 2049 hc = &ci->channels[j]; 2050 hc->freq = f; 2051 hc->ieee = table[i]; 2052 memcpy(hc->targetPowers, &table[i], 4); 2053 setmaxtxpow(hc, 1, 4); /* NB: col 1 is the freq, skip*/ 2054 j++; 2055 } 2056 ci->nchannels = j; 2057 ci->freqLow = (l == 32000) ? 0 : l; 2058 ci->freqHigh = h; 2059 } 2060 2061 static uint16_t 2062 ieee2mhz(int chan) 2063 { 2064 if (chan == 14) 2065 return 2484; 2066 if (chan < 14) 2067 return 2407 + chan*5; 2068 return 2512 + (chan-15)*20; 2069 } 2070 2071 /* 2072 * Construct channel info for 2.4GHz channels from cal data. 2073 */ 2074 static void 2075 get2Ghz(MWL_HAL_CHANNELINFO *ci, const uint8_t table[], int len) 2076 { 2077 int i, j; 2078 2079 j = 0; 2080 for (i = 0; i < len; i += 4) { 2081 struct mwl_hal_channel *hc = &ci->channels[j]; 2082 hc->ieee = 1+j; 2083 hc->freq = ieee2mhz(1+j); 2084 memcpy(hc->targetPowers, &table[i], 4); 2085 setmaxtxpow(hc, 0, 4); 2086 j++; 2087 } 2088 ci->nchannels = j; 2089 ci->freqLow = ieee2mhz(1); 2090 ci->freqHigh = ieee2mhz(j); 2091 } 2092 2093 #undef DUMPCALDATA 2094 #ifdef DUMPCALDATA 2095 static void 2096 dumpcaldata(const char *name, const uint8_t *table, int n) 2097 { 2098 int i; 2099 printf("\n%s:\n", name); 2100 for (i = 0; i < n; i += 4) 2101 printf("[%2d] %3d %3d %3d %3d\n", i/4, table[i+0], table[i+1], table[i+2], table[i+3]); 2102 } 2103 #endif 2104 2105 static int 2106 mwlGetPwrCalTable(struct mwl_hal_priv *mh) 2107 { 2108 const uint8_t *data; 2109 MWL_HAL_CHANNELINFO *ci; 2110 int len; 2111 2112 MWL_HAL_LOCK(mh); 2113 /* NB: we hold the lock so it's ok to use cmdbuf */ 2114 data = ((const HostCmd_FW_GET_CALTABLE *) mh->mh_cmdbuf)->calTbl; 2115 if (mwlGetCalTable(mh, 33, 0) == 0) { 2116 len = (data[2] | (data[3] << 8)) - 12; 2117 if (len > PWTAGETRATETABLE20M) 2118 len = PWTAGETRATETABLE20M; 2119 #ifdef DUMPCALDATA 2120 dumpcaldata("2.4G 20M", &data[12], len);/*XXX*/ 2121 #endif 2122 get2Ghz(&mh->mh_20M, &data[12], len); 2123 } 2124 if (mwlGetCalTable(mh, 34, 0) == 0) { 2125 len = (data[2] | (data[3] << 8)) - 12; 2126 if (len > PWTAGETRATETABLE40M) 2127 len = PWTAGETRATETABLE40M; 2128 #ifdef DUMPCALDATA 2129 dumpcaldata("2.4G 40M", &data[12], len);/*XXX*/ 2130 #endif 2131 ci = &mh->mh_40M; 2132 get2Ghz(ci, &data[12], len); 2133 } 2134 if (mwlGetCalTable(mh, 35, 0) == 0) { 2135 len = (data[2] | (data[3] << 8)) - 20; 2136 if (len > PWTAGETRATETABLE20M_5G) 2137 len = PWTAGETRATETABLE20M_5G; 2138 #ifdef DUMPCALDATA 2139 dumpcaldata("5G 20M", &data[20], len);/*XXX*/ 2140 #endif 2141 get5Ghz(&mh->mh_20M_5G, &data[20], len); 2142 } 2143 if (mwlGetCalTable(mh, 36, 0) == 0) { 2144 len = (data[2] | (data[3] << 8)) - 20; 2145 if (len > PWTAGETRATETABLE40M_5G) 2146 len = PWTAGETRATETABLE40M_5G; 2147 #ifdef DUMPCALDATA 2148 dumpcaldata("5G 40M", &data[20], len);/*XXX*/ 2149 #endif 2150 ci = &mh->mh_40M_5G; 2151 get5Ghz(ci, &data[20], len); 2152 } 2153 mh->mh_flags |= MHF_CALDATA; 2154 MWL_HAL_UNLOCK(mh); 2155 return 0; 2156 } 2157 2158 int 2159 mwl_hal_getregioncode(struct mwl_hal *mh0, uint8_t *countryCode) 2160 { 2161 struct mwl_hal_priv *mh = MWLPRIV(mh0); 2162 int retval; 2163 2164 MWL_HAL_LOCK(mh); 2165 retval = mwlGetCalTable(mh, 0, 0); 2166 if (retval == 0) { 2167 const HostCmd_FW_GET_CALTABLE *pCmd = 2168 (const HostCmd_FW_GET_CALTABLE *) mh->mh_cmdbuf; 2169 *countryCode = pCmd->calTbl[16]; 2170 } 2171 MWL_HAL_UNLOCK(mh); 2172 return retval; 2173 } 2174 2175 int 2176 mwl_hal_setpromisc(struct mwl_hal *mh0, int ena) 2177 { 2178 struct mwl_hal_priv *mh = MWLPRIV(mh0); 2179 uint32_t v; 2180 2181 MWL_HAL_LOCK(mh); 2182 v = RD4(mh, MACREG_REG_PROMISCUOUS); 2183 WR4(mh, MACREG_REG_PROMISCUOUS, ena ? v | 1 : v &~ 1); 2184 MWL_HAL_UNLOCK(mh); 2185 return 0; 2186 } 2187 2188 int 2189 mwl_hal_getpromisc(struct mwl_hal *mh0) 2190 { 2191 struct mwl_hal_priv *mh = MWLPRIV(mh0); 2192 uint32_t v; 2193 2194 MWL_HAL_LOCK(mh); 2195 v = RD4(mh, MACREG_REG_PROMISCUOUS); 2196 MWL_HAL_UNLOCK(mh); 2197 return (v & 1) != 0; 2198 } 2199 2200 int 2201 mwl_hal_GetBeacon(struct mwl_hal *mh0, uint8_t *pBcn, uint16_t *pLen) 2202 { 2203 struct mwl_hal_priv *mh = MWLPRIV(mh0); 2204 HostCmd_FW_GET_BEACON *pCmd; 2205 int retval; 2206 2207 MWL_HAL_LOCK(mh); 2208 _CMD_SETUP(pCmd, HostCmd_FW_GET_BEACON, HostCmd_CMD_GET_BEACON); 2209 pCmd->Bcnlen = htole16(0); 2210 2211 retval = mwlExecuteCmd(mh, HostCmd_CMD_GET_BEACON); 2212 if (retval == 0) { 2213 /* XXX bounds check */ 2214 memcpy(pBcn, &pCmd->Bcn, pCmd->Bcnlen); 2215 *pLen = pCmd->Bcnlen; 2216 } 2217 MWL_HAL_UNLOCK(mh); 2218 return retval; 2219 } 2220 2221 int 2222 mwl_hal_SetRifs(struct mwl_hal *mh0, uint8_t QNum) 2223 { 2224 struct mwl_hal_priv *mh = MWLPRIV(mh0); 2225 HostCmd_FW_SET_RIFS *pCmd; 2226 int retval; 2227 2228 MWL_HAL_LOCK(mh); 2229 _CMD_SETUP(pCmd, HostCmd_FW_SET_RIFS, HostCmd_CMD_SET_RIFS); 2230 pCmd->QNum = QNum; 2231 2232 retval = mwlExecuteCmd(mh, HostCmd_CMD_SET_RIFS); 2233 MWL_HAL_UNLOCK(mh); 2234 return retval; 2235 } 2236 2237 /* 2238 * Diagnostic api's for set/get registers. 2239 */ 2240 2241 static int 2242 getRFReg(struct mwl_hal_priv *mh, int flag, uint32_t reg, uint32_t *val) 2243 { 2244 HostCmd_DS_RF_REG_ACCESS *pCmd; 2245 int retval; 2246 2247 MWL_HAL_LOCK(mh); 2248 _CMD_SETUP(pCmd, HostCmd_DS_RF_REG_ACCESS, HostCmd_CMD_RF_REG_ACCESS); 2249 pCmd->Offset = htole16(reg); 2250 pCmd->Action = htole16(flag); 2251 pCmd->Value = htole32(*val); 2252 2253 retval = mwlExecuteCmd(mh, HostCmd_CMD_RF_REG_ACCESS); 2254 if (retval == 0) 2255 *val = pCmd->Value; 2256 MWL_HAL_UNLOCK(mh); 2257 return retval; 2258 } 2259 2260 static int 2261 getBBReg(struct mwl_hal_priv *mh, int flag, uint32_t reg, uint32_t *val) 2262 { 2263 HostCmd_DS_BBP_REG_ACCESS *pCmd; 2264 int retval; 2265 2266 MWL_HAL_LOCK(mh); 2267 _CMD_SETUP(pCmd, HostCmd_DS_BBP_REG_ACCESS, HostCmd_CMD_BBP_REG_ACCESS); 2268 pCmd->Offset = htole16(reg); 2269 pCmd->Action = htole16(flag); 2270 pCmd->Value = htole32(*val); 2271 2272 retval = mwlExecuteCmd(mh, HostCmd_CMD_BBP_REG_ACCESS); 2273 if (retval == 0) 2274 *val = pCmd->Value; 2275 MWL_HAL_UNLOCK(mh); 2276 return retval; 2277 } 2278 2279 static u_int 2280 mwl_hal_getregdump(struct mwl_hal_priv *mh, const MWL_DIAG_REGRANGE *regs, 2281 void *dstbuf, int space) 2282 { 2283 uint32_t *dp = dstbuf; 2284 int i; 2285 2286 for (i = 0; space >= 2*sizeof(uint32_t); i++) { 2287 u_int r = regs[i].start; 2288 u_int e = regs[i].end; 2289 *dp++ = (r<<16) | e; 2290 space -= sizeof(uint32_t); 2291 do { 2292 if (MWL_DIAG_ISMAC(r)) 2293 *dp = RD4(mh, r); 2294 else if (MWL_DIAG_ISBB(r)) 2295 getBBReg(mh, HostCmd_ACT_GEN_READ, 2296 r - MWL_DIAG_BASE_BB, dp); 2297 else if (MWL_DIAG_ISRF(r)) 2298 getRFReg(mh, HostCmd_ACT_GEN_READ, 2299 r - MWL_DIAG_BASE_RF, dp); 2300 else if (r < 0x1000 || r == MACREG_REG_FW_PRESENT) 2301 *dp = RD4(mh, r); 2302 else 2303 *dp = 0xffffffff; 2304 dp++; 2305 r += sizeof(uint32_t); 2306 space -= sizeof(uint32_t); 2307 } while (r <= e && space >= sizeof(uint32_t)); 2308 } 2309 return (char *) dp - (char *) dstbuf; 2310 } 2311 2312 int 2313 mwl_hal_getdiagstate(struct mwl_hal *mh0, int request, 2314 const void *args, uint32_t argsize, 2315 void **result, uint32_t *resultsize) 2316 { 2317 struct mwl_hal_priv *mh = MWLPRIV(mh0); 2318 2319 switch (request) { 2320 case MWL_DIAG_CMD_REVS: 2321 *result = &mh->mh_revs; 2322 *resultsize = sizeof(mh->mh_revs); 2323 return 1; 2324 case MWL_DIAG_CMD_REGS: 2325 *resultsize = mwl_hal_getregdump(mh, args, *result, *resultsize); 2326 return 1; 2327 case MWL_DIAG_CMD_HOSTCMD: { 2328 FWCmdHdr *pCmd = (FWCmdHdr *) &mh->mh_cmdbuf[0]; 2329 int retval; 2330 2331 MWL_HAL_LOCK(mh); 2332 memcpy(pCmd, args, argsize); 2333 retval = mwlExecuteCmd(mh, le16toh(pCmd->Cmd)); 2334 *result = (*resultsize != 0) ? pCmd : NULL; 2335 MWL_HAL_UNLOCK(mh); 2336 return (retval == 0); 2337 } 2338 case MWL_DIAG_CMD_FWLOAD: 2339 if (mwl_hal_fwload(mh0, __DECONST(void *, args))) { 2340 device_printf(mh->mh_dev, "problem loading fw image\n"); 2341 return 0; 2342 } 2343 return 1; 2344 } 2345 return 0; 2346 } 2347 2348 /* 2349 * Low level firmware cmd block handshake support. 2350 */ 2351 2352 static void 2353 mwlSendCmd(struct mwl_hal_priv *mh) 2354 { 2355 uint32_t dummy; 2356 2357 bus_dmamap_sync(mh->mh_dmat, mh->mh_dmamap, 2358 BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE); 2359 2360 WR4(mh, MACREG_REG_GEN_PTR, mh->mh_cmdaddr); 2361 dummy = RD4(mh, MACREG_REG_INT_CODE); 2362 2363 WR4(mh, MACREG_REG_H2A_INTERRUPT_EVENTS, MACREG_H2ARIC_BIT_DOOR_BELL); 2364 } 2365 2366 static int 2367 mwlWaitForCmdComplete(struct mwl_hal_priv *mh, uint16_t cmdCode) 2368 { 2369 #define MAX_WAIT_FW_COMPLETE_ITERATIONS 10000 2370 int i; 2371 2372 for (i = 0; i < MAX_WAIT_FW_COMPLETE_ITERATIONS; i++) { 2373 if (mh->mh_cmdbuf[0] == le16toh(cmdCode)) 2374 return 1; 2375 DELAY(1*1000); 2376 } 2377 return 0; 2378 #undef MAX_WAIT_FW_COMPLETE_ITERATIONS 2379 } 2380 2381 static int 2382 mwlExecuteCmd(struct mwl_hal_priv *mh, unsigned short cmd) 2383 { 2384 2385 MWL_HAL_LOCK_ASSERT(mh); 2386 2387 if ((mh->mh_flags & MHF_FWHANG) && 2388 (mh->mh_debug & MWL_HAL_DEBUG_IGNHANG) == 0) { 2389 #ifdef MWLHAL_DEBUG 2390 device_printf(mh->mh_dev, "firmware hung, skipping cmd %s\n", 2391 mwlcmdname(cmd)); 2392 #else 2393 device_printf(mh->mh_dev, "firmware hung, skipping cmd 0x%x\n", 2394 cmd); 2395 #endif 2396 return ENXIO; 2397 } 2398 if (RD4(mh, MACREG_REG_INT_CODE) == 0xffffffff) { 2399 device_printf(mh->mh_dev, "%s: device not present!\n", 2400 __func__); 2401 return EIO; 2402 } 2403 #ifdef MWLHAL_DEBUG 2404 if (mh->mh_debug & MWL_HAL_DEBUG_SENDCMD) 2405 dumpresult(mh, 0); 2406 #endif 2407 mwlSendCmd(mh); 2408 if (!mwlWaitForCmdComplete(mh, 0x8000 | cmd)) { 2409 #ifdef MWLHAL_DEBUG 2410 device_printf(mh->mh_dev, 2411 "timeout waiting for f/w cmd %s\n", mwlcmdname(cmd)); 2412 #else 2413 device_printf(mh->mh_dev, 2414 "timeout waiting for f/w cmd 0x%x\n", cmd); 2415 #endif 2416 mh->mh_flags |= MHF_FWHANG; 2417 return ETIMEDOUT; 2418 } 2419 bus_dmamap_sync(mh->mh_dmat, mh->mh_dmamap, 2420 BUS_DMASYNC_POSTREAD | BUS_DMASYNC_POSTWRITE); 2421 #ifdef MWLHAL_DEBUG 2422 if (mh->mh_debug & MWL_HAL_DEBUG_CMDDONE) 2423 dumpresult(mh, 1); 2424 #endif 2425 return 0; 2426 } 2427 2428 /* 2429 * Firmware download support. 2430 */ 2431 #define FW_DOWNLOAD_BLOCK_SIZE 256 2432 #define FW_CHECK_USECS (5*1000) /* 5ms */ 2433 #define FW_MAX_NUM_CHECKS 200 2434 2435 #if 0 2436 /* XXX read f/w from file */ 2437 #include <dev/mwl/mwlbootfw.h> 2438 #include <dev/mwl/mwl88W8363fw.h> 2439 #endif 2440 2441 static void 2442 mwlFwReset(struct mwl_hal_priv *mh) 2443 { 2444 if (RD4(mh, MACREG_REG_INT_CODE) == 0xffffffff) { 2445 device_printf(mh->mh_dev, "%s: device not present!\n", 2446 __func__); 2447 return; 2448 } 2449 WR4(mh, MACREG_REG_H2A_INTERRUPT_EVENTS, ISR_RESET); 2450 mh->mh_flags &= ~MHF_FWHANG; 2451 } 2452 2453 static void 2454 mwlTriggerPciCmd(struct mwl_hal_priv *mh) 2455 { 2456 uint32_t dummy; 2457 2458 bus_dmamap_sync(mh->mh_dmat, mh->mh_dmamap, BUS_DMASYNC_PREWRITE); 2459 2460 WR4(mh, MACREG_REG_GEN_PTR, mh->mh_cmdaddr); 2461 dummy = RD4(mh, MACREG_REG_INT_CODE); 2462 2463 WR4(mh, MACREG_REG_INT_CODE, 0x00); 2464 dummy = RD4(mh, MACREG_REG_INT_CODE); 2465 2466 WR4(mh, MACREG_REG_H2A_INTERRUPT_EVENTS, MACREG_H2ARIC_BIT_DOOR_BELL); 2467 dummy = RD4(mh, MACREG_REG_INT_CODE); 2468 } 2469 2470 static int 2471 mwlWaitFor(struct mwl_hal_priv *mh, uint32_t val) 2472 { 2473 int i; 2474 2475 for (i = 0; i < FW_MAX_NUM_CHECKS; i++) { 2476 DELAY(FW_CHECK_USECS); 2477 if (RD4(mh, MACREG_REG_INT_CODE) == val) 2478 return 1; 2479 } 2480 return 0; 2481 } 2482 2483 /* 2484 * Firmware block xmit when talking to the boot-rom. 2485 */ 2486 static int 2487 mwlSendBlock(struct mwl_hal_priv *mh, int bsize, const void *data, size_t dsize) 2488 { 2489 mh->mh_cmdbuf[0] = htole16(HostCmd_CMD_CODE_DNLD); 2490 mh->mh_cmdbuf[1] = htole16(bsize); 2491 memcpy(&mh->mh_cmdbuf[4], data , dsize); 2492 mwlTriggerPciCmd(mh); 2493 /* XXX 2000 vs 200 */ 2494 if (mwlWaitFor(mh, MACREG_INT_CODE_CMD_FINISHED)) { 2495 WR4(mh, MACREG_REG_INT_CODE, 0); 2496 return 1; 2497 } 2498 device_printf(mh->mh_dev, 2499 "%s: timeout waiting for CMD_FINISHED, INT_CODE 0x%x\n", 2500 __func__, RD4(mh, MACREG_REG_INT_CODE)); 2501 return 0; 2502 } 2503 2504 /* 2505 * Firmware block xmit when talking to the 1st-stage loader. 2506 */ 2507 static int 2508 mwlSendBlock2(struct mwl_hal_priv *mh, const void *data, size_t dsize) 2509 { 2510 memcpy(&mh->mh_cmdbuf[0], data, dsize); 2511 mwlTriggerPciCmd(mh); 2512 if (mwlWaitFor(mh, MACREG_INT_CODE_CMD_FINISHED)) { 2513 WR4(mh, MACREG_REG_INT_CODE, 0); 2514 return 1; 2515 } 2516 device_printf(mh->mh_dev, 2517 "%s: timeout waiting for CMD_FINISHED, INT_CODE 0x%x\n", 2518 __func__, RD4(mh, MACREG_REG_INT_CODE)); 2519 return 0; 2520 } 2521 2522 static void 2523 mwlPokeSdramController(struct mwl_hal_priv *mh, int SDRAMSIZE_Addr) 2524 { 2525 /** Set up sdram controller for superflyv2 **/ 2526 WR4(mh, 0x00006014, 0x33); 2527 WR4(mh, 0x00006018, 0xa3a2632); 2528 WR4(mh, 0x00006010, SDRAMSIZE_Addr); 2529 } 2530 2531 int 2532 mwl_hal_fwload(struct mwl_hal *mh0, void *fwargs) 2533 { 2534 struct mwl_hal_priv *mh = MWLPRIV(mh0); 2535 const char *fwname = "mw88W8363fw"; 2536 const char *fwbootname = "mwlboot"; 2537 const struct firmware *fwboot = NULL; 2538 const struct firmware *fw; 2539 /* XXX get from firmware header */ 2540 uint32_t FwReadySignature = HostCmd_SOFTAP_FWRDY_SIGNATURE; 2541 uint32_t OpMode = HostCmd_SOFTAP_MODE; 2542 const uint8_t *fp, *ep; 2543 const uint8_t *fmdata; 2544 uint32_t blocksize, nbytes, fmsize; 2545 int i, error, ntries; 2546 2547 fw = firmware_get(fwname); 2548 if (fw == NULL) { 2549 device_printf(mh->mh_dev, 2550 "could not load firmware image %s\n", fwname); 2551 return ENXIO; 2552 } 2553 fmdata = fw->data; 2554 fmsize = fw->datasize; 2555 if (fmsize < 4) { 2556 device_printf(mh->mh_dev, "firmware image %s too small\n", 2557 fwname); 2558 error = ENXIO; 2559 goto bad2; 2560 } 2561 if (fmdata[0] == 0x01 && fmdata[1] == 0x00 && 2562 fmdata[2] == 0x00 && fmdata[3] == 0x00) { 2563 /* 2564 * 2-stage load, get the boot firmware. 2565 */ 2566 fwboot = firmware_get(fwbootname); 2567 if (fwboot == NULL) { 2568 device_printf(mh->mh_dev, 2569 "could not load firmware image %s\n", fwbootname); 2570 error = ENXIO; 2571 goto bad2; 2572 } 2573 } else 2574 fwboot = NULL; 2575 2576 mwlFwReset(mh); 2577 2578 WR4(mh, MACREG_REG_A2H_INTERRUPT_CLEAR_SEL, MACREG_A2HRIC_BIT_MASK); 2579 WR4(mh, MACREG_REG_A2H_INTERRUPT_CAUSE, 0x00); 2580 WR4(mh, MACREG_REG_A2H_INTERRUPT_MASK, 0x00); 2581 WR4(mh, MACREG_REG_A2H_INTERRUPT_STATUS_MASK, MACREG_A2HRIC_BIT_MASK); 2582 if (mh->mh_SDRAMSIZE_Addr != 0) { 2583 /** Set up sdram controller for superflyv2 **/ 2584 mwlPokeSdramController(mh, mh->mh_SDRAMSIZE_Addr); 2585 } 2586 device_printf(mh->mh_dev, "load %s firmware image (%u bytes)\n", 2587 fwname, fmsize); 2588 if (fwboot != NULL) { 2589 /* 2590 * Do 2-stage load. The 1st stage loader is setup 2591 * with the bootrom loader then we load the real 2592 * image using a different handshake. With this 2593 * mechanism the firmware is segmented into chunks 2594 * that have a CRC. If a chunk is incorrect we'll 2595 * be told to retransmit. 2596 */ 2597 /* XXX assumes hlpimage fits in a block */ 2598 /* NB: zero size block indicates download is finished */ 2599 if (!mwlSendBlock(mh, fwboot->datasize, fwboot->data, fwboot->datasize) || 2600 !mwlSendBlock(mh, 0, NULL, 0)) { 2601 error = ETIMEDOUT; 2602 goto bad; 2603 } 2604 DELAY(200*FW_CHECK_USECS); 2605 if (mh->mh_SDRAMSIZE_Addr != 0) { 2606 /** Set up sdram controller for superflyv2 **/ 2607 mwlPokeSdramController(mh, mh->mh_SDRAMSIZE_Addr); 2608 } 2609 nbytes = ntries = 0; /* NB: silence compiler */ 2610 for (fp = fmdata, ep = fp + fmsize; fp < ep; ) { 2611 WR4(mh, MACREG_REG_INT_CODE, 0); 2612 blocksize = RD4(mh, MACREG_REG_SCRATCH); 2613 if (blocksize == 0) /* download complete */ 2614 break; 2615 if (blocksize > 0x00000c00) { 2616 error = EINVAL; 2617 goto bad; 2618 } 2619 if ((blocksize & 0x1) == 0) { 2620 /* block successfully downloaded, advance */ 2621 fp += nbytes; 2622 ntries = 0; 2623 } else { 2624 if (++ntries > 2) { 2625 /* 2626 * Guard against f/w telling us to 2627 * retry infinitely. 2628 */ 2629 error = ELOOP; 2630 goto bad; 2631 } 2632 /* clear NAK bit/flag */ 2633 blocksize &= ~0x1; 2634 } 2635 if (blocksize > ep - fp) { 2636 /* XXX this should not happen, what to do? */ 2637 blocksize = ep - fp; 2638 } 2639 nbytes = blocksize; 2640 if (!mwlSendBlock2(mh, fp, nbytes)) { 2641 error = ETIMEDOUT; 2642 goto bad; 2643 } 2644 } 2645 } else { 2646 for (fp = fmdata, ep = fp + fmsize; fp < ep;) { 2647 nbytes = ep - fp; 2648 if (nbytes > FW_DOWNLOAD_BLOCK_SIZE) 2649 nbytes = FW_DOWNLOAD_BLOCK_SIZE; 2650 if (!mwlSendBlock(mh, FW_DOWNLOAD_BLOCK_SIZE, fp, nbytes)) { 2651 error = EIO; 2652 goto bad; 2653 } 2654 fp += nbytes; 2655 } 2656 } 2657 /* done with firmware... */ 2658 if (fwboot != NULL) 2659 firmware_put(fwboot, FIRMWARE_UNLOAD); 2660 firmware_put(fw, FIRMWARE_UNLOAD); 2661 /* 2662 * Wait for firmware to startup; we monitor the 2663 * INT_CODE register waiting for a signature to 2664 * written back indicating it's ready to go. 2665 */ 2666 mh->mh_cmdbuf[1] = 0; 2667 /* 2668 * XXX WAR for mfg fw download 2669 */ 2670 if (OpMode != HostCmd_STA_MODE) 2671 mwlTriggerPciCmd(mh); 2672 for (i = 0; i < FW_MAX_NUM_CHECKS; i++) { 2673 WR4(mh, MACREG_REG_GEN_PTR, OpMode); 2674 DELAY(FW_CHECK_USECS); 2675 if (RD4(mh, MACREG_REG_INT_CODE) == FwReadySignature) { 2676 WR4(mh, MACREG_REG_INT_CODE, 0x00); 2677 return mwlResetHalState(mh); 2678 } 2679 } 2680 return ETIMEDOUT; 2681 bad: 2682 mwlFwReset(mh); 2683 bad2: 2684 /* done with firmware... */ 2685 if (fwboot != NULL) 2686 firmware_put(fwboot, FIRMWARE_UNLOAD); 2687 firmware_put(fw, FIRMWARE_UNLOAD); 2688 return error; 2689 } 2690 2691 #ifdef MWLHAL_DEBUG 2692 static const char * 2693 mwlcmdname(int cmd) 2694 { 2695 static char buf[12]; 2696 #define CMD(x) case HostCmd_CMD_##x: return #x 2697 switch (cmd) { 2698 CMD(CODE_DNLD); 2699 CMD(GET_HW_SPEC); 2700 CMD(SET_HW_SPEC); 2701 CMD(MAC_MULTICAST_ADR); 2702 CMD(802_11_GET_STAT); 2703 CMD(MAC_REG_ACCESS); 2704 CMD(BBP_REG_ACCESS); 2705 CMD(RF_REG_ACCESS); 2706 CMD(802_11_RADIO_CONTROL); 2707 CMD(802_11_RF_TX_POWER); 2708 CMD(802_11_RF_ANTENNA); 2709 CMD(SET_BEACON); 2710 CMD(SET_RF_CHANNEL); 2711 CMD(SET_AID); 2712 CMD(SET_INFRA_MODE); 2713 CMD(SET_G_PROTECT_FLAG); 2714 CMD(802_11_RTS_THSD); 2715 CMD(802_11_SET_SLOT); 2716 CMD(SET_EDCA_PARAMS); 2717 CMD(802_11H_DETECT_RADAR); 2718 CMD(SET_WMM_MODE); 2719 CMD(HT_GUARD_INTERVAL); 2720 CMD(SET_FIXED_RATE); 2721 CMD(SET_LINKADAPT_CS_MODE); 2722 CMD(SET_MAC_ADDR); 2723 CMD(SET_RATE_ADAPT_MODE); 2724 CMD(BSS_START); 2725 CMD(SET_NEW_STN); 2726 CMD(SET_KEEP_ALIVE); 2727 CMD(SET_APMODE); 2728 CMD(SET_SWITCH_CHANNEL); 2729 CMD(UPDATE_ENCRYPTION); 2730 CMD(BASTREAM); 2731 CMD(SET_RIFS); 2732 CMD(SET_N_PROTECT_FLAG); 2733 CMD(SET_N_PROTECT_OPMODE); 2734 CMD(SET_OPTIMIZATION_LEVEL); 2735 CMD(GET_CALTABLE); 2736 CMD(SET_MIMOPSHT); 2737 CMD(GET_BEACON); 2738 CMD(SET_REGION_CODE); 2739 CMD(SET_POWERSAVESTATION); 2740 CMD(SET_TIM); 2741 CMD(GET_TIM); 2742 CMD(GET_SEQNO); 2743 CMD(DWDS_ENABLE); 2744 CMD(AMPDU_RETRY_RATEDROP_MODE); 2745 CMD(CFEND_ENABLE); 2746 } 2747 snprintf(buf, sizeof(buf), "0x%x", cmd); 2748 return buf; 2749 #undef CMD 2750 } 2751 2752 static void 2753 dumpresult(struct mwl_hal_priv *mh, int showresult) 2754 { 2755 const FWCmdHdr *h = (const FWCmdHdr *)mh->mh_cmdbuf; 2756 const uint8_t *cp; 2757 int len, i; 2758 2759 len = le16toh(h->Length); 2760 #ifdef MWL_MBSS_SUPPORT 2761 device_printf(mh->mh_dev, "Cmd %s Length %d SeqNum %d MacId %d", 2762 mwlcmdname(le16toh(h->Cmd) &~ 0x8000), len, h->SeqNum, h->MacId); 2763 #else 2764 device_printf(mh->mh_dev, "Cmd %s Length %d SeqNum %d", 2765 mwlcmdname(le16toh(h->Cmd) &~ 0x8000), len, le16toh(h->SeqNum)); 2766 #endif 2767 if (showresult) { 2768 const char *results[] = 2769 { "OK", "ERROR", "NOT_SUPPORT", "PENDING", "BUSY", 2770 "PARTIAL_DATA" }; 2771 int result = le16toh(h->Result); 2772 2773 if (result <= HostCmd_RESULT_PARTIAL_DATA) 2774 printf(" Result %s", results[result]); 2775 else 2776 printf(" Result %d", result); 2777 } 2778 cp = (const uint8_t *)h; 2779 for (i = 0; i < len; i++) { 2780 if ((i % 16) == 0) 2781 printf("\n%02x", cp[i]); 2782 else 2783 printf(" %02x", cp[i]); 2784 } 2785 printf("\n"); 2786 } 2787 #endif /* MWLHAL_DEBUG */ 2788