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