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