pcu.c revision 71ba1c30851575b43ba76b0f9c26ff5567e8136c
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,
7861cde037234c4b8e6497a23f5f236c64cbf9d41dNick Kossifidis		int len, struct ieee80211_rate *rate)
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) {
8761cde037234c4b8e6497a23f5f236c64cbf9d41dNick Kossifidis		dur = ieee80211_generic_frame_duration(sc->hw,
8861cde037234c4b8e6497a23f5f236c64cbf9d41dNick Kossifidis						NULL, len, rate);
8961cde037234c4b8e6497a23f5f236c64cbf9d41dNick Kossifidis		return dur;
9061cde037234c4b8e6497a23f5f236c64cbf9d41dNick Kossifidis	}
9161cde037234c4b8e6497a23f5f236c64cbf9d41dNick Kossifidis
9261cde037234c4b8e6497a23f5f236c64cbf9d41dNick Kossifidis	bitrate = rate->bitrate;
9361cde037234c4b8e6497a23f5f236c64cbf9d41dNick Kossifidis	preamble = AR5K_INIT_OFDM_PREAMPLE_TIME;
9461cde037234c4b8e6497a23f5f236c64cbf9d41dNick Kossifidis	plcp_bits = AR5K_INIT_OFDM_PLCP_BITS;
9561cde037234c4b8e6497a23f5f236c64cbf9d41dNick Kossifidis	sym_time = AR5K_INIT_OFDM_SYMBOL_TIME;
9661cde037234c4b8e6497a23f5f236c64cbf9d41dNick Kossifidis
9761cde037234c4b8e6497a23f5f236c64cbf9d41dNick Kossifidis	switch (ah->ah_bwmode) {
9861cde037234c4b8e6497a23f5f236c64cbf9d41dNick Kossifidis	case AR5K_BWMODE_40MHZ:
9961cde037234c4b8e6497a23f5f236c64cbf9d41dNick Kossifidis		sifs = AR5K_INIT_SIFS_TURBO;
10061cde037234c4b8e6497a23f5f236c64cbf9d41dNick Kossifidis		preamble = AR5K_INIT_OFDM_PREAMBLE_TIME_MIN;
10161cde037234c4b8e6497a23f5f236c64cbf9d41dNick Kossifidis		break;
10261cde037234c4b8e6497a23f5f236c64cbf9d41dNick Kossifidis	case AR5K_BWMODE_10MHZ:
10361cde037234c4b8e6497a23f5f236c64cbf9d41dNick Kossifidis		sifs = AR5K_INIT_SIFS_HALF_RATE;
10461cde037234c4b8e6497a23f5f236c64cbf9d41dNick Kossifidis		preamble *= 2;
10561cde037234c4b8e6497a23f5f236c64cbf9d41dNick Kossifidis		sym_time *= 2;
10661cde037234c4b8e6497a23f5f236c64cbf9d41dNick Kossifidis		break;
10761cde037234c4b8e6497a23f5f236c64cbf9d41dNick Kossifidis	case AR5K_BWMODE_5MHZ:
10861cde037234c4b8e6497a23f5f236c64cbf9d41dNick Kossifidis		sifs = AR5K_INIT_SIFS_QUARTER_RATE;
10961cde037234c4b8e6497a23f5f236c64cbf9d41dNick Kossifidis		preamble *= 4;
11061cde037234c4b8e6497a23f5f236c64cbf9d41dNick Kossifidis		sym_time *= 4;
11161cde037234c4b8e6497a23f5f236c64cbf9d41dNick Kossifidis		break;
11261cde037234c4b8e6497a23f5f236c64cbf9d41dNick Kossifidis	default:
11361cde037234c4b8e6497a23f5f236c64cbf9d41dNick Kossifidis		sifs = AR5K_INIT_SIFS_DEFAULT_BG;
11461cde037234c4b8e6497a23f5f236c64cbf9d41dNick Kossifidis		break;
11561cde037234c4b8e6497a23f5f236c64cbf9d41dNick Kossifidis	}
11661cde037234c4b8e6497a23f5f236c64cbf9d41dNick Kossifidis
11761cde037234c4b8e6497a23f5f236c64cbf9d41dNick Kossifidis	bits = plcp_bits + (len << 3);
11861cde037234c4b8e6497a23f5f236c64cbf9d41dNick Kossifidis	/* Bit rate is in 100Kbits */
11961cde037234c4b8e6497a23f5f236c64cbf9d41dNick Kossifidis	symbol_bits = bitrate * sym_time;
12061cde037234c4b8e6497a23f5f236c64cbf9d41dNick Kossifidis	symbols = DIV_ROUND_UP(bits * 10, symbol_bits);
12161cde037234c4b8e6497a23f5f236c64cbf9d41dNick Kossifidis
12261cde037234c4b8e6497a23f5f236c64cbf9d41dNick Kossifidis	dur = sifs + preamble + (sym_time * symbols);
12361cde037234c4b8e6497a23f5f236c64cbf9d41dNick Kossifidis
12461cde037234c4b8e6497a23f5f236c64cbf9d41dNick Kossifidis	return dur;
12561cde037234c4b8e6497a23f5f236c64cbf9d41dNick Kossifidis}
12661cde037234c4b8e6497a23f5f236c64cbf9d41dNick Kossifidis
12761cde037234c4b8e6497a23f5f236c64cbf9d41dNick Kossifidis/**
1289320b5c4a7260d9593102f378201d17e3f030739Nick Kossifidis * ath5k_hw_get_default_slottime - Get the default slot time for current mode
129c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis *
130c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis * @ah: The &struct ath5k_hw
131c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis */
13271ba1c30851575b43ba76b0f9c26ff5567e8136cNick Kossifidisunsigned int ath5k_hw_get_default_slottime(struct ath5k_hw *ah)
133c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis{
1349320b5c4a7260d9593102f378201d17e3f030739Nick Kossifidis	struct ieee80211_channel *channel = ah->ah_current_channel;
1353017fcab416d8d1ee48ca16aa9a3062f600dab8eNick Kossifidis	unsigned int slot_time;
136c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis
1373017fcab416d8d1ee48ca16aa9a3062f600dab8eNick Kossifidis	switch (ah->ah_bwmode) {
1383017fcab416d8d1ee48ca16aa9a3062f600dab8eNick Kossifidis	case AR5K_BWMODE_40MHZ:
1393017fcab416d8d1ee48ca16aa9a3062f600dab8eNick Kossifidis		slot_time = AR5K_INIT_SLOT_TIME_TURBO;
1403017fcab416d8d1ee48ca16aa9a3062f600dab8eNick Kossifidis		break;
1413017fcab416d8d1ee48ca16aa9a3062f600dab8eNick Kossifidis	case AR5K_BWMODE_10MHZ:
1423017fcab416d8d1ee48ca16aa9a3062f600dab8eNick Kossifidis		slot_time = AR5K_INIT_SLOT_TIME_HALF_RATE;
1433017fcab416d8d1ee48ca16aa9a3062f600dab8eNick Kossifidis		break;
1443017fcab416d8d1ee48ca16aa9a3062f600dab8eNick Kossifidis	case AR5K_BWMODE_5MHZ:
1453017fcab416d8d1ee48ca16aa9a3062f600dab8eNick Kossifidis		slot_time = AR5K_INIT_SLOT_TIME_QUARTER_RATE;
1463017fcab416d8d1ee48ca16aa9a3062f600dab8eNick Kossifidis		break;
1473017fcab416d8d1ee48ca16aa9a3062f600dab8eNick Kossifidis	case AR5K_BWMODE_DEFAULT:
1483017fcab416d8d1ee48ca16aa9a3062f600dab8eNick Kossifidis		slot_time = AR5K_INIT_SLOT_TIME_DEFAULT;
1493017fcab416d8d1ee48ca16aa9a3062f600dab8eNick Kossifidis	default:
1503017fcab416d8d1ee48ca16aa9a3062f600dab8eNick Kossifidis		if (channel->hw_value & CHANNEL_CCK)
1513017fcab416d8d1ee48ca16aa9a3062f600dab8eNick Kossifidis			slot_time = AR5K_INIT_SLOT_TIME_B;
1523017fcab416d8d1ee48ca16aa9a3062f600dab8eNick Kossifidis		break;
1533017fcab416d8d1ee48ca16aa9a3062f600dab8eNick Kossifidis	}
154c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis
1553017fcab416d8d1ee48ca16aa9a3062f600dab8eNick Kossifidis	return slot_time;
1569320b5c4a7260d9593102f378201d17e3f030739Nick Kossifidis}
157c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis
1589320b5c4a7260d9593102f378201d17e3f030739Nick Kossifidis/**
1599320b5c4a7260d9593102f378201d17e3f030739Nick Kossifidis * ath5k_hw_get_default_sifs - Get the default SIFS for current mode
1609320b5c4a7260d9593102f378201d17e3f030739Nick Kossifidis *
1619320b5c4a7260d9593102f378201d17e3f030739Nick Kossifidis * @ah: The &struct ath5k_hw
1629320b5c4a7260d9593102f378201d17e3f030739Nick Kossifidis */
1633017fcab416d8d1ee48ca16aa9a3062f600dab8eNick Kossifidisunsigned int ath5k_hw_get_default_sifs(struct ath5k_hw *ah)
1649320b5c4a7260d9593102f378201d17e3f030739Nick Kossifidis{
1659320b5c4a7260d9593102f378201d17e3f030739Nick Kossifidis	struct ieee80211_channel *channel = ah->ah_current_channel;
1663017fcab416d8d1ee48ca16aa9a3062f600dab8eNick Kossifidis	unsigned int sifs;
167c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis
1683017fcab416d8d1ee48ca16aa9a3062f600dab8eNick Kossifidis	switch (ah->ah_bwmode) {
1693017fcab416d8d1ee48ca16aa9a3062f600dab8eNick Kossifidis	case AR5K_BWMODE_40MHZ:
1703017fcab416d8d1ee48ca16aa9a3062f600dab8eNick Kossifidis		sifs = AR5K_INIT_SIFS_TURBO;
1713017fcab416d8d1ee48ca16aa9a3062f600dab8eNick Kossifidis		break;
1723017fcab416d8d1ee48ca16aa9a3062f600dab8eNick Kossifidis	case AR5K_BWMODE_10MHZ:
1733017fcab416d8d1ee48ca16aa9a3062f600dab8eNick Kossifidis		sifs = AR5K_INIT_SIFS_HALF_RATE;
1743017fcab416d8d1ee48ca16aa9a3062f600dab8eNick Kossifidis		break;
1753017fcab416d8d1ee48ca16aa9a3062f600dab8eNick Kossifidis	case AR5K_BWMODE_5MHZ:
1763017fcab416d8d1ee48ca16aa9a3062f600dab8eNick Kossifidis		sifs = AR5K_INIT_SIFS_QUARTER_RATE;
1773017fcab416d8d1ee48ca16aa9a3062f600dab8eNick Kossifidis		break;
1783017fcab416d8d1ee48ca16aa9a3062f600dab8eNick Kossifidis	case AR5K_BWMODE_DEFAULT:
1793017fcab416d8d1ee48ca16aa9a3062f600dab8eNick Kossifidis		sifs = AR5K_INIT_SIFS_DEFAULT_BG;
1803017fcab416d8d1ee48ca16aa9a3062f600dab8eNick Kossifidis	default:
1813017fcab416d8d1ee48ca16aa9a3062f600dab8eNick Kossifidis		if (channel->hw_value & CHANNEL_5GHZ)
1823017fcab416d8d1ee48ca16aa9a3062f600dab8eNick Kossifidis			sifs = AR5K_INIT_SIFS_DEFAULT_A;
1833017fcab416d8d1ee48ca16aa9a3062f600dab8eNick Kossifidis		break;
1843017fcab416d8d1ee48ca16aa9a3062f600dab8eNick Kossifidis	}
185c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis
1863017fcab416d8d1ee48ca16aa9a3062f600dab8eNick Kossifidis	return sifs;
187c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis}
188c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis
189c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis/**
1909320b5c4a7260d9593102f378201d17e3f030739Nick Kossifidis * ath5k_hw_update_mib_counters - Update MIB counters (mac layer statistics)
191c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis *
192c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis * @ah: The &struct ath5k_hw
193c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis *
194495391d715a310a7cbf622850e372d40ac86ef6eBruno Randolf * Reads MIB counters from PCU and updates sw statistics. Is called after a
195495391d715a310a7cbf622850e372d40ac86ef6eBruno Randolf * MIB interrupt, because one of these counters might have reached their maximum
196495391d715a310a7cbf622850e372d40ac86ef6eBruno Randolf * and triggered the MIB interrupt, to let us read and clear the counter.
197495391d715a310a7cbf622850e372d40ac86ef6eBruno Randolf *
198495391d715a310a7cbf622850e372d40ac86ef6eBruno Randolf * Is called in interrupt context!
199c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis */
200495391d715a310a7cbf622850e372d40ac86ef6eBruno Randolfvoid ath5k_hw_update_mib_counters(struct ath5k_hw *ah)
201c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis{
202495391d715a310a7cbf622850e372d40ac86ef6eBruno Randolf	struct ath5k_statistics *stats = &ah->ah_sc->stats;
203c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis
204c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis	/* Read-And-Clear */
205495391d715a310a7cbf622850e372d40ac86ef6eBruno Randolf	stats->ack_fail += ath5k_hw_reg_read(ah, AR5K_ACK_FAIL);
206495391d715a310a7cbf622850e372d40ac86ef6eBruno Randolf	stats->rts_fail += ath5k_hw_reg_read(ah, AR5K_RTS_FAIL);
207495391d715a310a7cbf622850e372d40ac86ef6eBruno Randolf	stats->rts_ok += ath5k_hw_reg_read(ah, AR5K_RTS_OK);
208495391d715a310a7cbf622850e372d40ac86ef6eBruno Randolf	stats->fcs_error += ath5k_hw_reg_read(ah, AR5K_FCS_FAIL);
209495391d715a310a7cbf622850e372d40ac86ef6eBruno Randolf	stats->beacons += ath5k_hw_reg_read(ah, AR5K_BEACON_CNT);
210c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis}
211c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis
212c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis
213c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis/******************\
214c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis* ACK/CTS Timeouts *
215c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis\******************/
216c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis
2179320b5c4a7260d9593102f378201d17e3f030739Nick Kossifidis/**
2189320b5c4a7260d9593102f378201d17e3f030739Nick Kossifidis * ath5k_hw_write_rate_duration - fill rate code to duration table
2199320b5c4a7260d9593102f378201d17e3f030739Nick Kossifidis *
2209320b5c4a7260d9593102f378201d17e3f030739Nick Kossifidis * @ah: the &struct ath5k_hw
2219320b5c4a7260d9593102f378201d17e3f030739Nick Kossifidis * @mode: one of enum ath5k_driver_mode
2229320b5c4a7260d9593102f378201d17e3f030739Nick Kossifidis *
2239320b5c4a7260d9593102f378201d17e3f030739Nick Kossifidis * Write the rate code to duration table upon hw reset. This is a helper for
22461cde037234c4b8e6497a23f5f236c64cbf9d41dNick Kossifidis * ath5k_hw_pcu_init(). It seems all this is doing is setting an ACK timeout on
2259320b5c4a7260d9593102f378201d17e3f030739Nick Kossifidis * the hardware, based on current mode, for each rate. The rates which are
2269320b5c4a7260d9593102f378201d17e3f030739Nick Kossifidis * capable of short preamble (802.11b rates 2Mbps, 5.5Mbps, and 11Mbps) have
2279320b5c4a7260d9593102f378201d17e3f030739Nick Kossifidis * different rate code so we write their value twice (one for long preamble
2289320b5c4a7260d9593102f378201d17e3f030739Nick Kossifidis * and one for short).
2299320b5c4a7260d9593102f378201d17e3f030739Nick Kossifidis *
2309320b5c4a7260d9593102f378201d17e3f030739Nick Kossifidis * Note: Band doesn't matter here, if we set the values for OFDM it works
2319320b5c4a7260d9593102f378201d17e3f030739Nick Kossifidis * on both a and g modes. So all we have to do is set values for all g rates
23261cde037234c4b8e6497a23f5f236c64cbf9d41dNick Kossifidis * that include all OFDM and CCK rates.
23361cde037234c4b8e6497a23f5f236c64cbf9d41dNick Kossifidis *
2349320b5c4a7260d9593102f378201d17e3f030739Nick Kossifidis */
23561cde037234c4b8e6497a23f5f236c64cbf9d41dNick Kossifidisstatic inline void ath5k_hw_write_rate_duration(struct ath5k_hw *ah)
2369320b5c4a7260d9593102f378201d17e3f030739Nick Kossifidis{
2379320b5c4a7260d9593102f378201d17e3f030739Nick Kossifidis	struct ath5k_softc *sc = ah->ah_sc;
2389320b5c4a7260d9593102f378201d17e3f030739Nick Kossifidis	struct ieee80211_rate *rate;
2399320b5c4a7260d9593102f378201d17e3f030739Nick Kossifidis	unsigned int i;
24061cde037234c4b8e6497a23f5f236c64cbf9d41dNick Kossifidis	/* 802.11g covers both OFDM and CCK */
24161cde037234c4b8e6497a23f5f236c64cbf9d41dNick Kossifidis	u8 band = IEEE80211_BAND_2GHZ;
2429320b5c4a7260d9593102f378201d17e3f030739Nick Kossifidis
2439320b5c4a7260d9593102f378201d17e3f030739Nick Kossifidis	/* Write rate duration table */
24461cde037234c4b8e6497a23f5f236c64cbf9d41dNick Kossifidis	for (i = 0; i < sc->sbands[band].n_bitrates; i++) {
2459320b5c4a7260d9593102f378201d17e3f030739Nick Kossifidis		u32 reg;
2469320b5c4a7260d9593102f378201d17e3f030739Nick Kossifidis		u16 tx_time;
2479320b5c4a7260d9593102f378201d17e3f030739Nick Kossifidis
24861cde037234c4b8e6497a23f5f236c64cbf9d41dNick Kossifidis		if (ah->ah_ack_bitrate_high)
24961cde037234c4b8e6497a23f5f236c64cbf9d41dNick Kossifidis			rate = &sc->sbands[band].bitrates[ack_rates_high[i]];
25061cde037234c4b8e6497a23f5f236c64cbf9d41dNick Kossifidis		/* CCK -> 1Mb */
25161cde037234c4b8e6497a23f5f236c64cbf9d41dNick Kossifidis		else if (i < 4)
25261cde037234c4b8e6497a23f5f236c64cbf9d41dNick Kossifidis			rate = &sc->sbands[band].bitrates[0];
25361cde037234c4b8e6497a23f5f236c64cbf9d41dNick Kossifidis		/* OFDM -> 6Mb */
25461cde037234c4b8e6497a23f5f236c64cbf9d41dNick Kossifidis		else
25561cde037234c4b8e6497a23f5f236c64cbf9d41dNick Kossifidis			rate = &sc->sbands[band].bitrates[4];
2569320b5c4a7260d9593102f378201d17e3f030739Nick Kossifidis
2579320b5c4a7260d9593102f378201d17e3f030739Nick Kossifidis		/* Set ACK timeout */
2589320b5c4a7260d9593102f378201d17e3f030739Nick Kossifidis		reg = AR5K_RATE_DUR(rate->hw_value);
2599320b5c4a7260d9593102f378201d17e3f030739Nick Kossifidis
2609320b5c4a7260d9593102f378201d17e3f030739Nick Kossifidis		/* An ACK frame consists of 10 bytes. If you add the FCS,
2619320b5c4a7260d9593102f378201d17e3f030739Nick Kossifidis		 * which ieee80211_generic_frame_duration() adds,
2629320b5c4a7260d9593102f378201d17e3f030739Nick Kossifidis		 * its 14 bytes. Note we use the control rate and not the
2639320b5c4a7260d9593102f378201d17e3f030739Nick Kossifidis		 * actual rate for this rate. See mac80211 tx.c
2649320b5c4a7260d9593102f378201d17e3f030739Nick Kossifidis		 * ieee80211_duration() for a brief description of
2659320b5c4a7260d9593102f378201d17e3f030739Nick Kossifidis		 * what rate we should choose to TX ACKs. */
26661cde037234c4b8e6497a23f5f236c64cbf9d41dNick Kossifidis		tx_time = ath5k_hw_get_frame_duration(ah, 10, rate);
26761cde037234c4b8e6497a23f5f236c64cbf9d41dNick Kossifidis
26861cde037234c4b8e6497a23f5f236c64cbf9d41dNick Kossifidis		tx_time = le16_to_cpu(tx_time);
2699320b5c4a7260d9593102f378201d17e3f030739Nick Kossifidis
2709320b5c4a7260d9593102f378201d17e3f030739Nick Kossifidis		ath5k_hw_reg_write(ah, tx_time, reg);
2719320b5c4a7260d9593102f378201d17e3f030739Nick Kossifidis
2729320b5c4a7260d9593102f378201d17e3f030739Nick Kossifidis		if (!(rate->flags & IEEE80211_RATE_SHORT_PREAMBLE))
2739320b5c4a7260d9593102f378201d17e3f030739Nick Kossifidis			continue;
2749320b5c4a7260d9593102f378201d17e3f030739Nick Kossifidis
2759320b5c4a7260d9593102f378201d17e3f030739Nick Kossifidis		/*
2769320b5c4a7260d9593102f378201d17e3f030739Nick Kossifidis		 * We're not distinguishing short preamble here,
2779320b5c4a7260d9593102f378201d17e3f030739Nick Kossifidis		 * This is true, all we'll get is a longer value here
2789320b5c4a7260d9593102f378201d17e3f030739Nick Kossifidis		 * which is not necessarilly bad. We could use
2799320b5c4a7260d9593102f378201d17e3f030739Nick Kossifidis		 * export ieee80211_frame_duration() but that needs to be
2809320b5c4a7260d9593102f378201d17e3f030739Nick Kossifidis		 * fixed first to be properly used by mac802111 drivers:
2819320b5c4a7260d9593102f378201d17e3f030739Nick Kossifidis		 *
2829320b5c4a7260d9593102f378201d17e3f030739Nick Kossifidis		 *  - remove erp stuff and let the routine figure ofdm
2839320b5c4a7260d9593102f378201d17e3f030739Nick Kossifidis		 *    erp rates
2849320b5c4a7260d9593102f378201d17e3f030739Nick Kossifidis		 *  - remove passing argument ieee80211_local as
2859320b5c4a7260d9593102f378201d17e3f030739Nick Kossifidis		 *    drivers don't have access to it
2869320b5c4a7260d9593102f378201d17e3f030739Nick Kossifidis		 *  - move drivers using ieee80211_generic_frame_duration()
2879320b5c4a7260d9593102f378201d17e3f030739Nick Kossifidis		 *    to this
2889320b5c4a7260d9593102f378201d17e3f030739Nick Kossifidis		 */
2899320b5c4a7260d9593102f378201d17e3f030739Nick Kossifidis		ath5k_hw_reg_write(ah, tx_time,
2909320b5c4a7260d9593102f378201d17e3f030739Nick Kossifidis			reg + (AR5K_SET_SHORT_PREAMBLE << 2));
2919320b5c4a7260d9593102f378201d17e3f030739Nick Kossifidis	}
2929320b5c4a7260d9593102f378201d17e3f030739Nick Kossifidis}
2939320b5c4a7260d9593102f378201d17e3f030739Nick Kossifidis
294c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis/**
295c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis * ath5k_hw_set_ack_timeout - Set ACK timeout on PCU
296c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis *
297c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis * @ah: The &struct ath5k_hw
298c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis * @timeout: Timeout in usec
299c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis */
300626ede6b1aafb3a8cadfdd04b512fd1d3dc2113ePavel Roskinstatic int ath5k_hw_set_ack_timeout(struct ath5k_hw *ah, unsigned int timeout)
301c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis{
3023578e6ebb305e6bf7519f6e86741772892f4d51aLukáš Turek	if (ath5k_hw_clocktoh(ah, AR5K_REG_MS(0xffffffff, AR5K_TIME_OUT_ACK))
3033578e6ebb305e6bf7519f6e86741772892f4d51aLukáš Turek			<= timeout)
304c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis		return -EINVAL;
305c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis
306c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis	AR5K_REG_WRITE_BITS(ah, AR5K_TIME_OUT, AR5K_TIME_OUT_ACK,
3073578e6ebb305e6bf7519f6e86741772892f4d51aLukáš Turek		ath5k_hw_htoclock(ah, timeout));
308c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis
309c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis	return 0;
310c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis}
311c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis
312c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis/**
313c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis * ath5k_hw_set_cts_timeout - Set CTS timeout on PCU
314c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis *
315c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis * @ah: The &struct ath5k_hw
316c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis * @timeout: Timeout in usec
317c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis */
318626ede6b1aafb3a8cadfdd04b512fd1d3dc2113ePavel Roskinstatic int ath5k_hw_set_cts_timeout(struct ath5k_hw *ah, unsigned int timeout)
319c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis{
3203578e6ebb305e6bf7519f6e86741772892f4d51aLukáš Turek	if (ath5k_hw_clocktoh(ah, AR5K_REG_MS(0xffffffff, AR5K_TIME_OUT_CTS))
3213578e6ebb305e6bf7519f6e86741772892f4d51aLukáš Turek			<= timeout)
322c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis		return -EINVAL;
323c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis
324c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis	AR5K_REG_WRITE_BITS(ah, AR5K_TIME_OUT, AR5K_TIME_OUT_CTS,
3253578e6ebb305e6bf7519f6e86741772892f4d51aLukáš Turek			ath5k_hw_htoclock(ah, timeout));
326c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis
327c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis	return 0;
328c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis}
329c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis
3306e08d228b6d8e93d7b25b3573c6da7da179c2ae1Lukáš Turek
3319320b5c4a7260d9593102f378201d17e3f030739Nick Kossifidis/*******************\
3329320b5c4a7260d9593102f378201d17e3f030739Nick Kossifidis* RX filter Control *
3339320b5c4a7260d9593102f378201d17e3f030739Nick Kossifidis\*******************/
3346e08d228b6d8e93d7b25b3573c6da7da179c2ae1Lukáš Turek
3356e08d228b6d8e93d7b25b3573c6da7da179c2ae1Lukáš Turek/**
336c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis * ath5k_hw_set_lladdr - Set station id
337c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis *
338c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis * @ah: The &struct ath5k_hw
339c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis * @mac: The card's mac address
340c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis *
341c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis * Set station id on hw using the provided mac address
342c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis */
343c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidisint ath5k_hw_set_lladdr(struct ath5k_hw *ah, const u8 *mac)
344c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis{
345954fecea5d1df4d1dc7bf9a822a2fad308e8588eLuis R. Rodriguez	struct ath_common *common = ath5k_hw_common(ah);
346c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis	u32 low_id, high_id;
347f6bac3ea5990653765700b2c3778b08782abebe5Bob Copeland	u32 pcu_reg;
348c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis
349c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis	/* Set new station ID */
350954fecea5d1df4d1dc7bf9a822a2fad308e8588eLuis R. Rodriguez	memcpy(common->macaddr, mac, ETH_ALEN);
351c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis
352f6bac3ea5990653765700b2c3778b08782abebe5Bob Copeland	pcu_reg = ath5k_hw_reg_read(ah, AR5K_STA_ID1) & 0xffff0000;
353f6bac3ea5990653765700b2c3778b08782abebe5Bob Copeland
354bcd8f54a84ce99ade91c250a9bc850a9fd3389c1Luis R. Rodriguez	low_id = get_unaligned_le32(mac);
355bcd8f54a84ce99ade91c250a9bc850a9fd3389c1Luis R. Rodriguez	high_id = get_unaligned_le16(mac + 4);
356c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis
357c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis	ath5k_hw_reg_write(ah, low_id, AR5K_STA_ID0);
358f6bac3ea5990653765700b2c3778b08782abebe5Bob Copeland	ath5k_hw_reg_write(ah, pcu_reg | high_id, AR5K_STA_ID1);
359c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis
360c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis	return 0;
361c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis}
362c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis
363c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis/**
364418de6d955fa1da0cb4332661a31d21f57e954abNick Kossifidis * ath5k_hw_set_bssid - Set current BSSID on hw
365c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis *
366c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis * @ah: The &struct ath5k_hw
367c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis *
368418de6d955fa1da0cb4332661a31d21f57e954abNick Kossifidis * Sets the current BSSID and BSSID mask we have from the
369418de6d955fa1da0cb4332661a31d21f57e954abNick Kossifidis * common struct into the hardware
370c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis */
371418de6d955fa1da0cb4332661a31d21f57e954abNick Kossifidisvoid ath5k_hw_set_bssid(struct ath5k_hw *ah)
372c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis{
373954fecea5d1df4d1dc7bf9a822a2fad308e8588eLuis R. Rodriguez	struct ath_common *common = ath5k_hw_common(ah);
374c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis	u16 tim_offset = 0;
375c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis
376c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis	/*
377418de6d955fa1da0cb4332661a31d21f57e954abNick Kossifidis	 * Set BSSID mask on 5212
378c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis	 */
379a72d57a862f700edf85da81aae3cd8f923e989a1Luis R. Rodriguez	if (ah->ah_version == AR5K_AR5212)
380a72d57a862f700edf85da81aae3cd8f923e989a1Luis R. Rodriguez		ath_hw_setbssidmask(common);
381c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis
382c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis	/*
383418de6d955fa1da0cb4332661a31d21f57e954abNick Kossifidis	 * Set BSSID
384c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis	 */
385abba06869e2546484fa142528737d1a0622add54Luis R. Rodriguez	ath5k_hw_reg_write(ah,
386abba06869e2546484fa142528737d1a0622add54Luis R. Rodriguez			   get_unaligned_le32(common->curbssid),
387a3f86bff1c056f47c2df4c58bfcf7bdda8eaf9d0Luis R. Rodriguez			   AR5K_BSS_ID0);
388abba06869e2546484fa142528737d1a0622add54Luis R. Rodriguez	ath5k_hw_reg_write(ah,
389abba06869e2546484fa142528737d1a0622add54Luis R. Rodriguez			   get_unaligned_le16(common->curbssid + 4) |
390abba06869e2546484fa142528737d1a0622add54Luis R. Rodriguez			   ((common->curaid & 0x3fff) << AR5K_BSS_ID1_AID_S),
391a3f86bff1c056f47c2df4c58bfcf7bdda8eaf9d0Luis R. Rodriguez			   AR5K_BSS_ID1);
392c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis
393be5d6b75e0fb3f7e23ea5325109ef4195f2b282aLuis R. Rodriguez	if (common->curaid == 0) {
394c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis		ath5k_hw_disable_pspoll(ah);
395c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis		return;
396c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis	}
397c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis
398c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis	AR5K_REG_WRITE_BITS(ah, AR5K_BEACON, AR5K_BEACON_TIM,
399abba06869e2546484fa142528737d1a0622add54Luis R. Rodriguez			    tim_offset ? tim_offset + 4 : 0);
400c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis
401c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis	ath5k_hw_enable_pspoll(ah, NULL, 0);
402c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis}
403c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis
40413b81559200b8e54473e5b140323cbb5f2bb21c0Luis R. Rodriguezvoid ath5k_hw_set_bssid_mask(struct ath5k_hw *ah, const u8 *mask)
405c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis{
406954fecea5d1df4d1dc7bf9a822a2fad308e8588eLuis R. Rodriguez	struct ath_common *common = ath5k_hw_common(ah);
407c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis
408f07a6c495e88ae0143e3c20b1ed666314197277fNick Kossifidis	/* Cache bssid mask so that we can restore it
409f07a6c495e88ae0143e3c20b1ed666314197277fNick Kossifidis	 * on reset */
410954fecea5d1df4d1dc7bf9a822a2fad308e8588eLuis R. Rodriguez	memcpy(common->bssidmask, mask, ETH_ALEN);
41113b81559200b8e54473e5b140323cbb5f2bb21c0Luis R. Rodriguez	if (ah->ah_version == AR5K_AR5212)
41213b81559200b8e54473e5b140323cbb5f2bb21c0Luis R. Rodriguez		ath_hw_setbssidmask(common);
413c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis}
414c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis
415c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis/*
416c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis * Set multicast filter
417c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis */
418c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidisvoid ath5k_hw_set_mcast_filter(struct ath5k_hw *ah, u32 filter0, u32 filter1)
419c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis{
420c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis	ath5k_hw_reg_write(ah, filter0, AR5K_MCAST_FILTER0);
421c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis	ath5k_hw_reg_write(ah, filter1, AR5K_MCAST_FILTER1);
422c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis}
423c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis
424c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis/**
425c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis * ath5k_hw_get_rx_filter - Get current rx filter
426c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis *
427c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis * @ah: The &struct ath5k_hw
428c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis *
429c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis * Returns the RX filter by reading rx filter and
430c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis * phy error filter registers. RX filter is used
431c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis * to set the allowed frame types that PCU will accept
432c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis * and pass to the driver. For a list of frame types
433c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis * check out reg.h.
434c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis */
435c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidisu32 ath5k_hw_get_rx_filter(struct ath5k_hw *ah)
436c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis{
437c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis	u32 data, filter = 0;
438c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis
439c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis	filter = ath5k_hw_reg_read(ah, AR5K_RX_FILTER);
440c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis
441c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis	/*Radar detection for 5212*/
442c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis	if (ah->ah_version == AR5K_AR5212) {
443c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis		data = ath5k_hw_reg_read(ah, AR5K_PHY_ERR_FIL);
444c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis
445c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis		if (data & AR5K_PHY_ERR_FIL_RADAR)
446c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis			filter |= AR5K_RX_FILTER_RADARERR;
447c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis		if (data & (AR5K_PHY_ERR_FIL_OFDM | AR5K_PHY_ERR_FIL_CCK))
448c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis			filter |= AR5K_RX_FILTER_PHYERR;
449c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis	}
450c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis
451c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis	return filter;
452c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis}
453c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis
454c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis/**
455c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis * ath5k_hw_set_rx_filter - Set rx filter
456c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis *
457c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis * @ah: The &struct ath5k_hw
458c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis * @filter: RX filter mask (see reg.h)
459c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis *
460c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis * Sets RX filter register and also handles PHY error filter
461c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis * register on 5212 and newer chips so that we have proper PHY
462c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis * error reporting.
463c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis */
464c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidisvoid ath5k_hw_set_rx_filter(struct ath5k_hw *ah, u32 filter)
465c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis{
466c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis	u32 data = 0;
467c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis
468c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis	/* Set PHY error filter register on 5212*/
469c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis	if (ah->ah_version == AR5K_AR5212) {
470c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis		if (filter & AR5K_RX_FILTER_RADARERR)
471c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis			data |= AR5K_PHY_ERR_FIL_RADAR;
472c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis		if (filter & AR5K_RX_FILTER_PHYERR)
473c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis			data |= AR5K_PHY_ERR_FIL_OFDM | AR5K_PHY_ERR_FIL_CCK;
474c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis	}
475c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis
476c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis	/*
477c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis	 * The AR5210 uses promiscous mode to detect radar activity
478c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis	 */
479c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis	if (ah->ah_version == AR5K_AR5210 &&
480c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis			(filter & AR5K_RX_FILTER_RADARERR)) {
481c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis		filter &= ~AR5K_RX_FILTER_RADARERR;
482c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis		filter |= AR5K_RX_FILTER_PROM;
483c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis	}
484c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis
485f07a6c495e88ae0143e3c20b1ed666314197277fNick Kossifidis	/*Zero length DMA (phy error reporting) */
486c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis	if (data)
487c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis		AR5K_REG_ENABLE_BITS(ah, AR5K_RXCFG, AR5K_RXCFG_ZLFDMA);
488c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis	else
489c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis		AR5K_REG_DISABLE_BITS(ah, AR5K_RXCFG, AR5K_RXCFG_ZLFDMA);
490c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis
491c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis	/*Write RX Filter register*/
492c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis	ath5k_hw_reg_write(ah, filter & 0xff, AR5K_RX_FILTER);
493c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis
494c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis	/*Write PHY error filter register on 5212*/
495c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis	if (ah->ah_version == AR5K_AR5212)
496c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis		ath5k_hw_reg_write(ah, data, AR5K_PHY_ERR_FIL);
497c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis
498c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis}
499c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis
500c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis
501c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis/****************\
502c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis* Beacon control *
503c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis\****************/
504c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis
5051c0fc65e6de4e941ff483df445e721d6edb1f84bBenoit Papillault#define ATH5K_MAX_TSF_READ 10
5061c0fc65e6de4e941ff483df445e721d6edb1f84bBenoit Papillault
507c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis/**
508c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis * ath5k_hw_get_tsf64 - Get the full 64bit TSF
509c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis *
510c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis * @ah: The &struct ath5k_hw
511c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis *
512c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis * Returns the current TSF
513c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis */
514c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidisu64 ath5k_hw_get_tsf64(struct ath5k_hw *ah)
515c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis{
5161c0fc65e6de4e941ff483df445e721d6edb1f84bBenoit Papillault	u32 tsf_lower, tsf_upper1, tsf_upper2;
5171c0fc65e6de4e941ff483df445e721d6edb1f84bBenoit Papillault	int i;
51828df897a42aa41d6318be5b9872c4bb5c8d8d7e3Bruno Randolf	unsigned long flags;
51928df897a42aa41d6318be5b9872c4bb5c8d8d7e3Bruno Randolf
52028df897a42aa41d6318be5b9872c4bb5c8d8d7e3Bruno Randolf	/* This code is time critical - we don't want to be interrupted here */
52128df897a42aa41d6318be5b9872c4bb5c8d8d7e3Bruno Randolf	local_irq_save(flags);
5221c0fc65e6de4e941ff483df445e721d6edb1f84bBenoit Papillault
5231c0fc65e6de4e941ff483df445e721d6edb1f84bBenoit Papillault	/*
5241c0fc65e6de4e941ff483df445e721d6edb1f84bBenoit Papillault	 * While reading TSF upper and then lower part, the clock is still
5251c0fc65e6de4e941ff483df445e721d6edb1f84bBenoit Papillault	 * counting (or jumping in case of IBSS merge) so we might get
5261c0fc65e6de4e941ff483df445e721d6edb1f84bBenoit Papillault	 * inconsistent values. To avoid this, we read the upper part again
5271c0fc65e6de4e941ff483df445e721d6edb1f84bBenoit Papillault	 * and check it has not been changed. We make the hypothesis that a
5281c0fc65e6de4e941ff483df445e721d6edb1f84bBenoit Papillault	 * maximum of 3 changes can happens in a row (we use 10 as a safe
5291c0fc65e6de4e941ff483df445e721d6edb1f84bBenoit Papillault	 * value).
5301c0fc65e6de4e941ff483df445e721d6edb1f84bBenoit Papillault	 *
5311c0fc65e6de4e941ff483df445e721d6edb1f84bBenoit Papillault	 * Impact on performance is pretty small, since in most cases, only
5321c0fc65e6de4e941ff483df445e721d6edb1f84bBenoit Papillault	 * 3 register reads are needed.
5331c0fc65e6de4e941ff483df445e721d6edb1f84bBenoit Papillault	 */
5341c0fc65e6de4e941ff483df445e721d6edb1f84bBenoit Papillault
5351c0fc65e6de4e941ff483df445e721d6edb1f84bBenoit Papillault	tsf_upper1 = ath5k_hw_reg_read(ah, AR5K_TSF_U32);
5361c0fc65e6de4e941ff483df445e721d6edb1f84bBenoit Papillault	for (i = 0; i < ATH5K_MAX_TSF_READ; i++) {
5371c0fc65e6de4e941ff483df445e721d6edb1f84bBenoit Papillault		tsf_lower = ath5k_hw_reg_read(ah, AR5K_TSF_L32);
5381c0fc65e6de4e941ff483df445e721d6edb1f84bBenoit Papillault		tsf_upper2 = ath5k_hw_reg_read(ah, AR5K_TSF_U32);
5391c0fc65e6de4e941ff483df445e721d6edb1f84bBenoit Papillault		if (tsf_upper2 == tsf_upper1)
5401c0fc65e6de4e941ff483df445e721d6edb1f84bBenoit Papillault			break;
5411c0fc65e6de4e941ff483df445e721d6edb1f84bBenoit Papillault		tsf_upper1 = tsf_upper2;
5421c0fc65e6de4e941ff483df445e721d6edb1f84bBenoit Papillault	}
5431c0fc65e6de4e941ff483df445e721d6edb1f84bBenoit Papillault
54428df897a42aa41d6318be5b9872c4bb5c8d8d7e3Bruno Randolf	local_irq_restore(flags);
54528df897a42aa41d6318be5b9872c4bb5c8d8d7e3Bruno Randolf
5461c0fc65e6de4e941ff483df445e721d6edb1f84bBenoit Papillault	WARN_ON( i == ATH5K_MAX_TSF_READ );
5471c0fc65e6de4e941ff483df445e721d6edb1f84bBenoit Papillault
5481c0fc65e6de4e941ff483df445e721d6edb1f84bBenoit Papillault	return (((u64)tsf_upper1 << 32) | tsf_lower);
549c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis}
550c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis
551c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis/**
5528cab7581dba90b0519e25784e08feb5dedde737fAlina Friedrichsen * ath5k_hw_set_tsf64 - Set a new 64bit TSF
5538cab7581dba90b0519e25784e08feb5dedde737fAlina Friedrichsen *
5548cab7581dba90b0519e25784e08feb5dedde737fAlina Friedrichsen * @ah: The &struct ath5k_hw
5558cab7581dba90b0519e25784e08feb5dedde737fAlina Friedrichsen * @tsf64: The new 64bit TSF
5568cab7581dba90b0519e25784e08feb5dedde737fAlina Friedrichsen *
5578cab7581dba90b0519e25784e08feb5dedde737fAlina Friedrichsen * Sets the new TSF
5588cab7581dba90b0519e25784e08feb5dedde737fAlina Friedrichsen */
5598cab7581dba90b0519e25784e08feb5dedde737fAlina Friedrichsenvoid ath5k_hw_set_tsf64(struct ath5k_hw *ah, u64 tsf64)
5608cab7581dba90b0519e25784e08feb5dedde737fAlina Friedrichsen{
5618cab7581dba90b0519e25784e08feb5dedde737fAlina Friedrichsen	ath5k_hw_reg_write(ah, tsf64 & 0xffffffff, AR5K_TSF_L32);
5620ad65bd7e1b38dd2c86da5f07dbfa35fe1f03099Alina Friedrichsen	ath5k_hw_reg_write(ah, (tsf64 >> 32) & 0xffffffff, AR5K_TSF_U32);
5638cab7581dba90b0519e25784e08feb5dedde737fAlina Friedrichsen}
5648cab7581dba90b0519e25784e08feb5dedde737fAlina Friedrichsen
5658cab7581dba90b0519e25784e08feb5dedde737fAlina Friedrichsen/**
566c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis * ath5k_hw_reset_tsf - Force a TSF reset
567c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis *
568c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis * @ah: The &struct ath5k_hw
569c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis *
570c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis * Forces a TSF reset on PCU
571c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis */
572c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidisvoid ath5k_hw_reset_tsf(struct ath5k_hw *ah)
573c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis{
57414be9947ef9843102b67d315c7483de112b5b2d7Bob Copeland	u32 val;
57514be9947ef9843102b67d315c7483de112b5b2d7Bob Copeland
57614be9947ef9843102b67d315c7483de112b5b2d7Bob Copeland	val = ath5k_hw_reg_read(ah, AR5K_BEACON) | AR5K_BEACON_RESET_TSF;
57714be9947ef9843102b67d315c7483de112b5b2d7Bob Copeland
57814be9947ef9843102b67d315c7483de112b5b2d7Bob Copeland	/*
57914be9947ef9843102b67d315c7483de112b5b2d7Bob Copeland	 * Each write to the RESET_TSF bit toggles a hardware internal
58014be9947ef9843102b67d315c7483de112b5b2d7Bob Copeland	 * signal to reset TSF, but if left high it will cause a TSF reset
58114be9947ef9843102b67d315c7483de112b5b2d7Bob Copeland	 * on the next chip reset as well.  Thus we always write the value
58214be9947ef9843102b67d315c7483de112b5b2d7Bob Copeland	 * twice to clear the signal.
58314be9947ef9843102b67d315c7483de112b5b2d7Bob Copeland	 */
58414be9947ef9843102b67d315c7483de112b5b2d7Bob Copeland	ath5k_hw_reg_write(ah, val, AR5K_BEACON);
58514be9947ef9843102b67d315c7483de112b5b2d7Bob Copeland	ath5k_hw_reg_write(ah, val, AR5K_BEACON);
586c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis}
587c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis
588c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis/*
589c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis * Initialize beacon timers
590c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis */
591c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidisvoid ath5k_hw_init_beacon(struct ath5k_hw *ah, u32 next_beacon, u32 interval)
592c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis{
593c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis	u32 timer1, timer2, timer3;
594c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis
595c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis	/*
596c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis	 * Set the additional timers by mode
597c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis	 */
598ccfe5552aeb18c87a4d0ecb8cb7512280435bfddBruno Randolf	switch (ah->ah_sc->opmode) {
599f07a6c495e88ae0143e3c20b1ed666314197277fNick Kossifidis	case NL80211_IFTYPE_MONITOR:
60005c914fe330fa8e1cc67870dc0d3809dfd96c107Johannes Berg	case NL80211_IFTYPE_STATION:
601f07a6c495e88ae0143e3c20b1ed666314197277fNick Kossifidis		/* In STA mode timer1 is used as next wakeup
602f07a6c495e88ae0143e3c20b1ed666314197277fNick Kossifidis		 * timer and timer2 as next CFP duration start
603f07a6c495e88ae0143e3c20b1ed666314197277fNick Kossifidis		 * timer. Both in 1/8TUs. */
604f07a6c495e88ae0143e3c20b1ed666314197277fNick Kossifidis		/* TODO: PCF handling */
605c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis		if (ah->ah_version == AR5K_AR5210) {
606c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis			timer1 = 0xffffffff;
607c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis			timer2 = 0xffffffff;
608c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis		} else {
609c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis			timer1 = 0x0000ffff;
610c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis			timer2 = 0x0007ffff;
611c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis		}
612f07a6c495e88ae0143e3c20b1ed666314197277fNick Kossifidis		/* Mark associated AP as PCF incapable for now */
613f07a6c495e88ae0143e3c20b1ed666314197277fNick Kossifidis		AR5K_REG_DISABLE_BITS(ah, AR5K_STA_ID1, AR5K_STA_ID1_PCF);
614c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis		break;
615f07a6c495e88ae0143e3c20b1ed666314197277fNick Kossifidis	case NL80211_IFTYPE_ADHOC:
616f07a6c495e88ae0143e3c20b1ed666314197277fNick Kossifidis		AR5K_REG_ENABLE_BITS(ah, AR5K_TXCFG, AR5K_TXCFG_ADHOC_BCN_ATIM);
617c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis	default:
618f07a6c495e88ae0143e3c20b1ed666314197277fNick Kossifidis		/* On non-STA modes timer1 is used as next DMA
619f07a6c495e88ae0143e3c20b1ed666314197277fNick Kossifidis		 * beacon alert (DBA) timer and timer2 as next
620f07a6c495e88ae0143e3c20b1ed666314197277fNick Kossifidis		 * software beacon alert. Both in 1/8TUs. */
621c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis		timer1 = (next_beacon - AR5K_TUNE_DMA_BEACON_RESP) << 3;
622c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis		timer2 = (next_beacon - AR5K_TUNE_SW_BEACON_RESP) << 3;
623f07a6c495e88ae0143e3c20b1ed666314197277fNick Kossifidis		break;
624c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis	}
625c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis
626f07a6c495e88ae0143e3c20b1ed666314197277fNick Kossifidis	/* Timer3 marks the end of our ATIM window
627f07a6c495e88ae0143e3c20b1ed666314197277fNick Kossifidis	 * a zero length window is not allowed because
628f07a6c495e88ae0143e3c20b1ed666314197277fNick Kossifidis	 * we 'll get no beacons */
6294a79f2c517cce31c3b25aab0ec5078368b22c363Bruno Randolf	timer3 = next_beacon + 1;
630c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis
631c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis	/*
632c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis	 * Set the beacon register and enable all timers.
633c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis	 */
63435edf8aae8f903b154d658b9a7eed0d5c1a4a814Nick Kossifidis	/* When in AP or Mesh Point mode zero timer0 to start TSF */
635ccfe5552aeb18c87a4d0ecb8cb7512280435bfddBruno Randolf	if (ah->ah_sc->opmode == NL80211_IFTYPE_AP ||
636ccfe5552aeb18c87a4d0ecb8cb7512280435bfddBruno Randolf	    ah->ah_sc->opmode == NL80211_IFTYPE_MESH_POINT)
637f07a6c495e88ae0143e3c20b1ed666314197277fNick Kossifidis		ath5k_hw_reg_write(ah, 0, AR5K_TIMER0);
638428cbd4ff4d0f2423f49e499f499f04a636cb152Nick Kossifidis
639428cbd4ff4d0f2423f49e499f499f04a636cb152Nick Kossifidis	ath5k_hw_reg_write(ah, next_beacon, AR5K_TIMER0);
640c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis	ath5k_hw_reg_write(ah, timer1, AR5K_TIMER1);
641c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis	ath5k_hw_reg_write(ah, timer2, AR5K_TIMER2);
642c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis	ath5k_hw_reg_write(ah, timer3, AR5K_TIMER3);
643c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis
644f07a6c495e88ae0143e3c20b1ed666314197277fNick Kossifidis	/* Force a TSF reset if requested and enable beacons */
645f07a6c495e88ae0143e3c20b1ed666314197277fNick Kossifidis	if (interval & AR5K_BEACON_RESET_TSF)
646f07a6c495e88ae0143e3c20b1ed666314197277fNick Kossifidis		ath5k_hw_reset_tsf(ah);
647f07a6c495e88ae0143e3c20b1ed666314197277fNick Kossifidis
648c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis	ath5k_hw_reg_write(ah, interval & (AR5K_BEACON_PERIOD |
649f07a6c495e88ae0143e3c20b1ed666314197277fNick Kossifidis					AR5K_BEACON_ENABLE),
650f07a6c495e88ae0143e3c20b1ed666314197277fNick Kossifidis						AR5K_BEACON);
651f07a6c495e88ae0143e3c20b1ed666314197277fNick Kossifidis
652f07a6c495e88ae0143e3c20b1ed666314197277fNick Kossifidis	/* Flush any pending BMISS interrupts on ISR by
653f07a6c495e88ae0143e3c20b1ed666314197277fNick Kossifidis	 * performing a clear-on-write operation on PISR
654f07a6c495e88ae0143e3c20b1ed666314197277fNick Kossifidis	 * register for the BMISS bit (writing a bit on
655f07a6c495e88ae0143e3c20b1ed666314197277fNick Kossifidis	 * ISR togles a reset for that bit and leaves
656f07a6c495e88ae0143e3c20b1ed666314197277fNick Kossifidis	 * the rest bits intact) */
657f07a6c495e88ae0143e3c20b1ed666314197277fNick Kossifidis	if (ah->ah_version == AR5K_AR5210)
658f07a6c495e88ae0143e3c20b1ed666314197277fNick Kossifidis		ath5k_hw_reg_write(ah, AR5K_ISR_BMISS, AR5K_ISR);
659f07a6c495e88ae0143e3c20b1ed666314197277fNick Kossifidis	else
660f07a6c495e88ae0143e3c20b1ed666314197277fNick Kossifidis		ath5k_hw_reg_write(ah, AR5K_ISR_BMISS, AR5K_PISR);
661f07a6c495e88ae0143e3c20b1ed666314197277fNick Kossifidis
662f07a6c495e88ae0143e3c20b1ed666314197277fNick Kossifidis	/* TODO: Set enchanced sleep registers on AR5212
663f07a6c495e88ae0143e3c20b1ed666314197277fNick Kossifidis	 * based on vif->bss_conf params, until then
664f07a6c495e88ae0143e3c20b1ed666314197277fNick Kossifidis	 * disable power save reporting.*/
665f07a6c495e88ae0143e3c20b1ed666314197277fNick Kossifidis	AR5K_REG_DISABLE_BITS(ah, AR5K_STA_ID1, AR5K_STA_ID1_PWR_SV);
666f07a6c495e88ae0143e3c20b1ed666314197277fNick Kossifidis
667c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis}
668c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis
6696e08d228b6d8e93d7b25b3573c6da7da179c2ae1Lukáš Turek/**
6707f896126017830b29cf501d246ee32b81e359acdBruno Randolf * ath5k_check_timer_win - Check if timer B is timer A + window
6717f896126017830b29cf501d246ee32b81e359acdBruno Randolf *
6727f896126017830b29cf501d246ee32b81e359acdBruno Randolf * @a: timer a (before b)
6737f896126017830b29cf501d246ee32b81e359acdBruno Randolf * @b: timer b (after a)
6747f896126017830b29cf501d246ee32b81e359acdBruno Randolf * @window: difference between a and b
6757f896126017830b29cf501d246ee32b81e359acdBruno Randolf * @intval: timers are increased by this interval
6767f896126017830b29cf501d246ee32b81e359acdBruno Randolf *
6777f896126017830b29cf501d246ee32b81e359acdBruno Randolf * This helper function checks if timer B is timer A + window and covers
6787f896126017830b29cf501d246ee32b81e359acdBruno Randolf * cases where timer A or B might have already been updated or wrapped
6797f896126017830b29cf501d246ee32b81e359acdBruno Randolf * around (Timers are 16 bit).
6807f896126017830b29cf501d246ee32b81e359acdBruno Randolf *
6817f896126017830b29cf501d246ee32b81e359acdBruno Randolf * Returns true if O.K.
6827f896126017830b29cf501d246ee32b81e359acdBruno Randolf */
6837f896126017830b29cf501d246ee32b81e359acdBruno Randolfstatic inline bool
6847f896126017830b29cf501d246ee32b81e359acdBruno Randolfath5k_check_timer_win(int a, int b, int window, int intval)
6857f896126017830b29cf501d246ee32b81e359acdBruno Randolf{
6867f896126017830b29cf501d246ee32b81e359acdBruno Randolf	/*
6877f896126017830b29cf501d246ee32b81e359acdBruno Randolf	 * 1.) usually B should be A + window
6887f896126017830b29cf501d246ee32b81e359acdBruno Randolf	 * 2.) A already updated, B not updated yet
6897f896126017830b29cf501d246ee32b81e359acdBruno Randolf	 * 3.) A already updated and has wrapped around
6907f896126017830b29cf501d246ee32b81e359acdBruno Randolf	 * 4.) B has wrapped around
6917f896126017830b29cf501d246ee32b81e359acdBruno Randolf	 */
6927f896126017830b29cf501d246ee32b81e359acdBruno Randolf	if ((b - a == window) ||				/* 1.) */
6937f896126017830b29cf501d246ee32b81e359acdBruno Randolf	    (a - b == intval - window) ||			/* 2.) */
6947f896126017830b29cf501d246ee32b81e359acdBruno Randolf	    ((a | 0x10000) - b == intval - window) ||		/* 3.) */
6957f896126017830b29cf501d246ee32b81e359acdBruno Randolf	    ((b | 0x10000) - a == window))			/* 4.) */
6967f896126017830b29cf501d246ee32b81e359acdBruno Randolf		return true; /* O.K. */
6977f896126017830b29cf501d246ee32b81e359acdBruno Randolf	return false;
6987f896126017830b29cf501d246ee32b81e359acdBruno Randolf}
6997f896126017830b29cf501d246ee32b81e359acdBruno Randolf
7007f896126017830b29cf501d246ee32b81e359acdBruno Randolf/**
7017f896126017830b29cf501d246ee32b81e359acdBruno Randolf * ath5k_hw_check_beacon_timers - Check if the beacon timers are correct
7027f896126017830b29cf501d246ee32b81e359acdBruno Randolf *
7037f896126017830b29cf501d246ee32b81e359acdBruno Randolf * @ah: The &struct ath5k_hw
7047f896126017830b29cf501d246ee32b81e359acdBruno Randolf * @intval: beacon interval
7057f896126017830b29cf501d246ee32b81e359acdBruno Randolf *
7067f896126017830b29cf501d246ee32b81e359acdBruno Randolf * This is a workaround for IBSS mode:
7077f896126017830b29cf501d246ee32b81e359acdBruno Randolf *
7087f896126017830b29cf501d246ee32b81e359acdBruno Randolf * The need for this function arises from the fact that we have 4 separate
7097f896126017830b29cf501d246ee32b81e359acdBruno Randolf * HW timer registers (TIMER0 - TIMER3), which are closely related to the
7107f896126017830b29cf501d246ee32b81e359acdBruno Randolf * next beacon target time (NBTT), and that the HW updates these timers
7117f896126017830b29cf501d246ee32b81e359acdBruno Randolf * seperately based on the current TSF value. The hardware increments each
7127f896126017830b29cf501d246ee32b81e359acdBruno Randolf * timer by the beacon interval, when the local TSF coverted to TU is equal
7137f896126017830b29cf501d246ee32b81e359acdBruno Randolf * to the value stored in the timer.
7147f896126017830b29cf501d246ee32b81e359acdBruno Randolf *
7157f896126017830b29cf501d246ee32b81e359acdBruno Randolf * The reception of a beacon with the same BSSID can update the local HW TSF
7167f896126017830b29cf501d246ee32b81e359acdBruno Randolf * at any time - this is something we can't avoid. If the TSF jumps to a
7177f896126017830b29cf501d246ee32b81e359acdBruno Randolf * time which is later than the time stored in a timer, this timer will not
7187f896126017830b29cf501d246ee32b81e359acdBruno Randolf * be updated until the TSF in TU wraps around at 16 bit (the size of the
7197f896126017830b29cf501d246ee32b81e359acdBruno Randolf * timers) and reaches the time which is stored in the timer.
7207f896126017830b29cf501d246ee32b81e359acdBruno Randolf *
7217f896126017830b29cf501d246ee32b81e359acdBruno Randolf * The problem is that these timers are closely related to TIMER0 (NBTT) and
7227f896126017830b29cf501d246ee32b81e359acdBruno Randolf * that they define a time "window". When the TSF jumps between two timers
7237f896126017830b29cf501d246ee32b81e359acdBruno Randolf * (e.g. ATIM and NBTT), the one in the past will be left behind (not
7247f896126017830b29cf501d246ee32b81e359acdBruno Randolf * updated), while the one in the future will be updated every beacon
7257f896126017830b29cf501d246ee32b81e359acdBruno Randolf * interval. This causes the window to get larger, until the TSF wraps
7267f896126017830b29cf501d246ee32b81e359acdBruno Randolf * around as described above and the timer which was left behind gets
7277f896126017830b29cf501d246ee32b81e359acdBruno Randolf * updated again. But - because the beacon interval is usually not an exact
7287f896126017830b29cf501d246ee32b81e359acdBruno Randolf * divisor of the size of the timers (16 bit), an unwanted "window" between
7297f896126017830b29cf501d246ee32b81e359acdBruno Randolf * these timers has developed!
7307f896126017830b29cf501d246ee32b81e359acdBruno Randolf *
7317f896126017830b29cf501d246ee32b81e359acdBruno Randolf * This is especially important with the ATIM window, because during
7327f896126017830b29cf501d246ee32b81e359acdBruno Randolf * the ATIM window only ATIM frames and no data frames are allowed to be
7337f896126017830b29cf501d246ee32b81e359acdBruno Randolf * sent, which creates transmission pauses after each beacon. This symptom
7347f896126017830b29cf501d246ee32b81e359acdBruno Randolf * has been described as "ramping ping" because ping times increase linearly
7357f896126017830b29cf501d246ee32b81e359acdBruno Randolf * for some time and then drop down again. A wrong window on the DMA beacon
7367f896126017830b29cf501d246ee32b81e359acdBruno Randolf * timer has the same effect, so we check for these two conditions.
7377f896126017830b29cf501d246ee32b81e359acdBruno Randolf *
7387f896126017830b29cf501d246ee32b81e359acdBruno Randolf * Returns true if O.K.
7397f896126017830b29cf501d246ee32b81e359acdBruno Randolf */
7407f896126017830b29cf501d246ee32b81e359acdBruno Randolfbool
7417f896126017830b29cf501d246ee32b81e359acdBruno Randolfath5k_hw_check_beacon_timers(struct ath5k_hw *ah, int intval)
7427f896126017830b29cf501d246ee32b81e359acdBruno Randolf{
7437f896126017830b29cf501d246ee32b81e359acdBruno Randolf	unsigned int nbtt, atim, dma;
7447f896126017830b29cf501d246ee32b81e359acdBruno Randolf
7457f896126017830b29cf501d246ee32b81e359acdBruno Randolf	nbtt = ath5k_hw_reg_read(ah, AR5K_TIMER0);
7467f896126017830b29cf501d246ee32b81e359acdBruno Randolf	atim = ath5k_hw_reg_read(ah, AR5K_TIMER3);
7477f896126017830b29cf501d246ee32b81e359acdBruno Randolf	dma = ath5k_hw_reg_read(ah, AR5K_TIMER1) >> 3;
7487f896126017830b29cf501d246ee32b81e359acdBruno Randolf
7497f896126017830b29cf501d246ee32b81e359acdBruno Randolf	/* NOTE: SWBA is different. Having a wrong window there does not
7507f896126017830b29cf501d246ee32b81e359acdBruno Randolf	 * stop us from sending data and this condition is catched thru
7517f896126017830b29cf501d246ee32b81e359acdBruno Randolf	 * other means (SWBA interrupt) */
7527f896126017830b29cf501d246ee32b81e359acdBruno Randolf
7537f896126017830b29cf501d246ee32b81e359acdBruno Randolf	if (ath5k_check_timer_win(nbtt, atim, 1, intval) &&
7547f896126017830b29cf501d246ee32b81e359acdBruno Randolf	    ath5k_check_timer_win(dma, nbtt, AR5K_TUNE_DMA_BEACON_RESP,
7557f896126017830b29cf501d246ee32b81e359acdBruno Randolf				  intval))
7567f896126017830b29cf501d246ee32b81e359acdBruno Randolf		return true; /* O.K. */
7577f896126017830b29cf501d246ee32b81e359acdBruno Randolf	return false;
7587f896126017830b29cf501d246ee32b81e359acdBruno Randolf}
7597f896126017830b29cf501d246ee32b81e359acdBruno Randolf
7607f896126017830b29cf501d246ee32b81e359acdBruno Randolf/**
7616e08d228b6d8e93d7b25b3573c6da7da179c2ae1Lukáš Turek * ath5k_hw_set_coverage_class - Set IEEE 802.11 coverage class
7626e08d228b6d8e93d7b25b3573c6da7da179c2ae1Lukáš Turek *
7636e08d228b6d8e93d7b25b3573c6da7da179c2ae1Lukáš Turek * @ah: The &struct ath5k_hw
7646e08d228b6d8e93d7b25b3573c6da7da179c2ae1Lukáš Turek * @coverage_class: IEEE 802.11 coverage class number
7656e08d228b6d8e93d7b25b3573c6da7da179c2ae1Lukáš Turek *
766eeb8832b3181d6ca8593051b68c466e5d2653bb3Nick Kossifidis * Sets IFS intervals and ACK/CTS timeouts for given coverage class.
7676e08d228b6d8e93d7b25b3573c6da7da179c2ae1Lukáš Turek */
7686e08d228b6d8e93d7b25b3573c6da7da179c2ae1Lukáš Turekvoid ath5k_hw_set_coverage_class(struct ath5k_hw *ah, u8 coverage_class)
7696e08d228b6d8e93d7b25b3573c6da7da179c2ae1Lukáš Turek{
7706e08d228b6d8e93d7b25b3573c6da7da179c2ae1Lukáš Turek	/* As defined by IEEE 802.11-2007 17.3.8.6 */
7716e08d228b6d8e93d7b25b3573c6da7da179c2ae1Lukáš Turek	int slot_time = ath5k_hw_get_default_slottime(ah) + 3 * coverage_class;
7726e08d228b6d8e93d7b25b3573c6da7da179c2ae1Lukáš Turek	int ack_timeout = ath5k_hw_get_default_sifs(ah) + slot_time;
7736e08d228b6d8e93d7b25b3573c6da7da179c2ae1Lukáš Turek	int cts_timeout = ack_timeout;
7746e08d228b6d8e93d7b25b3573c6da7da179c2ae1Lukáš Turek
775eeb8832b3181d6ca8593051b68c466e5d2653bb3Nick Kossifidis	ath5k_hw_set_ifs_intervals(ah, slot_time);
7766e08d228b6d8e93d7b25b3573c6da7da179c2ae1Lukáš Turek	ath5k_hw_set_ack_timeout(ah, ack_timeout);
7776e08d228b6d8e93d7b25b3573c6da7da179c2ae1Lukáš Turek	ath5k_hw_set_cts_timeout(ah, cts_timeout);
7786e08d228b6d8e93d7b25b3573c6da7da179c2ae1Lukáš Turek
7796e08d228b6d8e93d7b25b3573c6da7da179c2ae1Lukáš Turek	ah->ah_coverage_class = coverage_class;
7806e08d228b6d8e93d7b25b3573c6da7da179c2ae1Lukáš Turek}
7819320b5c4a7260d9593102f378201d17e3f030739Nick Kossifidis
7829320b5c4a7260d9593102f378201d17e3f030739Nick Kossifidis/***************************\
7839320b5c4a7260d9593102f378201d17e3f030739Nick Kossifidis* Init/Start/Stop functions *
7849320b5c4a7260d9593102f378201d17e3f030739Nick Kossifidis\***************************/
7859320b5c4a7260d9593102f378201d17e3f030739Nick Kossifidis
7869320b5c4a7260d9593102f378201d17e3f030739Nick Kossifidis/**
7879320b5c4a7260d9593102f378201d17e3f030739Nick Kossifidis * ath5k_hw_start_rx_pcu - Start RX engine
7889320b5c4a7260d9593102f378201d17e3f030739Nick Kossifidis *
7899320b5c4a7260d9593102f378201d17e3f030739Nick Kossifidis * @ah: The &struct ath5k_hw
7909320b5c4a7260d9593102f378201d17e3f030739Nick Kossifidis *
7919320b5c4a7260d9593102f378201d17e3f030739Nick Kossifidis * Starts RX engine on PCU so that hw can process RXed frames
7929320b5c4a7260d9593102f378201d17e3f030739Nick Kossifidis * (ACK etc).
7939320b5c4a7260d9593102f378201d17e3f030739Nick Kossifidis *
7949320b5c4a7260d9593102f378201d17e3f030739Nick Kossifidis * NOTE: RX DMA should be already enabled using ath5k_hw_start_rx_dma
7959320b5c4a7260d9593102f378201d17e3f030739Nick Kossifidis */
7969320b5c4a7260d9593102f378201d17e3f030739Nick Kossifidisvoid ath5k_hw_start_rx_pcu(struct ath5k_hw *ah)
7979320b5c4a7260d9593102f378201d17e3f030739Nick Kossifidis{
7989320b5c4a7260d9593102f378201d17e3f030739Nick Kossifidis	AR5K_REG_DISABLE_BITS(ah, AR5K_DIAG_SW, AR5K_DIAG_SW_DIS_RX);
7999320b5c4a7260d9593102f378201d17e3f030739Nick Kossifidis}
8009320b5c4a7260d9593102f378201d17e3f030739Nick Kossifidis
8019320b5c4a7260d9593102f378201d17e3f030739Nick Kossifidis/**
8029320b5c4a7260d9593102f378201d17e3f030739Nick Kossifidis * at5k_hw_stop_rx_pcu - Stop RX engine
8039320b5c4a7260d9593102f378201d17e3f030739Nick Kossifidis *
8049320b5c4a7260d9593102f378201d17e3f030739Nick Kossifidis * @ah: The &struct ath5k_hw
8059320b5c4a7260d9593102f378201d17e3f030739Nick Kossifidis *
8069320b5c4a7260d9593102f378201d17e3f030739Nick Kossifidis * Stops RX engine on PCU
8079320b5c4a7260d9593102f378201d17e3f030739Nick Kossifidis */
8089320b5c4a7260d9593102f378201d17e3f030739Nick Kossifidisvoid ath5k_hw_stop_rx_pcu(struct ath5k_hw *ah)
8099320b5c4a7260d9593102f378201d17e3f030739Nick Kossifidis{
8109320b5c4a7260d9593102f378201d17e3f030739Nick Kossifidis	AR5K_REG_ENABLE_BITS(ah, AR5K_DIAG_SW, AR5K_DIAG_SW_DIS_RX);
8119320b5c4a7260d9593102f378201d17e3f030739Nick Kossifidis}
8129320b5c4a7260d9593102f378201d17e3f030739Nick Kossifidis
8139320b5c4a7260d9593102f378201d17e3f030739Nick Kossifidis/**
8149320b5c4a7260d9593102f378201d17e3f030739Nick Kossifidis * ath5k_hw_set_opmode - Set PCU operating mode
8159320b5c4a7260d9593102f378201d17e3f030739Nick Kossifidis *
8169320b5c4a7260d9593102f378201d17e3f030739Nick Kossifidis * @ah: The &struct ath5k_hw
8179320b5c4a7260d9593102f378201d17e3f030739Nick Kossifidis * @op_mode: &enum nl80211_iftype operating mode
8189320b5c4a7260d9593102f378201d17e3f030739Nick Kossifidis *
8199320b5c4a7260d9593102f378201d17e3f030739Nick Kossifidis * Configure PCU for the various operating modes (AP/STA etc)
8209320b5c4a7260d9593102f378201d17e3f030739Nick Kossifidis */
8219320b5c4a7260d9593102f378201d17e3f030739Nick Kossifidisint ath5k_hw_set_opmode(struct ath5k_hw *ah, enum nl80211_iftype op_mode)
8229320b5c4a7260d9593102f378201d17e3f030739Nick Kossifidis{
8239320b5c4a7260d9593102f378201d17e3f030739Nick Kossifidis	struct ath_common *common = ath5k_hw_common(ah);
8249320b5c4a7260d9593102f378201d17e3f030739Nick Kossifidis	u32 pcu_reg, beacon_reg, low_id, high_id;
8259320b5c4a7260d9593102f378201d17e3f030739Nick Kossifidis
8269320b5c4a7260d9593102f378201d17e3f030739Nick Kossifidis	ATH5K_DBG(ah->ah_sc, ATH5K_DEBUG_MODE, "mode %d\n", op_mode);
8279320b5c4a7260d9593102f378201d17e3f030739Nick Kossifidis
8289320b5c4a7260d9593102f378201d17e3f030739Nick Kossifidis	/* Preserve rest settings */
8299320b5c4a7260d9593102f378201d17e3f030739Nick Kossifidis	pcu_reg = ath5k_hw_reg_read(ah, AR5K_STA_ID1) & 0xffff0000;
8309320b5c4a7260d9593102f378201d17e3f030739Nick Kossifidis	pcu_reg &= ~(AR5K_STA_ID1_ADHOC | AR5K_STA_ID1_AP
8319320b5c4a7260d9593102f378201d17e3f030739Nick Kossifidis			| AR5K_STA_ID1_KEYSRCH_MODE
8329320b5c4a7260d9593102f378201d17e3f030739Nick Kossifidis			| (ah->ah_version == AR5K_AR5210 ?
8339320b5c4a7260d9593102f378201d17e3f030739Nick Kossifidis			(AR5K_STA_ID1_PWR_SV | AR5K_STA_ID1_NO_PSPOLL) : 0));
8349320b5c4a7260d9593102f378201d17e3f030739Nick Kossifidis
8359320b5c4a7260d9593102f378201d17e3f030739Nick Kossifidis	beacon_reg = 0;
8369320b5c4a7260d9593102f378201d17e3f030739Nick Kossifidis
8379320b5c4a7260d9593102f378201d17e3f030739Nick Kossifidis	switch (op_mode) {
8389320b5c4a7260d9593102f378201d17e3f030739Nick Kossifidis	case NL80211_IFTYPE_ADHOC:
8399320b5c4a7260d9593102f378201d17e3f030739Nick Kossifidis		pcu_reg |= AR5K_STA_ID1_ADHOC | AR5K_STA_ID1_KEYSRCH_MODE;
8409320b5c4a7260d9593102f378201d17e3f030739Nick Kossifidis		beacon_reg |= AR5K_BCR_ADHOC;
8419320b5c4a7260d9593102f378201d17e3f030739Nick Kossifidis		if (ah->ah_version == AR5K_AR5210)
8429320b5c4a7260d9593102f378201d17e3f030739Nick Kossifidis			pcu_reg |= AR5K_STA_ID1_NO_PSPOLL;
8439320b5c4a7260d9593102f378201d17e3f030739Nick Kossifidis		else
8449320b5c4a7260d9593102f378201d17e3f030739Nick Kossifidis			AR5K_REG_ENABLE_BITS(ah, AR5K_CFG, AR5K_CFG_IBSS);
8459320b5c4a7260d9593102f378201d17e3f030739Nick Kossifidis		break;
8469320b5c4a7260d9593102f378201d17e3f030739Nick Kossifidis
8479320b5c4a7260d9593102f378201d17e3f030739Nick Kossifidis	case NL80211_IFTYPE_AP:
8489320b5c4a7260d9593102f378201d17e3f030739Nick Kossifidis	case NL80211_IFTYPE_MESH_POINT:
8499320b5c4a7260d9593102f378201d17e3f030739Nick Kossifidis		pcu_reg |= AR5K_STA_ID1_AP | AR5K_STA_ID1_KEYSRCH_MODE;
8509320b5c4a7260d9593102f378201d17e3f030739Nick Kossifidis		beacon_reg |= AR5K_BCR_AP;
8519320b5c4a7260d9593102f378201d17e3f030739Nick Kossifidis		if (ah->ah_version == AR5K_AR5210)
8529320b5c4a7260d9593102f378201d17e3f030739Nick Kossifidis			pcu_reg |= AR5K_STA_ID1_NO_PSPOLL;
8539320b5c4a7260d9593102f378201d17e3f030739Nick Kossifidis		else
8549320b5c4a7260d9593102f378201d17e3f030739Nick Kossifidis			AR5K_REG_DISABLE_BITS(ah, AR5K_CFG, AR5K_CFG_IBSS);
8559320b5c4a7260d9593102f378201d17e3f030739Nick Kossifidis		break;
8569320b5c4a7260d9593102f378201d17e3f030739Nick Kossifidis
8579320b5c4a7260d9593102f378201d17e3f030739Nick Kossifidis	case NL80211_IFTYPE_STATION:
8589320b5c4a7260d9593102f378201d17e3f030739Nick Kossifidis		pcu_reg |= AR5K_STA_ID1_KEYSRCH_MODE
8599320b5c4a7260d9593102f378201d17e3f030739Nick Kossifidis			| (ah->ah_version == AR5K_AR5210 ?
8609320b5c4a7260d9593102f378201d17e3f030739Nick Kossifidis				AR5K_STA_ID1_PWR_SV : 0);
8619320b5c4a7260d9593102f378201d17e3f030739Nick Kossifidis	case NL80211_IFTYPE_MONITOR:
8629320b5c4a7260d9593102f378201d17e3f030739Nick Kossifidis		pcu_reg |= AR5K_STA_ID1_KEYSRCH_MODE
8639320b5c4a7260d9593102f378201d17e3f030739Nick Kossifidis			| (ah->ah_version == AR5K_AR5210 ?
8649320b5c4a7260d9593102f378201d17e3f030739Nick Kossifidis				AR5K_STA_ID1_NO_PSPOLL : 0);
8659320b5c4a7260d9593102f378201d17e3f030739Nick Kossifidis		break;
8669320b5c4a7260d9593102f378201d17e3f030739Nick Kossifidis
8679320b5c4a7260d9593102f378201d17e3f030739Nick Kossifidis	default:
8689320b5c4a7260d9593102f378201d17e3f030739Nick Kossifidis		return -EINVAL;
8699320b5c4a7260d9593102f378201d17e3f030739Nick Kossifidis	}
8709320b5c4a7260d9593102f378201d17e3f030739Nick Kossifidis
8719320b5c4a7260d9593102f378201d17e3f030739Nick Kossifidis	/*
8729320b5c4a7260d9593102f378201d17e3f030739Nick Kossifidis	 * Set PCU registers
8739320b5c4a7260d9593102f378201d17e3f030739Nick Kossifidis	 */
8749320b5c4a7260d9593102f378201d17e3f030739Nick Kossifidis	low_id = get_unaligned_le32(common->macaddr);
8759320b5c4a7260d9593102f378201d17e3f030739Nick Kossifidis	high_id = get_unaligned_le16(common->macaddr + 4);
8769320b5c4a7260d9593102f378201d17e3f030739Nick Kossifidis	ath5k_hw_reg_write(ah, low_id, AR5K_STA_ID0);
8779320b5c4a7260d9593102f378201d17e3f030739Nick Kossifidis	ath5k_hw_reg_write(ah, pcu_reg | high_id, AR5K_STA_ID1);
8789320b5c4a7260d9593102f378201d17e3f030739Nick Kossifidis
8799320b5c4a7260d9593102f378201d17e3f030739Nick Kossifidis	/*
8809320b5c4a7260d9593102f378201d17e3f030739Nick Kossifidis	 * Set Beacon Control Register on 5210
8819320b5c4a7260d9593102f378201d17e3f030739Nick Kossifidis	 */
8829320b5c4a7260d9593102f378201d17e3f030739Nick Kossifidis	if (ah->ah_version == AR5K_AR5210)
8839320b5c4a7260d9593102f378201d17e3f030739Nick Kossifidis		ath5k_hw_reg_write(ah, beacon_reg, AR5K_BCR);
8849320b5c4a7260d9593102f378201d17e3f030739Nick Kossifidis
8859320b5c4a7260d9593102f378201d17e3f030739Nick Kossifidis	return 0;
8869320b5c4a7260d9593102f378201d17e3f030739Nick Kossifidis}
8879320b5c4a7260d9593102f378201d17e3f030739Nick Kossifidis
8889320b5c4a7260d9593102f378201d17e3f030739Nick Kossifidisvoid ath5k_hw_pcu_init(struct ath5k_hw *ah, enum nl80211_iftype op_mode,
8899320b5c4a7260d9593102f378201d17e3f030739Nick Kossifidis								u8 mode)
8909320b5c4a7260d9593102f378201d17e3f030739Nick Kossifidis{
8919320b5c4a7260d9593102f378201d17e3f030739Nick Kossifidis	/* Set bssid and bssid mask */
8929320b5c4a7260d9593102f378201d17e3f030739Nick Kossifidis	ath5k_hw_set_bssid(ah);
8939320b5c4a7260d9593102f378201d17e3f030739Nick Kossifidis
8949320b5c4a7260d9593102f378201d17e3f030739Nick Kossifidis	/* Set PCU config */
8959320b5c4a7260d9593102f378201d17e3f030739Nick Kossifidis	ath5k_hw_set_opmode(ah, op_mode);
8969320b5c4a7260d9593102f378201d17e3f030739Nick Kossifidis
8979320b5c4a7260d9593102f378201d17e3f030739Nick Kossifidis	/* Write rate duration table only on AR5212 and if
8989320b5c4a7260d9593102f378201d17e3f030739Nick Kossifidis	 * virtual interface has already been brought up
8999320b5c4a7260d9593102f378201d17e3f030739Nick Kossifidis	 * XXX: rethink this after new mode changes to
9009320b5c4a7260d9593102f378201d17e3f030739Nick Kossifidis	 * mac80211 are integrated */
9019320b5c4a7260d9593102f378201d17e3f030739Nick Kossifidis	if (ah->ah_version == AR5K_AR5212 &&
9029320b5c4a7260d9593102f378201d17e3f030739Nick Kossifidis		ah->ah_sc->nvifs)
90361cde037234c4b8e6497a23f5f236c64cbf9d41dNick Kossifidis		ath5k_hw_write_rate_duration(ah);
9049320b5c4a7260d9593102f378201d17e3f030739Nick Kossifidis
9059320b5c4a7260d9593102f378201d17e3f030739Nick Kossifidis	/* Set RSSI/BRSSI thresholds
9069320b5c4a7260d9593102f378201d17e3f030739Nick Kossifidis	 *
9079320b5c4a7260d9593102f378201d17e3f030739Nick Kossifidis	 * Note: If we decide to set this value
9089320b5c4a7260d9593102f378201d17e3f030739Nick Kossifidis	 * dynamicaly, have in mind that when AR5K_RSSI_THR
9099320b5c4a7260d9593102f378201d17e3f030739Nick Kossifidis	 * register is read it might return 0x40 if we haven't
9109320b5c4a7260d9593102f378201d17e3f030739Nick Kossifidis	 * wrote anything to it plus BMISS RSSI threshold is zeroed.
9119320b5c4a7260d9593102f378201d17e3f030739Nick Kossifidis	 * So doing a save/restore procedure here isn't the right
9129320b5c4a7260d9593102f378201d17e3f030739Nick Kossifidis	 * choice. Instead store it on ath5k_hw */
9139320b5c4a7260d9593102f378201d17e3f030739Nick Kossifidis	ath5k_hw_reg_write(ah, (AR5K_TUNE_RSSI_THRES |
9149320b5c4a7260d9593102f378201d17e3f030739Nick Kossifidis				AR5K_TUNE_BMISS_THRES <<
9159320b5c4a7260d9593102f378201d17e3f030739Nick Kossifidis				AR5K_RSSI_THR_BMISS_S),
9169320b5c4a7260d9593102f378201d17e3f030739Nick Kossifidis				AR5K_RSSI_THR);
9179320b5c4a7260d9593102f378201d17e3f030739Nick Kossifidis
9189320b5c4a7260d9593102f378201d17e3f030739Nick Kossifidis	/* MIC QoS support */
9199320b5c4a7260d9593102f378201d17e3f030739Nick Kossifidis	if (ah->ah_mac_srev >= AR5K_SREV_AR2413) {
9209320b5c4a7260d9593102f378201d17e3f030739Nick Kossifidis		ath5k_hw_reg_write(ah, 0x000100aa, AR5K_MIC_QOS_CTL);
9219320b5c4a7260d9593102f378201d17e3f030739Nick Kossifidis		ath5k_hw_reg_write(ah, 0x00003210, AR5K_MIC_QOS_SEL);
9229320b5c4a7260d9593102f378201d17e3f030739Nick Kossifidis	}
9239320b5c4a7260d9593102f378201d17e3f030739Nick Kossifidis
9249320b5c4a7260d9593102f378201d17e3f030739Nick Kossifidis	/* QoS NOACK Policy */
9259320b5c4a7260d9593102f378201d17e3f030739Nick Kossifidis	if (ah->ah_version == AR5K_AR5212) {
9269320b5c4a7260d9593102f378201d17e3f030739Nick Kossifidis		ath5k_hw_reg_write(ah,
9279320b5c4a7260d9593102f378201d17e3f030739Nick Kossifidis			AR5K_REG_SM(2, AR5K_QOS_NOACK_2BIT_VALUES) |
9289320b5c4a7260d9593102f378201d17e3f030739Nick Kossifidis			AR5K_REG_SM(5, AR5K_QOS_NOACK_BIT_OFFSET)  |
9299320b5c4a7260d9593102f378201d17e3f030739Nick Kossifidis			AR5K_REG_SM(0, AR5K_QOS_NOACK_BYTE_OFFSET),
9309320b5c4a7260d9593102f378201d17e3f030739Nick Kossifidis			AR5K_QOS_NOACK);
9319320b5c4a7260d9593102f378201d17e3f030739Nick Kossifidis	}
9329320b5c4a7260d9593102f378201d17e3f030739Nick Kossifidis
9339320b5c4a7260d9593102f378201d17e3f030739Nick Kossifidis	/* Restore slot time and ACK timeouts */
9349320b5c4a7260d9593102f378201d17e3f030739Nick Kossifidis	if (ah->ah_coverage_class > 0)
9359320b5c4a7260d9593102f378201d17e3f030739Nick Kossifidis		ath5k_hw_set_coverage_class(ah, ah->ah_coverage_class);
9369320b5c4a7260d9593102f378201d17e3f030739Nick Kossifidis
93761cde037234c4b8e6497a23f5f236c64cbf9d41dNick Kossifidis	/* Set ACK bitrate mode (see ack_rates_high) */
93861cde037234c4b8e6497a23f5f236c64cbf9d41dNick Kossifidis	if (ah->ah_version == AR5K_AR5212) {
93961cde037234c4b8e6497a23f5f236c64cbf9d41dNick Kossifidis		u32 val = AR5K_STA_ID1_BASE_RATE_11B | AR5K_STA_ID1_ACKCTS_6MB;
94061cde037234c4b8e6497a23f5f236c64cbf9d41dNick Kossifidis		if (ah->ah_ack_bitrate_high)
94161cde037234c4b8e6497a23f5f236c64cbf9d41dNick Kossifidis			AR5K_REG_DISABLE_BITS(ah, AR5K_STA_ID1, val);
94261cde037234c4b8e6497a23f5f236c64cbf9d41dNick Kossifidis		else
94361cde037234c4b8e6497a23f5f236c64cbf9d41dNick Kossifidis			AR5K_REG_ENABLE_BITS(ah, AR5K_STA_ID1, val);
94461cde037234c4b8e6497a23f5f236c64cbf9d41dNick Kossifidis	}
9459320b5c4a7260d9593102f378201d17e3f030739Nick Kossifidis	return;
9469320b5c4a7260d9593102f378201d17e3f030739Nick Kossifidis}
947