pcu.c revision 35edf8aae8f903b154d658b9a7eed0d5c1a4a814
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 27c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis#include "ath5k.h" 28c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis#include "reg.h" 29c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis#include "debug.h" 30c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis#include "base.h" 31c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis 32c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis/*******************\ 33c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis* Generic functions * 34c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis\*******************/ 35c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis 36c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis/** 37c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis * ath5k_hw_set_opmode - Set PCU operating mode 38c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis * 39c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis * @ah: The &struct ath5k_hw 40c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis * 41c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis * Initialize PCU for the various operating modes (AP/STA etc) 42c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis * 43c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis * NOTE: ah->ah_op_mode must be set before calling this. 44c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis */ 45c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidisint ath5k_hw_set_opmode(struct ath5k_hw *ah) 46c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis{ 47c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis u32 pcu_reg, beacon_reg, low_id, high_id; 48c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis 49f07a6c495e88ae0143e3c20b1ed666314197277fNick Kossifidis 50f07a6c495e88ae0143e3c20b1ed666314197277fNick Kossifidis /* Preserve rest settings */ 51f07a6c495e88ae0143e3c20b1ed666314197277fNick Kossifidis pcu_reg = ath5k_hw_reg_read(ah, AR5K_STA_ID1) & 0xffff0000; 52f07a6c495e88ae0143e3c20b1ed666314197277fNick Kossifidis pcu_reg &= ~(AR5K_STA_ID1_ADHOC | AR5K_STA_ID1_AP 53f07a6c495e88ae0143e3c20b1ed666314197277fNick Kossifidis | AR5K_STA_ID1_KEYSRCH_MODE 54f07a6c495e88ae0143e3c20b1ed666314197277fNick Kossifidis | (ah->ah_version == AR5K_AR5210 ? 55f07a6c495e88ae0143e3c20b1ed666314197277fNick Kossifidis (AR5K_STA_ID1_PWR_SV | AR5K_STA_ID1_NO_PSPOLL) : 0)); 56f07a6c495e88ae0143e3c20b1ed666314197277fNick Kossifidis 57c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis beacon_reg = 0; 58c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis 59c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis ATH5K_TRACE(ah->ah_sc); 60c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis 61c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis switch (ah->ah_op_mode) { 6205c914fe330fa8e1cc67870dc0d3809dfd96c107Johannes Berg case NL80211_IFTYPE_ADHOC: 63f07a6c495e88ae0143e3c20b1ed666314197277fNick Kossifidis pcu_reg |= AR5K_STA_ID1_ADHOC | AR5K_STA_ID1_KEYSRCH_MODE; 64c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis beacon_reg |= AR5K_BCR_ADHOC; 65f07a6c495e88ae0143e3c20b1ed666314197277fNick Kossifidis if (ah->ah_version == AR5K_AR5210) 66f07a6c495e88ae0143e3c20b1ed666314197277fNick Kossifidis pcu_reg |= AR5K_STA_ID1_NO_PSPOLL; 67f07a6c495e88ae0143e3c20b1ed666314197277fNick Kossifidis else 684fb7404e0eaf574c00d01d2b1ce2615229b350cdSteve Brown AR5K_REG_ENABLE_BITS(ah, AR5K_CFG, AR5K_CFG_IBSS); 69c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis break; 70c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis 7105c914fe330fa8e1cc67870dc0d3809dfd96c107Johannes Berg case NL80211_IFTYPE_AP: 7205c914fe330fa8e1cc67870dc0d3809dfd96c107Johannes Berg case NL80211_IFTYPE_MESH_POINT: 73f07a6c495e88ae0143e3c20b1ed666314197277fNick Kossifidis pcu_reg |= AR5K_STA_ID1_AP | AR5K_STA_ID1_KEYSRCH_MODE; 74c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis beacon_reg |= AR5K_BCR_AP; 75f07a6c495e88ae0143e3c20b1ed666314197277fNick Kossifidis if (ah->ah_version == AR5K_AR5210) 76f07a6c495e88ae0143e3c20b1ed666314197277fNick Kossifidis pcu_reg |= AR5K_STA_ID1_NO_PSPOLL; 77f07a6c495e88ae0143e3c20b1ed666314197277fNick Kossifidis else 784fb7404e0eaf574c00d01d2b1ce2615229b350cdSteve Brown AR5K_REG_DISABLE_BITS(ah, AR5K_CFG, AR5K_CFG_IBSS); 79c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis break; 80c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis 8105c914fe330fa8e1cc67870dc0d3809dfd96c107Johannes Berg case NL80211_IFTYPE_STATION: 82f07a6c495e88ae0143e3c20b1ed666314197277fNick Kossifidis pcu_reg |= AR5K_STA_ID1_KEYSRCH_MODE 83f07a6c495e88ae0143e3c20b1ed666314197277fNick Kossifidis | (ah->ah_version == AR5K_AR5210 ? 84c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis AR5K_STA_ID1_PWR_SV : 0); 8505c914fe330fa8e1cc67870dc0d3809dfd96c107Johannes Berg case NL80211_IFTYPE_MONITOR: 86f07a6c495e88ae0143e3c20b1ed666314197277fNick Kossifidis pcu_reg |= AR5K_STA_ID1_KEYSRCH_MODE 87f07a6c495e88ae0143e3c20b1ed666314197277fNick Kossifidis | (ah->ah_version == AR5K_AR5210 ? 88c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis AR5K_STA_ID1_NO_PSPOLL : 0); 89c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis break; 90c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis 91c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis default: 92c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis return -EINVAL; 93c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis } 94c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis 95c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis /* 96c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis * Set PCU registers 97c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis */ 98c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis low_id = AR5K_LOW_ID(ah->ah_sta_id); 99c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis high_id = AR5K_HIGH_ID(ah->ah_sta_id); 100c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis ath5k_hw_reg_write(ah, low_id, AR5K_STA_ID0); 101c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis ath5k_hw_reg_write(ah, pcu_reg | high_id, AR5K_STA_ID1); 102c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis 103c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis /* 104c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis * Set Beacon Control Register on 5210 105c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis */ 106c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis if (ah->ah_version == AR5K_AR5210) 107c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis ath5k_hw_reg_write(ah, beacon_reg, AR5K_BCR); 108c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis 109c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis return 0; 110c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis} 111c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis 112c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis/** 113c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis * ath5k_hw_update - Update mib counters (mac layer statistics) 114c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis * 115c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis * @ah: The &struct ath5k_hw 116c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis * @stats: The &struct ieee80211_low_level_stats we use to track 117c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis * statistics on the driver 118c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis * 119c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis * Reads MIB counters from PCU and updates sw statistics. Must be 120c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis * called after a MIB interrupt. 121c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis */ 122c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidisvoid ath5k_hw_update_mib_counters(struct ath5k_hw *ah, 123c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis struct ieee80211_low_level_stats *stats) 124c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis{ 125c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis ATH5K_TRACE(ah->ah_sc); 126c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis 127c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis /* Read-And-Clear */ 128c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis stats->dot11ACKFailureCount += ath5k_hw_reg_read(ah, AR5K_ACK_FAIL); 129c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis stats->dot11RTSFailureCount += ath5k_hw_reg_read(ah, AR5K_RTS_FAIL); 130c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis stats->dot11RTSSuccessCount += ath5k_hw_reg_read(ah, AR5K_RTS_OK); 131c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis stats->dot11FCSErrorCount += ath5k_hw_reg_read(ah, AR5K_FCS_FAIL); 132c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis 133c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis /* XXX: Should we use this to track beacon count ? 134c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis * -we read it anyway to clear the register */ 135c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis ath5k_hw_reg_read(ah, AR5K_BEACON_CNT); 136c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis 137c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis /* Reset profile count registers on 5212*/ 138c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis if (ah->ah_version == AR5K_AR5212) { 139c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis ath5k_hw_reg_write(ah, 0, AR5K_PROFCNT_TX); 140c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis ath5k_hw_reg_write(ah, 0, AR5K_PROFCNT_RX); 141c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis ath5k_hw_reg_write(ah, 0, AR5K_PROFCNT_RXCLR); 142c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis ath5k_hw_reg_write(ah, 0, AR5K_PROFCNT_CYCLE); 143c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis } 144f07a6c495e88ae0143e3c20b1ed666314197277fNick Kossifidis 145f07a6c495e88ae0143e3c20b1ed666314197277fNick Kossifidis /* TODO: Handle ANI stats */ 146c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis} 147c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis 148c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis/** 149c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis * ath5k_hw_set_ack_bitrate - set bitrate for ACKs 150c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis * 151c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis * @ah: The &struct ath5k_hw 152c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis * @high: Flag to determine if we want to use high transmition rate 153c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis * for ACKs or not 154c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis * 155c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis * If high flag is set, we tell hw to use a set of control rates based on 156c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis * the current transmition rate (check out control_rates array inside reset.c). 157c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis * If not hw just uses the lowest rate available for the current modulation 158c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis * scheme being used (1Mbit for CCK and 6Mbits for OFDM). 159c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis */ 160c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidisvoid ath5k_hw_set_ack_bitrate_high(struct ath5k_hw *ah, bool high) 161c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis{ 162c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis if (ah->ah_version != AR5K_AR5212) 163c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis return; 164c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis else { 165c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis u32 val = AR5K_STA_ID1_BASE_RATE_11B | AR5K_STA_ID1_ACKCTS_6MB; 166c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis if (high) 167c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis AR5K_REG_ENABLE_BITS(ah, AR5K_STA_ID1, val); 168c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis else 169c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis AR5K_REG_DISABLE_BITS(ah, AR5K_STA_ID1, val); 170c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis } 171c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis} 172c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis 173c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis 174c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis/******************\ 175c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis* ACK/CTS Timeouts * 176c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis\******************/ 177c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis 178c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis/** 179c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis * ath5k_hw_het_ack_timeout - Get ACK timeout from PCU in usec 180c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis * 181c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis * @ah: The &struct ath5k_hw 182c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis */ 183c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidisunsigned int ath5k_hw_get_ack_timeout(struct ath5k_hw *ah) 184c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis{ 185c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis ATH5K_TRACE(ah->ah_sc); 186c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis 187c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis return ath5k_hw_clocktoh(AR5K_REG_MS(ath5k_hw_reg_read(ah, 188c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis AR5K_TIME_OUT), AR5K_TIME_OUT_ACK), ah->ah_turbo); 189c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis} 190c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis 191c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis/** 192c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis * ath5k_hw_set_ack_timeout - Set ACK timeout on PCU 193c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis * 194c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis * @ah: The &struct ath5k_hw 195c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis * @timeout: Timeout in usec 196c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis */ 197c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidisint ath5k_hw_set_ack_timeout(struct ath5k_hw *ah, unsigned int timeout) 198c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis{ 199c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis ATH5K_TRACE(ah->ah_sc); 200c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis if (ath5k_hw_clocktoh(AR5K_REG_MS(0xffffffff, AR5K_TIME_OUT_ACK), 201c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis ah->ah_turbo) <= timeout) 202c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis return -EINVAL; 203c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis 204c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis AR5K_REG_WRITE_BITS(ah, AR5K_TIME_OUT, AR5K_TIME_OUT_ACK, 205c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis ath5k_hw_htoclock(timeout, ah->ah_turbo)); 206c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis 207c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis return 0; 208c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis} 209c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis 210c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis/** 211c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis * ath5k_hw_get_cts_timeout - Get CTS timeout from PCU in usec 212c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis * 213c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis * @ah: The &struct ath5k_hw 214c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis */ 215c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidisunsigned int ath5k_hw_get_cts_timeout(struct ath5k_hw *ah) 216c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis{ 217c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis ATH5K_TRACE(ah->ah_sc); 218c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis return ath5k_hw_clocktoh(AR5K_REG_MS(ath5k_hw_reg_read(ah, 219c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis AR5K_TIME_OUT), AR5K_TIME_OUT_CTS), ah->ah_turbo); 220c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis} 221c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis 222c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis/** 223c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis * ath5k_hw_set_cts_timeout - Set CTS timeout on PCU 224c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis * 225c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis * @ah: The &struct ath5k_hw 226c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis * @timeout: Timeout in usec 227c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis */ 228c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidisint ath5k_hw_set_cts_timeout(struct ath5k_hw *ah, unsigned int timeout) 229c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis{ 230c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis ATH5K_TRACE(ah->ah_sc); 231c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis if (ath5k_hw_clocktoh(AR5K_REG_MS(0xffffffff, AR5K_TIME_OUT_CTS), 232c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis ah->ah_turbo) <= timeout) 233c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis return -EINVAL; 234c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis 235c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis AR5K_REG_WRITE_BITS(ah, AR5K_TIME_OUT, AR5K_TIME_OUT_CTS, 236c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis ath5k_hw_htoclock(timeout, ah->ah_turbo)); 237c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis 238c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis return 0; 239c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis} 240c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis 241c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis 242c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis/****************\ 243c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis* BSSID handling * 244c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis\****************/ 245c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis 246c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis/** 247c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis * ath5k_hw_get_lladdr - Get station id 248c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis * 249c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis * @ah: The &struct ath5k_hw 250c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis * @mac: The card's mac address 251c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis * 252c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis * Initialize ah->ah_sta_id using the mac address provided 253c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis * (just a memcpy). 254c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis * 255c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis * TODO: Remove it once we merge ath5k_softc and ath5k_hw 256c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis */ 257c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidisvoid ath5k_hw_get_lladdr(struct ath5k_hw *ah, u8 *mac) 258c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis{ 259c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis ATH5K_TRACE(ah->ah_sc); 260c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis memcpy(mac, ah->ah_sta_id, ETH_ALEN); 261c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis} 262c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis 263c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis/** 264c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis * ath5k_hw_set_lladdr - Set station id 265c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis * 266c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis * @ah: The &struct ath5k_hw 267c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis * @mac: The card's mac address 268c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis * 269c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis * Set station id on hw using the provided mac address 270c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis */ 271c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidisint ath5k_hw_set_lladdr(struct ath5k_hw *ah, const u8 *mac) 272c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis{ 273c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis u32 low_id, high_id; 274f6bac3ea5990653765700b2c3778b08782abebe5Bob Copeland u32 pcu_reg; 275c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis 276c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis ATH5K_TRACE(ah->ah_sc); 277c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis /* Set new station ID */ 278c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis memcpy(ah->ah_sta_id, mac, ETH_ALEN); 279c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis 280f6bac3ea5990653765700b2c3778b08782abebe5Bob Copeland pcu_reg = ath5k_hw_reg_read(ah, AR5K_STA_ID1) & 0xffff0000; 281f6bac3ea5990653765700b2c3778b08782abebe5Bob Copeland 282c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis low_id = AR5K_LOW_ID(mac); 283c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis high_id = AR5K_HIGH_ID(mac); 284c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis 285c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis ath5k_hw_reg_write(ah, low_id, AR5K_STA_ID0); 286f6bac3ea5990653765700b2c3778b08782abebe5Bob Copeland ath5k_hw_reg_write(ah, pcu_reg | high_id, AR5K_STA_ID1); 287c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis 288c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis return 0; 289c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis} 290c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis 291c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis/** 292c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis * ath5k_hw_set_associd - Set BSSID for association 293c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis * 294c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis * @ah: The &struct ath5k_hw 295c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis * @bssid: BSSID 296c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis * @assoc_id: Assoc id 297c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis * 298c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis * Sets the BSSID which trigers the "SME Join" operation 299c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis */ 300c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidisvoid ath5k_hw_set_associd(struct ath5k_hw *ah, const u8 *bssid, u16 assoc_id) 301c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis{ 302c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis u32 low_id, high_id; 303c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis u16 tim_offset = 0; 304c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis 305c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis /* 306c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis * Set simple BSSID mask on 5212 307c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis */ 308c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis if (ah->ah_version == AR5K_AR5212) { 309f07a6c495e88ae0143e3c20b1ed666314197277fNick Kossifidis ath5k_hw_reg_write(ah, AR5K_LOW_ID(ah->ah_bssid_mask), 310f07a6c495e88ae0143e3c20b1ed666314197277fNick Kossifidis AR5K_BSS_IDM0); 311f07a6c495e88ae0143e3c20b1ed666314197277fNick Kossifidis ath5k_hw_reg_write(ah, AR5K_HIGH_ID(ah->ah_bssid_mask), 312f07a6c495e88ae0143e3c20b1ed666314197277fNick Kossifidis AR5K_BSS_IDM1); 313c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis } 314c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis 315c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis /* 316c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis * Set BSSID which triggers the "SME Join" operation 317c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis */ 318c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis low_id = AR5K_LOW_ID(bssid); 319c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis high_id = AR5K_HIGH_ID(bssid); 320c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis ath5k_hw_reg_write(ah, low_id, AR5K_BSS_ID0); 321c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis ath5k_hw_reg_write(ah, high_id | ((assoc_id & 0x3fff) << 322c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis AR5K_BSS_ID1_AID_S), AR5K_BSS_ID1); 323c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis 324c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis if (assoc_id == 0) { 325c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis ath5k_hw_disable_pspoll(ah); 326c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis return; 327c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis } 328c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis 329c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis AR5K_REG_WRITE_BITS(ah, AR5K_BEACON, AR5K_BEACON_TIM, 330c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis tim_offset ? tim_offset + 4 : 0); 331c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis 332c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis ath5k_hw_enable_pspoll(ah, NULL, 0); 333c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis} 334c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis 335c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis/** 336c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis * ath5k_hw_set_bssid_mask - filter out bssids we listen 337c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis * 338c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis * @ah: the &struct ath5k_hw 339c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis * @mask: the bssid_mask, a u8 array of size ETH_ALEN 340c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis * 341c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis * BSSID masking is a method used by AR5212 and newer hardware to inform PCU 342c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis * which bits of the interface's MAC address should be looked at when trying 343c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis * to decide which packets to ACK. In station mode and AP mode with a single 344c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis * BSS every bit matters since we lock to only one BSS. In AP mode with 345c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis * multiple BSSes (virtual interfaces) not every bit matters because hw must 346c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis * accept frames for all BSSes and so we tweak some bits of our mac address 347c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis * in order to have multiple BSSes. 348c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis * 349c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis * NOTE: This is a simple filter and does *not* filter out all 350c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis * relevant frames. Some frames that are not for us might get ACKed from us 351c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis * by PCU because they just match the mask. 352c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis * 353c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis * When handling multiple BSSes you can get the BSSID mask by computing the 354c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis * set of ~ ( MAC XOR BSSID ) for all bssids we handle. 355c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis * 356c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis * When you do this you are essentially computing the common bits of all your 357c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis * BSSes. Later it is assumed the harware will "and" (&) the BSSID mask with 358c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis * the MAC address to obtain the relevant bits and compare the result with 359c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis * (frame's BSSID & mask) to see if they match. 360c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis */ 361c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis/* 362c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis * Simple example: on your card you have have two BSSes you have created with 363c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis * BSSID-01 and BSSID-02. Lets assume BSSID-01 will not use the MAC address. 364c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis * There is another BSSID-03 but you are not part of it. For simplicity's sake, 365c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis * assuming only 4 bits for a mac address and for BSSIDs you can then have: 366c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis * 367c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis * \ 368c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis * MAC: 0001 | 369c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis * BSSID-01: 0100 | --> Belongs to us 370c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis * BSSID-02: 1001 | 371c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis * / 372c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis * ------------------- 373c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis * BSSID-03: 0110 | --> External 374c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis * ------------------- 375c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis * 376c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis * Our bssid_mask would then be: 377c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis * 378c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis * On loop iteration for BSSID-01: 379c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis * ~(0001 ^ 0100) -> ~(0101) 380c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis * -> 1010 381c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis * bssid_mask = 1010 382c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis * 383c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis * On loop iteration for BSSID-02: 384c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis * bssid_mask &= ~(0001 ^ 1001) 385c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis * bssid_mask = (1010) & ~(0001 ^ 1001) 386c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis * bssid_mask = (1010) & ~(1001) 387c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis * bssid_mask = (1010) & (0110) 388c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis * bssid_mask = 0010 389c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis * 390c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis * A bssid_mask of 0010 means "only pay attention to the second least 391c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis * significant bit". This is because its the only bit common 392c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis * amongst the MAC and all BSSIDs we support. To findout what the real 393c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis * common bit is we can simply "&" the bssid_mask now with any BSSID we have 394c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis * or our MAC address (we assume the hardware uses the MAC address). 395c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis * 396c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis * Now, suppose there's an incoming frame for BSSID-03: 397c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis * 398c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis * IFRAME-01: 0110 399c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis * 400c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis * An easy eye-inspeciton of this already should tell you that this frame 401c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis * will not pass our check. This is beacuse the bssid_mask tells the 402c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis * hardware to only look at the second least significant bit and the 403c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis * common bit amongst the MAC and BSSIDs is 0, this frame has the 2nd LSB 404c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis * as 1, which does not match 0. 405c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis * 406c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis * So with IFRAME-01 we *assume* the hardware will do: 407c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis * 408c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis * allow = (IFRAME-01 & bssid_mask) == (bssid_mask & MAC) ? 1 : 0; 409c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis * --> allow = (0110 & 0010) == (0010 & 0001) ? 1 : 0; 410c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis * --> allow = (0010) == 0000 ? 1 : 0; 411c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis * --> allow = 0 412c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis * 413c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis * Lets now test a frame that should work: 414c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis * 415c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis * IFRAME-02: 0001 (we should allow) 416c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis * 417c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis * allow = (0001 & 1010) == 1010 418c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis * 419c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis * allow = (IFRAME-02 & bssid_mask) == (bssid_mask & MAC) ? 1 : 0; 420c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis * --> allow = (0001 & 0010) == (0010 & 0001) ? 1 :0; 421c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis * --> allow = (0010) == (0010) 422c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis * --> allow = 1 423c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis * 424c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis * Other examples: 425c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis * 426c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis * IFRAME-03: 0100 --> allowed 427c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis * IFRAME-04: 1001 --> allowed 428c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis * IFRAME-05: 1101 --> allowed but its not for us!!! 429c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis * 430c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis */ 431c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidisint ath5k_hw_set_bssid_mask(struct ath5k_hw *ah, const u8 *mask) 432c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis{ 433c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis u32 low_id, high_id; 434c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis ATH5K_TRACE(ah->ah_sc); 435c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis 436f07a6c495e88ae0143e3c20b1ed666314197277fNick Kossifidis /* Cache bssid mask so that we can restore it 437f07a6c495e88ae0143e3c20b1ed666314197277fNick Kossifidis * on reset */ 438f07a6c495e88ae0143e3c20b1ed666314197277fNick Kossifidis memcpy(ah->ah_bssid_mask, mask, ETH_ALEN); 439c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis if (ah->ah_version == AR5K_AR5212) { 440c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis low_id = AR5K_LOW_ID(mask); 441c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis high_id = AR5K_HIGH_ID(mask); 442c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis 443c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis ath5k_hw_reg_write(ah, low_id, AR5K_BSS_IDM0); 444c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis ath5k_hw_reg_write(ah, high_id, AR5K_BSS_IDM1); 445c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis 446c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis return 0; 447c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis } 448c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis 449c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis return -EIO; 450c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis} 451c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis 452c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis 453c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis/************\ 454c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis* RX Control * 455c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis\************/ 456c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis 457c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis/** 458c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis * ath5k_hw_start_rx_pcu - Start RX engine 459c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis * 460c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis * @ah: The &struct ath5k_hw 461c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis * 462c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis * Starts RX engine on PCU so that hw can process RXed frames 463c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis * (ACK etc). 464c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis * 465c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis * NOTE: RX DMA should be already enabled using ath5k_hw_start_rx_dma 466c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis * TODO: Init ANI here 467c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis */ 468c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidisvoid ath5k_hw_start_rx_pcu(struct ath5k_hw *ah) 469c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis{ 470c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis ATH5K_TRACE(ah->ah_sc); 471c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis AR5K_REG_DISABLE_BITS(ah, AR5K_DIAG_SW, AR5K_DIAG_SW_DIS_RX); 472c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis} 473c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis 474c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis/** 475c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis * at5k_hw_stop_rx_pcu - Stop RX engine 476c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis * 477c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis * @ah: The &struct ath5k_hw 478c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis * 479c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis * Stops RX engine on PCU 480c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis * 481c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis * TODO: Detach ANI here 482c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis */ 483c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidisvoid ath5k_hw_stop_rx_pcu(struct ath5k_hw *ah) 484c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis{ 485c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis ATH5K_TRACE(ah->ah_sc); 486c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis AR5K_REG_ENABLE_BITS(ah, AR5K_DIAG_SW, AR5K_DIAG_SW_DIS_RX); 487c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis} 488c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis 489c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis/* 490c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis * Set multicast filter 491c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis */ 492c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidisvoid ath5k_hw_set_mcast_filter(struct ath5k_hw *ah, u32 filter0, u32 filter1) 493c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis{ 494c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis ATH5K_TRACE(ah->ah_sc); 495c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis /* Set the multicat filter */ 496c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis ath5k_hw_reg_write(ah, filter0, AR5K_MCAST_FILTER0); 497c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis ath5k_hw_reg_write(ah, filter1, AR5K_MCAST_FILTER1); 498c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis} 499c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis 500c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis/* 501c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis * Set multicast filter by index 502c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis */ 503c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidisint ath5k_hw_set_mcast_filter_idx(struct ath5k_hw *ah, u32 index) 504c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis{ 505c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis 506c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis ATH5K_TRACE(ah->ah_sc); 507c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis if (index >= 64) 508c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis return -EINVAL; 509c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis else if (index >= 32) 510c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis AR5K_REG_ENABLE_BITS(ah, AR5K_MCAST_FILTER1, 511c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis (1 << (index - 32))); 512c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis else 513c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis AR5K_REG_ENABLE_BITS(ah, AR5K_MCAST_FILTER0, (1 << index)); 514c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis 515c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis return 0; 516c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis} 517c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis 518c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis/* 519c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis * Clear Multicast filter by index 520c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis */ 521c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidisint ath5k_hw_clear_mcast_filter_idx(struct ath5k_hw *ah, u32 index) 522c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis{ 523c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis 524c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis ATH5K_TRACE(ah->ah_sc); 525c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis if (index >= 64) 526c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis return -EINVAL; 527c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis else if (index >= 32) 528c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis AR5K_REG_DISABLE_BITS(ah, AR5K_MCAST_FILTER1, 529c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis (1 << (index - 32))); 530c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis else 531c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis AR5K_REG_DISABLE_BITS(ah, AR5K_MCAST_FILTER0, (1 << index)); 532c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis 533c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis return 0; 534c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis} 535c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis 536c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis/** 537c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis * ath5k_hw_get_rx_filter - Get current rx filter 538c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis * 539c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis * @ah: The &struct ath5k_hw 540c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis * 541c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis * Returns the RX filter by reading rx filter and 542c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis * phy error filter registers. RX filter is used 543c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis * to set the allowed frame types that PCU will accept 544c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis * and pass to the driver. For a list of frame types 545c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis * check out reg.h. 546c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis */ 547c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidisu32 ath5k_hw_get_rx_filter(struct ath5k_hw *ah) 548c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis{ 549c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis u32 data, filter = 0; 550c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis 551c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis ATH5K_TRACE(ah->ah_sc); 552c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis filter = ath5k_hw_reg_read(ah, AR5K_RX_FILTER); 553c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis 554c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis /*Radar detection for 5212*/ 555c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis if (ah->ah_version == AR5K_AR5212) { 556c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis data = ath5k_hw_reg_read(ah, AR5K_PHY_ERR_FIL); 557c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis 558c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis if (data & AR5K_PHY_ERR_FIL_RADAR) 559c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis filter |= AR5K_RX_FILTER_RADARERR; 560c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis if (data & (AR5K_PHY_ERR_FIL_OFDM | AR5K_PHY_ERR_FIL_CCK)) 561c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis filter |= AR5K_RX_FILTER_PHYERR; 562c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis } 563c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis 564c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis return filter; 565c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis} 566c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis 567c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis/** 568c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis * ath5k_hw_set_rx_filter - Set rx filter 569c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis * 570c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis * @ah: The &struct ath5k_hw 571c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis * @filter: RX filter mask (see reg.h) 572c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis * 573c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis * Sets RX filter register and also handles PHY error filter 574c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis * register on 5212 and newer chips so that we have proper PHY 575c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis * error reporting. 576c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis */ 577c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidisvoid ath5k_hw_set_rx_filter(struct ath5k_hw *ah, u32 filter) 578c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis{ 579c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis u32 data = 0; 580c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis 581c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis ATH5K_TRACE(ah->ah_sc); 582c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis 583c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis /* Set PHY error filter register on 5212*/ 584c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis if (ah->ah_version == AR5K_AR5212) { 585c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis if (filter & AR5K_RX_FILTER_RADARERR) 586c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis data |= AR5K_PHY_ERR_FIL_RADAR; 587c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis if (filter & AR5K_RX_FILTER_PHYERR) 588c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis data |= AR5K_PHY_ERR_FIL_OFDM | AR5K_PHY_ERR_FIL_CCK; 589c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis } 590c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis 591c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis /* 592c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis * The AR5210 uses promiscous mode to detect radar activity 593c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis */ 594c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis if (ah->ah_version == AR5K_AR5210 && 595c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis (filter & AR5K_RX_FILTER_RADARERR)) { 596c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis filter &= ~AR5K_RX_FILTER_RADARERR; 597c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis filter |= AR5K_RX_FILTER_PROM; 598c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis } 599c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis 600f07a6c495e88ae0143e3c20b1ed666314197277fNick Kossifidis /*Zero length DMA (phy error reporting) */ 601c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis if (data) 602c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis AR5K_REG_ENABLE_BITS(ah, AR5K_RXCFG, AR5K_RXCFG_ZLFDMA); 603c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis else 604c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis AR5K_REG_DISABLE_BITS(ah, AR5K_RXCFG, AR5K_RXCFG_ZLFDMA); 605c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis 606c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis /*Write RX Filter register*/ 607c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis ath5k_hw_reg_write(ah, filter & 0xff, AR5K_RX_FILTER); 608c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis 609c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis /*Write PHY error filter register on 5212*/ 610c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis if (ah->ah_version == AR5K_AR5212) 611c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis ath5k_hw_reg_write(ah, data, AR5K_PHY_ERR_FIL); 612c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis 613c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis} 614c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis 615c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis 616c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis/****************\ 617c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis* Beacon control * 618c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis\****************/ 619c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis 620c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis/** 621c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis * ath5k_hw_get_tsf32 - Get a 32bit TSF 622c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis * 623c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis * @ah: The &struct ath5k_hw 624c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis * 625c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis * Returns lower 32 bits of current TSF 626c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis */ 627c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidisu32 ath5k_hw_get_tsf32(struct ath5k_hw *ah) 628c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis{ 629c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis ATH5K_TRACE(ah->ah_sc); 630c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis return ath5k_hw_reg_read(ah, AR5K_TSF_L32); 631c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis} 632c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis 633c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis/** 634c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis * ath5k_hw_get_tsf64 - Get the full 64bit TSF 635c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis * 636c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis * @ah: The &struct ath5k_hw 637c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis * 638c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis * Returns the current TSF 639c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis */ 640c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidisu64 ath5k_hw_get_tsf64(struct ath5k_hw *ah) 641c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis{ 642c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis u64 tsf = ath5k_hw_reg_read(ah, AR5K_TSF_U32); 643c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis ATH5K_TRACE(ah->ah_sc); 644c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis 645c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis return ath5k_hw_reg_read(ah, AR5K_TSF_L32) | (tsf << 32); 646c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis} 647c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis 648c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis/** 6498cab7581dba90b0519e25784e08feb5dedde737fAlina Friedrichsen * ath5k_hw_set_tsf64 - Set a new 64bit TSF 6508cab7581dba90b0519e25784e08feb5dedde737fAlina Friedrichsen * 6518cab7581dba90b0519e25784e08feb5dedde737fAlina Friedrichsen * @ah: The &struct ath5k_hw 6528cab7581dba90b0519e25784e08feb5dedde737fAlina Friedrichsen * @tsf64: The new 64bit TSF 6538cab7581dba90b0519e25784e08feb5dedde737fAlina Friedrichsen * 6548cab7581dba90b0519e25784e08feb5dedde737fAlina Friedrichsen * Sets the new TSF 6558cab7581dba90b0519e25784e08feb5dedde737fAlina Friedrichsen */ 6568cab7581dba90b0519e25784e08feb5dedde737fAlina Friedrichsenvoid ath5k_hw_set_tsf64(struct ath5k_hw *ah, u64 tsf64) 6578cab7581dba90b0519e25784e08feb5dedde737fAlina Friedrichsen{ 6588cab7581dba90b0519e25784e08feb5dedde737fAlina Friedrichsen ATH5K_TRACE(ah->ah_sc); 6598cab7581dba90b0519e25784e08feb5dedde737fAlina Friedrichsen 6608cab7581dba90b0519e25784e08feb5dedde737fAlina Friedrichsen ath5k_hw_reg_write(ah, tsf64 & 0xffffffff, AR5K_TSF_L32); 6610ad65bd7e1b38dd2c86da5f07dbfa35fe1f03099Alina Friedrichsen ath5k_hw_reg_write(ah, (tsf64 >> 32) & 0xffffffff, AR5K_TSF_U32); 6628cab7581dba90b0519e25784e08feb5dedde737fAlina Friedrichsen} 6638cab7581dba90b0519e25784e08feb5dedde737fAlina Friedrichsen 6648cab7581dba90b0519e25784e08feb5dedde737fAlina Friedrichsen/** 665c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis * ath5k_hw_reset_tsf - Force a TSF reset 666c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis * 667c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis * @ah: The &struct ath5k_hw 668c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis * 669c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis * Forces a TSF reset on PCU 670c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis */ 671c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidisvoid ath5k_hw_reset_tsf(struct ath5k_hw *ah) 672c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis{ 67314be9947ef9843102b67d315c7483de112b5b2d7Bob Copeland u32 val; 67414be9947ef9843102b67d315c7483de112b5b2d7Bob Copeland 675c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis ATH5K_TRACE(ah->ah_sc); 67614be9947ef9843102b67d315c7483de112b5b2d7Bob Copeland 67714be9947ef9843102b67d315c7483de112b5b2d7Bob Copeland val = ath5k_hw_reg_read(ah, AR5K_BEACON) | AR5K_BEACON_RESET_TSF; 67814be9947ef9843102b67d315c7483de112b5b2d7Bob Copeland 67914be9947ef9843102b67d315c7483de112b5b2d7Bob Copeland /* 68014be9947ef9843102b67d315c7483de112b5b2d7Bob Copeland * Each write to the RESET_TSF bit toggles a hardware internal 68114be9947ef9843102b67d315c7483de112b5b2d7Bob Copeland * signal to reset TSF, but if left high it will cause a TSF reset 68214be9947ef9843102b67d315c7483de112b5b2d7Bob Copeland * on the next chip reset as well. Thus we always write the value 68314be9947ef9843102b67d315c7483de112b5b2d7Bob Copeland * twice to clear the signal. 68414be9947ef9843102b67d315c7483de112b5b2d7Bob Copeland */ 68514be9947ef9843102b67d315c7483de112b5b2d7Bob Copeland ath5k_hw_reg_write(ah, val, AR5K_BEACON); 68614be9947ef9843102b67d315c7483de112b5b2d7Bob Copeland ath5k_hw_reg_write(ah, val, AR5K_BEACON); 687c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis} 688c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis 689c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis/* 690c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis * Initialize beacon timers 691c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis */ 692c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidisvoid ath5k_hw_init_beacon(struct ath5k_hw *ah, u32 next_beacon, u32 interval) 693c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis{ 694c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis u32 timer1, timer2, timer3; 695c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis 696c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis ATH5K_TRACE(ah->ah_sc); 697c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis /* 698c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis * Set the additional timers by mode 699c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis */ 700c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis switch (ah->ah_op_mode) { 701f07a6c495e88ae0143e3c20b1ed666314197277fNick Kossifidis case NL80211_IFTYPE_MONITOR: 70205c914fe330fa8e1cc67870dc0d3809dfd96c107Johannes Berg case NL80211_IFTYPE_STATION: 703f07a6c495e88ae0143e3c20b1ed666314197277fNick Kossifidis /* In STA mode timer1 is used as next wakeup 704f07a6c495e88ae0143e3c20b1ed666314197277fNick Kossifidis * timer and timer2 as next CFP duration start 705f07a6c495e88ae0143e3c20b1ed666314197277fNick Kossifidis * timer. Both in 1/8TUs. */ 706f07a6c495e88ae0143e3c20b1ed666314197277fNick Kossifidis /* TODO: PCF handling */ 707c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis if (ah->ah_version == AR5K_AR5210) { 708c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis timer1 = 0xffffffff; 709c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis timer2 = 0xffffffff; 710c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis } else { 711c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis timer1 = 0x0000ffff; 712c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis timer2 = 0x0007ffff; 713c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis } 714f07a6c495e88ae0143e3c20b1ed666314197277fNick Kossifidis /* Mark associated AP as PCF incapable for now */ 715f07a6c495e88ae0143e3c20b1ed666314197277fNick Kossifidis AR5K_REG_DISABLE_BITS(ah, AR5K_STA_ID1, AR5K_STA_ID1_PCF); 716c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis break; 717f07a6c495e88ae0143e3c20b1ed666314197277fNick Kossifidis case NL80211_IFTYPE_ADHOC: 718f07a6c495e88ae0143e3c20b1ed666314197277fNick Kossifidis AR5K_REG_ENABLE_BITS(ah, AR5K_TXCFG, AR5K_TXCFG_ADHOC_BCN_ATIM); 719c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis default: 720f07a6c495e88ae0143e3c20b1ed666314197277fNick Kossifidis /* On non-STA modes timer1 is used as next DMA 721f07a6c495e88ae0143e3c20b1ed666314197277fNick Kossifidis * beacon alert (DBA) timer and timer2 as next 722f07a6c495e88ae0143e3c20b1ed666314197277fNick Kossifidis * software beacon alert. Both in 1/8TUs. */ 723c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis timer1 = (next_beacon - AR5K_TUNE_DMA_BEACON_RESP) << 3; 724c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis timer2 = (next_beacon - AR5K_TUNE_SW_BEACON_RESP) << 3; 725f07a6c495e88ae0143e3c20b1ed666314197277fNick Kossifidis break; 726c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis } 727c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis 728f07a6c495e88ae0143e3c20b1ed666314197277fNick Kossifidis /* Timer3 marks the end of our ATIM window 729f07a6c495e88ae0143e3c20b1ed666314197277fNick Kossifidis * a zero length window is not allowed because 730f07a6c495e88ae0143e3c20b1ed666314197277fNick Kossifidis * we 'll get no beacons */ 731c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis timer3 = next_beacon + (ah->ah_atim_window ? ah->ah_atim_window : 1); 732c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis 733c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis /* 734c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis * Set the beacon register and enable all timers. 735c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis */ 73635edf8aae8f903b154d658b9a7eed0d5c1a4a814Nick Kossifidis /* When in AP or Mesh Point mode zero timer0 to start TSF */ 73735edf8aae8f903b154d658b9a7eed0d5c1a4a814Nick Kossifidis if (ah->ah_op_mode == NL80211_IFTYPE_AP || 73835edf8aae8f903b154d658b9a7eed0d5c1a4a814Nick Kossifidis ah->ah_op_mode == NL80211_IFTYPE_MESH_POINT) 739f07a6c495e88ae0143e3c20b1ed666314197277fNick Kossifidis ath5k_hw_reg_write(ah, 0, AR5K_TIMER0); 740428cbd4ff4d0f2423f49e499f499f04a636cb152Nick Kossifidis 741428cbd4ff4d0f2423f49e499f499f04a636cb152Nick Kossifidis ath5k_hw_reg_write(ah, next_beacon, AR5K_TIMER0); 742c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis ath5k_hw_reg_write(ah, timer1, AR5K_TIMER1); 743c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis ath5k_hw_reg_write(ah, timer2, AR5K_TIMER2); 744c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis ath5k_hw_reg_write(ah, timer3, AR5K_TIMER3); 745c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis 746f07a6c495e88ae0143e3c20b1ed666314197277fNick Kossifidis /* Force a TSF reset if requested and enable beacons */ 747f07a6c495e88ae0143e3c20b1ed666314197277fNick Kossifidis if (interval & AR5K_BEACON_RESET_TSF) 748f07a6c495e88ae0143e3c20b1ed666314197277fNick Kossifidis ath5k_hw_reset_tsf(ah); 749f07a6c495e88ae0143e3c20b1ed666314197277fNick Kossifidis 750c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis ath5k_hw_reg_write(ah, interval & (AR5K_BEACON_PERIOD | 751f07a6c495e88ae0143e3c20b1ed666314197277fNick Kossifidis AR5K_BEACON_ENABLE), 752f07a6c495e88ae0143e3c20b1ed666314197277fNick Kossifidis AR5K_BEACON); 753f07a6c495e88ae0143e3c20b1ed666314197277fNick Kossifidis 754f07a6c495e88ae0143e3c20b1ed666314197277fNick Kossifidis /* Flush any pending BMISS interrupts on ISR by 755f07a6c495e88ae0143e3c20b1ed666314197277fNick Kossifidis * performing a clear-on-write operation on PISR 756f07a6c495e88ae0143e3c20b1ed666314197277fNick Kossifidis * register for the BMISS bit (writing a bit on 757f07a6c495e88ae0143e3c20b1ed666314197277fNick Kossifidis * ISR togles a reset for that bit and leaves 758f07a6c495e88ae0143e3c20b1ed666314197277fNick Kossifidis * the rest bits intact) */ 759f07a6c495e88ae0143e3c20b1ed666314197277fNick Kossifidis if (ah->ah_version == AR5K_AR5210) 760f07a6c495e88ae0143e3c20b1ed666314197277fNick Kossifidis ath5k_hw_reg_write(ah, AR5K_ISR_BMISS, AR5K_ISR); 761f07a6c495e88ae0143e3c20b1ed666314197277fNick Kossifidis else 762f07a6c495e88ae0143e3c20b1ed666314197277fNick Kossifidis ath5k_hw_reg_write(ah, AR5K_ISR_BMISS, AR5K_PISR); 763f07a6c495e88ae0143e3c20b1ed666314197277fNick Kossifidis 764f07a6c495e88ae0143e3c20b1ed666314197277fNick Kossifidis /* TODO: Set enchanced sleep registers on AR5212 765f07a6c495e88ae0143e3c20b1ed666314197277fNick Kossifidis * based on vif->bss_conf params, until then 766f07a6c495e88ae0143e3c20b1ed666314197277fNick Kossifidis * disable power save reporting.*/ 767f07a6c495e88ae0143e3c20b1ed666314197277fNick Kossifidis AR5K_REG_DISABLE_BITS(ah, AR5K_STA_ID1, AR5K_STA_ID1_PWR_SV); 768f07a6c495e88ae0143e3c20b1ed666314197277fNick Kossifidis 769c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis} 770c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis 771c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis#if 0 772c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis/* 773c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis * Set beacon timers 774c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis */ 775c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidisint ath5k_hw_set_beacon_timers(struct ath5k_hw *ah, 776c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis const struct ath5k_beacon_state *state) 777c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis{ 778c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis u32 cfp_period, next_cfp, dtim, interval, next_beacon; 779c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis 780c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis /* 781c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis * TODO: should be changed through *state 782c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis * review struct ath5k_beacon_state struct 783c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis * 784c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis * XXX: These are used for cfp period bellow, are they 785c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis * ok ? Is it O.K. for tsf here to be 0 or should we use 786c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis * get_tsf ? 787c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis */ 788c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis u32 dtim_count = 0; /* XXX */ 789c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis u32 cfp_count = 0; /* XXX */ 790c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis u32 tsf = 0; /* XXX */ 791c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis 792c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis ATH5K_TRACE(ah->ah_sc); 793c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis /* Return on an invalid beacon state */ 794c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis if (state->bs_interval < 1) 795c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis return -EINVAL; 796c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis 797c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis interval = state->bs_interval; 798c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis dtim = state->bs_dtim_period; 799c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis 800c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis /* 801c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis * PCF support? 802c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis */ 803c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis if (state->bs_cfp_period > 0) { 804c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis /* 805c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis * Enable PCF mode and set the CFP 806c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis * (Contention Free Period) and timer registers 807c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis */ 808c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis cfp_period = state->bs_cfp_period * state->bs_dtim_period * 809c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis state->bs_interval; 810c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis next_cfp = (cfp_count * state->bs_dtim_period + dtim_count) * 811c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis state->bs_interval; 812c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis 813c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis AR5K_REG_ENABLE_BITS(ah, AR5K_STA_ID1, 814c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis AR5K_STA_ID1_DEFAULT_ANTENNA | 815c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis AR5K_STA_ID1_PCF); 816c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis ath5k_hw_reg_write(ah, cfp_period, AR5K_CFP_PERIOD); 817c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis ath5k_hw_reg_write(ah, state->bs_cfp_max_duration, 818c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis AR5K_CFP_DUR); 819c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis ath5k_hw_reg_write(ah, (tsf + (next_cfp == 0 ? cfp_period : 820c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis next_cfp)) << 3, AR5K_TIMER2); 821c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis } else { 822c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis /* Disable PCF mode */ 823c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis AR5K_REG_DISABLE_BITS(ah, AR5K_STA_ID1, 824c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis AR5K_STA_ID1_DEFAULT_ANTENNA | 825c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis AR5K_STA_ID1_PCF); 826c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis } 827c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis 828c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis /* 829c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis * Enable the beacon timer register 830c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis */ 831c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis ath5k_hw_reg_write(ah, state->bs_next_beacon, AR5K_TIMER0); 832c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis 833c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis /* 834c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis * Start the beacon timers 835c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis */ 836c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis ath5k_hw_reg_write(ah, (ath5k_hw_reg_read(ah, AR5K_BEACON) & 837c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis ~(AR5K_BEACON_PERIOD | AR5K_BEACON_TIM)) | 838c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis AR5K_REG_SM(state->bs_tim_offset ? state->bs_tim_offset + 4 : 0, 839c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis AR5K_BEACON_TIM) | AR5K_REG_SM(state->bs_interval, 840c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis AR5K_BEACON_PERIOD), AR5K_BEACON); 841c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis 842c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis /* 843c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis * Write new beacon miss threshold, if it appears to be valid 844c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis * XXX: Figure out right values for min <= bs_bmiss_threshold <= max 845c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis * and return if its not in range. We can test this by reading value and 846c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis * setting value to a largest value and seeing which values register. 847c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis */ 848c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis 849c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis AR5K_REG_WRITE_BITS(ah, AR5K_RSSI_THR, AR5K_RSSI_THR_BMISS, 850c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis state->bs_bmiss_threshold); 851c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis 852c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis /* 853c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis * Set sleep control register 854c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis * XXX: Didn't find this in 5210 code but since this register 855c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis * exists also in ar5k's 5210 headers i leave it as common code. 856c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis */ 857c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis AR5K_REG_WRITE_BITS(ah, AR5K_SLEEP_CTL, AR5K_SLEEP_CTL_SLDUR, 858c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis (state->bs_sleep_duration - 3) << 3); 859c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis 860c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis /* 861c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis * Set enhanced sleep registers on 5212 862c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis */ 863c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis if (ah->ah_version == AR5K_AR5212) { 864c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis if (state->bs_sleep_duration > state->bs_interval && 865c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis roundup(state->bs_sleep_duration, interval) == 866c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis state->bs_sleep_duration) 867c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis interval = state->bs_sleep_duration; 868c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis 869c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis if (state->bs_sleep_duration > dtim && (dtim == 0 || 870c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis roundup(state->bs_sleep_duration, dtim) == 871c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis state->bs_sleep_duration)) 872c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis dtim = state->bs_sleep_duration; 873c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis 874c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis if (interval > dtim) 875c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis return -EINVAL; 876c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis 877c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis next_beacon = interval == dtim ? state->bs_next_dtim : 878c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis state->bs_next_beacon; 879c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis 880c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis ath5k_hw_reg_write(ah, 881c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis AR5K_REG_SM((state->bs_next_dtim - 3) << 3, 882c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis AR5K_SLEEP0_NEXT_DTIM) | 883c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis AR5K_REG_SM(10, AR5K_SLEEP0_CABTO) | 884c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis AR5K_SLEEP0_ENH_SLEEP_EN | 885c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis AR5K_SLEEP0_ASSUME_DTIM, AR5K_SLEEP0); 886c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis 887c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis ath5k_hw_reg_write(ah, AR5K_REG_SM((next_beacon - 3) << 3, 888c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis AR5K_SLEEP1_NEXT_TIM) | 889c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis AR5K_REG_SM(10, AR5K_SLEEP1_BEACON_TO), AR5K_SLEEP1); 890c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis 891c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis ath5k_hw_reg_write(ah, 892c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis AR5K_REG_SM(interval, AR5K_SLEEP2_TIM_PER) | 893c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis AR5K_REG_SM(dtim, AR5K_SLEEP2_DTIM_PER), AR5K_SLEEP2); 894c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis } 895c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis 896c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis return 0; 897c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis} 898c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis 899c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis/* 900c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis * Reset beacon timers 901c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis */ 902c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidisvoid ath5k_hw_reset_beacon(struct ath5k_hw *ah) 903c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis{ 904c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis ATH5K_TRACE(ah->ah_sc); 905c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis /* 906c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis * Disable beacon timer 907c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis */ 908c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis ath5k_hw_reg_write(ah, 0, AR5K_TIMER0); 909c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis 910c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis /* 911c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis * Disable some beacon register values 912c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis */ 913c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis AR5K_REG_DISABLE_BITS(ah, AR5K_STA_ID1, 914c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis AR5K_STA_ID1_DEFAULT_ANTENNA | AR5K_STA_ID1_PCF); 915c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis ath5k_hw_reg_write(ah, AR5K_BEACON_PERIOD, AR5K_BEACON); 916c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis} 917c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis 918c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis/* 919c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis * Wait for beacon queue to finish 920c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis */ 921c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidisint ath5k_hw_beaconq_finish(struct ath5k_hw *ah, unsigned long phys_addr) 922c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis{ 923c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis unsigned int i; 924c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis int ret; 925c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis 926c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis ATH5K_TRACE(ah->ah_sc); 927c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis 928c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis /* 5210 doesn't have QCU*/ 929c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis if (ah->ah_version == AR5K_AR5210) { 930c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis /* 931c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis * Wait for beaconn queue to finish by checking 932c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis * Control Register and Beacon Status Register. 933c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis */ 934c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis for (i = AR5K_TUNE_BEACON_INTERVAL / 2; i > 0; i--) { 935c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis if (!(ath5k_hw_reg_read(ah, AR5K_BSR) & AR5K_BSR_TXQ1F) 936c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis || 937c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis !(ath5k_hw_reg_read(ah, AR5K_CR) & AR5K_BSR_TXQ1F)) 938c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis break; 939c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis udelay(10); 940c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis } 941c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis 942c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis /* Timeout... */ 943c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis if (i <= 0) { 944c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis /* 945c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis * Re-schedule the beacon queue 946c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis */ 947c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis ath5k_hw_reg_write(ah, phys_addr, AR5K_NOQCU_TXDP1); 948c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis ath5k_hw_reg_write(ah, AR5K_BCR_TQ1V | AR5K_BCR_BDMAE, 949c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis AR5K_BCR); 950c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis 951c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis return -EIO; 952c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis } 953c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis ret = 0; 954c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis } else { 955c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis /*5211/5212*/ 956c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis ret = ath5k_hw_register_timeout(ah, 957c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis AR5K_QUEUE_STATUS(AR5K_TX_QUEUE_ID_BEACON), 958c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis AR5K_QCU_STS_FRMPENDCNT, 0, false); 959c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis 960c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis if (AR5K_REG_READ_Q(ah, AR5K_QCU_TXE, AR5K_TX_QUEUE_ID_BEACON)) 961c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis return -EIO; 962c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis } 963c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis 964c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis return ret; 965c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis} 966c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis#endif 967c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis 968c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis 969c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis/*********************\ 970c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis* Key table functions * 971c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis\*********************/ 972c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis 973c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis/* 974c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis * Reset a key entry on the table 975c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis */ 976c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidisint ath5k_hw_reset_key(struct ath5k_hw *ah, u16 entry) 977c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis{ 978f07a6c495e88ae0143e3c20b1ed666314197277fNick Kossifidis unsigned int i, type; 97917683c65c8a5f3f29f5408334992986b996d8205Bob Copeland u16 micentry = entry + AR5K_KEYTABLE_MIC_OFFSET; 980c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis 981c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis ATH5K_TRACE(ah->ah_sc); 982c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis AR5K_ASSERT_ENTRY(entry, AR5K_KEYTABLE_SIZE); 983c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis 984f07a6c495e88ae0143e3c20b1ed666314197277fNick Kossifidis type = ath5k_hw_reg_read(ah, AR5K_KEYTABLE_TYPE(entry)); 985f07a6c495e88ae0143e3c20b1ed666314197277fNick Kossifidis 986c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis for (i = 0; i < AR5K_KEYCACHE_SIZE; i++) 987c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis ath5k_hw_reg_write(ah, 0, AR5K_KEYTABLE_OFF(entry, i)); 988c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis 989f07a6c495e88ae0143e3c20b1ed666314197277fNick Kossifidis /* Reset associated MIC entry if TKIP 990f07a6c495e88ae0143e3c20b1ed666314197277fNick Kossifidis * is enabled located at offset (entry + 64) */ 991f07a6c495e88ae0143e3c20b1ed666314197277fNick Kossifidis if (type == AR5K_KEYTABLE_TYPE_TKIP) { 99217683c65c8a5f3f29f5408334992986b996d8205Bob Copeland AR5K_ASSERT_ENTRY(micentry, AR5K_KEYTABLE_SIZE); 993f07a6c495e88ae0143e3c20b1ed666314197277fNick Kossifidis for (i = 0; i < AR5K_KEYCACHE_SIZE / 2 ; i++) 99417683c65c8a5f3f29f5408334992986b996d8205Bob Copeland ath5k_hw_reg_write(ah, 0, 99517683c65c8a5f3f29f5408334992986b996d8205Bob Copeland AR5K_KEYTABLE_OFF(micentry, i)); 996f07a6c495e88ae0143e3c20b1ed666314197277fNick Kossifidis } 997f07a6c495e88ae0143e3c20b1ed666314197277fNick Kossifidis 998c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis /* 999c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis * Set NULL encryption on AR5212+ 1000c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis * 1001c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis * Note: AR5K_KEYTABLE_TYPE -> AR5K_KEYTABLE_OFF(entry, 5) 1002c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis * AR5K_KEYTABLE_TYPE_NULL -> 0x00000007 1003c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis * 1004c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis * Note2: Windows driver (ndiswrapper) sets this to 1005c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis * 0x00000714 instead of 0x00000007 1006c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis */ 1007ded7a7eaab2a39b7b5c36a2ec3be46f6ebcedba5Jiri Slaby if (ah->ah_version >= AR5K_AR5211) { 1008c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis ath5k_hw_reg_write(ah, AR5K_KEYTABLE_TYPE_NULL, 1009c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis AR5K_KEYTABLE_TYPE(entry)); 1010c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis 101117683c65c8a5f3f29f5408334992986b996d8205Bob Copeland if (type == AR5K_KEYTABLE_TYPE_TKIP) { 101217683c65c8a5f3f29f5408334992986b996d8205Bob Copeland ath5k_hw_reg_write(ah, AR5K_KEYTABLE_TYPE_NULL, 101317683c65c8a5f3f29f5408334992986b996d8205Bob Copeland AR5K_KEYTABLE_TYPE(micentry)); 101417683c65c8a5f3f29f5408334992986b996d8205Bob Copeland } 101517683c65c8a5f3f29f5408334992986b996d8205Bob Copeland } 101617683c65c8a5f3f29f5408334992986b996d8205Bob Copeland 1017c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis return 0; 1018c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis} 1019c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis 1020c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis/* 1021c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis * Check if a table entry is valid 1022c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis */ 1023c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidisint ath5k_hw_is_key_valid(struct ath5k_hw *ah, u16 entry) 1024c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis{ 1025c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis ATH5K_TRACE(ah->ah_sc); 1026c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis AR5K_ASSERT_ENTRY(entry, AR5K_KEYTABLE_SIZE); 1027c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis 1028c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis /* Check the validation flag at the end of the entry */ 1029c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis return ath5k_hw_reg_read(ah, AR5K_KEYTABLE_MAC1(entry)) & 1030c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis AR5K_KEYTABLE_VALID; 1031c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis} 1032c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis 1033671434904633876f89be70af415c35c89fb90115Bob Copelandstatic 1034671434904633876f89be70af415c35c89fb90115Bob Copelandint ath5k_keycache_type(const struct ieee80211_key_conf *key) 1035671434904633876f89be70af415c35c89fb90115Bob Copeland{ 1036671434904633876f89be70af415c35c89fb90115Bob Copeland switch (key->alg) { 1037671434904633876f89be70af415c35c89fb90115Bob Copeland case ALG_TKIP: 1038671434904633876f89be70af415c35c89fb90115Bob Copeland return AR5K_KEYTABLE_TYPE_TKIP; 1039671434904633876f89be70af415c35c89fb90115Bob Copeland case ALG_CCMP: 1040671434904633876f89be70af415c35c89fb90115Bob Copeland return AR5K_KEYTABLE_TYPE_CCM; 1041671434904633876f89be70af415c35c89fb90115Bob Copeland case ALG_WEP: 1042e31a16d6f64ef0e324c6f54d5112703c3f13a9c4Zhu Yi if (key->keylen == WLAN_KEY_LEN_WEP40) 1043671434904633876f89be70af415c35c89fb90115Bob Copeland return AR5K_KEYTABLE_TYPE_40; 1044e31a16d6f64ef0e324c6f54d5112703c3f13a9c4Zhu Yi else if (key->keylen == WLAN_KEY_LEN_WEP104) 1045671434904633876f89be70af415c35c89fb90115Bob Copeland return AR5K_KEYTABLE_TYPE_104; 10463cfcf6ac6d69dc290e96416731eea5c88ac7d426Jouni Malinen return -EINVAL; 10473cfcf6ac6d69dc290e96416731eea5c88ac7d426Jouni Malinen default: 10483cfcf6ac6d69dc290e96416731eea5c88ac7d426Jouni Malinen return -EINVAL; 1049671434904633876f89be70af415c35c89fb90115Bob Copeland } 1050671434904633876f89be70af415c35c89fb90115Bob Copeland return -EINVAL; 1051671434904633876f89be70af415c35c89fb90115Bob Copeland} 1052671434904633876f89be70af415c35c89fb90115Bob Copeland 1053c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis/* 1054c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis * Set a key entry on the table 1055c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis */ 1056c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidisint ath5k_hw_set_key(struct ath5k_hw *ah, u16 entry, 1057c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis const struct ieee80211_key_conf *key, const u8 *mac) 1058c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis{ 1059c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis unsigned int i; 10603f64b435ab76e79bfb3b4d36f043e6f892093b71Bob Copeland int keylen; 1061c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis __le32 key_v[5] = {}; 10623f64b435ab76e79bfb3b4d36f043e6f892093b71Bob Copeland __le32 key0 = 0, key1 = 0; 10633f64b435ab76e79bfb3b4d36f043e6f892093b71Bob Copeland __le32 *rxmic, *txmic; 1064672cf3cefe5f686637dec72b9f3d21fe1cdc8c94Roel Kluin int keytype; 10653f64b435ab76e79bfb3b4d36f043e6f892093b71Bob Copeland u16 micentry = entry + AR5K_KEYTABLE_MIC_OFFSET; 10663f64b435ab76e79bfb3b4d36f043e6f892093b71Bob Copeland bool is_tkip; 1067671434904633876f89be70af415c35c89fb90115Bob Copeland const u8 *key_ptr; 1068c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis 1069c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis ATH5K_TRACE(ah->ah_sc); 1070c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis 10713f64b435ab76e79bfb3b4d36f043e6f892093b71Bob Copeland is_tkip = (key->alg == ALG_TKIP); 10723f64b435ab76e79bfb3b4d36f043e6f892093b71Bob Copeland 10733f64b435ab76e79bfb3b4d36f043e6f892093b71Bob Copeland /* 10743f64b435ab76e79bfb3b4d36f043e6f892093b71Bob Copeland * key->keylen comes in from mac80211 in bytes. 10753f64b435ab76e79bfb3b4d36f043e6f892093b71Bob Copeland * TKIP is 128 bit + 128 bit mic 10763f64b435ab76e79bfb3b4d36f043e6f892093b71Bob Copeland */ 10773f64b435ab76e79bfb3b4d36f043e6f892093b71Bob Copeland keylen = (is_tkip) ? (128 / 8) : key->keylen; 1078c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis 10793f64b435ab76e79bfb3b4d36f043e6f892093b71Bob Copeland if (entry > AR5K_KEYTABLE_SIZE || 10803f64b435ab76e79bfb3b4d36f043e6f892093b71Bob Copeland (is_tkip && micentry > AR5K_KEYTABLE_SIZE)) 1081c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis return -EOPNOTSUPP; 1082c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis 1083671434904633876f89be70af415c35c89fb90115Bob Copeland if (unlikely(keylen > 16)) 1084671434904633876f89be70af415c35c89fb90115Bob Copeland return -EOPNOTSUPP; 1085c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis 1086671434904633876f89be70af415c35c89fb90115Bob Copeland keytype = ath5k_keycache_type(key); 1087671434904633876f89be70af415c35c89fb90115Bob Copeland if (keytype < 0) 1088671434904633876f89be70af415c35c89fb90115Bob Copeland return keytype; 1089c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis 1090671434904633876f89be70af415c35c89fb90115Bob Copeland /* 1091671434904633876f89be70af415c35c89fb90115Bob Copeland * each key block is 6 bytes wide, written as pairs of 1092671434904633876f89be70af415c35c89fb90115Bob Copeland * alternating 32 and 16 bit le values. 1093671434904633876f89be70af415c35c89fb90115Bob Copeland */ 1094671434904633876f89be70af415c35c89fb90115Bob Copeland key_ptr = key->key; 1095671434904633876f89be70af415c35c89fb90115Bob Copeland for (i = 0; keylen >= 6; keylen -= 6) { 1096671434904633876f89be70af415c35c89fb90115Bob Copeland memcpy(&key_v[i], key_ptr, 6); 1097671434904633876f89be70af415c35c89fb90115Bob Copeland i += 2; 1098671434904633876f89be70af415c35c89fb90115Bob Copeland key_ptr += 6; 1099c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis } 1100671434904633876f89be70af415c35c89fb90115Bob Copeland if (keylen) 1101671434904633876f89be70af415c35c89fb90115Bob Copeland memcpy(&key_v[i], key_ptr, keylen); 1102c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis 11033f64b435ab76e79bfb3b4d36f043e6f892093b71Bob Copeland /* intentionally corrupt key until mic is installed */ 11043f64b435ab76e79bfb3b4d36f043e6f892093b71Bob Copeland if (is_tkip) { 11053f64b435ab76e79bfb3b4d36f043e6f892093b71Bob Copeland key0 = key_v[0] = ~key_v[0]; 11063f64b435ab76e79bfb3b4d36f043e6f892093b71Bob Copeland key1 = key_v[1] = ~key_v[1]; 11073f64b435ab76e79bfb3b4d36f043e6f892093b71Bob Copeland } 11083f64b435ab76e79bfb3b4d36f043e6f892093b71Bob Copeland 1109c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis for (i = 0; i < ARRAY_SIZE(key_v); i++) 1110c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis ath5k_hw_reg_write(ah, le32_to_cpu(key_v[i]), 1111c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis AR5K_KEYTABLE_OFF(entry, i)); 1112c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis 1113c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis ath5k_hw_reg_write(ah, keytype, AR5K_KEYTABLE_TYPE(entry)); 1114c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis 11153f64b435ab76e79bfb3b4d36f043e6f892093b71Bob Copeland if (is_tkip) { 11163f64b435ab76e79bfb3b4d36f043e6f892093b71Bob Copeland /* Install rx/tx MIC */ 11173f64b435ab76e79bfb3b4d36f043e6f892093b71Bob Copeland rxmic = (__le32 *) &key->key[16]; 11183f64b435ab76e79bfb3b4d36f043e6f892093b71Bob Copeland txmic = (__le32 *) &key->key[24]; 1119f650470a8f506bc33a15778432ebb8cdcf89175bBob Copeland 1120f650470a8f506bc33a15778432ebb8cdcf89175bBob Copeland if (ah->ah_combined_mic) { 1121f650470a8f506bc33a15778432ebb8cdcf89175bBob Copeland key_v[0] = rxmic[0]; 1122388cdf31db6dfc3d175786a76989266380e12c26Bob Copeland key_v[1] = cpu_to_le32(le32_to_cpu(txmic[0]) >> 16); 1123f650470a8f506bc33a15778432ebb8cdcf89175bBob Copeland key_v[2] = rxmic[1]; 1124388cdf31db6dfc3d175786a76989266380e12c26Bob Copeland key_v[3] = cpu_to_le32(le32_to_cpu(txmic[0]) & 0xffff); 1125f650470a8f506bc33a15778432ebb8cdcf89175bBob Copeland key_v[4] = txmic[1]; 1126f650470a8f506bc33a15778432ebb8cdcf89175bBob Copeland } else { 1127f650470a8f506bc33a15778432ebb8cdcf89175bBob Copeland key_v[0] = rxmic[0]; 1128f650470a8f506bc33a15778432ebb8cdcf89175bBob Copeland key_v[1] = 0; 1129f650470a8f506bc33a15778432ebb8cdcf89175bBob Copeland key_v[2] = rxmic[1]; 1130f650470a8f506bc33a15778432ebb8cdcf89175bBob Copeland key_v[3] = 0; 1131f650470a8f506bc33a15778432ebb8cdcf89175bBob Copeland key_v[4] = 0; 1132f650470a8f506bc33a15778432ebb8cdcf89175bBob Copeland } 11333f64b435ab76e79bfb3b4d36f043e6f892093b71Bob Copeland for (i = 0; i < ARRAY_SIZE(key_v); i++) 11343f64b435ab76e79bfb3b4d36f043e6f892093b71Bob Copeland ath5k_hw_reg_write(ah, le32_to_cpu(key_v[i]), 11353f64b435ab76e79bfb3b4d36f043e6f892093b71Bob Copeland AR5K_KEYTABLE_OFF(micentry, i)); 11363f64b435ab76e79bfb3b4d36f043e6f892093b71Bob Copeland 11373f64b435ab76e79bfb3b4d36f043e6f892093b71Bob Copeland ath5k_hw_reg_write(ah, AR5K_KEYTABLE_TYPE_NULL, 11383f64b435ab76e79bfb3b4d36f043e6f892093b71Bob Copeland AR5K_KEYTABLE_TYPE(micentry)); 11393f64b435ab76e79bfb3b4d36f043e6f892093b71Bob Copeland ath5k_hw_reg_write(ah, 0, AR5K_KEYTABLE_MAC0(micentry)); 11403f64b435ab76e79bfb3b4d36f043e6f892093b71Bob Copeland ath5k_hw_reg_write(ah, 0, AR5K_KEYTABLE_MAC1(micentry)); 11413f64b435ab76e79bfb3b4d36f043e6f892093b71Bob Copeland 11423f64b435ab76e79bfb3b4d36f043e6f892093b71Bob Copeland /* restore first 2 words of key */ 11433f64b435ab76e79bfb3b4d36f043e6f892093b71Bob Copeland ath5k_hw_reg_write(ah, le32_to_cpu(~key0), 11443f64b435ab76e79bfb3b4d36f043e6f892093b71Bob Copeland AR5K_KEYTABLE_OFF(entry, 0)); 11453f64b435ab76e79bfb3b4d36f043e6f892093b71Bob Copeland ath5k_hw_reg_write(ah, le32_to_cpu(~key1), 11463f64b435ab76e79bfb3b4d36f043e6f892093b71Bob Copeland AR5K_KEYTABLE_OFF(entry, 1)); 11473f64b435ab76e79bfb3b4d36f043e6f892093b71Bob Copeland } 11483f64b435ab76e79bfb3b4d36f043e6f892093b71Bob Copeland 1149c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis return ath5k_hw_set_key_lladdr(ah, entry, mac); 1150c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis} 1151c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis 1152c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidisint ath5k_hw_set_key_lladdr(struct ath5k_hw *ah, u16 entry, const u8 *mac) 1153c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis{ 1154c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis u32 low_id, high_id; 1155c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis 1156c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis ATH5K_TRACE(ah->ah_sc); 1157c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis /* Invalid entry (key table overflow) */ 1158c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis AR5K_ASSERT_ENTRY(entry, AR5K_KEYTABLE_SIZE); 1159c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis 1160c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis /* MAC may be NULL if it's a broadcast key. In this case no need to 1161c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis * to compute AR5K_LOW_ID and AR5K_HIGH_ID as we already know it. */ 1162dc822b5db479dc0178d5c04cbb656dad0b6564fbJohannes Berg if (!mac) { 1163c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis low_id = 0xffffffff; 1164c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis high_id = 0xffff | AR5K_KEYTABLE_VALID; 1165c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis } else { 1166c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis low_id = AR5K_LOW_ID(mac); 1167c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis high_id = AR5K_HIGH_ID(mac) | AR5K_KEYTABLE_VALID; 1168c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis } 1169c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis 1170c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis ath5k_hw_reg_write(ah, low_id, AR5K_KEYTABLE_MAC0(entry)); 1171c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis ath5k_hw_reg_write(ah, high_id, AR5K_KEYTABLE_MAC1(entry)); 1172c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis 1173c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis return 0; 1174c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis} 1175c6e387a214f4b2c4bd48020409e366c133385d98Nick Kossifidis 1176