2 * Copyright (c) 2006 The DragonFly Project. All rights reserved.
4 * This code is derived from software contributed to The DragonFly Project
5 * by Sepherosa Ziehau <sepherosa@gmail.com>
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
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
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.
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
34 * $DragonFly: src/sys/dev/netif/acx/acx100.c,v 1.13 2008/06/08 10:06:05 sephe Exp $
37 #include <sys/param.h>
39 #include <sys/endian.h>
41 #include <sys/socket.h>
42 #include <sys/sysctl.h>
45 #include <net/if_arp.h>
46 #include <net/if_media.h>
48 #include <netproto/802_11/ieee80211_var.h>
49 #include <netproto/802_11/ieee80211_radiotap.h>
50 #include <netproto/802_11/wlan_ratectl/amrr/ieee80211_amrr_param.h>
51 #include <netproto/802_11/wlan_ratectl/onoe/ieee80211_onoe_param.h>
53 #include <bus/pci/pcireg.h>
57 #include <dev/netif/acx/if_acxreg.h>
58 #include <dev/netif/acx/if_acxvar.h>
59 #include <dev/netif/acx/acxcmd.h>
61 #define ACX100_CONF_FW_RING 0x0003
62 #define ACX100_CONF_MEMOPT 0x0005
64 #define ACX100_INTR_ENABLE (ACXRV_INTR_TX_FINI | ACXRV_INTR_RX_FINI)
66 * XXX do we really care about following interrupts?
68 * ACXRV_INTR_INFO | ACXRV_INTR_SCAN_FINI
71 #define ACX100_INTR_DISABLE (uint16_t)~(ACXRV_INTR_UNKN)
73 #define ACX100_RATE(rate) ((rate) * 5)
75 #define ACX100_RSSI_CORR 8
76 #define ACX100_TXPOWER 18
77 #define ACX100_GPIO_POWER_LED 0x0800
78 #define ACX100_EE_EADDR_OFS 0x1a
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))
85 * Following structs' fields are little endian
88 struct acx100_bss_join
{
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 */
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 */
109 #define ACX100_RINGOPT_AUTO_RESET 0x1
110 #define ACX100_TXRING_PRIO_DEFAULT 0
111 #define ACX100_SET_RING_END(conf, end) \
113 (conf)->fw_ring_end[0] = htole32(end); \
114 (conf)->fw_ring_end[1] = htole32(end + 8); \
117 struct acx100_conf_memblk_size
{
118 struct acx_conf confcom
;
119 uint16_t memblk_size
; /* size of each mem block */
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 */
128 * Memory blocks are controled by hardware
129 * once after they are initialized
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 */
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 */
143 #define ACX100_MEMBLK_ALIGN 0x20
145 struct acx100_conf_cca_mode
{
146 struct acx_conf confcom
;
151 struct acx100_conf_ed_thresh
{
152 struct acx_conf confcom
;
157 struct acx100_conf_wepkey
{
158 struct acx_conf confcom
;
159 uint8_t action
; /* see ACX100_WEPKEY_ACT_ */
162 #define ACX100_WEPKEY_LEN 29
163 uint8_t key
[ACX100_WEPKEY_LEN
];
166 #define ACX100_WEPKEY_ACT_ADD 1
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
);
184 #define ACXCMD_init_mem ACXCMD_INIT_MEM
185 ACX_NOARG_FUNC(init_mem
);
187 static const uint16_t acx100_reg
[ACXREG_MAX
] = {
188 ACXREG(SOFT_RESET
, 0x0000),
190 ACXREG(FWMEM_ADDR
, 0x0014),
191 ACXREG(FWMEM_DATA
, 0x0018),
192 ACXREG(FWMEM_CTRL
, 0x001c),
193 ACXREG(FWMEM_START
, 0x0020),
195 ACXREG(EVENT_MASK
, 0x0034),
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),
203 ACXREG(HINTR_TRIG
, 0x00b0),
204 ACXREG(RADIO_ENABLE
, 0x0104),
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),
213 ACXREG(PHY_ADDR
, 0x0268),
214 ACXREG(PHY_DATA
, 0x026c),
215 ACXREG(PHY_CTRL
, 0x0270),
217 ACXREG(GPIO_OUT_ENABLE
, 0x0290),
218 ACXREG(GPIO_OUT
, 0x0298),
220 ACXREG(CMD_REG_OFFSET
, 0x02a4),
221 ACXREG(INFO_REG_OFFSET
, 0x02a8),
223 ACXREG(RESET_SENSE
, 0x02d4),
224 ACXREG(ECPU_CTRL
, 0x02d8)
227 static const uint8_t acx100_txpower_maxim
[21] = {
236 static const uint8_t acx100_txpower_rfmd
[21] = {
245 static const uint8_t acx100_rate_map
[45] = {
253 static int acx100_init(struct acx_softc
*);
254 static int acx100_init_wep(struct acx_softc
*);
255 static int acx100_init_tmplt(struct acx_softc
*);
256 static int acx100_init_fw_ring(struct acx_softc
*);
257 static int acx100_init_memory(struct acx_softc
*);
259 static void acx100_init_fw_txring(struct acx_softc
*, uint32_t);
260 static void acx100_init_fw_rxring(struct acx_softc
*, uint32_t);
262 static int acx100_read_config(struct acx_softc
*, struct acx_config
*);
263 static int acx100_write_config(struct acx_softc
*, struct acx_config
*);
265 static void *acx100_ratectl_attach(struct ieee80211com
*, u_int
);
267 static int acx100_set_txpower(struct acx_softc
*);
269 static uint8_t acx100_set_fw_txdesc_rate(struct acx_softc
*,
271 struct ieee80211_node
*, int);
272 static void acx100_tx_complete(struct acx_softc
*, struct acx_txbuf
*,
274 static void acx100_set_bss_join_param(struct acx_softc
*, void *, int);
276 static int acx100_set_wepkey(struct acx_softc
*, struct ieee80211_key
*,
279 static void acx100_proc_wep_rxbuf(struct acx_softc
*, struct mbuf
*, int *);
281 #define ACX100_CHK_RATE(ifp, rate, rate_idx) \
282 acx100_check_rate(ifp, rate, rate_idx, __func__)
285 acx100_check_rate(struct ifnet
*ifp
, u_int rate
, int rate_idx
,
288 #define N(arr) (sizeof(arr) / sizeof(arr[0]))
289 if (rate
>= N(acx100_rate_map
)) {
290 if_printf(ifp
, "%s rate out of range %u (idx %d)\n",
291 fname
, rate
, rate_idx
);
296 if (acx100_rate_map
[rate
] == 0) {
297 if_printf(ifp
, "%s invalid rate %u (idx %d)\n",
298 fname
, rate
, rate_idx
);
305 acx100_set_param(device_t dev
)
307 struct acx_softc
*sc
= device_get_softc(dev
);
308 struct ieee80211com
*ic
= &sc
->sc_ic
;
309 struct acx_firmware
*fw
= &sc
->sc_firmware
;
311 sc
->chip_mem1_rid
= PCIR_BAR(1);
312 sc
->chip_mem2_rid
= PCIR_BAR(2);
313 sc
->chip_ioreg
= acx100_reg
;
314 sc
->chip_hw_crypt
= 1;
315 sc
->chip_intr_enable
= ACX100_INTR_ENABLE
;
316 sc
->chip_intr_disable
= ACX100_INTR_DISABLE
;
317 sc
->chip_gpio_pled
= ACX100_GPIO_POWER_LED
;
318 sc
->chip_ee_eaddr_ofs
= ACX100_EE_EADDR_OFS
;
319 sc
->chip_txdesc1_len
= ACX_FRAME_HDRLEN
;
320 sc
->chip_fw_txdesc_ctrl
= DESC_CTRL_AUTODMA
|
322 DESC_CTRL_FIRST_FRAG
;
323 sc
->chip_short_retry_limit
= 7;
324 sc
->chip_rssi_corr
= ACX100_RSSI_CORR
;
326 sc
->chip_phymode
= IEEE80211_MODE_11B
;
327 sc
->chip_chan_flags
= IEEE80211_CHAN_B
;
329 ic
->ic_phytype
= IEEE80211_T_DS
;
331 ic
->ic_sup_rates
[IEEE80211_MODE_11B
] = acx_rates_11b_pbcc
;
333 ic
->ic_sup_rates
[IEEE80211_MODE_11B
] = acx_rates_11b
;
335 IEEE80211_ONOE_PARAM_SETUP(&sc
->sc_onoe_param
);
337 ic
->ic_ratectl
.rc_st_ratectl_cap
= IEEE80211_RATECTL_CAP_ONOE
;
338 ic
->ic_ratectl
.rc_st_ratectl
= IEEE80211_RATECTL_ONOE
;
339 ic
->ic_ratectl
.rc_st_attach
= acx100_ratectl_attach
;
341 sc
->chip_init
= acx100_init
;
342 sc
->chip_set_wepkey
= acx100_set_wepkey
;
343 sc
->chip_read_config
= acx100_read_config
;
344 sc
->chip_write_config
= acx100_write_config
;
345 sc
->chip_set_fw_txdesc_rate
= acx100_set_fw_txdesc_rate
;
346 sc
->chip_tx_complete
= acx100_tx_complete
;
347 sc
->chip_set_bss_join_param
= acx100_set_bss_join_param
;
348 sc
->chip_proc_wep_rxbuf
= acx100_proc_wep_rxbuf
;
350 fw
->combined_radio_fw
= 0;
355 acx100_init(struct acx_softc
*sc
)
359 * Order of initialization:
362 * 3) Firmware TX/RX ring
364 * Above order is critical to get a correct memory map
367 if (acx100_init_wep(sc
) != 0) {
368 if_printf(&sc
->sc_ic
.ic_if
, "%s can't initialize wep\n",
373 if (acx100_init_tmplt(sc
) != 0) {
374 if_printf(&sc
->sc_ic
.ic_if
, "%s can't initialize templates\n",
379 if (acx100_init_fw_ring(sc
) != 0) {
380 if_printf(&sc
->sc_ic
.ic_if
, "%s can't initialize fw ring\n",
385 if (acx100_init_memory(sc
) != 0) {
386 if_printf(&sc
->sc_ic
.ic_if
, "%s can't initialize hw memory\n",
394 acx100_init_wep(struct acx_softc
*sc
)
396 struct acx_conf_wepopt wep_opt
;
397 struct acx_conf_mmap mem_map
;
399 /* Set WEP cache start/end address */
400 if (acx_get_mmap_conf(sc
, &mem_map
) != 0) {
401 if_printf(&sc
->sc_ic
.ic_if
, "can't get mmap\n");
405 mem_map
.wep_cache_start
= htole32(le32toh(mem_map
.code_end
) + 4);
406 mem_map
.wep_cache_end
= htole32(le32toh(mem_map
.code_end
) + 4);
407 if (acx_set_mmap_conf(sc
, &mem_map
) != 0) {
408 if_printf(&sc
->sc_ic
.ic_if
, "can't set mmap\n");
412 /* Set WEP options */
413 wep_opt
.nkey
= htole16(IEEE80211_WEP_NKID
+ 10);
414 wep_opt
.opt
= WEPOPT_HDWEP
;
415 if (acx_set_wepopt_conf(sc
, &wep_opt
) != 0) {
416 if_printf(&sc
->sc_ic
.ic_if
, "can't set wep opt\n");
423 acx100_init_tmplt(struct acx_softc
*sc
)
425 struct acx_conf_mmap mem_map
;
427 /* Set templates start address */
428 if (acx_get_mmap_conf(sc
, &mem_map
) != 0) {
429 if_printf(&sc
->sc_ic
.ic_if
, "can't get mmap\n");
433 mem_map
.pkt_tmplt_start
= mem_map
.wep_cache_end
;
434 if (acx_set_mmap_conf(sc
, &mem_map
) != 0) {
435 if_printf(&sc
->sc_ic
.ic_if
, "can't set mmap\n");
439 /* Initialize various packet templates */
440 if (acx_init_tmplt_ordered(sc
) != 0) {
441 if_printf(&sc
->sc_ic
.ic_if
, "can't init tmplt\n");
448 acx100_init_fw_ring(struct acx_softc
*sc
)
450 struct acx100_conf_fw_ring ring
;
451 struct acx_conf_mmap mem_map
;
452 uint32_t txring_start
, rxring_start
, ring_end
;
454 /* Set firmware descriptor ring start address */
455 if (acx_get_mmap_conf(sc
, &mem_map
) != 0) {
456 if_printf(&sc
->sc_ic
.ic_if
, "can't get mmap\n");
460 txring_start
= le32toh(mem_map
.pkt_tmplt_end
) + 4;
461 rxring_start
= txring_start
+ ACX100_FW_TXRING_SIZE
;
462 ring_end
= rxring_start
+ ACX100_FW_RXRING_SIZE
;
464 mem_map
.fw_desc_start
= htole32(txring_start
);
465 if (acx_set_mmap_conf(sc
, &mem_map
) != 0) {
466 if_printf(&sc
->sc_ic
.ic_if
, "can't set mmap\n");
470 /* Set firmware descriptor ring configure */
471 bzero(&ring
, sizeof(ring
));
472 ring
.fw_ring_size
= htole32(ACX100_FW_TXRING_SIZE
+
473 ACX100_FW_RXRING_SIZE
+ 8);
475 ring
.fw_txring_num
= 1;
476 ring
.fw_txring_addr
= htole32(txring_start
);
477 ring
.fw_txring_prio
= ACX100_TXRING_PRIO_DEFAULT
;
478 ring
.fw_txdesc_num
= 0; /* XXX ignored?? */
480 ring
.fw_rxring_addr
= htole32(rxring_start
);
481 ring
.fw_rxdesc_num
= 0; /* XXX ignored?? */
483 ring
.opt
= ACX100_RINGOPT_AUTO_RESET
;
484 ACX100_SET_RING_END(&ring
, ring_end
);
485 if (acx100_set_fw_ring_conf(sc
, &ring
) != 0) {
486 if_printf(&sc
->sc_ic
.ic_if
, "can't set fw ring configure\n");
490 /* Setup firmware TX/RX descriptor ring */
491 acx100_init_fw_txring(sc
, txring_start
);
492 acx100_init_fw_rxring(sc
, rxring_start
);
497 #define MEMBLK_ALIGN(addr) \
498 (((addr) + (ACX100_MEMBLK_ALIGN - 1)) & ~(ACX100_MEMBLK_ALIGN - 1))
501 acx100_init_memory(struct acx_softc
*sc
)
503 struct acx100_conf_memblk_size memblk_sz
;
504 struct acx100_conf_mem mem
;
505 struct acx_conf_mmap mem_map
;
506 uint32_t memblk_start
, memblk_end
;
507 int total_memblk
, txblk_num
, rxblk_num
;
509 /* Set memory block start address */
510 if (acx_get_mmap_conf(sc
, &mem_map
) != 0) {
511 if_printf(&sc
->sc_ic
.ic_if
, "can't get mmap\n");
515 mem_map
.memblk_start
=
516 htole32(MEMBLK_ALIGN(le32toh(mem_map
.fw_desc_end
) + 4));
518 if (acx_set_mmap_conf(sc
, &mem_map
) != 0) {
519 if_printf(&sc
->sc_ic
.ic_if
, "can't set mmap\n");
523 /* Set memory block size */
524 memblk_sz
.memblk_size
= htole16(ACX_MEMBLOCK_SIZE
);
525 if (acx100_set_memblk_size_conf(sc
, &memblk_sz
) != 0) {
526 if_printf(&sc
->sc_ic
.ic_if
, "can't set mem block size\n");
530 /* Get memory map after setting it */
531 if (acx_get_mmap_conf(sc
, &mem_map
) != 0) {
532 if_printf(&sc
->sc_ic
.ic_if
, "can't get mmap again\n");
535 memblk_start
= le32toh(mem_map
.memblk_start
);
536 memblk_end
= le32toh(mem_map
.memblk_end
);
538 /* Set memory options */
539 mem
.opt
= htole32(ACX100_MEMOPT_MEMBLOCK
| ACX100_MEMOPT_HOSTDESC
);
540 mem
.h_rxring_paddr
= htole32(sc
->sc_ring_data
.rx_ring_paddr
);
542 total_memblk
= (memblk_end
- memblk_start
) / ACX_MEMBLOCK_SIZE
;
544 rxblk_num
= total_memblk
/ 2; /* 50% */
545 txblk_num
= total_memblk
- rxblk_num
; /* 50% */
547 DPRINTF((&sc
->sc_ic
.ic_if
, "\ttotal memory blocks\t%d\n"
548 "\trx memory blocks\t%d\n"
549 "\ttx memory blocks\t%d\n",
550 total_memblk
, rxblk_num
, txblk_num
));
552 mem
.rx_memblk_num
= htole16(rxblk_num
);
553 mem
.tx_memblk_num
= htole16(txblk_num
);
555 mem
.rx_memblk_addr
= htole32(MEMBLK_ALIGN(memblk_start
));
557 htole32(MEMBLK_ALIGN(memblk_start
+
558 (ACX_MEMBLOCK_SIZE
* rxblk_num
)));
560 if (acx100_set_mem_conf(sc
, &mem
) != 0) {
561 if_printf(&sc
->sc_ic
.ic_if
, "can't set mem options\n");
565 /* Initialize memory */
566 if (acx_init_mem(sc
) != 0) {
567 if_printf(&sc
->sc_ic
.ic_if
, "can't init mem\n");
576 acx100_init_fw_txring(struct acx_softc
*sc
, uint32_t fw_txdesc_start
)
578 struct acx_fw_txdesc fw_desc
;
579 struct acx_txbuf
*tx_buf
;
580 uint32_t desc_paddr
, fw_desc_offset
;
583 bzero(&fw_desc
, sizeof(fw_desc
));
584 fw_desc
.f_tx_ctrl
= DESC_CTRL_HOSTOWN
|
587 DESC_CTRL_FIRST_FRAG
;
589 tx_buf
= sc
->sc_buf_data
.tx_buf
;
590 fw_desc_offset
= fw_txdesc_start
;
591 desc_paddr
= sc
->sc_ring_data
.tx_ring_paddr
;
593 for (i
= 0; i
< ACX_TX_DESC_CNT
; ++i
) {
594 fw_desc
.f_tx_host_desc
= htole32(desc_paddr
);
596 if (i
== ACX_TX_DESC_CNT
- 1) {
597 fw_desc
.f_tx_next_desc
= htole32(fw_txdesc_start
);
599 fw_desc
.f_tx_next_desc
=
600 htole32(fw_desc_offset
+
601 sizeof(struct acx_fw_txdesc
));
604 tx_buf
[i
].tb_fwdesc_ofs
= fw_desc_offset
;
605 DESC_WRITE_REGION_1(sc
, fw_desc_offset
, &fw_desc
,
608 desc_paddr
+= (2 * sizeof(struct acx_host_desc
));
609 fw_desc_offset
+= sizeof(fw_desc
);
614 acx100_init_fw_rxring(struct acx_softc
*sc
, uint32_t fw_rxdesc_start
)
616 struct acx_fw_rxdesc fw_desc
;
617 uint32_t fw_desc_offset
;
620 bzero(&fw_desc
, sizeof(fw_desc
));
621 fw_desc
.f_rx_ctrl
= DESC_CTRL_RECLAIM
| DESC_CTRL_AUTODMA
;
623 fw_desc_offset
= fw_rxdesc_start
;
625 for (i
= 0; i
< ACX_RX_DESC_CNT
; ++i
) {
626 if (i
== ACX_RX_DESC_CNT
- 1) {
627 fw_desc
.f_rx_next_desc
= htole32(fw_rxdesc_start
);
629 fw_desc
.f_rx_next_desc
=
630 htole32(fw_desc_offset
+
631 sizeof(struct acx_fw_rxdesc
));
634 DESC_WRITE_REGION_1(sc
, fw_desc_offset
, &fw_desc
,
637 fw_desc_offset
+= sizeof(fw_desc
);
642 acx100_read_config(struct acx_softc
*sc
, struct acx_config
*conf
)
644 struct acx100_conf_cca_mode cca
;
645 struct acx100_conf_ed_thresh ed
;
649 * CCA mode and ED threshold MUST be read during initialization
650 * or the acx100 card won't work as expected
654 if (acx100_get_cca_mode_conf(sc
, &cca
) != 0) {
655 if_printf(&sc
->sc_ic
.ic_if
, "%s can't get cca mode\n",
659 conf
->cca_mode
= cca
.cca_mode
;
660 DPRINTF((&sc
->sc_ic
.ic_if
, "cca mode %02x\n", cca
.cca_mode
));
662 /* Get ED threshold */
663 if (acx100_get_ed_thresh_conf(sc
, &ed
) != 0) {
664 if_printf(&sc
->sc_ic
.ic_if
, "%s can't get ed threshold\n",
668 conf
->ed_thresh
= ed
.ed_thresh
;
669 DPRINTF((&sc
->sc_ic
.ic_if
, "ed threshold %02x\n", ed
.ed_thresh
));
675 acx100_write_config(struct acx_softc
*sc
, struct acx_config
*conf
)
677 struct acx100_conf_cca_mode cca
;
678 struct acx100_conf_ed_thresh ed
;
681 cca
.cca_mode
= conf
->cca_mode
;
682 if (acx100_set_cca_mode_conf(sc
, &cca
) != 0) {
683 if_printf(&sc
->sc_ic
.ic_if
, "%s can't set cca mode\n",
688 /* Set ED threshold */
689 ed
.ed_thresh
= conf
->ed_thresh
;
690 if (acx100_set_ed_thresh_conf(sc
, &ed
) != 0) {
691 if_printf(&sc
->sc_ic
.ic_if
, "%s can't set ed threshold\n",
697 acx100_set_txpower(sc
); /* ignore return value */
703 acx100_set_txpower(struct acx_softc
*sc
)
707 switch (sc
->sc_radio_type
) {
708 case ACX_RADIO_TYPE_MAXIM
:
709 map
= acx100_txpower_maxim
;
711 case ACX_RADIO_TYPE_RFMD
:
712 case ACX_RADIO_TYPE_RALINK
:
713 map
= acx100_txpower_rfmd
;
716 if_printf(&sc
->sc_ic
.ic_if
, "TX power for radio type 0x%02x "
717 "can't be set yet\n", sc
->sc_radio_type
);
721 acx_write_phyreg(sc
, ACXRV_PHYREG_TXPOWER
, map
[ACX100_TXPOWER
]);
726 acx100_set_fw_txdesc_rate(struct acx_softc
*sc
, struct acx_txbuf
*tx_buf
,
727 struct ieee80211_node
*ni
, int data_len
)
731 tx_buf
->tb_rateidx_len
= 1;
733 rate
= 2; /* 1Mbit/s */
734 tx_buf
->tb_rateidx
[0] = 0;
736 ieee80211_ratectl_findrate(ni
, data_len
,
737 tx_buf
->tb_rateidx
, 1);
738 rate
= IEEE80211_RS_RATE(&ni
->ni_rates
,
739 tx_buf
->tb_rateidx
[0]);
740 if (ACX100_CHK_RATE(&sc
->sc_ic
.ic_if
, rate
,
741 tx_buf
->tb_rateidx
[0]) < 0)
744 FW_TXDESC_SETFIELD_1(sc
, tx_buf
, f_tx_rate100
, ACX100_RATE(rate
));
750 acx100_set_bss_join_param(struct acx_softc
*sc
, void *param
, int dtim_intvl
)
752 struct acx100_bss_join
*bj
= param
;
753 struct ifnet
*ifp
= &sc
->sc_ic
.ic_if
;
754 const struct ieee80211_rateset
*rs
= &sc
->sc_ic
.ic_bss
->ni_rates
;
759 for (i
= 0; i
< rs
->rs_nrates
; ++i
) {
760 u_int map_idx
= IEEE80211_RS_RATE(rs
, i
);
763 if (ACX100_CHK_RATE(ifp
, map_idx
, i
) < 0)
766 rate
= acx100_rate_map
[map_idx
];
767 if (rs
->rs_rates
[i
] & IEEE80211_RATE_BASIC
)
768 bj
->basic_rates
|= rate
;
769 bj
->op_rates
|= rate
;
771 DPRINTF((ifp
, "basic rates:0x%02x, op rates:0x%02x\n",
772 bj
->basic_rates
, bj
->op_rates
));
774 bj
->dtim_intvl
= dtim_intvl
;
778 acx100_set_wepkey(struct acx_softc
*sc
, struct ieee80211_key
*wk
, int wk_idx
)
780 struct acx100_conf_wepkey conf_wk
;
782 if (wk
->wk_keylen
> ACX100_WEPKEY_LEN
) {
783 if_printf(&sc
->sc_ic
.ic_if
, "%dth WEP key size beyond %d\n",
784 wk_idx
, ACX100_WEPKEY_LEN
);
788 conf_wk
.action
= ACX100_WEPKEY_ACT_ADD
;
789 conf_wk
.key_len
= wk
->wk_keylen
;
790 conf_wk
.key_idx
= wk_idx
;
791 bcopy(wk
->wk_key
, conf_wk
.key
, wk
->wk_keylen
);
792 if (acx100_set_wepkey_conf(sc
, &conf_wk
) != 0) {
793 if_printf(&sc
->sc_ic
.ic_if
, "%s set %dth WEP key failed\n",
801 acx100_proc_wep_rxbuf(struct acx_softc
*sc
, struct mbuf
*m
, int *len
)
804 struct ieee80211_frame
*f
;
807 * Strip leading IV and KID, and trailing CRC
810 f
= mtod(m
, struct ieee80211_frame
*);
812 if ((f
->i_fc
[1] & IEEE80211_FC1_DIR_MASK
) == IEEE80211_FC1_DIR_DSTODS
)
813 mac_hdrlen
= sizeof(struct ieee80211_frame_addr4
);
815 mac_hdrlen
= sizeof(struct ieee80211_frame
);
817 #define IEEEWEP_IVLEN (IEEE80211_WEP_IVLEN + IEEE80211_WEP_KIDLEN)
818 #define IEEEWEP_EXLEN (IEEEWEP_IVLEN + IEEE80211_WEP_CRCLEN)
820 *len
= *len
- IEEEWEP_EXLEN
;
822 /* Move MAC header toward frame body */
823 ovbcopy(f
, (uint8_t *)f
+ IEEEWEP_IVLEN
, mac_hdrlen
);
824 m_adj(m
, IEEEWEP_IVLEN
);
831 acx100_tx_complete(struct acx_softc
*sc
, struct acx_txbuf
*tx_buf
,
832 int frame_len
, int is_fail
)
834 int rts_retries
, data_retries
;
835 struct ieee80211_ratectl_res rc_res
;
837 rts_retries
= FW_TXDESC_GETFIELD_1(sc
, tx_buf
, f_tx_rts_nretry
);
838 data_retries
= FW_TXDESC_GETFIELD_1(sc
, tx_buf
, f_tx_data_nretry
);
840 rc_res
.rc_res_rateidx
= tx_buf
->tb_rateidx
[0];
841 rc_res
.rc_res_tries
= data_retries
+ 1;
843 ieee80211_ratectl_tx_complete(tx_buf
->tb_node
, frame_len
,
844 &rc_res
, 1, data_retries
, rts_retries
,
849 acx100_ratectl_attach(struct ieee80211com
*ic
, u_int rc
)
851 struct acx_softc
*sc
= ic
->ic_if
.if_softc
;
854 case IEEE80211_RATECTL_ONOE
:
855 return &sc
->sc_onoe_param
;
856 case IEEE80211_RATECTL_NONE
:
857 /* This could only happen during detaching */
860 panic("unknown rate control algo %u\n", rc
);