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