- Import driver[acx(4)] for TI acx100/acx111 based WiFi NIC.
[dragonfly/port-amd64.git] / sys / dev / netif / acx / acx111.c
blobe381c2d3b5df24bd3a717cd3532eb6bf59662edc
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:
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.
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.
34 * $DragonFly: src/sys/dev/netif/acx/acx111.c,v 1.1 2006/04/01 02:55:36 sephe Exp $
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>
44 #include <machine/bus.h>
45 #include <machine/resource.h>
47 #include <net/if.h>
48 #include <net/if_arp.h>
49 #include <net/if_media.h>
51 #include <netproto/802_11/ieee80211_var.h>
53 #include <bus/pci/pcireg.h>
55 #define ACX_DEBUG
57 #include "if_acxreg.h"
58 #include "if_acxvar.h"
59 #include "acxcmd.h"
61 #define ACX111_CONF_MEM 0x0003
62 #define ACX111_CONF_MEMINFO 0x0005
64 #define ACX111_INTR_ENABLE (ACXRV_INTR_TX_FINI | ACXRV_INTR_RX_FINI)
66 * XXX do we really care about fowlling interrupts?
68 * ACXRV_INTR_IV_ICV_FAILURE | ACXRV_INTR_INFO |
69 * ACXRV_INTR_SCAN_FINI | ACXRV_INTR_FCS_THRESHOLD
72 #define ACX111_INTR_DISABLE (uint16_t)~(ACXRV_INTR_CMD_FINI)
74 #define ACX111_RATE_2 0x0001
75 #define ACX111_RATE_4 0x0002
76 #define ACX111_RATE_11 0x0004
77 #define ACX111_RATE_12 0x0008
78 #define ACX111_RATE_18 0x0010
79 #define ACX111_RATE_22 0x0020
80 #define ACX111_RATE_24 0x0040
81 #define ACX111_RATE_36 0x0080
82 #define ACX111_RATE_44 0x0100
83 #define ACX111_RATE_48 0x0200
84 #define ACX111_RATE_72 0x0400
85 #define ACX111_RATE_96 0x0800
86 #define ACX111_RATE_108 0x1000
87 #define ACX111_RATE(rate) [rate] = ACX111_RATE_##rate
89 /* XXX skip ACX111_RATE_44 */
90 #define ACX111_RATE_ALL 0x1eff
92 #define ACX111_TXPOWER 15
93 #define ACX111_GPIO_POWER_LED 0x0040
94 #define ACX111_EE_EADDR_OFS 0x21
96 #define ACX111_FW_TXDESC_SIZE (sizeof(struct acx_fw_txdesc) + 4)
98 #if ACX111_TXPOWER <= 12
99 #define ACX111_TXPOWER_VAL 1
100 #else
101 #define ACX111_TXPOWER_VAL 2
102 #endif
105 * NOTE:
106 * Following structs' fields are little endian
109 struct acx111_bss_join {
110 uint16_t basic_rates;
111 uint8_t dtim_intvl;
112 } __packed;
114 struct acx111_conf_mem {
115 struct acx_conf confcom;
117 uint16_t sta_max; /* max num of sta, ACX111_STA_MAX */
118 uint16_t memblk_size; /* mem block size */
119 uint8_t rx_memblk_perc; /* percent of RX mem block, unit: 5% */
120 uint8_t fw_rxring_num; /* num of RX ring */
121 uint8_t fw_txring_num; /* num of TX ring */
122 uint8_t opt; /* see ACX111_MEMOPT_ */
123 uint8_t xfer_perc; /* frag/xfer proportion, unit: 5% */
124 uint16_t reserved0;
125 uint8_t reserved1;
127 uint8_t fw_rxdesc_num; /* num of fw rx desc */
128 uint8_t fw_rxring_reserved1;
129 uint8_t fw_rxring_type; /* see ACX111_RXRING_TYPE_ */
130 uint8_t fw_rxring_prio; /* see ACX111_RXRING_PRIO_ */
132 uint32_t h_rxring_paddr; /* host rx desc start phyaddr */
134 uint8_t fw_txdesc_num; /* num of fw tx desc */
135 uint8_t fw_txring_reserved1;
136 uint8_t fw_txring_reserved2;
137 uint8_t fw_txring_attr; /* see ACX111_TXRING_ATTR_ */
138 } __packed;
140 #define ACX111_STA_MAX 32
141 #define ACX111_RX_MEMBLK_PERCENT 10 /* 50% */
142 #define ACX111_XFER_PERCENT 15 /* 75% */
143 #define ACX111_RXRING_TYPE_DEFAULT 7
144 #define ACX111_RXRING_PRIO_DEFAULT 0
145 #define ACX111_TXRING_ATTR_DEFAULT 0
146 #define ACX111_MEMOPT_DEFAULT 0
148 struct acx111_conf_meminfo {
149 struct acx_conf confcom;
150 uint32_t tx_memblk_addr; /* start addr of tx mem blocks */
151 uint32_t rx_memblk_addr; /* start addr of rx mem blocks */
152 uint32_t fw_rxring_start; /* start phyaddr of fw rx ring */
153 uint32_t reserved0;
154 uint32_t fw_txring_start; /* start phyaddr of fw tx ring */
155 uint8_t fw_txring_attr; /* XXX see ACX111_TXRING_ATTR_ */
156 uint16_t reserved1;
157 uint8_t reserved2;
158 } __packed;
160 struct acx111_conf_txpower {
161 struct acx_conf confcom;
162 uint8_t txpower;
163 } __packed;
165 struct acx111_conf_option {
166 struct acx_conf confcom;
167 uint32_t feature;
168 uint32_t dataflow; /* see ACX111_DATAFLOW_ */
169 } __packed;
171 #define ACX111_DATAFLOW_SNIFFER 0x00000080
172 #define ACX111_DATAFLOW_NO_TXCRYPT 0x00000001
174 struct acx111_wepkey {
175 uint8_t mac_addr[IEEE80211_ADDR_LEN];
176 uint16_t action; /* see ACX111_WEPKEY_ACT_ */
177 uint16_t reserved;
178 uint8_t key_len;
179 uint8_t key_type; /* see ACX111_WEPKEY_TYPE_ */
180 uint8_t index; /* XXX ?? */
181 uint8_t key_idx;
182 uint8_t counter[6];
183 #define ACX111_WEPKEY_LEN 32
184 uint8_t key[ACX111_WEPKEY_LEN];
185 } __packed;
187 #define ACX111_WEPKEY_ACT_ADD 1
188 #define ACX111_WEPKEY_TYPE_DEFAULT 0
190 #define ACX111_CONF_FUNC(sg, name) _ACX_CONF_FUNC(sg, name, 111)
191 #define ACX_CONF_mem ACX111_CONF_MEM
192 #define ACX_CONF_meminfo ACX111_CONF_MEMINFO
193 #define ACX_CONF_txpower ACX_CONF_TXPOWER
194 #define ACX_CONF_option ACX_CONF_OPTION
195 ACX111_CONF_FUNC(set, mem);
196 ACX111_CONF_FUNC(get, meminfo);
197 ACX111_CONF_FUNC(set, txpower);
198 ACX111_CONF_FUNC(get, option);
199 ACX111_CONF_FUNC(set, option);
201 static const uint16_t acx111_reg[ACXREG_MAX] = {
202 ACXREG(SOFT_RESET, 0x0000),
204 ACXREG(FWMEM_ADDR, 0x0014),
205 ACXREG(FWMEM_DATA, 0x0018),
206 ACXREG(FWMEM_CTRL, 0x001c),
207 ACXREG(FWMEM_START, 0x0020),
209 ACXREG(EVENT_MASK, 0x0034),
211 ACXREG(INTR_TRIG, 0x00b4),
212 ACXREG(INTR_MASK, 0x00d4),
213 ACXREG(INTR_STATUS, 0x00f0),
214 ACXREG(INTR_STATUS_CLR, 0x00e4),
215 ACXREG(INTR_ACK, 0x00e8),
217 ACXREG(HINTR_TRIG, 0x00ec),
218 ACXREG(RADIO_ENABLE, 0x01d0),
220 ACXREG(EEPROM_INIT, 0x0100),
221 ACXREG(EEPROM_CTRL, 0x0338),
222 ACXREG(EEPROM_ADDR, 0x033c),
223 ACXREG(EEPROM_DATA, 0x0340),
224 ACXREG(EEPROM_CONF, 0x0344),
225 ACXREG(EEPROM_INFO, 0x0390),
227 ACXREG(PHY_ADDR, 0x0350),
228 ACXREG(PHY_DATA, 0x0354),
229 ACXREG(PHY_CTRL, 0x0358),
231 ACXREG(GPIO_OUT_ENABLE, 0x0374),
232 ACXREG(GPIO_OUT, 0x037c),
234 ACXREG(CMD_REG_OFFSET, 0x0388),
235 ACXREG(INFO_REG_OFFSET, 0x038c),
237 ACXREG(RESET_SENSE, 0x0104),
238 ACXREG(ECPU_CTRL, 0x0108)
241 /* XXX */
242 static uint16_t acx111_rate_map[109] = {
243 ACX111_RATE(2),
244 ACX111_RATE(4),
245 ACX111_RATE(11),
246 ACX111_RATE(22),
247 ACX111_RATE(12),
248 ACX111_RATE(18),
249 ACX111_RATE(24),
250 ACX111_RATE(36),
251 ACX111_RATE(48),
252 ACX111_RATE(72),
253 ACX111_RATE(96),
254 ACX111_RATE(108)
258 * For firmware whose version is listed in the following array,
259 * software WEP should be used, since hardware WEP's performance
260 * is too poor
262 static const uint32_t acx111_softwep_fwver[] = {
263 0x01020030,
264 0 /* KEEP THIS */
267 static int acx111_init(struct acx_softc *);
268 static int acx111_init_memory(struct acx_softc *);
269 static void acx111_init_fw_txring(struct acx_softc *, uint32_t);
271 static int acx111_write_config(struct acx_softc *, struct acx_config *);
273 static void acx111_set_fw_txdesc_rate(struct acx_softc *,
274 struct acx_txbuf *, int);
275 static void acx111_set_bss_join_param(struct acx_softc *, void *, int);
277 static int acx111_set_wepkey(struct acx_softc *,
278 struct ieee80211_wepkey *, int);
280 void
281 acx111_set_param(device_t dev)
283 struct acx_softc *sc = device_get_softc(dev);
285 sc->chip_mem1_rid = PCIR_BAR(0);
286 sc->chip_mem2_rid = PCIR_BAR(1);
287 sc->chip_ioreg = acx111_reg;
288 sc->chip_intr_enable = ACX111_INTR_ENABLE;
289 sc->chip_intr_disable = ACX111_INTR_DISABLE;
290 sc->chip_gpio_pled = ACX111_GPIO_POWER_LED;
291 sc->chip_ee_eaddr_ofs = ACX111_EE_EADDR_OFS;
293 sc->chip_phymode = IEEE80211_MODE_11G;
294 sc->chip_chan_flags = IEEE80211_CHAN_CCK |
295 IEEE80211_CHAN_OFDM |
296 IEEE80211_CHAN_DYN |
297 IEEE80211_CHAN_2GHZ;
298 sc->sc_ic.ic_phytype = IEEE80211_T_OFDM;
299 sc->sc_ic.ic_sup_rates[IEEE80211_MODE_11B] = acx_rates_11b;
300 sc->sc_ic.ic_sup_rates[IEEE80211_MODE_11G] = acx_rates_11g;
302 sc->chip_init = acx111_init;
303 sc->chip_set_wepkey = acx111_set_wepkey;
304 sc->chip_write_config = acx111_write_config;
305 sc->chip_set_fw_txdesc_rate = acx111_set_fw_txdesc_rate;
306 sc->chip_set_bss_join_param = acx111_set_bss_join_param;
309 static int
310 acx111_init(struct acx_softc *sc)
313 * NOTE:
314 * Order of initialization:
315 * 1) Templates
316 * 2) Hardware memory
317 * Above order is critical to get a correct memory map
320 if (acx_init_tmplt_ordered(sc) != 0) {
321 if_printf(&sc->sc_ic.ic_if, "%s can't initialize templates\n",
322 __func__);
323 return ENXIO;
326 if (acx111_init_memory(sc) != 0) {
327 if_printf(&sc->sc_ic.ic_if, "%s can't initialize hw memory\n",
328 __func__);
329 return ENXIO;
331 return 0;
334 static int
335 acx111_init_memory(struct acx_softc *sc)
337 struct acx111_conf_mem mem;
338 struct acx111_conf_meminfo mem_info;
340 /* Set memory configuration */
341 bzero(&mem, sizeof(mem));
343 mem.sta_max = htole16(ACX111_STA_MAX);
344 mem.memblk_size = htole16(ACX_MEMBLOCK_SIZE);
345 mem.rx_memblk_perc = ACX111_RX_MEMBLK_PERCENT;
346 mem.opt = ACX111_MEMOPT_DEFAULT;
347 mem.xfer_perc = ACX111_XFER_PERCENT;
349 mem.fw_rxring_num = 1;
350 mem.fw_rxring_type = ACX111_RXRING_TYPE_DEFAULT;
351 mem.fw_rxring_prio = ACX111_RXRING_PRIO_DEFAULT;
352 mem.fw_rxdesc_num = ACX_RX_DESC_CNT;
353 mem.h_rxring_paddr = htole32(sc->sc_ring_data.rx_ring_paddr);
355 mem.fw_txring_num = 1;
356 mem.fw_txring_attr = ACX111_TXRING_ATTR_DEFAULT;
357 mem.fw_txdesc_num = ACX_TX_DESC_CNT;
359 if (acx111_set_mem_conf(sc, &mem) != 0) {
360 if_printf(&sc->sc_ic.ic_if, "can't set mem\n");
361 return 1;
364 /* Get memory configuration */
365 if (acx111_get_meminfo_conf(sc, &mem_info) != 0) {
366 if_printf(&sc->sc_ic.ic_if, "can't get meminfo\n");
367 return 1;
370 /* Setup firmware TX descriptor ring */
371 acx111_init_fw_txring(sc, le32toh(mem_info.fw_txring_start));
374 * There is no need to setup firmware RX descriptor ring,
375 * it is automaticly setup by hardware.
378 return 0;
381 static void
382 acx111_init_fw_txring(struct acx_softc *sc, uint32_t fw_txdesc_start)
384 struct acx_txbuf *tx_buf;
385 uint32_t desc_paddr;
386 int i;
388 tx_buf = sc->sc_buf_data.tx_buf;
389 desc_paddr = sc->sc_ring_data.tx_ring_paddr;
391 for (i = 0; i < ACX_TX_DESC_CNT; ++i) {
392 tx_buf[i].tb_fwdesc_ofs = fw_txdesc_start +
393 (i * ACX111_FW_TXDESC_SIZE);
396 * Except for the following fields, rest of the fields
397 * are setup by hardware.
399 FW_TXDESC_SETFIELD_4(sc, &tx_buf[i], f_tx_host_desc,
400 desc_paddr);
401 FW_TXDESC_SETFIELD_1(sc, &tx_buf[i], f_tx_ctrl,
402 DESC_CTRL_HOSTOWN);
404 desc_paddr += (2 * sizeof(struct acx_host_desc));
408 static int
409 acx111_write_config(struct acx_softc *sc, struct acx_config *conf)
411 struct acx111_conf_txpower tx_power;
412 struct acx111_conf_option opt;
413 uint32_t dataflow;
414 const uint32_t *fwver;
416 /* Set TX power */
417 tx_power.txpower = ACX111_TXPOWER_VAL;
418 if (acx111_set_txpower_conf(sc, &tx_power) != 0) {
419 if_printf(&sc->sc_ic.ic_if, "%s can't set TX power\n",
420 __func__);
421 return ENXIO;
425 * Turn off sniffering
426 * Turn on hardware/software WEP
428 if (acx111_get_option_conf(sc, &opt) != 0) {
429 if_printf(&sc->sc_ic.ic_if, "%s can't get option\n", __func__);
430 return ENXIO;
433 dataflow = le32toh(opt.dataflow) & ~ACX111_DATAFLOW_SNIFFER;
435 for (fwver = acx111_softwep_fwver; *fwver != 0; ++fwver) {
436 if (sc->sc_firmware_ver == *fwver)
437 break;
440 if (*fwver != 0) {
441 DPRINTF((&sc->sc_ic.ic_if, "disable hardware WEP\n"));
442 dataflow |= ACX111_DATAFLOW_NO_TXCRYPT;
443 sc->sc_softwep = 1;
444 } else {
445 DPRINTF((&sc->sc_ic.ic_if, "enable hardware WEP\n"));
446 dataflow &= ~ACX111_DATAFLOW_NO_TXCRYPT;
447 sc->sc_softwep = 0;
450 opt.dataflow = htole32(dataflow);
452 if (acx111_set_option_conf(sc, &opt) != 0) {
453 if_printf(&sc->sc_ic.ic_if, "%s can't set option\n", __func__);
454 return ENXIO;
456 return 0;
459 static void
460 acx111_set_fw_txdesc_rate(struct acx_softc *sc, struct acx_txbuf *tx_buf,
461 int rate0)
463 uint16_t rate;
465 rate = acx111_rate_map[rate0];
466 KASSERT(rate != 0, ("no rate map for %d\n", rate0));
468 FW_TXDESC_SETFIELD_2(sc, tx_buf, u.r2.rate111, rate);
471 static void
472 acx111_set_bss_join_param(struct acx_softc *sc, void *param, int dtim_intvl)
474 struct acx111_bss_join *bj = param;
476 bj->basic_rates = htole16(ACX111_RATE_ALL);
477 bj->dtim_intvl = dtim_intvl;
480 static int
481 acx111_set_wepkey(struct acx_softc *sc, struct ieee80211_wepkey *wk, int wk_idx)
483 struct acx111_wepkey wepkey;
485 if (wk->wk_len > ACX111_WEPKEY_LEN) {
486 if_printf(&sc->sc_ic.ic_if, "%dth WEP key size beyond %d\n",
487 wk_idx, ACX111_WEPKEY_LEN);
488 return EINVAL;
491 bzero(&wepkey, sizeof(wepkey));
492 wepkey.action = htole16(ACX111_WEPKEY_ACT_ADD);
493 wepkey.key_type = ACX111_WEPKEY_TYPE_DEFAULT;
494 wepkey.index = 0; /* XXX ignored? */
495 wepkey.key_len = wk->wk_len;
496 wepkey.key_idx = wk_idx;
497 bcopy(wk->wk_key, wepkey.key, wk->wk_len);
498 if (acx_exec_command(sc, ACXCMD_WEP_MGMT, &wepkey, sizeof(wepkey),
499 NULL, 0) != 0) {
500 if_printf(&sc->sc_ic.ic_if, "%s set %dth WEP key failed\n",
501 __func__, wk_idx);
502 return ENXIO;
504 return 0;