pcu.c revision a27049e2c926bcf68360532a5ae66e408296ae85
1c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis/*
2c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis * Copyright (c) 2004-2008 Reyk Floeter <reyk@openbsd.org>
3c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis * Copyright (c) 2006-2008 Nick Kossifidis <mickflemm@gmail.com>
4c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis * Copyright (c) 2007-2008 Matthew W. S. Bell  <mentor@madwifi.org>
5c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis * Copyright (c) 2007-2008 Luis Rodriguez <mcgrof@winlab.rutgers.edu>
6c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis * Copyright (c) 2007-2008 Pavel Roskin <proski@gnu.org>
7c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis * Copyright (c) 2007-2008 Jiri Slaby <jirislaby@gmail.com>
8c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis *
9c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis * Permission to use, copy, modify, and distribute this software for any
10c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis * purpose with or without fee is hereby granted, provided that the above
11c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis * copyright notice and this permission notice appear in all copies.
12c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis *
13c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
14c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
15c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
16c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
17c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
18c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
19c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
20c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis *
21c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis */
22c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis
23c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis/*********************************\
24c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis* Protocol Control Unit Functions *
25c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis\*********************************/
26c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis
27bcd8f54a84ce99ade91c250a9bc850a9fd3389c1Luis R. Rodriguez#include <asm/unaligned.h>
28bcd8f54a84ce99ade91c250a9bc850a9fd3389c1Luis R. Rodriguez
29c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis#include "ath5k.h"
30c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis#include "reg.h"
31c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis#include "debug.h"
32c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis#include "base.h"
33c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis
3461cde037234c4b8e6497a23f5f236c64cbf9d41dNick Kossifidis/*
3561cde037234c4b8e6497a23f5f236c64cbf9d41dNick Kossifidis * AR5212+ can use higher rates for ack transmition
3661cde037234c4b8e6497a23f5f236c64cbf9d41dNick Kossifidis * based on current tx rate instead of the base rate.
3761cde037234c4b8e6497a23f5f236c64cbf9d41dNick Kossifidis * It does this to better utilize channel usage.
3861cde037234c4b8e6497a23f5f236c64cbf9d41dNick Kossifidis * This is a mapping between G rates (that cover both
3961cde037234c4b8e6497a23f5f236c64cbf9d41dNick Kossifidis * CCK and OFDM) and ack rates that we use when setting
4061cde037234c4b8e6497a23f5f236c64cbf9d41dNick Kossifidis * rate -> duration table. This mapping is hw-based so
4161cde037234c4b8e6497a23f5f236c64cbf9d41dNick Kossifidis * don't change anything.
4261cde037234c4b8e6497a23f5f236c64cbf9d41dNick Kossifidis *
4361cde037234c4b8e6497a23f5f236c64cbf9d41dNick Kossifidis * To enable this functionality we must set
4461cde037234c4b8e6497a23f5f236c64cbf9d41dNick Kossifidis * ah->ah_ack_bitrate_high to true else base rate is
4561cde037234c4b8e6497a23f5f236c64cbf9d41dNick Kossifidis * used (1Mb for CCK, 6Mb for OFDM).
4661cde037234c4b8e6497a23f5f236c64cbf9d41dNick Kossifidis */
4761cde037234c4b8e6497a23f5f236c64cbf9d41dNick Kossifidisstatic const unsigned int ack_rates_high[] =
4861cde037234c4b8e6497a23f5f236c64cbf9d41dNick Kossifidis/* Tx	-> ACK	*/
4961cde037234c4b8e6497a23f5f236c64cbf9d41dNick Kossifidis/* 1Mb	-> 1Mb	*/	{ 0,
5061cde037234c4b8e6497a23f5f236c64cbf9d41dNick Kossifidis/* 2MB	-> 2Mb	*/	1,
5161cde037234c4b8e6497a23f5f236c64cbf9d41dNick Kossifidis/* 5.5Mb -> 2Mb	*/	1,
5261cde037234c4b8e6497a23f5f236c64cbf9d41dNick Kossifidis/* 11Mb	-> 2Mb	*/	1,
5361cde037234c4b8e6497a23f5f236c64cbf9d41dNick Kossifidis/* 6Mb	-> 6Mb	*/	4,
5461cde037234c4b8e6497a23f5f236c64cbf9d41dNick Kossifidis/* 9Mb	-> 6Mb	*/	4,
5561cde037234c4b8e6497a23f5f236c64cbf9d41dNick Kossifidis/* 12Mb	-> 12Mb	*/	6,
5661cde037234c4b8e6497a23f5f236c64cbf9d41dNick Kossifidis/* 18Mb	-> 12Mb	*/	6,
5761cde037234c4b8e6497a23f5f236c64cbf9d41dNick Kossifidis/* 24Mb	-> 24Mb	*/	8,
5861cde037234c4b8e6497a23f5f236c64cbf9d41dNick Kossifidis/* 36Mb	-> 24Mb	*/	8,
5961cde037234c4b8e6497a23f5f236c64cbf9d41dNick Kossifidis/* 48Mb	-> 24Mb	*/	8,
6061cde037234c4b8e6497a23f5f236c64cbf9d41dNick Kossifidis/* 54Mb	-> 24Mb	*/	8 };
6161cde037234c4b8e6497a23f5f236c64cbf9d41dNick Kossifidis
62c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis/*******************\
639320b5c4a7260d9593102f378201d17e3f030739Nick Kossifidis* Helper functions *
64c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis\*******************/
65c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis
66c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis/**
6761cde037234c4b8e6497a23f5f236c64cbf9d41dNick Kossifidis * ath5k_hw_get_frame_duration - Get tx time of a frame
6861cde037234c4b8e6497a23f5f236c64cbf9d41dNick Kossifidis *
6961cde037234c4b8e6497a23f5f236c64cbf9d41dNick Kossifidis * @ah: The &struct ath5k_hw
7061cde037234c4b8e6497a23f5f236c64cbf9d41dNick Kossifidis * @len: Frame's length in bytes
7161cde037234c4b8e6497a23f5f236c64cbf9d41dNick Kossifidis * @rate: The @struct ieee80211_rate
7261cde037234c4b8e6497a23f5f236c64cbf9d41dNick Kossifidis *
7361cde037234c4b8e6497a23f5f236c64cbf9d41dNick Kossifidis * Calculate tx duration of a frame given it's rate and length
7461cde037234c4b8e6497a23f5f236c64cbf9d41dNick Kossifidis * It extends ieee80211_generic_frame_duration for non standard
7561cde037234c4b8e6497a23f5f236c64cbf9d41dNick Kossifidis * bwmodes.
7661cde037234c4b8e6497a23f5f236c64cbf9d41dNick Kossifidis */
7761cde037234c4b8e6497a23f5f236c64cbf9d41dNick Kossifidisint ath5k_hw_get_frame_duration(struct ath5k_hw *ah,
78a27049e2c926bcf68360532a5ae66e408296ae85Felix Fietkau		int len, struct ieee80211_rate *rate, bool shortpre)
7961cde037234c4b8e6497a23f5f236c64cbf9d41dNick Kossifidis{
8061cde037234c4b8e6497a23f5f236c64cbf9d41dNick Kossifidis	struct ath5k_softc *sc = ah->ah_sc;
8161cde037234c4b8e6497a23f5f236c64cbf9d41dNick Kossifidis	int sifs, preamble, plcp_bits, sym_time;
8261cde037234c4b8e6497a23f5f236c64cbf9d41dNick Kossifidis	int bitrate, bits, symbols, symbol_bits;
8361cde037234c4b8e6497a23f5f236c64cbf9d41dNick Kossifidis	int dur;
8461cde037234c4b8e6497a23f5f236c64cbf9d41dNick Kossifidis
8561cde037234c4b8e6497a23f5f236c64cbf9d41dNick Kossifidis	/* Fallback */
8661cde037234c4b8e6497a23f5f236c64cbf9d41dNick Kossifidis	if (!ah->ah_bwmode) {
87a27049e2c926bcf68360532a5ae66e408296ae85Felix Fietkau		__le16 raw_dur = ieee80211_generic_frame_duration(sc->hw,
88a27049e2c926bcf68360532a5ae66e408296ae85Felix Fietkau					NULL, len, rate);
89a27049e2c926bcf68360532a5ae66e408296ae85Felix Fietkau
90a27049e2c926bcf68360532a5ae66e408296ae85Felix Fietkau		/* subtract difference between long and short preamble */
91a27049e2c926bcf68360532a5ae66e408296ae85Felix Fietkau		dur = le16_to_cpu(raw_dur);
92a27049e2c926bcf68360532a5ae66e408296ae85Felix Fietkau		if (shortpre)
93a27049e2c926bcf68360532a5ae66e408296ae85Felix Fietkau			dur -= 96;
94a27049e2c926bcf68360532a5ae66e408296ae85Felix Fietkau
95a27049e2c926bcf68360532a5ae66e408296ae85Felix Fietkau		return dur;
9661cde037234c4b8e6497a23f5f236c64cbf9d41dNick Kossifidis	}
9761cde037234c4b8e6497a23f5f236c64cbf9d41dNick Kossifidis
9861cde037234c4b8e6497a23f5f236c64cbf9d41dNick Kossifidis	bitrate = rate->bitrate;
9961cde037234c4b8e6497a23f5f236c64cbf9d41dNick Kossifidis	preamble = AR5K_INIT_OFDM_PREAMPLE_TIME;
10061cde037234c4b8e6497a23f5f236c64cbf9d41dNick Kossifidis	plcp_bits = AR5K_INIT_OFDM_PLCP_BITS;
10161cde037234c4b8e6497a23f5f236c64cbf9d41dNick Kossifidis	sym_time = AR5K_INIT_OFDM_SYMBOL_TIME;
10261cde037234c4b8e6497a23f5f236c64cbf9d41dNick Kossifidis
10361cde037234c4b8e6497a23f5f236c64cbf9d41dNick Kossifidis	switch (ah->ah_bwmode) {
10461cde037234c4b8e6497a23f5f236c64cbf9d41dNick Kossifidis	case AR5K_BWMODE_40MHZ:
10561cde037234c4b8e6497a23f5f236c64cbf9d41dNick Kossifidis		sifs = AR5K_INIT_SIFS_TURBO;
10661cde037234c4b8e6497a23f5f236c64cbf9d41dNick Kossifidis		preamble = AR5K_INIT_OFDM_PREAMBLE_TIME_MIN;
10761cde037234c4b8e6497a23f5f236c64cbf9d41dNick Kossifidis		break;
10861cde037234c4b8e6497a23f5f236c64cbf9d41dNick Kossifidis	case AR5K_BWMODE_10MHZ:
10961cde037234c4b8e6497a23f5f236c64cbf9d41dNick Kossifidis		sifs = AR5K_INIT_SIFS_HALF_RATE;
11061cde037234c4b8e6497a23f5f236c64cbf9d41dNick Kossifidis		preamble *= 2;
11161cde037234c4b8e6497a23f5f236c64cbf9d41dNick Kossifidis		sym_time *= 2;
11261cde037234c4b8e6497a23f5f236c64cbf9d41dNick Kossifidis		break;
11361cde037234c4b8e6497a23f5f236c64cbf9d41dNick Kossifidis	case AR5K_BWMODE_5MHZ:
11461cde037234c4b8e6497a23f5f236c64cbf9d41dNick Kossifidis		sifs = AR5K_INIT_SIFS_QUARTER_RATE;
11561cde037234c4b8e6497a23f5f236c64cbf9d41dNick Kossifidis		preamble *= 4;
11661cde037234c4b8e6497a23f5f236c64cbf9d41dNick Kossifidis		sym_time *= 4;
11761cde037234c4b8e6497a23f5f236c64cbf9d41dNick Kossifidis		break;
11861cde037234c4b8e6497a23f5f236c64cbf9d41dNick Kossifidis	default:
11961cde037234c4b8e6497a23f5f236c64cbf9d41dNick Kossifidis		sifs = AR5K_INIT_SIFS_DEFAULT_BG;
12061cde037234c4b8e6497a23f5f236c64cbf9d41dNick Kossifidis		break;
12161cde037234c4b8e6497a23f5f236c64cbf9d41dNick Kossifidis	}
12261cde037234c4b8e6497a23f5f236c64cbf9d41dNick Kossifidis
12361cde037234c4b8e6497a23f5f236c64cbf9d41dNick Kossifidis	bits = plcp_bits + (len << 3);
12461cde037234c4b8e6497a23f5f236c64cbf9d41dNick Kossifidis	/* Bit rate is in 100Kbits */
12561cde037234c4b8e6497a23f5f236c64cbf9d41dNick Kossifidis	symbol_bits = bitrate * sym_time;
12661cde037234c4b8e6497a23f5f236c64cbf9d41dNick Kossifidis	symbols = DIV_ROUND_UP(bits * 10, symbol_bits);
12761cde037234c4b8e6497a23f5f236c64cbf9d41dNick Kossifidis
12861cde037234c4b8e6497a23f5f236c64cbf9d41dNick Kossifidis	dur = sifs + preamble + (sym_time * symbols);
12961cde037234c4b8e6497a23f5f236c64cbf9d41dNick Kossifidis
13061cde037234c4b8e6497a23f5f236c64cbf9d41dNick Kossifidis	return dur;
13161cde037234c4b8e6497a23f5f236c64cbf9d41dNick Kossifidis}
13261cde037234c4b8e6497a23f5f236c64cbf9d41dNick Kossifidis
13361cde037234c4b8e6497a23f5f236c64cbf9d41dNick Kossifidis/**
1349320b5c4a7260d9593102f378201d17e3f030739Nick Kossifidis * ath5k_hw_get_default_slottime - Get the default slot time for current mode
135c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis *
136c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis * @ah: The &struct ath5k_hw
137c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis */
13871ba1c30851575b43ba76b0f9c26ff5567e8136cNick Kossifidisunsigned int ath5k_hw_get_default_slottime(struct ath5k_hw *ah)
139c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis{
1409320b5c4a7260d9593102f378201d17e3f030739Nick Kossifidis	struct ieee80211_channel *channel = ah->ah_current_channel;
1413017fcab416d8d1ee48ca16aa9a3062f600dab8eNick Kossifidis	unsigned int slot_time;
142c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis
1433017fcab416d8d1ee48ca16aa9a3062f600dab8eNick Kossifidis	switch (ah->ah_bwmode) {
1443017fcab416d8d1ee48ca16aa9a3062f600dab8eNick Kossifidis	case AR5K_BWMODE_40MHZ:
1453017fcab416d8d1ee48ca16aa9a3062f600dab8eNick Kossifidis		slot_time = AR5K_INIT_SLOT_TIME_TURBO;
1463017fcab416d8d1ee48ca16aa9a3062f600dab8eNick Kossifidis		break;
1473017fcab416d8d1ee48ca16aa9a3062f600dab8eNick Kossifidis	case AR5K_BWMODE_10MHZ:
1483017fcab416d8d1ee48ca16aa9a3062f600dab8eNick Kossifidis		slot_time = AR5K_INIT_SLOT_TIME_HALF_RATE;
1493017fcab416d8d1ee48ca16aa9a3062f600dab8eNick Kossifidis		break;
1503017fcab416d8d1ee48ca16aa9a3062f600dab8eNick Kossifidis	case AR5K_BWMODE_5MHZ:
1513017fcab416d8d1ee48ca16aa9a3062f600dab8eNick Kossifidis		slot_time = AR5K_INIT_SLOT_TIME_QUARTER_RATE;
1523017fcab416d8d1ee48ca16aa9a3062f600dab8eNick Kossifidis		break;
1533017fcab416d8d1ee48ca16aa9a3062f600dab8eNick Kossifidis	case AR5K_BWMODE_DEFAULT:
1543017fcab416d8d1ee48ca16aa9a3062f600dab8eNick Kossifidis		slot_time = AR5K_INIT_SLOT_TIME_DEFAULT;
1553017fcab416d8d1ee48ca16aa9a3062f600dab8eNick Kossifidis	default:
1563017fcab416d8d1ee48ca16aa9a3062f600dab8eNick Kossifidis		if (channel->hw_value & CHANNEL_CCK)
1573017fcab416d8d1ee48ca16aa9a3062f600dab8eNick Kossifidis			slot_time = AR5K_INIT_SLOT_TIME_B;
1583017fcab416d8d1ee48ca16aa9a3062f600dab8eNick Kossifidis		break;
1593017fcab416d8d1ee48ca16aa9a3062f600dab8eNick Kossifidis	}
160c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis
1613017fcab416d8d1ee48ca16aa9a3062f600dab8eNick Kossifidis	return slot_time;
1629320b5c4a7260d9593102f378201d17e3f030739Nick Kossifidis}
163c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis
1649320b5c4a7260d9593102f378201d17e3f030739Nick Kossifidis/**
1659320b5c4a7260d9593102f378201d17e3f030739Nick Kossifidis * ath5k_hw_get_default_sifs - Get the default SIFS for current mode
1669320b5c4a7260d9593102f378201d17e3f030739Nick Kossifidis *
1679320b5c4a7260d9593102f378201d17e3f030739Nick Kossifidis * @ah: The &struct ath5k_hw
1689320b5c4a7260d9593102f378201d17e3f030739Nick Kossifidis */
1693017fcab416d8d1ee48ca16aa9a3062f600dab8eNick Kossifidisunsigned int ath5k_hw_get_default_sifs(struct ath5k_hw *ah)
1709320b5c4a7260d9593102f378201d17e3f030739Nick Kossifidis{
1719320b5c4a7260d9593102f378201d17e3f030739Nick Kossifidis	struct ieee80211_channel *channel = ah->ah_current_channel;
1723017fcab416d8d1ee48ca16aa9a3062f600dab8eNick Kossifidis	unsigned int sifs;
173c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis
1743017fcab416d8d1ee48ca16aa9a3062f600dab8eNick Kossifidis	switch (ah->ah_bwmode) {
1753017fcab416d8d1ee48ca16aa9a3062f600dab8eNick Kossifidis	case AR5K_BWMODE_40MHZ:
1763017fcab416d8d1ee48ca16aa9a3062f600dab8eNick Kossifidis		sifs = AR5K_INIT_SIFS_TURBO;
1773017fcab416d8d1ee48ca16aa9a3062f600dab8eNick Kossifidis		break;
1783017fcab416d8d1ee48ca16aa9a3062f600dab8eNick Kossifidis	case AR5K_BWMODE_10MHZ:
1793017fcab416d8d1ee48ca16aa9a3062f600dab8eNick Kossifidis		sifs = AR5K_INIT_SIFS_HALF_RATE;
1803017fcab416d8d1ee48ca16aa9a3062f600dab8eNick Kossifidis		break;
1813017fcab416d8d1ee48ca16aa9a3062f600dab8eNick Kossifidis	case AR5K_BWMODE_5MHZ:
1823017fcab416d8d1ee48ca16aa9a3062f600dab8eNick Kossifidis		sifs = AR5K_INIT_SIFS_QUARTER_RATE;
1833017fcab416d8d1ee48ca16aa9a3062f600dab8eNick Kossifidis		break;
1843017fcab416d8d1ee48ca16aa9a3062f600dab8eNick Kossifidis	case AR5K_BWMODE_DEFAULT:
1853017fcab416d8d1ee48ca16aa9a3062f600dab8eNick Kossifidis		sifs = AR5K_INIT_SIFS_DEFAULT_BG;
1863017fcab416d8d1ee48ca16aa9a3062f600dab8eNick Kossifidis	default:
1873017fcab416d8d1ee48ca16aa9a3062f600dab8eNick Kossifidis		if (channel->hw_value & CHANNEL_5GHZ)
1883017fcab416d8d1ee48ca16aa9a3062f600dab8eNick Kossifidis			sifs = AR5K_INIT_SIFS_DEFAULT_A;
1893017fcab416d8d1ee48ca16aa9a3062f600dab8eNick Kossifidis		break;
1903017fcab416d8d1ee48ca16aa9a3062f600dab8eNick Kossifidis	}
191c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis
1923017fcab416d8d1ee48ca16aa9a3062f600dab8eNick Kossifidis	return sifs;
193c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis}
194c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis
195c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis/**
1969320b5c4a7260d9593102f378201d17e3f030739Nick Kossifidis * ath5k_hw_update_mib_counters - Update MIB counters (mac layer statistics)
197c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis *
198c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis * @ah: The &struct ath5k_hw
199c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis *
200495391d715a310a7cbf622850e372d40ac86ef6eBruno Randolf * Reads MIB counters from PCU and updates sw statistics. Is called after a
201495391d715a310a7cbf622850e372d40ac86ef6eBruno Randolf * MIB interrupt, because one of these counters might have reached their maximum
202495391d715a310a7cbf622850e372d40ac86ef6eBruno Randolf * and triggered the MIB interrupt, to let us read and clear the counter.
203495391d715a310a7cbf622850e372d40ac86ef6eBruno Randolf *
204495391d715a310a7cbf622850e372d40ac86ef6eBruno Randolf * Is called in interrupt context!
205c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis */
206495391d715a310a7cbf622850e372d40ac86ef6eBruno Randolfvoid ath5k_hw_update_mib_counters(struct ath5k_hw *ah)
207c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis{
208495391d715a310a7cbf622850e372d40ac86ef6eBruno Randolf	struct ath5k_statistics *stats = &ah->ah_sc->stats;
209c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis
210c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis	/* Read-And-Clear */
211495391d715a310a7cbf622850e372d40ac86ef6eBruno Randolf	stats->ack_fail += ath5k_hw_reg_read(ah, AR5K_ACK_FAIL);
212495391d715a310a7cbf622850e372d40ac86ef6eBruno Randolf	stats->rts_fail += ath5k_hw_reg_read(ah, AR5K_RTS_FAIL);
213495391d715a310a7cbf622850e372d40ac86ef6eBruno Randolf	stats->rts_ok += ath5k_hw_reg_read(ah, AR5K_RTS_OK);
214495391d715a310a7cbf622850e372d40ac86ef6eBruno Randolf	stats->fcs_error += ath5k_hw_reg_read(ah, AR5K_FCS_FAIL);
215495391d715a310a7cbf622850e372d40ac86ef6eBruno Randolf	stats->beacons += ath5k_hw_reg_read(ah, AR5K_BEACON_CNT);
216c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis}
217c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis
218c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis
219c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis/******************\
220c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis* ACK/CTS Timeouts *
221c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis\******************/
222c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis
2239320b5c4a7260d9593102f378201d17e3f030739Nick Kossifidis/**
2249320b5c4a7260d9593102f378201d17e3f030739Nick Kossifidis * ath5k_hw_write_rate_duration - fill rate code to duration table
2259320b5c4a7260d9593102f378201d17e3f030739Nick Kossifidis *
2269320b5c4a7260d9593102f378201d17e3f030739Nick Kossifidis * @ah: the &struct ath5k_hw
2279320b5c4a7260d9593102f378201d17e3f030739Nick Kossifidis * @mode: one of enum ath5k_driver_mode
2289320b5c4a7260d9593102f378201d17e3f030739Nick Kossifidis *
2299320b5c4a7260d9593102f378201d17e3f030739Nick Kossifidis * Write the rate code to duration table upon hw reset. This is a helper for
23061cde037234c4b8e6497a23f5f236c64cbf9d41dNick Kossifidis * ath5k_hw_pcu_init(). It seems all this is doing is setting an ACK timeout on
2319320b5c4a7260d9593102f378201d17e3f030739Nick Kossifidis * the hardware, based on current mode, for each rate. The rates which are
2329320b5c4a7260d9593102f378201d17e3f030739Nick Kossifidis * capable of short preamble (802.11b rates 2Mbps, 5.5Mbps, and 11Mbps) have
2339320b5c4a7260d9593102f378201d17e3f030739Nick Kossifidis * different rate code so we write their value twice (one for long preamble
2349320b5c4a7260d9593102f378201d17e3f030739Nick Kossifidis * and one for short).
2359320b5c4a7260d9593102f378201d17e3f030739Nick Kossifidis *
2369320b5c4a7260d9593102f378201d17e3f030739Nick Kossifidis * Note: Band doesn't matter here, if we set the values for OFDM it works
2379320b5c4a7260d9593102f378201d17e3f030739Nick Kossifidis * on both a and g modes. So all we have to do is set values for all g rates
23861cde037234c4b8e6497a23f5f236c64cbf9d41dNick Kossifidis * that include all OFDM and CCK rates.
23961cde037234c4b8e6497a23f5f236c64cbf9d41dNick Kossifidis *
2409320b5c4a7260d9593102f378201d17e3f030739Nick Kossifidis */
24161cde037234c4b8e6497a23f5f236c64cbf9d41dNick Kossifidisstatic inline void ath5k_hw_write_rate_duration(struct ath5k_hw *ah)
2429320b5c4a7260d9593102f378201d17e3f030739Nick Kossifidis{
2439320b5c4a7260d9593102f378201d17e3f030739Nick Kossifidis	struct ath5k_softc *sc = ah->ah_sc;
2449320b5c4a7260d9593102f378201d17e3f030739Nick Kossifidis	struct ieee80211_rate *rate;
2459320b5c4a7260d9593102f378201d17e3f030739Nick Kossifidis	unsigned int i;
24661cde037234c4b8e6497a23f5f236c64cbf9d41dNick Kossifidis	/* 802.11g covers both OFDM and CCK */
24761cde037234c4b8e6497a23f5f236c64cbf9d41dNick Kossifidis	u8 band = IEEE80211_BAND_2GHZ;
2489320b5c4a7260d9593102f378201d17e3f030739Nick Kossifidis
2499320b5c4a7260d9593102f378201d17e3f030739Nick Kossifidis	/* Write rate duration table */
25061cde037234c4b8e6497a23f5f236c64cbf9d41dNick Kossifidis	for (i = 0; i < sc->sbands[band].n_bitrates; i++) {
2519320b5c4a7260d9593102f378201d17e3f030739Nick Kossifidis		u32 reg;
2529320b5c4a7260d9593102f378201d17e3f030739Nick Kossifidis		u16 tx_time;
2539320b5c4a7260d9593102f378201d17e3f030739Nick Kossifidis
25461cde037234c4b8e6497a23f5f236c64cbf9d41dNick Kossifidis		if (ah->ah_ack_bitrate_high)
25561cde037234c4b8e6497a23f5f236c64cbf9d41dNick Kossifidis			rate = &sc->sbands[band].bitrates[ack_rates_high[i]];
25661cde037234c4b8e6497a23f5f236c64cbf9d41dNick Kossifidis		/* CCK -> 1Mb */
25761cde037234c4b8e6497a23f5f236c64cbf9d41dNick Kossifidis		else if (i < 4)
25861cde037234c4b8e6497a23f5f236c64cbf9d41dNick Kossifidis			rate = &sc->sbands[band].bitrates[0];
25961cde037234c4b8e6497a23f5f236c64cbf9d41dNick Kossifidis		/* OFDM -> 6Mb */
26061cde037234c4b8e6497a23f5f236c64cbf9d41dNick Kossifidis		else
26161cde037234c4b8e6497a23f5f236c64cbf9d41dNick Kossifidis			rate = &sc->sbands[band].bitrates[4];
2629320b5c4a7260d9593102f378201d17e3f030739Nick Kossifidis
2639320b5c4a7260d9593102f378201d17e3f030739Nick Kossifidis		/* Set ACK timeout */
2649320b5c4a7260d9593102f378201d17e3f030739Nick Kossifidis		reg = AR5K_RATE_DUR(rate->hw_value);
2659320b5c4a7260d9593102f378201d17e3f030739Nick Kossifidis
2669320b5c4a7260d9593102f378201d17e3f030739Nick Kossifidis		/* An ACK frame consists of 10 bytes. If you add the FCS,
2679320b5c4a7260d9593102f378201d17e3f030739Nick Kossifidis		 * which ieee80211_generic_frame_duration() adds,
2689320b5c4a7260d9593102f378201d17e3f030739Nick Kossifidis		 * its 14 bytes. Note we use the control rate and not the
2699320b5c4a7260d9593102f378201d17e3f030739Nick Kossifidis		 * actual rate for this rate. See mac80211 tx.c
2709320b5c4a7260d9593102f378201d17e3f030739Nick Kossifidis		 * ieee80211_duration() for a brief description of
2719320b5c4a7260d9593102f378201d17e3f030739Nick Kossifidis		 * what rate we should choose to TX ACKs. */
272a27049e2c926bcf68360532a5ae66e408296ae85Felix Fietkau		tx_time = ath5k_hw_get_frame_duration(ah, 10, rate, false);
27361cde037234c4b8e6497a23f5f236c64cbf9d41dNick Kossifidis
2749320b5c4a7260d9593102f378201d17e3f030739Nick Kossifidis		ath5k_hw_reg_write(ah, tx_time, reg);
2759320b5c4a7260d9593102f378201d17e3f030739Nick Kossifidis
2769320b5c4a7260d9593102f378201d17e3f030739Nick Kossifidis		if (!(rate->flags & IEEE80211_RATE_SHORT_PREAMBLE))
2779320b5c4a7260d9593102f378201d17e3f030739Nick Kossifidis			continue;
2789320b5c4a7260d9593102f378201d17e3f030739Nick Kossifidis
279a27049e2c926bcf68360532a5ae66e408296ae85Felix Fietkau		tx_time = ath5k_hw_get_frame_duration(ah, 10, rate, true);
2809320b5c4a7260d9593102f378201d17e3f030739Nick Kossifidis		ath5k_hw_reg_write(ah, tx_time,
2819320b5c4a7260d9593102f378201d17e3f030739Nick Kossifidis			reg + (AR5K_SET_SHORT_PREAMBLE << 2));
2829320b5c4a7260d9593102f378201d17e3f030739Nick Kossifidis	}
2839320b5c4a7260d9593102f378201d17e3f030739Nick Kossifidis}
2849320b5c4a7260d9593102f378201d17e3f030739Nick Kossifidis
285c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis/**
286c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis * ath5k_hw_set_ack_timeout - Set ACK timeout on PCU
287c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis *
288c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis * @ah: The &struct ath5k_hw
289c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis * @timeout: Timeout in usec
290c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis */
291626ede6b1aafb3a8cadfdd04b512fd1d3dc2113ePavel Roskinstatic int ath5k_hw_set_ack_timeout(struct ath5k_hw *ah, unsigned int timeout)
292c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis{
2933578e6ebb305e6bf7519f6e86741772892f4d51aLukáš Turek	if (ath5k_hw_clocktoh(ah, AR5K_REG_MS(0xffffffff, AR5K_TIME_OUT_ACK))
2943578e6ebb305e6bf7519f6e86741772892f4d51aLukáš Turek			<= timeout)
295c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis		return -EINVAL;
296c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis
297c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis	AR5K_REG_WRITE_BITS(ah, AR5K_TIME_OUT, AR5K_TIME_OUT_ACK,
2983578e6ebb305e6bf7519f6e86741772892f4d51aLukáš Turek		ath5k_hw_htoclock(ah, timeout));
299c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis
300c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis	return 0;
301c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis}
302c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis
303c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis/**
304c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis * ath5k_hw_set_cts_timeout - Set CTS timeout on PCU
305c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis *
306c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis * @ah: The &struct ath5k_hw
307c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis * @timeout: Timeout in usec
308c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis */
309626ede6b1aafb3a8cadfdd04b512fd1d3dc2113ePavel Roskinstatic int ath5k_hw_set_cts_timeout(struct ath5k_hw *ah, unsigned int timeout)
310c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis{
3113578e6ebb305e6bf7519f6e86741772892f4d51aLukáš Turek	if (ath5k_hw_clocktoh(ah, AR5K_REG_MS(0xffffffff, AR5K_TIME_OUT_CTS))
3123578e6ebb305e6bf7519f6e86741772892f4d51aLukáš Turek			<= timeout)
313c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis		return -EINVAL;
314c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis
315c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis	AR5K_REG_WRITE_BITS(ah, AR5K_TIME_OUT, AR5K_TIME_OUT_CTS,
3163578e6ebb305e6bf7519f6e86741772892f4d51aLukáš Turek			ath5k_hw_htoclock(ah, timeout));
317c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis
318c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis	return 0;
319c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis}
320c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis
3216e08d228b6d8e93d7b25b3573c6da7da179c2ae1Lukáš Turek
3229320b5c4a7260d9593102f378201d17e3f030739Nick Kossifidis/*******************\
3239320b5c4a7260d9593102f378201d17e3f030739Nick Kossifidis* RX filter Control *
3249320b5c4a7260d9593102f378201d17e3f030739Nick Kossifidis\*******************/
3256e08d228b6d8e93d7b25b3573c6da7da179c2ae1Lukáš Turek
3266e08d228b6d8e93d7b25b3573c6da7da179c2ae1Lukáš Turek/**
327c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis * ath5k_hw_set_lladdr - Set station id
328c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis *
329c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis * @ah: The &struct ath5k_hw
330c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis * @mac: The card's mac address
331c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis *
332c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis * Set station id on hw using the provided mac address
333c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis */
334c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidisint ath5k_hw_set_lladdr(struct ath5k_hw *ah, const u8 *mac)
335c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis{
336954fecea5d1df4d1dc7bf9a822a2fad308e8588eLuis R. Rodriguez	struct ath_common *common = ath5k_hw_common(ah);
337c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis	u32 low_id, high_id;
338f6bac3ea5990653765700b2c3778b08782abebe5Bob Copeland	u32 pcu_reg;
339c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis
340c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis	/* Set new station ID */
341954fecea5d1df4d1dc7bf9a822a2fad308e8588eLuis R. Rodriguez	memcpy(common->macaddr, mac, ETH_ALEN);
342c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis
343f6bac3ea5990653765700b2c3778b08782abebe5Bob Copeland	pcu_reg = ath5k_hw_reg_read(ah, AR5K_STA_ID1) & 0xffff0000;
344f6bac3ea5990653765700b2c3778b08782abebe5Bob Copeland
345bcd8f54a84ce99ade91c250a9bc850a9fd3389c1Luis R. Rodriguez	low_id = get_unaligned_le32(mac);
346bcd8f54a84ce99ade91c250a9bc850a9fd3389c1Luis R. Rodriguez	high_id = get_unaligned_le16(mac + 4);
347c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis
348c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis	ath5k_hw_reg_write(ah, low_id, AR5K_STA_ID0);
349f6bac3ea5990653765700b2c3778b08782abebe5Bob Copeland	ath5k_hw_reg_write(ah, pcu_reg | high_id, AR5K_STA_ID1);
350c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis
351c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis	return 0;
352c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis}
353c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis
354c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis/**
355418de6d955fa1da0cb4332661a31d21f57e954abNick Kossifidis * ath5k_hw_set_bssid - Set current BSSID on hw
356c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis *
357c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis * @ah: The &struct ath5k_hw
358c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis *
359418de6d955fa1da0cb4332661a31d21f57e954abNick Kossifidis * Sets the current BSSID and BSSID mask we have from the
360418de6d955fa1da0cb4332661a31d21f57e954abNick Kossifidis * common struct into the hardware
361c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis */
362418de6d955fa1da0cb4332661a31d21f57e954abNick Kossifidisvoid ath5k_hw_set_bssid(struct ath5k_hw *ah)
363c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis{
364954fecea5d1df4d1dc7bf9a822a2fad308e8588eLuis R. Rodriguez	struct ath_common *common = ath5k_hw_common(ah);
365c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis	u16 tim_offset = 0;
366c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis
367c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis	/*
368418de6d955fa1da0cb4332661a31d21f57e954abNick Kossifidis	 * Set BSSID mask on 5212
369c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis	 */
370a72d57a862f700edf85da81aae3cd8f923e989a1Luis R. Rodriguez	if (ah->ah_version == AR5K_AR5212)
371a72d57a862f700edf85da81aae3cd8f923e989a1Luis R. Rodriguez		ath_hw_setbssidmask(common);
372c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis
373c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis	/*
374418de6d955fa1da0cb4332661a31d21f57e954abNick Kossifidis	 * Set BSSID
375c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis	 */
376abba06869e2546484fa142528737d1a0622add54Luis R. Rodriguez	ath5k_hw_reg_write(ah,
377abba06869e2546484fa142528737d1a0622add54Luis R. Rodriguez			   get_unaligned_le32(common->curbssid),
378a3f86bff1c056f47c2df4c58bfcf7bdda8eaf9d0Luis R. Rodriguez			   AR5K_BSS_ID0);
379abba06869e2546484fa142528737d1a0622add54Luis R. Rodriguez	ath5k_hw_reg_write(ah,
380abba06869e2546484fa142528737d1a0622add54Luis R. Rodriguez			   get_unaligned_le16(common->curbssid + 4) |
381abba06869e2546484fa142528737d1a0622add54Luis R. Rodriguez			   ((common->curaid & 0x3fff) << AR5K_BSS_ID1_AID_S),
382a3f86bff1c056f47c2df4c58bfcf7bdda8eaf9d0Luis R. Rodriguez			   AR5K_BSS_ID1);
383c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis
384be5d6b75e0fb3f7e23ea5325109ef4195f2b282aLuis R. Rodriguez	if (common->curaid == 0) {
385c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis		ath5k_hw_disable_pspoll(ah);
386c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis		return;
387c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis	}
388c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis
389c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis	AR5K_REG_WRITE_BITS(ah, AR5K_BEACON, AR5K_BEACON_TIM,
390abba06869e2546484fa142528737d1a0622add54Luis R. Rodriguez			    tim_offset ? tim_offset + 4 : 0);
391c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis
392c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis	ath5k_hw_enable_pspoll(ah, NULL, 0);
393c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis}
394c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis
39513b81559200b8e54473e5b140323cbb5f2bb21c0Luis R. Rodriguezvoid ath5k_hw_set_bssid_mask(struct ath5k_hw *ah, const u8 *mask)
396c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis{
397954fecea5d1df4d1dc7bf9a822a2fad308e8588eLuis R. Rodriguez	struct ath_common *common = ath5k_hw_common(ah);
398c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis
399f07a6c495e88ae0143e3c20b1ed666314197277fNick Kossifidis	/* Cache bssid mask so that we can restore it
400f07a6c495e88ae0143e3c20b1ed666314197277fNick Kossifidis	 * on reset */
401954fecea5d1df4d1dc7bf9a822a2fad308e8588eLuis R. Rodriguez	memcpy(common->bssidmask, mask, ETH_ALEN);
40213b81559200b8e54473e5b140323cbb5f2bb21c0Luis R. Rodriguez	if (ah->ah_version == AR5K_AR5212)
40313b81559200b8e54473e5b140323cbb5f2bb21c0Luis R. Rodriguez		ath_hw_setbssidmask(common);
404c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis}
405c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis
406c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis/*
407c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis * Set multicast filter
408c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis */
409c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidisvoid ath5k_hw_set_mcast_filter(struct ath5k_hw *ah, u32 filter0, u32 filter1)
410c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis{
411c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis	ath5k_hw_reg_write(ah, filter0, AR5K_MCAST_FILTER0);
412c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis	ath5k_hw_reg_write(ah, filter1, AR5K_MCAST_FILTER1);
413c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis}
414c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis
415c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis/**
416c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis * ath5k_hw_get_rx_filter - Get current rx filter
417c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis *
418c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis * @ah: The &struct ath5k_hw
419c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis *
420c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis * Returns the RX filter by reading rx filter and
421c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis * phy error filter registers. RX filter is used
422c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis * to set the allowed frame types that PCU will accept
423c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis * and pass to the driver. For a list of frame types
424c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis * check out reg.h.
425c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis */
426c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidisu32 ath5k_hw_get_rx_filter(struct ath5k_hw *ah)
427c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis{
428c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis	u32 data, filter = 0;
429c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis
430c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis	filter = ath5k_hw_reg_read(ah, AR5K_RX_FILTER);
431c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis
432c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis	/*Radar detection for 5212*/
433c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis	if (ah->ah_version == AR5K_AR5212) {
434c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis		data = ath5k_hw_reg_read(ah, AR5K_PHY_ERR_FIL);
435c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis
436c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis		if (data & AR5K_PHY_ERR_FIL_RADAR)
437c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis			filter |= AR5K_RX_FILTER_RADARERR;
438c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis		if (data & (AR5K_PHY_ERR_FIL_OFDM | AR5K_PHY_ERR_FIL_CCK))
439c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis			filter |= AR5K_RX_FILTER_PHYERR;
440c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis	}
441c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis
442c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis	return filter;
443c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis}
444c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis
445c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis/**
446c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis * ath5k_hw_set_rx_filter - Set rx filter
447c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis *
448c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis * @ah: The &struct ath5k_hw
449c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis * @filter: RX filter mask (see reg.h)
450c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis *
451c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis * Sets RX filter register and also handles PHY error filter
452c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis * register on 5212 and newer chips so that we have proper PHY
453c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis * error reporting.
454c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis */
455c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidisvoid ath5k_hw_set_rx_filter(struct ath5k_hw *ah, u32 filter)
456c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis{
457c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis	u32 data = 0;
458c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis
459c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis	/* Set PHY error filter register on 5212*/
460c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis	if (ah->ah_version == AR5K_AR5212) {
461c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis		if (filter & AR5K_RX_FILTER_RADARERR)
462c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis			data |= AR5K_PHY_ERR_FIL_RADAR;
463c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis		if (filter & AR5K_RX_FILTER_PHYERR)
464c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis			data |= AR5K_PHY_ERR_FIL_OFDM | AR5K_PHY_ERR_FIL_CCK;
465c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis	}
466c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis
467c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis	/*
468c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis	 * The AR5210 uses promiscous mode to detect radar activity
469c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis	 */
470c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis	if (ah->ah_version == AR5K_AR5210 &&
471c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis			(filter & AR5K_RX_FILTER_RADARERR)) {
472c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis		filter &= ~AR5K_RX_FILTER_RADARERR;
473c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis		filter |= AR5K_RX_FILTER_PROM;
474c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis	}
475c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis
476f07a6c495e88ae0143e3c20b1ed666314197277fNick Kossifidis	/*Zero length DMA (phy error reporting) */
477c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis	if (data)
478c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis		AR5K_REG_ENABLE_BITS(ah, AR5K_RXCFG, AR5K_RXCFG_ZLFDMA);
479c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis	else
480c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis		AR5K_REG_DISABLE_BITS(ah, AR5K_RXCFG, AR5K_RXCFG_ZLFDMA);
481c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis
482c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis	/*Write RX Filter register*/
483c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis	ath5k_hw_reg_write(ah, filter & 0xff, AR5K_RX_FILTER);
484c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis
485c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis	/*Write PHY error filter register on 5212*/
486c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis	if (ah->ah_version == AR5K_AR5212)
487c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis		ath5k_hw_reg_write(ah, data, AR5K_PHY_ERR_FIL);
488c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis
489c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis}
490c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis
491c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis
492c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis/****************\
493c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis* Beacon control *
494c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis\****************/
495c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis
4961c0fc65e6de4e941ff483df445e721d6edb1f84bBenoit Papillault#define ATH5K_MAX_TSF_READ 10
4971c0fc65e6de4e941ff483df445e721d6edb1f84bBenoit Papillault
498c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis/**
499c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis * ath5k_hw_get_tsf64 - Get the full 64bit TSF
500c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis *
501c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis * @ah: The &struct ath5k_hw
502c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis *
503c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis * Returns the current TSF
504c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis */
505c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidisu64 ath5k_hw_get_tsf64(struct ath5k_hw *ah)
506c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis{
5071c0fc65e6de4e941ff483df445e721d6edb1f84bBenoit Papillault	u32 tsf_lower, tsf_upper1, tsf_upper2;
5081c0fc65e6de4e941ff483df445e721d6edb1f84bBenoit Papillault	int i;
50928df897a42aa41d6318be5b9872c4bb5c8d8d7e3Bruno Randolf	unsigned long flags;
51028df897a42aa41d6318be5b9872c4bb5c8d8d7e3Bruno Randolf
51128df897a42aa41d6318be5b9872c4bb5c8d8d7e3Bruno Randolf	/* This code is time critical - we don't want to be interrupted here */
51228df897a42aa41d6318be5b9872c4bb5c8d8d7e3Bruno Randolf	local_irq_save(flags);
5131c0fc65e6de4e941ff483df445e721d6edb1f84bBenoit Papillault
5141c0fc65e6de4e941ff483df445e721d6edb1f84bBenoit Papillault	/*
5151c0fc65e6de4e941ff483df445e721d6edb1f84bBenoit Papillault	 * While reading TSF upper and then lower part, the clock is still
5161c0fc65e6de4e941ff483df445e721d6edb1f84bBenoit Papillault	 * counting (or jumping in case of IBSS merge) so we might get
5171c0fc65e6de4e941ff483df445e721d6edb1f84bBenoit Papillault	 * inconsistent values. To avoid this, we read the upper part again
5181c0fc65e6de4e941ff483df445e721d6edb1f84bBenoit Papillault	 * and check it has not been changed. We make the hypothesis that a
5191c0fc65e6de4e941ff483df445e721d6edb1f84bBenoit Papillault	 * maximum of 3 changes can happens in a row (we use 10 as a safe
5201c0fc65e6de4e941ff483df445e721d6edb1f84bBenoit Papillault	 * value).
5211c0fc65e6de4e941ff483df445e721d6edb1f84bBenoit Papillault	 *
5221c0fc65e6de4e941ff483df445e721d6edb1f84bBenoit Papillault	 * Impact on performance is pretty small, since in most cases, only
5231c0fc65e6de4e941ff483df445e721d6edb1f84bBenoit Papillault	 * 3 register reads are needed.
5241c0fc65e6de4e941ff483df445e721d6edb1f84bBenoit Papillault	 */
5251c0fc65e6de4e941ff483df445e721d6edb1f84bBenoit Papillault
5261c0fc65e6de4e941ff483df445e721d6edb1f84bBenoit Papillault	tsf_upper1 = ath5k_hw_reg_read(ah, AR5K_TSF_U32);
5271c0fc65e6de4e941ff483df445e721d6edb1f84bBenoit Papillault	for (i = 0; i < ATH5K_MAX_TSF_READ; i++) {
5281c0fc65e6de4e941ff483df445e721d6edb1f84bBenoit Papillault		tsf_lower = ath5k_hw_reg_read(ah, AR5K_TSF_L32);
5291c0fc65e6de4e941ff483df445e721d6edb1f84bBenoit Papillault		tsf_upper2 = ath5k_hw_reg_read(ah, AR5K_TSF_U32);
5301c0fc65e6de4e941ff483df445e721d6edb1f84bBenoit Papillault		if (tsf_upper2 == tsf_upper1)
5311c0fc65e6de4e941ff483df445e721d6edb1f84bBenoit Papillault			break;
5321c0fc65e6de4e941ff483df445e721d6edb1f84bBenoit Papillault		tsf_upper1 = tsf_upper2;
5331c0fc65e6de4e941ff483df445e721d6edb1f84bBenoit Papillault	}
5341c0fc65e6de4e941ff483df445e721d6edb1f84bBenoit Papillault
53528df897a42aa41d6318be5b9872c4bb5c8d8d7e3Bruno Randolf	local_irq_restore(flags);
53628df897a42aa41d6318be5b9872c4bb5c8d8d7e3Bruno Randolf
5371c0fc65e6de4e941ff483df445e721d6edb1f84bBenoit Papillault	WARN_ON( i == ATH5K_MAX_TSF_READ );
5381c0fc65e6de4e941ff483df445e721d6edb1f84bBenoit Papillault
5391c0fc65e6de4e941ff483df445e721d6edb1f84bBenoit Papillault	return (((u64)tsf_upper1 << 32) | tsf_lower);
540c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis}
541c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis
542c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis/**
5438cab7581dba90b0519e25784e08feb5dedde737fAlina Friedrichsen * ath5k_hw_set_tsf64 - Set a new 64bit TSF
5448cab7581dba90b0519e25784e08feb5dedde737fAlina Friedrichsen *
5458cab7581dba90b0519e25784e08feb5dedde737fAlina Friedrichsen * @ah: The &struct ath5k_hw
5468cab7581dba90b0519e25784e08feb5dedde737fAlina Friedrichsen * @tsf64: The new 64bit TSF
5478cab7581dba90b0519e25784e08feb5dedde737fAlina Friedrichsen *
5488cab7581dba90b0519e25784e08feb5dedde737fAlina Friedrichsen * Sets the new TSF
5498cab7581dba90b0519e25784e08feb5dedde737fAlina Friedrichsen */
5508cab7581dba90b0519e25784e08feb5dedde737fAlina Friedrichsenvoid ath5k_hw_set_tsf64(struct ath5k_hw *ah, u64 tsf64)
5518cab7581dba90b0519e25784e08feb5dedde737fAlina Friedrichsen{
5528cab7581dba90b0519e25784e08feb5dedde737fAlina Friedrichsen	ath5k_hw_reg_write(ah, tsf64 & 0xffffffff, AR5K_TSF_L32);
5530ad65bd7e1b38dd2c86da5f07dbfa35fe1f03099Alina Friedrichsen	ath5k_hw_reg_write(ah, (tsf64 >> 32) & 0xffffffff, AR5K_TSF_U32);
5548cab7581dba90b0519e25784e08feb5dedde737fAlina Friedrichsen}
5558cab7581dba90b0519e25784e08feb5dedde737fAlina Friedrichsen
5568cab7581dba90b0519e25784e08feb5dedde737fAlina Friedrichsen/**
557c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis * ath5k_hw_reset_tsf - Force a TSF reset
558c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis *
559c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis * @ah: The &struct ath5k_hw
560c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis *
561c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis * Forces a TSF reset on PCU
562c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis */
563c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidisvoid ath5k_hw_reset_tsf(struct ath5k_hw *ah)
564c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis{
56514be9947ef9843102b67d315c7483de112b5b2d7Bob Copeland	u32 val;
56614be9947ef9843102b67d315c7483de112b5b2d7Bob Copeland
56714be9947ef9843102b67d315c7483de112b5b2d7Bob Copeland	val = ath5k_hw_reg_read(ah, AR5K_BEACON) | AR5K_BEACON_RESET_TSF;
56814be9947ef9843102b67d315c7483de112b5b2d7Bob Copeland
56914be9947ef9843102b67d315c7483de112b5b2d7Bob Copeland	/*
57014be9947ef9843102b67d315c7483de112b5b2d7Bob Copeland	 * Each write to the RESET_TSF bit toggles a hardware internal
57114be9947ef9843102b67d315c7483de112b5b2d7Bob Copeland	 * signal to reset TSF, but if left high it will cause a TSF reset
57214be9947ef9843102b67d315c7483de112b5b2d7Bob Copeland	 * on the next chip reset as well.  Thus we always write the value
57314be9947ef9843102b67d315c7483de112b5b2d7Bob Copeland	 * twice to clear the signal.
57414be9947ef9843102b67d315c7483de112b5b2d7Bob Copeland	 */
57514be9947ef9843102b67d315c7483de112b5b2d7Bob Copeland	ath5k_hw_reg_write(ah, val, AR5K_BEACON);
57614be9947ef9843102b67d315c7483de112b5b2d7Bob Copeland	ath5k_hw_reg_write(ah, val, AR5K_BEACON);
577c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis}
578c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis
579c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis/*
580c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis * Initialize beacon timers
581c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis */
582c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidisvoid ath5k_hw_init_beacon(struct ath5k_hw *ah, u32 next_beacon, u32 interval)
583c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis{
584c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis	u32 timer1, timer2, timer3;
585c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis
586c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis	/*
587c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis	 * Set the additional timers by mode
588c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis	 */
589ccfe5552aeb18c87a4d0ecb8cb7512280435bfddBruno Randolf	switch (ah->ah_sc->opmode) {
590f07a6c495e88ae0143e3c20b1ed666314197277fNick Kossifidis	case NL80211_IFTYPE_MONITOR:
59105c914fe330fa8e1cc67870dc0d3809dfd96c107Johannes Berg	case NL80211_IFTYPE_STATION:
592f07a6c495e88ae0143e3c20b1ed666314197277fNick Kossifidis		/* In STA mode timer1 is used as next wakeup
593f07a6c495e88ae0143e3c20b1ed666314197277fNick Kossifidis		 * timer and timer2 as next CFP duration start
594f07a6c495e88ae0143e3c20b1ed666314197277fNick Kossifidis		 * timer. Both in 1/8TUs. */
595f07a6c495e88ae0143e3c20b1ed666314197277fNick Kossifidis		/* TODO: PCF handling */
596c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis		if (ah->ah_version == AR5K_AR5210) {
597c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis			timer1 = 0xffffffff;
598c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis			timer2 = 0xffffffff;
599c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis		} else {
600c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis			timer1 = 0x0000ffff;
601c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis			timer2 = 0x0007ffff;
602c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis		}
603f07a6c495e88ae0143e3c20b1ed666314197277fNick Kossifidis		/* Mark associated AP as PCF incapable for now */
604f07a6c495e88ae0143e3c20b1ed666314197277fNick Kossifidis		AR5K_REG_DISABLE_BITS(ah, AR5K_STA_ID1, AR5K_STA_ID1_PCF);
605c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis		break;
606f07a6c495e88ae0143e3c20b1ed666314197277fNick Kossifidis	case NL80211_IFTYPE_ADHOC:
607f07a6c495e88ae0143e3c20b1ed666314197277fNick Kossifidis		AR5K_REG_ENABLE_BITS(ah, AR5K_TXCFG, AR5K_TXCFG_ADHOC_BCN_ATIM);
608c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis	default:
609f07a6c495e88ae0143e3c20b1ed666314197277fNick Kossifidis		/* On non-STA modes timer1 is used as next DMA
610f07a6c495e88ae0143e3c20b1ed666314197277fNick Kossifidis		 * beacon alert (DBA) timer and timer2 as next
611f07a6c495e88ae0143e3c20b1ed666314197277fNick Kossifidis		 * software beacon alert. Both in 1/8TUs. */
612c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis		timer1 = (next_beacon - AR5K_TUNE_DMA_BEACON_RESP) << 3;
613c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis		timer2 = (next_beacon - AR5K_TUNE_SW_BEACON_RESP) << 3;
614f07a6c495e88ae0143e3c20b1ed666314197277fNick Kossifidis		break;
615c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis	}
616c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis
617f07a6c495e88ae0143e3c20b1ed666314197277fNick Kossifidis	/* Timer3 marks the end of our ATIM window
618f07a6c495e88ae0143e3c20b1ed666314197277fNick Kossifidis	 * a zero length window is not allowed because
619f07a6c495e88ae0143e3c20b1ed666314197277fNick Kossifidis	 * we 'll get no beacons */
6204a79f2c517cce31c3b25aab0ec5078368b22c363Bruno Randolf	timer3 = next_beacon + 1;
621c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis
622c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis	/*
623c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis	 * Set the beacon register and enable all timers.
624c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis	 */
62535edf8aae8f903b154d658b9a7eed0d5c1a4a814Nick Kossifidis	/* When in AP or Mesh Point mode zero timer0 to start TSF */
626ccfe5552aeb18c87a4d0ecb8cb7512280435bfddBruno Randolf	if (ah->ah_sc->opmode == NL80211_IFTYPE_AP ||
627ccfe5552aeb18c87a4d0ecb8cb7512280435bfddBruno Randolf	    ah->ah_sc->opmode == NL80211_IFTYPE_MESH_POINT)
628f07a6c495e88ae0143e3c20b1ed666314197277fNick Kossifidis		ath5k_hw_reg_write(ah, 0, AR5K_TIMER0);
629428cbd4ff4d0f2423f49e499f499f04a636cb152Nick Kossifidis
630428cbd4ff4d0f2423f49e499f499f04a636cb152Nick Kossifidis	ath5k_hw_reg_write(ah, next_beacon, AR5K_TIMER0);
631c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis	ath5k_hw_reg_write(ah, timer1, AR5K_TIMER1);
632c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis	ath5k_hw_reg_write(ah, timer2, AR5K_TIMER2);
633c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis	ath5k_hw_reg_write(ah, timer3, AR5K_TIMER3);
634c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis
635f07a6c495e88ae0143e3c20b1ed666314197277fNick Kossifidis	/* Force a TSF reset if requested and enable beacons */
636f07a6c495e88ae0143e3c20b1ed666314197277fNick Kossifidis	if (interval & AR5K_BEACON_RESET_TSF)
637f07a6c495e88ae0143e3c20b1ed666314197277fNick Kossifidis		ath5k_hw_reset_tsf(ah);
638f07a6c495e88ae0143e3c20b1ed666314197277fNick Kossifidis
639c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis	ath5k_hw_reg_write(ah, interval & (AR5K_BEACON_PERIOD |
640f07a6c495e88ae0143e3c20b1ed666314197277fNick Kossifidis					AR5K_BEACON_ENABLE),
641f07a6c495e88ae0143e3c20b1ed666314197277fNick Kossifidis						AR5K_BEACON);
642f07a6c495e88ae0143e3c20b1ed666314197277fNick Kossifidis
643f07a6c495e88ae0143e3c20b1ed666314197277fNick Kossifidis	/* Flush any pending BMISS interrupts on ISR by
644f07a6c495e88ae0143e3c20b1ed666314197277fNick Kossifidis	 * performing a clear-on-write operation on PISR
645f07a6c495e88ae0143e3c20b1ed666314197277fNick Kossifidis	 * register for the BMISS bit (writing a bit on
646f07a6c495e88ae0143e3c20b1ed666314197277fNick Kossifidis	 * ISR togles a reset for that bit and leaves
647f07a6c495e88ae0143e3c20b1ed666314197277fNick Kossifidis	 * the rest bits intact) */
648f07a6c495e88ae0143e3c20b1ed666314197277fNick Kossifidis	if (ah->ah_version == AR5K_AR5210)
649f07a6c495e88ae0143e3c20b1ed666314197277fNick Kossifidis		ath5k_hw_reg_write(ah, AR5K_ISR_BMISS, AR5K_ISR);
650f07a6c495e88ae0143e3c20b1ed666314197277fNick Kossifidis	else
651f07a6c495e88ae0143e3c20b1ed666314197277fNick Kossifidis		ath5k_hw_reg_write(ah, AR5K_ISR_BMISS, AR5K_PISR);
652f07a6c495e88ae0143e3c20b1ed666314197277fNick Kossifidis
653f07a6c495e88ae0143e3c20b1ed666314197277fNick Kossifidis	/* TODO: Set enchanced sleep registers on AR5212
654f07a6c495e88ae0143e3c20b1ed666314197277fNick Kossifidis	 * based on vif->bss_conf params, until then
655f07a6c495e88ae0143e3c20b1ed666314197277fNick Kossifidis	 * disable power save reporting.*/
656f07a6c495e88ae0143e3c20b1ed666314197277fNick Kossifidis	AR5K_REG_DISABLE_BITS(ah, AR5K_STA_ID1, AR5K_STA_ID1_PWR_SV);
657f07a6c495e88ae0143e3c20b1ed666314197277fNick Kossifidis
658c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis}
659c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis
6606e08d228b6d8e93d7b25b3573c6da7da179c2ae1Lukáš Turek/**
6617f896126017830b29cf501d246ee32b81e359acdBruno Randolf * ath5k_check_timer_win - Check if timer B is timer A + window
6627f896126017830b29cf501d246ee32b81e359acdBruno Randolf *
6637f896126017830b29cf501d246ee32b81e359acdBruno Randolf * @a: timer a (before b)
6647f896126017830b29cf501d246ee32b81e359acdBruno Randolf * @b: timer b (after a)
6657f896126017830b29cf501d246ee32b81e359acdBruno Randolf * @window: difference between a and b
6667f896126017830b29cf501d246ee32b81e359acdBruno Randolf * @intval: timers are increased by this interval
6677f896126017830b29cf501d246ee32b81e359acdBruno Randolf *
6687f896126017830b29cf501d246ee32b81e359acdBruno Randolf * This helper function checks if timer B is timer A + window and covers
6697f896126017830b29cf501d246ee32b81e359acdBruno Randolf * cases where timer A or B might have already been updated or wrapped
6707f896126017830b29cf501d246ee32b81e359acdBruno Randolf * around (Timers are 16 bit).
6717f896126017830b29cf501d246ee32b81e359acdBruno Randolf *
6727f896126017830b29cf501d246ee32b81e359acdBruno Randolf * Returns true if O.K.
6737f896126017830b29cf501d246ee32b81e359acdBruno Randolf */
6747f896126017830b29cf501d246ee32b81e359acdBruno Randolfstatic inline bool
6757f896126017830b29cf501d246ee32b81e359acdBruno Randolfath5k_check_timer_win(int a, int b, int window, int intval)
6767f896126017830b29cf501d246ee32b81e359acdBruno Randolf{
6777f896126017830b29cf501d246ee32b81e359acdBruno Randolf	/*
6787f896126017830b29cf501d246ee32b81e359acdBruno Randolf	 * 1.) usually B should be A + window
6797f896126017830b29cf501d246ee32b81e359acdBruno Randolf	 * 2.) A already updated, B not updated yet
6807f896126017830b29cf501d246ee32b81e359acdBruno Randolf	 * 3.) A already updated and has wrapped around
6817f896126017830b29cf501d246ee32b81e359acdBruno Randolf	 * 4.) B has wrapped around
6827f896126017830b29cf501d246ee32b81e359acdBruno Randolf	 */
6837f896126017830b29cf501d246ee32b81e359acdBruno Randolf	if ((b - a == window) ||				/* 1.) */
6847f896126017830b29cf501d246ee32b81e359acdBruno Randolf	    (a - b == intval - window) ||			/* 2.) */
6857f896126017830b29cf501d246ee32b81e359acdBruno Randolf	    ((a | 0x10000) - b == intval - window) ||		/* 3.) */
6867f896126017830b29cf501d246ee32b81e359acdBruno Randolf	    ((b | 0x10000) - a == window))			/* 4.) */
6877f896126017830b29cf501d246ee32b81e359acdBruno Randolf		return true; /* O.K. */
6887f896126017830b29cf501d246ee32b81e359acdBruno Randolf	return false;
6897f896126017830b29cf501d246ee32b81e359acdBruno Randolf}
6907f896126017830b29cf501d246ee32b81e359acdBruno Randolf
6917f896126017830b29cf501d246ee32b81e359acdBruno Randolf/**
6927f896126017830b29cf501d246ee32b81e359acdBruno Randolf * ath5k_hw_check_beacon_timers - Check if the beacon timers are correct
6937f896126017830b29cf501d246ee32b81e359acdBruno Randolf *
6947f896126017830b29cf501d246ee32b81e359acdBruno Randolf * @ah: The &struct ath5k_hw
6957f896126017830b29cf501d246ee32b81e359acdBruno Randolf * @intval: beacon interval
6967f896126017830b29cf501d246ee32b81e359acdBruno Randolf *
6977f896126017830b29cf501d246ee32b81e359acdBruno Randolf * This is a workaround for IBSS mode:
6987f896126017830b29cf501d246ee32b81e359acdBruno Randolf *
6997f896126017830b29cf501d246ee32b81e359acdBruno Randolf * The need for this function arises from the fact that we have 4 separate
7007f896126017830b29cf501d246ee32b81e359acdBruno Randolf * HW timer registers (TIMER0 - TIMER3), which are closely related to the
7017f896126017830b29cf501d246ee32b81e359acdBruno Randolf * next beacon target time (NBTT), and that the HW updates these timers
7027f896126017830b29cf501d246ee32b81e359acdBruno Randolf * seperately based on the current TSF value. The hardware increments each
7037f896126017830b29cf501d246ee32b81e359acdBruno Randolf * timer by the beacon interval, when the local TSF coverted to TU is equal
7047f896126017830b29cf501d246ee32b81e359acdBruno Randolf * to the value stored in the timer.
7057f896126017830b29cf501d246ee32b81e359acdBruno Randolf *
7067f896126017830b29cf501d246ee32b81e359acdBruno Randolf * The reception of a beacon with the same BSSID can update the local HW TSF
7077f896126017830b29cf501d246ee32b81e359acdBruno Randolf * at any time - this is something we can't avoid. If the TSF jumps to a
7087f896126017830b29cf501d246ee32b81e359acdBruno Randolf * time which is later than the time stored in a timer, this timer will not
7097f896126017830b29cf501d246ee32b81e359acdBruno Randolf * be updated until the TSF in TU wraps around at 16 bit (the size of the
7107f896126017830b29cf501d246ee32b81e359acdBruno Randolf * timers) and reaches the time which is stored in the timer.
7117f896126017830b29cf501d246ee32b81e359acdBruno Randolf *
7127f896126017830b29cf501d246ee32b81e359acdBruno Randolf * The problem is that these timers are closely related to TIMER0 (NBTT) and
7137f896126017830b29cf501d246ee32b81e359acdBruno Randolf * that they define a time "window". When the TSF jumps between two timers
7147f896126017830b29cf501d246ee32b81e359acdBruno Randolf * (e.g. ATIM and NBTT), the one in the past will be left behind (not
7157f896126017830b29cf501d246ee32b81e359acdBruno Randolf * updated), while the one in the future will be updated every beacon
7167f896126017830b29cf501d246ee32b81e359acdBruno Randolf * interval. This causes the window to get larger, until the TSF wraps
7177f896126017830b29cf501d246ee32b81e359acdBruno Randolf * around as described above and the timer which was left behind gets
7187f896126017830b29cf501d246ee32b81e359acdBruno Randolf * updated again. But - because the beacon interval is usually not an exact
7197f896126017830b29cf501d246ee32b81e359acdBruno Randolf * divisor of the size of the timers (16 bit), an unwanted "window" between
7207f896126017830b29cf501d246ee32b81e359acdBruno Randolf * these timers has developed!
7217f896126017830b29cf501d246ee32b81e359acdBruno Randolf *
7227f896126017830b29cf501d246ee32b81e359acdBruno Randolf * This is especially important with the ATIM window, because during
7237f896126017830b29cf501d246ee32b81e359acdBruno Randolf * the ATIM window only ATIM frames and no data frames are allowed to be
7247f896126017830b29cf501d246ee32b81e359acdBruno Randolf * sent, which creates transmission pauses after each beacon. This symptom
7257f896126017830b29cf501d246ee32b81e359acdBruno Randolf * has been described as "ramping ping" because ping times increase linearly
7267f896126017830b29cf501d246ee32b81e359acdBruno Randolf * for some time and then drop down again. A wrong window on the DMA beacon
7277f896126017830b29cf501d246ee32b81e359acdBruno Randolf * timer has the same effect, so we check for these two conditions.
7287f896126017830b29cf501d246ee32b81e359acdBruno Randolf *
7297f896126017830b29cf501d246ee32b81e359acdBruno Randolf * Returns true if O.K.
7307f896126017830b29cf501d246ee32b81e359acdBruno Randolf */
7317f896126017830b29cf501d246ee32b81e359acdBruno Randolfbool
7327f896126017830b29cf501d246ee32b81e359acdBruno Randolfath5k_hw_check_beacon_timers(struct ath5k_hw *ah, int intval)
7337f896126017830b29cf501d246ee32b81e359acdBruno Randolf{
7347f896126017830b29cf501d246ee32b81e359acdBruno Randolf	unsigned int nbtt, atim, dma;
7357f896126017830b29cf501d246ee32b81e359acdBruno Randolf
7367f896126017830b29cf501d246ee32b81e359acdBruno Randolf	nbtt = ath5k_hw_reg_read(ah, AR5K_TIMER0);
7377f896126017830b29cf501d246ee32b81e359acdBruno Randolf	atim = ath5k_hw_reg_read(ah, AR5K_TIMER3);
7387f896126017830b29cf501d246ee32b81e359acdBruno Randolf	dma = ath5k_hw_reg_read(ah, AR5K_TIMER1) >> 3;
7397f896126017830b29cf501d246ee32b81e359acdBruno Randolf
7407f896126017830b29cf501d246ee32b81e359acdBruno Randolf	/* NOTE: SWBA is different. Having a wrong window there does not
7417f896126017830b29cf501d246ee32b81e359acdBruno Randolf	 * stop us from sending data and this condition is catched thru
7427f896126017830b29cf501d246ee32b81e359acdBruno Randolf	 * other means (SWBA interrupt) */
7437f896126017830b29cf501d246ee32b81e359acdBruno Randolf
7447f896126017830b29cf501d246ee32b81e359acdBruno Randolf	if (ath5k_check_timer_win(nbtt, atim, 1, intval) &&
7457f896126017830b29cf501d246ee32b81e359acdBruno Randolf	    ath5k_check_timer_win(dma, nbtt, AR5K_TUNE_DMA_BEACON_RESP,
7467f896126017830b29cf501d246ee32b81e359acdBruno Randolf				  intval))
7477f896126017830b29cf501d246ee32b81e359acdBruno Randolf		return true; /* O.K. */
7487f896126017830b29cf501d246ee32b81e359acdBruno Randolf	return false;
7497f896126017830b29cf501d246ee32b81e359acdBruno Randolf}
7507f896126017830b29cf501d246ee32b81e359acdBruno Randolf
7517f896126017830b29cf501d246ee32b81e359acdBruno Randolf/**
7526e08d228b6d8e93d7b25b3573c6da7da179c2ae1Lukáš Turek * ath5k_hw_set_coverage_class - Set IEEE 802.11 coverage class
7536e08d228b6d8e93d7b25b3573c6da7da179c2ae1Lukáš Turek *
7546e08d228b6d8e93d7b25b3573c6da7da179c2ae1Lukáš Turek * @ah: The &struct ath5k_hw
7556e08d228b6d8e93d7b25b3573c6da7da179c2ae1Lukáš Turek * @coverage_class: IEEE 802.11 coverage class number
7566e08d228b6d8e93d7b25b3573c6da7da179c2ae1Lukáš Turek *
757eeb8832b3181d6ca8593051b68c466e5d2653bb3Nick Kossifidis * Sets IFS intervals and ACK/CTS timeouts for given coverage class.
7586e08d228b6d8e93d7b25b3573c6da7da179c2ae1Lukáš Turek */
7596e08d228b6d8e93d7b25b3573c6da7da179c2ae1Lukáš Turekvoid ath5k_hw_set_coverage_class(struct ath5k_hw *ah, u8 coverage_class)
7606e08d228b6d8e93d7b25b3573c6da7da179c2ae1Lukáš Turek{
7616e08d228b6d8e93d7b25b3573c6da7da179c2ae1Lukáš Turek	/* As defined by IEEE 802.11-2007 17.3.8.6 */
7626e08d228b6d8e93d7b25b3573c6da7da179c2ae1Lukáš Turek	int slot_time = ath5k_hw_get_default_slottime(ah) + 3 * coverage_class;
7636e08d228b6d8e93d7b25b3573c6da7da179c2ae1Lukáš Turek	int ack_timeout = ath5k_hw_get_default_sifs(ah) + slot_time;
7646e08d228b6d8e93d7b25b3573c6da7da179c2ae1Lukáš Turek	int cts_timeout = ack_timeout;
7656e08d228b6d8e93d7b25b3573c6da7da179c2ae1Lukáš Turek
766eeb8832b3181d6ca8593051b68c466e5d2653bb3Nick Kossifidis	ath5k_hw_set_ifs_intervals(ah, slot_time);
7676e08d228b6d8e93d7b25b3573c6da7da179c2ae1Lukáš Turek	ath5k_hw_set_ack_timeout(ah, ack_timeout);
7686e08d228b6d8e93d7b25b3573c6da7da179c2ae1Lukáš Turek	ath5k_hw_set_cts_timeout(ah, cts_timeout);
7696e08d228b6d8e93d7b25b3573c6da7da179c2ae1Lukáš Turek
7706e08d228b6d8e93d7b25b3573c6da7da179c2ae1Lukáš Turek	ah->ah_coverage_class = coverage_class;
7716e08d228b6d8e93d7b25b3573c6da7da179c2ae1Lukáš Turek}
7729320b5c4a7260d9593102f378201d17e3f030739Nick Kossifidis
7739320b5c4a7260d9593102f378201d17e3f030739Nick Kossifidis/***************************\
7749320b5c4a7260d9593102f378201d17e3f030739Nick Kossifidis* Init/Start/Stop functions *
7759320b5c4a7260d9593102f378201d17e3f030739Nick Kossifidis\***************************/
7769320b5c4a7260d9593102f378201d17e3f030739Nick Kossifidis
7779320b5c4a7260d9593102f378201d17e3f030739Nick Kossifidis/**
7789320b5c4a7260d9593102f378201d17e3f030739Nick Kossifidis * ath5k_hw_start_rx_pcu - Start RX engine
7799320b5c4a7260d9593102f378201d17e3f030739Nick Kossifidis *
7809320b5c4a7260d9593102f378201d17e3f030739Nick Kossifidis * @ah: The &struct ath5k_hw
7819320b5c4a7260d9593102f378201d17e3f030739Nick Kossifidis *
7829320b5c4a7260d9593102f378201d17e3f030739Nick Kossifidis * Starts RX engine on PCU so that hw can process RXed frames
7839320b5c4a7260d9593102f378201d17e3f030739Nick Kossifidis * (ACK etc).
7849320b5c4a7260d9593102f378201d17e3f030739Nick Kossifidis *
7859320b5c4a7260d9593102f378201d17e3f030739Nick Kossifidis * NOTE: RX DMA should be already enabled using ath5k_hw_start_rx_dma
7869320b5c4a7260d9593102f378201d17e3f030739Nick Kossifidis */
7879320b5c4a7260d9593102f378201d17e3f030739Nick Kossifidisvoid ath5k_hw_start_rx_pcu(struct ath5k_hw *ah)
7889320b5c4a7260d9593102f378201d17e3f030739Nick Kossifidis{
7899320b5c4a7260d9593102f378201d17e3f030739Nick Kossifidis	AR5K_REG_DISABLE_BITS(ah, AR5K_DIAG_SW, AR5K_DIAG_SW_DIS_RX);
7909320b5c4a7260d9593102f378201d17e3f030739Nick Kossifidis}
7919320b5c4a7260d9593102f378201d17e3f030739Nick Kossifidis
7929320b5c4a7260d9593102f378201d17e3f030739Nick Kossifidis/**
7939320b5c4a7260d9593102f378201d17e3f030739Nick Kossifidis * at5k_hw_stop_rx_pcu - Stop RX engine
7949320b5c4a7260d9593102f378201d17e3f030739Nick Kossifidis *
7959320b5c4a7260d9593102f378201d17e3f030739Nick Kossifidis * @ah: The &struct ath5k_hw
7969320b5c4a7260d9593102f378201d17e3f030739Nick Kossifidis *
7979320b5c4a7260d9593102f378201d17e3f030739Nick Kossifidis * Stops RX engine on PCU
7989320b5c4a7260d9593102f378201d17e3f030739Nick Kossifidis */
7999320b5c4a7260d9593102f378201d17e3f030739Nick Kossifidisvoid ath5k_hw_stop_rx_pcu(struct ath5k_hw *ah)
8009320b5c4a7260d9593102f378201d17e3f030739Nick Kossifidis{
8019320b5c4a7260d9593102f378201d17e3f030739Nick Kossifidis	AR5K_REG_ENABLE_BITS(ah, AR5K_DIAG_SW, AR5K_DIAG_SW_DIS_RX);
8029320b5c4a7260d9593102f378201d17e3f030739Nick Kossifidis}
8039320b5c4a7260d9593102f378201d17e3f030739Nick Kossifidis
8049320b5c4a7260d9593102f378201d17e3f030739Nick Kossifidis/**
8059320b5c4a7260d9593102f378201d17e3f030739Nick Kossifidis * ath5k_hw_set_opmode - Set PCU operating mode
8069320b5c4a7260d9593102f378201d17e3f030739Nick Kossifidis *
8079320b5c4a7260d9593102f378201d17e3f030739Nick Kossifidis * @ah: The &struct ath5k_hw
8089320b5c4a7260d9593102f378201d17e3f030739Nick Kossifidis * @op_mode: &enum nl80211_iftype operating mode
8099320b5c4a7260d9593102f378201d17e3f030739Nick Kossifidis *
8109320b5c4a7260d9593102f378201d17e3f030739Nick Kossifidis * Configure PCU for the various operating modes (AP/STA etc)
8119320b5c4a7260d9593102f378201d17e3f030739Nick Kossifidis */
8129320b5c4a7260d9593102f378201d17e3f030739Nick Kossifidisint ath5k_hw_set_opmode(struct ath5k_hw *ah, enum nl80211_iftype op_mode)
8139320b5c4a7260d9593102f378201d17e3f030739Nick Kossifidis{
8149320b5c4a7260d9593102f378201d17e3f030739Nick Kossifidis	struct ath_common *common = ath5k_hw_common(ah);
8159320b5c4a7260d9593102f378201d17e3f030739Nick Kossifidis	u32 pcu_reg, beacon_reg, low_id, high_id;
8169320b5c4a7260d9593102f378201d17e3f030739Nick Kossifidis
8179320b5c4a7260d9593102f378201d17e3f030739Nick Kossifidis	ATH5K_DBG(ah->ah_sc, ATH5K_DEBUG_MODE, "mode %d\n", op_mode);
8189320b5c4a7260d9593102f378201d17e3f030739Nick Kossifidis
8199320b5c4a7260d9593102f378201d17e3f030739Nick Kossifidis	/* Preserve rest settings */
8209320b5c4a7260d9593102f378201d17e3f030739Nick Kossifidis	pcu_reg = ath5k_hw_reg_read(ah, AR5K_STA_ID1) & 0xffff0000;
8219320b5c4a7260d9593102f378201d17e3f030739Nick Kossifidis	pcu_reg &= ~(AR5K_STA_ID1_ADHOC | AR5K_STA_ID1_AP
8229320b5c4a7260d9593102f378201d17e3f030739Nick Kossifidis			| AR5K_STA_ID1_KEYSRCH_MODE
8239320b5c4a7260d9593102f378201d17e3f030739Nick Kossifidis			| (ah->ah_version == AR5K_AR5210 ?
8249320b5c4a7260d9593102f378201d17e3f030739Nick Kossifidis			(AR5K_STA_ID1_PWR_SV | AR5K_STA_ID1_NO_PSPOLL) : 0));
8259320b5c4a7260d9593102f378201d17e3f030739Nick Kossifidis
8269320b5c4a7260d9593102f378201d17e3f030739Nick Kossifidis	beacon_reg = 0;
8279320b5c4a7260d9593102f378201d17e3f030739Nick Kossifidis
8289320b5c4a7260d9593102f378201d17e3f030739Nick Kossifidis	switch (op_mode) {
8299320b5c4a7260d9593102f378201d17e3f030739Nick Kossifidis	case NL80211_IFTYPE_ADHOC:
8309320b5c4a7260d9593102f378201d17e3f030739Nick Kossifidis		pcu_reg |= AR5K_STA_ID1_ADHOC | AR5K_STA_ID1_KEYSRCH_MODE;
8319320b5c4a7260d9593102f378201d17e3f030739Nick Kossifidis		beacon_reg |= AR5K_BCR_ADHOC;
8329320b5c4a7260d9593102f378201d17e3f030739Nick Kossifidis		if (ah->ah_version == AR5K_AR5210)
8339320b5c4a7260d9593102f378201d17e3f030739Nick Kossifidis			pcu_reg |= AR5K_STA_ID1_NO_PSPOLL;
8349320b5c4a7260d9593102f378201d17e3f030739Nick Kossifidis		else
8359320b5c4a7260d9593102f378201d17e3f030739Nick Kossifidis			AR5K_REG_ENABLE_BITS(ah, AR5K_CFG, AR5K_CFG_IBSS);
8369320b5c4a7260d9593102f378201d17e3f030739Nick Kossifidis		break;
8379320b5c4a7260d9593102f378201d17e3f030739Nick Kossifidis
8389320b5c4a7260d9593102f378201d17e3f030739Nick Kossifidis	case NL80211_IFTYPE_AP:
8399320b5c4a7260d9593102f378201d17e3f030739Nick Kossifidis	case NL80211_IFTYPE_MESH_POINT:
8409320b5c4a7260d9593102f378201d17e3f030739Nick Kossifidis		pcu_reg |= AR5K_STA_ID1_AP | AR5K_STA_ID1_KEYSRCH_MODE;
8419320b5c4a7260d9593102f378201d17e3f030739Nick Kossifidis		beacon_reg |= AR5K_BCR_AP;
8429320b5c4a7260d9593102f378201d17e3f030739Nick Kossifidis		if (ah->ah_version == AR5K_AR5210)
8439320b5c4a7260d9593102f378201d17e3f030739Nick Kossifidis			pcu_reg |= AR5K_STA_ID1_NO_PSPOLL;
8449320b5c4a7260d9593102f378201d17e3f030739Nick Kossifidis		else
8459320b5c4a7260d9593102f378201d17e3f030739Nick Kossifidis			AR5K_REG_DISABLE_BITS(ah, AR5K_CFG, AR5K_CFG_IBSS);
8469320b5c4a7260d9593102f378201d17e3f030739Nick Kossifidis		break;
8479320b5c4a7260d9593102f378201d17e3f030739Nick Kossifidis
8489320b5c4a7260d9593102f378201d17e3f030739Nick Kossifidis	case NL80211_IFTYPE_STATION:
8499320b5c4a7260d9593102f378201d17e3f030739Nick Kossifidis		pcu_reg |= AR5K_STA_ID1_KEYSRCH_MODE
8509320b5c4a7260d9593102f378201d17e3f030739Nick Kossifidis			| (ah->ah_version == AR5K_AR5210 ?
8519320b5c4a7260d9593102f378201d17e3f030739Nick Kossifidis				AR5K_STA_ID1_PWR_SV : 0);
8529320b5c4a7260d9593102f378201d17e3f030739Nick Kossifidis	case NL80211_IFTYPE_MONITOR:
8539320b5c4a7260d9593102f378201d17e3f030739Nick Kossifidis		pcu_reg |= AR5K_STA_ID1_KEYSRCH_MODE
8549320b5c4a7260d9593102f378201d17e3f030739Nick Kossifidis			| (ah->ah_version == AR5K_AR5210 ?
8559320b5c4a7260d9593102f378201d17e3f030739Nick Kossifidis				AR5K_STA_ID1_NO_PSPOLL : 0);
8569320b5c4a7260d9593102f378201d17e3f030739Nick Kossifidis		break;
8579320b5c4a7260d9593102f378201d17e3f030739Nick Kossifidis
8589320b5c4a7260d9593102f378201d17e3f030739Nick Kossifidis	default:
8599320b5c4a7260d9593102f378201d17e3f030739Nick Kossifidis		return -EINVAL;
8609320b5c4a7260d9593102f378201d17e3f030739Nick Kossifidis	}
8619320b5c4a7260d9593102f378201d17e3f030739Nick Kossifidis
8629320b5c4a7260d9593102f378201d17e3f030739Nick Kossifidis	/*
8639320b5c4a7260d9593102f378201d17e3f030739Nick Kossifidis	 * Set PCU registers
8649320b5c4a7260d9593102f378201d17e3f030739Nick Kossifidis	 */
8659320b5c4a7260d9593102f378201d17e3f030739Nick Kossifidis	low_id = get_unaligned_le32(common->macaddr);
8669320b5c4a7260d9593102f378201d17e3f030739Nick Kossifidis	high_id = get_unaligned_le16(common->macaddr + 4);
8679320b5c4a7260d9593102f378201d17e3f030739Nick Kossifidis	ath5k_hw_reg_write(ah, low_id, AR5K_STA_ID0);
8689320b5c4a7260d9593102f378201d17e3f030739Nick Kossifidis	ath5k_hw_reg_write(ah, pcu_reg | high_id, AR5K_STA_ID1);
8699320b5c4a7260d9593102f378201d17e3f030739Nick Kossifidis
8709320b5c4a7260d9593102f378201d17e3f030739Nick Kossifidis	/*
8719320b5c4a7260d9593102f378201d17e3f030739Nick Kossifidis	 * Set Beacon Control Register on 5210
8729320b5c4a7260d9593102f378201d17e3f030739Nick Kossifidis	 */
8739320b5c4a7260d9593102f378201d17e3f030739Nick Kossifidis	if (ah->ah_version == AR5K_AR5210)
8749320b5c4a7260d9593102f378201d17e3f030739Nick Kossifidis		ath5k_hw_reg_write(ah, beacon_reg, AR5K_BCR);
8759320b5c4a7260d9593102f378201d17e3f030739Nick Kossifidis
8769320b5c4a7260d9593102f378201d17e3f030739Nick Kossifidis	return 0;
8779320b5c4a7260d9593102f378201d17e3f030739Nick Kossifidis}
8789320b5c4a7260d9593102f378201d17e3f030739Nick Kossifidis
8799320b5c4a7260d9593102f378201d17e3f030739Nick Kossifidisvoid ath5k_hw_pcu_init(struct ath5k_hw *ah, enum nl80211_iftype op_mode,
8809320b5c4a7260d9593102f378201d17e3f030739Nick Kossifidis								u8 mode)
8819320b5c4a7260d9593102f378201d17e3f030739Nick Kossifidis{
8829320b5c4a7260d9593102f378201d17e3f030739Nick Kossifidis	/* Set bssid and bssid mask */
8839320b5c4a7260d9593102f378201d17e3f030739Nick Kossifidis	ath5k_hw_set_bssid(ah);
8849320b5c4a7260d9593102f378201d17e3f030739Nick Kossifidis
8859320b5c4a7260d9593102f378201d17e3f030739Nick Kossifidis	/* Set PCU config */
8869320b5c4a7260d9593102f378201d17e3f030739Nick Kossifidis	ath5k_hw_set_opmode(ah, op_mode);
8879320b5c4a7260d9593102f378201d17e3f030739Nick Kossifidis
8889320b5c4a7260d9593102f378201d17e3f030739Nick Kossifidis	/* Write rate duration table only on AR5212 and if
8899320b5c4a7260d9593102f378201d17e3f030739Nick Kossifidis	 * virtual interface has already been brought up
8909320b5c4a7260d9593102f378201d17e3f030739Nick Kossifidis	 * XXX: rethink this after new mode changes to
8919320b5c4a7260d9593102f378201d17e3f030739Nick Kossifidis	 * mac80211 are integrated */
8929320b5c4a7260d9593102f378201d17e3f030739Nick Kossifidis	if (ah->ah_version == AR5K_AR5212 &&
8939320b5c4a7260d9593102f378201d17e3f030739Nick Kossifidis		ah->ah_sc->nvifs)
89461cde037234c4b8e6497a23f5f236c64cbf9d41dNick Kossifidis		ath5k_hw_write_rate_duration(ah);
8959320b5c4a7260d9593102f378201d17e3f030739Nick Kossifidis
8969320b5c4a7260d9593102f378201d17e3f030739Nick Kossifidis	/* Set RSSI/BRSSI thresholds
8979320b5c4a7260d9593102f378201d17e3f030739Nick Kossifidis	 *
8989320b5c4a7260d9593102f378201d17e3f030739Nick Kossifidis	 * Note: If we decide to set this value
8999320b5c4a7260d9593102f378201d17e3f030739Nick Kossifidis	 * dynamicaly, have in mind that when AR5K_RSSI_THR
9009320b5c4a7260d9593102f378201d17e3f030739Nick Kossifidis	 * register is read it might return 0x40 if we haven't
9019320b5c4a7260d9593102f378201d17e3f030739Nick Kossifidis	 * wrote anything to it plus BMISS RSSI threshold is zeroed.
9029320b5c4a7260d9593102f378201d17e3f030739Nick Kossifidis	 * So doing a save/restore procedure here isn't the right
9039320b5c4a7260d9593102f378201d17e3f030739Nick Kossifidis	 * choice. Instead store it on ath5k_hw */
9049320b5c4a7260d9593102f378201d17e3f030739Nick Kossifidis	ath5k_hw_reg_write(ah, (AR5K_TUNE_RSSI_THRES |
9059320b5c4a7260d9593102f378201d17e3f030739Nick Kossifidis				AR5K_TUNE_BMISS_THRES <<
9069320b5c4a7260d9593102f378201d17e3f030739Nick Kossifidis				AR5K_RSSI_THR_BMISS_S),
9079320b5c4a7260d9593102f378201d17e3f030739Nick Kossifidis				AR5K_RSSI_THR);
9089320b5c4a7260d9593102f378201d17e3f030739Nick Kossifidis
9099320b5c4a7260d9593102f378201d17e3f030739Nick Kossifidis	/* MIC QoS support */
9109320b5c4a7260d9593102f378201d17e3f030739Nick Kossifidis	if (ah->ah_mac_srev >= AR5K_SREV_AR2413) {
9119320b5c4a7260d9593102f378201d17e3f030739Nick Kossifidis		ath5k_hw_reg_write(ah, 0x000100aa, AR5K_MIC_QOS_CTL);
9129320b5c4a7260d9593102f378201d17e3f030739Nick Kossifidis		ath5k_hw_reg_write(ah, 0x00003210, AR5K_MIC_QOS_SEL);
9139320b5c4a7260d9593102f378201d17e3f030739Nick Kossifidis	}
9149320b5c4a7260d9593102f378201d17e3f030739Nick Kossifidis
9159320b5c4a7260d9593102f378201d17e3f030739Nick Kossifidis	/* QoS NOACK Policy */
9169320b5c4a7260d9593102f378201d17e3f030739Nick Kossifidis	if (ah->ah_version == AR5K_AR5212) {
9179320b5c4a7260d9593102f378201d17e3f030739Nick Kossifidis		ath5k_hw_reg_write(ah,
9189320b5c4a7260d9593102f378201d17e3f030739Nick Kossifidis			AR5K_REG_SM(2, AR5K_QOS_NOACK_2BIT_VALUES) |
9199320b5c4a7260d9593102f378201d17e3f030739Nick Kossifidis			AR5K_REG_SM(5, AR5K_QOS_NOACK_BIT_OFFSET)  |
9209320b5c4a7260d9593102f378201d17e3f030739Nick Kossifidis			AR5K_REG_SM(0, AR5K_QOS_NOACK_BYTE_OFFSET),
9219320b5c4a7260d9593102f378201d17e3f030739Nick Kossifidis			AR5K_QOS_NOACK);
9229320b5c4a7260d9593102f378201d17e3f030739Nick Kossifidis	}
9239320b5c4a7260d9593102f378201d17e3f030739Nick Kossifidis
9249320b5c4a7260d9593102f378201d17e3f030739Nick Kossifidis	/* Restore slot time and ACK timeouts */
9259320b5c4a7260d9593102f378201d17e3f030739Nick Kossifidis	if (ah->ah_coverage_class > 0)
9269320b5c4a7260d9593102f378201d17e3f030739Nick Kossifidis		ath5k_hw_set_coverage_class(ah, ah->ah_coverage_class);
9279320b5c4a7260d9593102f378201d17e3f030739Nick Kossifidis
92861cde037234c4b8e6497a23f5f236c64cbf9d41dNick Kossifidis	/* Set ACK bitrate mode (see ack_rates_high) */
92961cde037234c4b8e6497a23f5f236c64cbf9d41dNick Kossifidis	if (ah->ah_version == AR5K_AR5212) {
93061cde037234c4b8e6497a23f5f236c64cbf9d41dNick Kossifidis		u32 val = AR5K_STA_ID1_BASE_RATE_11B | AR5K_STA_ID1_ACKCTS_6MB;
93161cde037234c4b8e6497a23f5f236c64cbf9d41dNick Kossifidis		if (ah->ah_ack_bitrate_high)
93261cde037234c4b8e6497a23f5f236c64cbf9d41dNick Kossifidis			AR5K_REG_DISABLE_BITS(ah, AR5K_STA_ID1, val);
93361cde037234c4b8e6497a23f5f236c64cbf9d41dNick Kossifidis		else
93461cde037234c4b8e6497a23f5f236c64cbf9d41dNick Kossifidis			AR5K_REG_ENABLE_BITS(ah, AR5K_STA_ID1, val);
93561cde037234c4b8e6497a23f5f236c64cbf9d41dNick Kossifidis	}
9369320b5c4a7260d9593102f378201d17e3f030739Nick Kossifidis	return;
9379320b5c4a7260d9593102f378201d17e3f030739Nick Kossifidis}
938