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