1 /* $OpenBSD: acx100.c,v 1.21 2010/04/20 22:05:41 tedu 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 101 int acx100_init(struct acx_softc *); 102 int acx100_init_wep(struct acx_softc *); 103 int acx100_init_tmplt(struct acx_softc *); 104 int acx100_init_fw_ring(struct acx_softc *); 105 int acx100_init_memory(struct acx_softc *); 106 void acx100_init_fw_txring(struct acx_softc *, uint32_t); 107 void acx100_init_fw_rxring(struct acx_softc *, uint32_t); 108 int acx100_read_config(struct acx_softc *, struct acx_config *); 109 int acx100_write_config(struct acx_softc *, struct acx_config *); 110 int acx100_set_txpower(struct acx_softc *); 111 void acx100_set_fw_txdesc_rate(struct acx_softc *, 112 struct acx_txbuf *, int); 113 void acx100_set_bss_join_param(struct acx_softc *, void *, int); 114 int acx100_set_wepkey(struct acx_softc *, struct ieee80211_key *, int); 115 void acx100_proc_wep_rxbuf(struct acx_softc *, struct mbuf *, int *); 116 117 /* 118 * NOTE: 119 * Following structs' fields are little endian 120 */ 121 struct acx100_bss_join { 122 uint8_t dtim_intvl; 123 uint8_t basic_rates; 124 uint8_t all_rates; 125 } __packed; 126 127 struct 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) \ 145 do { \ 146 (conf)->fw_ring_end[0] = htole32(end); \ 147 (conf)->fw_ring_end[1] = htole32(end + 8); \ 148 } while (0) 149 150 struct acx100_conf_memblk_size { 151 struct acx_conf confcom; 152 uint16_t memblk_size; /* size of each mem block */ 153 } __packed; 154 155 struct 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 178 struct acx100_conf_cca_mode { 179 struct acx_conf confcom; 180 uint8_t cca_mode; 181 uint8_t unknown; 182 } __packed; 183 184 struct acx100_conf_ed_thresh { 185 struct acx_conf confcom; 186 uint8_t ed_thresh; 187 uint8_t unknown[3]; 188 } __packed; 189 190 struct 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 201 static 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 241 static 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 250 static 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 259 void 260 acx100_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 sc->chip_intr_disable = ACX100_INTR_DISABLE; 268 sc->chip_gpio_pled = ACX100_GPIO_POWER_LED; 269 sc->chip_ee_eaddr_ofs = ACX100_EE_EADDR_OFS; 270 sc->chip_txdesc1_len = ACX_FRAME_HDRLEN; 271 sc->chip_fw_txdesc_ctrl = DESC_CTRL_AUTODMA | 272 DESC_CTRL_RECLAIM | DESC_CTRL_FIRST_FRAG; 273 274 sc->chip_phymode = IEEE80211_MODE_11B; 275 sc->chip_chan_flags = IEEE80211_CHAN_B; 276 sc->sc_ic.ic_phytype = IEEE80211_T_DS; 277 sc->sc_ic.ic_sup_rates[IEEE80211_MODE_11B] = ieee80211_std_rateset_11b; 278 279 sc->chip_init = acx100_init; 280 sc->chip_set_wepkey = acx100_set_wepkey; 281 sc->chip_read_config = acx100_read_config; 282 sc->chip_write_config = acx100_write_config; 283 sc->chip_set_fw_txdesc_rate = acx100_set_fw_txdesc_rate; 284 sc->chip_set_bss_join_param = acx100_set_bss_join_param; 285 sc->chip_proc_wep_rxbuf = acx100_proc_wep_rxbuf; 286 } 287 288 int 289 acx100_init(struct acx_softc *sc) 290 { 291 struct ifnet *ifp = &sc->sc_ic.ic_if; 292 293 /* 294 * NOTE: 295 * Order of initialization: 296 * 1) WEP 297 * 2) Templates 298 * 3) Firmware TX/RX ring 299 * 4) Hardware memory 300 * Above order is critical to get a correct memory map 301 */ 302 if (acx100_init_wep(sc) != 0) { 303 printf("%s: %s can't initialize wep\n", 304 ifp->if_xname, __func__); 305 return (ENXIO); 306 } 307 308 if (acx100_init_tmplt(sc) != 0) { 309 printf("%s: %s can't initialize templates\n", 310 ifp->if_xname, __func__); 311 return (ENXIO); 312 } 313 314 if (acx100_init_fw_ring(sc) != 0) { 315 printf("%s: %s can't initialize fw ring\n", 316 ifp->if_xname, __func__); 317 return (ENXIO); 318 } 319 320 if (acx100_init_memory(sc) != 0) { 321 printf("%s: %s can't initialize hw memory\n", 322 ifp->if_xname, __func__); 323 return (ENXIO); 324 } 325 326 return (0); 327 } 328 329 int 330 acx100_init_wep(struct acx_softc *sc) 331 { 332 struct acx_conf_wepopt wep_opt; 333 struct acx_conf_mmap mem_map; 334 struct ifnet *ifp = &sc->sc_ic.ic_if; 335 336 /* Set WEP cache start/end address */ 337 if (acx_get_conf(sc, ACX_CONF_MMAP, &mem_map, sizeof(mem_map)) != 0) { 338 printf("%s: can't get mmap\n", ifp->if_xname); 339 return (1); 340 } 341 342 mem_map.wep_cache_start = htole32(letoh32(mem_map.code_end) + 4); 343 mem_map.wep_cache_end = htole32(letoh32(mem_map.code_end) + 4); 344 if (acx_set_conf(sc, ACX_CONF_MMAP, &mem_map, sizeof(mem_map)) != 0) { 345 printf("%s: can't set mmap\n", ifp->if_xname); 346 return (1); 347 } 348 349 /* Set WEP options */ 350 wep_opt.nkey = htole16(IEEE80211_WEP_NKID + 10); 351 wep_opt.opt = WEPOPT_HDWEP; 352 if (acx_set_conf(sc, ACX_CONF_WEPOPT, &wep_opt, sizeof(wep_opt)) != 0) { 353 printf("%s: can't set wep opt\n", ifp->if_xname); 354 return (1); 355 } 356 357 return (0); 358 } 359 360 int 361 acx100_init_tmplt(struct acx_softc *sc) 362 { 363 struct acx_conf_mmap mem_map; 364 struct ifnet *ifp = &sc->sc_ic.ic_if; 365 366 /* Set templates start address */ 367 if (acx_get_conf(sc, ACX_CONF_MMAP, &mem_map, sizeof(mem_map)) != 0) { 368 printf("%s: can't get mmap\n", ifp->if_xname); 369 return (1); 370 } 371 372 mem_map.pkt_tmplt_start = mem_map.wep_cache_end; 373 if (acx_set_conf(sc, ACX_CONF_MMAP, &mem_map, sizeof(mem_map)) != 0) { 374 printf("%s: can't set mmap\n", ifp->if_xname); 375 return (1); 376 } 377 378 /* Initialize various packet templates */ 379 if (acx_init_tmplt_ordered(sc) != 0) { 380 printf("%s: can't init tmplt\n", ifp->if_xname); 381 return (1); 382 } 383 384 return (0); 385 } 386 387 int 388 acx100_init_fw_ring(struct acx_softc *sc) 389 { 390 struct acx100_conf_fw_ring ring; 391 struct acx_conf_mmap mem_map; 392 struct ifnet *ifp = &sc->sc_ic.ic_if; 393 uint32_t txring_start, rxring_start, ring_end; 394 395 /* Set firmware descriptor ring start address */ 396 if (acx_get_conf(sc, ACX_CONF_MMAP, &mem_map, sizeof(mem_map)) != 0) { 397 printf("%s: can't get mmap\n", ifp->if_xname); 398 return (1); 399 } 400 401 txring_start = letoh32(mem_map.pkt_tmplt_end) + 4; 402 rxring_start = txring_start + ACX100_FW_TXRING_SIZE; 403 ring_end = rxring_start + ACX100_FW_RXRING_SIZE; 404 405 mem_map.fw_desc_start = htole32(txring_start); 406 if (acx_set_conf(sc, ACX_CONF_MMAP, &mem_map, sizeof(mem_map)) != 0) { 407 printf("%s: can't set mmap\n", ifp->if_xname); 408 return (1); 409 } 410 411 /* Set firmware descriptor ring configure */ 412 bzero(&ring, sizeof(ring)); 413 ring.fw_ring_size = htole32(ACX100_FW_TXRING_SIZE + 414 ACX100_FW_RXRING_SIZE + 8); 415 416 ring.fw_txring_num = 1; 417 ring.fw_txring_addr = htole32(txring_start); 418 ring.fw_txring_prio = ACX100_TXRING_PRIO_DEFAULT; 419 ring.fw_txdesc_num = 0; /* XXX ignored?? */ 420 421 ring.fw_rxring_addr = htole32(rxring_start); 422 ring.fw_rxdesc_num = 0; /* XXX ignored?? */ 423 424 ring.opt = ACX100_RINGOPT_AUTO_RESET; 425 ACX100_SET_RING_END(&ring, ring_end); 426 if (acx_set_conf(sc, ACX100_CONF_FW_RING, &ring, sizeof(ring)) != 0) { 427 printf("%s: can't set fw ring configure\n", ifp->if_xname); 428 return (1); 429 } 430 431 /* Setup firmware TX/RX descriptor ring */ 432 acx100_init_fw_txring(sc, txring_start); 433 acx100_init_fw_rxring(sc, rxring_start); 434 435 return (0); 436 } 437 438 #define MEMBLK_ALIGN(addr) \ 439 (((addr) + (ACX100_MEMBLK_ALIGN - 1)) & ~(ACX100_MEMBLK_ALIGN - 1)) 440 441 int 442 acx100_init_memory(struct acx_softc *sc) 443 { 444 struct acx100_conf_memblk_size memblk_sz; 445 struct acx100_conf_mem mem; 446 struct acx_conf_mmap mem_map; 447 struct ifnet *ifp = &sc->sc_ic.ic_if; 448 uint32_t memblk_start, memblk_end; 449 int total_memblk, txblk_num, rxblk_num; 450 451 /* Set memory block start address */ 452 if (acx_get_conf(sc, ACX_CONF_MMAP, &mem_map, sizeof(mem_map)) != 0) { 453 printf("%s: can't get mmap\n", ifp->if_xname); 454 return (1); 455 } 456 457 mem_map.memblk_start = 458 htole32(MEMBLK_ALIGN(letoh32(mem_map.fw_desc_end) + 4)); 459 460 if (acx_set_conf(sc, ACX_CONF_MMAP, &mem_map, sizeof(mem_map)) != 0) { 461 printf("%s: can't set mmap\n", ifp->if_xname); 462 return (1); 463 } 464 465 /* Set memory block size */ 466 memblk_sz.memblk_size = htole16(ACX_MEMBLOCK_SIZE); 467 if (acx_set_conf(sc, ACX_CONF_MEMBLK_SIZE, &memblk_sz, 468 sizeof(memblk_sz)) != 0) { 469 printf("%s: can't set mem block size\n", ifp->if_xname); 470 return (1); 471 } 472 473 /* Get memory map after setting it */ 474 if (acx_get_conf(sc, ACX_CONF_MMAP, &mem_map, sizeof(mem_map)) != 0) { 475 printf("%s: can't get mmap again\n", ifp->if_xname); 476 return (1); 477 } 478 memblk_start = letoh32(mem_map.memblk_start); 479 memblk_end = letoh32(mem_map.memblk_end); 480 481 /* Set memory options */ 482 mem.opt = htole32(ACX100_MEMOPT_MEMBLOCK | ACX100_MEMOPT_HOSTDESC); 483 mem.h_rxring_paddr = htole32(sc->sc_ring_data.rx_ring_paddr); 484 485 total_memblk = (memblk_end - memblk_start) / ACX_MEMBLOCK_SIZE; 486 487 rxblk_num = total_memblk / 2; /* 50% */ 488 txblk_num = total_memblk - rxblk_num; /* 50% */ 489 490 DPRINTF(("%s: \ttotal memory blocks\t%d\n" 491 "\trx memory blocks\t%d\n" 492 "\ttx memory blocks\t%d\n", 493 ifp->if_xname, total_memblk, rxblk_num, txblk_num)); 494 495 mem.rx_memblk_num = htole16(rxblk_num); 496 mem.tx_memblk_num = htole16(txblk_num); 497 498 mem.rx_memblk_addr = htole32(MEMBLK_ALIGN(memblk_start)); 499 mem.tx_memblk_addr = htole32(MEMBLK_ALIGN(memblk_start + 500 (ACX_MEMBLOCK_SIZE * rxblk_num))); 501 502 if (acx_set_conf(sc, ACX100_CONF_MEMOPT, &mem, sizeof(mem)) != 0) { 503 printf("%s: can't set mem options\n", ifp->if_xname); 504 return (1); 505 } 506 507 /* Initialize memory */ 508 if (acx_exec_command(sc, ACXCMD_INIT_MEM, NULL, 0, NULL, 0) != 0) { 509 printf("%s: can't init mem\n", ifp->if_xname); 510 return (1); 511 } 512 513 return (0); 514 } 515 516 #undef MEMBLK_ALIGN 517 518 void 519 acx100_init_fw_txring(struct acx_softc *sc, uint32_t fw_txdesc_start) 520 { 521 struct acx_fw_txdesc fw_desc; 522 struct acx_txbuf *tx_buf; 523 uint32_t desc_paddr, fw_desc_offset; 524 int i; 525 526 bzero(&fw_desc, sizeof(fw_desc)); 527 fw_desc.f_tx_ctrl = DESC_CTRL_HOSTOWN | DESC_CTRL_RECLAIM | 528 DESC_CTRL_AUTODMA | DESC_CTRL_FIRST_FRAG; 529 530 tx_buf = sc->sc_buf_data.tx_buf; 531 fw_desc_offset = fw_txdesc_start; 532 desc_paddr = sc->sc_ring_data.tx_ring_paddr; 533 534 for (i = 0; i < ACX_TX_DESC_CNT; ++i) { 535 fw_desc.f_tx_host_desc = htole32(desc_paddr); 536 537 if (i == ACX_TX_DESC_CNT - 1) { 538 fw_desc.f_tx_next_desc = htole32(fw_txdesc_start); 539 } else { 540 fw_desc.f_tx_next_desc = htole32(fw_desc_offset + 541 sizeof(struct acx_fw_txdesc)); 542 } 543 544 tx_buf[i].tb_fwdesc_ofs = fw_desc_offset; 545 DESC_WRITE_REGION_1(sc, fw_desc_offset, &fw_desc, 546 sizeof(fw_desc)); 547 548 desc_paddr += (2 * sizeof(struct acx_host_desc)); 549 fw_desc_offset += sizeof(fw_desc); 550 } 551 } 552 553 void 554 acx100_init_fw_rxring(struct acx_softc *sc, uint32_t fw_rxdesc_start) 555 { 556 struct acx_fw_rxdesc fw_desc; 557 uint32_t fw_desc_offset; 558 int i; 559 560 bzero(&fw_desc, sizeof(fw_desc)); 561 fw_desc.f_rx_ctrl = DESC_CTRL_RECLAIM | DESC_CTRL_AUTODMA; 562 563 fw_desc_offset = fw_rxdesc_start; 564 565 for (i = 0; i < ACX_RX_DESC_CNT; ++i) { 566 if (i == ACX_RX_DESC_CNT - 1) { 567 fw_desc.f_rx_next_desc = htole32(fw_rxdesc_start); 568 } else { 569 fw_desc.f_rx_next_desc = 570 htole32(fw_desc_offset + 571 sizeof(struct acx_fw_rxdesc)); 572 } 573 574 DESC_WRITE_REGION_1(sc, fw_desc_offset, &fw_desc, 575 sizeof(fw_desc)); 576 577 fw_desc_offset += sizeof(fw_desc); 578 } 579 } 580 581 int 582 acx100_read_config(struct acx_softc *sc, struct acx_config *conf) 583 { 584 struct acx100_conf_cca_mode cca; 585 struct acx100_conf_ed_thresh ed; 586 struct ifnet *ifp = &sc->sc_ic.ic_if; 587 588 /* 589 * NOTE: 590 * CCA mode and ED threshold MUST be read during initialization 591 * or the acx100 card won't work as expected 592 */ 593 594 /* Get CCA mode */ 595 if (acx_get_conf(sc, ACX_CONF_CCA_MODE, &cca, sizeof(cca)) != 0) { 596 printf("%s: %s can't get cca mode\n", 597 ifp->if_xname, __func__); 598 return (ENXIO); 599 } 600 conf->cca_mode = cca.cca_mode; 601 DPRINTF(("%s: cca mode %02x\n", ifp->if_xname, cca.cca_mode)); 602 603 /* Get ED threshold */ 604 if (acx_get_conf(sc, ACX_CONF_ED_THRESH, &ed, sizeof(ed)) != 0) { 605 printf("%s: %s can't get ed threshold\n", 606 ifp->if_xname, __func__); 607 return (ENXIO); 608 } 609 conf->ed_thresh = ed.ed_thresh; 610 DPRINTF(("%s: ed threshold %02x\n", ifp->if_xname, ed.ed_thresh)); 611 612 return (0); 613 } 614 615 int 616 acx100_write_config(struct acx_softc *sc, struct acx_config *conf) 617 { 618 struct acx100_conf_cca_mode cca; 619 struct acx100_conf_ed_thresh ed; 620 struct ifnet *ifp = &sc->sc_ic.ic_if; 621 622 /* Set CCA mode */ 623 cca.cca_mode = conf->cca_mode; 624 if (acx_set_conf(sc, ACX_CONF_CCA_MODE, &cca, sizeof(cca)) != 0) { 625 printf("%s: %s can't set cca mode\n", 626 ifp->if_xname, __func__); 627 return (ENXIO); 628 } 629 630 /* Set ED threshold */ 631 ed.ed_thresh = conf->ed_thresh; 632 if (acx_set_conf(sc, ACX_CONF_ED_THRESH, &ed, sizeof(ed)) != 0) { 633 printf("%s: %s can't set ed threshold\n", 634 ifp->if_xname, __func__); 635 return (ENXIO); 636 } 637 638 /* Set TX power */ 639 acx100_set_txpower(sc); /* ignore return value */ 640 641 return (0); 642 } 643 644 int 645 acx100_set_txpower(struct acx_softc *sc) 646 { 647 struct ifnet *ifp = &sc->sc_ic.ic_if; 648 const uint8_t *map; 649 650 switch (sc->sc_radio_type) { 651 case ACX_RADIO_TYPE_MAXIM: 652 map = acx100_txpower_maxim; 653 break; 654 case ACX_RADIO_TYPE_RFMD: 655 case ACX_RADIO_TYPE_RALINK: 656 map = acx100_txpower_rfmd; 657 break; 658 default: 659 printf("%s: TX power for radio type 0x%02x can't be set yet\n", 660 ifp->if_xname, sc->sc_radio_type); 661 return (1); 662 } 663 664 acx_write_phyreg(sc, ACXRV_PHYREG_TXPOWER, map[ACX100_TXPOWER]); 665 666 return (0); 667 } 668 669 void 670 acx100_set_fw_txdesc_rate(struct acx_softc *sc, struct acx_txbuf *tx_buf, 671 int rate) 672 { 673 FW_TXDESC_SETFIELD_1(sc, tx_buf, f_tx_rate100, ACX100_RATE(rate)); 674 } 675 676 void 677 acx100_set_bss_join_param(struct acx_softc *sc, void *param, int dtim_intvl) 678 { 679 struct acx100_bss_join *bj = param; 680 681 bj->dtim_intvl = dtim_intvl; 682 bj->basic_rates = 15; /* XXX */ 683 bj->all_rates = 31; /* XXX */ 684 } 685 686 int 687 acx100_set_wepkey(struct acx_softc *sc, struct ieee80211_key *k, int k_idx) 688 { 689 struct acx100_conf_wepkey conf_wk; 690 struct ifnet *ifp = &sc->sc_ic.ic_if; 691 692 if (k->k_len > ACX100_WEPKEY_LEN) { 693 printf("%s: %dth WEP key size beyond %d\n", 694 ifp->if_xname, k_idx, ACX100_WEPKEY_LEN); 695 return EINVAL; 696 } 697 698 conf_wk.action = ACX100_WEPKEY_ACT_ADD; 699 conf_wk.key_len = k->k_len; 700 conf_wk.key_idx = k_idx; 701 bcopy(k->k_key, conf_wk.key, k->k_len); 702 if (acx_set_conf(sc, ACX_CONF_WEPKEY, &conf_wk, sizeof(conf_wk)) != 0) { 703 printf("%s: %s set %dth WEP key failed\n", 704 ifp->if_xname, __func__, k_idx); 705 return ENXIO; 706 } 707 return 0; 708 } 709 710 void 711 acx100_proc_wep_rxbuf(struct acx_softc *sc, struct mbuf *m, int *len) 712 { 713 int mac_hdrlen; 714 struct ieee80211_frame *f; 715 716 /* 717 * Strip leading IV and KID, and trailing CRC 718 */ 719 f = mtod(m, struct ieee80211_frame *); 720 721 if ((f->i_fc[1] & IEEE80211_FC1_DIR_MASK) == IEEE80211_FC1_DIR_DSTODS) 722 mac_hdrlen = sizeof(struct ieee80211_frame_addr4); 723 else 724 mac_hdrlen = sizeof(struct ieee80211_frame); 725 726 #define IEEEWEP_IVLEN (IEEE80211_WEP_IVLEN + IEEE80211_WEP_KIDLEN) 727 #define IEEEWEP_EXLEN (IEEEWEP_IVLEN + IEEE80211_WEP_CRCLEN) 728 729 *len = *len - IEEEWEP_EXLEN; 730 731 /* Move MAC header toward frame body */ 732 ovbcopy(f, (uint8_t *)f + IEEEWEP_IVLEN, mac_hdrlen); 733 m_adj(m, IEEEWEP_IVLEN); 734 735 #undef IEEEWEP_EXLEN 736 #undef IEEEWEP_IVLEN 737 } 738