Annotation of sys/dev/ic/acx111.c, Revision 1.1
1.1 ! nbrk 1: /* $OpenBSD: acx111.c,v 1.16 2007/08/05 21:37:29 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/endian.h>
! 55: #include <sys/socket.h>
! 56: #include <sys/sysctl.h>
! 57: #include <sys/device.h>
! 58:
! 59: #include <machine/bus.h>
! 60:
! 61: #include <net/if.h>
! 62: #include <net/if_arp.h>
! 63: #include <net/if_media.h>
! 64:
! 65: #include <net/if.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 ACX111_CONF_MEM 0x0003
! 82: #define ACX111_CONF_MEMINFO 0x0005
! 83:
! 84: #define ACX111_INTR_ENABLE (ACXRV_INTR_TX_FINI | ACXRV_INTR_RX_FINI)
! 85: /*
! 86: * XXX do we really care about fowlling interrupts?
! 87: *
! 88: * ACXRV_INTR_IV_ICV_FAILURE | ACXRV_INTR_INFO |
! 89: * ACXRV_INTR_SCAN_FINI | ACXRV_INTR_FCS_THRESHOLD
! 90: */
! 91:
! 92: #define ACX111_INTR_DISABLE (uint16_t)~(ACXRV_INTR_CMD_FINI)
! 93:
! 94: #define ACX111_RATE_2 0x0001
! 95: #define ACX111_RATE_4 0x0002
! 96: #define ACX111_RATE_11 0x0004
! 97: #define ACX111_RATE_12 0x0008
! 98: #define ACX111_RATE_18 0x0010
! 99: #define ACX111_RATE_22 0x0020
! 100: #define ACX111_RATE_24 0x0040
! 101: #define ACX111_RATE_36 0x0080
! 102: #define ACX111_RATE_44 0x0100
! 103: #define ACX111_RATE_48 0x0200
! 104: #define ACX111_RATE_72 0x0400
! 105: #define ACX111_RATE_96 0x0800
! 106: #define ACX111_RATE_108 0x1000
! 107:
! 108: /* XXX skip ACX111_RATE_44 */
! 109: #define ACX111_RATE_ALL 0x1eff
! 110:
! 111: #define ACX111_TXPOWER 15
! 112: #define ACX111_GPIO_POWER_LED 0x0040
! 113: #define ACX111_EE_EADDR_OFS 0x21
! 114:
! 115: #define ACX111_FW_TXDESC_SIZE (sizeof(struct acx_fw_txdesc) + 4)
! 116:
! 117: #if ACX111_TXPOWER <= 12
! 118: #define ACX111_TXPOWER_VAL 1
! 119: #else
! 120: #define ACX111_TXPOWER_VAL 2
! 121: #endif
! 122:
! 123: int acx111_init(struct acx_softc *);
! 124: int acx111_init_memory(struct acx_softc *);
! 125: void acx111_init_fw_txring(struct acx_softc *, uint32_t);
! 126: int acx111_write_config(struct acx_softc *, struct acx_config *);
! 127: void acx111_set_fw_txdesc_rate(struct acx_softc *,
! 128: struct acx_txbuf *, int);
! 129: void acx111_set_bss_join_param(struct acx_softc *, void *, int);
! 130:
! 131: /*
! 132: * NOTE:
! 133: * Following structs' fields are little endian
! 134: */
! 135: struct acx111_bss_join {
! 136: uint16_t basic_rates;
! 137: uint8_t dtim_intvl;
! 138: } __packed;
! 139:
! 140: struct acx111_conf_mem {
! 141: struct acx_conf confcom;
! 142:
! 143: uint16_t sta_max; /* max num of sta, ACX111_STA_MAX */
! 144: uint16_t memblk_size; /* mem block size */
! 145: uint8_t rx_memblk_perc; /* percent of RX mem block, unit: 5% */
! 146: uint8_t fw_rxring_num; /* num of RX ring */
! 147: uint8_t fw_txring_num; /* num of TX ring */
! 148: uint8_t opt; /* see ACX111_MEMOPT_ */
! 149: uint8_t xfer_perc; /* frag/xfer proportion, unit: 5% */
! 150: uint16_t reserved0;
! 151: uint8_t reserved1;
! 152:
! 153: uint8_t fw_rxdesc_num; /* num of fw rx desc */
! 154: uint8_t fw_rxring_reserved1;
! 155: uint8_t fw_rxring_type; /* see ACX111_RXRING_TYPE_ */
! 156: uint8_t fw_rxring_prio; /* see ACX111_RXRING_PRIO_ */
! 157:
! 158: uint32_t h_rxring_paddr; /* host rx desc start phyaddr */
! 159:
! 160: uint8_t fw_txdesc_num; /* num of fw tx desc */
! 161: uint8_t fw_txring_reserved1;
! 162: uint8_t fw_txring_reserved2;
! 163: uint8_t fw_txring_attr; /* see ACX111_TXRING_ATTR_ */
! 164: } __packed;
! 165:
! 166: #define ACX111_STA_MAX 32
! 167: #define ACX111_RX_MEMBLK_PERCENT 10 /* 50% */
! 168: #define ACX111_XFER_PERCENT 15 /* 75% */
! 169: #define ACX111_RXRING_TYPE_DEFAULT 7
! 170: #define ACX111_RXRING_PRIO_DEFAULT 0
! 171: #define ACX111_TXRING_ATTR_DEFAULT 0
! 172: #define ACX111_MEMOPT_DEFAULT 0
! 173:
! 174: struct acx111_conf_meminfo {
! 175: struct acx_conf confcom;
! 176: uint32_t tx_memblk_addr; /* start addr of tx mem blocks */
! 177: uint32_t rx_memblk_addr; /* start addr of rx mem blocks */
! 178: uint32_t fw_rxring_start; /* start phyaddr of fw rx ring */
! 179: uint32_t reserved0;
! 180: uint32_t fw_txring_start; /* start phyaddr of fw tx ring */
! 181: uint8_t fw_txring_attr; /* XXX see ACX111_TXRING_ATTR_ */
! 182: uint16_t reserved1;
! 183: uint8_t reserved2;
! 184: } __packed;
! 185:
! 186: struct acx111_conf_txpower {
! 187: struct acx_conf confcom;
! 188: uint8_t txpower;
! 189: } __packed;
! 190:
! 191: struct acx111_conf_option {
! 192: struct acx_conf confcom;
! 193: uint32_t feature;
! 194: uint32_t dataflow; /* see ACX111_DF_ */
! 195: } __packed;
! 196:
! 197: #define ACX111_DF_NO_RXDECRYPT 0x00000080
! 198: #define ACX111_DF_NO_TXENCRYPT 0x00000001
! 199:
! 200: struct acx111_wepkey {
! 201: uint8_t mac_addr[IEEE80211_ADDR_LEN];
! 202: uint16_t action; /* see ACX111_WEPKEY_ACT_ */
! 203: uint16_t reserved;
! 204: uint8_t key_len;
! 205: uint8_t key_type; /* see ACX111_WEPKEY_TYPE_ */
! 206: uint8_t index; /* XXX ?? */
! 207: uint8_t key_idx;
! 208: uint8_t counter[6];
! 209: #define ACX111_WEPKEY_LEN 32
! 210: uint8_t key[ACX111_WEPKEY_LEN];
! 211: } __packed;
! 212:
! 213: #define ACX111_WEPKEY_ACT_ADD 1
! 214: #define ACX111_WEPKEY_TYPE_DEFAULT 0
! 215:
! 216: static const uint16_t acx111_reg[ACXREG_MAX] = {
! 217: ACXREG(SOFT_RESET, 0x0000),
! 218:
! 219: ACXREG(FWMEM_ADDR, 0x0014),
! 220: ACXREG(FWMEM_DATA, 0x0018),
! 221: ACXREG(FWMEM_CTRL, 0x001c),
! 222: ACXREG(FWMEM_START, 0x0020),
! 223:
! 224: ACXREG(EVENT_MASK, 0x0034),
! 225:
! 226: ACXREG(INTR_TRIG, 0x00b4),
! 227: ACXREG(INTR_MASK, 0x00d4),
! 228: ACXREG(INTR_STATUS, 0x00f0),
! 229: ACXREG(INTR_STATUS_CLR, 0x00e4),
! 230: ACXREG(INTR_ACK, 0x00e8),
! 231:
! 232: ACXREG(HINTR_TRIG, 0x00ec),
! 233: ACXREG(RADIO_ENABLE, 0x01d0),
! 234:
! 235: ACXREG(EEPROM_INIT, 0x0100),
! 236: ACXREG(EEPROM_CTRL, 0x0338),
! 237: ACXREG(EEPROM_ADDR, 0x033c),
! 238: ACXREG(EEPROM_DATA, 0x0340),
! 239: ACXREG(EEPROM_CONF, 0x0344),
! 240: ACXREG(EEPROM_INFO, 0x0390),
! 241:
! 242: ACXREG(PHY_ADDR, 0x0350),
! 243: ACXREG(PHY_DATA, 0x0354),
! 244: ACXREG(PHY_CTRL, 0x0358),
! 245:
! 246: ACXREG(GPIO_OUT_ENABLE, 0x0374),
! 247: ACXREG(GPIO_OUT, 0x037c),
! 248:
! 249: ACXREG(CMD_REG_OFFSET, 0x0388),
! 250: ACXREG(INFO_REG_OFFSET, 0x038c),
! 251:
! 252: ACXREG(RESET_SENSE, 0x0104),
! 253: ACXREG(ECPU_CTRL, 0x0108)
! 254: };
! 255:
! 256: /* XXX */
! 257: static uint16_t acx111_rate_map[109] = {
! 258: ACX111_RATE_2,
! 259: ACX111_RATE_4,
! 260: ACX111_RATE_11,
! 261: ACX111_RATE_22,
! 262: ACX111_RATE_12,
! 263: ACX111_RATE_18,
! 264: ACX111_RATE_24,
! 265: ACX111_RATE_36,
! 266: ACX111_RATE_48,
! 267: ACX111_RATE_72,
! 268: ACX111_RATE_96,
! 269: ACX111_RATE_108
! 270: };
! 271:
! 272: void
! 273: acx111_set_param(struct acx_softc *sc)
! 274: {
! 275: sc->chip_mem1_rid = PCIR_BAR(0);
! 276: sc->chip_mem2_rid = PCIR_BAR(1);
! 277: sc->chip_ioreg = acx111_reg;
! 278: sc->chip_intr_enable = ACX111_INTR_ENABLE;
! 279: sc->chip_intr_disable = ACX111_INTR_DISABLE;
! 280: sc->chip_gpio_pled = ACX111_GPIO_POWER_LED;
! 281: sc->chip_ee_eaddr_ofs = ACX111_EE_EADDR_OFS;
! 282:
! 283: sc->chip_phymode = IEEE80211_MODE_11G;
! 284: sc->chip_chan_flags = IEEE80211_CHAN_CCK |
! 285: IEEE80211_CHAN_OFDM |
! 286: IEEE80211_CHAN_DYN |
! 287: IEEE80211_CHAN_2GHZ;
! 288: sc->sc_ic.ic_caps = IEEE80211_C_WEP;
! 289: sc->sc_ic.ic_phytype = IEEE80211_T_OFDM;
! 290: sc->sc_ic.ic_sup_rates[IEEE80211_MODE_11B] = ieee80211_std_rateset_11b;
! 291: sc->sc_ic.ic_sup_rates[IEEE80211_MODE_11G] = ieee80211_std_rateset_11g;
! 292:
! 293: sc->chip_init = acx111_init;
! 294: sc->chip_write_config = acx111_write_config;
! 295: sc->chip_set_fw_txdesc_rate = acx111_set_fw_txdesc_rate;
! 296: sc->chip_set_bss_join_param = acx111_set_bss_join_param;
! 297: sc->sc_flags |= ACX_FLAG_ACX111;
! 298: }
! 299:
! 300: int
! 301: acx111_init(struct acx_softc *sc)
! 302: {
! 303: struct ifnet *ifp = &sc->sc_ic.ic_if;
! 304:
! 305: /*
! 306: * NOTE:
! 307: * Order of initialization:
! 308: * 1) Templates
! 309: * 2) Hardware memory
! 310: * Above order is critical to get a correct memory map
! 311: */
! 312: if (acx_init_tmplt_ordered(sc) != 0) {
! 313: printf("%s: %s can't initialize templates\n",
! 314: ifp->if_xname, __func__);
! 315: return (ENXIO);
! 316: }
! 317:
! 318: if (acx111_init_memory(sc) != 0) {
! 319: printf("%s: %s can't initialize hw memory\n",
! 320: ifp->if_xname, __func__);
! 321: return (ENXIO);
! 322: }
! 323:
! 324: return (0);
! 325: }
! 326:
! 327: int
! 328: acx111_init_memory(struct acx_softc *sc)
! 329: {
! 330: struct acx111_conf_mem mem;
! 331: struct acx111_conf_meminfo mem_info;
! 332: struct ifnet *ifp = &sc->sc_ic.ic_if;
! 333:
! 334: /* Set memory configuration */
! 335: bzero(&mem, sizeof(mem));
! 336:
! 337: mem.sta_max = htole16(ACX111_STA_MAX);
! 338: mem.memblk_size = htole16(ACX_MEMBLOCK_SIZE);
! 339: mem.rx_memblk_perc = ACX111_RX_MEMBLK_PERCENT;
! 340: mem.opt = ACX111_MEMOPT_DEFAULT;
! 341: mem.xfer_perc = ACX111_XFER_PERCENT;
! 342:
! 343: mem.fw_rxring_num = 1;
! 344: mem.fw_rxring_type = ACX111_RXRING_TYPE_DEFAULT;
! 345: mem.fw_rxring_prio = ACX111_RXRING_PRIO_DEFAULT;
! 346: mem.fw_rxdesc_num = ACX_RX_DESC_CNT;
! 347: mem.h_rxring_paddr = htole32(sc->sc_ring_data.rx_ring_paddr);
! 348:
! 349: mem.fw_txring_num = 1;
! 350: mem.fw_txring_attr = ACX111_TXRING_ATTR_DEFAULT;
! 351: mem.fw_txdesc_num = ACX_TX_DESC_CNT;
! 352:
! 353: if (acx_set_conf(sc, ACX111_CONF_MEM, &mem, sizeof(mem)) != 0) {
! 354: printf("%s: can't set mem\n", ifp->if_xname);
! 355: return (1);
! 356: }
! 357:
! 358: /* Get memory configuration */
! 359: if (acx_get_conf(sc, ACX111_CONF_MEMINFO, &mem_info,
! 360: sizeof(mem_info)) != 0) {
! 361: printf("%s: can't get meminfo\n", ifp->if_xname);
! 362: return (1);
! 363: }
! 364:
! 365: /* Setup firmware TX descriptor ring */
! 366: acx111_init_fw_txring(sc, letoh32(mem_info.fw_txring_start));
! 367:
! 368: /*
! 369: * There is no need to setup firmware RX descriptor ring,
! 370: * it is automaticly setup by hardware.
! 371: */
! 372:
! 373: return (0);
! 374: }
! 375:
! 376: void
! 377: acx111_init_fw_txring(struct acx_softc *sc, uint32_t fw_txdesc_start)
! 378: {
! 379: struct acx_txbuf *tx_buf;
! 380: uint32_t desc_paddr;
! 381: int i;
! 382:
! 383: tx_buf = sc->sc_buf_data.tx_buf;
! 384: desc_paddr = sc->sc_ring_data.tx_ring_paddr;
! 385:
! 386: for (i = 0; i < ACX_TX_DESC_CNT; ++i) {
! 387: tx_buf[i].tb_fwdesc_ofs = fw_txdesc_start +
! 388: (i * ACX111_FW_TXDESC_SIZE);
! 389:
! 390: /*
! 391: * Except for the following fields, rest of the fields
! 392: * are setup by hardware.
! 393: */
! 394: FW_TXDESC_SETFIELD_4(sc, &tx_buf[i], f_tx_host_desc,
! 395: desc_paddr);
! 396: FW_TXDESC_SETFIELD_1(sc, &tx_buf[i], f_tx_ctrl,
! 397: DESC_CTRL_HOSTOWN);
! 398:
! 399: desc_paddr += (2 * sizeof(struct acx_host_desc));
! 400: }
! 401: }
! 402:
! 403: int
! 404: acx111_write_config(struct acx_softc *sc, struct acx_config *conf)
! 405: {
! 406: struct acx111_conf_txpower tx_power;
! 407: struct acx111_conf_option opt;
! 408: struct ifnet *ifp = &sc->sc_ic.ic_if;
! 409: uint32_t dataflow;
! 410:
! 411: /* Set TX power */
! 412: tx_power.txpower = ACX111_TXPOWER_VAL;
! 413: if (acx_set_conf(sc, ACX_CONF_TXPOWER, &tx_power,
! 414: sizeof(tx_power)) != 0) {
! 415: printf("%s: %s can't set TX power\n",
! 416: ifp->if_xname, __func__);
! 417: return (ENXIO);
! 418: }
! 419:
! 420: /*
! 421: * Turn off hardware WEP
! 422: */
! 423: if (acx_get_conf(sc, ACX_CONF_OPTION, &opt, sizeof(opt)) != 0) {
! 424: printf("%s: %s can't get option\n", ifp->if_xname, __func__);
! 425: return (ENXIO);
! 426: }
! 427:
! 428: dataflow = letoh32(opt.dataflow) |
! 429: ACX111_DF_NO_TXENCRYPT |
! 430: ACX111_DF_NO_RXDECRYPT;
! 431: opt.dataflow = htole32(dataflow);
! 432:
! 433: if (acx_set_conf(sc, ACX_CONF_OPTION, &opt, sizeof(opt)) != 0) {
! 434: printf("%s: %s can't set option\n", ifp->if_xname, __func__);
! 435: return (ENXIO);
! 436: }
! 437:
! 438: return (0);
! 439: }
! 440:
! 441: void
! 442: acx111_set_fw_txdesc_rate(struct acx_softc *sc, struct acx_txbuf *tx_buf,
! 443: int rate0)
! 444: {
! 445: uint16_t rate;
! 446:
! 447: rate = acx111_rate_map[rate0];
! 448: if (rate == 0)
! 449: /* set rate to 1Mbit/s if rate was zero */
! 450: rate = acx111_rate_map[2];
! 451:
! 452: FW_TXDESC_SETFIELD_2(sc, tx_buf, u.r2.rate111, rate);
! 453: }
! 454:
! 455: void
! 456: acx111_set_bss_join_param(struct acx_softc *sc, void *param, int dtim_intvl)
! 457: {
! 458: struct acx111_bss_join *bj = param;
! 459:
! 460: bj->basic_rates = htole16(ACX111_RATE_ALL);
! 461: bj->dtim_intvl = dtim_intvl;
! 462: }
CVSweb