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