acx100.c revision 1.22
1/* $OpenBSD: acx100.c,v 1.22 2012/10/27 16:13:28 claudio Exp $ */ 2 3/* 4 * Copyright (c) 2006 Jonathan Gray <jsg@openbsd.org> 5 * 6 * Permission to use, copy, modify, and distribute this software for any 7 * purpose with or without fee is hereby granted, provided that the above 8 * copyright notice and this permission notice appear in all copies. 9 * 10 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 11 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 12 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 13 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 14 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 15 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 16 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 17 */ 18 19/* 20 * Copyright (c) 2006 The DragonFly Project. All rights reserved. 21 * 22 * This code is derived from software contributed to The DragonFly Project 23 * by Sepherosa Ziehau <sepherosa@gmail.com> 24 * 25 * Redistribution and use in source and binary forms, with or without 26 * modification, are permitted provided that the following conditions 27 * are met: 28 * 29 * 1. Redistributions of source code must retain the above copyright 30 * notice, this list of conditions and the following disclaimer. 31 * 2. Redistributions in binary form must reproduce the above copyright 32 * notice, this list of conditions and the following disclaimer in 33 * the documentation and/or other materials provided with the 34 * distribution. 35 * 3. Neither the name of The DragonFly Project nor the names of its 36 * contributors may be used to endorse or promote products derived 37 * from this software without specific, prior written permission. 38 * 39 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 40 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 41 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS 42 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE 43 * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, 44 * INCIDENTAL, SPECIAL, EXEMPLARY OR CONSEQUENTIAL DAMAGES (INCLUDING, 45 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 46 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED 47 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 48 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT 49 * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 50 * SUCH DAMAGE. 51 */ 52 53#include <sys/param.h> 54#include <sys/systm.h> 55#include <sys/mbuf.h> 56#include <sys/endian.h> 57#include <sys/socket.h> 58#include <sys/device.h> 59 60#include <machine/bus.h> 61 62#include <net/if.h> 63#include <net/if_arp.h> 64#include <net/if_media.h> 65 66#ifdef INET 67#include <netinet/in.h> 68#include <netinet/if_ether.h> 69#endif 70 71#include <net80211/ieee80211_var.h> 72#include <net80211/ieee80211_amrr.h> 73#include <net80211/ieee80211_radiotap.h> 74 75#include <dev/pci/pcireg.h> 76 77#include <dev/ic/acxvar.h> 78#include <dev/ic/acxreg.h> 79 80#define ACX100_CONF_FW_RING 0x0003 81#define ACX100_CONF_MEMOPT 0x0005 82 83#define ACX100_INTR_ENABLE (ACXRV_INTR_TX_FINI | ACXRV_INTR_RX_FINI) 84/* 85 * XXX do we really care about following interrupts? 86 * 87 * ACXRV_INTR_INFO | ACXRV_INTR_SCAN_FINI 88 */ 89 90#define ACX100_INTR_DISABLE (uint16_t)~(ACXRV_INTR_UNKN) 91 92#define ACX100_RATE(rate) ((rate) * 5) 93 94#define ACX100_TXPOWER 18 95#define ACX100_GPIO_POWER_LED 0x0800 96#define ACX100_EE_EADDR_OFS 0x1a 97 98#define ACX100_FW_TXRING_SIZE (ACX_TX_DESC_CNT * sizeof(struct acx_fw_txdesc)) 99#define ACX100_FW_RXRING_SIZE (ACX_RX_DESC_CNT * sizeof(struct acx_fw_rxdesc)) 100 101int acx100_init(struct acx_softc *); 102int acx100_init_wep(struct acx_softc *); 103int acx100_init_tmplt(struct acx_softc *); 104int acx100_init_fw_ring(struct acx_softc *); 105int acx100_init_memory(struct acx_softc *); 106void acx100_init_fw_txring(struct acx_softc *, uint32_t); 107void acx100_init_fw_rxring(struct acx_softc *, uint32_t); 108int acx100_read_config(struct acx_softc *, struct acx_config *); 109int acx100_write_config(struct acx_softc *, struct acx_config *); 110int acx100_set_txpower(struct acx_softc *); 111void acx100_set_fw_txdesc_rate(struct acx_softc *, 112 struct acx_txbuf *, int); 113void acx100_set_bss_join_param(struct acx_softc *, void *, int); 114int acx100_set_wepkey(struct acx_softc *, struct ieee80211_key *, int); 115void acx100_proc_wep_rxbuf(struct acx_softc *, struct mbuf *, int *); 116 117/* 118 * NOTE: 119 * Following structs' fields are little endian 120 */ 121struct acx100_bss_join { 122 uint8_t dtim_intvl; 123 uint8_t basic_rates; 124 uint8_t all_rates; 125} __packed; 126 127struct acx100_conf_fw_ring { 128 struct acx_conf confcom; 129 uint32_t fw_ring_size; /* total size of fw (tx + rx) ring */ 130 uint32_t fw_rxring_addr; /* start phyaddr of fw rx desc */ 131 uint8_t opt; /* see ACX100_RINGOPT_ */ 132 uint8_t fw_txring_num; /* num of TX ring */ 133 uint8_t fw_rxdesc_num; /* num of fw rx desc */ 134 uint8_t reserved0; 135 uint32_t fw_ring_end[2]; /* see ACX100_SET_RING_END() */ 136 uint32_t fw_txring_addr; /* start phyaddr of fw tx desc */ 137 uint8_t fw_txring_prio; /* see ACX100_TXRING_PRIO_ */ 138 uint8_t fw_txdesc_num; /* num of fw tx desc */ 139 uint16_t reserved1; 140} __packed; 141 142#define ACX100_RINGOPT_AUTO_RESET 0x1 143#define ACX100_TXRING_PRIO_DEFAULT 0 144#define ACX100_SET_RING_END(conf, end) \ 145do { \ 146 (conf)->fw_ring_end[0] = htole32(end); \ 147 (conf)->fw_ring_end[1] = htole32(end + 8); \ 148} while (0) 149 150struct acx100_conf_memblk_size { 151 struct acx_conf confcom; 152 uint16_t memblk_size; /* size of each mem block */ 153} __packed; 154 155struct acx100_conf_mem { 156 struct acx_conf confcom; 157 uint32_t opt; /* see ACX100_MEMOPT_ */ 158 uint32_t h_rxring_paddr; /* host rx desc start phyaddr */ 159 160 /* 161 * Memory blocks are controled by hardware 162 * once after they are initialized 163 */ 164 uint32_t rx_memblk_addr; /* start addr of rx mem blocks */ 165 uint32_t tx_memblk_addr; /* start addr of tx mem blocks */ 166 uint16_t rx_memblk_num; /* num of RX mem block */ 167 uint16_t tx_memblk_num; /* num of TX mem block */ 168} __packed; 169 170#define ACX100_MEMOPT_MEM_INSTR 0x00000000 /* memory access instruct */ 171#define ACX100_MEMOPT_HOSTDESC 0x00010000 /* host indirect desc */ 172#define ACX100_MEMOPT_MEMBLOCK 0x00020000 /* local mem block list */ 173#define ACX100_MEMOPT_IO_INSTR 0x00040000 /* IO instruct */ 174#define ACX100_MEMOPT_PCICONF 0x00080000 /* PCI conf space */ 175 176#define ACX100_MEMBLK_ALIGN 0x20 177 178struct acx100_conf_cca_mode { 179 struct acx_conf confcom; 180 uint8_t cca_mode; 181 uint8_t unknown; 182} __packed; 183 184struct acx100_conf_ed_thresh { 185 struct acx_conf confcom; 186 uint8_t ed_thresh; 187 uint8_t unknown[3]; 188} __packed; 189 190struct acx100_conf_wepkey { 191 struct acx_conf confcom; 192 uint8_t action; /* see ACX100_WEPKEY_ACT_ */ 193 uint8_t key_len; 194 uint8_t key_idx; 195#define ACX100_WEPKEY_LEN 29 196 uint8_t key[ACX100_WEPKEY_LEN]; 197} __packed; 198 199#define ACX100_WEPKEY_ACT_ADD 1 200 201static const uint16_t acx100_reg[ACXREG_MAX] = { 202 ACXREG(SOFT_RESET, 0x0000), 203 204 ACXREG(FWMEM_ADDR, 0x0014), 205 ACXREG(FWMEM_DATA, 0x0018), 206 ACXREG(FWMEM_CTRL, 0x001c), 207 ACXREG(FWMEM_START, 0x0020), 208 209 ACXREG(EVENT_MASK, 0x0034), 210 211 ACXREG(INTR_TRIG, 0x007c), 212 ACXREG(INTR_MASK, 0x0098), 213 ACXREG(INTR_STATUS, 0x00a4), 214 ACXREG(INTR_STATUS_CLR, 0x00a8), 215 ACXREG(INTR_ACK, 0x00ac), 216 217 ACXREG(HINTR_TRIG, 0x00b0), 218 ACXREG(RADIO_ENABLE, 0x0104), 219 220 ACXREG(EEPROM_INIT, 0x02d0), 221 ACXREG(EEPROM_CTRL, 0x0250), 222 ACXREG(EEPROM_ADDR, 0x0254), 223 ACXREG(EEPROM_DATA, 0x0258), 224 ACXREG(EEPROM_CONF, 0x025c), 225 ACXREG(EEPROM_INFO, 0x02ac), 226 227 ACXREG(PHY_ADDR, 0x0268), 228 ACXREG(PHY_DATA, 0x026c), 229 ACXREG(PHY_CTRL, 0x0270), 230 231 ACXREG(GPIO_OUT_ENABLE, 0x0290), 232 ACXREG(GPIO_OUT, 0x0298), 233 234 ACXREG(CMD_REG_OFFSET, 0x02a4), 235 ACXREG(INFO_REG_OFFSET, 0x02a8), 236 237 ACXREG(RESET_SENSE, 0x02d4), 238 ACXREG(ECPU_CTRL, 0x02d8) 239}; 240 241static const uint8_t acx100_txpower_maxim[21] = { 242 63, 63, 63, 62, 243 61, 61, 60, 60, 244 59, 58, 57, 55, 245 53, 50, 47, 43, 246 38, 31, 23, 13, 247 0 248}; 249 250static const uint8_t acx100_txpower_rfmd[21] = { 251 0, 0, 0, 1, 252 2, 2, 3, 3, 253 4, 5, 6, 8, 254 10, 13, 16, 20, 255 25, 32, 41, 50, 256 63 257}; 258 259void 260acx100_set_param(struct acx_softc *sc) 261{ 262 sc->chip_mem1_rid = PCIR_BAR(1); 263 sc->chip_mem2_rid = PCIR_BAR(2); 264 sc->chip_ioreg = acx100_reg; 265 sc->chip_hw_crypt = 1; 266 sc->chip_intr_enable = ACX100_INTR_ENABLE; 267#ifndef IEEE80211_STA_ONLY 268 sc->chip_intr_enable |= ACXRV_INTR_DTIM; 269#endif 270 sc->chip_intr_disable = ACX100_INTR_DISABLE; 271 sc->chip_gpio_pled = ACX100_GPIO_POWER_LED; 272 sc->chip_ee_eaddr_ofs = ACX100_EE_EADDR_OFS; 273 sc->chip_txdesc1_len = ACX_FRAME_HDRLEN; 274 sc->chip_fw_txdesc_ctrl = DESC_CTRL_AUTODMA | 275 DESC_CTRL_RECLAIM | DESC_CTRL_FIRST_FRAG; 276 277 sc->chip_phymode = IEEE80211_MODE_11B; 278 sc->chip_chan_flags = IEEE80211_CHAN_B; 279 sc->sc_ic.ic_phytype = IEEE80211_T_DS; 280 sc->sc_ic.ic_sup_rates[IEEE80211_MODE_11B] = ieee80211_std_rateset_11b; 281 282 sc->chip_init = acx100_init; 283 sc->chip_set_wepkey = acx100_set_wepkey; 284 sc->chip_read_config = acx100_read_config; 285 sc->chip_write_config = acx100_write_config; 286 sc->chip_set_fw_txdesc_rate = acx100_set_fw_txdesc_rate; 287 sc->chip_set_bss_join_param = acx100_set_bss_join_param; 288 sc->chip_proc_wep_rxbuf = acx100_proc_wep_rxbuf; 289} 290 291int 292acx100_init(struct acx_softc *sc) 293{ 294 struct ifnet *ifp = &sc->sc_ic.ic_if; 295 296 /* 297 * NOTE: 298 * Order of initialization: 299 * 1) WEP 300 * 2) Templates 301 * 3) Firmware TX/RX ring 302 * 4) Hardware memory 303 * Above order is critical to get a correct memory map 304 */ 305 if (acx100_init_wep(sc) != 0) { 306 printf("%s: %s can't initialize wep\n", 307 ifp->if_xname, __func__); 308 return (ENXIO); 309 } 310 311 if (acx100_init_tmplt(sc) != 0) { 312 printf("%s: %s can't initialize templates\n", 313 ifp->if_xname, __func__); 314 return (ENXIO); 315 } 316 317 if (acx100_init_fw_ring(sc) != 0) { 318 printf("%s: %s can't initialize fw ring\n", 319 ifp->if_xname, __func__); 320 return (ENXIO); 321 } 322 323 if (acx100_init_memory(sc) != 0) { 324 printf("%s: %s can't initialize hw memory\n", 325 ifp->if_xname, __func__); 326 return (ENXIO); 327 } 328 329 return (0); 330} 331 332int 333acx100_init_wep(struct acx_softc *sc) 334{ 335 struct acx_conf_wepopt wep_opt; 336 struct acx_conf_mmap mem_map; 337 struct ifnet *ifp = &sc->sc_ic.ic_if; 338 339 /* Set WEP cache start/end address */ 340 if (acx_get_conf(sc, ACX_CONF_MMAP, &mem_map, sizeof(mem_map)) != 0) { 341 printf("%s: can't get mmap\n", ifp->if_xname); 342 return (1); 343 } 344 345 mem_map.wep_cache_start = htole32(letoh32(mem_map.code_end) + 4); 346 mem_map.wep_cache_end = htole32(letoh32(mem_map.code_end) + 4); 347 if (acx_set_conf(sc, ACX_CONF_MMAP, &mem_map, sizeof(mem_map)) != 0) { 348 printf("%s: can't set mmap\n", ifp->if_xname); 349 return (1); 350 } 351 352 /* Set WEP options */ 353 wep_opt.nkey = htole16(IEEE80211_WEP_NKID + 10); 354 wep_opt.opt = WEPOPT_HDWEP; 355 if (acx_set_conf(sc, ACX_CONF_WEPOPT, &wep_opt, sizeof(wep_opt)) != 0) { 356 printf("%s: can't set wep opt\n", ifp->if_xname); 357 return (1); 358 } 359 360 return (0); 361} 362 363int 364acx100_init_tmplt(struct acx_softc *sc) 365{ 366 struct acx_conf_mmap mem_map; 367 struct ifnet *ifp = &sc->sc_ic.ic_if; 368 369 /* Set templates start address */ 370 if (acx_get_conf(sc, ACX_CONF_MMAP, &mem_map, sizeof(mem_map)) != 0) { 371 printf("%s: can't get mmap\n", ifp->if_xname); 372 return (1); 373 } 374 375 mem_map.pkt_tmplt_start = mem_map.wep_cache_end; 376 if (acx_set_conf(sc, ACX_CONF_MMAP, &mem_map, sizeof(mem_map)) != 0) { 377 printf("%s: can't set mmap\n", ifp->if_xname); 378 return (1); 379 } 380 381 /* Initialize various packet templates */ 382 if (acx_init_tmplt_ordered(sc) != 0) { 383 printf("%s: can't init tmplt\n", ifp->if_xname); 384 return (1); 385 } 386 387 return (0); 388} 389 390int 391acx100_init_fw_ring(struct acx_softc *sc) 392{ 393 struct acx100_conf_fw_ring ring; 394 struct acx_conf_mmap mem_map; 395 struct ifnet *ifp = &sc->sc_ic.ic_if; 396 uint32_t txring_start, rxring_start, ring_end; 397 398 /* Set firmware descriptor ring start address */ 399 if (acx_get_conf(sc, ACX_CONF_MMAP, &mem_map, sizeof(mem_map)) != 0) { 400 printf("%s: can't get mmap\n", ifp->if_xname); 401 return (1); 402 } 403 404 txring_start = letoh32(mem_map.pkt_tmplt_end) + 4; 405 rxring_start = txring_start + ACX100_FW_TXRING_SIZE; 406 ring_end = rxring_start + ACX100_FW_RXRING_SIZE; 407 408 mem_map.fw_desc_start = htole32(txring_start); 409 if (acx_set_conf(sc, ACX_CONF_MMAP, &mem_map, sizeof(mem_map)) != 0) { 410 printf("%s: can't set mmap\n", ifp->if_xname); 411 return (1); 412 } 413 414 /* Set firmware descriptor ring configure */ 415 bzero(&ring, sizeof(ring)); 416 ring.fw_ring_size = htole32(ACX100_FW_TXRING_SIZE + 417 ACX100_FW_RXRING_SIZE + 8); 418 419 ring.fw_txring_num = 1; 420 ring.fw_txring_addr = htole32(txring_start); 421 ring.fw_txring_prio = ACX100_TXRING_PRIO_DEFAULT; 422 ring.fw_txdesc_num = 0; /* XXX ignored?? */ 423 424 ring.fw_rxring_addr = htole32(rxring_start); 425 ring.fw_rxdesc_num = 0; /* XXX ignored?? */ 426 427 ring.opt = ACX100_RINGOPT_AUTO_RESET; 428 ACX100_SET_RING_END(&ring, ring_end); 429 if (acx_set_conf(sc, ACX100_CONF_FW_RING, &ring, sizeof(ring)) != 0) { 430 printf("%s: can't set fw ring configure\n", ifp->if_xname); 431 return (1); 432 } 433 434 /* Setup firmware TX/RX descriptor ring */ 435 acx100_init_fw_txring(sc, txring_start); 436 acx100_init_fw_rxring(sc, rxring_start); 437 438 return (0); 439} 440 441#define MEMBLK_ALIGN(addr) \ 442 (((addr) + (ACX100_MEMBLK_ALIGN - 1)) & ~(ACX100_MEMBLK_ALIGN - 1)) 443 444int 445acx100_init_memory(struct acx_softc *sc) 446{ 447 struct acx100_conf_memblk_size memblk_sz; 448 struct acx100_conf_mem mem; 449 struct acx_conf_mmap mem_map; 450 struct ifnet *ifp = &sc->sc_ic.ic_if; 451 uint32_t memblk_start, memblk_end; 452 int total_memblk, txblk_num, rxblk_num; 453 454 /* Set memory block start address */ 455 if (acx_get_conf(sc, ACX_CONF_MMAP, &mem_map, sizeof(mem_map)) != 0) { 456 printf("%s: can't get mmap\n", ifp->if_xname); 457 return (1); 458 } 459 460 mem_map.memblk_start = 461 htole32(MEMBLK_ALIGN(letoh32(mem_map.fw_desc_end) + 4)); 462 463 if (acx_set_conf(sc, ACX_CONF_MMAP, &mem_map, sizeof(mem_map)) != 0) { 464 printf("%s: can't set mmap\n", ifp->if_xname); 465 return (1); 466 } 467 468 /* Set memory block size */ 469 memblk_sz.memblk_size = htole16(ACX_MEMBLOCK_SIZE); 470 if (acx_set_conf(sc, ACX_CONF_MEMBLK_SIZE, &memblk_sz, 471 sizeof(memblk_sz)) != 0) { 472 printf("%s: can't set mem block size\n", ifp->if_xname); 473 return (1); 474 } 475 476 /* Get memory map after setting it */ 477 if (acx_get_conf(sc, ACX_CONF_MMAP, &mem_map, sizeof(mem_map)) != 0) { 478 printf("%s: can't get mmap again\n", ifp->if_xname); 479 return (1); 480 } 481 memblk_start = letoh32(mem_map.memblk_start); 482 memblk_end = letoh32(mem_map.memblk_end); 483 484 /* Set memory options */ 485 mem.opt = htole32(ACX100_MEMOPT_MEMBLOCK | ACX100_MEMOPT_HOSTDESC); 486 mem.h_rxring_paddr = htole32(sc->sc_ring_data.rx_ring_paddr); 487 488 total_memblk = (memblk_end - memblk_start) / ACX_MEMBLOCK_SIZE; 489 490 rxblk_num = total_memblk / 2; /* 50% */ 491 txblk_num = total_memblk - rxblk_num; /* 50% */ 492 493 DPRINTF(("%s: \ttotal memory blocks\t%d\n" 494 "\trx memory blocks\t%d\n" 495 "\ttx memory blocks\t%d\n", 496 ifp->if_xname, total_memblk, rxblk_num, txblk_num)); 497 498 mem.rx_memblk_num = htole16(rxblk_num); 499 mem.tx_memblk_num = htole16(txblk_num); 500 501 mem.rx_memblk_addr = htole32(MEMBLK_ALIGN(memblk_start)); 502 mem.tx_memblk_addr = htole32(MEMBLK_ALIGN(memblk_start + 503 (ACX_MEMBLOCK_SIZE * rxblk_num))); 504 505 if (acx_set_conf(sc, ACX100_CONF_MEMOPT, &mem, sizeof(mem)) != 0) { 506 printf("%s: can't set mem options\n", ifp->if_xname); 507 return (1); 508 } 509 510 /* Initialize memory */ 511 if (acx_exec_command(sc, ACXCMD_INIT_MEM, NULL, 0, NULL, 0) != 0) { 512 printf("%s: can't init mem\n", ifp->if_xname); 513 return (1); 514 } 515 516 return (0); 517} 518 519#undef MEMBLK_ALIGN 520 521void 522acx100_init_fw_txring(struct acx_softc *sc, uint32_t fw_txdesc_start) 523{ 524 struct acx_fw_txdesc fw_desc; 525 struct acx_txbuf *tx_buf; 526 uint32_t desc_paddr, fw_desc_offset; 527 int i; 528 529 bzero(&fw_desc, sizeof(fw_desc)); 530 fw_desc.f_tx_ctrl = DESC_CTRL_HOSTOWN | DESC_CTRL_RECLAIM | 531 DESC_CTRL_AUTODMA | DESC_CTRL_FIRST_FRAG; 532 533 tx_buf = sc->sc_buf_data.tx_buf; 534 fw_desc_offset = fw_txdesc_start; 535 desc_paddr = sc->sc_ring_data.tx_ring_paddr; 536 537 for (i = 0; i < ACX_TX_DESC_CNT; ++i) { 538 fw_desc.f_tx_host_desc = htole32(desc_paddr); 539 540 if (i == ACX_TX_DESC_CNT - 1) { 541 fw_desc.f_tx_next_desc = htole32(fw_txdesc_start); 542 } else { 543 fw_desc.f_tx_next_desc = htole32(fw_desc_offset + 544 sizeof(struct acx_fw_txdesc)); 545 } 546 547 tx_buf[i].tb_fwdesc_ofs = fw_desc_offset; 548 DESC_WRITE_REGION_1(sc, fw_desc_offset, &fw_desc, 549 sizeof(fw_desc)); 550 551 desc_paddr += (2 * sizeof(struct acx_host_desc)); 552 fw_desc_offset += sizeof(fw_desc); 553 } 554} 555 556void 557acx100_init_fw_rxring(struct acx_softc *sc, uint32_t fw_rxdesc_start) 558{ 559 struct acx_fw_rxdesc fw_desc; 560 uint32_t fw_desc_offset; 561 int i; 562 563 bzero(&fw_desc, sizeof(fw_desc)); 564 fw_desc.f_rx_ctrl = DESC_CTRL_RECLAIM | DESC_CTRL_AUTODMA; 565 566 fw_desc_offset = fw_rxdesc_start; 567 568 for (i = 0; i < ACX_RX_DESC_CNT; ++i) { 569 if (i == ACX_RX_DESC_CNT - 1) { 570 fw_desc.f_rx_next_desc = htole32(fw_rxdesc_start); 571 } else { 572 fw_desc.f_rx_next_desc = 573 htole32(fw_desc_offset + 574 sizeof(struct acx_fw_rxdesc)); 575 } 576 577 DESC_WRITE_REGION_1(sc, fw_desc_offset, &fw_desc, 578 sizeof(fw_desc)); 579 580 fw_desc_offset += sizeof(fw_desc); 581 } 582} 583 584int 585acx100_read_config(struct acx_softc *sc, struct acx_config *conf) 586{ 587 struct acx100_conf_cca_mode cca; 588 struct acx100_conf_ed_thresh ed; 589 struct ifnet *ifp = &sc->sc_ic.ic_if; 590 591 /* 592 * NOTE: 593 * CCA mode and ED threshold MUST be read during initialization 594 * or the acx100 card won't work as expected 595 */ 596 597 /* Get CCA mode */ 598 if (acx_get_conf(sc, ACX_CONF_CCA_MODE, &cca, sizeof(cca)) != 0) { 599 printf("%s: %s can't get cca mode\n", 600 ifp->if_xname, __func__); 601 return (ENXIO); 602 } 603 conf->cca_mode = cca.cca_mode; 604 DPRINTF(("%s: cca mode %02x\n", ifp->if_xname, cca.cca_mode)); 605 606 /* Get ED threshold */ 607 if (acx_get_conf(sc, ACX_CONF_ED_THRESH, &ed, sizeof(ed)) != 0) { 608 printf("%s: %s can't get ed threshold\n", 609 ifp->if_xname, __func__); 610 return (ENXIO); 611 } 612 conf->ed_thresh = ed.ed_thresh; 613 DPRINTF(("%s: ed threshold %02x\n", ifp->if_xname, ed.ed_thresh)); 614 615 return (0); 616} 617 618int 619acx100_write_config(struct acx_softc *sc, struct acx_config *conf) 620{ 621 struct acx100_conf_cca_mode cca; 622 struct acx100_conf_ed_thresh ed; 623 struct ifnet *ifp = &sc->sc_ic.ic_if; 624 625 /* Set CCA mode */ 626 cca.cca_mode = conf->cca_mode; 627 if (acx_set_conf(sc, ACX_CONF_CCA_MODE, &cca, sizeof(cca)) != 0) { 628 printf("%s: %s can't set cca mode\n", 629 ifp->if_xname, __func__); 630 return (ENXIO); 631 } 632 633 /* Set ED threshold */ 634 ed.ed_thresh = conf->ed_thresh; 635 if (acx_set_conf(sc, ACX_CONF_ED_THRESH, &ed, sizeof(ed)) != 0) { 636 printf("%s: %s can't set ed threshold\n", 637 ifp->if_xname, __func__); 638 return (ENXIO); 639 } 640 641 /* Set TX power */ 642 acx100_set_txpower(sc); /* ignore return value */ 643 644 return (0); 645} 646 647int 648acx100_set_txpower(struct acx_softc *sc) 649{ 650 struct ifnet *ifp = &sc->sc_ic.ic_if; 651 const uint8_t *map; 652 653 switch (sc->sc_radio_type) { 654 case ACX_RADIO_TYPE_MAXIM: 655 map = acx100_txpower_maxim; 656 break; 657 case ACX_RADIO_TYPE_RFMD: 658 case ACX_RADIO_TYPE_RALINK: 659 map = acx100_txpower_rfmd; 660 break; 661 default: 662 printf("%s: TX power for radio type 0x%02x can't be set yet\n", 663 ifp->if_xname, sc->sc_radio_type); 664 return (1); 665 } 666 667 acx_write_phyreg(sc, ACXRV_PHYREG_TXPOWER, map[ACX100_TXPOWER]); 668 669 return (0); 670} 671 672void 673acx100_set_fw_txdesc_rate(struct acx_softc *sc, struct acx_txbuf *tx_buf, 674 int rate) 675{ 676 FW_TXDESC_SETFIELD_1(sc, tx_buf, f_tx_rate100, ACX100_RATE(rate)); 677} 678 679void 680acx100_set_bss_join_param(struct acx_softc *sc, void *param, int dtim_intvl) 681{ 682 struct acx100_bss_join *bj = param; 683 684 bj->dtim_intvl = dtim_intvl; 685 bj->basic_rates = 15; /* XXX */ 686 bj->all_rates = 31; /* XXX */ 687} 688 689int 690acx100_set_wepkey(struct acx_softc *sc, struct ieee80211_key *k, int k_idx) 691{ 692 struct acx100_conf_wepkey conf_wk; 693 struct ifnet *ifp = &sc->sc_ic.ic_if; 694 695 if (k->k_len > ACX100_WEPKEY_LEN) { 696 printf("%s: %dth WEP key size beyond %d\n", 697 ifp->if_xname, k_idx, ACX100_WEPKEY_LEN); 698 return EINVAL; 699 } 700 701 conf_wk.action = ACX100_WEPKEY_ACT_ADD; 702 conf_wk.key_len = k->k_len; 703 conf_wk.key_idx = k_idx; 704 bcopy(k->k_key, conf_wk.key, k->k_len); 705 if (acx_set_conf(sc, ACX_CONF_WEPKEY, &conf_wk, sizeof(conf_wk)) != 0) { 706 printf("%s: %s set %dth WEP key failed\n", 707 ifp->if_xname, __func__, k_idx); 708 return ENXIO; 709 } 710 return 0; 711} 712 713void 714acx100_proc_wep_rxbuf(struct acx_softc *sc, struct mbuf *m, int *len) 715{ 716 int mac_hdrlen; 717 struct ieee80211_frame *f; 718 719 /* 720 * Strip leading IV and KID, and trailing CRC 721 */ 722 f = mtod(m, struct ieee80211_frame *); 723 724 if ((f->i_fc[1] & IEEE80211_FC1_DIR_MASK) == IEEE80211_FC1_DIR_DSTODS) 725 mac_hdrlen = sizeof(struct ieee80211_frame_addr4); 726 else 727 mac_hdrlen = sizeof(struct ieee80211_frame); 728 729#define IEEEWEP_IVLEN (IEEE80211_WEP_IVLEN + IEEE80211_WEP_KIDLEN) 730#define IEEEWEP_EXLEN (IEEEWEP_IVLEN + IEEE80211_WEP_CRCLEN) 731 732 *len = *len - IEEEWEP_EXLEN; 733 734 /* Move MAC header toward frame body */ 735 ovbcopy(f, (uint8_t *)f + IEEEWEP_IVLEN, mac_hdrlen); 736 m_adj(m, IEEEWEP_IVLEN); 737 738#undef IEEEWEP_EXLEN 739#undef IEEEWEP_IVLEN 740} 741