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