1 /*- 2 * Copyright (c) 2007 Marvell Semiconductor, Inc. 3 * Copyright (c) 2007 Sam Leffler, Errno Consulting 4 * Copyright (c) 2008 Weongyo Jeong <weongyo@freebsd.org> 5 * All rights reserved. 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 1. Redistributions of source code must retain the above copyright 11 * notice, this list of conditions and the following disclaimer, 12 * without modification. 13 * 2. Redistributions in binary form must reproduce at minimum a disclaimer 14 * similar to the "NO WARRANTY" disclaimer below ("Disclaimer") and any 15 * redistribution must be conditioned upon including a substantially 16 * similar Disclaimer requirement for further binary redistribution. 17 * 18 * NO WARRANTY 19 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 20 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 21 * LIMITED TO, THE IMPLIED WARRANTIES OF NONINFRINGEMENT, MERCHANTIBILITY 22 * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL 23 * THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, 24 * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 25 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 26 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER 27 * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 28 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF 29 * THE POSSIBILITY OF SUCH DAMAGES. 30 */ 31 32 #include <sys/cdefs.h> 33 #ifdef __FreeBSD__ 34 __FBSDID("$FreeBSD$"); 35 #endif 36 37 #include <sys/param.h> 38 #include <sys/systm.h> 39 #include <sys/endian.h> 40 #include <sys/kernel.h> 41 #include <sys/malloc.h> 42 #include <sys/firmware.h> 43 #include <sys/socket.h> 44 45 #include <machine/bus.h> 46 #include <sys/bus.h> 47 48 #include <net/if.h> 49 #include <net/if_var.h> 50 #include <net/if_dl.h> 51 #include <net/if_media.h> 52 #include <net/ethernet.h> 53 54 #include <net80211/ieee80211_var.h> 55 56 #include <dev/malo/if_malo.h> 57 58 #define MALO_WAITOK 1 59 #define MALO_NOWAIT 0 60 61 #define _CMD_SETUP(pCmd, _type, _cmd) do { \ 62 pCmd = (_type *)&mh->mh_cmdbuf[0]; \ 63 memset(pCmd, 0, sizeof(_type)); \ 64 pCmd->cmdhdr.cmd = htole16(_cmd); \ 65 pCmd->cmdhdr.length = htole16(sizeof(_type)); \ 66 } while (0) 67 68 static __inline uint32_t 69 malo_hal_read4(struct malo_hal *mh, bus_size_t off) 70 { 71 return bus_space_read_4(mh->mh_iot, mh->mh_ioh, off); 72 } 73 74 static __inline void 75 malo_hal_write4(struct malo_hal *mh, bus_size_t off, uint32_t val) 76 { 77 bus_space_write_4(mh->mh_iot, mh->mh_ioh, off, val); 78 } 79 80 static void 81 malo_hal_load_cb(void *arg, bus_dma_segment_t *segs, int nsegs, int error) 82 { 83 bus_addr_t *paddr = (bus_addr_t*) arg; 84 85 KASSERT(error == 0, ("error %u on bus_dma callback", error)); 86 *paddr = segs->ds_addr; 87 } 88 89 /* 90 * Setup for communication with the device. We allocate 91 * a command buffer and map it for bus dma use. The pci 92 * device id is used to identify whether the device has 93 * SRAM on it (in which case f/w download must include a 94 * memory controller reset). All bus i/o operations happen 95 * in BAR 1; the driver passes in the tag and handle we need. 96 */ 97 struct malo_hal * 98 malo_hal_attach(device_t dev, uint16_t devid, 99 bus_space_handle_t ioh, bus_space_tag_t iot, bus_dma_tag_t tag) 100 { 101 int error; 102 struct malo_hal *mh; 103 104 mh = malloc(sizeof(struct malo_hal), M_DEVBUF, M_NOWAIT | M_ZERO); 105 if (mh == NULL) 106 return NULL; 107 108 mh->mh_dev = dev; 109 mh->mh_ioh = ioh; 110 mh->mh_iot = iot; 111 112 snprintf(mh->mh_mtxname, sizeof(mh->mh_mtxname), 113 "%s_hal", device_get_nameunit(dev)); 114 mtx_init(&mh->mh_mtx, mh->mh_mtxname, NULL, MTX_DEF); 115 116 /* 117 * Allocate the command buffer and map into the address 118 * space of the h/w. We request "coherent" memory which 119 * will be uncached on some architectures. 120 */ 121 error = bus_dma_tag_create(tag, /* parent */ 122 PAGE_SIZE, 0, /* alignment, bounds */ 123 BUS_SPACE_MAXADDR_32BIT, /* lowaddr */ 124 BUS_SPACE_MAXADDR, /* highaddr */ 125 NULL, NULL, /* filter, filterarg */ 126 MALO_CMDBUF_SIZE, /* maxsize */ 127 1, /* nsegments */ 128 MALO_CMDBUF_SIZE, /* maxsegsize */ 129 BUS_DMA_ALLOCNOW, /* flags */ 130 NULL, /* lockfunc */ 131 NULL, /* lockarg */ 132 &mh->mh_dmat); 133 if (error != 0) { 134 device_printf(dev, "unable to allocate memory for cmd tag, " 135 "error %u\n", error); 136 goto fail; 137 } 138 139 /* allocate descriptors */ 140 error = bus_dmamap_create(mh->mh_dmat, BUS_DMA_NOWAIT, &mh->mh_dmamap); 141 if (error != 0) { 142 device_printf(dev, "unable to create dmamap for cmd buffers, " 143 "error %u\n", error); 144 goto fail; 145 } 146 147 error = bus_dmamem_alloc(mh->mh_dmat, (void**) &mh->mh_cmdbuf, 148 BUS_DMA_NOWAIT | BUS_DMA_COHERENT, 149 &mh->mh_dmamap); 150 if (error != 0) { 151 device_printf(dev, "unable to allocate memory for cmd buffer, " 152 "error %u\n", error); 153 goto fail; 154 } 155 156 error = bus_dmamap_load(mh->mh_dmat, mh->mh_dmamap, 157 mh->mh_cmdbuf, MALO_CMDBUF_SIZE, 158 malo_hal_load_cb, &mh->mh_cmdaddr, 159 BUS_DMA_NOWAIT); 160 if (error != 0) { 161 device_printf(dev, "unable to load cmd buffer, error %u\n", 162 error); 163 goto fail; 164 } 165 166 return (mh); 167 168 fail: 169 if (mh->mh_dmamap != NULL) { 170 bus_dmamap_unload(mh->mh_dmat, mh->mh_dmamap); 171 if (mh->mh_cmdbuf != NULL) 172 bus_dmamem_free(mh->mh_dmat, mh->mh_cmdbuf, 173 mh->mh_dmamap); 174 bus_dmamap_destroy(mh->mh_dmat, mh->mh_dmamap); 175 } 176 if (mh->mh_dmat) 177 bus_dma_tag_destroy(mh->mh_dmat); 178 free(mh, M_DEVBUF); 179 180 return (NULL); 181 } 182 183 /* 184 * Low level firmware cmd block handshake support. 185 */ 186 187 static void 188 malo_hal_send_cmd(struct malo_hal *mh) 189 { 190 uint32_t dummy; 191 192 bus_dmamap_sync(mh->mh_dmat, mh->mh_dmamap, 193 BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE); 194 195 malo_hal_write4(mh, MALO_REG_GEN_PTR, mh->mh_cmdaddr); 196 dummy = malo_hal_read4(mh, MALO_REG_INT_CODE); 197 198 malo_hal_write4(mh, MALO_REG_H2A_INTERRUPT_EVENTS, 199 MALO_H2ARIC_BIT_DOOR_BELL); 200 } 201 202 static int 203 malo_hal_waitforcmd(struct malo_hal *mh, uint16_t cmd) 204 { 205 #define MAX_WAIT_FW_COMPLETE_ITERATIONS 10000 206 int i; 207 208 for (i = 0; i < MAX_WAIT_FW_COMPLETE_ITERATIONS; i++) { 209 if (mh->mh_cmdbuf[0] == le16toh(cmd)) 210 return 1; 211 212 DELAY(1 * 1000); 213 } 214 215 return 0; 216 #undef MAX_WAIT_FW_COMPLETE_ITERATIONS 217 } 218 219 static int 220 malo_hal_execute_cmd(struct malo_hal *mh, unsigned short cmd) 221 { 222 MALO_HAL_LOCK_ASSERT(mh); 223 224 if ((mh->mh_flags & MHF_FWHANG) && 225 (mh->mh_debug & MALO_HAL_DEBUG_IGNHANG) == 0) { 226 device_printf(mh->mh_dev, "firmware hung, skipping cmd 0x%x\n", 227 cmd); 228 return ENXIO; 229 } 230 231 if (malo_hal_read4(mh, MALO_REG_INT_CODE) == 0xffffffff) { 232 device_printf(mh->mh_dev, "%s: device not present!\n", 233 __func__); 234 return EIO; 235 } 236 237 malo_hal_send_cmd(mh); 238 if (!malo_hal_waitforcmd(mh, cmd | 0x8000)) { 239 device_printf(mh->mh_dev, 240 "timeout waiting for f/w cmd 0x%x\n", cmd); 241 mh->mh_flags |= MHF_FWHANG; 242 return ETIMEDOUT; 243 } 244 245 bus_dmamap_sync(mh->mh_dmat, mh->mh_dmamap, 246 BUS_DMASYNC_POSTREAD | BUS_DMASYNC_POSTWRITE); 247 248 return 0; 249 } 250 251 static int 252 malo_hal_get_cal_table(struct malo_hal *mh, uint8_t annex, uint8_t index) 253 { 254 struct malo_cmd_caltable *cmd; 255 int ret; 256 257 MALO_HAL_LOCK_ASSERT(mh); 258 259 _CMD_SETUP(cmd, struct malo_cmd_caltable, MALO_HOSTCMD_GET_CALTABLE); 260 cmd->annex = annex; 261 cmd->index = index; 262 263 ret = malo_hal_execute_cmd(mh, MALO_HOSTCMD_GET_CALTABLE); 264 if (ret == 0 && cmd->caltbl[0] != annex && annex != 0 && annex != 255) 265 ret = EIO; 266 return ret; 267 } 268 269 static int 270 malo_hal_get_pwrcal_table(struct malo_hal *mh, struct malo_hal_caldata *cal) 271 { 272 const uint8_t *data; 273 int len; 274 275 MALO_HAL_LOCK(mh); 276 /* NB: we hold the lock so it's ok to use cmdbuf */ 277 data = ((const struct malo_cmd_caltable *) mh->mh_cmdbuf)->caltbl; 278 if (malo_hal_get_cal_table(mh, 33, 0) == 0) { 279 len = (data[2] | (data[3] << 8)) - 12; 280 /* XXX validate len */ 281 memcpy(cal->pt_ratetable_20m, &data[12], len); 282 } 283 mh->mh_flags |= MHF_CALDATA; 284 MALO_HAL_UNLOCK(mh); 285 286 return 0; 287 } 288 289 /* 290 * Reset internal state after a firmware download. 291 */ 292 static int 293 malo_hal_resetstate(struct malo_hal *mh) 294 { 295 /* 296 * Fetch cal data for later use. 297 * XXX may want to fetch other stuff too. 298 */ 299 if ((mh->mh_flags & MHF_CALDATA) == 0) 300 malo_hal_get_pwrcal_table(mh, &mh->mh_caldata); 301 return 0; 302 } 303 304 static void 305 malo_hal_fw_reset(struct malo_hal *mh) 306 { 307 308 if (malo_hal_read4(mh, MALO_REG_INT_CODE) == 0xffffffff) { 309 device_printf(mh->mh_dev, "%s: device not present!\n", 310 __func__); 311 return; 312 } 313 314 malo_hal_write4(mh, MALO_REG_H2A_INTERRUPT_EVENTS, MALO_ISR_RESET); 315 mh->mh_flags &= ~MHF_FWHANG; 316 } 317 318 static void 319 malo_hal_trigger_pcicmd(struct malo_hal *mh) 320 { 321 uint32_t dummy; 322 323 bus_dmamap_sync(mh->mh_dmat, mh->mh_dmamap, BUS_DMASYNC_PREWRITE); 324 325 malo_hal_write4(mh, MALO_REG_GEN_PTR, mh->mh_cmdaddr); 326 dummy = malo_hal_read4(mh, MALO_REG_INT_CODE); 327 328 malo_hal_write4(mh, MALO_REG_INT_CODE, 0x00); 329 dummy = malo_hal_read4(mh, MALO_REG_INT_CODE); 330 331 malo_hal_write4(mh, MALO_REG_H2A_INTERRUPT_EVENTS, 332 MALO_H2ARIC_BIT_DOOR_BELL); 333 dummy = malo_hal_read4(mh, MALO_REG_INT_CODE); 334 } 335 336 static int 337 malo_hal_waitfor(struct malo_hal *mh, uint32_t val) 338 { 339 int i; 340 341 for (i = 0; i < MALO_FW_MAX_NUM_CHECKS; i++) { 342 DELAY(MALO_FW_CHECK_USECS); 343 if (malo_hal_read4(mh, MALO_REG_INT_CODE) == val) 344 return 0; 345 } 346 347 return -1; 348 } 349 350 /* 351 * Firmware block xmit when talking to the boot-rom. 352 */ 353 static int 354 malo_hal_send_helper(struct malo_hal *mh, int bsize, 355 const void *data, size_t dsize, int waitfor) 356 { 357 mh->mh_cmdbuf[0] = htole16(MALO_HOSTCMD_CODE_DNLD); 358 mh->mh_cmdbuf[1] = htole16(bsize); 359 memcpy(&mh->mh_cmdbuf[4], data , dsize); 360 361 malo_hal_trigger_pcicmd(mh); 362 363 if (waitfor == MALO_NOWAIT) 364 goto pass; 365 366 /* XXX 2000 vs 200 */ 367 if (malo_hal_waitfor(mh, MALO_INT_CODE_CMD_FINISHED) != 0) { 368 device_printf(mh->mh_dev, 369 "%s: timeout waiting for CMD_FINISHED, INT_CODE 0x%x\n", 370 __func__, malo_hal_read4(mh, MALO_REG_INT_CODE)); 371 372 return ETIMEDOUT; 373 } 374 375 pass: 376 malo_hal_write4(mh, MALO_REG_INT_CODE, 0); 377 378 return (0); 379 } 380 381 static int 382 malo_hal_fwload_helper(struct malo_hal *mh, char *helper) 383 { 384 const struct firmware *fw; 385 int error; 386 387 fw = firmware_get(helper); 388 if (fw == NULL) { 389 device_printf(mh->mh_dev, "could not read microcode %s!\n", 390 helper); 391 return (EIO); 392 } 393 394 device_printf(mh->mh_dev, "load %s firmware image (%zu bytes)\n", 395 helper, fw->datasize); 396 397 error = malo_hal_send_helper(mh, fw->datasize, fw->data, fw->datasize, 398 MALO_WAITOK); 399 if (error != 0) 400 goto fail; 401 402 /* tell the card we're done and... */ 403 error = malo_hal_send_helper(mh, 0, NULL, 0, MALO_NOWAIT); 404 405 fail: 406 firmware_put(fw, FIRMWARE_UNLOAD); 407 408 return (error); 409 } 410 411 /* 412 * Firmware block xmit when talking to the 1st-stage loader. 413 */ 414 static int 415 malo_hal_send_main(struct malo_hal *mh, const void *data, size_t dsize, 416 uint16_t seqnum, int waitfor) 417 { 418 mh->mh_cmdbuf[0] = htole16(MALO_HOSTCMD_CODE_DNLD); 419 mh->mh_cmdbuf[1] = htole16(dsize); 420 mh->mh_cmdbuf[2] = htole16(seqnum); 421 mh->mh_cmdbuf[3] = 0; 422 memcpy(&mh->mh_cmdbuf[4], data, dsize); 423 424 malo_hal_trigger_pcicmd(mh); 425 426 if (waitfor == MALO_NOWAIT) 427 goto pass; 428 429 if (malo_hal_waitfor(mh, MALO_INT_CODE_CMD_FINISHED) != 0) { 430 device_printf(mh->mh_dev, 431 "%s: timeout waiting for CMD_FINISHED, INT_CODE 0x%x\n", 432 __func__, malo_hal_read4(mh, MALO_REG_INT_CODE)); 433 434 return ETIMEDOUT; 435 } 436 437 pass: 438 malo_hal_write4(mh, MALO_REG_INT_CODE, 0); 439 440 return 0; 441 } 442 443 static int 444 malo_hal_fwload_main(struct malo_hal *mh, char *firmware) 445 { 446 const struct firmware *fw; 447 const uint8_t *fp; 448 int error; 449 size_t count; 450 uint16_t seqnum; 451 uint32_t blocksize; 452 453 error = 0; 454 455 fw = firmware_get(firmware); 456 if (fw == NULL) { 457 device_printf(mh->mh_dev, "could not read firmware %s!\n", 458 firmware); 459 return (EIO); 460 } 461 462 device_printf(mh->mh_dev, "load %s firmware image (%zu bytes)\n", 463 firmware, fw->datasize); 464 465 seqnum = 1; 466 for (count = 0; count < fw->datasize; count += blocksize) { 467 blocksize = MIN(256, fw->datasize - count); 468 fp = (const uint8_t *)fw->data + count; 469 470 error = malo_hal_send_main(mh, fp, blocksize, seqnum++, 471 MALO_NOWAIT); 472 if (error != 0) 473 goto fail; 474 DELAY(500); 475 } 476 477 /* 478 * send a command with size 0 to tell that the firmware has been 479 * uploaded 480 */ 481 error = malo_hal_send_main(mh, NULL, 0, seqnum++, MALO_NOWAIT); 482 DELAY(100); 483 484 fail: 485 firmware_put(fw, FIRMWARE_UNLOAD); 486 487 return (error); 488 } 489 490 int 491 malo_hal_fwload(struct malo_hal *mh, char *helper, char *firmware) 492 { 493 int error, i; 494 uint32_t fwreadysig, opmode; 495 496 /* 497 * NB: now malo(4) supports only STA mode. It will be better if it 498 * supports AP mode. 499 */ 500 fwreadysig = MALO_HOSTCMD_STA_FWRDY_SIGNATURE; 501 opmode = MALO_HOSTCMD_STA_MODE; 502 503 malo_hal_fw_reset(mh); 504 505 malo_hal_write4(mh, MALO_REG_A2H_INTERRUPT_CLEAR_SEL, 506 MALO_A2HRIC_BIT_MASK); 507 malo_hal_write4(mh, MALO_REG_A2H_INTERRUPT_CAUSE, 0x00); 508 malo_hal_write4(mh, MALO_REG_A2H_INTERRUPT_MASK, 0x00); 509 malo_hal_write4(mh, MALO_REG_A2H_INTERRUPT_STATUS_MASK, 510 MALO_A2HRIC_BIT_MASK); 511 512 error = malo_hal_fwload_helper(mh, helper); 513 if (error != 0) { 514 device_printf(mh->mh_dev, "failed to load bootrom loader.\n"); 515 goto fail; 516 } 517 518 DELAY(200 * MALO_FW_CHECK_USECS); 519 520 error = malo_hal_fwload_main(mh, firmware); 521 if (error != 0) { 522 device_printf(mh->mh_dev, "failed to load firmware.\n"); 523 goto fail; 524 } 525 526 /* 527 * Wait for firmware to startup; we monitor the INT_CODE register 528 * waiting for a signature to written back indicating it's ready to go. 529 */ 530 mh->mh_cmdbuf[1] = 0; 531 532 if (opmode != MALO_HOSTCMD_STA_MODE) 533 malo_hal_trigger_pcicmd(mh); 534 535 for (i = 0; i < MALO_FW_MAX_NUM_CHECKS; i++) { 536 malo_hal_write4(mh, MALO_REG_GEN_PTR, opmode); 537 DELAY(MALO_FW_CHECK_USECS); 538 if (malo_hal_read4(mh, MALO_REG_INT_CODE) == fwreadysig) { 539 malo_hal_write4(mh, MALO_REG_INT_CODE, 0x00); 540 return malo_hal_resetstate(mh); 541 } 542 } 543 544 return ETIMEDOUT; 545 fail: 546 malo_hal_fw_reset(mh); 547 548 return (error); 549 } 550 551 /* 552 * Return "hw specs". Note this must be the first cmd MUST be done after 553 * a firmware download or the f/w will lockup. 554 */ 555 int 556 malo_hal_gethwspecs(struct malo_hal *mh, struct malo_hal_hwspec *hw) 557 { 558 struct malo_cmd_get_hwspec *cmd; 559 int ret; 560 561 MALO_HAL_LOCK(mh); 562 563 _CMD_SETUP(cmd, struct malo_cmd_get_hwspec, MALO_HOSTCMD_GET_HW_SPEC); 564 memset(&cmd->permaddr[0], 0xff, IEEE80211_ADDR_LEN); 565 cmd->ul_fw_awakecookie = htole32((unsigned int)mh->mh_cmdaddr + 2048); 566 567 ret = malo_hal_execute_cmd(mh, MALO_HOSTCMD_GET_HW_SPEC); 568 if (ret == 0) { 569 IEEE80211_ADDR_COPY(hw->macaddr, cmd->permaddr); 570 hw->wcbbase[0] = le32toh(cmd->wcbbase0) & 0x0000ffff; 571 hw->wcbbase[1] = le32toh(cmd->wcbbase1) & 0x0000ffff; 572 hw->wcbbase[2] = le32toh(cmd->wcbbase2) & 0x0000ffff; 573 hw->wcbbase[3] = le32toh(cmd->wcbbase3) & 0x0000ffff; 574 hw->rxdesc_read = le32toh(cmd->rxpdrd_ptr)& 0x0000ffff; 575 hw->rxdesc_write = le32toh(cmd->rxpdwr_ptr)& 0x0000ffff; 576 hw->regioncode = le16toh(cmd->regioncode) & 0x00ff; 577 hw->fw_releasenum = le32toh(cmd->fw_releasenum); 578 hw->maxnum_wcb = le16toh(cmd->num_wcb); 579 hw->maxnum_mcaddr = le16toh(cmd->num_mcastaddr); 580 hw->num_antenna = le16toh(cmd->num_antenna); 581 hw->hwversion = cmd->version; 582 hw->hostinterface = cmd->hostif; 583 } 584 585 MALO_HAL_UNLOCK(mh); 586 587 return ret; 588 } 589 590 void 591 malo_hal_detach(struct malo_hal *mh) 592 { 593 594 bus_dmamem_free(mh->mh_dmat, mh->mh_cmdbuf, mh->mh_dmamap); 595 bus_dmamap_destroy(mh->mh_dmat, mh->mh_dmamap); 596 bus_dma_tag_destroy(mh->mh_dmat); 597 mtx_destroy(&mh->mh_mtx); 598 free(mh, M_DEVBUF); 599 } 600 601 /* 602 * Configure antenna use. Takes effect immediately. 603 * 604 * XXX tx antenna setting ignored 605 * XXX rx antenna setting should always be 3 (for now) 606 */ 607 int 608 malo_hal_setantenna(struct malo_hal *mh, enum malo_hal_antenna dirset, int ant) 609 { 610 struct malo_cmd_rf_antenna *cmd; 611 int ret; 612 613 if (!(dirset == MHA_ANTENNATYPE_RX || dirset == MHA_ANTENNATYPE_TX)) 614 return EINVAL; 615 616 MALO_HAL_LOCK(mh); 617 618 _CMD_SETUP(cmd, struct malo_cmd_rf_antenna, 619 MALO_HOSTCMD_802_11_RF_ANTENNA); 620 cmd->action = htole16(dirset); 621 if (ant == 0) { /* default to all/both antennae */ 622 /* XXX never reach now. */ 623 ant = 3; 624 } 625 cmd->mode = htole16(ant); 626 627 ret = malo_hal_execute_cmd(mh, MALO_HOSTCMD_802_11_RF_ANTENNA); 628 629 MALO_HAL_UNLOCK(mh); 630 631 return ret; 632 } 633 634 /* 635 * Configure radio. Takes effect immediately. 636 * 637 * XXX preamble installed after set fixed rate cmd 638 */ 639 int 640 malo_hal_setradio(struct malo_hal *mh, int onoff, 641 enum malo_hal_preamble preamble) 642 { 643 struct malo_cmd_radio_control *cmd; 644 int ret; 645 646 MALO_HAL_LOCK(mh); 647 648 _CMD_SETUP(cmd, struct malo_cmd_radio_control, 649 MALO_HOSTCMD_802_11_RADIO_CONTROL); 650 cmd->action = htole16(MALO_HOSTCMD_ACT_GEN_SET); 651 if (onoff == 0) 652 cmd->control = 0; 653 else 654 cmd->control = htole16(preamble); 655 cmd->radio_on = htole16(onoff); 656 657 ret = malo_hal_execute_cmd(mh, MALO_HOSTCMD_802_11_RADIO_CONTROL); 658 659 MALO_HAL_UNLOCK(mh); 660 661 return ret; 662 } 663 664 /* 665 * Set the interrupt mask. 666 */ 667 void 668 malo_hal_intrset(struct malo_hal *mh, uint32_t mask) 669 { 670 671 malo_hal_write4(mh, MALO_REG_A2H_INTERRUPT_MASK, 0); 672 (void)malo_hal_read4(mh, MALO_REG_INT_CODE); 673 674 mh->mh_imask = mask; 675 malo_hal_write4(mh, MALO_REG_A2H_INTERRUPT_MASK, mask); 676 (void)malo_hal_read4(mh, MALO_REG_INT_CODE); 677 } 678 679 int 680 malo_hal_setchannel(struct malo_hal *mh, const struct malo_hal_channel *chan) 681 { 682 struct malo_cmd_fw_set_rf_channel *cmd; 683 int ret; 684 685 MALO_HAL_LOCK(mh); 686 687 _CMD_SETUP(cmd, struct malo_cmd_fw_set_rf_channel, 688 MALO_HOSTCMD_SET_RF_CHANNEL); 689 cmd->action = htole16(MALO_HOSTCMD_ACT_GEN_SET); 690 cmd->cur_channel = chan->channel; 691 692 ret = malo_hal_execute_cmd(mh, MALO_HOSTCMD_SET_RF_CHANNEL); 693 694 MALO_HAL_UNLOCK(mh); 695 696 return ret; 697 } 698 699 int 700 malo_hal_settxpower(struct malo_hal *mh, const struct malo_hal_channel *c) 701 { 702 struct malo_cmd_rf_tx_power *cmd; 703 const struct malo_hal_caldata *cal = &mh->mh_caldata; 704 uint8_t chan = c->channel; 705 uint16_t pow; 706 int i, idx, ret; 707 708 MALO_HAL_LOCK(mh); 709 710 _CMD_SETUP(cmd, struct malo_cmd_rf_tx_power, 711 MALO_HOSTCMD_802_11_RF_TX_POWER); 712 cmd->action = htole16(MALO_HOSTCMD_ACT_GEN_SET_LIST); 713 for (i = 0; i < 4; i++) { 714 idx = (chan - 1) * 4 + i; 715 pow = cal->pt_ratetable_20m[idx]; 716 cmd->power_levellist[i] = htole16(pow); 717 } 718 ret = malo_hal_execute_cmd(mh, MALO_HOSTCMD_802_11_RF_TX_POWER); 719 720 MALO_HAL_UNLOCK(mh); 721 722 return ret; 723 } 724 725 int 726 malo_hal_setpromisc(struct malo_hal *mh, int enable) 727 { 728 /* XXX need host cmd */ 729 return 0; 730 } 731 732 int 733 malo_hal_setassocid(struct malo_hal *mh, 734 const uint8_t bssid[IEEE80211_ADDR_LEN], uint16_t associd) 735 { 736 struct malo_cmd_fw_set_aid *cmd; 737 int ret; 738 739 MALO_HAL_LOCK(mh); 740 741 _CMD_SETUP(cmd, struct malo_cmd_fw_set_aid, 742 MALO_HOSTCMD_SET_AID); 743 cmd->cmdhdr.seqnum = 1; 744 cmd->associd = htole16(associd); 745 IEEE80211_ADDR_COPY(&cmd->macaddr[0], bssid); 746 747 ret = malo_hal_execute_cmd(mh, MALO_HOSTCMD_SET_AID); 748 MALO_HAL_UNLOCK(mh); 749 return ret; 750 } 751 752 /* 753 * Kick the firmware to tell it there are new tx descriptors 754 * for processing. The driver says what h/w q has work in 755 * case the f/w ever gets smarter. 756 */ 757 void 758 malo_hal_txstart(struct malo_hal *mh, int qnum) 759 { 760 bus_space_write_4(mh->mh_iot, mh->mh_ioh, 761 MALO_REG_H2A_INTERRUPT_EVENTS, MALO_H2ARIC_BIT_PPA_READY); 762 (void) bus_space_read_4(mh->mh_iot, mh->mh_ioh, MALO_REG_INT_CODE); 763 } 764 765 /* 766 * Return the current ISR setting and clear the cause. 767 */ 768 void 769 malo_hal_getisr(struct malo_hal *mh, uint32_t *status) 770 { 771 uint32_t cause; 772 773 cause = bus_space_read_4(mh->mh_iot, mh->mh_ioh, 774 MALO_REG_A2H_INTERRUPT_CAUSE); 775 if (cause == 0xffffffff) { /* card removed */ 776 cause = 0; 777 } else if (cause != 0) { 778 /* clear cause bits */ 779 bus_space_write_4(mh->mh_iot, mh->mh_ioh, 780 MALO_REG_A2H_INTERRUPT_CAUSE, cause &~ mh->mh_imask); 781 (void) bus_space_read_4(mh->mh_iot, mh->mh_ioh, 782 MALO_REG_INT_CODE); 783 cause &= mh->mh_imask; 784 } 785 786 *status = cause; 787 } 788 789 /* 790 * Callback from the driver on a cmd done interrupt. Nothing to do right 791 * now as we spin waiting for cmd completion. 792 */ 793 void 794 malo_hal_cmddone(struct malo_hal *mh) 795 { 796 /* NB : do nothing. */ 797 } 798 799 int 800 malo_hal_prescan(struct malo_hal *mh) 801 { 802 struct malo_cmd_prescan *cmd; 803 int ret; 804 805 MALO_HAL_LOCK(mh); 806 807 _CMD_SETUP(cmd, struct malo_cmd_prescan, MALO_HOSTCMD_SET_PRE_SCAN); 808 cmd->cmdhdr.seqnum = 1; 809 810 ret = malo_hal_execute_cmd(mh, MALO_HOSTCMD_SET_PRE_SCAN); 811 812 MALO_HAL_UNLOCK(mh); 813 814 return ret; 815 } 816 817 int 818 malo_hal_postscan(struct malo_hal *mh, uint8_t *macaddr, uint8_t ibsson) 819 { 820 struct malo_cmd_postscan *cmd; 821 int ret; 822 823 MALO_HAL_LOCK(mh); 824 825 _CMD_SETUP(cmd, struct malo_cmd_postscan, MALO_HOSTCMD_SET_POST_SCAN); 826 cmd->cmdhdr.seqnum = 1; 827 cmd->isibss = htole32(ibsson); 828 IEEE80211_ADDR_COPY(&cmd->bssid[0], macaddr); 829 830 ret = malo_hal_execute_cmd(mh, MALO_HOSTCMD_SET_POST_SCAN); 831 832 MALO_HAL_UNLOCK(mh); 833 834 return ret; 835 } 836 837 int 838 malo_hal_set_slot(struct malo_hal *mh, int is_short) 839 { 840 int ret; 841 struct malo_cmd_fw_setslot *cmd; 842 843 MALO_HAL_LOCK(mh); 844 845 _CMD_SETUP(cmd, struct malo_cmd_fw_setslot, MALO_HOSTCMD_SET_SLOT); 846 cmd->action = htole16(MALO_HOSTCMD_ACT_GEN_SET); 847 cmd->slot = (is_short == 1 ? 1 : 0); 848 849 ret = malo_hal_execute_cmd(mh, MALO_HOSTCMD_SET_SLOT); 850 851 MALO_HAL_UNLOCK(mh); 852 853 return ret; 854 } 855 856 int 857 malo_hal_set_rate(struct malo_hal *mh, uint16_t curmode, uint8_t rate) 858 { 859 int i, ret; 860 struct malo_cmd_set_rate *cmd; 861 862 MALO_HAL_LOCK(mh); 863 864 _CMD_SETUP(cmd, struct malo_cmd_set_rate, MALO_HOSTCMD_SET_RATE); 865 cmd->aprates[0] = 2; 866 cmd->aprates[1] = 4; 867 cmd->aprates[2] = 11; 868 cmd->aprates[3] = 22; 869 if (curmode == IEEE80211_MODE_11G) { 870 cmd->aprates[4] = 0; /* XXX reserved? */ 871 cmd->aprates[5] = 12; 872 cmd->aprates[6] = 18; 873 cmd->aprates[7] = 24; 874 cmd->aprates[8] = 36; 875 cmd->aprates[9] = 48; 876 cmd->aprates[10] = 72; 877 cmd->aprates[11] = 96; 878 cmd->aprates[12] = 108; 879 } 880 881 if (rate != 0) { 882 /* fixed rate */ 883 for (i = 0; i < 13; i++) { 884 if (cmd->aprates[i] == rate) { 885 cmd->rateindex = i; 886 cmd->dataratetype = 1; 887 break; 888 } 889 } 890 } 891 892 ret = malo_hal_execute_cmd(mh, MALO_HOSTCMD_SET_RATE); 893 894 MALO_HAL_UNLOCK(mh); 895 896 return ret; 897 } 898 899 int 900 malo_hal_setmcast(struct malo_hal *mh, int nmc, const uint8_t macs[]) 901 { 902 struct malo_cmd_mcast *cmd; 903 int ret; 904 905 if (nmc > MALO_HAL_MCAST_MAX) 906 return EINVAL; 907 908 MALO_HAL_LOCK(mh); 909 910 _CMD_SETUP(cmd, struct malo_cmd_mcast, MALO_HOSTCMD_MAC_MULTICAST_ADR); 911 memcpy(cmd->maclist, macs, nmc * IEEE80211_ADDR_LEN); 912 cmd->numaddr = htole16(nmc); 913 cmd->action = htole16(0xffff); 914 915 ret = malo_hal_execute_cmd(mh, MALO_HOSTCMD_MAC_MULTICAST_ADR); 916 917 MALO_HAL_UNLOCK(mh); 918 919 return ret; 920 } 921