pcu.c revision 626ede6b1aafb3a8cadfdd04b512fd1d3dc2113e
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
34c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis/*******************\
35c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis* Generic functions *
36c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis\*******************/
37c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis
38c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis/**
39c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis * ath5k_hw_set_opmode - Set PCU operating mode
40c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis *
41c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis * @ah: The &struct ath5k_hw
42c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis *
43c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis * Initialize PCU for the various operating modes (AP/STA etc)
44c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis *
45c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis * NOTE: ah->ah_op_mode must be set before calling this.
46c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis */
47c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidisint ath5k_hw_set_opmode(struct ath5k_hw *ah)
48c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis{
49954fecea5d1df4d1dc7bf9a822a2fad308e8588eLuis R. Rodriguez	struct ath_common *common = ath5k_hw_common(ah);
50c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis	u32 pcu_reg, beacon_reg, low_id, high_id;
51c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis
52f07a6c495e88ae0143e3c20b1ed666314197277fNick Kossifidis
53f07a6c495e88ae0143e3c20b1ed666314197277fNick Kossifidis	/* Preserve rest settings */
54f07a6c495e88ae0143e3c20b1ed666314197277fNick Kossifidis	pcu_reg = ath5k_hw_reg_read(ah, AR5K_STA_ID1) & 0xffff0000;
55f07a6c495e88ae0143e3c20b1ed666314197277fNick Kossifidis	pcu_reg &= ~(AR5K_STA_ID1_ADHOC | AR5K_STA_ID1_AP
56f07a6c495e88ae0143e3c20b1ed666314197277fNick Kossifidis			| AR5K_STA_ID1_KEYSRCH_MODE
57f07a6c495e88ae0143e3c20b1ed666314197277fNick Kossifidis			| (ah->ah_version == AR5K_AR5210 ?
58f07a6c495e88ae0143e3c20b1ed666314197277fNick Kossifidis			(AR5K_STA_ID1_PWR_SV | AR5K_STA_ID1_NO_PSPOLL) : 0));
59f07a6c495e88ae0143e3c20b1ed666314197277fNick Kossifidis
60c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis	beacon_reg = 0;
61c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis
62c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis	ATH5K_TRACE(ah->ah_sc);
63c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis
64c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis	switch (ah->ah_op_mode) {
6505c914fe330fa8e1cc67870dc0d3809dfd96c107Johannes Berg	case NL80211_IFTYPE_ADHOC:
66f07a6c495e88ae0143e3c20b1ed666314197277fNick Kossifidis		pcu_reg |= AR5K_STA_ID1_ADHOC | AR5K_STA_ID1_KEYSRCH_MODE;
67c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis		beacon_reg |= AR5K_BCR_ADHOC;
68f07a6c495e88ae0143e3c20b1ed666314197277fNick Kossifidis		if (ah->ah_version == AR5K_AR5210)
69f07a6c495e88ae0143e3c20b1ed666314197277fNick Kossifidis			pcu_reg |= AR5K_STA_ID1_NO_PSPOLL;
70f07a6c495e88ae0143e3c20b1ed666314197277fNick Kossifidis		else
714fb7404e0eaf574c00d01d2b1ce2615229b350cdSteve Brown			AR5K_REG_ENABLE_BITS(ah, AR5K_CFG, AR5K_CFG_IBSS);
72c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis		break;
73c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis
7405c914fe330fa8e1cc67870dc0d3809dfd96c107Johannes Berg	case NL80211_IFTYPE_AP:
7505c914fe330fa8e1cc67870dc0d3809dfd96c107Johannes Berg	case NL80211_IFTYPE_MESH_POINT:
76f07a6c495e88ae0143e3c20b1ed666314197277fNick Kossifidis		pcu_reg |= AR5K_STA_ID1_AP | AR5K_STA_ID1_KEYSRCH_MODE;
77c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis		beacon_reg |= AR5K_BCR_AP;
78f07a6c495e88ae0143e3c20b1ed666314197277fNick Kossifidis		if (ah->ah_version == AR5K_AR5210)
79f07a6c495e88ae0143e3c20b1ed666314197277fNick Kossifidis			pcu_reg |= AR5K_STA_ID1_NO_PSPOLL;
80f07a6c495e88ae0143e3c20b1ed666314197277fNick Kossifidis		else
814fb7404e0eaf574c00d01d2b1ce2615229b350cdSteve Brown			AR5K_REG_DISABLE_BITS(ah, AR5K_CFG, AR5K_CFG_IBSS);
82c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis		break;
83c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis
8405c914fe330fa8e1cc67870dc0d3809dfd96c107Johannes Berg	case NL80211_IFTYPE_STATION:
85f07a6c495e88ae0143e3c20b1ed666314197277fNick Kossifidis		pcu_reg |= AR5K_STA_ID1_KEYSRCH_MODE
86f07a6c495e88ae0143e3c20b1ed666314197277fNick Kossifidis			| (ah->ah_version == AR5K_AR5210 ?
87c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis				AR5K_STA_ID1_PWR_SV : 0);
8805c914fe330fa8e1cc67870dc0d3809dfd96c107Johannes Berg	case NL80211_IFTYPE_MONITOR:
89f07a6c495e88ae0143e3c20b1ed666314197277fNick Kossifidis		pcu_reg |= AR5K_STA_ID1_KEYSRCH_MODE
90f07a6c495e88ae0143e3c20b1ed666314197277fNick Kossifidis			| (ah->ah_version == AR5K_AR5210 ?
91c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis				AR5K_STA_ID1_NO_PSPOLL : 0);
92c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis		break;
93c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis
94c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis	default:
95c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis		return -EINVAL;
96c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis	}
97c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis
98c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis	/*
99c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis	 * Set PCU registers
100c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis	 */
101954fecea5d1df4d1dc7bf9a822a2fad308e8588eLuis R. Rodriguez	low_id = get_unaligned_le32(common->macaddr);
102954fecea5d1df4d1dc7bf9a822a2fad308e8588eLuis R. Rodriguez	high_id = get_unaligned_le16(common->macaddr + 4);
103c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis	ath5k_hw_reg_write(ah, low_id, AR5K_STA_ID0);
104c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis	ath5k_hw_reg_write(ah, pcu_reg | high_id, AR5K_STA_ID1);
105c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis
106c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis	/*
107c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis	 * Set Beacon Control Register on 5210
108c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis	 */
109c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis	if (ah->ah_version == AR5K_AR5210)
110c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis		ath5k_hw_reg_write(ah, beacon_reg, AR5K_BCR);
111c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis
112c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis	return 0;
113c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis}
114c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis
115c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis/**
116c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis * ath5k_hw_update - Update mib counters (mac layer statistics)
117c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis *
118c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis * @ah: The &struct ath5k_hw
119c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis * @stats: The &struct ieee80211_low_level_stats we use to track
120c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis * statistics on the driver
121c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis *
122c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis * Reads MIB counters from PCU and updates sw statistics. Must be
123c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis * called after a MIB interrupt.
124c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis */
125c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidisvoid ath5k_hw_update_mib_counters(struct ath5k_hw *ah,
126c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis		struct ieee80211_low_level_stats  *stats)
127c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis{
128c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis	ATH5K_TRACE(ah->ah_sc);
129c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis
130c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis	/* Read-And-Clear */
131c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis	stats->dot11ACKFailureCount += ath5k_hw_reg_read(ah, AR5K_ACK_FAIL);
132c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis	stats->dot11RTSFailureCount += ath5k_hw_reg_read(ah, AR5K_RTS_FAIL);
133c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis	stats->dot11RTSSuccessCount += ath5k_hw_reg_read(ah, AR5K_RTS_OK);
134c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis	stats->dot11FCSErrorCount += ath5k_hw_reg_read(ah, AR5K_FCS_FAIL);
135c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis
136c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis	/* XXX: Should we use this to track beacon count ?
137c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis	 * -we read it anyway to clear the register */
138c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis	ath5k_hw_reg_read(ah, AR5K_BEACON_CNT);
139c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis
140c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis	/* Reset profile count registers on 5212*/
141c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis	if (ah->ah_version == AR5K_AR5212) {
142c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis		ath5k_hw_reg_write(ah, 0, AR5K_PROFCNT_TX);
143c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis		ath5k_hw_reg_write(ah, 0, AR5K_PROFCNT_RX);
144c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis		ath5k_hw_reg_write(ah, 0, AR5K_PROFCNT_RXCLR);
145c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis		ath5k_hw_reg_write(ah, 0, AR5K_PROFCNT_CYCLE);
146c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis	}
147f07a6c495e88ae0143e3c20b1ed666314197277fNick Kossifidis
148f07a6c495e88ae0143e3c20b1ed666314197277fNick Kossifidis	/* TODO: Handle ANI stats */
149c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis}
150c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis
151c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis/**
152c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis * ath5k_hw_set_ack_bitrate - set bitrate for ACKs
153c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis *
154c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis * @ah: The &struct ath5k_hw
155c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis * @high: Flag to determine if we want to use high transmition rate
156c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis * for ACKs or not
157c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis *
158c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis * If high flag is set, we tell hw to use a set of control rates based on
159c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis * the current transmition rate (check out control_rates array inside reset.c).
160c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis * If not hw just uses the lowest rate available for the current modulation
161c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis * scheme being used (1Mbit for CCK and 6Mbits for OFDM).
162c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis */
163c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidisvoid ath5k_hw_set_ack_bitrate_high(struct ath5k_hw *ah, bool high)
164c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis{
165c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis	if (ah->ah_version != AR5K_AR5212)
166c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis		return;
167c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis	else {
168c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis		u32 val = AR5K_STA_ID1_BASE_RATE_11B | AR5K_STA_ID1_ACKCTS_6MB;
169c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis		if (high)
170c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis			AR5K_REG_ENABLE_BITS(ah, AR5K_STA_ID1, val);
171c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis		else
172c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis			AR5K_REG_DISABLE_BITS(ah, AR5K_STA_ID1, val);
173c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis	}
174c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis}
175c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis
176c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis
177c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis/******************\
178c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis* ACK/CTS Timeouts *
179c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis\******************/
180c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis
181626ede6b1aafb3a8cadfdd04b512fd1d3dc2113ePavel Roskin#if 0
182c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis/**
183c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis * ath5k_hw_het_ack_timeout - Get ACK timeout from PCU in usec
184c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis *
185c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis * @ah: The &struct ath5k_hw
186c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis */
187c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidisunsigned int ath5k_hw_get_ack_timeout(struct ath5k_hw *ah)
188c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis{
189c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis	ATH5K_TRACE(ah->ah_sc);
190c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis
1913578e6ebb305e6bf7519f6e86741772892f4d51aLukáš Turek	return ath5k_hw_clocktoh(ah, AR5K_REG_MS(ath5k_hw_reg_read(ah,
1923578e6ebb305e6bf7519f6e86741772892f4d51aLukáš Turek			AR5K_TIME_OUT), AR5K_TIME_OUT_ACK));
193c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis}
194626ede6b1aafb3a8cadfdd04b512fd1d3dc2113ePavel Roskin#endif
195c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis
196c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis/**
197c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis * ath5k_hw_set_ack_timeout - Set ACK timeout on PCU
198c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis *
199c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis * @ah: The &struct ath5k_hw
200c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis * @timeout: Timeout in usec
201c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis */
202626ede6b1aafb3a8cadfdd04b512fd1d3dc2113ePavel Roskinstatic int ath5k_hw_set_ack_timeout(struct ath5k_hw *ah, unsigned int timeout)
203c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis{
204c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis	ATH5K_TRACE(ah->ah_sc);
2053578e6ebb305e6bf7519f6e86741772892f4d51aLukáš Turek	if (ath5k_hw_clocktoh(ah, AR5K_REG_MS(0xffffffff, AR5K_TIME_OUT_ACK))
2063578e6ebb305e6bf7519f6e86741772892f4d51aLukáš Turek			<= timeout)
207c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis		return -EINVAL;
208c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis
209c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis	AR5K_REG_WRITE_BITS(ah, AR5K_TIME_OUT, AR5K_TIME_OUT_ACK,
2103578e6ebb305e6bf7519f6e86741772892f4d51aLukáš Turek		ath5k_hw_htoclock(ah, timeout));
211c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis
212c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis	return 0;
213c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis}
214c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis
215626ede6b1aafb3a8cadfdd04b512fd1d3dc2113ePavel Roskin#if 0
216c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis/**
217c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis * ath5k_hw_get_cts_timeout - Get CTS timeout from PCU in usec
218c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis *
219c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis * @ah: The &struct ath5k_hw
220c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis */
221c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidisunsigned int ath5k_hw_get_cts_timeout(struct ath5k_hw *ah)
222c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis{
223c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis	ATH5K_TRACE(ah->ah_sc);
2243578e6ebb305e6bf7519f6e86741772892f4d51aLukáš Turek	return ath5k_hw_clocktoh(ah, AR5K_REG_MS(ath5k_hw_reg_read(ah,
2253578e6ebb305e6bf7519f6e86741772892f4d51aLukáš Turek			AR5K_TIME_OUT), AR5K_TIME_OUT_CTS));
226c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis}
227626ede6b1aafb3a8cadfdd04b512fd1d3dc2113ePavel Roskin#endif
228c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis
229c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis/**
230c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis * ath5k_hw_set_cts_timeout - Set CTS timeout on PCU
231c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis *
232c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis * @ah: The &struct ath5k_hw
233c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis * @timeout: Timeout in usec
234c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis */
235626ede6b1aafb3a8cadfdd04b512fd1d3dc2113ePavel Roskinstatic int ath5k_hw_set_cts_timeout(struct ath5k_hw *ah, unsigned int timeout)
236c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis{
237c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis	ATH5K_TRACE(ah->ah_sc);
2383578e6ebb305e6bf7519f6e86741772892f4d51aLukáš Turek	if (ath5k_hw_clocktoh(ah, AR5K_REG_MS(0xffffffff, AR5K_TIME_OUT_CTS))
2393578e6ebb305e6bf7519f6e86741772892f4d51aLukáš Turek			<= timeout)
240c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis		return -EINVAL;
241c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis
242c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis	AR5K_REG_WRITE_BITS(ah, AR5K_TIME_OUT, AR5K_TIME_OUT_CTS,
2433578e6ebb305e6bf7519f6e86741772892f4d51aLukáš Turek			ath5k_hw_htoclock(ah, timeout));
244c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis
245c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis	return 0;
246c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis}
247c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis
248c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis/**
2493578e6ebb305e6bf7519f6e86741772892f4d51aLukáš Turek * ath5k_hw_htoclock - Translate usec to hw clock units
2503578e6ebb305e6bf7519f6e86741772892f4d51aLukáš Turek *
2513578e6ebb305e6bf7519f6e86741772892f4d51aLukáš Turek * @ah: The &struct ath5k_hw
2523578e6ebb305e6bf7519f6e86741772892f4d51aLukáš Turek * @usec: value in microseconds
2533578e6ebb305e6bf7519f6e86741772892f4d51aLukáš Turek */
2543578e6ebb305e6bf7519f6e86741772892f4d51aLukáš Turekunsigned int ath5k_hw_htoclock(struct ath5k_hw *ah, unsigned int usec)
2553578e6ebb305e6bf7519f6e86741772892f4d51aLukáš Turek{
2563578e6ebb305e6bf7519f6e86741772892f4d51aLukáš Turek	return usec * ath5k_hw_get_clockrate(ah);
2573578e6ebb305e6bf7519f6e86741772892f4d51aLukáš Turek}
2583578e6ebb305e6bf7519f6e86741772892f4d51aLukáš Turek
2593578e6ebb305e6bf7519f6e86741772892f4d51aLukáš Turek/**
2603578e6ebb305e6bf7519f6e86741772892f4d51aLukáš Turek * ath5k_hw_clocktoh - Translate hw clock units to usec
2613578e6ebb305e6bf7519f6e86741772892f4d51aLukáš Turek * @clock: value in hw clock units
2623578e6ebb305e6bf7519f6e86741772892f4d51aLukáš Turek */
2633578e6ebb305e6bf7519f6e86741772892f4d51aLukáš Turekunsigned int ath5k_hw_clocktoh(struct ath5k_hw *ah, unsigned int clock)
2643578e6ebb305e6bf7519f6e86741772892f4d51aLukáš Turek{
2653578e6ebb305e6bf7519f6e86741772892f4d51aLukáš Turek	return clock / ath5k_hw_get_clockrate(ah);
2663578e6ebb305e6bf7519f6e86741772892f4d51aLukáš Turek}
2673578e6ebb305e6bf7519f6e86741772892f4d51aLukáš Turek
2683578e6ebb305e6bf7519f6e86741772892f4d51aLukáš Turek/**
2693578e6ebb305e6bf7519f6e86741772892f4d51aLukáš Turek * ath5k_hw_get_clockrate - Get the clock rate for current mode
2703578e6ebb305e6bf7519f6e86741772892f4d51aLukáš Turek *
2713578e6ebb305e6bf7519f6e86741772892f4d51aLukáš Turek * @ah: The &struct ath5k_hw
2723578e6ebb305e6bf7519f6e86741772892f4d51aLukáš Turek */
2733578e6ebb305e6bf7519f6e86741772892f4d51aLukáš Turekunsigned int ath5k_hw_get_clockrate(struct ath5k_hw *ah)
2743578e6ebb305e6bf7519f6e86741772892f4d51aLukáš Turek{
2753578e6ebb305e6bf7519f6e86741772892f4d51aLukáš Turek	struct ieee80211_channel *channel = ah->ah_current_channel;
2763578e6ebb305e6bf7519f6e86741772892f4d51aLukáš Turek	int clock;
2773578e6ebb305e6bf7519f6e86741772892f4d51aLukáš Turek
2783578e6ebb305e6bf7519f6e86741772892f4d51aLukáš Turek	if (channel->hw_value & CHANNEL_5GHZ)
2793578e6ebb305e6bf7519f6e86741772892f4d51aLukáš Turek		clock = 40; /* 802.11a */
2803578e6ebb305e6bf7519f6e86741772892f4d51aLukáš Turek	else if (channel->hw_value & CHANNEL_CCK)
2813578e6ebb305e6bf7519f6e86741772892f4d51aLukáš Turek		clock = 22; /* 802.11b */
2823578e6ebb305e6bf7519f6e86741772892f4d51aLukáš Turek	else
2833578e6ebb305e6bf7519f6e86741772892f4d51aLukáš Turek		clock = 44; /* 802.11g */
2843578e6ebb305e6bf7519f6e86741772892f4d51aLukáš Turek
2853578e6ebb305e6bf7519f6e86741772892f4d51aLukáš Turek	/* Clock rate in turbo modes is twice the normal rate */
2863578e6ebb305e6bf7519f6e86741772892f4d51aLukáš Turek	if (channel->hw_value & CHANNEL_TURBO)
2873578e6ebb305e6bf7519f6e86741772892f4d51aLukáš Turek		clock *= 2;
2883578e6ebb305e6bf7519f6e86741772892f4d51aLukáš Turek
2893578e6ebb305e6bf7519f6e86741772892f4d51aLukáš Turek	return clock;
2903578e6ebb305e6bf7519f6e86741772892f4d51aLukáš Turek}
2913578e6ebb305e6bf7519f6e86741772892f4d51aLukáš Turek
2923578e6ebb305e6bf7519f6e86741772892f4d51aLukáš Turek/**
2936e08d228b6d8e93d7b25b3573c6da7da179c2ae1Lukáš Turek * ath5k_hw_get_default_slottime - Get the default slot time for current mode
2946e08d228b6d8e93d7b25b3573c6da7da179c2ae1Lukáš Turek *
2956e08d228b6d8e93d7b25b3573c6da7da179c2ae1Lukáš Turek * @ah: The &struct ath5k_hw
2966e08d228b6d8e93d7b25b3573c6da7da179c2ae1Lukáš Turek */
297626ede6b1aafb3a8cadfdd04b512fd1d3dc2113ePavel Roskinstatic unsigned int ath5k_hw_get_default_slottime(struct ath5k_hw *ah)
2986e08d228b6d8e93d7b25b3573c6da7da179c2ae1Lukáš Turek{
2996e08d228b6d8e93d7b25b3573c6da7da179c2ae1Lukáš Turek	struct ieee80211_channel *channel = ah->ah_current_channel;
3006e08d228b6d8e93d7b25b3573c6da7da179c2ae1Lukáš Turek
3016e08d228b6d8e93d7b25b3573c6da7da179c2ae1Lukáš Turek	if (channel->hw_value & CHANNEL_TURBO)
3026e08d228b6d8e93d7b25b3573c6da7da179c2ae1Lukáš Turek		return 6; /* both turbo modes */
3036e08d228b6d8e93d7b25b3573c6da7da179c2ae1Lukáš Turek
3046e08d228b6d8e93d7b25b3573c6da7da179c2ae1Lukáš Turek	if (channel->hw_value & CHANNEL_CCK)
3056e08d228b6d8e93d7b25b3573c6da7da179c2ae1Lukáš Turek		return 20; /* 802.11b */
3066e08d228b6d8e93d7b25b3573c6da7da179c2ae1Lukáš Turek
3076e08d228b6d8e93d7b25b3573c6da7da179c2ae1Lukáš Turek	return 9; /* 802.11 a/g */
3086e08d228b6d8e93d7b25b3573c6da7da179c2ae1Lukáš Turek}
3096e08d228b6d8e93d7b25b3573c6da7da179c2ae1Lukáš Turek
3106e08d228b6d8e93d7b25b3573c6da7da179c2ae1Lukáš Turek/**
3116e08d228b6d8e93d7b25b3573c6da7da179c2ae1Lukáš Turek * ath5k_hw_get_default_sifs - Get the default SIFS for current mode
3126e08d228b6d8e93d7b25b3573c6da7da179c2ae1Lukáš Turek *
3136e08d228b6d8e93d7b25b3573c6da7da179c2ae1Lukáš Turek * @ah: The &struct ath5k_hw
3146e08d228b6d8e93d7b25b3573c6da7da179c2ae1Lukáš Turek */
315626ede6b1aafb3a8cadfdd04b512fd1d3dc2113ePavel Roskinstatic unsigned int ath5k_hw_get_default_sifs(struct ath5k_hw *ah)
3166e08d228b6d8e93d7b25b3573c6da7da179c2ae1Lukáš Turek{
3176e08d228b6d8e93d7b25b3573c6da7da179c2ae1Lukáš Turek	struct ieee80211_channel *channel = ah->ah_current_channel;
3186e08d228b6d8e93d7b25b3573c6da7da179c2ae1Lukáš Turek
3196e08d228b6d8e93d7b25b3573c6da7da179c2ae1Lukáš Turek	if (channel->hw_value & CHANNEL_TURBO)
3206e08d228b6d8e93d7b25b3573c6da7da179c2ae1Lukáš Turek		return 8; /* both turbo modes */
3216e08d228b6d8e93d7b25b3573c6da7da179c2ae1Lukáš Turek
3226e08d228b6d8e93d7b25b3573c6da7da179c2ae1Lukáš Turek	if (channel->hw_value & CHANNEL_5GHZ)
3236e08d228b6d8e93d7b25b3573c6da7da179c2ae1Lukáš Turek		return 16; /* 802.11a */
3246e08d228b6d8e93d7b25b3573c6da7da179c2ae1Lukáš Turek
3256e08d228b6d8e93d7b25b3573c6da7da179c2ae1Lukáš Turek	return 10; /* 802.11 b/g */
3266e08d228b6d8e93d7b25b3573c6da7da179c2ae1Lukáš Turek}
3276e08d228b6d8e93d7b25b3573c6da7da179c2ae1Lukáš Turek
3286e08d228b6d8e93d7b25b3573c6da7da179c2ae1Lukáš Turek/**
329c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis * ath5k_hw_set_lladdr - Set station id
330c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis *
331c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis * @ah: The &struct ath5k_hw
332c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis * @mac: The card's mac address
333c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis *
334c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis * Set station id on hw using the provided mac address
335c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis */
336c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidisint ath5k_hw_set_lladdr(struct ath5k_hw *ah, const u8 *mac)
337c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis{
338954fecea5d1df4d1dc7bf9a822a2fad308e8588eLuis R. Rodriguez	struct ath_common *common = ath5k_hw_common(ah);
339c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis	u32 low_id, high_id;
340f6bac3ea5990653765700b2c3778b08782abebe5Bob Copeland	u32 pcu_reg;
341c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis
342c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis	ATH5K_TRACE(ah->ah_sc);
343c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis	/* Set new station ID */
344954fecea5d1df4d1dc7bf9a822a2fad308e8588eLuis R. Rodriguez	memcpy(common->macaddr, mac, ETH_ALEN);
345c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis
346f6bac3ea5990653765700b2c3778b08782abebe5Bob Copeland	pcu_reg = ath5k_hw_reg_read(ah, AR5K_STA_ID1) & 0xffff0000;
347f6bac3ea5990653765700b2c3778b08782abebe5Bob Copeland
348bcd8f54a84ce99ade91c250a9bc850a9fd3389c1Luis R. Rodriguez	low_id = get_unaligned_le32(mac);
349bcd8f54a84ce99ade91c250a9bc850a9fd3389c1Luis R. Rodriguez	high_id = get_unaligned_le16(mac + 4);
350c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis
351c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis	ath5k_hw_reg_write(ah, low_id, AR5K_STA_ID0);
352f6bac3ea5990653765700b2c3778b08782abebe5Bob Copeland	ath5k_hw_reg_write(ah, pcu_reg | high_id, AR5K_STA_ID1);
353c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis
354c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis	return 0;
355c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis}
356c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis
357c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis/**
358c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis * ath5k_hw_set_associd - Set BSSID for association
359c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis *
360c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis * @ah: The &struct ath5k_hw
361c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis * @bssid: BSSID
362c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis * @assoc_id: Assoc id
363c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis *
364c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis * Sets the BSSID which trigers the "SME Join" operation
365c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis */
366be5d6b75e0fb3f7e23ea5325109ef4195f2b282aLuis R. Rodriguezvoid ath5k_hw_set_associd(struct ath5k_hw *ah)
367c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis{
368954fecea5d1df4d1dc7bf9a822a2fad308e8588eLuis R. Rodriguez	struct ath_common *common = ath5k_hw_common(ah);
369c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis	u16 tim_offset = 0;
370c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis
371c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis	/*
372c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis	 * Set simple BSSID mask on 5212
373c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis	 */
374a72d57a862f700edf85da81aae3cd8f923e989a1Luis R. Rodriguez	if (ah->ah_version == AR5K_AR5212)
375a72d57a862f700edf85da81aae3cd8f923e989a1Luis R. Rodriguez		ath_hw_setbssidmask(common);
376c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis
377c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis	/*
378c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis	 * Set BSSID which triggers the "SME Join" operation
379c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis	 */
380abba06869e2546484fa142528737d1a0622add54Luis R. Rodriguez	ath5k_hw_reg_write(ah,
381abba06869e2546484fa142528737d1a0622add54Luis R. Rodriguez			   get_unaligned_le32(common->curbssid),
382a3f86bff1c056f47c2df4c58bfcf7bdda8eaf9d0Luis R. Rodriguez			   AR5K_BSS_ID0);
383abba06869e2546484fa142528737d1a0622add54Luis R. Rodriguez	ath5k_hw_reg_write(ah,
384abba06869e2546484fa142528737d1a0622add54Luis R. Rodriguez			   get_unaligned_le16(common->curbssid + 4) |
385abba06869e2546484fa142528737d1a0622add54Luis R. Rodriguez			   ((common->curaid & 0x3fff) << AR5K_BSS_ID1_AID_S),
386a3f86bff1c056f47c2df4c58bfcf7bdda8eaf9d0Luis R. Rodriguez			   AR5K_BSS_ID1);
387c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis
388be5d6b75e0fb3f7e23ea5325109ef4195f2b282aLuis R. Rodriguez	if (common->curaid == 0) {
389c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis		ath5k_hw_disable_pspoll(ah);
390c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis		return;
391c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis	}
392c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis
393c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis	AR5K_REG_WRITE_BITS(ah, AR5K_BEACON, AR5K_BEACON_TIM,
394abba06869e2546484fa142528737d1a0622add54Luis R. Rodriguez			    tim_offset ? tim_offset + 4 : 0);
395c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis
396c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis	ath5k_hw_enable_pspoll(ah, NULL, 0);
397c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis}
398c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis
39913b81559200b8e54473e5b140323cbb5f2bb21c0Luis R. Rodriguezvoid ath5k_hw_set_bssid_mask(struct ath5k_hw *ah, const u8 *mask)
400c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis{
401954fecea5d1df4d1dc7bf9a822a2fad308e8588eLuis R. Rodriguez	struct ath_common *common = ath5k_hw_common(ah);
402c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis	ATH5K_TRACE(ah->ah_sc);
403c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis
404f07a6c495e88ae0143e3c20b1ed666314197277fNick Kossifidis	/* Cache bssid mask so that we can restore it
405f07a6c495e88ae0143e3c20b1ed666314197277fNick Kossifidis	 * on reset */
406954fecea5d1df4d1dc7bf9a822a2fad308e8588eLuis R. Rodriguez	memcpy(common->bssidmask, mask, ETH_ALEN);
40713b81559200b8e54473e5b140323cbb5f2bb21c0Luis R. Rodriguez	if (ah->ah_version == AR5K_AR5212)
40813b81559200b8e54473e5b140323cbb5f2bb21c0Luis R. Rodriguez		ath_hw_setbssidmask(common);
409c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis}
410c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis
411c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis/************\
412c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis* RX Control *
413c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis\************/
414c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis
415c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis/**
416c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis * ath5k_hw_start_rx_pcu - Start RX engine
417c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis *
418c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis * @ah: The &struct ath5k_hw
419c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis *
420c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis * Starts RX engine on PCU so that hw can process RXed frames
421c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis * (ACK etc).
422c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis *
423c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis * NOTE: RX DMA should be already enabled using ath5k_hw_start_rx_dma
424c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis * TODO: Init ANI here
425c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis */
426c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidisvoid ath5k_hw_start_rx_pcu(struct ath5k_hw *ah)
427c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis{
428c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis	ATH5K_TRACE(ah->ah_sc);
429c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis	AR5K_REG_DISABLE_BITS(ah, AR5K_DIAG_SW, AR5K_DIAG_SW_DIS_RX);
430c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis}
431c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis
432c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis/**
433c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis * at5k_hw_stop_rx_pcu - Stop RX engine
434c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis *
435c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis * @ah: The &struct ath5k_hw
436c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis *
437c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis * Stops RX engine on PCU
438c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis *
439c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis * TODO: Detach ANI here
440c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis */
441c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidisvoid ath5k_hw_stop_rx_pcu(struct ath5k_hw *ah)
442c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis{
443c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis	ATH5K_TRACE(ah->ah_sc);
444c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis	AR5K_REG_ENABLE_BITS(ah, AR5K_DIAG_SW, AR5K_DIAG_SW_DIS_RX);
445c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis}
446c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis
447c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis/*
448c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis * Set multicast filter
449c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis */
450c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidisvoid ath5k_hw_set_mcast_filter(struct ath5k_hw *ah, u32 filter0, u32 filter1)
451c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis{
452c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis	ATH5K_TRACE(ah->ah_sc);
453c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis	/* Set the multicat filter */
454c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis	ath5k_hw_reg_write(ah, filter0, AR5K_MCAST_FILTER0);
455c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis	ath5k_hw_reg_write(ah, filter1, AR5K_MCAST_FILTER1);
456c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis}
457c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis
458626ede6b1aafb3a8cadfdd04b512fd1d3dc2113ePavel Roskin#if 0
459c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis/*
460c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis * Set multicast filter by index
461c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis */
462c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidisint ath5k_hw_set_mcast_filter_idx(struct ath5k_hw *ah, u32 index)
463c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis{
464c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis
465c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis	ATH5K_TRACE(ah->ah_sc);
466c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis	if (index >= 64)
467c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis		return -EINVAL;
468c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis	else if (index >= 32)
469c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis		AR5K_REG_ENABLE_BITS(ah, AR5K_MCAST_FILTER1,
470c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis				(1 << (index - 32)));
471c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis	else
472c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis		AR5K_REG_ENABLE_BITS(ah, AR5K_MCAST_FILTER0, (1 << index));
473c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis
474c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis	return 0;
475c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis}
476c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis
477c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis/*
478c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis * Clear Multicast filter by index
479c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis */
480c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidisint ath5k_hw_clear_mcast_filter_idx(struct ath5k_hw *ah, u32 index)
481c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis{
482c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis
483c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis	ATH5K_TRACE(ah->ah_sc);
484c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis	if (index >= 64)
485c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis		return -EINVAL;
486c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis	else if (index >= 32)
487c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis		AR5K_REG_DISABLE_BITS(ah, AR5K_MCAST_FILTER1,
488c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis				(1 << (index - 32)));
489c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis	else
490c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis		AR5K_REG_DISABLE_BITS(ah, AR5K_MCAST_FILTER0, (1 << index));
491c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis
492c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis	return 0;
493c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis}
494626ede6b1aafb3a8cadfdd04b512fd1d3dc2113ePavel Roskin#endif
495c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis
496c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis/**
497c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis * ath5k_hw_get_rx_filter - Get current rx filter
498c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis *
499c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis * @ah: The &struct ath5k_hw
500c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis *
501c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis * Returns the RX filter by reading rx filter and
502c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis * phy error filter registers. RX filter is used
503c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis * to set the allowed frame types that PCU will accept
504c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis * and pass to the driver. For a list of frame types
505c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis * check out reg.h.
506c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis */
507c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidisu32 ath5k_hw_get_rx_filter(struct ath5k_hw *ah)
508c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis{
509c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis	u32 data, filter = 0;
510c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis
511c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis	ATH5K_TRACE(ah->ah_sc);
512c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis	filter = ath5k_hw_reg_read(ah, AR5K_RX_FILTER);
513c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis
514c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis	/*Radar detection for 5212*/
515c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis	if (ah->ah_version == AR5K_AR5212) {
516c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis		data = ath5k_hw_reg_read(ah, AR5K_PHY_ERR_FIL);
517c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis
518c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis		if (data & AR5K_PHY_ERR_FIL_RADAR)
519c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis			filter |= AR5K_RX_FILTER_RADARERR;
520c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis		if (data & (AR5K_PHY_ERR_FIL_OFDM | AR5K_PHY_ERR_FIL_CCK))
521c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis			filter |= AR5K_RX_FILTER_PHYERR;
522c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis	}
523c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis
524c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis	return filter;
525c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis}
526c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis
527c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis/**
528c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis * ath5k_hw_set_rx_filter - Set rx filter
529c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis *
530c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis * @ah: The &struct ath5k_hw
531c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis * @filter: RX filter mask (see reg.h)
532c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis *
533c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis * Sets RX filter register and also handles PHY error filter
534c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis * register on 5212 and newer chips so that we have proper PHY
535c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis * error reporting.
536c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis */
537c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidisvoid ath5k_hw_set_rx_filter(struct ath5k_hw *ah, u32 filter)
538c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis{
539c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis	u32 data = 0;
540c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis
541c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis	ATH5K_TRACE(ah->ah_sc);
542c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis
543c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis	/* Set PHY error filter register on 5212*/
544c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis	if (ah->ah_version == AR5K_AR5212) {
545c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis		if (filter & AR5K_RX_FILTER_RADARERR)
546c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis			data |= AR5K_PHY_ERR_FIL_RADAR;
547c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis		if (filter & AR5K_RX_FILTER_PHYERR)
548c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis			data |= AR5K_PHY_ERR_FIL_OFDM | AR5K_PHY_ERR_FIL_CCK;
549c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis	}
550c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis
551c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis	/*
552c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis	 * The AR5210 uses promiscous mode to detect radar activity
553c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis	 */
554c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis	if (ah->ah_version == AR5K_AR5210 &&
555c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis			(filter & AR5K_RX_FILTER_RADARERR)) {
556c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis		filter &= ~AR5K_RX_FILTER_RADARERR;
557c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis		filter |= AR5K_RX_FILTER_PROM;
558c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis	}
559c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis
560f07a6c495e88ae0143e3c20b1ed666314197277fNick Kossifidis	/*Zero length DMA (phy error reporting) */
561c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis	if (data)
562c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis		AR5K_REG_ENABLE_BITS(ah, AR5K_RXCFG, AR5K_RXCFG_ZLFDMA);
563c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis	else
564c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis		AR5K_REG_DISABLE_BITS(ah, AR5K_RXCFG, AR5K_RXCFG_ZLFDMA);
565c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis
566c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis	/*Write RX Filter register*/
567c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis	ath5k_hw_reg_write(ah, filter & 0xff, AR5K_RX_FILTER);
568c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis
569c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis	/*Write PHY error filter register on 5212*/
570c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis	if (ah->ah_version == AR5K_AR5212)
571c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis		ath5k_hw_reg_write(ah, data, AR5K_PHY_ERR_FIL);
572c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis
573c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis}
574c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis
575c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis
576c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis/****************\
577c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis* Beacon control *
578c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis\****************/
579c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis
580c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis/**
581c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis * ath5k_hw_get_tsf64 - Get the full 64bit TSF
582c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis *
583c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis * @ah: The &struct ath5k_hw
584c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis *
585c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis * Returns the current TSF
586c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis */
587c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidisu64 ath5k_hw_get_tsf64(struct ath5k_hw *ah)
588c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis{
589c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis	u64 tsf = ath5k_hw_reg_read(ah, AR5K_TSF_U32);
590c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis	ATH5K_TRACE(ah->ah_sc);
591c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis
592c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis	return ath5k_hw_reg_read(ah, AR5K_TSF_L32) | (tsf << 32);
593c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis}
594c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis
595c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis/**
5968cab7581dba90b0519e25784e08feb5dedde737fAlina Friedrichsen * ath5k_hw_set_tsf64 - Set a new 64bit TSF
5978cab7581dba90b0519e25784e08feb5dedde737fAlina Friedrichsen *
5988cab7581dba90b0519e25784e08feb5dedde737fAlina Friedrichsen * @ah: The &struct ath5k_hw
5998cab7581dba90b0519e25784e08feb5dedde737fAlina Friedrichsen * @tsf64: The new 64bit TSF
6008cab7581dba90b0519e25784e08feb5dedde737fAlina Friedrichsen *
6018cab7581dba90b0519e25784e08feb5dedde737fAlina Friedrichsen * Sets the new TSF
6028cab7581dba90b0519e25784e08feb5dedde737fAlina Friedrichsen */
6038cab7581dba90b0519e25784e08feb5dedde737fAlina Friedrichsenvoid ath5k_hw_set_tsf64(struct ath5k_hw *ah, u64 tsf64)
6048cab7581dba90b0519e25784e08feb5dedde737fAlina Friedrichsen{
6058cab7581dba90b0519e25784e08feb5dedde737fAlina Friedrichsen	ATH5K_TRACE(ah->ah_sc);
6068cab7581dba90b0519e25784e08feb5dedde737fAlina Friedrichsen
6078cab7581dba90b0519e25784e08feb5dedde737fAlina Friedrichsen	ath5k_hw_reg_write(ah, tsf64 & 0xffffffff, AR5K_TSF_L32);
6080ad65bd7e1b38dd2c86da5f07dbfa35fe1f03099Alina Friedrichsen	ath5k_hw_reg_write(ah, (tsf64 >> 32) & 0xffffffff, AR5K_TSF_U32);
6098cab7581dba90b0519e25784e08feb5dedde737fAlina Friedrichsen}
6108cab7581dba90b0519e25784e08feb5dedde737fAlina Friedrichsen
6118cab7581dba90b0519e25784e08feb5dedde737fAlina Friedrichsen/**
612c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis * ath5k_hw_reset_tsf - Force a TSF reset
613c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis *
614c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis * @ah: The &struct ath5k_hw
615c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis *
616c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis * Forces a TSF reset on PCU
617c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis */
618c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidisvoid ath5k_hw_reset_tsf(struct ath5k_hw *ah)
619c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis{
62014be9947ef9843102b67d315c7483de112b5b2d7Bob Copeland	u32 val;
62114be9947ef9843102b67d315c7483de112b5b2d7Bob Copeland
622c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis	ATH5K_TRACE(ah->ah_sc);
62314be9947ef9843102b67d315c7483de112b5b2d7Bob Copeland
62414be9947ef9843102b67d315c7483de112b5b2d7Bob Copeland	val = ath5k_hw_reg_read(ah, AR5K_BEACON) | AR5K_BEACON_RESET_TSF;
62514be9947ef9843102b67d315c7483de112b5b2d7Bob Copeland
62614be9947ef9843102b67d315c7483de112b5b2d7Bob Copeland	/*
62714be9947ef9843102b67d315c7483de112b5b2d7Bob Copeland	 * Each write to the RESET_TSF bit toggles a hardware internal
62814be9947ef9843102b67d315c7483de112b5b2d7Bob Copeland	 * signal to reset TSF, but if left high it will cause a TSF reset
62914be9947ef9843102b67d315c7483de112b5b2d7Bob Copeland	 * on the next chip reset as well.  Thus we always write the value
63014be9947ef9843102b67d315c7483de112b5b2d7Bob Copeland	 * twice to clear the signal.
63114be9947ef9843102b67d315c7483de112b5b2d7Bob Copeland	 */
63214be9947ef9843102b67d315c7483de112b5b2d7Bob Copeland	ath5k_hw_reg_write(ah, val, AR5K_BEACON);
63314be9947ef9843102b67d315c7483de112b5b2d7Bob Copeland	ath5k_hw_reg_write(ah, val, AR5K_BEACON);
634c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis}
635c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis
636c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis/*
637c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis * Initialize beacon timers
638c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis */
639c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidisvoid ath5k_hw_init_beacon(struct ath5k_hw *ah, u32 next_beacon, u32 interval)
640c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis{
641c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis	u32 timer1, timer2, timer3;
642c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis
643c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis	ATH5K_TRACE(ah->ah_sc);
644c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis	/*
645c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis	 * Set the additional timers by mode
646c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis	 */
647c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis	switch (ah->ah_op_mode) {
648f07a6c495e88ae0143e3c20b1ed666314197277fNick Kossifidis	case NL80211_IFTYPE_MONITOR:
64905c914fe330fa8e1cc67870dc0d3809dfd96c107Johannes Berg	case NL80211_IFTYPE_STATION:
650f07a6c495e88ae0143e3c20b1ed666314197277fNick Kossifidis		/* In STA mode timer1 is used as next wakeup
651f07a6c495e88ae0143e3c20b1ed666314197277fNick Kossifidis		 * timer and timer2 as next CFP duration start
652f07a6c495e88ae0143e3c20b1ed666314197277fNick Kossifidis		 * timer. Both in 1/8TUs. */
653f07a6c495e88ae0143e3c20b1ed666314197277fNick Kossifidis		/* TODO: PCF handling */
654c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis		if (ah->ah_version == AR5K_AR5210) {
655c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis			timer1 = 0xffffffff;
656c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis			timer2 = 0xffffffff;
657c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis		} else {
658c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis			timer1 = 0x0000ffff;
659c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis			timer2 = 0x0007ffff;
660c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis		}
661f07a6c495e88ae0143e3c20b1ed666314197277fNick Kossifidis		/* Mark associated AP as PCF incapable for now */
662f07a6c495e88ae0143e3c20b1ed666314197277fNick Kossifidis		AR5K_REG_DISABLE_BITS(ah, AR5K_STA_ID1, AR5K_STA_ID1_PCF);
663c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis		break;
664f07a6c495e88ae0143e3c20b1ed666314197277fNick Kossifidis	case NL80211_IFTYPE_ADHOC:
665f07a6c495e88ae0143e3c20b1ed666314197277fNick Kossifidis		AR5K_REG_ENABLE_BITS(ah, AR5K_TXCFG, AR5K_TXCFG_ADHOC_BCN_ATIM);
666c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis	default:
667f07a6c495e88ae0143e3c20b1ed666314197277fNick Kossifidis		/* On non-STA modes timer1 is used as next DMA
668f07a6c495e88ae0143e3c20b1ed666314197277fNick Kossifidis		 * beacon alert (DBA) timer and timer2 as next
669f07a6c495e88ae0143e3c20b1ed666314197277fNick Kossifidis		 * software beacon alert. Both in 1/8TUs. */
670c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis		timer1 = (next_beacon - AR5K_TUNE_DMA_BEACON_RESP) << 3;
671c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis		timer2 = (next_beacon - AR5K_TUNE_SW_BEACON_RESP) << 3;
672f07a6c495e88ae0143e3c20b1ed666314197277fNick Kossifidis		break;
673c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis	}
674c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis
675f07a6c495e88ae0143e3c20b1ed666314197277fNick Kossifidis	/* Timer3 marks the end of our ATIM window
676f07a6c495e88ae0143e3c20b1ed666314197277fNick Kossifidis	 * a zero length window is not allowed because
677f07a6c495e88ae0143e3c20b1ed666314197277fNick Kossifidis	 * we 'll get no beacons */
678c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis	timer3 = next_beacon + (ah->ah_atim_window ? ah->ah_atim_window : 1);
679c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis
680c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis	/*
681c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis	 * Set the beacon register and enable all timers.
682c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis	 */
68335edf8aae8f903b154d658b9a7eed0d5c1a4a814Nick Kossifidis	/* When in AP or Mesh Point mode zero timer0 to start TSF */
68435edf8aae8f903b154d658b9a7eed0d5c1a4a814Nick Kossifidis	if (ah->ah_op_mode == NL80211_IFTYPE_AP ||
68535edf8aae8f903b154d658b9a7eed0d5c1a4a814Nick Kossifidis	    ah->ah_op_mode == NL80211_IFTYPE_MESH_POINT)
686f07a6c495e88ae0143e3c20b1ed666314197277fNick Kossifidis		ath5k_hw_reg_write(ah, 0, AR5K_TIMER0);
687428cbd4ff4d0f2423f49e499f499f04a636cb152Nick Kossifidis
688428cbd4ff4d0f2423f49e499f499f04a636cb152Nick Kossifidis	ath5k_hw_reg_write(ah, next_beacon, AR5K_TIMER0);
689c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis	ath5k_hw_reg_write(ah, timer1, AR5K_TIMER1);
690c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis	ath5k_hw_reg_write(ah, timer2, AR5K_TIMER2);
691c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis	ath5k_hw_reg_write(ah, timer3, AR5K_TIMER3);
692c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis
693f07a6c495e88ae0143e3c20b1ed666314197277fNick Kossifidis	/* Force a TSF reset if requested and enable beacons */
694f07a6c495e88ae0143e3c20b1ed666314197277fNick Kossifidis	if (interval & AR5K_BEACON_RESET_TSF)
695f07a6c495e88ae0143e3c20b1ed666314197277fNick Kossifidis		ath5k_hw_reset_tsf(ah);
696f07a6c495e88ae0143e3c20b1ed666314197277fNick Kossifidis
697c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis	ath5k_hw_reg_write(ah, interval & (AR5K_BEACON_PERIOD |
698f07a6c495e88ae0143e3c20b1ed666314197277fNick Kossifidis					AR5K_BEACON_ENABLE),
699f07a6c495e88ae0143e3c20b1ed666314197277fNick Kossifidis						AR5K_BEACON);
700f07a6c495e88ae0143e3c20b1ed666314197277fNick Kossifidis
701f07a6c495e88ae0143e3c20b1ed666314197277fNick Kossifidis	/* Flush any pending BMISS interrupts on ISR by
702f07a6c495e88ae0143e3c20b1ed666314197277fNick Kossifidis	 * performing a clear-on-write operation on PISR
703f07a6c495e88ae0143e3c20b1ed666314197277fNick Kossifidis	 * register for the BMISS bit (writing a bit on
704f07a6c495e88ae0143e3c20b1ed666314197277fNick Kossifidis	 * ISR togles a reset for that bit and leaves
705f07a6c495e88ae0143e3c20b1ed666314197277fNick Kossifidis	 * the rest bits intact) */
706f07a6c495e88ae0143e3c20b1ed666314197277fNick Kossifidis	if (ah->ah_version == AR5K_AR5210)
707f07a6c495e88ae0143e3c20b1ed666314197277fNick Kossifidis		ath5k_hw_reg_write(ah, AR5K_ISR_BMISS, AR5K_ISR);
708f07a6c495e88ae0143e3c20b1ed666314197277fNick Kossifidis	else
709f07a6c495e88ae0143e3c20b1ed666314197277fNick Kossifidis		ath5k_hw_reg_write(ah, AR5K_ISR_BMISS, AR5K_PISR);
710f07a6c495e88ae0143e3c20b1ed666314197277fNick Kossifidis
711f07a6c495e88ae0143e3c20b1ed666314197277fNick Kossifidis	/* TODO: Set enchanced sleep registers on AR5212
712f07a6c495e88ae0143e3c20b1ed666314197277fNick Kossifidis	 * based on vif->bss_conf params, until then
713f07a6c495e88ae0143e3c20b1ed666314197277fNick Kossifidis	 * disable power save reporting.*/
714f07a6c495e88ae0143e3c20b1ed666314197277fNick Kossifidis	AR5K_REG_DISABLE_BITS(ah, AR5K_STA_ID1, AR5K_STA_ID1_PWR_SV);
715f07a6c495e88ae0143e3c20b1ed666314197277fNick Kossifidis
716c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis}
717c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis
718c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis#if 0
719c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis/*
720c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis * Set beacon timers
721c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis */
722c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidisint ath5k_hw_set_beacon_timers(struct ath5k_hw *ah,
723c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis		const struct ath5k_beacon_state *state)
724c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis{
725c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis	u32 cfp_period, next_cfp, dtim, interval, next_beacon;
726c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis
727c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis	/*
728c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis	 * TODO: should be changed through *state
729c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis	 * review struct ath5k_beacon_state struct
730c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis	 *
731c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis	 * XXX: These are used for cfp period bellow, are they
732c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis	 * ok ? Is it O.K. for tsf here to be 0 or should we use
733c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis	 * get_tsf ?
734c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis	 */
735c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis	u32 dtim_count = 0; /* XXX */
736c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis	u32 cfp_count = 0; /* XXX */
737c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis	u32 tsf = 0; /* XXX */
738c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis
739c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis	ATH5K_TRACE(ah->ah_sc);
740c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis	/* Return on an invalid beacon state */
741c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis	if (state->bs_interval < 1)
742c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis		return -EINVAL;
743c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis
744c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis	interval = state->bs_interval;
745c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis	dtim = state->bs_dtim_period;
746c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis
747c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis	/*
748c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis	 * PCF support?
749c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis	 */
750c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis	if (state->bs_cfp_period > 0) {
751c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis		/*
752c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis		 * Enable PCF mode and set the CFP
753c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis		 * (Contention Free Period) and timer registers
754c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis		 */
755c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis		cfp_period = state->bs_cfp_period * state->bs_dtim_period *
756c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis			state->bs_interval;
757c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis		next_cfp = (cfp_count * state->bs_dtim_period + dtim_count) *
758c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis			state->bs_interval;
759c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis
760c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis		AR5K_REG_ENABLE_BITS(ah, AR5K_STA_ID1,
761c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis				AR5K_STA_ID1_DEFAULT_ANTENNA |
762c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis				AR5K_STA_ID1_PCF);
763c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis		ath5k_hw_reg_write(ah, cfp_period, AR5K_CFP_PERIOD);
764c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis		ath5k_hw_reg_write(ah, state->bs_cfp_max_duration,
765c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis				AR5K_CFP_DUR);
766c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis		ath5k_hw_reg_write(ah, (tsf + (next_cfp == 0 ? cfp_period :
767c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis						next_cfp)) << 3, AR5K_TIMER2);
768c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis	} else {
769c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis		/* Disable PCF mode */
770c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis		AR5K_REG_DISABLE_BITS(ah, AR5K_STA_ID1,
771c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis				AR5K_STA_ID1_DEFAULT_ANTENNA |
772c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis				AR5K_STA_ID1_PCF);
773c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis	}
774c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis
775c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis	/*
776c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis	 * Enable the beacon timer register
777c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis	 */
778c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis	ath5k_hw_reg_write(ah, state->bs_next_beacon, AR5K_TIMER0);
779c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis
780c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis	/*
781c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis	 * Start the beacon timers
782c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis	 */
783c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis	ath5k_hw_reg_write(ah, (ath5k_hw_reg_read(ah, AR5K_BEACON) &
784c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis		~(AR5K_BEACON_PERIOD | AR5K_BEACON_TIM)) |
785c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis		AR5K_REG_SM(state->bs_tim_offset ? state->bs_tim_offset + 4 : 0,
786c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis		AR5K_BEACON_TIM) | AR5K_REG_SM(state->bs_interval,
787c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis		AR5K_BEACON_PERIOD), AR5K_BEACON);
788c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis
789c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis	/*
790c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis	 * Write new beacon miss threshold, if it appears to be valid
791c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis	 * XXX: Figure out right values for min <= bs_bmiss_threshold <= max
792c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis	 * and return if its not in range. We can test this by reading value and
793c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis	 * setting value to a largest value and seeing which values register.
794c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis	 */
795c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis
796c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis	AR5K_REG_WRITE_BITS(ah, AR5K_RSSI_THR, AR5K_RSSI_THR_BMISS,
797c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis			state->bs_bmiss_threshold);
798c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis
799c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis	/*
800c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis	 * Set sleep control register
801c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis	 * XXX: Didn't find this in 5210 code but since this register
802c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis	 * exists also in ar5k's 5210 headers i leave it as common code.
803c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis	 */
804c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis	AR5K_REG_WRITE_BITS(ah, AR5K_SLEEP_CTL, AR5K_SLEEP_CTL_SLDUR,
805c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis			(state->bs_sleep_duration - 3) << 3);
806c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis
807c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis	/*
808c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis	 * Set enhanced sleep registers on 5212
809c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis	 */
810c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis	if (ah->ah_version == AR5K_AR5212) {
811c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis		if (state->bs_sleep_duration > state->bs_interval &&
812c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis				roundup(state->bs_sleep_duration, interval) ==
813c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis				state->bs_sleep_duration)
814c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis			interval = state->bs_sleep_duration;
815c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis
816c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis		if (state->bs_sleep_duration > dtim && (dtim == 0 ||
817c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis				roundup(state->bs_sleep_duration, dtim) ==
818c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis				state->bs_sleep_duration))
819c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis			dtim = state->bs_sleep_duration;
820c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis
821c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis		if (interval > dtim)
822c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis			return -EINVAL;
823c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis
824c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis		next_beacon = interval == dtim ? state->bs_next_dtim :
825c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis			state->bs_next_beacon;
826c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis
827c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis		ath5k_hw_reg_write(ah,
828c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis			AR5K_REG_SM((state->bs_next_dtim - 3) << 3,
829c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis			AR5K_SLEEP0_NEXT_DTIM) |
830c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis			AR5K_REG_SM(10, AR5K_SLEEP0_CABTO) |
831c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis			AR5K_SLEEP0_ENH_SLEEP_EN |
832c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis			AR5K_SLEEP0_ASSUME_DTIM, AR5K_SLEEP0);
833c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis
834c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis		ath5k_hw_reg_write(ah, AR5K_REG_SM((next_beacon - 3) << 3,
835c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis			AR5K_SLEEP1_NEXT_TIM) |
836c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis			AR5K_REG_SM(10, AR5K_SLEEP1_BEACON_TO), AR5K_SLEEP1);
837c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis
838c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis		ath5k_hw_reg_write(ah,
839c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis			AR5K_REG_SM(interval, AR5K_SLEEP2_TIM_PER) |
840c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis			AR5K_REG_SM(dtim, AR5K_SLEEP2_DTIM_PER), AR5K_SLEEP2);
841c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis	}
842c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis
843c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis	return 0;
844c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis}
845c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis
846c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis/*
847c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis * Reset beacon timers
848c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis */
849c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidisvoid ath5k_hw_reset_beacon(struct ath5k_hw *ah)
850c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis{
851c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis	ATH5K_TRACE(ah->ah_sc);
852c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis	/*
853c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis	 * Disable beacon timer
854c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis	 */
855c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis	ath5k_hw_reg_write(ah, 0, AR5K_TIMER0);
856c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis
857c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis	/*
858c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis	 * Disable some beacon register values
859c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis	 */
860c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis	AR5K_REG_DISABLE_BITS(ah, AR5K_STA_ID1,
861c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis			AR5K_STA_ID1_DEFAULT_ANTENNA | AR5K_STA_ID1_PCF);
862c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis	ath5k_hw_reg_write(ah, AR5K_BEACON_PERIOD, AR5K_BEACON);
863c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis}
864c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis
865c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis/*
866c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis * Wait for beacon queue to finish
867c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis */
868c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidisint ath5k_hw_beaconq_finish(struct ath5k_hw *ah, unsigned long phys_addr)
869c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis{
870c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis	unsigned int i;
871c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis	int ret;
872c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis
873c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis	ATH5K_TRACE(ah->ah_sc);
874c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis
875c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis	/* 5210 doesn't have QCU*/
876c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis	if (ah->ah_version == AR5K_AR5210) {
877c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis		/*
878c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis		 * Wait for beaconn queue to finish by checking
879c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis		 * Control Register and Beacon Status Register.
880c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis		 */
881c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis		for (i = AR5K_TUNE_BEACON_INTERVAL / 2; i > 0; i--) {
882c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis			if (!(ath5k_hw_reg_read(ah, AR5K_BSR) & AR5K_BSR_TXQ1F)
883c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis					||
884c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis			    !(ath5k_hw_reg_read(ah, AR5K_CR) & AR5K_BSR_TXQ1F))
885c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis				break;
886c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis			udelay(10);
887c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis		}
888c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis
889c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis		/* Timeout... */
890c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis		if (i <= 0) {
891c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis			/*
892c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis			 * Re-schedule the beacon queue
893c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis			 */
894c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis			ath5k_hw_reg_write(ah, phys_addr, AR5K_NOQCU_TXDP1);
895c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis			ath5k_hw_reg_write(ah, AR5K_BCR_TQ1V | AR5K_BCR_BDMAE,
896c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis					AR5K_BCR);
897c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis
898c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis			return -EIO;
899c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis		}
900c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis		ret = 0;
901c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis	} else {
902c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis	/*5211/5212*/
903c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis		ret = ath5k_hw_register_timeout(ah,
904c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis			AR5K_QUEUE_STATUS(AR5K_TX_QUEUE_ID_BEACON),
905c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis			AR5K_QCU_STS_FRMPENDCNT, 0, false);
906c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis
907c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis		if (AR5K_REG_READ_Q(ah, AR5K_QCU_TXE, AR5K_TX_QUEUE_ID_BEACON))
908c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis			return -EIO;
909c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis	}
910c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis
911c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis	return ret;
912c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis}
913c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis#endif
914c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis
915c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis
916c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis/*********************\
917c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis* Key table functions *
918c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis\*********************/
919c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis
920c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis/*
921c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis * Reset a key entry on the table
922c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis */
923c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidisint ath5k_hw_reset_key(struct ath5k_hw *ah, u16 entry)
924c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis{
925f07a6c495e88ae0143e3c20b1ed666314197277fNick Kossifidis	unsigned int i, type;
92617683c65c8a5f3f29f5408334992986b996d8205Bob Copeland	u16 micentry = entry + AR5K_KEYTABLE_MIC_OFFSET;
927c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis
928c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis	ATH5K_TRACE(ah->ah_sc);
929c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis	AR5K_ASSERT_ENTRY(entry, AR5K_KEYTABLE_SIZE);
930c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis
931f07a6c495e88ae0143e3c20b1ed666314197277fNick Kossifidis	type = ath5k_hw_reg_read(ah, AR5K_KEYTABLE_TYPE(entry));
932f07a6c495e88ae0143e3c20b1ed666314197277fNick Kossifidis
933c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis	for (i = 0; i < AR5K_KEYCACHE_SIZE; i++)
934c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis		ath5k_hw_reg_write(ah, 0, AR5K_KEYTABLE_OFF(entry, i));
935c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis
936f07a6c495e88ae0143e3c20b1ed666314197277fNick Kossifidis	/* Reset associated MIC entry if TKIP
937f07a6c495e88ae0143e3c20b1ed666314197277fNick Kossifidis	 * is enabled located at offset (entry + 64) */
938f07a6c495e88ae0143e3c20b1ed666314197277fNick Kossifidis	if (type == AR5K_KEYTABLE_TYPE_TKIP) {
93917683c65c8a5f3f29f5408334992986b996d8205Bob Copeland		AR5K_ASSERT_ENTRY(micentry, AR5K_KEYTABLE_SIZE);
940f07a6c495e88ae0143e3c20b1ed666314197277fNick Kossifidis		for (i = 0; i < AR5K_KEYCACHE_SIZE / 2 ; i++)
94117683c65c8a5f3f29f5408334992986b996d8205Bob Copeland			ath5k_hw_reg_write(ah, 0,
94217683c65c8a5f3f29f5408334992986b996d8205Bob Copeland				AR5K_KEYTABLE_OFF(micentry, i));
943f07a6c495e88ae0143e3c20b1ed666314197277fNick Kossifidis	}
944f07a6c495e88ae0143e3c20b1ed666314197277fNick Kossifidis
945c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis	/*
946c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis	 * Set NULL encryption on AR5212+
947c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis	 *
948c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis	 * Note: AR5K_KEYTABLE_TYPE -> AR5K_KEYTABLE_OFF(entry, 5)
949c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis	 *       AR5K_KEYTABLE_TYPE_NULL -> 0x00000007
950c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis	 *
951c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis	 * Note2: Windows driver (ndiswrapper) sets this to
952c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis	 *        0x00000714 instead of 0x00000007
953c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis	 */
954ded7a7eaab2a39b7b5c36a2ec3be46f6ebcedba5Jiri Slaby	if (ah->ah_version >= AR5K_AR5211) {
955c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis		ath5k_hw_reg_write(ah, AR5K_KEYTABLE_TYPE_NULL,
956c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis				AR5K_KEYTABLE_TYPE(entry));
957c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis
95817683c65c8a5f3f29f5408334992986b996d8205Bob Copeland		if (type == AR5K_KEYTABLE_TYPE_TKIP) {
95917683c65c8a5f3f29f5408334992986b996d8205Bob Copeland			ath5k_hw_reg_write(ah, AR5K_KEYTABLE_TYPE_NULL,
96017683c65c8a5f3f29f5408334992986b996d8205Bob Copeland				AR5K_KEYTABLE_TYPE(micentry));
96117683c65c8a5f3f29f5408334992986b996d8205Bob Copeland		}
96217683c65c8a5f3f29f5408334992986b996d8205Bob Copeland	}
96317683c65c8a5f3f29f5408334992986b996d8205Bob Copeland
964c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis	return 0;
965c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis}
966c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis
967626ede6b1aafb3a8cadfdd04b512fd1d3dc2113ePavel Roskin#if 0
968c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis/*
969c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis * Check if a table entry is valid
970c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis */
971c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidisint ath5k_hw_is_key_valid(struct ath5k_hw *ah, u16 entry)
972c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis{
973c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis	ATH5K_TRACE(ah->ah_sc);
974c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis	AR5K_ASSERT_ENTRY(entry, AR5K_KEYTABLE_SIZE);
975c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis
976c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis	/* Check the validation flag at the end of the entry */
977c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis	return ath5k_hw_reg_read(ah, AR5K_KEYTABLE_MAC1(entry)) &
978c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis		AR5K_KEYTABLE_VALID;
979c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis}
980626ede6b1aafb3a8cadfdd04b512fd1d3dc2113ePavel Roskin#endif
981c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis
982671434904633876f89be70af415c35c89fb90115Bob Copelandstatic
983671434904633876f89be70af415c35c89fb90115Bob Copelandint ath5k_keycache_type(const struct ieee80211_key_conf *key)
984671434904633876f89be70af415c35c89fb90115Bob Copeland{
985671434904633876f89be70af415c35c89fb90115Bob Copeland	switch (key->alg) {
986671434904633876f89be70af415c35c89fb90115Bob Copeland	case ALG_TKIP:
987671434904633876f89be70af415c35c89fb90115Bob Copeland		return AR5K_KEYTABLE_TYPE_TKIP;
988671434904633876f89be70af415c35c89fb90115Bob Copeland	case ALG_CCMP:
989671434904633876f89be70af415c35c89fb90115Bob Copeland		return AR5K_KEYTABLE_TYPE_CCM;
990671434904633876f89be70af415c35c89fb90115Bob Copeland	case ALG_WEP:
991e31a16d6f64ef0e324c6f54d5112703c3f13a9c4Zhu Yi		if (key->keylen == WLAN_KEY_LEN_WEP40)
992671434904633876f89be70af415c35c89fb90115Bob Copeland			return AR5K_KEYTABLE_TYPE_40;
993e31a16d6f64ef0e324c6f54d5112703c3f13a9c4Zhu Yi		else if (key->keylen == WLAN_KEY_LEN_WEP104)
994671434904633876f89be70af415c35c89fb90115Bob Copeland			return AR5K_KEYTABLE_TYPE_104;
9953cfcf6ac6d69dc290e96416731eea5c88ac7d426Jouni Malinen		return -EINVAL;
9963cfcf6ac6d69dc290e96416731eea5c88ac7d426Jouni Malinen	default:
9973cfcf6ac6d69dc290e96416731eea5c88ac7d426Jouni Malinen		return -EINVAL;
998671434904633876f89be70af415c35c89fb90115Bob Copeland	}
999671434904633876f89be70af415c35c89fb90115Bob Copeland	return -EINVAL;
1000671434904633876f89be70af415c35c89fb90115Bob Copeland}
1001671434904633876f89be70af415c35c89fb90115Bob Copeland
1002c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis/*
1003c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis * Set a key entry on the table
1004c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis */
1005c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidisint ath5k_hw_set_key(struct ath5k_hw *ah, u16 entry,
1006c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis		const struct ieee80211_key_conf *key, const u8 *mac)
1007c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis{
1008c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis	unsigned int i;
10093f64b435ab76e79bfb3b4d36f043e6f892093b71Bob Copeland	int keylen;
1010c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis	__le32 key_v[5] = {};
10113f64b435ab76e79bfb3b4d36f043e6f892093b71Bob Copeland	__le32 key0 = 0, key1 = 0;
10123f64b435ab76e79bfb3b4d36f043e6f892093b71Bob Copeland	__le32 *rxmic, *txmic;
1013672cf3cefe5f686637dec72b9f3d21fe1cdc8c94Roel Kluin	int keytype;
10143f64b435ab76e79bfb3b4d36f043e6f892093b71Bob Copeland	u16 micentry = entry + AR5K_KEYTABLE_MIC_OFFSET;
10153f64b435ab76e79bfb3b4d36f043e6f892093b71Bob Copeland	bool is_tkip;
1016671434904633876f89be70af415c35c89fb90115Bob Copeland	const u8 *key_ptr;
1017c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis
1018c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis	ATH5K_TRACE(ah->ah_sc);
1019c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis
10203f64b435ab76e79bfb3b4d36f043e6f892093b71Bob Copeland	is_tkip = (key->alg == ALG_TKIP);
10213f64b435ab76e79bfb3b4d36f043e6f892093b71Bob Copeland
10223f64b435ab76e79bfb3b4d36f043e6f892093b71Bob Copeland	/*
10233f64b435ab76e79bfb3b4d36f043e6f892093b71Bob Copeland	 * key->keylen comes in from mac80211 in bytes.
10243f64b435ab76e79bfb3b4d36f043e6f892093b71Bob Copeland	 * TKIP is 128 bit + 128 bit mic
10253f64b435ab76e79bfb3b4d36f043e6f892093b71Bob Copeland	 */
10263f64b435ab76e79bfb3b4d36f043e6f892093b71Bob Copeland	keylen = (is_tkip) ? (128 / 8) : key->keylen;
1027c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis
10283f64b435ab76e79bfb3b4d36f043e6f892093b71Bob Copeland	if (entry > AR5K_KEYTABLE_SIZE ||
10293f64b435ab76e79bfb3b4d36f043e6f892093b71Bob Copeland		(is_tkip && micentry > AR5K_KEYTABLE_SIZE))
1030c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis		return -EOPNOTSUPP;
1031c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis
1032671434904633876f89be70af415c35c89fb90115Bob Copeland	if (unlikely(keylen > 16))
1033671434904633876f89be70af415c35c89fb90115Bob Copeland		return -EOPNOTSUPP;
1034c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis
1035671434904633876f89be70af415c35c89fb90115Bob Copeland	keytype = ath5k_keycache_type(key);
1036671434904633876f89be70af415c35c89fb90115Bob Copeland	if (keytype < 0)
1037671434904633876f89be70af415c35c89fb90115Bob Copeland		return keytype;
1038c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis
1039671434904633876f89be70af415c35c89fb90115Bob Copeland	/*
1040671434904633876f89be70af415c35c89fb90115Bob Copeland	 * each key block is 6 bytes wide, written as pairs of
1041671434904633876f89be70af415c35c89fb90115Bob Copeland	 * alternating 32 and 16 bit le values.
1042671434904633876f89be70af415c35c89fb90115Bob Copeland	 */
1043671434904633876f89be70af415c35c89fb90115Bob Copeland	key_ptr = key->key;
1044671434904633876f89be70af415c35c89fb90115Bob Copeland	for (i = 0; keylen >= 6; keylen -= 6) {
1045671434904633876f89be70af415c35c89fb90115Bob Copeland		memcpy(&key_v[i], key_ptr, 6);
1046671434904633876f89be70af415c35c89fb90115Bob Copeland		i += 2;
1047671434904633876f89be70af415c35c89fb90115Bob Copeland		key_ptr += 6;
1048c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis	}
1049671434904633876f89be70af415c35c89fb90115Bob Copeland	if (keylen)
1050671434904633876f89be70af415c35c89fb90115Bob Copeland		memcpy(&key_v[i], key_ptr, keylen);
1051c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis
10523f64b435ab76e79bfb3b4d36f043e6f892093b71Bob Copeland	/* intentionally corrupt key until mic is installed */
10533f64b435ab76e79bfb3b4d36f043e6f892093b71Bob Copeland	if (is_tkip) {
10543f64b435ab76e79bfb3b4d36f043e6f892093b71Bob Copeland		key0 = key_v[0] = ~key_v[0];
10553f64b435ab76e79bfb3b4d36f043e6f892093b71Bob Copeland		key1 = key_v[1] = ~key_v[1];
10563f64b435ab76e79bfb3b4d36f043e6f892093b71Bob Copeland	}
10573f64b435ab76e79bfb3b4d36f043e6f892093b71Bob Copeland
1058c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis	for (i = 0; i < ARRAY_SIZE(key_v); i++)
1059c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis		ath5k_hw_reg_write(ah, le32_to_cpu(key_v[i]),
1060c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis				AR5K_KEYTABLE_OFF(entry, i));
1061c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis
1062c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis	ath5k_hw_reg_write(ah, keytype, AR5K_KEYTABLE_TYPE(entry));
1063c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis
10643f64b435ab76e79bfb3b4d36f043e6f892093b71Bob Copeland	if (is_tkip) {
10653f64b435ab76e79bfb3b4d36f043e6f892093b71Bob Copeland		/* Install rx/tx MIC */
10663f64b435ab76e79bfb3b4d36f043e6f892093b71Bob Copeland		rxmic = (__le32 *) &key->key[16];
10673f64b435ab76e79bfb3b4d36f043e6f892093b71Bob Copeland		txmic = (__le32 *) &key->key[24];
1068f650470a8f506bc33a15778432ebb8cdcf89175bBob Copeland
1069f650470a8f506bc33a15778432ebb8cdcf89175bBob Copeland		if (ah->ah_combined_mic) {
1070f650470a8f506bc33a15778432ebb8cdcf89175bBob Copeland			key_v[0] = rxmic[0];
1071388cdf31db6dfc3d175786a76989266380e12c26Bob Copeland			key_v[1] = cpu_to_le32(le32_to_cpu(txmic[0]) >> 16);
1072f650470a8f506bc33a15778432ebb8cdcf89175bBob Copeland			key_v[2] = rxmic[1];
1073388cdf31db6dfc3d175786a76989266380e12c26Bob Copeland			key_v[3] = cpu_to_le32(le32_to_cpu(txmic[0]) & 0xffff);
1074f650470a8f506bc33a15778432ebb8cdcf89175bBob Copeland			key_v[4] = txmic[1];
1075f650470a8f506bc33a15778432ebb8cdcf89175bBob Copeland		} else {
1076f650470a8f506bc33a15778432ebb8cdcf89175bBob Copeland			key_v[0] = rxmic[0];
1077f650470a8f506bc33a15778432ebb8cdcf89175bBob Copeland			key_v[1] = 0;
1078f650470a8f506bc33a15778432ebb8cdcf89175bBob Copeland			key_v[2] = rxmic[1];
1079f650470a8f506bc33a15778432ebb8cdcf89175bBob Copeland			key_v[3] = 0;
1080f650470a8f506bc33a15778432ebb8cdcf89175bBob Copeland			key_v[4] = 0;
1081f650470a8f506bc33a15778432ebb8cdcf89175bBob Copeland		}
10823f64b435ab76e79bfb3b4d36f043e6f892093b71Bob Copeland		for (i = 0; i < ARRAY_SIZE(key_v); i++)
10833f64b435ab76e79bfb3b4d36f043e6f892093b71Bob Copeland			ath5k_hw_reg_write(ah, le32_to_cpu(key_v[i]),
10843f64b435ab76e79bfb3b4d36f043e6f892093b71Bob Copeland				AR5K_KEYTABLE_OFF(micentry, i));
10853f64b435ab76e79bfb3b4d36f043e6f892093b71Bob Copeland
10863f64b435ab76e79bfb3b4d36f043e6f892093b71Bob Copeland		ath5k_hw_reg_write(ah, AR5K_KEYTABLE_TYPE_NULL,
10873f64b435ab76e79bfb3b4d36f043e6f892093b71Bob Copeland			AR5K_KEYTABLE_TYPE(micentry));
10883f64b435ab76e79bfb3b4d36f043e6f892093b71Bob Copeland		ath5k_hw_reg_write(ah, 0, AR5K_KEYTABLE_MAC0(micentry));
10893f64b435ab76e79bfb3b4d36f043e6f892093b71Bob Copeland		ath5k_hw_reg_write(ah, 0, AR5K_KEYTABLE_MAC1(micentry));
10903f64b435ab76e79bfb3b4d36f043e6f892093b71Bob Copeland
10913f64b435ab76e79bfb3b4d36f043e6f892093b71Bob Copeland		/* restore first 2 words of key */
10923f64b435ab76e79bfb3b4d36f043e6f892093b71Bob Copeland		ath5k_hw_reg_write(ah, le32_to_cpu(~key0),
10933f64b435ab76e79bfb3b4d36f043e6f892093b71Bob Copeland			AR5K_KEYTABLE_OFF(entry, 0));
10943f64b435ab76e79bfb3b4d36f043e6f892093b71Bob Copeland		ath5k_hw_reg_write(ah, le32_to_cpu(~key1),
10953f64b435ab76e79bfb3b4d36f043e6f892093b71Bob Copeland			AR5K_KEYTABLE_OFF(entry, 1));
10963f64b435ab76e79bfb3b4d36f043e6f892093b71Bob Copeland	}
10973f64b435ab76e79bfb3b4d36f043e6f892093b71Bob Copeland
1098c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis	return ath5k_hw_set_key_lladdr(ah, entry, mac);
1099c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis}
1100c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis
1101c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidisint ath5k_hw_set_key_lladdr(struct ath5k_hw *ah, u16 entry, const u8 *mac)
1102c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis{
1103c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis	u32 low_id, high_id;
1104c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis
1105c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis	ATH5K_TRACE(ah->ah_sc);
1106c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis	 /* Invalid entry (key table overflow) */
1107c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis	AR5K_ASSERT_ENTRY(entry, AR5K_KEYTABLE_SIZE);
1108c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis
1109bcd8f54a84ce99ade91c250a9bc850a9fd3389c1Luis R. Rodriguez	/*
1110bcd8f54a84ce99ade91c250a9bc850a9fd3389c1Luis R. Rodriguez	 * MAC may be NULL if it's a broadcast key. In this case no need to
1111bcd8f54a84ce99ade91c250a9bc850a9fd3389c1Luis R. Rodriguez	 * to compute get_unaligned_le32 and get_unaligned_le16 as we
1112bcd8f54a84ce99ade91c250a9bc850a9fd3389c1Luis R. Rodriguez	 * already know it.
1113bcd8f54a84ce99ade91c250a9bc850a9fd3389c1Luis R. Rodriguez	 */
1114dc822b5db479dc0178d5c04cbb656dad0b6564fbJohannes Berg	if (!mac) {
1115c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis		low_id = 0xffffffff;
1116c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis		high_id = 0xffff | AR5K_KEYTABLE_VALID;
1117c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis	} else {
1118bcd8f54a84ce99ade91c250a9bc850a9fd3389c1Luis R. Rodriguez		low_id = get_unaligned_le32(mac);
1119bcd8f54a84ce99ade91c250a9bc850a9fd3389c1Luis R. Rodriguez		high_id = get_unaligned_le16(mac + 4) | AR5K_KEYTABLE_VALID;
1120c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis	}
1121c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis
1122c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis	ath5k_hw_reg_write(ah, low_id, AR5K_KEYTABLE_MAC0(entry));
1123c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis	ath5k_hw_reg_write(ah, high_id, AR5K_KEYTABLE_MAC1(entry));
1124c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis
1125c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis	return 0;
1126c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis}
1127c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis
11286e08d228b6d8e93d7b25b3573c6da7da179c2ae1Lukáš Turek/**
11296e08d228b6d8e93d7b25b3573c6da7da179c2ae1Lukáš Turek * ath5k_hw_set_coverage_class - Set IEEE 802.11 coverage class
11306e08d228b6d8e93d7b25b3573c6da7da179c2ae1Lukáš Turek *
11316e08d228b6d8e93d7b25b3573c6da7da179c2ae1Lukáš Turek * @ah: The &struct ath5k_hw
11326e08d228b6d8e93d7b25b3573c6da7da179c2ae1Lukáš Turek * @coverage_class: IEEE 802.11 coverage class number
11336e08d228b6d8e93d7b25b3573c6da7da179c2ae1Lukáš Turek *
11346e08d228b6d8e93d7b25b3573c6da7da179c2ae1Lukáš Turek * Sets slot time, ACK timeout and CTS timeout for given coverage class.
11356e08d228b6d8e93d7b25b3573c6da7da179c2ae1Lukáš Turek */
11366e08d228b6d8e93d7b25b3573c6da7da179c2ae1Lukáš Turekvoid ath5k_hw_set_coverage_class(struct ath5k_hw *ah, u8 coverage_class)
11376e08d228b6d8e93d7b25b3573c6da7da179c2ae1Lukáš Turek{
11386e08d228b6d8e93d7b25b3573c6da7da179c2ae1Lukáš Turek	/* As defined by IEEE 802.11-2007 17.3.8.6 */
11396e08d228b6d8e93d7b25b3573c6da7da179c2ae1Lukáš Turek	int slot_time = ath5k_hw_get_default_slottime(ah) + 3 * coverage_class;
11406e08d228b6d8e93d7b25b3573c6da7da179c2ae1Lukáš Turek	int ack_timeout = ath5k_hw_get_default_sifs(ah) + slot_time;
11416e08d228b6d8e93d7b25b3573c6da7da179c2ae1Lukáš Turek	int cts_timeout = ack_timeout;
11426e08d228b6d8e93d7b25b3573c6da7da179c2ae1Lukáš Turek
11436e08d228b6d8e93d7b25b3573c6da7da179c2ae1Lukáš Turek	ath5k_hw_set_slot_time(ah, slot_time);
11446e08d228b6d8e93d7b25b3573c6da7da179c2ae1Lukáš Turek	ath5k_hw_set_ack_timeout(ah, ack_timeout);
11456e08d228b6d8e93d7b25b3573c6da7da179c2ae1Lukáš Turek	ath5k_hw_set_cts_timeout(ah, cts_timeout);
11466e08d228b6d8e93d7b25b3573c6da7da179c2ae1Lukáš Turek
11476e08d228b6d8e93d7b25b3573c6da7da179c2ae1Lukáš Turek	ah->ah_coverage_class = coverage_class;
11486e08d228b6d8e93d7b25b3573c6da7da179c2ae1Lukáš Turek}
1149