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