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