blob: c7c1fe0237245ea070fa4adbe85ff065faf152df [file] [log] [blame]
Nick Kossifidisc6e387a2008-08-29 22:45:39 +03001/*
2 * Copyright (c) 2004-2008 Reyk Floeter <reyk@openbsd.org>
3 * Copyright (c) 2006-2008 Nick Kossifidis <mickflemm@gmail.com>
4 * Copyright (c) 2007-2008 Matthew W. S. Bell <mentor@madwifi.org>
5 * Copyright (c) 2007-2008 Luis Rodriguez <mcgrof@winlab.rutgers.edu>
6 * Copyright (c) 2007-2008 Pavel Roskin <proski@gnu.org>
7 * Copyright (c) 2007-2008 Jiri Slaby <jirislaby@gmail.com>
8 *
9 * Permission to use, copy, modify, and distribute this software for any
10 * purpose with or without fee is hereby granted, provided that the above
11 * copyright notice and this permission notice appear in all copies.
12 *
13 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
14 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
15 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
16 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
17 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
18 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
19 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
20 *
21 */
22
23/*********************************\
24* Protocol Control Unit Functions *
25\*********************************/
26
Luis R. Rodriguezbcd8f542009-09-09 22:43:17 -070027#include <asm/unaligned.h>
28
Nick Kossifidisc6e387a2008-08-29 22:45:39 +030029#include "ath5k.h"
30#include "reg.h"
31#include "debug.h"
32#include "base.h"
33
34/*******************\
35* Generic functions *
36\*******************/
37
38/**
39 * ath5k_hw_set_opmode - Set PCU operating mode
40 *
41 * @ah: The &struct ath5k_hw
Bruno Randolfccfe5552010-03-09 16:55:38 +090042 * @op_mode: &enum nl80211_iftype operating mode
Nick Kossifidisc6e387a2008-08-29 22:45:39 +030043 *
44 * Initialize PCU for the various operating modes (AP/STA etc)
Nick Kossifidisc6e387a2008-08-29 22:45:39 +030045 */
Bruno Randolfccfe5552010-03-09 16:55:38 +090046int ath5k_hw_set_opmode(struct ath5k_hw *ah, enum nl80211_iftype op_mode)
Nick Kossifidisc6e387a2008-08-29 22:45:39 +030047{
Luis R. Rodriguez954fece2009-09-10 10:51:33 -070048 struct ath_common *common = ath5k_hw_common(ah);
Nick Kossifidisc6e387a2008-08-29 22:45:39 +030049 u32 pcu_reg, beacon_reg, low_id, high_id;
50
Bruno Randolfccfe5552010-03-09 16:55:38 +090051 ATH5K_DBG(ah->ah_sc, ATH5K_DEBUG_MODE, "mode %d\n", op_mode);
Nick Kossifidisf07a6c42008-10-29 04:28:28 +020052
53 /* Preserve rest settings */
54 pcu_reg = ath5k_hw_reg_read(ah, AR5K_STA_ID1) & 0xffff0000;
55 pcu_reg &= ~(AR5K_STA_ID1_ADHOC | AR5K_STA_ID1_AP
56 | AR5K_STA_ID1_KEYSRCH_MODE
57 | (ah->ah_version == AR5K_AR5210 ?
58 (AR5K_STA_ID1_PWR_SV | AR5K_STA_ID1_NO_PSPOLL) : 0));
59
Nick Kossifidisc6e387a2008-08-29 22:45:39 +030060 beacon_reg = 0;
61
62 ATH5K_TRACE(ah->ah_sc);
63
Bruno Randolfccfe5552010-03-09 16:55:38 +090064 switch (op_mode) {
Johannes Berg05c914f2008-09-11 00:01:58 +020065 case NL80211_IFTYPE_ADHOC:
Nick Kossifidisf07a6c42008-10-29 04:28:28 +020066 pcu_reg |= AR5K_STA_ID1_ADHOC | AR5K_STA_ID1_KEYSRCH_MODE;
Nick Kossifidisc6e387a2008-08-29 22:45:39 +030067 beacon_reg |= AR5K_BCR_ADHOC;
Nick Kossifidisf07a6c42008-10-29 04:28:28 +020068 if (ah->ah_version == AR5K_AR5210)
69 pcu_reg |= AR5K_STA_ID1_NO_PSPOLL;
70 else
Steve Brown4fb74042008-12-23 07:57:05 -050071 AR5K_REG_ENABLE_BITS(ah, AR5K_CFG, AR5K_CFG_IBSS);
Nick Kossifidisc6e387a2008-08-29 22:45:39 +030072 break;
73
Johannes Berg05c914f2008-09-11 00:01:58 +020074 case NL80211_IFTYPE_AP:
75 case NL80211_IFTYPE_MESH_POINT:
Nick Kossifidisf07a6c42008-10-29 04:28:28 +020076 pcu_reg |= AR5K_STA_ID1_AP | AR5K_STA_ID1_KEYSRCH_MODE;
Nick Kossifidisc6e387a2008-08-29 22:45:39 +030077 beacon_reg |= AR5K_BCR_AP;
Nick Kossifidisf07a6c42008-10-29 04:28:28 +020078 if (ah->ah_version == AR5K_AR5210)
79 pcu_reg |= AR5K_STA_ID1_NO_PSPOLL;
80 else
Steve Brown4fb74042008-12-23 07:57:05 -050081 AR5K_REG_DISABLE_BITS(ah, AR5K_CFG, AR5K_CFG_IBSS);
Nick Kossifidisc6e387a2008-08-29 22:45:39 +030082 break;
83
Johannes Berg05c914f2008-09-11 00:01:58 +020084 case NL80211_IFTYPE_STATION:
Nick Kossifidisf07a6c42008-10-29 04:28:28 +020085 pcu_reg |= AR5K_STA_ID1_KEYSRCH_MODE
86 | (ah->ah_version == AR5K_AR5210 ?
Nick Kossifidisc6e387a2008-08-29 22:45:39 +030087 AR5K_STA_ID1_PWR_SV : 0);
Johannes Berg05c914f2008-09-11 00:01:58 +020088 case NL80211_IFTYPE_MONITOR:
Nick Kossifidisf07a6c42008-10-29 04:28:28 +020089 pcu_reg |= AR5K_STA_ID1_KEYSRCH_MODE
90 | (ah->ah_version == AR5K_AR5210 ?
Nick Kossifidisc6e387a2008-08-29 22:45:39 +030091 AR5K_STA_ID1_NO_PSPOLL : 0);
92 break;
93
94 default:
95 return -EINVAL;
96 }
97
98 /*
99 * Set PCU registers
100 */
Luis R. Rodriguez954fece2009-09-10 10:51:33 -0700101 low_id = get_unaligned_le32(common->macaddr);
102 high_id = get_unaligned_le16(common->macaddr + 4);
Nick Kossifidisc6e387a2008-08-29 22:45:39 +0300103 ath5k_hw_reg_write(ah, low_id, AR5K_STA_ID0);
104 ath5k_hw_reg_write(ah, pcu_reg | high_id, AR5K_STA_ID1);
105
106 /*
107 * Set Beacon Control Register on 5210
108 */
109 if (ah->ah_version == AR5K_AR5210)
110 ath5k_hw_reg_write(ah, beacon_reg, AR5K_BCR);
111
112 return 0;
113}
114
115/**
Bruno Randolf495391d2010-03-25 14:49:36 +0900116 * ath5k_hw_update - Update MIB counters (mac layer statistics)
Nick Kossifidisc6e387a2008-08-29 22:45:39 +0300117 *
118 * @ah: The &struct ath5k_hw
Nick Kossifidisc6e387a2008-08-29 22:45:39 +0300119 *
Bruno Randolf495391d2010-03-25 14:49:36 +0900120 * Reads MIB counters from PCU and updates sw statistics. Is called after a
121 * MIB interrupt, because one of these counters might have reached their maximum
122 * and triggered the MIB interrupt, to let us read and clear the counter.
123 *
124 * Is called in interrupt context!
Nick Kossifidisc6e387a2008-08-29 22:45:39 +0300125 */
Bruno Randolf495391d2010-03-25 14:49:36 +0900126void ath5k_hw_update_mib_counters(struct ath5k_hw *ah)
Nick Kossifidisc6e387a2008-08-29 22:45:39 +0300127{
Bruno Randolf495391d2010-03-25 14:49:36 +0900128 struct ath5k_statistics *stats = &ah->ah_sc->stats;
Nick Kossifidisc6e387a2008-08-29 22:45:39 +0300129
130 /* Read-And-Clear */
Bruno Randolf495391d2010-03-25 14:49:36 +0900131 stats->ack_fail += ath5k_hw_reg_read(ah, AR5K_ACK_FAIL);
132 stats->rts_fail += ath5k_hw_reg_read(ah, AR5K_RTS_FAIL);
133 stats->rts_ok += ath5k_hw_reg_read(ah, AR5K_RTS_OK);
134 stats->fcs_error += ath5k_hw_reg_read(ah, AR5K_FCS_FAIL);
135 stats->beacons += ath5k_hw_reg_read(ah, AR5K_BEACON_CNT);
Nick Kossifidisc6e387a2008-08-29 22:45:39 +0300136}
137
138/**
139 * ath5k_hw_set_ack_bitrate - set bitrate for ACKs
140 *
141 * @ah: The &struct ath5k_hw
142 * @high: Flag to determine if we want to use high transmition rate
143 * for ACKs or not
144 *
145 * If high flag is set, we tell hw to use a set of control rates based on
146 * the current transmition rate (check out control_rates array inside reset.c).
147 * If not hw just uses the lowest rate available for the current modulation
148 * scheme being used (1Mbit for CCK and 6Mbits for OFDM).
149 */
150void ath5k_hw_set_ack_bitrate_high(struct ath5k_hw *ah, bool high)
151{
152 if (ah->ah_version != AR5K_AR5212)
153 return;
154 else {
155 u32 val = AR5K_STA_ID1_BASE_RATE_11B | AR5K_STA_ID1_ACKCTS_6MB;
156 if (high)
157 AR5K_REG_ENABLE_BITS(ah, AR5K_STA_ID1, val);
158 else
159 AR5K_REG_DISABLE_BITS(ah, AR5K_STA_ID1, val);
160 }
161}
162
163
164/******************\
165* ACK/CTS Timeouts *
166\******************/
167
Nick Kossifidisc6e387a2008-08-29 22:45:39 +0300168/**
169 * ath5k_hw_set_ack_timeout - Set ACK timeout on PCU
170 *
171 * @ah: The &struct ath5k_hw
172 * @timeout: Timeout in usec
173 */
Pavel Roskin626ede62010-02-18 20:28:02 -0500174static int ath5k_hw_set_ack_timeout(struct ath5k_hw *ah, unsigned int timeout)
Nick Kossifidisc6e387a2008-08-29 22:45:39 +0300175{
176 ATH5K_TRACE(ah->ah_sc);
Lukáš Turek3578e6e2009-12-21 22:50:50 +0100177 if (ath5k_hw_clocktoh(ah, AR5K_REG_MS(0xffffffff, AR5K_TIME_OUT_ACK))
178 <= timeout)
Nick Kossifidisc6e387a2008-08-29 22:45:39 +0300179 return -EINVAL;
180
181 AR5K_REG_WRITE_BITS(ah, AR5K_TIME_OUT, AR5K_TIME_OUT_ACK,
Lukáš Turek3578e6e2009-12-21 22:50:50 +0100182 ath5k_hw_htoclock(ah, timeout));
Nick Kossifidisc6e387a2008-08-29 22:45:39 +0300183
184 return 0;
185}
186
Nick Kossifidisc6e387a2008-08-29 22:45:39 +0300187/**
188 * ath5k_hw_set_cts_timeout - Set CTS timeout on PCU
189 *
190 * @ah: The &struct ath5k_hw
191 * @timeout: Timeout in usec
192 */
Pavel Roskin626ede62010-02-18 20:28:02 -0500193static int ath5k_hw_set_cts_timeout(struct ath5k_hw *ah, unsigned int timeout)
Nick Kossifidisc6e387a2008-08-29 22:45:39 +0300194{
195 ATH5K_TRACE(ah->ah_sc);
Lukáš Turek3578e6e2009-12-21 22:50:50 +0100196 if (ath5k_hw_clocktoh(ah, AR5K_REG_MS(0xffffffff, AR5K_TIME_OUT_CTS))
197 <= timeout)
Nick Kossifidisc6e387a2008-08-29 22:45:39 +0300198 return -EINVAL;
199
200 AR5K_REG_WRITE_BITS(ah, AR5K_TIME_OUT, AR5K_TIME_OUT_CTS,
Lukáš Turek3578e6e2009-12-21 22:50:50 +0100201 ath5k_hw_htoclock(ah, timeout));
Nick Kossifidisc6e387a2008-08-29 22:45:39 +0300202
203 return 0;
204}
205
Nick Kossifidisc6e387a2008-08-29 22:45:39 +0300206/**
Lukáš Turek3578e6e2009-12-21 22:50:50 +0100207 * ath5k_hw_htoclock - Translate usec to hw clock units
208 *
209 * @ah: The &struct ath5k_hw
210 * @usec: value in microseconds
211 */
212unsigned int ath5k_hw_htoclock(struct ath5k_hw *ah, unsigned int usec)
213{
214 return usec * ath5k_hw_get_clockrate(ah);
215}
216
217/**
218 * ath5k_hw_clocktoh - Translate hw clock units to usec
219 * @clock: value in hw clock units
220 */
221unsigned int ath5k_hw_clocktoh(struct ath5k_hw *ah, unsigned int clock)
222{
223 return clock / ath5k_hw_get_clockrate(ah);
224}
225
226/**
227 * ath5k_hw_get_clockrate - Get the clock rate for current mode
228 *
229 * @ah: The &struct ath5k_hw
230 */
231unsigned int ath5k_hw_get_clockrate(struct ath5k_hw *ah)
232{
233 struct ieee80211_channel *channel = ah->ah_current_channel;
234 int clock;
235
236 if (channel->hw_value & CHANNEL_5GHZ)
237 clock = 40; /* 802.11a */
238 else if (channel->hw_value & CHANNEL_CCK)
239 clock = 22; /* 802.11b */
240 else
241 clock = 44; /* 802.11g */
242
243 /* Clock rate in turbo modes is twice the normal rate */
244 if (channel->hw_value & CHANNEL_TURBO)
245 clock *= 2;
246
247 return clock;
248}
249
250/**
Lukáš Turek6e08d222009-12-21 22:50:51 +0100251 * ath5k_hw_get_default_slottime - Get the default slot time for current mode
252 *
253 * @ah: The &struct ath5k_hw
254 */
Pavel Roskin626ede62010-02-18 20:28:02 -0500255static unsigned int ath5k_hw_get_default_slottime(struct ath5k_hw *ah)
Lukáš Turek6e08d222009-12-21 22:50:51 +0100256{
257 struct ieee80211_channel *channel = ah->ah_current_channel;
258
259 if (channel->hw_value & CHANNEL_TURBO)
260 return 6; /* both turbo modes */
261
262 if (channel->hw_value & CHANNEL_CCK)
263 return 20; /* 802.11b */
264
265 return 9; /* 802.11 a/g */
266}
267
268/**
269 * ath5k_hw_get_default_sifs - Get the default SIFS for current mode
270 *
271 * @ah: The &struct ath5k_hw
272 */
Pavel Roskin626ede62010-02-18 20:28:02 -0500273static unsigned int ath5k_hw_get_default_sifs(struct ath5k_hw *ah)
Lukáš Turek6e08d222009-12-21 22:50:51 +0100274{
275 struct ieee80211_channel *channel = ah->ah_current_channel;
276
277 if (channel->hw_value & CHANNEL_TURBO)
278 return 8; /* both turbo modes */
279
280 if (channel->hw_value & CHANNEL_5GHZ)
281 return 16; /* 802.11a */
282
283 return 10; /* 802.11 b/g */
284}
285
286/**
Nick Kossifidisc6e387a2008-08-29 22:45:39 +0300287 * ath5k_hw_set_lladdr - Set station id
288 *
289 * @ah: The &struct ath5k_hw
290 * @mac: The card's mac address
291 *
292 * Set station id on hw using the provided mac address
293 */
294int ath5k_hw_set_lladdr(struct ath5k_hw *ah, const u8 *mac)
295{
Luis R. Rodriguez954fece2009-09-10 10:51:33 -0700296 struct ath_common *common = ath5k_hw_common(ah);
Nick Kossifidisc6e387a2008-08-29 22:45:39 +0300297 u32 low_id, high_id;
Bob Copelandf6bac3e2008-11-26 16:17:11 -0500298 u32 pcu_reg;
Nick Kossifidisc6e387a2008-08-29 22:45:39 +0300299
300 ATH5K_TRACE(ah->ah_sc);
301 /* Set new station ID */
Luis R. Rodriguez954fece2009-09-10 10:51:33 -0700302 memcpy(common->macaddr, mac, ETH_ALEN);
Nick Kossifidisc6e387a2008-08-29 22:45:39 +0300303
Bob Copelandf6bac3e2008-11-26 16:17:11 -0500304 pcu_reg = ath5k_hw_reg_read(ah, AR5K_STA_ID1) & 0xffff0000;
305
Luis R. Rodriguezbcd8f542009-09-09 22:43:17 -0700306 low_id = get_unaligned_le32(mac);
307 high_id = get_unaligned_le16(mac + 4);
Nick Kossifidisc6e387a2008-08-29 22:45:39 +0300308
309 ath5k_hw_reg_write(ah, low_id, AR5K_STA_ID0);
Bob Copelandf6bac3e2008-11-26 16:17:11 -0500310 ath5k_hw_reg_write(ah, pcu_reg | high_id, AR5K_STA_ID1);
Nick Kossifidisc6e387a2008-08-29 22:45:39 +0300311
312 return 0;
313}
314
315/**
316 * ath5k_hw_set_associd - Set BSSID for association
317 *
318 * @ah: The &struct ath5k_hw
319 * @bssid: BSSID
320 * @assoc_id: Assoc id
321 *
322 * Sets the BSSID which trigers the "SME Join" operation
323 */
Luis R. Rodriguezbe5d6b72009-10-06 20:44:31 -0400324void ath5k_hw_set_associd(struct ath5k_hw *ah)
Nick Kossifidisc6e387a2008-08-29 22:45:39 +0300325{
Luis R. Rodriguez954fece2009-09-10 10:51:33 -0700326 struct ath_common *common = ath5k_hw_common(ah);
Nick Kossifidisc6e387a2008-08-29 22:45:39 +0300327 u16 tim_offset = 0;
328
329 /*
330 * Set simple BSSID mask on 5212
331 */
Luis R. Rodrigueza72d57a2009-10-06 20:44:29 -0400332 if (ah->ah_version == AR5K_AR5212)
333 ath_hw_setbssidmask(common);
Nick Kossifidisc6e387a2008-08-29 22:45:39 +0300334
335 /*
336 * Set BSSID which triggers the "SME Join" operation
337 */
Luis R. Rodriguezabba0682009-10-06 20:44:32 -0400338 ath5k_hw_reg_write(ah,
339 get_unaligned_le32(common->curbssid),
Luis R. Rodrigueza3f86bf2009-10-06 20:44:33 -0400340 AR5K_BSS_ID0);
Luis R. Rodriguezabba0682009-10-06 20:44:32 -0400341 ath5k_hw_reg_write(ah,
342 get_unaligned_le16(common->curbssid + 4) |
343 ((common->curaid & 0x3fff) << AR5K_BSS_ID1_AID_S),
Luis R. Rodrigueza3f86bf2009-10-06 20:44:33 -0400344 AR5K_BSS_ID1);
Nick Kossifidisc6e387a2008-08-29 22:45:39 +0300345
Luis R. Rodriguezbe5d6b72009-10-06 20:44:31 -0400346 if (common->curaid == 0) {
Nick Kossifidisc6e387a2008-08-29 22:45:39 +0300347 ath5k_hw_disable_pspoll(ah);
348 return;
349 }
350
351 AR5K_REG_WRITE_BITS(ah, AR5K_BEACON, AR5K_BEACON_TIM,
Luis R. Rodriguezabba0682009-10-06 20:44:32 -0400352 tim_offset ? tim_offset + 4 : 0);
Nick Kossifidisc6e387a2008-08-29 22:45:39 +0300353
354 ath5k_hw_enable_pspoll(ah, NULL, 0);
355}
356
Luis R. Rodriguez13b81552009-09-10 17:52:45 -0700357void ath5k_hw_set_bssid_mask(struct ath5k_hw *ah, const u8 *mask)
Nick Kossifidisc6e387a2008-08-29 22:45:39 +0300358{
Luis R. Rodriguez954fece2009-09-10 10:51:33 -0700359 struct ath_common *common = ath5k_hw_common(ah);
Nick Kossifidisc6e387a2008-08-29 22:45:39 +0300360 ATH5K_TRACE(ah->ah_sc);
361
Nick Kossifidisf07a6c42008-10-29 04:28:28 +0200362 /* Cache bssid mask so that we can restore it
363 * on reset */
Luis R. Rodriguez954fece2009-09-10 10:51:33 -0700364 memcpy(common->bssidmask, mask, ETH_ALEN);
Luis R. Rodriguez13b81552009-09-10 17:52:45 -0700365 if (ah->ah_version == AR5K_AR5212)
366 ath_hw_setbssidmask(common);
Nick Kossifidisc6e387a2008-08-29 22:45:39 +0300367}
368
Nick Kossifidisc6e387a2008-08-29 22:45:39 +0300369/************\
370* RX Control *
371\************/
372
373/**
374 * ath5k_hw_start_rx_pcu - Start RX engine
375 *
376 * @ah: The &struct ath5k_hw
377 *
378 * Starts RX engine on PCU so that hw can process RXed frames
379 * (ACK etc).
380 *
381 * NOTE: RX DMA should be already enabled using ath5k_hw_start_rx_dma
382 * TODO: Init ANI here
383 */
384void ath5k_hw_start_rx_pcu(struct ath5k_hw *ah)
385{
386 ATH5K_TRACE(ah->ah_sc);
387 AR5K_REG_DISABLE_BITS(ah, AR5K_DIAG_SW, AR5K_DIAG_SW_DIS_RX);
388}
389
390/**
391 * at5k_hw_stop_rx_pcu - Stop RX engine
392 *
393 * @ah: The &struct ath5k_hw
394 *
395 * Stops RX engine on PCU
396 *
397 * TODO: Detach ANI here
398 */
399void ath5k_hw_stop_rx_pcu(struct ath5k_hw *ah)
400{
401 ATH5K_TRACE(ah->ah_sc);
402 AR5K_REG_ENABLE_BITS(ah, AR5K_DIAG_SW, AR5K_DIAG_SW_DIS_RX);
403}
404
405/*
406 * Set multicast filter
407 */
408void ath5k_hw_set_mcast_filter(struct ath5k_hw *ah, u32 filter0, u32 filter1)
409{
410 ATH5K_TRACE(ah->ah_sc);
411 /* Set the multicat filter */
412 ath5k_hw_reg_write(ah, filter0, AR5K_MCAST_FILTER0);
413 ath5k_hw_reg_write(ah, filter1, AR5K_MCAST_FILTER1);
414}
415
Nick Kossifidisc6e387a2008-08-29 22:45:39 +0300416/**
417 * ath5k_hw_get_rx_filter - Get current rx filter
418 *
419 * @ah: The &struct ath5k_hw
420 *
421 * Returns the RX filter by reading rx filter and
422 * phy error filter registers. RX filter is used
423 * to set the allowed frame types that PCU will accept
424 * and pass to the driver. For a list of frame types
425 * check out reg.h.
426 */
427u32 ath5k_hw_get_rx_filter(struct ath5k_hw *ah)
428{
429 u32 data, filter = 0;
430
431 ATH5K_TRACE(ah->ah_sc);
432 filter = ath5k_hw_reg_read(ah, AR5K_RX_FILTER);
433
434 /*Radar detection for 5212*/
435 if (ah->ah_version == AR5K_AR5212) {
436 data = ath5k_hw_reg_read(ah, AR5K_PHY_ERR_FIL);
437
438 if (data & AR5K_PHY_ERR_FIL_RADAR)
439 filter |= AR5K_RX_FILTER_RADARERR;
440 if (data & (AR5K_PHY_ERR_FIL_OFDM | AR5K_PHY_ERR_FIL_CCK))
441 filter |= AR5K_RX_FILTER_PHYERR;
442 }
443
444 return filter;
445}
446
447/**
448 * ath5k_hw_set_rx_filter - Set rx filter
449 *
450 * @ah: The &struct ath5k_hw
451 * @filter: RX filter mask (see reg.h)
452 *
453 * Sets RX filter register and also handles PHY error filter
454 * register on 5212 and newer chips so that we have proper PHY
455 * error reporting.
456 */
457void ath5k_hw_set_rx_filter(struct ath5k_hw *ah, u32 filter)
458{
459 u32 data = 0;
460
461 ATH5K_TRACE(ah->ah_sc);
462
463 /* Set PHY error filter register on 5212*/
464 if (ah->ah_version == AR5K_AR5212) {
465 if (filter & AR5K_RX_FILTER_RADARERR)
466 data |= AR5K_PHY_ERR_FIL_RADAR;
467 if (filter & AR5K_RX_FILTER_PHYERR)
468 data |= AR5K_PHY_ERR_FIL_OFDM | AR5K_PHY_ERR_FIL_CCK;
469 }
470
471 /*
472 * The AR5210 uses promiscous mode to detect radar activity
473 */
474 if (ah->ah_version == AR5K_AR5210 &&
475 (filter & AR5K_RX_FILTER_RADARERR)) {
476 filter &= ~AR5K_RX_FILTER_RADARERR;
477 filter |= AR5K_RX_FILTER_PROM;
478 }
479
Nick Kossifidisf07a6c42008-10-29 04:28:28 +0200480 /*Zero length DMA (phy error reporting) */
Nick Kossifidisc6e387a2008-08-29 22:45:39 +0300481 if (data)
482 AR5K_REG_ENABLE_BITS(ah, AR5K_RXCFG, AR5K_RXCFG_ZLFDMA);
483 else
484 AR5K_REG_DISABLE_BITS(ah, AR5K_RXCFG, AR5K_RXCFG_ZLFDMA);
485
486 /*Write RX Filter register*/
487 ath5k_hw_reg_write(ah, filter & 0xff, AR5K_RX_FILTER);
488
489 /*Write PHY error filter register on 5212*/
490 if (ah->ah_version == AR5K_AR5212)
491 ath5k_hw_reg_write(ah, data, AR5K_PHY_ERR_FIL);
492
493}
494
495
496/****************\
497* Beacon control *
498\****************/
499
500/**
Nick Kossifidisc6e387a2008-08-29 22:45:39 +0300501 * ath5k_hw_get_tsf64 - Get the full 64bit TSF
502 *
503 * @ah: The &struct ath5k_hw
504 *
505 * Returns the current TSF
506 */
507u64 ath5k_hw_get_tsf64(struct ath5k_hw *ah)
508{
509 u64 tsf = ath5k_hw_reg_read(ah, AR5K_TSF_U32);
510 ATH5K_TRACE(ah->ah_sc);
511
512 return ath5k_hw_reg_read(ah, AR5K_TSF_L32) | (tsf << 32);
513}
514
515/**
Alina Friedrichsen8cab7582009-01-23 05:39:13 +0100516 * ath5k_hw_set_tsf64 - Set a new 64bit TSF
517 *
518 * @ah: The &struct ath5k_hw
519 * @tsf64: The new 64bit TSF
520 *
521 * Sets the new TSF
522 */
523void ath5k_hw_set_tsf64(struct ath5k_hw *ah, u64 tsf64)
524{
525 ATH5K_TRACE(ah->ah_sc);
526
Alina Friedrichsen8cab7582009-01-23 05:39:13 +0100527 ath5k_hw_reg_write(ah, tsf64 & 0xffffffff, AR5K_TSF_L32);
Alina Friedrichsen0ad65bd2009-03-02 23:29:48 +0100528 ath5k_hw_reg_write(ah, (tsf64 >> 32) & 0xffffffff, AR5K_TSF_U32);
Alina Friedrichsen8cab7582009-01-23 05:39:13 +0100529}
530
531/**
Nick Kossifidisc6e387a2008-08-29 22:45:39 +0300532 * ath5k_hw_reset_tsf - Force a TSF reset
533 *
534 * @ah: The &struct ath5k_hw
535 *
536 * Forces a TSF reset on PCU
537 */
538void ath5k_hw_reset_tsf(struct ath5k_hw *ah)
539{
Bob Copeland14be9942008-09-28 12:09:43 -0400540 u32 val;
541
Nick Kossifidisc6e387a2008-08-29 22:45:39 +0300542 ATH5K_TRACE(ah->ah_sc);
Bob Copeland14be9942008-09-28 12:09:43 -0400543
544 val = ath5k_hw_reg_read(ah, AR5K_BEACON) | AR5K_BEACON_RESET_TSF;
545
546 /*
547 * Each write to the RESET_TSF bit toggles a hardware internal
548 * signal to reset TSF, but if left high it will cause a TSF reset
549 * on the next chip reset as well. Thus we always write the value
550 * twice to clear the signal.
551 */
552 ath5k_hw_reg_write(ah, val, AR5K_BEACON);
553 ath5k_hw_reg_write(ah, val, AR5K_BEACON);
Nick Kossifidisc6e387a2008-08-29 22:45:39 +0300554}
555
556/*
557 * Initialize beacon timers
558 */
559void ath5k_hw_init_beacon(struct ath5k_hw *ah, u32 next_beacon, u32 interval)
560{
561 u32 timer1, timer2, timer3;
562
563 ATH5K_TRACE(ah->ah_sc);
564 /*
565 * Set the additional timers by mode
566 */
Bruno Randolfccfe5552010-03-09 16:55:38 +0900567 switch (ah->ah_sc->opmode) {
Nick Kossifidisf07a6c42008-10-29 04:28:28 +0200568 case NL80211_IFTYPE_MONITOR:
Johannes Berg05c914f2008-09-11 00:01:58 +0200569 case NL80211_IFTYPE_STATION:
Nick Kossifidisf07a6c42008-10-29 04:28:28 +0200570 /* In STA mode timer1 is used as next wakeup
571 * timer and timer2 as next CFP duration start
572 * timer. Both in 1/8TUs. */
573 /* TODO: PCF handling */
Nick Kossifidisc6e387a2008-08-29 22:45:39 +0300574 if (ah->ah_version == AR5K_AR5210) {
575 timer1 = 0xffffffff;
576 timer2 = 0xffffffff;
577 } else {
578 timer1 = 0x0000ffff;
579 timer2 = 0x0007ffff;
580 }
Nick Kossifidisf07a6c42008-10-29 04:28:28 +0200581 /* Mark associated AP as PCF incapable for now */
582 AR5K_REG_DISABLE_BITS(ah, AR5K_STA_ID1, AR5K_STA_ID1_PCF);
Nick Kossifidisc6e387a2008-08-29 22:45:39 +0300583 break;
Nick Kossifidisf07a6c42008-10-29 04:28:28 +0200584 case NL80211_IFTYPE_ADHOC:
585 AR5K_REG_ENABLE_BITS(ah, AR5K_TXCFG, AR5K_TXCFG_ADHOC_BCN_ATIM);
Nick Kossifidisc6e387a2008-08-29 22:45:39 +0300586 default:
Nick Kossifidisf07a6c42008-10-29 04:28:28 +0200587 /* On non-STA modes timer1 is used as next DMA
588 * beacon alert (DBA) timer and timer2 as next
589 * software beacon alert. Both in 1/8TUs. */
Nick Kossifidisc6e387a2008-08-29 22:45:39 +0300590 timer1 = (next_beacon - AR5K_TUNE_DMA_BEACON_RESP) << 3;
591 timer2 = (next_beacon - AR5K_TUNE_SW_BEACON_RESP) << 3;
Nick Kossifidisf07a6c42008-10-29 04:28:28 +0200592 break;
Nick Kossifidisc6e387a2008-08-29 22:45:39 +0300593 }
594
Nick Kossifidisf07a6c42008-10-29 04:28:28 +0200595 /* Timer3 marks the end of our ATIM window
596 * a zero length window is not allowed because
597 * we 'll get no beacons */
Nick Kossifidisc6e387a2008-08-29 22:45:39 +0300598 timer3 = next_beacon + (ah->ah_atim_window ? ah->ah_atim_window : 1);
599
600 /*
601 * Set the beacon register and enable all timers.
Nick Kossifidisc6e387a2008-08-29 22:45:39 +0300602 */
Nick Kossifidis35edf8a2009-06-12 16:09:53 -0700603 /* When in AP or Mesh Point mode zero timer0 to start TSF */
Bruno Randolfccfe5552010-03-09 16:55:38 +0900604 if (ah->ah_sc->opmode == NL80211_IFTYPE_AP ||
605 ah->ah_sc->opmode == NL80211_IFTYPE_MESH_POINT)
Nick Kossifidisf07a6c42008-10-29 04:28:28 +0200606 ath5k_hw_reg_write(ah, 0, AR5K_TIMER0);
Nick Kossifidis428cbd42009-04-30 15:55:47 -0400607
608 ath5k_hw_reg_write(ah, next_beacon, AR5K_TIMER0);
Nick Kossifidisc6e387a2008-08-29 22:45:39 +0300609 ath5k_hw_reg_write(ah, timer1, AR5K_TIMER1);
610 ath5k_hw_reg_write(ah, timer2, AR5K_TIMER2);
611 ath5k_hw_reg_write(ah, timer3, AR5K_TIMER3);
612
Nick Kossifidisf07a6c42008-10-29 04:28:28 +0200613 /* Force a TSF reset if requested and enable beacons */
614 if (interval & AR5K_BEACON_RESET_TSF)
615 ath5k_hw_reset_tsf(ah);
616
Nick Kossifidisc6e387a2008-08-29 22:45:39 +0300617 ath5k_hw_reg_write(ah, interval & (AR5K_BEACON_PERIOD |
Nick Kossifidisf07a6c42008-10-29 04:28:28 +0200618 AR5K_BEACON_ENABLE),
619 AR5K_BEACON);
620
621 /* Flush any pending BMISS interrupts on ISR by
622 * performing a clear-on-write operation on PISR
623 * register for the BMISS bit (writing a bit on
624 * ISR togles a reset for that bit and leaves
625 * the rest bits intact) */
626 if (ah->ah_version == AR5K_AR5210)
627 ath5k_hw_reg_write(ah, AR5K_ISR_BMISS, AR5K_ISR);
628 else
629 ath5k_hw_reg_write(ah, AR5K_ISR_BMISS, AR5K_PISR);
630
631 /* TODO: Set enchanced sleep registers on AR5212
632 * based on vif->bss_conf params, until then
633 * disable power save reporting.*/
634 AR5K_REG_DISABLE_BITS(ah, AR5K_STA_ID1, AR5K_STA_ID1_PWR_SV);
635
Nick Kossifidisc6e387a2008-08-29 22:45:39 +0300636}
637
Nick Kossifidisc6e387a2008-08-29 22:45:39 +0300638
639/*********************\
640* Key table functions *
641\*********************/
642
643/*
644 * Reset a key entry on the table
645 */
646int ath5k_hw_reset_key(struct ath5k_hw *ah, u16 entry)
647{
Nick Kossifidisf07a6c42008-10-29 04:28:28 +0200648 unsigned int i, type;
Bob Copeland17683c62008-10-29 23:24:26 -0400649 u16 micentry = entry + AR5K_KEYTABLE_MIC_OFFSET;
Nick Kossifidisc6e387a2008-08-29 22:45:39 +0300650
651 ATH5K_TRACE(ah->ah_sc);
652 AR5K_ASSERT_ENTRY(entry, AR5K_KEYTABLE_SIZE);
653
Nick Kossifidisf07a6c42008-10-29 04:28:28 +0200654 type = ath5k_hw_reg_read(ah, AR5K_KEYTABLE_TYPE(entry));
655
Nick Kossifidisc6e387a2008-08-29 22:45:39 +0300656 for (i = 0; i < AR5K_KEYCACHE_SIZE; i++)
657 ath5k_hw_reg_write(ah, 0, AR5K_KEYTABLE_OFF(entry, i));
658
Nick Kossifidisf07a6c42008-10-29 04:28:28 +0200659 /* Reset associated MIC entry if TKIP
660 * is enabled located at offset (entry + 64) */
661 if (type == AR5K_KEYTABLE_TYPE_TKIP) {
Bob Copeland17683c62008-10-29 23:24:26 -0400662 AR5K_ASSERT_ENTRY(micentry, AR5K_KEYTABLE_SIZE);
Nick Kossifidisf07a6c42008-10-29 04:28:28 +0200663 for (i = 0; i < AR5K_KEYCACHE_SIZE / 2 ; i++)
Bob Copeland17683c62008-10-29 23:24:26 -0400664 ath5k_hw_reg_write(ah, 0,
665 AR5K_KEYTABLE_OFF(micentry, i));
Nick Kossifidisf07a6c42008-10-29 04:28:28 +0200666 }
667
Nick Kossifidisc6e387a2008-08-29 22:45:39 +0300668 /*
669 * Set NULL encryption on AR5212+
670 *
671 * Note: AR5K_KEYTABLE_TYPE -> AR5K_KEYTABLE_OFF(entry, 5)
672 * AR5K_KEYTABLE_TYPE_NULL -> 0x00000007
673 *
674 * Note2: Windows driver (ndiswrapper) sets this to
675 * 0x00000714 instead of 0x00000007
676 */
Jiri Slabyded7a7e2009-04-25 14:09:23 +0200677 if (ah->ah_version >= AR5K_AR5211) {
Nick Kossifidisc6e387a2008-08-29 22:45:39 +0300678 ath5k_hw_reg_write(ah, AR5K_KEYTABLE_TYPE_NULL,
679 AR5K_KEYTABLE_TYPE(entry));
680
Bob Copeland17683c62008-10-29 23:24:26 -0400681 if (type == AR5K_KEYTABLE_TYPE_TKIP) {
682 ath5k_hw_reg_write(ah, AR5K_KEYTABLE_TYPE_NULL,
683 AR5K_KEYTABLE_TYPE(micentry));
684 }
685 }
686
Nick Kossifidisc6e387a2008-08-29 22:45:39 +0300687 return 0;
688}
689
Bob Copeland67143492008-11-25 20:55:21 -0500690static
691int ath5k_keycache_type(const struct ieee80211_key_conf *key)
692{
693 switch (key->alg) {
694 case ALG_TKIP:
695 return AR5K_KEYTABLE_TYPE_TKIP;
696 case ALG_CCMP:
697 return AR5K_KEYTABLE_TYPE_CCM;
698 case ALG_WEP:
Zhu Yie31a16d2009-05-21 21:47:03 +0800699 if (key->keylen == WLAN_KEY_LEN_WEP40)
Bob Copeland67143492008-11-25 20:55:21 -0500700 return AR5K_KEYTABLE_TYPE_40;
Zhu Yie31a16d2009-05-21 21:47:03 +0800701 else if (key->keylen == WLAN_KEY_LEN_WEP104)
Bob Copeland67143492008-11-25 20:55:21 -0500702 return AR5K_KEYTABLE_TYPE_104;
Jouni Malinen3cfcf6ac2009-01-08 13:32:02 +0200703 return -EINVAL;
704 default:
705 return -EINVAL;
Bob Copeland67143492008-11-25 20:55:21 -0500706 }
707 return -EINVAL;
708}
709
Nick Kossifidisc6e387a2008-08-29 22:45:39 +0300710/*
711 * Set a key entry on the table
712 */
713int ath5k_hw_set_key(struct ath5k_hw *ah, u16 entry,
714 const struct ieee80211_key_conf *key, const u8 *mac)
715{
716 unsigned int i;
Bob Copeland3f64b432008-10-29 23:19:14 -0400717 int keylen;
Nick Kossifidisc6e387a2008-08-29 22:45:39 +0300718 __le32 key_v[5] = {};
Bob Copeland3f64b432008-10-29 23:19:14 -0400719 __le32 key0 = 0, key1 = 0;
720 __le32 *rxmic, *txmic;
Roel Kluin672cf3c2009-01-18 23:50:27 +0100721 int keytype;
Bob Copeland3f64b432008-10-29 23:19:14 -0400722 u16 micentry = entry + AR5K_KEYTABLE_MIC_OFFSET;
723 bool is_tkip;
Bob Copeland67143492008-11-25 20:55:21 -0500724 const u8 *key_ptr;
Nick Kossifidisc6e387a2008-08-29 22:45:39 +0300725
726 ATH5K_TRACE(ah->ah_sc);
727
Bob Copeland3f64b432008-10-29 23:19:14 -0400728 is_tkip = (key->alg == ALG_TKIP);
Nick Kossifidisc6e387a2008-08-29 22:45:39 +0300729
Bob Copeland3f64b432008-10-29 23:19:14 -0400730 /*
731 * key->keylen comes in from mac80211 in bytes.
732 * TKIP is 128 bit + 128 bit mic
733 */
734 keylen = (is_tkip) ? (128 / 8) : key->keylen;
735
736 if (entry > AR5K_KEYTABLE_SIZE ||
737 (is_tkip && micentry > AR5K_KEYTABLE_SIZE))
Nick Kossifidisc6e387a2008-08-29 22:45:39 +0300738 return -EOPNOTSUPP;
739
Bob Copeland67143492008-11-25 20:55:21 -0500740 if (unlikely(keylen > 16))
741 return -EOPNOTSUPP;
Nick Kossifidisc6e387a2008-08-29 22:45:39 +0300742
Bob Copeland67143492008-11-25 20:55:21 -0500743 keytype = ath5k_keycache_type(key);
744 if (keytype < 0)
745 return keytype;
Nick Kossifidisc6e387a2008-08-29 22:45:39 +0300746
Bob Copeland67143492008-11-25 20:55:21 -0500747 /*
748 * each key block is 6 bytes wide, written as pairs of
749 * alternating 32 and 16 bit le values.
750 */
751 key_ptr = key->key;
752 for (i = 0; keylen >= 6; keylen -= 6) {
753 memcpy(&key_v[i], key_ptr, 6);
754 i += 2;
755 key_ptr += 6;
Nick Kossifidisc6e387a2008-08-29 22:45:39 +0300756 }
Bob Copeland67143492008-11-25 20:55:21 -0500757 if (keylen)
758 memcpy(&key_v[i], key_ptr, keylen);
Nick Kossifidisc6e387a2008-08-29 22:45:39 +0300759
Bob Copeland3f64b432008-10-29 23:19:14 -0400760 /* intentionally corrupt key until mic is installed */
761 if (is_tkip) {
762 key0 = key_v[0] = ~key_v[0];
763 key1 = key_v[1] = ~key_v[1];
764 }
765
Nick Kossifidisc6e387a2008-08-29 22:45:39 +0300766 for (i = 0; i < ARRAY_SIZE(key_v); i++)
767 ath5k_hw_reg_write(ah, le32_to_cpu(key_v[i]),
768 AR5K_KEYTABLE_OFF(entry, i));
769
770 ath5k_hw_reg_write(ah, keytype, AR5K_KEYTABLE_TYPE(entry));
771
Bob Copeland3f64b432008-10-29 23:19:14 -0400772 if (is_tkip) {
773 /* Install rx/tx MIC */
774 rxmic = (__le32 *) &key->key[16];
775 txmic = (__le32 *) &key->key[24];
Bob Copelandf6504702008-11-26 16:17:25 -0500776
777 if (ah->ah_combined_mic) {
778 key_v[0] = rxmic[0];
Bob Copeland388cdf32008-12-09 23:05:38 -0500779 key_v[1] = cpu_to_le32(le32_to_cpu(txmic[0]) >> 16);
Bob Copelandf6504702008-11-26 16:17:25 -0500780 key_v[2] = rxmic[1];
Bob Copeland388cdf32008-12-09 23:05:38 -0500781 key_v[3] = cpu_to_le32(le32_to_cpu(txmic[0]) & 0xffff);
Bob Copelandf6504702008-11-26 16:17:25 -0500782 key_v[4] = txmic[1];
783 } else {
784 key_v[0] = rxmic[0];
785 key_v[1] = 0;
786 key_v[2] = rxmic[1];
787 key_v[3] = 0;
788 key_v[4] = 0;
789 }
Bob Copeland3f64b432008-10-29 23:19:14 -0400790 for (i = 0; i < ARRAY_SIZE(key_v); i++)
791 ath5k_hw_reg_write(ah, le32_to_cpu(key_v[i]),
792 AR5K_KEYTABLE_OFF(micentry, i));
793
794 ath5k_hw_reg_write(ah, AR5K_KEYTABLE_TYPE_NULL,
795 AR5K_KEYTABLE_TYPE(micentry));
796 ath5k_hw_reg_write(ah, 0, AR5K_KEYTABLE_MAC0(micentry));
797 ath5k_hw_reg_write(ah, 0, AR5K_KEYTABLE_MAC1(micentry));
798
799 /* restore first 2 words of key */
800 ath5k_hw_reg_write(ah, le32_to_cpu(~key0),
801 AR5K_KEYTABLE_OFF(entry, 0));
802 ath5k_hw_reg_write(ah, le32_to_cpu(~key1),
803 AR5K_KEYTABLE_OFF(entry, 1));
804 }
805
Nick Kossifidisc6e387a2008-08-29 22:45:39 +0300806 return ath5k_hw_set_key_lladdr(ah, entry, mac);
807}
808
809int ath5k_hw_set_key_lladdr(struct ath5k_hw *ah, u16 entry, const u8 *mac)
810{
811 u32 low_id, high_id;
812
813 ATH5K_TRACE(ah->ah_sc);
814 /* Invalid entry (key table overflow) */
815 AR5K_ASSERT_ENTRY(entry, AR5K_KEYTABLE_SIZE);
816
Luis R. Rodriguezbcd8f542009-09-09 22:43:17 -0700817 /*
818 * MAC may be NULL if it's a broadcast key. In this case no need to
819 * to compute get_unaligned_le32 and get_unaligned_le16 as we
820 * already know it.
821 */
Johannes Bergdc822b52008-12-29 12:55:09 +0100822 if (!mac) {
Nick Kossifidisc6e387a2008-08-29 22:45:39 +0300823 low_id = 0xffffffff;
824 high_id = 0xffff | AR5K_KEYTABLE_VALID;
825 } else {
Luis R. Rodriguezbcd8f542009-09-09 22:43:17 -0700826 low_id = get_unaligned_le32(mac);
827 high_id = get_unaligned_le16(mac + 4) | AR5K_KEYTABLE_VALID;
Nick Kossifidisc6e387a2008-08-29 22:45:39 +0300828 }
829
830 ath5k_hw_reg_write(ah, low_id, AR5K_KEYTABLE_MAC0(entry));
831 ath5k_hw_reg_write(ah, high_id, AR5K_KEYTABLE_MAC1(entry));
832
833 return 0;
834}
835
Lukáš Turek6e08d222009-12-21 22:50:51 +0100836/**
837 * ath5k_hw_set_coverage_class - Set IEEE 802.11 coverage class
838 *
839 * @ah: The &struct ath5k_hw
840 * @coverage_class: IEEE 802.11 coverage class number
841 *
842 * Sets slot time, ACK timeout and CTS timeout for given coverage class.
843 */
844void ath5k_hw_set_coverage_class(struct ath5k_hw *ah, u8 coverage_class)
845{
846 /* As defined by IEEE 802.11-2007 17.3.8.6 */
847 int slot_time = ath5k_hw_get_default_slottime(ah) + 3 * coverage_class;
848 int ack_timeout = ath5k_hw_get_default_sifs(ah) + slot_time;
849 int cts_timeout = ack_timeout;
850
851 ath5k_hw_set_slot_time(ah, slot_time);
852 ath5k_hw_set_ack_timeout(ah, ack_timeout);
853 ath5k_hw_set_cts_timeout(ah, cts_timeout);
854
855 ah->ah_coverage_class = coverage_class;
856}