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