1/*	$OpenBSD: acx111.c,v 1.24 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/endian.h>
57#include <sys/socket.h>
58#include <sys/systm.h>
59#include <sys/device.h>
60
61#include <machine/bus.h>
62
63#include <net/if.h>
64#include <net/if_media.h>
65
66#include <netinet/in.h>
67#include <netinet/if_ether.h>
68
69#include <net80211/ieee80211_var.h>
70#include <net80211/ieee80211_amrr.h>
71#include <net80211/ieee80211_radiotap.h>
72
73#include <dev/pci/pcireg.h>
74
75#include <dev/ic/acxvar.h>
76#include <dev/ic/acxreg.h>
77
78#define ACX111_CONF_MEM		0x0003
79#define ACX111_CONF_MEMINFO	0x0005
80
81#define ACX111_INTR_ENABLE	(ACXRV_INTR_TX_FINI | ACXRV_INTR_RX_FINI)
82/*
83 * XXX do we really care about fowlling interrupts?
84 *
85 * ACXRV_INTR_IV_ICV_FAILURE | ACXRV_INTR_INFO |
86 * ACXRV_INTR_SCAN_FINI | ACXRV_INTR_FCS_THRESHOLD
87 */
88
89#define ACX111_INTR_DISABLE	(uint16_t)~(ACXRV_INTR_CMD_FINI)
90
91#define ACX111_RATE_2		0x0001
92#define ACX111_RATE_4		0x0002
93#define ACX111_RATE_11		0x0004
94#define ACX111_RATE_12		0x0008
95#define ACX111_RATE_18		0x0010
96#define ACX111_RATE_22		0x0020
97#define ACX111_RATE_24		0x0040
98#define ACX111_RATE_36		0x0080
99#define ACX111_RATE_44		0x0100
100#define ACX111_RATE_48		0x0200
101#define ACX111_RATE_72		0x0400
102#define ACX111_RATE_96		0x0800
103#define ACX111_RATE_108		0x1000
104
105/* XXX skip ACX111_RATE_44 */
106#define ACX111_RATE_ALL		0x1eff
107
108#define ACX111_TXPOWER		15
109#define ACX111_GPIO_POWER_LED	0x0040
110#define ACX111_EE_EADDR_OFS	0x21
111
112#define ACX111_FW_TXDESC_SIZE	(sizeof(struct acx_fw_txdesc) + 4)
113
114#if ACX111_TXPOWER <= 12
115#define ACX111_TXPOWER_VAL	1
116#else
117#define ACX111_TXPOWER_VAL	2
118#endif
119
120int	acx111_init(struct acx_softc *);
121int	acx111_init_memory(struct acx_softc *);
122void	acx111_init_fw_txring(struct acx_softc *, uint32_t);
123int	acx111_write_config(struct acx_softc *, struct acx_config *);
124void	acx111_set_fw_txdesc_rate(struct acx_softc *,
125	    struct acx_txbuf *, int);
126void	acx111_set_bss_join_param(struct acx_softc *, void *, int);
127
128/*
129 * NOTE:
130 * Following structs' fields are little endian
131 */
132struct acx111_bss_join {
133	uint16_t	basic_rates;
134	uint8_t		dtim_intvl;
135} __packed;
136
137struct acx111_conf_mem {
138	struct acx_conf	confcom;
139
140	uint16_t	sta_max;	/* max num of sta, ACX111_STA_MAX */
141	uint16_t	memblk_size;	/* mem block size */
142	uint8_t		rx_memblk_perc;	/* percent of RX mem block, unit: 5% */
143	uint8_t		fw_rxring_num;	/* num of RX ring */
144	uint8_t		fw_txring_num;	/* num of TX ring */
145	uint8_t		opt;		/* see ACX111_MEMOPT_ */
146	uint8_t		xfer_perc;	/* frag/xfer proportion, unit: 5% */
147	uint16_t	reserved0;
148	uint8_t		reserved1;
149
150	uint8_t		fw_rxdesc_num;	/* num of fw rx desc */
151	uint8_t		fw_rxring_reserved1;
152	uint8_t		fw_rxring_type;	/* see ACX111_RXRING_TYPE_ */
153	uint8_t		fw_rxring_prio;	/* see ACX111_RXRING_PRIO_ */
154
155	uint32_t	h_rxring_paddr; /* host rx desc start phyaddr */
156
157	uint8_t		fw_txdesc_num;	/* num of fw tx desc */
158	uint8_t		fw_txring_reserved1;
159	uint8_t		fw_txring_reserved2;
160	uint8_t		fw_txring_attr;	/* see ACX111_TXRING_ATTR_ */
161} __packed;
162
163#define ACX111_STA_MAX			32
164#define ACX111_RX_MEMBLK_PERCENT	10	/* 50% */
165#define ACX111_XFER_PERCENT		15	/* 75% */
166#define ACX111_RXRING_TYPE_DEFAULT	7
167#define ACX111_RXRING_PRIO_DEFAULT	0
168#define ACX111_TXRING_ATTR_DEFAULT	0
169#define ACX111_MEMOPT_DEFAULT		0
170
171struct acx111_conf_meminfo {
172	struct acx_conf	confcom;
173	uint32_t	tx_memblk_addr;	/* start addr of tx mem blocks */
174	uint32_t	rx_memblk_addr;	/* start addr of rx mem blocks */
175	uint32_t	fw_rxring_start; /* start phyaddr of fw rx ring */
176	uint32_t	reserved0;
177	uint32_t	fw_txring_start; /* start phyaddr of fw tx ring */
178	uint8_t		fw_txring_attr;	/* XXX see ACX111_TXRING_ATTR_ */
179	uint16_t	reserved1;
180	uint8_t		reserved2;
181} __packed;
182
183struct acx111_conf_txpower {
184	struct acx_conf	confcom;
185	uint8_t		txpower;
186} __packed;
187
188struct acx111_conf_option {
189	struct acx_conf	confcom;
190	uint32_t	feature;
191	uint32_t	dataflow;	/* see ACX111_DF_ */
192} __packed;
193
194#define ACX111_DF_NO_RXDECRYPT	0x00000080
195#define ACX111_DF_NO_TXENCRYPT	0x00000001
196
197struct acx111_wepkey {
198	uint8_t		mac_addr[IEEE80211_ADDR_LEN];
199	uint16_t	action;		/* see ACX111_WEPKEY_ACT_ */
200	uint16_t	reserved;
201	uint8_t		key_len;
202	uint8_t		key_type;	/* see ACX111_WEPKEY_TYPE_ */
203	uint8_t		index;		/* XXX ?? */
204	uint8_t		key_idx;
205	uint8_t		counter[6];
206#define ACX111_WEPKEY_LEN	32
207	uint8_t		key[ACX111_WEPKEY_LEN];
208} __packed;
209
210#define ACX111_WEPKEY_ACT_ADD		1
211#define ACX111_WEPKEY_TYPE_DEFAULT	0
212
213static const uint16_t acx111_reg[ACXREG_MAX] = {
214	ACXREG(SOFT_RESET,		0x0000),
215
216	ACXREG(FWMEM_ADDR,		0x0014),
217	ACXREG(FWMEM_DATA,		0x0018),
218	ACXREG(FWMEM_CTRL,		0x001c),
219	ACXREG(FWMEM_START,		0x0020),
220
221	ACXREG(EVENT_MASK,		0x0034),
222
223	ACXREG(INTR_TRIG,		0x00b4),
224	ACXREG(INTR_MASK,		0x00d4),
225	ACXREG(INTR_STATUS,		0x00f0),
226	ACXREG(INTR_STATUS_CLR,		0x00e4),
227	ACXREG(INTR_ACK,		0x00e8),
228
229	ACXREG(HINTR_TRIG,		0x00ec),
230	ACXREG(RADIO_ENABLE,		0x01d0),
231
232	ACXREG(EEPROM_INIT,		0x0100),
233	ACXREG(EEPROM_CTRL,		0x0338),
234	ACXREG(EEPROM_ADDR,		0x033c),
235	ACXREG(EEPROM_DATA,		0x0340),
236	ACXREG(EEPROM_CONF,		0x0344),
237	ACXREG(EEPROM_INFO,		0x0390),
238
239	ACXREG(PHY_ADDR,		0x0350),
240	ACXREG(PHY_DATA,		0x0354),
241	ACXREG(PHY_CTRL,		0x0358),
242
243	ACXREG(GPIO_OUT_ENABLE,		0x0374),
244	ACXREG(GPIO_OUT,		0x037c),
245
246	ACXREG(CMD_REG_OFFSET,		0x0388),
247	ACXREG(INFO_REG_OFFSET,		0x038c),
248
249	ACXREG(RESET_SENSE,		0x0104),
250	ACXREG(ECPU_CTRL,		0x0108)
251};
252
253/* XXX */
254static uint16_t	acx111_rate_map[109] = {
255	ACX111_RATE_2,
256	ACX111_RATE_4,
257	ACX111_RATE_11,
258	ACX111_RATE_22,
259	ACX111_RATE_12,
260	ACX111_RATE_18,
261	ACX111_RATE_24,
262	ACX111_RATE_36,
263	ACX111_RATE_48,
264	ACX111_RATE_72,
265	ACX111_RATE_96,
266	ACX111_RATE_108
267};
268
269void
270acx111_set_param(struct acx_softc *sc)
271{
272	sc->chip_mem1_rid = PCIR_BAR(0);
273	sc->chip_mem2_rid = PCIR_BAR(1);
274	sc->chip_ioreg = acx111_reg;
275	sc->chip_intr_enable = ACX111_INTR_ENABLE;
276#ifndef IEEE80211_STA_ONLY
277	sc->chip_intr_enable |= ACXRV_INTR_DTIM;
278#endif
279	sc->chip_intr_disable = ACX111_INTR_DISABLE;
280	sc->chip_gpio_pled = ACX111_GPIO_POWER_LED;
281	sc->chip_ee_eaddr_ofs = ACX111_EE_EADDR_OFS;
282
283	sc->chip_phymode = IEEE80211_MODE_11G;
284	sc->chip_chan_flags = IEEE80211_CHAN_CCK |
285	    IEEE80211_CHAN_OFDM |
286	    IEEE80211_CHAN_DYN |
287	    IEEE80211_CHAN_2GHZ;
288	sc->sc_ic.ic_caps = IEEE80211_C_WEP | IEEE80211_C_SHSLOT;
289	sc->sc_ic.ic_phytype = IEEE80211_T_OFDM;
290	sc->sc_ic.ic_sup_rates[IEEE80211_MODE_11B] = ieee80211_std_rateset_11b;
291	sc->sc_ic.ic_sup_rates[IEEE80211_MODE_11G] = ieee80211_std_rateset_11g;
292
293	sc->chip_init = acx111_init;
294	sc->chip_write_config = acx111_write_config;
295	sc->chip_set_fw_txdesc_rate = acx111_set_fw_txdesc_rate;
296	sc->chip_set_bss_join_param = acx111_set_bss_join_param;
297	sc->sc_flags |= ACX_FLAG_ACX111;
298}
299
300int
301acx111_init(struct acx_softc *sc)
302{
303	struct ifnet *ifp = &sc->sc_ic.ic_if;
304
305	/*
306	 * NOTE:
307	 * Order of initialization:
308	 * 1) Templates
309	 * 2) Hardware memory
310	 * Above order is critical to get a correct memory map
311	 */
312	if (acx_init_tmplt_ordered(sc) != 0) {
313		printf("%s: %s can't initialize templates\n",
314		    ifp->if_xname, __func__);
315		return (ENXIO);
316	}
317
318	if (acx111_init_memory(sc) != 0) {
319		printf("%s: %s can't initialize hw memory\n",
320		    ifp->if_xname, __func__);
321		return (ENXIO);
322	}
323
324	return (0);
325}
326
327int
328acx111_init_memory(struct acx_softc *sc)
329{
330	struct acx111_conf_mem mem;
331	struct acx111_conf_meminfo mem_info;
332	struct ifnet *ifp = &sc->sc_ic.ic_if;
333
334	/* Set memory configuration */
335	bzero(&mem, sizeof(mem));
336
337	mem.sta_max = htole16(ACX111_STA_MAX);
338	mem.memblk_size = htole16(ACX_MEMBLOCK_SIZE);
339	mem.rx_memblk_perc = ACX111_RX_MEMBLK_PERCENT;
340	mem.opt = ACX111_MEMOPT_DEFAULT;
341	mem.xfer_perc = ACX111_XFER_PERCENT;
342
343	mem.fw_rxring_num = 1;
344	mem.fw_rxring_type = ACX111_RXRING_TYPE_DEFAULT;
345	mem.fw_rxring_prio = ACX111_RXRING_PRIO_DEFAULT;
346	mem.fw_rxdesc_num = ACX_RX_DESC_CNT;
347	mem.h_rxring_paddr = htole32(sc->sc_ring_data.rx_ring_paddr);
348
349	mem.fw_txring_num = 1;
350	mem.fw_txring_attr = ACX111_TXRING_ATTR_DEFAULT;
351	mem.fw_txdesc_num = ACX_TX_DESC_CNT;
352
353	if (acx_set_conf(sc, ACX111_CONF_MEM, &mem, sizeof(mem)) != 0) {
354		printf("%s: can't set mem\n", ifp->if_xname);
355		return (1);
356	}
357
358	/* Get memory configuration */
359	if (acx_get_conf(sc, ACX111_CONF_MEMINFO, &mem_info,
360	    sizeof(mem_info)) != 0) {
361		printf("%s: can't get meminfo\n", ifp->if_xname);
362		return (1);
363	}
364
365	/* Setup firmware TX descriptor ring */
366	acx111_init_fw_txring(sc, letoh32(mem_info.fw_txring_start));
367
368	/*
369	 * There is no need to setup firmware RX descriptor ring,
370	 * it is automatically setup by hardware.
371	 */
372
373	return (0);
374}
375
376void
377acx111_init_fw_txring(struct acx_softc *sc, uint32_t fw_txdesc_start)
378{
379	struct acx_txbuf *tx_buf;
380	uint32_t desc_paddr;
381	int i;
382
383	tx_buf = sc->sc_buf_data.tx_buf;
384	desc_paddr = sc->sc_ring_data.tx_ring_paddr;
385
386	for (i = 0; i < ACX_TX_DESC_CNT; ++i) {
387		tx_buf[i].tb_fwdesc_ofs = fw_txdesc_start +
388		    (i * ACX111_FW_TXDESC_SIZE);
389
390		/*
391		 * Except for the following fields, rest of the fields
392		 * are setup by hardware.
393		 */
394		FW_TXDESC_SETFIELD_4(sc, &tx_buf[i], f_tx_host_desc,
395		    desc_paddr);
396		FW_TXDESC_SETFIELD_1(sc, &tx_buf[i], f_tx_ctrl,
397		    DESC_CTRL_HOSTOWN);
398
399		desc_paddr += (2 * sizeof(struct acx_host_desc));
400	}
401}
402
403int
404acx111_write_config(struct acx_softc *sc, struct acx_config *conf)
405{
406	struct acx111_conf_txpower tx_power;
407	struct acx111_conf_option opt;
408	struct ifnet *ifp = &sc->sc_ic.ic_if;
409	uint32_t dataflow;
410
411	/* Set TX power */
412	tx_power.txpower = ACX111_TXPOWER_VAL;
413	if (acx_set_conf(sc, ACX_CONF_TXPOWER, &tx_power,
414	    sizeof(tx_power)) != 0) {
415		printf("%s: %s can't set TX power\n",
416		    ifp->if_xname, __func__);
417		return (ENXIO);
418	}
419
420	/*
421	 * Turn off hardware WEP
422	 */
423	if (acx_get_conf(sc, ACX_CONF_OPTION, &opt, sizeof(opt)) != 0) {
424		printf("%s: %s can't get option\n", ifp->if_xname, __func__);
425		return (ENXIO);
426	}
427
428	dataflow = letoh32(opt.dataflow) |
429	    ACX111_DF_NO_TXENCRYPT |
430	    ACX111_DF_NO_RXDECRYPT;
431	opt.dataflow = htole32(dataflow);
432
433	if (acx_set_conf(sc, ACX_CONF_OPTION, &opt, sizeof(opt)) != 0) {
434		printf("%s: %s can't set option\n", ifp->if_xname, __func__);
435		return (ENXIO);
436	}
437
438	return (0);
439}
440
441void
442acx111_set_fw_txdesc_rate(struct acx_softc *sc, struct acx_txbuf *tx_buf,
443    int rate0)
444{
445	uint16_t rate;
446
447	rate = acx111_rate_map[rate0];
448	if (rate == 0)
449		/* set rate to 1Mbit/s if rate was zero */
450		rate = acx111_rate_map[2];
451
452	FW_TXDESC_SETFIELD_2(sc, tx_buf, u.r2.rate111, rate);
453}
454
455void
456acx111_set_bss_join_param(struct acx_softc *sc, void *param, int dtim_intvl)
457{
458	struct acx111_bss_join *bj = param;
459
460	bj->basic_rates = htole16(ACX111_RATE_ALL);
461	bj->dtim_intvl = dtim_intvl;
462}
463