xref: /openbsd/sys/dev/ic/acx100.c (revision 4b1a56af)
1 /*	$OpenBSD: acx100.c,v 1.28 2022/01/09 05:42:38 jsg 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 controlled 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
acx100_set_param(struct acx_softc * sc)259 acx100_set_param(struct acx_softc *sc)
260 {
261 	sc->chip_mem1_rid = PCIR_BAR(1);
262 	sc->chip_mem2_rid = PCIR_BAR(2);
263 	sc->chip_ioreg = acx100_reg;
264 	sc->chip_hw_crypt = 1;
265 	sc->chip_intr_enable = ACX100_INTR_ENABLE;
266 #ifndef IEEE80211_STA_ONLY
267 	sc->chip_intr_enable |= ACXRV_INTR_DTIM;
268 #endif
269 	sc->chip_intr_disable = ACX100_INTR_DISABLE;
270 	sc->chip_gpio_pled = ACX100_GPIO_POWER_LED;
271 	sc->chip_ee_eaddr_ofs = ACX100_EE_EADDR_OFS;
272 	sc->chip_txdesc1_len = ACX_FRAME_HDRLEN;
273 	sc->chip_fw_txdesc_ctrl = DESC_CTRL_AUTODMA |
274 	    DESC_CTRL_RECLAIM | DESC_CTRL_FIRST_FRAG;
275 
276 	sc->chip_phymode = IEEE80211_MODE_11B;
277 	sc->chip_chan_flags = IEEE80211_CHAN_B;
278 	sc->sc_ic.ic_phytype = IEEE80211_T_DS;
279 	sc->sc_ic.ic_sup_rates[IEEE80211_MODE_11B] = ieee80211_std_rateset_11b;
280 
281 	sc->chip_init = acx100_init;
282 	sc->chip_set_wepkey = acx100_set_wepkey;
283 	sc->chip_read_config = acx100_read_config;
284 	sc->chip_write_config = acx100_write_config;
285 	sc->chip_set_fw_txdesc_rate = acx100_set_fw_txdesc_rate;
286 	sc->chip_set_bss_join_param = acx100_set_bss_join_param;
287 	sc->chip_proc_wep_rxbuf = acx100_proc_wep_rxbuf;
288 }
289 
290 int
acx100_init(struct acx_softc * sc)291 acx100_init(struct acx_softc *sc)
292 {
293 	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 	if (acx100_init_wep(sc) != 0) {
305 		printf("%s: %s can't initialize wep\n",
306 		    ifp->if_xname, __func__);
307 		return (ENXIO);
308 	}
309 
310 	if (acx100_init_tmplt(sc) != 0) {
311 		printf("%s: %s can't initialize templates\n",
312 		    ifp->if_xname, __func__);
313 		return (ENXIO);
314 	}
315 
316 	if (acx100_init_fw_ring(sc) != 0) {
317 		printf("%s: %s can't initialize fw ring\n",
318 		    ifp->if_xname, __func__);
319 		return (ENXIO);
320 	}
321 
322 	if (acx100_init_memory(sc) != 0) {
323 		printf("%s: %s can't initialize hw memory\n",
324 		    ifp->if_xname, __func__);
325 		return (ENXIO);
326 	}
327 
328 	return (0);
329 }
330 
331 int
acx100_init_wep(struct acx_softc * sc)332 acx100_init_wep(struct acx_softc *sc)
333 {
334 	struct acx_conf_wepopt wep_opt;
335 	struct acx_conf_mmap mem_map;
336 	struct ifnet *ifp = &sc->sc_ic.ic_if;
337 
338 	/* Set WEP cache start/end address */
339 	if (acx_get_conf(sc, ACX_CONF_MMAP, &mem_map, sizeof(mem_map)) != 0) {
340 		printf("%s: can't get mmap\n", ifp->if_xname);
341 		return (1);
342 	}
343 
344 	mem_map.wep_cache_start = htole32(letoh32(mem_map.code_end) + 4);
345 	mem_map.wep_cache_end = htole32(letoh32(mem_map.code_end) + 4);
346 	if (acx_set_conf(sc, ACX_CONF_MMAP, &mem_map, sizeof(mem_map)) != 0) {
347 		printf("%s: can't set mmap\n", ifp->if_xname);
348 		return (1);
349 	}
350 
351 	/* Set WEP options */
352 	wep_opt.nkey = htole16(IEEE80211_WEP_NKID + 10);
353 	wep_opt.opt = WEPOPT_HDWEP;
354 	if (acx_set_conf(sc, ACX_CONF_WEPOPT, &wep_opt, sizeof(wep_opt)) != 0) {
355 		printf("%s: can't set wep opt\n", ifp->if_xname);
356 		return (1);
357 	}
358 
359 	return (0);
360 }
361 
362 int
acx100_init_tmplt(struct acx_softc * sc)363 acx100_init_tmplt(struct acx_softc *sc)
364 {
365 	struct acx_conf_mmap mem_map;
366 	struct ifnet *ifp = &sc->sc_ic.ic_if;
367 
368 	/* Set templates start address */
369 	if (acx_get_conf(sc, ACX_CONF_MMAP, &mem_map, sizeof(mem_map)) != 0) {
370 		printf("%s: can't get mmap\n", ifp->if_xname);
371 		return (1);
372 	}
373 
374 	mem_map.pkt_tmplt_start = mem_map.wep_cache_end;
375 	if (acx_set_conf(sc, ACX_CONF_MMAP, &mem_map, sizeof(mem_map)) != 0) {
376 		printf("%s: can't set mmap\n", ifp->if_xname);
377 		return (1);
378 	}
379 
380 	/* Initialize various packet templates */
381 	if (acx_init_tmplt_ordered(sc) != 0) {
382 		printf("%s: can't init tmplt\n", ifp->if_xname);
383 		return (1);
384 	}
385 
386 	return (0);
387 }
388 
389 int
acx100_init_fw_ring(struct acx_softc * sc)390 acx100_init_fw_ring(struct acx_softc *sc)
391 {
392 	struct acx100_conf_fw_ring ring;
393 	struct acx_conf_mmap mem_map;
394 	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 	if (acx_get_conf(sc, ACX_CONF_MMAP, &mem_map, sizeof(mem_map)) != 0) {
399 		printf("%s: can't get mmap\n", ifp->if_xname);
400 		return (1);
401 	}
402 
403 	txring_start = letoh32(mem_map.pkt_tmplt_end) + 4;
404 	rxring_start = txring_start + ACX100_FW_TXRING_SIZE;
405 	ring_end = rxring_start + ACX100_FW_RXRING_SIZE;
406 
407 	mem_map.fw_desc_start = htole32(txring_start);
408 	if (acx_set_conf(sc, ACX_CONF_MMAP, &mem_map, sizeof(mem_map)) != 0) {
409 		printf("%s: can't set mmap\n", ifp->if_xname);
410 		return (1);
411 	}
412 
413 	/* Set firmware descriptor ring configure */
414 	bzero(&ring, sizeof(ring));
415 	ring.fw_ring_size = htole32(ACX100_FW_TXRING_SIZE +
416 	    ACX100_FW_RXRING_SIZE + 8);
417 
418 	ring.fw_txring_num = 1;
419 	ring.fw_txring_addr = htole32(txring_start);
420 	ring.fw_txring_prio = ACX100_TXRING_PRIO_DEFAULT;
421 	ring.fw_txdesc_num = 0; /* XXX ignored?? */
422 
423 	ring.fw_rxring_addr = htole32(rxring_start);
424 	ring.fw_rxdesc_num = 0; /* XXX ignored?? */
425 
426 	ring.opt = ACX100_RINGOPT_AUTO_RESET;
427 	ACX100_SET_RING_END(&ring, ring_end);
428 	if (acx_set_conf(sc, ACX100_CONF_FW_RING, &ring, sizeof(ring)) != 0) {
429 		printf("%s: can't set fw ring configure\n", ifp->if_xname);
430 		return (1);
431 	}
432 
433 	/* Setup firmware TX/RX descriptor ring */
434 	acx100_init_fw_txring(sc, txring_start);
435 	acx100_init_fw_rxring(sc, rxring_start);
436 
437 	return (0);
438 }
439 
440 #define MEMBLK_ALIGN(addr)	\
441     (((addr) + (ACX100_MEMBLK_ALIGN - 1)) & ~(ACX100_MEMBLK_ALIGN - 1))
442 
443 int
acx100_init_memory(struct acx_softc * sc)444 acx100_init_memory(struct acx_softc *sc)
445 {
446 	struct acx100_conf_memblk_size memblk_sz;
447 	struct acx100_conf_mem mem;
448 	struct acx_conf_mmap mem_map;
449 	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 	if (acx_get_conf(sc, ACX_CONF_MMAP, &mem_map, sizeof(mem_map)) != 0) {
455 		printf("%s: can't get mmap\n", ifp->if_xname);
456 		return (1);
457 	}
458 
459 	mem_map.memblk_start =
460 	    htole32(MEMBLK_ALIGN(letoh32(mem_map.fw_desc_end) + 4));
461 
462 	if (acx_set_conf(sc, ACX_CONF_MMAP, &mem_map, sizeof(mem_map)) != 0) {
463 		printf("%s: can't set mmap\n", ifp->if_xname);
464 		return (1);
465 	}
466 
467 	/* Set memory block size */
468 	memblk_sz.memblk_size = htole16(ACX_MEMBLOCK_SIZE);
469 	if (acx_set_conf(sc, ACX_CONF_MEMBLK_SIZE, &memblk_sz,
470 	    sizeof(memblk_sz)) != 0) {
471 		printf("%s: can't set mem block size\n", ifp->if_xname);
472 		return (1);
473 	}
474 
475 	/* Get memory map after setting it */
476 	if (acx_get_conf(sc, ACX_CONF_MMAP, &mem_map, sizeof(mem_map)) != 0) {
477 		printf("%s: can't get mmap again\n", ifp->if_xname);
478 		return (1);
479 	}
480 	memblk_start = letoh32(mem_map.memblk_start);
481 	memblk_end = letoh32(mem_map.memblk_end);
482 
483 	/* Set memory options */
484 	mem.opt = htole32(ACX100_MEMOPT_MEMBLOCK | ACX100_MEMOPT_HOSTDESC);
485 	mem.h_rxring_paddr = htole32(sc->sc_ring_data.rx_ring_paddr);
486 
487 	total_memblk = (memblk_end - memblk_start) / ACX_MEMBLOCK_SIZE;
488 
489 	rxblk_num = total_memblk / 2;		/* 50% */
490 	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 	mem.rx_memblk_num = htole16(rxblk_num);
498 	mem.tx_memblk_num = htole16(txblk_num);
499 
500 	mem.rx_memblk_addr = htole32(MEMBLK_ALIGN(memblk_start));
501 	mem.tx_memblk_addr = htole32(MEMBLK_ALIGN(memblk_start +
502 	    (ACX_MEMBLOCK_SIZE * rxblk_num)));
503 
504 	if (acx_set_conf(sc, ACX100_CONF_MEMOPT, &mem, sizeof(mem)) != 0) {
505 		printf("%s: can't set mem options\n", ifp->if_xname);
506 		return (1);
507 	}
508 
509 	/* Initialize memory */
510 	if (acx_exec_command(sc, ACXCMD_INIT_MEM, NULL, 0, NULL, 0) != 0) {
511 		printf("%s: can't init mem\n", ifp->if_xname);
512 		return (1);
513 	}
514 
515 	return (0);
516 }
517 
518 #undef MEMBLK_ALIGN
519 
520 void
acx100_init_fw_txring(struct acx_softc * sc,uint32_t fw_txdesc_start)521 acx100_init_fw_txring(struct acx_softc *sc, uint32_t fw_txdesc_start)
522 {
523 	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 	bzero(&fw_desc, sizeof(fw_desc));
529 	fw_desc.f_tx_ctrl = DESC_CTRL_HOSTOWN | DESC_CTRL_RECLAIM |
530 	    DESC_CTRL_AUTODMA | DESC_CTRL_FIRST_FRAG;
531 
532 	tx_buf = sc->sc_buf_data.tx_buf;
533 	fw_desc_offset = fw_txdesc_start;
534 	desc_paddr = sc->sc_ring_data.tx_ring_paddr;
535 
536 	for (i = 0; i < ACX_TX_DESC_CNT; ++i) {
537 		fw_desc.f_tx_host_desc = htole32(desc_paddr);
538 
539 		if (i == ACX_TX_DESC_CNT - 1) {
540 			fw_desc.f_tx_next_desc = htole32(fw_txdesc_start);
541 		} else {
542 			fw_desc.f_tx_next_desc = htole32(fw_desc_offset +
543 			    sizeof(struct acx_fw_txdesc));
544 		}
545 
546 		tx_buf[i].tb_fwdesc_ofs = fw_desc_offset;
547 		DESC_WRITE_REGION_1(sc, fw_desc_offset, &fw_desc,
548 		    sizeof(fw_desc));
549 
550 		desc_paddr += (2 * sizeof(struct acx_host_desc));
551 		fw_desc_offset += sizeof(fw_desc);
552 	}
553 }
554 
555 void
acx100_init_fw_rxring(struct acx_softc * sc,uint32_t fw_rxdesc_start)556 acx100_init_fw_rxring(struct acx_softc *sc, uint32_t fw_rxdesc_start)
557 {
558 	struct acx_fw_rxdesc fw_desc;
559 	uint32_t fw_desc_offset;
560 	int i;
561 
562 	bzero(&fw_desc, sizeof(fw_desc));
563 	fw_desc.f_rx_ctrl = DESC_CTRL_RECLAIM | DESC_CTRL_AUTODMA;
564 
565 	fw_desc_offset = fw_rxdesc_start;
566 
567 	for (i = 0; i < ACX_RX_DESC_CNT; ++i) {
568 		if (i == ACX_RX_DESC_CNT - 1) {
569 			fw_desc.f_rx_next_desc = htole32(fw_rxdesc_start);
570 		} else {
571 			fw_desc.f_rx_next_desc =
572 			    htole32(fw_desc_offset +
573 			    sizeof(struct acx_fw_rxdesc));
574 		}
575 
576 		DESC_WRITE_REGION_1(sc, fw_desc_offset, &fw_desc,
577 		    sizeof(fw_desc));
578 
579 		fw_desc_offset += sizeof(fw_desc);
580 	}
581 }
582 
583 int
acx100_read_config(struct acx_softc * sc,struct acx_config * conf)584 acx100_read_config(struct acx_softc *sc, struct acx_config *conf)
585 {
586 	struct acx100_conf_cca_mode cca;
587 	struct acx100_conf_ed_thresh ed;
588 	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 	if (acx_get_conf(sc, ACX_CONF_CCA_MODE, &cca, sizeof(cca)) != 0) {
598 		printf("%s: %s can't get cca mode\n",
599 		    ifp->if_xname, __func__);
600 		return (ENXIO);
601 	}
602 	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 	if (acx_get_conf(sc, ACX_CONF_ED_THRESH, &ed, sizeof(ed)) != 0) {
607 		printf("%s: %s can't get ed threshold\n",
608 		    ifp->if_xname, __func__);
609 		return (ENXIO);
610 	}
611 	conf->ed_thresh = ed.ed_thresh;
612 	DPRINTF(("%s: ed threshold %02x\n", ifp->if_xname, ed.ed_thresh));
613 
614 	return (0);
615 }
616 
617 int
acx100_write_config(struct acx_softc * sc,struct acx_config * conf)618 acx100_write_config(struct acx_softc *sc, struct acx_config *conf)
619 {
620 	struct acx100_conf_cca_mode cca;
621 	struct acx100_conf_ed_thresh ed;
622 	struct ifnet *ifp = &sc->sc_ic.ic_if;
623 
624 	/* Set CCA mode */
625 	cca.cca_mode = conf->cca_mode;
626 	if (acx_set_conf(sc, ACX_CONF_CCA_MODE, &cca, sizeof(cca)) != 0) {
627 		printf("%s: %s can't set cca mode\n",
628 		    ifp->if_xname, __func__);
629 		return (ENXIO);
630 	}
631 
632 	/* Set ED threshold */
633 	ed.ed_thresh = conf->ed_thresh;
634 	if (acx_set_conf(sc, ACX_CONF_ED_THRESH, &ed, sizeof(ed)) != 0) {
635 		printf("%s: %s can't set ed threshold\n",
636 		    ifp->if_xname, __func__);
637 		return (ENXIO);
638 	}
639 
640 	/* Set TX power */
641 	acx100_set_txpower(sc);	/* ignore return value */
642 
643 	return (0);
644 }
645 
646 int
acx100_set_txpower(struct acx_softc * sc)647 acx100_set_txpower(struct acx_softc *sc)
648 {
649 	struct ifnet *ifp = &sc->sc_ic.ic_if;
650 	const uint8_t *map;
651 
652 	switch (sc->sc_radio_type) {
653 	case ACX_RADIO_TYPE_MAXIM:
654 		map = acx100_txpower_maxim;
655 		break;
656 	case ACX_RADIO_TYPE_RFMD:
657 	case ACX_RADIO_TYPE_RALINK:
658 		map = acx100_txpower_rfmd;
659 		break;
660 	default:
661 		printf("%s: TX power for radio type 0x%02x can't be set yet\n",
662 		    ifp->if_xname, sc->sc_radio_type);
663 		return (1);
664 	}
665 
666 	acx_write_phyreg(sc, ACXRV_PHYREG_TXPOWER, map[ACX100_TXPOWER]);
667 
668 	return (0);
669 }
670 
671 void
acx100_set_fw_txdesc_rate(struct acx_softc * sc,struct acx_txbuf * tx_buf,int rate)672 acx100_set_fw_txdesc_rate(struct acx_softc *sc, struct acx_txbuf *tx_buf,
673     int rate)
674 {
675 	FW_TXDESC_SETFIELD_1(sc, tx_buf, f_tx_rate100, ACX100_RATE(rate));
676 }
677 
678 void
acx100_set_bss_join_param(struct acx_softc * sc,void * param,int dtim_intvl)679 acx100_set_bss_join_param(struct acx_softc *sc, void *param, int dtim_intvl)
680 {
681 	struct acx100_bss_join *bj = param;
682 
683 	bj->dtim_intvl = dtim_intvl;
684 	bj->basic_rates = 15;	/* XXX */
685 	bj->all_rates = 31;	/* XXX */
686 }
687 
688 int
acx100_set_wepkey(struct acx_softc * sc,struct ieee80211_key * k,int k_idx)689 acx100_set_wepkey(struct acx_softc *sc, struct ieee80211_key *k, int k_idx)
690 {
691 	struct acx100_conf_wepkey conf_wk;
692 	struct ifnet *ifp = &sc->sc_ic.ic_if;
693 
694 	if (k->k_len > ACX100_WEPKEY_LEN) {
695 		printf("%s: %dth WEP key size beyond %d\n",
696 		    ifp->if_xname, k_idx, ACX100_WEPKEY_LEN);
697 		return EINVAL;
698 	}
699 
700 	conf_wk.action = ACX100_WEPKEY_ACT_ADD;
701 	conf_wk.key_len = k->k_len;
702 	conf_wk.key_idx = k_idx;
703 	bcopy(k->k_key, conf_wk.key, k->k_len);
704 	if (acx_set_conf(sc, ACX_CONF_WEPKEY, &conf_wk, sizeof(conf_wk)) != 0) {
705 		printf("%s: %s set %dth WEP key failed\n",
706 		    ifp->if_xname, __func__, k_idx);
707 		return ENXIO;
708 	}
709 	return 0;
710 }
711 
712 void
acx100_proc_wep_rxbuf(struct acx_softc * sc,struct mbuf * m,int * len)713 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 	f = mtod(m, struct ieee80211_frame *);
722 
723 	if (ieee80211_has_addr4(f))
724 		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 	*len = *len - IEEEWEP_EXLEN;
732 
733 	/* Move MAC header toward frame body */
734 	memmove((uint8_t *)f + IEEEWEP_IVLEN, f, mac_hdrlen);
735 	m_adj(m, IEEEWEP_IVLEN);
736 
737 #undef IEEEWEP_EXLEN
738 #undef IEEEWEP_IVLEN
739 }
740