summaryrefslogtreecommitdiff
path: root/sys/dev/ic/athnvar.h
blob: d0d6210e4a3d43ea308338ad0a0ec000702b1f15 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
/*	$OpenBSD: athnvar.h,v 1.4 2009/11/17 18:21:07 damien Exp $	*/

/*-
 * Copyright (c) 2009 Damien Bergamini <damien.bergamini@free.fr>
 *
 * Permission to use, copy, modify, and distribute this software for any
 * purpose with or without fee is hereby granted, provided that the above
 * copyright notice and this permission notice appear in all copies.
 *
 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 */

#define ATHN_DEBUG		1
#define ATHN_INTR_MITIGATION	1
#define ATHN_BT_COEXISTENCE	1

#ifdef ATHN_DEBUG
#define DPRINTF(x)	do { if (athn_debug > 0) printf x; } while (0)
#define DPRINTFN(n, x)	do { if (athn_debug >= (n)) printf x; } while (0)
extern int athn_debug;
#else
#define DPRINTF(x)
#define DPRINTFN(n, x)
#endif

#define ATHN_RXBUFSZ	3872
#define ATHN_TXBUFSZ	4096

#define ATHN_NRXBUFS		64
#define ATHN_NTXBUFS		64	/* Shared between all Tx queues. */
#define ATHN_MAX_SCATTER	16

struct athn_rx_radiotap_header {
	struct ieee80211_radiotap_header wr_ihdr;
	uint64_t	wr_tsft;
	uint8_t		wr_flags;
	uint8_t		wr_rate;
	uint16_t	wr_chan_freq;
	uint16_t	wr_chan_flags;
	int8_t		wr_dbm_antsignal;
	uint8_t		wr_antenna;
} __packed;

#define ATHN_RX_RADIOTAP_PRESENT						\
	(1 << IEEE80211_RADIOTAP_TSFT |					\
	 1 << IEEE80211_RADIOTAP_FLAGS |				\
	 1 << IEEE80211_RADIOTAP_RATE |					\
	 1 << IEEE80211_RADIOTAP_CHANNEL |				\
	 1 << IEEE80211_RADIOTAP_DBM_ANTSIGNAL |			\
	 1 << IEEE80211_RADIOTAP_ANTENNA)

struct athn_tx_radiotap_header {
	struct ieee80211_radiotap_header wt_ihdr;
	uint8_t		wt_flags;
	uint8_t		wt_rate;
	uint16_t	wt_chan_freq;
	uint16_t	wt_chan_flags;
	uint8_t		wt_hwqueue;
} __packed;

#define ATHN_TX_RADIOTAP_PRESENT						\
	(1 << IEEE80211_RADIOTAP_FLAGS |				\
	 1 << IEEE80211_RADIOTAP_RATE |					\
	 1 << IEEE80211_RADIOTAP_CHANNEL |				\
	 1 << IEEE80211_RADIOTAP_HWQUEUE)

struct athn_tx_buf {
	SIMPLEQ_ENTRY(athn_tx_buf)	bf_list;

	struct ar_tx_desc		*bf_descs;
	bus_dmamap_t			bf_map;
	bus_addr_t			bf_daddr;

	struct mbuf			*bf_m;
	struct ieee80211_node		*bf_ni;
};

struct athn_txq {
	SIMPLEQ_HEAD(, athn_tx_buf)	head;
	struct ar_tx_desc		*lastds;
};

struct athn_rx_buf {
	SIMPLEQ_ENTRY(athn_rx_buf)	bf_list;

	struct ar_rx_desc		*bf_desc;
	bus_dmamap_t			bf_map;

	struct mbuf			*bf_m;
	bus_addr_t			bf_daddr;
};

struct athn_rxq {
	struct athn_rx_buf		bf[ATHN_NRXBUFS];

	struct ar_rx_desc		*descs;
	struct ar_rx_desc		*lastds;
	bus_dmamap_t			map;
	bus_dma_segment_t		seg;

	SIMPLEQ_HEAD(, athn_rx_buf)	head;
};

/* Software rate indexes. */
#define ATHN_RIDX_CCK1	0
#define ATHN_RIDX_OFDM6	4
#define ATHN_RIDX_MCS0	12
#define ATHN_RIDX_MCS15	27
#define ATHN_RIDX_MAX	27
#define ATHN_IS_OFDM_RIDX(ridx)	(athn_rates[ridx].phy == IEEE80211_T_OFDM)
#define ATHN_IS_HT_RIDX(ridx)	((ridx) >= ATHN_RIDX_MCS0)

static const struct athn_rate {
	uint8_t	rate;		/* Rate in 500Kbps unit or MCS if 0x80. */
	uint8_t	hwrate;		/* HW representation. */
	enum	ieee80211_phytype phy;
} athn_rates[] = {
	{    2, 0x1b, IEEE80211_T_DS },
	{    4, 0x1a, IEEE80211_T_DS },
	{   11, 0x19, IEEE80211_T_DS },
	{   22, 0x18, IEEE80211_T_DS },
	{   12, 0x0b, IEEE80211_T_OFDM },
	{   18, 0x0f, IEEE80211_T_OFDM },
	{   24, 0x0a, IEEE80211_T_OFDM },
	{   36, 0x0e, IEEE80211_T_OFDM },
	{   48, 0x09, IEEE80211_T_OFDM },
	{   72, 0x0d, IEEE80211_T_OFDM },
	{   96, 0x08, IEEE80211_T_OFDM },
	{  108, 0x0c, IEEE80211_T_OFDM },
	{ 0x80, 0x80, IEEE80211_T_OFDM },
	{ 0x81, 0x81, IEEE80211_T_OFDM },
	{ 0x82, 0x82, IEEE80211_T_OFDM },
	{ 0x83, 0x83, IEEE80211_T_OFDM },
	{ 0x84, 0x84, IEEE80211_T_OFDM },
	{ 0x85, 0x85, IEEE80211_T_OFDM },
	{ 0x86, 0x86, IEEE80211_T_OFDM },
	{ 0x87, 0x87, IEEE80211_T_OFDM },
	{ 0x88, 0x88, IEEE80211_T_OFDM },
	{ 0x89, 0x89, IEEE80211_T_OFDM },
	{ 0x8a, 0x8a, IEEE80211_T_OFDM },
	{ 0x8b, 0x8b, IEEE80211_T_OFDM },
	{ 0x8c, 0x8c, IEEE80211_T_OFDM },
	{ 0x8d, 0x8d, IEEE80211_T_OFDM },
	{ 0x8e, 0x8e, IEEE80211_T_OFDM },
	{ 0x8f, 0x8f, IEEE80211_T_OFDM }
};

struct athn_series {
	uint8_t		tries;
	uint8_t		hwrate;
	uint16_t	dur;
};

struct athn_pier {
	uint8_t		fbin;
	const uint8_t	*pwr[AR_PD_GAINS_IN_MASK];
	const uint8_t	*vpd[AR_PD_GAINS_IN_MASK];
};

/*
 * Structures used to store initialization values.
 */
struct athn_ini {
	int		nregs;
	const uint16_t	*regs;
	const uint32_t	*vals_5g20;
#ifndef IEEE80211_NO_HT
	const uint32_t	*vals_5g40;
	const uint32_t	*vals_2g40;
#endif
	const uint32_t	*vals_2g20;
	int		ncmregs;
	const uint16_t	*cmregs;
	const uint32_t	*cmvals;
};

struct athn_gain {
	int		nregs;
	const uint16_t	*regs;
	const uint32_t	*vals_5g;
	const uint32_t	*vals_2g;
};

struct athn_addac {
	int		nvals;
	const uint32_t	*vals;
};

/* Tx queue software indexes. */
#define ATHN_QID_AC_BE		0
#define ATHN_QID_PSPOLL		1
#define ATHN_QID_AC_BK		2
#define ATHN_QID_AC_VI		3
#define ATHN_QID_AC_VO		4
#define ATHN_QID_UAPSD		5
#define ATHN_QID_CAB		6
#define ATHN_QID_BEACON		7
#define ATHN_QID_COUNT		8

/* Map Access Category to Tx queue Id. */
static const uint8_t athn_ac2qid[EDCA_NUM_AC] = {
	ATHN_QID_AC_BE,	/* EDCA_AC_BE */
	ATHN_QID_AC_BK,	/* EDCA_AC_BK */
	ATHN_QID_AC_VI,	/* EDCA_AC_VI */
	ATHN_QID_AC_VO	/* EDCA_AC_VO */
};

static const uint8_t athn_5ghz_chans[] = {
	/* UNII 1. */
	36, 40, 44, 48,
	/* UNII 2. */
	52, 56, 60, 64,
	/* Middle band. */
	100, 104, 108, 112, 116, 120, 124, 128, 132, 136, 140,
	/* UNII 3. */
	149, 153, 157, 161, 165
};

/* Number of data bits per OFDM symbol for MCS[0-15]. */
/* See tables 20-29, 20-30, 20-33, 20-34. */
static const uint16_t ar_mcs_ndbps[][2] = {
	/* 20MHz  40MHz */
	{     26,    54 },	/* MCS0 */
	{     52,   108 },	/* MCS1 */
	{     78,   162 },	/* MCS2 */
	{    104,   216 },	/* MCS3 */
	{    156,   324 },	/* MCS4 */
	{    208,   432 },	/* MCS5 */
	{    234,   486 },	/* MCS6 */
	{    260,   540 },	/* MCS7 */
	{     26,   108 },	/* MCS8 */
	{     52,   216 },	/* MCS9 */
	{     78,   324 },	/* MCS10 */
	{    104,   432 },	/* MCS11 */
	{    156,   648 },	/* MCS12 */
	{    208,   864 },	/* MCS13 */
	{    234,   972 },	/* MCS14 */
	{    260,  1080 }	/* MCS15 */
};

#define ATHN_POWER_OFDM6	0
#define ATHN_POWER_OFDM9	1
#define ATHN_POWER_OFDM12	2
#define ATHN_POWER_OFDM18	3
#define ATHN_POWER_OFDM24	4
#define ATHN_POWER_OFDM36	5
#define ATHN_POWER_OFDM48	6
#define ATHN_POWER_OFDM54	7
#define ATHN_POWER_CCK1_LP	8
#define ATHN_POWER_CCK2_LP	9
#define ATHN_POWER_CCK2_SP	10
#define ATHN_POWER_CCK55_LP	11
#define ATHN_POWER_CCK55_SP	12
#define ATHN_POWER_CCK11_LP	13
#define ATHN_POWER_CCK11_SP	14
#define ATHN_POWER_XR		15
#define ATHN_POWER_HT20(mcs)	(16 + (mcs))
#define ATHN_POWER_HT40(mcs)	(24 + (mcs))
#define ATHN_POWER_CCK_DUP	32
#define ATHN_POWER_OFDM_DUP	33
#define ATHN_POWER_CCK_EXT	34
#define ATHN_POWER_OFDM_EXT	35
#define ATHN_POWER_COUNT	36

struct athn_node {
	struct ieee80211_node		ni;
	struct ieee80211_amrr_node	amn;
	uint8_t				ridx[IEEE80211_RATE_MAXSIZE];
	uint8_t				fallback[IEEE80211_RATE_MAXSIZE];
};

#define ATHN_ANI_PERIOD		100
#define ATHN_ANI_RSSI_THR_HIGH	40
#define ATHN_ANI_RSSI_THR_LOW	7
struct athn_ani {
	uint8_t		noise_immunity_level;
	uint8_t		spur_immunity_level;
	uint8_t		firstep_level;
	uint8_t		ofdm_weak_signal;
	uint8_t		cck_weak_signal;

	uint32_t	listen_time;

	uint32_t	ofdm_trig_high;
	uint32_t	ofdm_trig_low;

	int32_t		cck_trig_high;
	int32_t		cck_trig_low;

	uint32_t	ofdm_phy_err_base;
	uint32_t	cck_phy_err_base;
	uint32_t	ofdm_phy_err_count;
	uint32_t	cck_phy_err_count;
	
	uint32_t	cyccnt;
	uint32_t	txfcnt;
	uint32_t	rxfcnt;
};

struct athn_iq_cal {
	uint32_t	pwr_meas_i;
	uint32_t	pwr_meas_q;
	int32_t		iq_corr_meas;
};

struct athn_adc_cal {
	uint32_t	pwr_meas_odd_i;
	uint32_t	pwr_meas_even_i;
	uint32_t	pwr_meas_odd_q;
	uint32_t	pwr_meas_even_q;
};

struct athn_calib {
	int			nsamples;
	struct athn_iq_cal	iq[AR_MAX_CHAINS];
	struct athn_adc_cal	adc_gain[AR_MAX_CHAINS];
	struct athn_adc_cal	adc_dc_offset[AR_MAX_CHAINS];
};

#define ATHN_NF_CAL_HIST_MAX	5

struct athn_softc;

struct athn_ops {
	void	(*setup)(struct athn_softc *);
	void	(*set_txpower)(struct athn_softc *, struct ieee80211_channel *,
		    struct ieee80211_channel *);
	void	(*spur_mitigate)(struct athn_softc *,
		    struct ieee80211_channel *, struct ieee80211_channel *);
	const struct ar_spur_chan *(*get_spur_chans)(struct athn_softc *, int);
	void	(*init_from_rom)(struct athn_softc *,
		    struct ieee80211_channel *, struct ieee80211_channel *);
	int	(*set_synth)(struct athn_softc *, struct ieee80211_channel *,
		    struct ieee80211_channel *);
	void	(*swap_rom)(struct athn_softc *);
	void	(*olpc_init)(struct athn_softc *);
};

struct athn_softc {
	struct device			sc_dev;
	struct ieee80211com		sc_ic;

	int				(*sc_enable)(struct athn_softc *);
	void				(*sc_disable)(struct athn_softc *);
	void				(*sc_power)(struct athn_softc *, int);
	void				(*sc_disable_aspm)(struct athn_softc *);

	int				(*sc_newstate)(struct ieee80211com *,
					    enum ieee80211_state, int);

	bus_dma_tag_t			sc_dmat;
	bus_space_tag_t			sc_st;
	bus_space_handle_t		sc_sh;

	struct timeout			scan_to;
	struct timeout			calib_to;
	struct ieee80211_amrr		amrr;

	u_int				flags;
#define ATHN_FLAG_PCIE			(1 << 0)
#define ATHN_FLAG_OLPC			(1 << 1)
#define ATHN_FLAG_SPLIT_MMIC		(1 << 2)
#define ATHN_FLAG_RFSILENT		(1 << 3)
#define ATHN_FLAG_RFSILENT_REVERSED	(1 << 4)
#define ATHN_FLAG_BTCOEX2WIRE		(1 << 5)
#define ATHN_FLAG_BTCOEX3WIRE		(1 << 6)
/* Shortcut. */
#define ATHN_FLAG_BTCOEX	(ATHN_FLAG_BTCOEX2WIRE | ATHN_FLAG_BTCOEX3WIRE)

	uint8_t				ngpiopins;
	int				led_pin;
	int				rfsilent_pin;

	uint16_t			mac_ver;
	uint8_t				mac_rev;
	uint8_t				rf_rev;
	uint16_t			eep_rev;
	uint32_t			phy_rev;

	uint8_t				txchainmask;
	uint8_t				rxchainmask;
	uint8_t				ntxchains;
	uint8_t				nrxchains;

	uint8_t				calib_mask;
#define ATHN_CAL_IQ		(1 << 0)
#define ATHN_CAL_ADC_GAIN	(1 << 1)
#define ATHN_CAL_ADC_DC		(1 << 2)

	/* Open Loop Power Control. */
	int8_t				tx_gain_tbl[AR9280_TX_GAIN_TABLE_SIZE];
	int8_t				pdadc;
	int8_t				tcomp;

	uint32_t			rwbuf[64];

	int				kc_entries;

	void				*eep;
	uint32_t			eep_base;
	uint32_t			eep_size;

	struct athn_rxq			rxq;
	struct athn_txq			txq[31];	/* 0x1f ??? */

	struct ar_tx_desc		*descs;
	bus_dmamap_t			map;
	bus_dma_segment_t		seg;
	SIMPLEQ_HEAD(, athn_tx_buf)	txbufs;
	struct athn_tx_buf		txpool[ATHN_NTXBUFS];

	int				sc_if_flags;
	int				sc_tx_timer;

	const struct athn_ini		*ini;
	const struct athn_gain		*rx_gain;
	const struct athn_gain		*tx_gain;
	const struct athn_addac		*addac;
	const uint32_t			*serdes;
	uint32_t			workaround;


	struct athn_ops			ops;

	int				fixed_ridx;
	int				sifs;

	int16_t				def_nf;
	struct {
		int16_t	nf[AR_MAX_CHAINS];
		int16_t	nf_ext[AR_MAX_CHAINS];
	}				nf_hist[ATHN_NF_CAL_HIST_MAX];
	int				nf_hist_cur;
	int16_t				nf_priv[AR_MAX_CHAINS];
	int16_t				nf_ext_priv[AR_MAX_CHAINS];

	struct athn_calib		calib;
	struct athn_ani			ani;

#if NBPFILTER > 0
	caddr_t				sc_drvbpf;

	union {
		struct athn_rx_radiotap_header th;
		uint8_t pad[IEEE80211_RADIOTAP_HDRLEN];
	} sc_rxtapu;
#define sc_rxtap			sc_rxtapu.th
	int				sc_rxtap_len;

	union {
		struct athn_tx_radiotap_header th;
		uint8_t pad[IEEE80211_RADIOTAP_HDRLEN];
	} sc_txtapu;
#define sc_txtap			sc_txtapu.th
	int				sc_txtap_len;
#endif
};

extern int	athn_attach(struct athn_softc *);
extern void	athn_detach(struct athn_softc *);
extern int	athn_intr(void *);
extern int	ar5416_attach(struct athn_softc *);
extern int	ar9280_attach(struct athn_softc *);
extern int	ar9285_attach(struct athn_softc *);
extern int	ar9287_attach(struct athn_softc *);
extern uint8_t	athn_reverse_bits(uint8_t, int);
extern uint8_t	athn_chan2fbin(struct ieee80211_channel *);
extern void	athn_set_viterbi_mask(struct athn_softc *, int);
extern void	athn_write_txpower(struct athn_softc *, int16_t[]);
extern void	athn_get_lg_tpow(struct athn_softc *,
		    struct ieee80211_channel *, uint8_t,
		    const struct ar_cal_target_power_leg *, int, uint8_t[]);
extern void	athn_get_ht_tpow(struct athn_softc *,
		    struct ieee80211_channel *, uint8_t,
		    const struct ar_cal_target_power_ht *, int, uint8_t[]);
extern void	athn_get_pdadcs(struct athn_softc *, uint8_t,
		    struct athn_pier *, struct athn_pier *, int, int, uint8_t,
		    uint8_t *, uint8_t *);
extern void	athn_get_pier_ival(uint8_t, const uint8_t *, int, int *,
		    int *);
/* XXX not here. */
extern void	ar5416_set_txpower(struct athn_softc *,
		    struct ieee80211_channel *, struct ieee80211_channel *);
extern void	ar5416_swap_rom(struct athn_softc *);
extern void	ar9280_2_0_olpc_get_pdadcs(struct athn_softc *,
		    struct ieee80211_channel *, int, uint8_t[], uint8_t[],
		    uint8_t *);
extern int	ar9280_set_synth(struct athn_softc *,
		    struct ieee80211_channel *, struct ieee80211_channel *);
extern void	ar9280_spur_mitigate(struct athn_softc *,
		    struct ieee80211_channel *, struct ieee80211_channel *);
extern void	ar9287_1_2_enable_async_fifo(struct athn_softc *);
extern void	ar9287_1_2_setup_async_fifo(struct athn_softc *);
extern const	struct ar_spur_chan *ar5416_get_spur_chans(struct athn_softc *,
		    int);
extern int	ar5416_init_calib(struct athn_softc *,
		    struct ieee80211_channel *, struct ieee80211_channel *);
extern int	ar9285_1_2_init_calib(struct athn_softc *,
		    struct ieee80211_channel *, struct ieee80211_channel *);
extern void	ar9285_pa_calib(struct athn_softc *);
extern void	ar9280_reset_rx_gain(struct athn_softc *,
		    struct ieee80211_channel *);
extern void	ar9280_reset_tx_gain(struct athn_softc *,
		    struct ieee80211_channel *);
extern void	ar5416_reset_addac(struct athn_softc *,
		    struct ieee80211_channel *);
extern void	ar5416_reset_bb_gain(struct athn_softc *,
		    struct ieee80211_channel *);
extern void	ar5416_rf_reset(struct athn_softc *,
		    struct ieee80211_channel *);