[BACK]Return to acx100.c CVS log [TXT][DIR] Up to [local] / sys / dev / ic

Annotation of sys/dev/ic/acx100.c, Revision 1.1.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