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