root/dev/ic/acx100.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. acx100_set_param
  2. acx100_init
  3. acx100_init_wep
  4. acx100_init_tmplt
  5. acx100_init_fw_ring
  6. acx100_init_memory
  7. acx100_init_fw_txring
  8. acx100_init_fw_rxring
  9. acx100_read_config
  10. acx100_write_config
  11. acx100_set_txpower
  12. acx100_set_fw_txdesc_rate
  13. acx100_set_bss_join_param
  14. acx100_set_wepkey
  15. acx100_proc_wep_rxbuf

    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 }

/* [<][>][^][v][top][bottom][index][help] */