The Design and Implementation of the FreeBSD Operating System, Second Edition
Now available: The Design and Implementation of the FreeBSD Operating System (Second Edition)


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]

FreeBSD/Linux Kernel Cross Reference
sys/dev/ic/acx100.c

Version: -  FREEBSD  -  FREEBSD-13-STABLE  -  FREEBSD-13-0  -  FREEBSD-12-STABLE  -  FREEBSD-12-0  -  FREEBSD-11-STABLE  -  FREEBSD-11-0  -  FREEBSD-10-STABLE  -  FREEBSD-10-0  -  FREEBSD-9-STABLE  -  FREEBSD-9-0  -  FREEBSD-8-STABLE  -  FREEBSD-8-0  -  FREEBSD-7-STABLE  -  FREEBSD-7-0  -  FREEBSD-6-STABLE  -  FREEBSD-6-0  -  FREEBSD-5-STABLE  -  FREEBSD-5-0  -  FREEBSD-4-STABLE  -  FREEBSD-3-STABLE  -  FREEBSD22  -  l41  -  OPENBSD  -  linux-2.6  -  MK84  -  PLAN9  -  xnu-8792 
SearchContext: -  none  -  3  -  10 

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

Cache object: 437df3537576b1d022df4b341b9b74c4


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]


This page is part of the FreeBSD/Linux Linux Kernel Cross-Reference, and was automatically generated using a modified version of the LXR engine.