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