162306a36Sopenharmony_ci/*- 262306a36Sopenharmony_ci * Copyright (c) 2002-2005 Sam Leffler, Errno Consulting 362306a36Sopenharmony_ci * Copyright (c) 2004-2005 Atheros Communications, Inc. 462306a36Sopenharmony_ci * Copyright (c) 2006 Devicescape Software, Inc. 562306a36Sopenharmony_ci * Copyright (c) 2007 Jiri Slaby <jirislaby@gmail.com> 662306a36Sopenharmony_ci * Copyright (c) 2007 Luis R. Rodriguez <mcgrof@winlab.rutgers.edu> 762306a36Sopenharmony_ci * 862306a36Sopenharmony_ci * All rights reserved. 962306a36Sopenharmony_ci * 1062306a36Sopenharmony_ci * Redistribution and use in source and binary forms, with or without 1162306a36Sopenharmony_ci * modification, are permitted provided that the following conditions 1262306a36Sopenharmony_ci * are met: 1362306a36Sopenharmony_ci * 1. Redistributions of source code must retain the above copyright 1462306a36Sopenharmony_ci * notice, this list of conditions and the following disclaimer, 1562306a36Sopenharmony_ci * without modification. 1662306a36Sopenharmony_ci * 2. Redistributions in binary form must reproduce at minimum a disclaimer 1762306a36Sopenharmony_ci * similar to the "NO WARRANTY" disclaimer below ("Disclaimer") and any 1862306a36Sopenharmony_ci * redistribution must be conditioned upon including a substantially 1962306a36Sopenharmony_ci * similar Disclaimer requirement for further binary redistribution. 2062306a36Sopenharmony_ci * 3. Neither the names of the above-listed copyright holders nor the names 2162306a36Sopenharmony_ci * of any contributors may be used to endorse or promote products derived 2262306a36Sopenharmony_ci * from this software without specific prior written permission. 2362306a36Sopenharmony_ci * 2462306a36Sopenharmony_ci * Alternatively, this software may be distributed under the terms of the 2562306a36Sopenharmony_ci * GNU General Public License ("GPL") version 2 as published by the Free 2662306a36Sopenharmony_ci * Software Foundation. 2762306a36Sopenharmony_ci * 2862306a36Sopenharmony_ci * NO WARRANTY 2962306a36Sopenharmony_ci * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 3062306a36Sopenharmony_ci * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 3162306a36Sopenharmony_ci * LIMITED TO, THE IMPLIED WARRANTIES OF NONINFRINGEMENT, MERCHANTIBILITY 3262306a36Sopenharmony_ci * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL 3362306a36Sopenharmony_ci * THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, 3462306a36Sopenharmony_ci * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 3562306a36Sopenharmony_ci * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 3662306a36Sopenharmony_ci * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER 3762306a36Sopenharmony_ci * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 3862306a36Sopenharmony_ci * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF 3962306a36Sopenharmony_ci * THE POSSIBILITY OF SUCH DAMAGES. 4062306a36Sopenharmony_ci * 4162306a36Sopenharmony_ci */ 4262306a36Sopenharmony_ci 4362306a36Sopenharmony_ci#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt 4462306a36Sopenharmony_ci 4562306a36Sopenharmony_ci#include <linux/module.h> 4662306a36Sopenharmony_ci#include <linux/delay.h> 4762306a36Sopenharmony_ci#include <linux/dma-mapping.h> 4862306a36Sopenharmony_ci#include <linux/hardirq.h> 4962306a36Sopenharmony_ci#include <linux/if.h> 5062306a36Sopenharmony_ci#include <linux/io.h> 5162306a36Sopenharmony_ci#include <linux/netdevice.h> 5262306a36Sopenharmony_ci#include <linux/cache.h> 5362306a36Sopenharmony_ci#include <linux/ethtool.h> 5462306a36Sopenharmony_ci#include <linux/uaccess.h> 5562306a36Sopenharmony_ci#include <linux/slab.h> 5662306a36Sopenharmony_ci#include <linux/etherdevice.h> 5762306a36Sopenharmony_ci#include <linux/nl80211.h> 5862306a36Sopenharmony_ci 5962306a36Sopenharmony_ci#include <net/cfg80211.h> 6062306a36Sopenharmony_ci#include <net/ieee80211_radiotap.h> 6162306a36Sopenharmony_ci 6262306a36Sopenharmony_ci#include <asm/unaligned.h> 6362306a36Sopenharmony_ci 6462306a36Sopenharmony_ci#include <net/mac80211.h> 6562306a36Sopenharmony_ci#include "base.h" 6662306a36Sopenharmony_ci#include "reg.h" 6762306a36Sopenharmony_ci#include "debug.h" 6862306a36Sopenharmony_ci#include "ani.h" 6962306a36Sopenharmony_ci#include "ath5k.h" 7062306a36Sopenharmony_ci#include "../regd.h" 7162306a36Sopenharmony_ci 7262306a36Sopenharmony_ci#define CREATE_TRACE_POINTS 7362306a36Sopenharmony_ci#include "trace.h" 7462306a36Sopenharmony_ci 7562306a36Sopenharmony_cibool ath5k_modparam_nohwcrypt; 7662306a36Sopenharmony_cimodule_param_named(nohwcrypt, ath5k_modparam_nohwcrypt, bool, 0444); 7762306a36Sopenharmony_ciMODULE_PARM_DESC(nohwcrypt, "Disable hardware encryption."); 7862306a36Sopenharmony_ci 7962306a36Sopenharmony_cistatic bool modparam_fastchanswitch; 8062306a36Sopenharmony_cimodule_param_named(fastchanswitch, modparam_fastchanswitch, bool, 0444); 8162306a36Sopenharmony_ciMODULE_PARM_DESC(fastchanswitch, "Enable fast channel switching for AR2413/AR5413 radios."); 8262306a36Sopenharmony_ci 8362306a36Sopenharmony_cistatic bool ath5k_modparam_no_hw_rfkill_switch; 8462306a36Sopenharmony_cimodule_param_named(no_hw_rfkill_switch, ath5k_modparam_no_hw_rfkill_switch, 8562306a36Sopenharmony_ci bool, 0444); 8662306a36Sopenharmony_ciMODULE_PARM_DESC(no_hw_rfkill_switch, "Ignore the GPIO RFKill switch state"); 8762306a36Sopenharmony_ci 8862306a36Sopenharmony_ci 8962306a36Sopenharmony_ci/* Module info */ 9062306a36Sopenharmony_ciMODULE_AUTHOR("Jiri Slaby"); 9162306a36Sopenharmony_ciMODULE_AUTHOR("Nick Kossifidis"); 9262306a36Sopenharmony_ciMODULE_DESCRIPTION("Support for 5xxx series of Atheros 802.11 wireless LAN cards."); 9362306a36Sopenharmony_ciMODULE_LICENSE("Dual BSD/GPL"); 9462306a36Sopenharmony_ci 9562306a36Sopenharmony_cistatic int ath5k_init(struct ieee80211_hw *hw); 9662306a36Sopenharmony_cistatic int ath5k_reset(struct ath5k_hw *ah, struct ieee80211_channel *chan, 9762306a36Sopenharmony_ci bool skip_pcu); 9862306a36Sopenharmony_ci 9962306a36Sopenharmony_ci/* Known SREVs */ 10062306a36Sopenharmony_cistatic const struct ath5k_srev_name srev_names[] = { 10162306a36Sopenharmony_ci#ifdef CONFIG_ATH5K_AHB 10262306a36Sopenharmony_ci { "5312", AR5K_VERSION_MAC, AR5K_SREV_AR5312_R2 }, 10362306a36Sopenharmony_ci { "5312", AR5K_VERSION_MAC, AR5K_SREV_AR5312_R7 }, 10462306a36Sopenharmony_ci { "2313", AR5K_VERSION_MAC, AR5K_SREV_AR2313_R8 }, 10562306a36Sopenharmony_ci { "2315", AR5K_VERSION_MAC, AR5K_SREV_AR2315_R6 }, 10662306a36Sopenharmony_ci { "2315", AR5K_VERSION_MAC, AR5K_SREV_AR2315_R7 }, 10762306a36Sopenharmony_ci { "2317", AR5K_VERSION_MAC, AR5K_SREV_AR2317_R1 }, 10862306a36Sopenharmony_ci { "2317", AR5K_VERSION_MAC, AR5K_SREV_AR2317_R2 }, 10962306a36Sopenharmony_ci#else 11062306a36Sopenharmony_ci { "5210", AR5K_VERSION_MAC, AR5K_SREV_AR5210 }, 11162306a36Sopenharmony_ci { "5311", AR5K_VERSION_MAC, AR5K_SREV_AR5311 }, 11262306a36Sopenharmony_ci { "5311A", AR5K_VERSION_MAC, AR5K_SREV_AR5311A }, 11362306a36Sopenharmony_ci { "5311B", AR5K_VERSION_MAC, AR5K_SREV_AR5311B }, 11462306a36Sopenharmony_ci { "5211", AR5K_VERSION_MAC, AR5K_SREV_AR5211 }, 11562306a36Sopenharmony_ci { "5212", AR5K_VERSION_MAC, AR5K_SREV_AR5212 }, 11662306a36Sopenharmony_ci { "5213", AR5K_VERSION_MAC, AR5K_SREV_AR5213 }, 11762306a36Sopenharmony_ci { "5213A", AR5K_VERSION_MAC, AR5K_SREV_AR5213A }, 11862306a36Sopenharmony_ci { "2413", AR5K_VERSION_MAC, AR5K_SREV_AR2413 }, 11962306a36Sopenharmony_ci { "2414", AR5K_VERSION_MAC, AR5K_SREV_AR2414 }, 12062306a36Sopenharmony_ci { "5424", AR5K_VERSION_MAC, AR5K_SREV_AR5424 }, 12162306a36Sopenharmony_ci { "5413", AR5K_VERSION_MAC, AR5K_SREV_AR5413 }, 12262306a36Sopenharmony_ci { "5414", AR5K_VERSION_MAC, AR5K_SREV_AR5414 }, 12362306a36Sopenharmony_ci { "2415", AR5K_VERSION_MAC, AR5K_SREV_AR2415 }, 12462306a36Sopenharmony_ci { "5416", AR5K_VERSION_MAC, AR5K_SREV_AR5416 }, 12562306a36Sopenharmony_ci { "5418", AR5K_VERSION_MAC, AR5K_SREV_AR5418 }, 12662306a36Sopenharmony_ci { "2425", AR5K_VERSION_MAC, AR5K_SREV_AR2425 }, 12762306a36Sopenharmony_ci { "2417", AR5K_VERSION_MAC, AR5K_SREV_AR2417 }, 12862306a36Sopenharmony_ci#endif 12962306a36Sopenharmony_ci { "xxxxx", AR5K_VERSION_MAC, AR5K_SREV_UNKNOWN }, 13062306a36Sopenharmony_ci { "5110", AR5K_VERSION_RAD, AR5K_SREV_RAD_5110 }, 13162306a36Sopenharmony_ci { "5111", AR5K_VERSION_RAD, AR5K_SREV_RAD_5111 }, 13262306a36Sopenharmony_ci { "5111A", AR5K_VERSION_RAD, AR5K_SREV_RAD_5111A }, 13362306a36Sopenharmony_ci { "2111", AR5K_VERSION_RAD, AR5K_SREV_RAD_2111 }, 13462306a36Sopenharmony_ci { "5112", AR5K_VERSION_RAD, AR5K_SREV_RAD_5112 }, 13562306a36Sopenharmony_ci { "5112A", AR5K_VERSION_RAD, AR5K_SREV_RAD_5112A }, 13662306a36Sopenharmony_ci { "5112B", AR5K_VERSION_RAD, AR5K_SREV_RAD_5112B }, 13762306a36Sopenharmony_ci { "2112", AR5K_VERSION_RAD, AR5K_SREV_RAD_2112 }, 13862306a36Sopenharmony_ci { "2112A", AR5K_VERSION_RAD, AR5K_SREV_RAD_2112A }, 13962306a36Sopenharmony_ci { "2112B", AR5K_VERSION_RAD, AR5K_SREV_RAD_2112B }, 14062306a36Sopenharmony_ci { "2413", AR5K_VERSION_RAD, AR5K_SREV_RAD_2413 }, 14162306a36Sopenharmony_ci { "5413", AR5K_VERSION_RAD, AR5K_SREV_RAD_5413 }, 14262306a36Sopenharmony_ci { "5424", AR5K_VERSION_RAD, AR5K_SREV_RAD_5424 }, 14362306a36Sopenharmony_ci { "5133", AR5K_VERSION_RAD, AR5K_SREV_RAD_5133 }, 14462306a36Sopenharmony_ci#ifdef CONFIG_ATH5K_AHB 14562306a36Sopenharmony_ci { "2316", AR5K_VERSION_RAD, AR5K_SREV_RAD_2316 }, 14662306a36Sopenharmony_ci { "2317", AR5K_VERSION_RAD, AR5K_SREV_RAD_2317 }, 14762306a36Sopenharmony_ci#endif 14862306a36Sopenharmony_ci { "xxxxx", AR5K_VERSION_RAD, AR5K_SREV_UNKNOWN }, 14962306a36Sopenharmony_ci}; 15062306a36Sopenharmony_ci 15162306a36Sopenharmony_cistatic const struct ieee80211_rate ath5k_rates[] = { 15262306a36Sopenharmony_ci { .bitrate = 10, 15362306a36Sopenharmony_ci .hw_value = ATH5K_RATE_CODE_1M, }, 15462306a36Sopenharmony_ci { .bitrate = 20, 15562306a36Sopenharmony_ci .hw_value = ATH5K_RATE_CODE_2M, 15662306a36Sopenharmony_ci .hw_value_short = ATH5K_RATE_CODE_2M | AR5K_SET_SHORT_PREAMBLE, 15762306a36Sopenharmony_ci .flags = IEEE80211_RATE_SHORT_PREAMBLE }, 15862306a36Sopenharmony_ci { .bitrate = 55, 15962306a36Sopenharmony_ci .hw_value = ATH5K_RATE_CODE_5_5M, 16062306a36Sopenharmony_ci .hw_value_short = ATH5K_RATE_CODE_5_5M | AR5K_SET_SHORT_PREAMBLE, 16162306a36Sopenharmony_ci .flags = IEEE80211_RATE_SHORT_PREAMBLE }, 16262306a36Sopenharmony_ci { .bitrate = 110, 16362306a36Sopenharmony_ci .hw_value = ATH5K_RATE_CODE_11M, 16462306a36Sopenharmony_ci .hw_value_short = ATH5K_RATE_CODE_11M | AR5K_SET_SHORT_PREAMBLE, 16562306a36Sopenharmony_ci .flags = IEEE80211_RATE_SHORT_PREAMBLE }, 16662306a36Sopenharmony_ci { .bitrate = 60, 16762306a36Sopenharmony_ci .hw_value = ATH5K_RATE_CODE_6M, 16862306a36Sopenharmony_ci .flags = IEEE80211_RATE_SUPPORTS_5MHZ | 16962306a36Sopenharmony_ci IEEE80211_RATE_SUPPORTS_10MHZ }, 17062306a36Sopenharmony_ci { .bitrate = 90, 17162306a36Sopenharmony_ci .hw_value = ATH5K_RATE_CODE_9M, 17262306a36Sopenharmony_ci .flags = IEEE80211_RATE_SUPPORTS_5MHZ | 17362306a36Sopenharmony_ci IEEE80211_RATE_SUPPORTS_10MHZ }, 17462306a36Sopenharmony_ci { .bitrate = 120, 17562306a36Sopenharmony_ci .hw_value = ATH5K_RATE_CODE_12M, 17662306a36Sopenharmony_ci .flags = IEEE80211_RATE_SUPPORTS_5MHZ | 17762306a36Sopenharmony_ci IEEE80211_RATE_SUPPORTS_10MHZ }, 17862306a36Sopenharmony_ci { .bitrate = 180, 17962306a36Sopenharmony_ci .hw_value = ATH5K_RATE_CODE_18M, 18062306a36Sopenharmony_ci .flags = IEEE80211_RATE_SUPPORTS_5MHZ | 18162306a36Sopenharmony_ci IEEE80211_RATE_SUPPORTS_10MHZ }, 18262306a36Sopenharmony_ci { .bitrate = 240, 18362306a36Sopenharmony_ci .hw_value = ATH5K_RATE_CODE_24M, 18462306a36Sopenharmony_ci .flags = IEEE80211_RATE_SUPPORTS_5MHZ | 18562306a36Sopenharmony_ci IEEE80211_RATE_SUPPORTS_10MHZ }, 18662306a36Sopenharmony_ci { .bitrate = 360, 18762306a36Sopenharmony_ci .hw_value = ATH5K_RATE_CODE_36M, 18862306a36Sopenharmony_ci .flags = IEEE80211_RATE_SUPPORTS_5MHZ | 18962306a36Sopenharmony_ci IEEE80211_RATE_SUPPORTS_10MHZ }, 19062306a36Sopenharmony_ci { .bitrate = 480, 19162306a36Sopenharmony_ci .hw_value = ATH5K_RATE_CODE_48M, 19262306a36Sopenharmony_ci .flags = IEEE80211_RATE_SUPPORTS_5MHZ | 19362306a36Sopenharmony_ci IEEE80211_RATE_SUPPORTS_10MHZ }, 19462306a36Sopenharmony_ci { .bitrate = 540, 19562306a36Sopenharmony_ci .hw_value = ATH5K_RATE_CODE_54M, 19662306a36Sopenharmony_ci .flags = IEEE80211_RATE_SUPPORTS_5MHZ | 19762306a36Sopenharmony_ci IEEE80211_RATE_SUPPORTS_10MHZ }, 19862306a36Sopenharmony_ci}; 19962306a36Sopenharmony_ci 20062306a36Sopenharmony_cistatic inline u64 ath5k_extend_tsf(struct ath5k_hw *ah, u32 rstamp) 20162306a36Sopenharmony_ci{ 20262306a36Sopenharmony_ci u64 tsf = ath5k_hw_get_tsf64(ah); 20362306a36Sopenharmony_ci 20462306a36Sopenharmony_ci if ((tsf & 0x7fff) < rstamp) 20562306a36Sopenharmony_ci tsf -= 0x8000; 20662306a36Sopenharmony_ci 20762306a36Sopenharmony_ci return (tsf & ~0x7fff) | rstamp; 20862306a36Sopenharmony_ci} 20962306a36Sopenharmony_ci 21062306a36Sopenharmony_ciconst char * 21162306a36Sopenharmony_ciath5k_chip_name(enum ath5k_srev_type type, u_int16_t val) 21262306a36Sopenharmony_ci{ 21362306a36Sopenharmony_ci const char *name = "xxxxx"; 21462306a36Sopenharmony_ci unsigned int i; 21562306a36Sopenharmony_ci 21662306a36Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(srev_names); i++) { 21762306a36Sopenharmony_ci if (srev_names[i].sr_type != type) 21862306a36Sopenharmony_ci continue; 21962306a36Sopenharmony_ci 22062306a36Sopenharmony_ci if ((val & 0xf0) == srev_names[i].sr_val) 22162306a36Sopenharmony_ci name = srev_names[i].sr_name; 22262306a36Sopenharmony_ci 22362306a36Sopenharmony_ci if ((val & 0xff) == srev_names[i].sr_val) { 22462306a36Sopenharmony_ci name = srev_names[i].sr_name; 22562306a36Sopenharmony_ci break; 22662306a36Sopenharmony_ci } 22762306a36Sopenharmony_ci } 22862306a36Sopenharmony_ci 22962306a36Sopenharmony_ci return name; 23062306a36Sopenharmony_ci} 23162306a36Sopenharmony_cistatic unsigned int ath5k_ioread32(void *hw_priv, u32 reg_offset) 23262306a36Sopenharmony_ci{ 23362306a36Sopenharmony_ci struct ath5k_hw *ah = (struct ath5k_hw *) hw_priv; 23462306a36Sopenharmony_ci return ath5k_hw_reg_read(ah, reg_offset); 23562306a36Sopenharmony_ci} 23662306a36Sopenharmony_ci 23762306a36Sopenharmony_cistatic void ath5k_iowrite32(void *hw_priv, u32 val, u32 reg_offset) 23862306a36Sopenharmony_ci{ 23962306a36Sopenharmony_ci struct ath5k_hw *ah = (struct ath5k_hw *) hw_priv; 24062306a36Sopenharmony_ci ath5k_hw_reg_write(ah, val, reg_offset); 24162306a36Sopenharmony_ci} 24262306a36Sopenharmony_ci 24362306a36Sopenharmony_cistatic const struct ath_ops ath5k_common_ops = { 24462306a36Sopenharmony_ci .read = ath5k_ioread32, 24562306a36Sopenharmony_ci .write = ath5k_iowrite32, 24662306a36Sopenharmony_ci}; 24762306a36Sopenharmony_ci 24862306a36Sopenharmony_ci/***********************\ 24962306a36Sopenharmony_ci* Driver Initialization * 25062306a36Sopenharmony_ci\***********************/ 25162306a36Sopenharmony_ci 25262306a36Sopenharmony_cistatic void ath5k_reg_notifier(struct wiphy *wiphy, 25362306a36Sopenharmony_ci struct regulatory_request *request) 25462306a36Sopenharmony_ci{ 25562306a36Sopenharmony_ci struct ieee80211_hw *hw = wiphy_to_ieee80211_hw(wiphy); 25662306a36Sopenharmony_ci struct ath5k_hw *ah = hw->priv; 25762306a36Sopenharmony_ci struct ath_regulatory *regulatory = ath5k_hw_regulatory(ah); 25862306a36Sopenharmony_ci 25962306a36Sopenharmony_ci ath_reg_notifier_apply(wiphy, request, regulatory); 26062306a36Sopenharmony_ci} 26162306a36Sopenharmony_ci 26262306a36Sopenharmony_ci/********************\ 26362306a36Sopenharmony_ci* Channel/mode setup * 26462306a36Sopenharmony_ci\********************/ 26562306a36Sopenharmony_ci 26662306a36Sopenharmony_ci/* 26762306a36Sopenharmony_ci * Returns true for the channel numbers used. 26862306a36Sopenharmony_ci */ 26962306a36Sopenharmony_ci#ifdef CONFIG_ATH5K_TEST_CHANNELS 27062306a36Sopenharmony_cistatic bool ath5k_is_standard_channel(short chan, enum nl80211_band band) 27162306a36Sopenharmony_ci{ 27262306a36Sopenharmony_ci return true; 27362306a36Sopenharmony_ci} 27462306a36Sopenharmony_ci 27562306a36Sopenharmony_ci#else 27662306a36Sopenharmony_cistatic bool ath5k_is_standard_channel(short chan, enum nl80211_band band) 27762306a36Sopenharmony_ci{ 27862306a36Sopenharmony_ci if (band == NL80211_BAND_2GHZ && chan <= 14) 27962306a36Sopenharmony_ci return true; 28062306a36Sopenharmony_ci 28162306a36Sopenharmony_ci return /* UNII 1,2 */ 28262306a36Sopenharmony_ci (((chan & 3) == 0 && chan >= 36 && chan <= 64) || 28362306a36Sopenharmony_ci /* midband */ 28462306a36Sopenharmony_ci ((chan & 3) == 0 && chan >= 100 && chan <= 140) || 28562306a36Sopenharmony_ci /* UNII-3 */ 28662306a36Sopenharmony_ci ((chan & 3) == 1 && chan >= 149 && chan <= 165) || 28762306a36Sopenharmony_ci /* 802.11j 5.030-5.080 GHz (20MHz) */ 28862306a36Sopenharmony_ci (chan == 8 || chan == 12 || chan == 16) || 28962306a36Sopenharmony_ci /* 802.11j 4.9GHz (20MHz) */ 29062306a36Sopenharmony_ci (chan == 184 || chan == 188 || chan == 192 || chan == 196)); 29162306a36Sopenharmony_ci} 29262306a36Sopenharmony_ci#endif 29362306a36Sopenharmony_ci 29462306a36Sopenharmony_cistatic unsigned int 29562306a36Sopenharmony_ciath5k_setup_channels(struct ath5k_hw *ah, struct ieee80211_channel *channels, 29662306a36Sopenharmony_ci unsigned int mode, unsigned int max) 29762306a36Sopenharmony_ci{ 29862306a36Sopenharmony_ci unsigned int count, size, freq, ch; 29962306a36Sopenharmony_ci enum nl80211_band band; 30062306a36Sopenharmony_ci 30162306a36Sopenharmony_ci switch (mode) { 30262306a36Sopenharmony_ci case AR5K_MODE_11A: 30362306a36Sopenharmony_ci /* 1..220, but 2GHz frequencies are filtered by check_channel */ 30462306a36Sopenharmony_ci size = 220; 30562306a36Sopenharmony_ci band = NL80211_BAND_5GHZ; 30662306a36Sopenharmony_ci break; 30762306a36Sopenharmony_ci case AR5K_MODE_11B: 30862306a36Sopenharmony_ci case AR5K_MODE_11G: 30962306a36Sopenharmony_ci size = 26; 31062306a36Sopenharmony_ci band = NL80211_BAND_2GHZ; 31162306a36Sopenharmony_ci break; 31262306a36Sopenharmony_ci default: 31362306a36Sopenharmony_ci ATH5K_WARN(ah, "bad mode, not copying channels\n"); 31462306a36Sopenharmony_ci return 0; 31562306a36Sopenharmony_ci } 31662306a36Sopenharmony_ci 31762306a36Sopenharmony_ci count = 0; 31862306a36Sopenharmony_ci for (ch = 1; ch <= size && count < max; ch++) { 31962306a36Sopenharmony_ci freq = ieee80211_channel_to_frequency(ch, band); 32062306a36Sopenharmony_ci 32162306a36Sopenharmony_ci if (freq == 0) /* mapping failed - not a standard channel */ 32262306a36Sopenharmony_ci continue; 32362306a36Sopenharmony_ci 32462306a36Sopenharmony_ci /* Write channel info, needed for ath5k_channel_ok() */ 32562306a36Sopenharmony_ci channels[count].center_freq = freq; 32662306a36Sopenharmony_ci channels[count].band = band; 32762306a36Sopenharmony_ci channels[count].hw_value = mode; 32862306a36Sopenharmony_ci 32962306a36Sopenharmony_ci /* Check if channel is supported by the chipset */ 33062306a36Sopenharmony_ci if (!ath5k_channel_ok(ah, &channels[count])) 33162306a36Sopenharmony_ci continue; 33262306a36Sopenharmony_ci 33362306a36Sopenharmony_ci if (!ath5k_is_standard_channel(ch, band)) 33462306a36Sopenharmony_ci continue; 33562306a36Sopenharmony_ci 33662306a36Sopenharmony_ci count++; 33762306a36Sopenharmony_ci } 33862306a36Sopenharmony_ci 33962306a36Sopenharmony_ci return count; 34062306a36Sopenharmony_ci} 34162306a36Sopenharmony_ci 34262306a36Sopenharmony_cistatic void 34362306a36Sopenharmony_ciath5k_setup_rate_idx(struct ath5k_hw *ah, struct ieee80211_supported_band *b) 34462306a36Sopenharmony_ci{ 34562306a36Sopenharmony_ci u8 i; 34662306a36Sopenharmony_ci 34762306a36Sopenharmony_ci for (i = 0; i < AR5K_MAX_RATES; i++) 34862306a36Sopenharmony_ci ah->rate_idx[b->band][i] = -1; 34962306a36Sopenharmony_ci 35062306a36Sopenharmony_ci for (i = 0; i < b->n_bitrates; i++) { 35162306a36Sopenharmony_ci ah->rate_idx[b->band][b->bitrates[i].hw_value] = i; 35262306a36Sopenharmony_ci if (b->bitrates[i].hw_value_short) 35362306a36Sopenharmony_ci ah->rate_idx[b->band][b->bitrates[i].hw_value_short] = i; 35462306a36Sopenharmony_ci } 35562306a36Sopenharmony_ci} 35662306a36Sopenharmony_ci 35762306a36Sopenharmony_cistatic int 35862306a36Sopenharmony_ciath5k_setup_bands(struct ieee80211_hw *hw) 35962306a36Sopenharmony_ci{ 36062306a36Sopenharmony_ci struct ath5k_hw *ah = hw->priv; 36162306a36Sopenharmony_ci struct ieee80211_supported_band *sband; 36262306a36Sopenharmony_ci int max_c, count_c = 0; 36362306a36Sopenharmony_ci int i; 36462306a36Sopenharmony_ci 36562306a36Sopenharmony_ci BUILD_BUG_ON(ARRAY_SIZE(ah->sbands) < NUM_NL80211_BANDS); 36662306a36Sopenharmony_ci max_c = ARRAY_SIZE(ah->channels); 36762306a36Sopenharmony_ci 36862306a36Sopenharmony_ci /* 2GHz band */ 36962306a36Sopenharmony_ci sband = &ah->sbands[NL80211_BAND_2GHZ]; 37062306a36Sopenharmony_ci sband->band = NL80211_BAND_2GHZ; 37162306a36Sopenharmony_ci sband->bitrates = &ah->rates[NL80211_BAND_2GHZ][0]; 37262306a36Sopenharmony_ci 37362306a36Sopenharmony_ci if (test_bit(AR5K_MODE_11G, ah->ah_capabilities.cap_mode)) { 37462306a36Sopenharmony_ci /* G mode */ 37562306a36Sopenharmony_ci memcpy(sband->bitrates, &ath5k_rates[0], 37662306a36Sopenharmony_ci sizeof(struct ieee80211_rate) * 12); 37762306a36Sopenharmony_ci sband->n_bitrates = 12; 37862306a36Sopenharmony_ci 37962306a36Sopenharmony_ci sband->channels = ah->channels; 38062306a36Sopenharmony_ci sband->n_channels = ath5k_setup_channels(ah, sband->channels, 38162306a36Sopenharmony_ci AR5K_MODE_11G, max_c); 38262306a36Sopenharmony_ci 38362306a36Sopenharmony_ci hw->wiphy->bands[NL80211_BAND_2GHZ] = sband; 38462306a36Sopenharmony_ci count_c = sband->n_channels; 38562306a36Sopenharmony_ci max_c -= count_c; 38662306a36Sopenharmony_ci } else if (test_bit(AR5K_MODE_11B, ah->ah_capabilities.cap_mode)) { 38762306a36Sopenharmony_ci /* B mode */ 38862306a36Sopenharmony_ci memcpy(sband->bitrates, &ath5k_rates[0], 38962306a36Sopenharmony_ci sizeof(struct ieee80211_rate) * 4); 39062306a36Sopenharmony_ci sband->n_bitrates = 4; 39162306a36Sopenharmony_ci 39262306a36Sopenharmony_ci /* 5211 only supports B rates and uses 4bit rate codes 39362306a36Sopenharmony_ci * (e.g normally we have 0x1B for 1M, but on 5211 we have 0x0B) 39462306a36Sopenharmony_ci * fix them up here: 39562306a36Sopenharmony_ci */ 39662306a36Sopenharmony_ci if (ah->ah_version == AR5K_AR5211) { 39762306a36Sopenharmony_ci for (i = 0; i < 4; i++) { 39862306a36Sopenharmony_ci sband->bitrates[i].hw_value = 39962306a36Sopenharmony_ci sband->bitrates[i].hw_value & 0xF; 40062306a36Sopenharmony_ci sband->bitrates[i].hw_value_short = 40162306a36Sopenharmony_ci sband->bitrates[i].hw_value_short & 0xF; 40262306a36Sopenharmony_ci } 40362306a36Sopenharmony_ci } 40462306a36Sopenharmony_ci 40562306a36Sopenharmony_ci sband->channels = ah->channels; 40662306a36Sopenharmony_ci sband->n_channels = ath5k_setup_channels(ah, sband->channels, 40762306a36Sopenharmony_ci AR5K_MODE_11B, max_c); 40862306a36Sopenharmony_ci 40962306a36Sopenharmony_ci hw->wiphy->bands[NL80211_BAND_2GHZ] = sband; 41062306a36Sopenharmony_ci count_c = sband->n_channels; 41162306a36Sopenharmony_ci max_c -= count_c; 41262306a36Sopenharmony_ci } 41362306a36Sopenharmony_ci ath5k_setup_rate_idx(ah, sband); 41462306a36Sopenharmony_ci 41562306a36Sopenharmony_ci /* 5GHz band, A mode */ 41662306a36Sopenharmony_ci if (test_bit(AR5K_MODE_11A, ah->ah_capabilities.cap_mode)) { 41762306a36Sopenharmony_ci sband = &ah->sbands[NL80211_BAND_5GHZ]; 41862306a36Sopenharmony_ci sband->band = NL80211_BAND_5GHZ; 41962306a36Sopenharmony_ci sband->bitrates = &ah->rates[NL80211_BAND_5GHZ][0]; 42062306a36Sopenharmony_ci 42162306a36Sopenharmony_ci memcpy(sband->bitrates, &ath5k_rates[4], 42262306a36Sopenharmony_ci sizeof(struct ieee80211_rate) * 8); 42362306a36Sopenharmony_ci sband->n_bitrates = 8; 42462306a36Sopenharmony_ci 42562306a36Sopenharmony_ci sband->channels = &ah->channels[count_c]; 42662306a36Sopenharmony_ci sband->n_channels = ath5k_setup_channels(ah, sband->channels, 42762306a36Sopenharmony_ci AR5K_MODE_11A, max_c); 42862306a36Sopenharmony_ci 42962306a36Sopenharmony_ci hw->wiphy->bands[NL80211_BAND_5GHZ] = sband; 43062306a36Sopenharmony_ci } 43162306a36Sopenharmony_ci ath5k_setup_rate_idx(ah, sband); 43262306a36Sopenharmony_ci 43362306a36Sopenharmony_ci ath5k_debug_dump_bands(ah); 43462306a36Sopenharmony_ci 43562306a36Sopenharmony_ci return 0; 43662306a36Sopenharmony_ci} 43762306a36Sopenharmony_ci 43862306a36Sopenharmony_ci/* 43962306a36Sopenharmony_ci * Set/change channels. We always reset the chip. 44062306a36Sopenharmony_ci * To accomplish this we must first cleanup any pending DMA, 44162306a36Sopenharmony_ci * then restart stuff after a la ath5k_init. 44262306a36Sopenharmony_ci * 44362306a36Sopenharmony_ci * Called with ah->lock. 44462306a36Sopenharmony_ci */ 44562306a36Sopenharmony_ciint 44662306a36Sopenharmony_ciath5k_chan_set(struct ath5k_hw *ah, struct cfg80211_chan_def *chandef) 44762306a36Sopenharmony_ci{ 44862306a36Sopenharmony_ci ATH5K_DBG(ah, ATH5K_DEBUG_RESET, 44962306a36Sopenharmony_ci "channel set, resetting (%u -> %u MHz)\n", 45062306a36Sopenharmony_ci ah->curchan->center_freq, chandef->chan->center_freq); 45162306a36Sopenharmony_ci 45262306a36Sopenharmony_ci switch (chandef->width) { 45362306a36Sopenharmony_ci case NL80211_CHAN_WIDTH_20: 45462306a36Sopenharmony_ci case NL80211_CHAN_WIDTH_20_NOHT: 45562306a36Sopenharmony_ci ah->ah_bwmode = AR5K_BWMODE_DEFAULT; 45662306a36Sopenharmony_ci break; 45762306a36Sopenharmony_ci case NL80211_CHAN_WIDTH_5: 45862306a36Sopenharmony_ci ah->ah_bwmode = AR5K_BWMODE_5MHZ; 45962306a36Sopenharmony_ci break; 46062306a36Sopenharmony_ci case NL80211_CHAN_WIDTH_10: 46162306a36Sopenharmony_ci ah->ah_bwmode = AR5K_BWMODE_10MHZ; 46262306a36Sopenharmony_ci break; 46362306a36Sopenharmony_ci default: 46462306a36Sopenharmony_ci WARN_ON(1); 46562306a36Sopenharmony_ci return -EINVAL; 46662306a36Sopenharmony_ci } 46762306a36Sopenharmony_ci 46862306a36Sopenharmony_ci /* 46962306a36Sopenharmony_ci * To switch channels clear any pending DMA operations; 47062306a36Sopenharmony_ci * wait long enough for the RX fifo to drain, reset the 47162306a36Sopenharmony_ci * hardware at the new frequency, and then re-enable 47262306a36Sopenharmony_ci * the relevant bits of the h/w. 47362306a36Sopenharmony_ci */ 47462306a36Sopenharmony_ci return ath5k_reset(ah, chandef->chan, true); 47562306a36Sopenharmony_ci} 47662306a36Sopenharmony_ci 47762306a36Sopenharmony_civoid ath5k_vif_iter(void *data, u8 *mac, struct ieee80211_vif *vif) 47862306a36Sopenharmony_ci{ 47962306a36Sopenharmony_ci struct ath5k_vif_iter_data *iter_data = data; 48062306a36Sopenharmony_ci int i; 48162306a36Sopenharmony_ci struct ath5k_vif *avf = (void *)vif->drv_priv; 48262306a36Sopenharmony_ci 48362306a36Sopenharmony_ci if (iter_data->hw_macaddr) 48462306a36Sopenharmony_ci for (i = 0; i < ETH_ALEN; i++) 48562306a36Sopenharmony_ci iter_data->mask[i] &= 48662306a36Sopenharmony_ci ~(iter_data->hw_macaddr[i] ^ mac[i]); 48762306a36Sopenharmony_ci 48862306a36Sopenharmony_ci if (!iter_data->found_active) { 48962306a36Sopenharmony_ci iter_data->found_active = true; 49062306a36Sopenharmony_ci memcpy(iter_data->active_mac, mac, ETH_ALEN); 49162306a36Sopenharmony_ci } 49262306a36Sopenharmony_ci 49362306a36Sopenharmony_ci if (iter_data->need_set_hw_addr && iter_data->hw_macaddr) 49462306a36Sopenharmony_ci if (ether_addr_equal(iter_data->hw_macaddr, mac)) 49562306a36Sopenharmony_ci iter_data->need_set_hw_addr = false; 49662306a36Sopenharmony_ci 49762306a36Sopenharmony_ci if (!iter_data->any_assoc) { 49862306a36Sopenharmony_ci if (avf->assoc) 49962306a36Sopenharmony_ci iter_data->any_assoc = true; 50062306a36Sopenharmony_ci } 50162306a36Sopenharmony_ci 50262306a36Sopenharmony_ci /* Calculate combined mode - when APs are active, operate in AP mode. 50362306a36Sopenharmony_ci * Otherwise use the mode of the new interface. This can currently 50462306a36Sopenharmony_ci * only deal with combinations of APs and STAs. Only one ad-hoc 50562306a36Sopenharmony_ci * interfaces is allowed. 50662306a36Sopenharmony_ci */ 50762306a36Sopenharmony_ci if (avf->opmode == NL80211_IFTYPE_AP) 50862306a36Sopenharmony_ci iter_data->opmode = NL80211_IFTYPE_AP; 50962306a36Sopenharmony_ci else { 51062306a36Sopenharmony_ci if (avf->opmode == NL80211_IFTYPE_STATION) 51162306a36Sopenharmony_ci iter_data->n_stas++; 51262306a36Sopenharmony_ci if (iter_data->opmode == NL80211_IFTYPE_UNSPECIFIED) 51362306a36Sopenharmony_ci iter_data->opmode = avf->opmode; 51462306a36Sopenharmony_ci } 51562306a36Sopenharmony_ci} 51662306a36Sopenharmony_ci 51762306a36Sopenharmony_civoid 51862306a36Sopenharmony_ciath5k_update_bssid_mask_and_opmode(struct ath5k_hw *ah, 51962306a36Sopenharmony_ci struct ieee80211_vif *vif) 52062306a36Sopenharmony_ci{ 52162306a36Sopenharmony_ci struct ath_common *common = ath5k_hw_common(ah); 52262306a36Sopenharmony_ci struct ath5k_vif_iter_data iter_data; 52362306a36Sopenharmony_ci u32 rfilt; 52462306a36Sopenharmony_ci 52562306a36Sopenharmony_ci /* 52662306a36Sopenharmony_ci * Use the hardware MAC address as reference, the hardware uses it 52762306a36Sopenharmony_ci * together with the BSSID mask when matching addresses. 52862306a36Sopenharmony_ci */ 52962306a36Sopenharmony_ci iter_data.hw_macaddr = common->macaddr; 53062306a36Sopenharmony_ci eth_broadcast_addr(iter_data.mask); 53162306a36Sopenharmony_ci iter_data.found_active = false; 53262306a36Sopenharmony_ci iter_data.need_set_hw_addr = true; 53362306a36Sopenharmony_ci iter_data.opmode = NL80211_IFTYPE_UNSPECIFIED; 53462306a36Sopenharmony_ci iter_data.n_stas = 0; 53562306a36Sopenharmony_ci 53662306a36Sopenharmony_ci if (vif) 53762306a36Sopenharmony_ci ath5k_vif_iter(&iter_data, vif->addr, vif); 53862306a36Sopenharmony_ci 53962306a36Sopenharmony_ci /* Get list of all active MAC addresses */ 54062306a36Sopenharmony_ci ieee80211_iterate_active_interfaces_atomic( 54162306a36Sopenharmony_ci ah->hw, IEEE80211_IFACE_ITER_RESUME_ALL, 54262306a36Sopenharmony_ci ath5k_vif_iter, &iter_data); 54362306a36Sopenharmony_ci memcpy(ah->bssidmask, iter_data.mask, ETH_ALEN); 54462306a36Sopenharmony_ci 54562306a36Sopenharmony_ci ah->opmode = iter_data.opmode; 54662306a36Sopenharmony_ci if (ah->opmode == NL80211_IFTYPE_UNSPECIFIED) 54762306a36Sopenharmony_ci /* Nothing active, default to station mode */ 54862306a36Sopenharmony_ci ah->opmode = NL80211_IFTYPE_STATION; 54962306a36Sopenharmony_ci 55062306a36Sopenharmony_ci ath5k_hw_set_opmode(ah, ah->opmode); 55162306a36Sopenharmony_ci ATH5K_DBG(ah, ATH5K_DEBUG_MODE, "mode setup opmode %d (%s)\n", 55262306a36Sopenharmony_ci ah->opmode, ath_opmode_to_string(ah->opmode)); 55362306a36Sopenharmony_ci 55462306a36Sopenharmony_ci if (iter_data.need_set_hw_addr && iter_data.found_active) 55562306a36Sopenharmony_ci ath5k_hw_set_lladdr(ah, iter_data.active_mac); 55662306a36Sopenharmony_ci 55762306a36Sopenharmony_ci if (ath5k_hw_hasbssidmask(ah)) 55862306a36Sopenharmony_ci ath5k_hw_set_bssid_mask(ah, ah->bssidmask); 55962306a36Sopenharmony_ci 56062306a36Sopenharmony_ci /* Set up RX Filter */ 56162306a36Sopenharmony_ci if (iter_data.n_stas > 1) { 56262306a36Sopenharmony_ci /* If you have multiple STA interfaces connected to 56362306a36Sopenharmony_ci * different APs, ARPs are not received (most of the time?) 56462306a36Sopenharmony_ci * Enabling PROMISC appears to fix that problem. 56562306a36Sopenharmony_ci */ 56662306a36Sopenharmony_ci ah->filter_flags |= AR5K_RX_FILTER_PROM; 56762306a36Sopenharmony_ci } 56862306a36Sopenharmony_ci 56962306a36Sopenharmony_ci rfilt = ah->filter_flags; 57062306a36Sopenharmony_ci ath5k_hw_set_rx_filter(ah, rfilt); 57162306a36Sopenharmony_ci ATH5K_DBG(ah, ATH5K_DEBUG_MODE, "RX filter 0x%x\n", rfilt); 57262306a36Sopenharmony_ci} 57362306a36Sopenharmony_ci 57462306a36Sopenharmony_cistatic inline int 57562306a36Sopenharmony_ciath5k_hw_to_driver_rix(struct ath5k_hw *ah, int hw_rix) 57662306a36Sopenharmony_ci{ 57762306a36Sopenharmony_ci int rix; 57862306a36Sopenharmony_ci 57962306a36Sopenharmony_ci /* return base rate on errors */ 58062306a36Sopenharmony_ci if (WARN(hw_rix < 0 || hw_rix >= AR5K_MAX_RATES, 58162306a36Sopenharmony_ci "hw_rix out of bounds: %x\n", hw_rix)) 58262306a36Sopenharmony_ci return 0; 58362306a36Sopenharmony_ci 58462306a36Sopenharmony_ci rix = ah->rate_idx[ah->curchan->band][hw_rix]; 58562306a36Sopenharmony_ci if (WARN(rix < 0, "invalid hw_rix: %x\n", hw_rix)) 58662306a36Sopenharmony_ci rix = 0; 58762306a36Sopenharmony_ci 58862306a36Sopenharmony_ci return rix; 58962306a36Sopenharmony_ci} 59062306a36Sopenharmony_ci 59162306a36Sopenharmony_ci/***************\ 59262306a36Sopenharmony_ci* Buffers setup * 59362306a36Sopenharmony_ci\***************/ 59462306a36Sopenharmony_ci 59562306a36Sopenharmony_cistatic 59662306a36Sopenharmony_cistruct sk_buff *ath5k_rx_skb_alloc(struct ath5k_hw *ah, dma_addr_t *skb_addr) 59762306a36Sopenharmony_ci{ 59862306a36Sopenharmony_ci struct ath_common *common = ath5k_hw_common(ah); 59962306a36Sopenharmony_ci struct sk_buff *skb; 60062306a36Sopenharmony_ci 60162306a36Sopenharmony_ci /* 60262306a36Sopenharmony_ci * Allocate buffer with headroom_needed space for the 60362306a36Sopenharmony_ci * fake physical layer header at the start. 60462306a36Sopenharmony_ci */ 60562306a36Sopenharmony_ci skb = ath_rxbuf_alloc(common, 60662306a36Sopenharmony_ci common->rx_bufsize, 60762306a36Sopenharmony_ci GFP_ATOMIC); 60862306a36Sopenharmony_ci 60962306a36Sopenharmony_ci if (!skb) { 61062306a36Sopenharmony_ci ATH5K_ERR(ah, "can't alloc skbuff of size %u\n", 61162306a36Sopenharmony_ci common->rx_bufsize); 61262306a36Sopenharmony_ci return NULL; 61362306a36Sopenharmony_ci } 61462306a36Sopenharmony_ci 61562306a36Sopenharmony_ci *skb_addr = dma_map_single(ah->dev, 61662306a36Sopenharmony_ci skb->data, common->rx_bufsize, 61762306a36Sopenharmony_ci DMA_FROM_DEVICE); 61862306a36Sopenharmony_ci 61962306a36Sopenharmony_ci if (unlikely(dma_mapping_error(ah->dev, *skb_addr))) { 62062306a36Sopenharmony_ci ATH5K_ERR(ah, "%s: DMA mapping failed\n", __func__); 62162306a36Sopenharmony_ci dev_kfree_skb(skb); 62262306a36Sopenharmony_ci return NULL; 62362306a36Sopenharmony_ci } 62462306a36Sopenharmony_ci return skb; 62562306a36Sopenharmony_ci} 62662306a36Sopenharmony_ci 62762306a36Sopenharmony_cistatic int 62862306a36Sopenharmony_ciath5k_rxbuf_setup(struct ath5k_hw *ah, struct ath5k_buf *bf) 62962306a36Sopenharmony_ci{ 63062306a36Sopenharmony_ci struct sk_buff *skb = bf->skb; 63162306a36Sopenharmony_ci struct ath5k_desc *ds; 63262306a36Sopenharmony_ci int ret; 63362306a36Sopenharmony_ci 63462306a36Sopenharmony_ci if (!skb) { 63562306a36Sopenharmony_ci skb = ath5k_rx_skb_alloc(ah, &bf->skbaddr); 63662306a36Sopenharmony_ci if (!skb) 63762306a36Sopenharmony_ci return -ENOMEM; 63862306a36Sopenharmony_ci bf->skb = skb; 63962306a36Sopenharmony_ci } 64062306a36Sopenharmony_ci 64162306a36Sopenharmony_ci /* 64262306a36Sopenharmony_ci * Setup descriptors. For receive we always terminate 64362306a36Sopenharmony_ci * the descriptor list with a self-linked entry so we'll 64462306a36Sopenharmony_ci * not get overrun under high load (as can happen with a 64562306a36Sopenharmony_ci * 5212 when ANI processing enables PHY error frames). 64662306a36Sopenharmony_ci * 64762306a36Sopenharmony_ci * To ensure the last descriptor is self-linked we create 64862306a36Sopenharmony_ci * each descriptor as self-linked and add it to the end. As 64962306a36Sopenharmony_ci * each additional descriptor is added the previous self-linked 65062306a36Sopenharmony_ci * entry is "fixed" naturally. This should be safe even 65162306a36Sopenharmony_ci * if DMA is happening. When processing RX interrupts we 65262306a36Sopenharmony_ci * never remove/process the last, self-linked, entry on the 65362306a36Sopenharmony_ci * descriptor list. This ensures the hardware always has 65462306a36Sopenharmony_ci * someplace to write a new frame. 65562306a36Sopenharmony_ci */ 65662306a36Sopenharmony_ci ds = bf->desc; 65762306a36Sopenharmony_ci ds->ds_link = bf->daddr; /* link to self */ 65862306a36Sopenharmony_ci ds->ds_data = bf->skbaddr; 65962306a36Sopenharmony_ci ret = ath5k_hw_setup_rx_desc(ah, ds, ah->common.rx_bufsize, 0); 66062306a36Sopenharmony_ci if (ret) { 66162306a36Sopenharmony_ci ATH5K_ERR(ah, "%s: could not setup RX desc\n", __func__); 66262306a36Sopenharmony_ci return ret; 66362306a36Sopenharmony_ci } 66462306a36Sopenharmony_ci 66562306a36Sopenharmony_ci if (ah->rxlink != NULL) 66662306a36Sopenharmony_ci *ah->rxlink = bf->daddr; 66762306a36Sopenharmony_ci ah->rxlink = &ds->ds_link; 66862306a36Sopenharmony_ci return 0; 66962306a36Sopenharmony_ci} 67062306a36Sopenharmony_ci 67162306a36Sopenharmony_cistatic enum ath5k_pkt_type get_hw_packet_type(struct sk_buff *skb) 67262306a36Sopenharmony_ci{ 67362306a36Sopenharmony_ci struct ieee80211_hdr *hdr; 67462306a36Sopenharmony_ci enum ath5k_pkt_type htype; 67562306a36Sopenharmony_ci __le16 fc; 67662306a36Sopenharmony_ci 67762306a36Sopenharmony_ci hdr = (struct ieee80211_hdr *)skb->data; 67862306a36Sopenharmony_ci fc = hdr->frame_control; 67962306a36Sopenharmony_ci 68062306a36Sopenharmony_ci if (ieee80211_is_beacon(fc)) 68162306a36Sopenharmony_ci htype = AR5K_PKT_TYPE_BEACON; 68262306a36Sopenharmony_ci else if (ieee80211_is_probe_resp(fc)) 68362306a36Sopenharmony_ci htype = AR5K_PKT_TYPE_PROBE_RESP; 68462306a36Sopenharmony_ci else if (ieee80211_is_atim(fc)) 68562306a36Sopenharmony_ci htype = AR5K_PKT_TYPE_ATIM; 68662306a36Sopenharmony_ci else if (ieee80211_is_pspoll(fc)) 68762306a36Sopenharmony_ci htype = AR5K_PKT_TYPE_PSPOLL; 68862306a36Sopenharmony_ci else 68962306a36Sopenharmony_ci htype = AR5K_PKT_TYPE_NORMAL; 69062306a36Sopenharmony_ci 69162306a36Sopenharmony_ci return htype; 69262306a36Sopenharmony_ci} 69362306a36Sopenharmony_ci 69462306a36Sopenharmony_cistatic struct ieee80211_rate * 69562306a36Sopenharmony_ciath5k_get_rate(const struct ieee80211_hw *hw, 69662306a36Sopenharmony_ci const struct ieee80211_tx_info *info, 69762306a36Sopenharmony_ci struct ath5k_buf *bf, int idx) 69862306a36Sopenharmony_ci{ 69962306a36Sopenharmony_ci /* 70062306a36Sopenharmony_ci * convert a ieee80211_tx_rate RC-table entry to 70162306a36Sopenharmony_ci * the respective ieee80211_rate struct 70262306a36Sopenharmony_ci */ 70362306a36Sopenharmony_ci if (bf->rates[idx].idx < 0) { 70462306a36Sopenharmony_ci return NULL; 70562306a36Sopenharmony_ci } 70662306a36Sopenharmony_ci 70762306a36Sopenharmony_ci return &hw->wiphy->bands[info->band]->bitrates[ bf->rates[idx].idx ]; 70862306a36Sopenharmony_ci} 70962306a36Sopenharmony_ci 71062306a36Sopenharmony_cistatic u16 71162306a36Sopenharmony_ciath5k_get_rate_hw_value(const struct ieee80211_hw *hw, 71262306a36Sopenharmony_ci const struct ieee80211_tx_info *info, 71362306a36Sopenharmony_ci struct ath5k_buf *bf, int idx) 71462306a36Sopenharmony_ci{ 71562306a36Sopenharmony_ci struct ieee80211_rate *rate; 71662306a36Sopenharmony_ci u16 hw_rate; 71762306a36Sopenharmony_ci u8 rc_flags; 71862306a36Sopenharmony_ci 71962306a36Sopenharmony_ci rate = ath5k_get_rate(hw, info, bf, idx); 72062306a36Sopenharmony_ci if (!rate) 72162306a36Sopenharmony_ci return 0; 72262306a36Sopenharmony_ci 72362306a36Sopenharmony_ci rc_flags = bf->rates[idx].flags; 72462306a36Sopenharmony_ci hw_rate = (rc_flags & IEEE80211_TX_RC_USE_SHORT_PREAMBLE) ? 72562306a36Sopenharmony_ci rate->hw_value_short : rate->hw_value; 72662306a36Sopenharmony_ci 72762306a36Sopenharmony_ci return hw_rate; 72862306a36Sopenharmony_ci} 72962306a36Sopenharmony_ci 73062306a36Sopenharmony_cistatic bool ath5k_merge_ratetbl(struct ieee80211_sta *sta, 73162306a36Sopenharmony_ci struct ath5k_buf *bf, 73262306a36Sopenharmony_ci struct ieee80211_tx_info *tx_info) 73362306a36Sopenharmony_ci{ 73462306a36Sopenharmony_ci struct ieee80211_sta_rates *ratetbl; 73562306a36Sopenharmony_ci u8 i; 73662306a36Sopenharmony_ci 73762306a36Sopenharmony_ci if (!sta) 73862306a36Sopenharmony_ci return false; 73962306a36Sopenharmony_ci 74062306a36Sopenharmony_ci ratetbl = rcu_dereference(sta->rates); 74162306a36Sopenharmony_ci if (!ratetbl) 74262306a36Sopenharmony_ci return false; 74362306a36Sopenharmony_ci 74462306a36Sopenharmony_ci if (tx_info->control.rates[0].idx < 0 || 74562306a36Sopenharmony_ci tx_info->control.rates[0].count == 0) 74662306a36Sopenharmony_ci { 74762306a36Sopenharmony_ci i = 0; 74862306a36Sopenharmony_ci } else { 74962306a36Sopenharmony_ci bf->rates[0] = tx_info->control.rates[0]; 75062306a36Sopenharmony_ci i = 1; 75162306a36Sopenharmony_ci } 75262306a36Sopenharmony_ci 75362306a36Sopenharmony_ci for ( ; i < IEEE80211_TX_MAX_RATES; i++) { 75462306a36Sopenharmony_ci bf->rates[i].idx = ratetbl->rate[i].idx; 75562306a36Sopenharmony_ci bf->rates[i].flags = ratetbl->rate[i].flags; 75662306a36Sopenharmony_ci if (tx_info->control.use_rts) 75762306a36Sopenharmony_ci bf->rates[i].count = ratetbl->rate[i].count_rts; 75862306a36Sopenharmony_ci else if (tx_info->control.use_cts_prot) 75962306a36Sopenharmony_ci bf->rates[i].count = ratetbl->rate[i].count_cts; 76062306a36Sopenharmony_ci else 76162306a36Sopenharmony_ci bf->rates[i].count = ratetbl->rate[i].count; 76262306a36Sopenharmony_ci } 76362306a36Sopenharmony_ci 76462306a36Sopenharmony_ci return true; 76562306a36Sopenharmony_ci} 76662306a36Sopenharmony_ci 76762306a36Sopenharmony_cistatic int 76862306a36Sopenharmony_ciath5k_txbuf_setup(struct ath5k_hw *ah, struct ath5k_buf *bf, 76962306a36Sopenharmony_ci struct ath5k_txq *txq, int padsize, 77062306a36Sopenharmony_ci struct ieee80211_tx_control *control) 77162306a36Sopenharmony_ci{ 77262306a36Sopenharmony_ci struct ath5k_desc *ds = bf->desc; 77362306a36Sopenharmony_ci struct sk_buff *skb = bf->skb; 77462306a36Sopenharmony_ci struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); 77562306a36Sopenharmony_ci unsigned int pktlen, flags, keyidx = AR5K_TXKEYIX_INVALID; 77662306a36Sopenharmony_ci struct ieee80211_rate *rate; 77762306a36Sopenharmony_ci struct ieee80211_sta *sta; 77862306a36Sopenharmony_ci unsigned int mrr_rate[3], mrr_tries[3]; 77962306a36Sopenharmony_ci int i, ret; 78062306a36Sopenharmony_ci u16 hw_rate; 78162306a36Sopenharmony_ci u16 cts_rate = 0; 78262306a36Sopenharmony_ci u16 duration = 0; 78362306a36Sopenharmony_ci u8 rc_flags; 78462306a36Sopenharmony_ci 78562306a36Sopenharmony_ci flags = AR5K_TXDESC_INTREQ | AR5K_TXDESC_CLRDMASK; 78662306a36Sopenharmony_ci 78762306a36Sopenharmony_ci /* XXX endianness */ 78862306a36Sopenharmony_ci bf->skbaddr = dma_map_single(ah->dev, skb->data, skb->len, 78962306a36Sopenharmony_ci DMA_TO_DEVICE); 79062306a36Sopenharmony_ci 79162306a36Sopenharmony_ci if (dma_mapping_error(ah->dev, bf->skbaddr)) 79262306a36Sopenharmony_ci return -ENOSPC; 79362306a36Sopenharmony_ci 79462306a36Sopenharmony_ci if (control) 79562306a36Sopenharmony_ci sta = control->sta; 79662306a36Sopenharmony_ci else 79762306a36Sopenharmony_ci sta = NULL; 79862306a36Sopenharmony_ci 79962306a36Sopenharmony_ci if (!ath5k_merge_ratetbl(sta, bf, info)) { 80062306a36Sopenharmony_ci ieee80211_get_tx_rates(info->control.vif, 80162306a36Sopenharmony_ci sta, skb, bf->rates, 80262306a36Sopenharmony_ci ARRAY_SIZE(bf->rates)); 80362306a36Sopenharmony_ci } 80462306a36Sopenharmony_ci 80562306a36Sopenharmony_ci rate = ath5k_get_rate(ah->hw, info, bf, 0); 80662306a36Sopenharmony_ci 80762306a36Sopenharmony_ci if (!rate) { 80862306a36Sopenharmony_ci ret = -EINVAL; 80962306a36Sopenharmony_ci goto err_unmap; 81062306a36Sopenharmony_ci } 81162306a36Sopenharmony_ci 81262306a36Sopenharmony_ci if (info->flags & IEEE80211_TX_CTL_NO_ACK) 81362306a36Sopenharmony_ci flags |= AR5K_TXDESC_NOACK; 81462306a36Sopenharmony_ci 81562306a36Sopenharmony_ci rc_flags = bf->rates[0].flags; 81662306a36Sopenharmony_ci 81762306a36Sopenharmony_ci hw_rate = ath5k_get_rate_hw_value(ah->hw, info, bf, 0); 81862306a36Sopenharmony_ci 81962306a36Sopenharmony_ci pktlen = skb->len; 82062306a36Sopenharmony_ci 82162306a36Sopenharmony_ci /* FIXME: If we are in g mode and rate is a CCK rate 82262306a36Sopenharmony_ci * subtract ah->ah_txpower.txp_cck_ofdm_pwr_delta 82362306a36Sopenharmony_ci * from tx power (value is in dB units already) */ 82462306a36Sopenharmony_ci if (info->control.hw_key) { 82562306a36Sopenharmony_ci keyidx = info->control.hw_key->hw_key_idx; 82662306a36Sopenharmony_ci pktlen += info->control.hw_key->icv_len; 82762306a36Sopenharmony_ci } 82862306a36Sopenharmony_ci if (rc_flags & IEEE80211_TX_RC_USE_RTS_CTS) { 82962306a36Sopenharmony_ci flags |= AR5K_TXDESC_RTSENA; 83062306a36Sopenharmony_ci cts_rate = ieee80211_get_rts_cts_rate(ah->hw, info)->hw_value; 83162306a36Sopenharmony_ci duration = le16_to_cpu(ieee80211_rts_duration(ah->hw, 83262306a36Sopenharmony_ci info->control.vif, pktlen, info)); 83362306a36Sopenharmony_ci } 83462306a36Sopenharmony_ci if (rc_flags & IEEE80211_TX_RC_USE_CTS_PROTECT) { 83562306a36Sopenharmony_ci flags |= AR5K_TXDESC_CTSENA; 83662306a36Sopenharmony_ci cts_rate = ieee80211_get_rts_cts_rate(ah->hw, info)->hw_value; 83762306a36Sopenharmony_ci duration = le16_to_cpu(ieee80211_ctstoself_duration(ah->hw, 83862306a36Sopenharmony_ci info->control.vif, pktlen, info)); 83962306a36Sopenharmony_ci } 84062306a36Sopenharmony_ci 84162306a36Sopenharmony_ci ret = ah->ah_setup_tx_desc(ah, ds, pktlen, 84262306a36Sopenharmony_ci ieee80211_get_hdrlen_from_skb(skb), padsize, 84362306a36Sopenharmony_ci get_hw_packet_type(skb), 84462306a36Sopenharmony_ci (ah->ah_txpower.txp_requested * 2), 84562306a36Sopenharmony_ci hw_rate, 84662306a36Sopenharmony_ci bf->rates[0].count, keyidx, ah->ah_tx_ant, flags, 84762306a36Sopenharmony_ci cts_rate, duration); 84862306a36Sopenharmony_ci if (ret) 84962306a36Sopenharmony_ci goto err_unmap; 85062306a36Sopenharmony_ci 85162306a36Sopenharmony_ci /* Set up MRR descriptor */ 85262306a36Sopenharmony_ci if (ah->ah_capabilities.cap_has_mrr_support) { 85362306a36Sopenharmony_ci memset(mrr_rate, 0, sizeof(mrr_rate)); 85462306a36Sopenharmony_ci memset(mrr_tries, 0, sizeof(mrr_tries)); 85562306a36Sopenharmony_ci 85662306a36Sopenharmony_ci for (i = 0; i < 3; i++) { 85762306a36Sopenharmony_ci 85862306a36Sopenharmony_ci rate = ath5k_get_rate(ah->hw, info, bf, i); 85962306a36Sopenharmony_ci if (!rate) 86062306a36Sopenharmony_ci break; 86162306a36Sopenharmony_ci 86262306a36Sopenharmony_ci mrr_rate[i] = ath5k_get_rate_hw_value(ah->hw, info, bf, i); 86362306a36Sopenharmony_ci mrr_tries[i] = bf->rates[i].count; 86462306a36Sopenharmony_ci } 86562306a36Sopenharmony_ci 86662306a36Sopenharmony_ci ath5k_hw_setup_mrr_tx_desc(ah, ds, 86762306a36Sopenharmony_ci mrr_rate[0], mrr_tries[0], 86862306a36Sopenharmony_ci mrr_rate[1], mrr_tries[1], 86962306a36Sopenharmony_ci mrr_rate[2], mrr_tries[2]); 87062306a36Sopenharmony_ci } 87162306a36Sopenharmony_ci 87262306a36Sopenharmony_ci ds->ds_link = 0; 87362306a36Sopenharmony_ci ds->ds_data = bf->skbaddr; 87462306a36Sopenharmony_ci 87562306a36Sopenharmony_ci spin_lock_bh(&txq->lock); 87662306a36Sopenharmony_ci list_add_tail(&bf->list, &txq->q); 87762306a36Sopenharmony_ci txq->txq_len++; 87862306a36Sopenharmony_ci if (txq->link == NULL) /* is this first packet? */ 87962306a36Sopenharmony_ci ath5k_hw_set_txdp(ah, txq->qnum, bf->daddr); 88062306a36Sopenharmony_ci else /* no, so only link it */ 88162306a36Sopenharmony_ci *txq->link = bf->daddr; 88262306a36Sopenharmony_ci 88362306a36Sopenharmony_ci txq->link = &ds->ds_link; 88462306a36Sopenharmony_ci ath5k_hw_start_tx_dma(ah, txq->qnum); 88562306a36Sopenharmony_ci spin_unlock_bh(&txq->lock); 88662306a36Sopenharmony_ci 88762306a36Sopenharmony_ci return 0; 88862306a36Sopenharmony_cierr_unmap: 88962306a36Sopenharmony_ci dma_unmap_single(ah->dev, bf->skbaddr, skb->len, DMA_TO_DEVICE); 89062306a36Sopenharmony_ci return ret; 89162306a36Sopenharmony_ci} 89262306a36Sopenharmony_ci 89362306a36Sopenharmony_ci/*******************\ 89462306a36Sopenharmony_ci* Descriptors setup * 89562306a36Sopenharmony_ci\*******************/ 89662306a36Sopenharmony_ci 89762306a36Sopenharmony_cistatic int 89862306a36Sopenharmony_ciath5k_desc_alloc(struct ath5k_hw *ah) 89962306a36Sopenharmony_ci{ 90062306a36Sopenharmony_ci struct ath5k_desc *ds; 90162306a36Sopenharmony_ci struct ath5k_buf *bf; 90262306a36Sopenharmony_ci dma_addr_t da; 90362306a36Sopenharmony_ci unsigned int i; 90462306a36Sopenharmony_ci int ret; 90562306a36Sopenharmony_ci 90662306a36Sopenharmony_ci /* allocate descriptors */ 90762306a36Sopenharmony_ci ah->desc_len = sizeof(struct ath5k_desc) * 90862306a36Sopenharmony_ci (ATH_TXBUF + ATH_RXBUF + ATH_BCBUF + 1); 90962306a36Sopenharmony_ci 91062306a36Sopenharmony_ci ah->desc = dma_alloc_coherent(ah->dev, ah->desc_len, 91162306a36Sopenharmony_ci &ah->desc_daddr, GFP_KERNEL); 91262306a36Sopenharmony_ci if (ah->desc == NULL) { 91362306a36Sopenharmony_ci ATH5K_ERR(ah, "can't allocate descriptors\n"); 91462306a36Sopenharmony_ci ret = -ENOMEM; 91562306a36Sopenharmony_ci goto err; 91662306a36Sopenharmony_ci } 91762306a36Sopenharmony_ci ds = ah->desc; 91862306a36Sopenharmony_ci da = ah->desc_daddr; 91962306a36Sopenharmony_ci ATH5K_DBG(ah, ATH5K_DEBUG_ANY, "DMA map: %p (%zu) -> %llx\n", 92062306a36Sopenharmony_ci ds, ah->desc_len, (unsigned long long)ah->desc_daddr); 92162306a36Sopenharmony_ci 92262306a36Sopenharmony_ci bf = kcalloc(1 + ATH_TXBUF + ATH_RXBUF + ATH_BCBUF, 92362306a36Sopenharmony_ci sizeof(struct ath5k_buf), GFP_KERNEL); 92462306a36Sopenharmony_ci if (bf == NULL) { 92562306a36Sopenharmony_ci ATH5K_ERR(ah, "can't allocate bufptr\n"); 92662306a36Sopenharmony_ci ret = -ENOMEM; 92762306a36Sopenharmony_ci goto err_free; 92862306a36Sopenharmony_ci } 92962306a36Sopenharmony_ci ah->bufptr = bf; 93062306a36Sopenharmony_ci 93162306a36Sopenharmony_ci INIT_LIST_HEAD(&ah->rxbuf); 93262306a36Sopenharmony_ci for (i = 0; i < ATH_RXBUF; i++, bf++, ds++, da += sizeof(*ds)) { 93362306a36Sopenharmony_ci bf->desc = ds; 93462306a36Sopenharmony_ci bf->daddr = da; 93562306a36Sopenharmony_ci list_add_tail(&bf->list, &ah->rxbuf); 93662306a36Sopenharmony_ci } 93762306a36Sopenharmony_ci 93862306a36Sopenharmony_ci INIT_LIST_HEAD(&ah->txbuf); 93962306a36Sopenharmony_ci ah->txbuf_len = ATH_TXBUF; 94062306a36Sopenharmony_ci for (i = 0; i < ATH_TXBUF; i++, bf++, ds++, da += sizeof(*ds)) { 94162306a36Sopenharmony_ci bf->desc = ds; 94262306a36Sopenharmony_ci bf->daddr = da; 94362306a36Sopenharmony_ci list_add_tail(&bf->list, &ah->txbuf); 94462306a36Sopenharmony_ci } 94562306a36Sopenharmony_ci 94662306a36Sopenharmony_ci /* beacon buffers */ 94762306a36Sopenharmony_ci INIT_LIST_HEAD(&ah->bcbuf); 94862306a36Sopenharmony_ci for (i = 0; i < ATH_BCBUF; i++, bf++, ds++, da += sizeof(*ds)) { 94962306a36Sopenharmony_ci bf->desc = ds; 95062306a36Sopenharmony_ci bf->daddr = da; 95162306a36Sopenharmony_ci list_add_tail(&bf->list, &ah->bcbuf); 95262306a36Sopenharmony_ci } 95362306a36Sopenharmony_ci 95462306a36Sopenharmony_ci return 0; 95562306a36Sopenharmony_cierr_free: 95662306a36Sopenharmony_ci dma_free_coherent(ah->dev, ah->desc_len, ah->desc, ah->desc_daddr); 95762306a36Sopenharmony_cierr: 95862306a36Sopenharmony_ci ah->desc = NULL; 95962306a36Sopenharmony_ci return ret; 96062306a36Sopenharmony_ci} 96162306a36Sopenharmony_ci 96262306a36Sopenharmony_civoid 96362306a36Sopenharmony_ciath5k_txbuf_free_skb(struct ath5k_hw *ah, struct ath5k_buf *bf) 96462306a36Sopenharmony_ci{ 96562306a36Sopenharmony_ci BUG_ON(!bf); 96662306a36Sopenharmony_ci if (!bf->skb) 96762306a36Sopenharmony_ci return; 96862306a36Sopenharmony_ci dma_unmap_single(ah->dev, bf->skbaddr, bf->skb->len, 96962306a36Sopenharmony_ci DMA_TO_DEVICE); 97062306a36Sopenharmony_ci ieee80211_free_txskb(ah->hw, bf->skb); 97162306a36Sopenharmony_ci bf->skb = NULL; 97262306a36Sopenharmony_ci bf->skbaddr = 0; 97362306a36Sopenharmony_ci bf->desc->ds_data = 0; 97462306a36Sopenharmony_ci} 97562306a36Sopenharmony_ci 97662306a36Sopenharmony_civoid 97762306a36Sopenharmony_ciath5k_rxbuf_free_skb(struct ath5k_hw *ah, struct ath5k_buf *bf) 97862306a36Sopenharmony_ci{ 97962306a36Sopenharmony_ci struct ath_common *common = ath5k_hw_common(ah); 98062306a36Sopenharmony_ci 98162306a36Sopenharmony_ci BUG_ON(!bf); 98262306a36Sopenharmony_ci if (!bf->skb) 98362306a36Sopenharmony_ci return; 98462306a36Sopenharmony_ci dma_unmap_single(ah->dev, bf->skbaddr, common->rx_bufsize, 98562306a36Sopenharmony_ci DMA_FROM_DEVICE); 98662306a36Sopenharmony_ci dev_kfree_skb_any(bf->skb); 98762306a36Sopenharmony_ci bf->skb = NULL; 98862306a36Sopenharmony_ci bf->skbaddr = 0; 98962306a36Sopenharmony_ci bf->desc->ds_data = 0; 99062306a36Sopenharmony_ci} 99162306a36Sopenharmony_ci 99262306a36Sopenharmony_cistatic void 99362306a36Sopenharmony_ciath5k_desc_free(struct ath5k_hw *ah) 99462306a36Sopenharmony_ci{ 99562306a36Sopenharmony_ci struct ath5k_buf *bf; 99662306a36Sopenharmony_ci 99762306a36Sopenharmony_ci list_for_each_entry(bf, &ah->txbuf, list) 99862306a36Sopenharmony_ci ath5k_txbuf_free_skb(ah, bf); 99962306a36Sopenharmony_ci list_for_each_entry(bf, &ah->rxbuf, list) 100062306a36Sopenharmony_ci ath5k_rxbuf_free_skb(ah, bf); 100162306a36Sopenharmony_ci list_for_each_entry(bf, &ah->bcbuf, list) 100262306a36Sopenharmony_ci ath5k_txbuf_free_skb(ah, bf); 100362306a36Sopenharmony_ci 100462306a36Sopenharmony_ci /* Free memory associated with all descriptors */ 100562306a36Sopenharmony_ci dma_free_coherent(ah->dev, ah->desc_len, ah->desc, ah->desc_daddr); 100662306a36Sopenharmony_ci ah->desc = NULL; 100762306a36Sopenharmony_ci ah->desc_daddr = 0; 100862306a36Sopenharmony_ci 100962306a36Sopenharmony_ci kfree(ah->bufptr); 101062306a36Sopenharmony_ci ah->bufptr = NULL; 101162306a36Sopenharmony_ci} 101262306a36Sopenharmony_ci 101362306a36Sopenharmony_ci 101462306a36Sopenharmony_ci/**************\ 101562306a36Sopenharmony_ci* Queues setup * 101662306a36Sopenharmony_ci\**************/ 101762306a36Sopenharmony_ci 101862306a36Sopenharmony_cistatic struct ath5k_txq * 101962306a36Sopenharmony_ciath5k_txq_setup(struct ath5k_hw *ah, 102062306a36Sopenharmony_ci int qtype, int subtype) 102162306a36Sopenharmony_ci{ 102262306a36Sopenharmony_ci struct ath5k_txq *txq; 102362306a36Sopenharmony_ci struct ath5k_txq_info qi = { 102462306a36Sopenharmony_ci .tqi_subtype = subtype, 102562306a36Sopenharmony_ci /* XXX: default values not correct for B and XR channels, 102662306a36Sopenharmony_ci * but who cares? */ 102762306a36Sopenharmony_ci .tqi_aifs = AR5K_TUNE_AIFS, 102862306a36Sopenharmony_ci .tqi_cw_min = AR5K_TUNE_CWMIN, 102962306a36Sopenharmony_ci .tqi_cw_max = AR5K_TUNE_CWMAX 103062306a36Sopenharmony_ci }; 103162306a36Sopenharmony_ci int qnum; 103262306a36Sopenharmony_ci 103362306a36Sopenharmony_ci /* 103462306a36Sopenharmony_ci * Enable interrupts only for EOL and DESC conditions. 103562306a36Sopenharmony_ci * We mark tx descriptors to receive a DESC interrupt 103662306a36Sopenharmony_ci * when a tx queue gets deep; otherwise we wait for the 103762306a36Sopenharmony_ci * EOL to reap descriptors. Note that this is done to 103862306a36Sopenharmony_ci * reduce interrupt load and this only defers reaping 103962306a36Sopenharmony_ci * descriptors, never transmitting frames. Aside from 104062306a36Sopenharmony_ci * reducing interrupts this also permits more concurrency. 104162306a36Sopenharmony_ci * The only potential downside is if the tx queue backs 104262306a36Sopenharmony_ci * up in which case the top half of the kernel may backup 104362306a36Sopenharmony_ci * due to a lack of tx descriptors. 104462306a36Sopenharmony_ci */ 104562306a36Sopenharmony_ci qi.tqi_flags = AR5K_TXQ_FLAG_TXEOLINT_ENABLE | 104662306a36Sopenharmony_ci AR5K_TXQ_FLAG_TXDESCINT_ENABLE; 104762306a36Sopenharmony_ci qnum = ath5k_hw_setup_tx_queue(ah, qtype, &qi); 104862306a36Sopenharmony_ci if (qnum < 0) { 104962306a36Sopenharmony_ci /* 105062306a36Sopenharmony_ci * NB: don't print a message, this happens 105162306a36Sopenharmony_ci * normally on parts with too few tx queues 105262306a36Sopenharmony_ci */ 105362306a36Sopenharmony_ci return ERR_PTR(qnum); 105462306a36Sopenharmony_ci } 105562306a36Sopenharmony_ci txq = &ah->txqs[qnum]; 105662306a36Sopenharmony_ci if (!txq->setup) { 105762306a36Sopenharmony_ci txq->qnum = qnum; 105862306a36Sopenharmony_ci txq->link = NULL; 105962306a36Sopenharmony_ci INIT_LIST_HEAD(&txq->q); 106062306a36Sopenharmony_ci spin_lock_init(&txq->lock); 106162306a36Sopenharmony_ci txq->setup = true; 106262306a36Sopenharmony_ci txq->txq_len = 0; 106362306a36Sopenharmony_ci txq->txq_max = ATH5K_TXQ_LEN_MAX; 106462306a36Sopenharmony_ci txq->txq_poll_mark = false; 106562306a36Sopenharmony_ci txq->txq_stuck = 0; 106662306a36Sopenharmony_ci } 106762306a36Sopenharmony_ci return &ah->txqs[qnum]; 106862306a36Sopenharmony_ci} 106962306a36Sopenharmony_ci 107062306a36Sopenharmony_cistatic int 107162306a36Sopenharmony_ciath5k_beaconq_setup(struct ath5k_hw *ah) 107262306a36Sopenharmony_ci{ 107362306a36Sopenharmony_ci struct ath5k_txq_info qi = { 107462306a36Sopenharmony_ci /* XXX: default values not correct for B and XR channels, 107562306a36Sopenharmony_ci * but who cares? */ 107662306a36Sopenharmony_ci .tqi_aifs = AR5K_TUNE_AIFS, 107762306a36Sopenharmony_ci .tqi_cw_min = AR5K_TUNE_CWMIN, 107862306a36Sopenharmony_ci .tqi_cw_max = AR5K_TUNE_CWMAX, 107962306a36Sopenharmony_ci /* NB: for dynamic turbo, don't enable any other interrupts */ 108062306a36Sopenharmony_ci .tqi_flags = AR5K_TXQ_FLAG_TXDESCINT_ENABLE 108162306a36Sopenharmony_ci }; 108262306a36Sopenharmony_ci 108362306a36Sopenharmony_ci return ath5k_hw_setup_tx_queue(ah, AR5K_TX_QUEUE_BEACON, &qi); 108462306a36Sopenharmony_ci} 108562306a36Sopenharmony_ci 108662306a36Sopenharmony_cistatic int 108762306a36Sopenharmony_ciath5k_beaconq_config(struct ath5k_hw *ah) 108862306a36Sopenharmony_ci{ 108962306a36Sopenharmony_ci struct ath5k_txq_info qi; 109062306a36Sopenharmony_ci int ret; 109162306a36Sopenharmony_ci 109262306a36Sopenharmony_ci ret = ath5k_hw_get_tx_queueprops(ah, ah->bhalq, &qi); 109362306a36Sopenharmony_ci if (ret) 109462306a36Sopenharmony_ci goto err; 109562306a36Sopenharmony_ci 109662306a36Sopenharmony_ci if (ah->opmode == NL80211_IFTYPE_AP || 109762306a36Sopenharmony_ci ah->opmode == NL80211_IFTYPE_MESH_POINT) { 109862306a36Sopenharmony_ci /* 109962306a36Sopenharmony_ci * Always burst out beacon and CAB traffic 110062306a36Sopenharmony_ci * (aifs = cwmin = cwmax = 0) 110162306a36Sopenharmony_ci */ 110262306a36Sopenharmony_ci qi.tqi_aifs = 0; 110362306a36Sopenharmony_ci qi.tqi_cw_min = 0; 110462306a36Sopenharmony_ci qi.tqi_cw_max = 0; 110562306a36Sopenharmony_ci } else if (ah->opmode == NL80211_IFTYPE_ADHOC) { 110662306a36Sopenharmony_ci /* 110762306a36Sopenharmony_ci * Adhoc mode; backoff between 0 and (2 * cw_min). 110862306a36Sopenharmony_ci */ 110962306a36Sopenharmony_ci qi.tqi_aifs = 0; 111062306a36Sopenharmony_ci qi.tqi_cw_min = 0; 111162306a36Sopenharmony_ci qi.tqi_cw_max = 2 * AR5K_TUNE_CWMIN; 111262306a36Sopenharmony_ci } 111362306a36Sopenharmony_ci 111462306a36Sopenharmony_ci ATH5K_DBG(ah, ATH5K_DEBUG_BEACON, 111562306a36Sopenharmony_ci "beacon queueprops tqi_aifs:%d tqi_cw_min:%d tqi_cw_max:%d\n", 111662306a36Sopenharmony_ci qi.tqi_aifs, qi.tqi_cw_min, qi.tqi_cw_max); 111762306a36Sopenharmony_ci 111862306a36Sopenharmony_ci ret = ath5k_hw_set_tx_queueprops(ah, ah->bhalq, &qi); 111962306a36Sopenharmony_ci if (ret) { 112062306a36Sopenharmony_ci ATH5K_ERR(ah, "%s: unable to update parameters for beacon " 112162306a36Sopenharmony_ci "hardware queue!\n", __func__); 112262306a36Sopenharmony_ci goto err; 112362306a36Sopenharmony_ci } 112462306a36Sopenharmony_ci ret = ath5k_hw_reset_tx_queue(ah, ah->bhalq); /* push to h/w */ 112562306a36Sopenharmony_ci if (ret) 112662306a36Sopenharmony_ci goto err; 112762306a36Sopenharmony_ci 112862306a36Sopenharmony_ci /* reconfigure cabq with ready time to 80% of beacon_interval */ 112962306a36Sopenharmony_ci ret = ath5k_hw_get_tx_queueprops(ah, AR5K_TX_QUEUE_ID_CAB, &qi); 113062306a36Sopenharmony_ci if (ret) 113162306a36Sopenharmony_ci goto err; 113262306a36Sopenharmony_ci 113362306a36Sopenharmony_ci qi.tqi_ready_time = (ah->bintval * 80) / 100; 113462306a36Sopenharmony_ci ret = ath5k_hw_set_tx_queueprops(ah, AR5K_TX_QUEUE_ID_CAB, &qi); 113562306a36Sopenharmony_ci if (ret) 113662306a36Sopenharmony_ci goto err; 113762306a36Sopenharmony_ci 113862306a36Sopenharmony_ci ret = ath5k_hw_reset_tx_queue(ah, AR5K_TX_QUEUE_ID_CAB); 113962306a36Sopenharmony_cierr: 114062306a36Sopenharmony_ci return ret; 114162306a36Sopenharmony_ci} 114262306a36Sopenharmony_ci 114362306a36Sopenharmony_ci/** 114462306a36Sopenharmony_ci * ath5k_drain_tx_buffs - Empty tx buffers 114562306a36Sopenharmony_ci * 114662306a36Sopenharmony_ci * @ah: The &struct ath5k_hw 114762306a36Sopenharmony_ci * 114862306a36Sopenharmony_ci * Empty tx buffers from all queues in preparation 114962306a36Sopenharmony_ci * of a reset or during shutdown. 115062306a36Sopenharmony_ci * 115162306a36Sopenharmony_ci * NB: this assumes output has been stopped and 115262306a36Sopenharmony_ci * we do not need to block ath5k_tx_tasklet 115362306a36Sopenharmony_ci */ 115462306a36Sopenharmony_cistatic void 115562306a36Sopenharmony_ciath5k_drain_tx_buffs(struct ath5k_hw *ah) 115662306a36Sopenharmony_ci{ 115762306a36Sopenharmony_ci struct ath5k_txq *txq; 115862306a36Sopenharmony_ci struct ath5k_buf *bf, *bf0; 115962306a36Sopenharmony_ci int i; 116062306a36Sopenharmony_ci 116162306a36Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(ah->txqs); i++) { 116262306a36Sopenharmony_ci if (ah->txqs[i].setup) { 116362306a36Sopenharmony_ci txq = &ah->txqs[i]; 116462306a36Sopenharmony_ci spin_lock_bh(&txq->lock); 116562306a36Sopenharmony_ci list_for_each_entry_safe(bf, bf0, &txq->q, list) { 116662306a36Sopenharmony_ci ath5k_debug_printtxbuf(ah, bf); 116762306a36Sopenharmony_ci 116862306a36Sopenharmony_ci ath5k_txbuf_free_skb(ah, bf); 116962306a36Sopenharmony_ci 117062306a36Sopenharmony_ci spin_lock(&ah->txbuflock); 117162306a36Sopenharmony_ci list_move_tail(&bf->list, &ah->txbuf); 117262306a36Sopenharmony_ci ah->txbuf_len++; 117362306a36Sopenharmony_ci txq->txq_len--; 117462306a36Sopenharmony_ci spin_unlock(&ah->txbuflock); 117562306a36Sopenharmony_ci } 117662306a36Sopenharmony_ci txq->link = NULL; 117762306a36Sopenharmony_ci txq->txq_poll_mark = false; 117862306a36Sopenharmony_ci spin_unlock_bh(&txq->lock); 117962306a36Sopenharmony_ci } 118062306a36Sopenharmony_ci } 118162306a36Sopenharmony_ci} 118262306a36Sopenharmony_ci 118362306a36Sopenharmony_cistatic void 118462306a36Sopenharmony_ciath5k_txq_release(struct ath5k_hw *ah) 118562306a36Sopenharmony_ci{ 118662306a36Sopenharmony_ci struct ath5k_txq *txq = ah->txqs; 118762306a36Sopenharmony_ci unsigned int i; 118862306a36Sopenharmony_ci 118962306a36Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(ah->txqs); i++, txq++) 119062306a36Sopenharmony_ci if (txq->setup) { 119162306a36Sopenharmony_ci ath5k_hw_release_tx_queue(ah, txq->qnum); 119262306a36Sopenharmony_ci txq->setup = false; 119362306a36Sopenharmony_ci } 119462306a36Sopenharmony_ci} 119562306a36Sopenharmony_ci 119662306a36Sopenharmony_ci 119762306a36Sopenharmony_ci/*************\ 119862306a36Sopenharmony_ci* RX Handling * 119962306a36Sopenharmony_ci\*************/ 120062306a36Sopenharmony_ci 120162306a36Sopenharmony_ci/* 120262306a36Sopenharmony_ci * Enable the receive h/w following a reset. 120362306a36Sopenharmony_ci */ 120462306a36Sopenharmony_cistatic int 120562306a36Sopenharmony_ciath5k_rx_start(struct ath5k_hw *ah) 120662306a36Sopenharmony_ci{ 120762306a36Sopenharmony_ci struct ath_common *common = ath5k_hw_common(ah); 120862306a36Sopenharmony_ci struct ath5k_buf *bf; 120962306a36Sopenharmony_ci int ret; 121062306a36Sopenharmony_ci 121162306a36Sopenharmony_ci common->rx_bufsize = roundup(IEEE80211_MAX_FRAME_LEN, common->cachelsz); 121262306a36Sopenharmony_ci 121362306a36Sopenharmony_ci ATH5K_DBG(ah, ATH5K_DEBUG_RESET, "cachelsz %u rx_bufsize %u\n", 121462306a36Sopenharmony_ci common->cachelsz, common->rx_bufsize); 121562306a36Sopenharmony_ci 121662306a36Sopenharmony_ci spin_lock_bh(&ah->rxbuflock); 121762306a36Sopenharmony_ci ah->rxlink = NULL; 121862306a36Sopenharmony_ci list_for_each_entry(bf, &ah->rxbuf, list) { 121962306a36Sopenharmony_ci ret = ath5k_rxbuf_setup(ah, bf); 122062306a36Sopenharmony_ci if (ret != 0) { 122162306a36Sopenharmony_ci spin_unlock_bh(&ah->rxbuflock); 122262306a36Sopenharmony_ci goto err; 122362306a36Sopenharmony_ci } 122462306a36Sopenharmony_ci } 122562306a36Sopenharmony_ci bf = list_first_entry(&ah->rxbuf, struct ath5k_buf, list); 122662306a36Sopenharmony_ci ath5k_hw_set_rxdp(ah, bf->daddr); 122762306a36Sopenharmony_ci spin_unlock_bh(&ah->rxbuflock); 122862306a36Sopenharmony_ci 122962306a36Sopenharmony_ci ath5k_hw_start_rx_dma(ah); /* enable recv descriptors */ 123062306a36Sopenharmony_ci ath5k_update_bssid_mask_and_opmode(ah, NULL); /* set filters, etc. */ 123162306a36Sopenharmony_ci ath5k_hw_start_rx_pcu(ah); /* re-enable PCU/DMA engine */ 123262306a36Sopenharmony_ci 123362306a36Sopenharmony_ci return 0; 123462306a36Sopenharmony_cierr: 123562306a36Sopenharmony_ci return ret; 123662306a36Sopenharmony_ci} 123762306a36Sopenharmony_ci 123862306a36Sopenharmony_ci/* 123962306a36Sopenharmony_ci * Disable the receive logic on PCU (DRU) 124062306a36Sopenharmony_ci * In preparation for a shutdown. 124162306a36Sopenharmony_ci * 124262306a36Sopenharmony_ci * Note: Doesn't stop rx DMA, ath5k_hw_dma_stop 124362306a36Sopenharmony_ci * does. 124462306a36Sopenharmony_ci */ 124562306a36Sopenharmony_cistatic void 124662306a36Sopenharmony_ciath5k_rx_stop(struct ath5k_hw *ah) 124762306a36Sopenharmony_ci{ 124862306a36Sopenharmony_ci 124962306a36Sopenharmony_ci ath5k_hw_set_rx_filter(ah, 0); /* clear recv filter */ 125062306a36Sopenharmony_ci ath5k_hw_stop_rx_pcu(ah); /* disable PCU */ 125162306a36Sopenharmony_ci 125262306a36Sopenharmony_ci ath5k_debug_printrxbuffs(ah); 125362306a36Sopenharmony_ci} 125462306a36Sopenharmony_ci 125562306a36Sopenharmony_cistatic unsigned int 125662306a36Sopenharmony_ciath5k_rx_decrypted(struct ath5k_hw *ah, struct sk_buff *skb, 125762306a36Sopenharmony_ci struct ath5k_rx_status *rs) 125862306a36Sopenharmony_ci{ 125962306a36Sopenharmony_ci struct ath_common *common = ath5k_hw_common(ah); 126062306a36Sopenharmony_ci struct ieee80211_hdr *hdr = (void *)skb->data; 126162306a36Sopenharmony_ci unsigned int keyix, hlen; 126262306a36Sopenharmony_ci 126362306a36Sopenharmony_ci if (!(rs->rs_status & AR5K_RXERR_DECRYPT) && 126462306a36Sopenharmony_ci rs->rs_keyix != AR5K_RXKEYIX_INVALID) 126562306a36Sopenharmony_ci return RX_FLAG_DECRYPTED; 126662306a36Sopenharmony_ci 126762306a36Sopenharmony_ci /* Apparently when a default key is used to decrypt the packet 126862306a36Sopenharmony_ci the hw does not set the index used to decrypt. In such cases 126962306a36Sopenharmony_ci get the index from the packet. */ 127062306a36Sopenharmony_ci hlen = ieee80211_hdrlen(hdr->frame_control); 127162306a36Sopenharmony_ci if (ieee80211_has_protected(hdr->frame_control) && 127262306a36Sopenharmony_ci !(rs->rs_status & AR5K_RXERR_DECRYPT) && 127362306a36Sopenharmony_ci skb->len >= hlen + 4) { 127462306a36Sopenharmony_ci keyix = skb->data[hlen + 3] >> 6; 127562306a36Sopenharmony_ci 127662306a36Sopenharmony_ci if (test_bit(keyix, common->keymap)) 127762306a36Sopenharmony_ci return RX_FLAG_DECRYPTED; 127862306a36Sopenharmony_ci } 127962306a36Sopenharmony_ci 128062306a36Sopenharmony_ci return 0; 128162306a36Sopenharmony_ci} 128262306a36Sopenharmony_ci 128362306a36Sopenharmony_ci 128462306a36Sopenharmony_cistatic void 128562306a36Sopenharmony_ciath5k_check_ibss_tsf(struct ath5k_hw *ah, struct sk_buff *skb, 128662306a36Sopenharmony_ci struct ieee80211_rx_status *rxs) 128762306a36Sopenharmony_ci{ 128862306a36Sopenharmony_ci u64 tsf, bc_tstamp; 128962306a36Sopenharmony_ci u32 hw_tu; 129062306a36Sopenharmony_ci struct ieee80211_mgmt *mgmt = (struct ieee80211_mgmt *)skb->data; 129162306a36Sopenharmony_ci 129262306a36Sopenharmony_ci if (le16_to_cpu(mgmt->u.beacon.capab_info) & WLAN_CAPABILITY_IBSS) { 129362306a36Sopenharmony_ci /* 129462306a36Sopenharmony_ci * Received an IBSS beacon with the same BSSID. Hardware *must* 129562306a36Sopenharmony_ci * have updated the local TSF. We have to work around various 129662306a36Sopenharmony_ci * hardware bugs, though... 129762306a36Sopenharmony_ci */ 129862306a36Sopenharmony_ci tsf = ath5k_hw_get_tsf64(ah); 129962306a36Sopenharmony_ci bc_tstamp = le64_to_cpu(mgmt->u.beacon.timestamp); 130062306a36Sopenharmony_ci hw_tu = TSF_TO_TU(tsf); 130162306a36Sopenharmony_ci 130262306a36Sopenharmony_ci ATH5K_DBG_UNLIMIT(ah, ATH5K_DEBUG_BEACON, 130362306a36Sopenharmony_ci "beacon %llx mactime %llx (diff %lld) tsf now %llx\n", 130462306a36Sopenharmony_ci (unsigned long long)bc_tstamp, 130562306a36Sopenharmony_ci (unsigned long long)rxs->mactime, 130662306a36Sopenharmony_ci (unsigned long long)(rxs->mactime - bc_tstamp), 130762306a36Sopenharmony_ci (unsigned long long)tsf); 130862306a36Sopenharmony_ci 130962306a36Sopenharmony_ci /* 131062306a36Sopenharmony_ci * Sometimes the HW will give us a wrong tstamp in the rx 131162306a36Sopenharmony_ci * status, causing the timestamp extension to go wrong. 131262306a36Sopenharmony_ci * (This seems to happen especially with beacon frames bigger 131362306a36Sopenharmony_ci * than 78 byte (incl. FCS)) 131462306a36Sopenharmony_ci * But we know that the receive timestamp must be later than the 131562306a36Sopenharmony_ci * timestamp of the beacon since HW must have synced to that. 131662306a36Sopenharmony_ci * 131762306a36Sopenharmony_ci * NOTE: here we assume mactime to be after the frame was 131862306a36Sopenharmony_ci * received, not like mac80211 which defines it at the start. 131962306a36Sopenharmony_ci */ 132062306a36Sopenharmony_ci if (bc_tstamp > rxs->mactime) { 132162306a36Sopenharmony_ci ATH5K_DBG_UNLIMIT(ah, ATH5K_DEBUG_BEACON, 132262306a36Sopenharmony_ci "fixing mactime from %llx to %llx\n", 132362306a36Sopenharmony_ci (unsigned long long)rxs->mactime, 132462306a36Sopenharmony_ci (unsigned long long)tsf); 132562306a36Sopenharmony_ci rxs->mactime = tsf; 132662306a36Sopenharmony_ci } 132762306a36Sopenharmony_ci 132862306a36Sopenharmony_ci /* 132962306a36Sopenharmony_ci * Local TSF might have moved higher than our beacon timers, 133062306a36Sopenharmony_ci * in that case we have to update them to continue sending 133162306a36Sopenharmony_ci * beacons. This also takes care of synchronizing beacon sending 133262306a36Sopenharmony_ci * times with other stations. 133362306a36Sopenharmony_ci */ 133462306a36Sopenharmony_ci if (hw_tu >= ah->nexttbtt) 133562306a36Sopenharmony_ci ath5k_beacon_update_timers(ah, bc_tstamp); 133662306a36Sopenharmony_ci 133762306a36Sopenharmony_ci /* Check if the beacon timers are still correct, because a TSF 133862306a36Sopenharmony_ci * update might have created a window between them - for a 133962306a36Sopenharmony_ci * longer description see the comment of this function: */ 134062306a36Sopenharmony_ci if (!ath5k_hw_check_beacon_timers(ah, ah->bintval)) { 134162306a36Sopenharmony_ci ath5k_beacon_update_timers(ah, bc_tstamp); 134262306a36Sopenharmony_ci ATH5K_DBG_UNLIMIT(ah, ATH5K_DEBUG_BEACON, 134362306a36Sopenharmony_ci "fixed beacon timers after beacon receive\n"); 134462306a36Sopenharmony_ci } 134562306a36Sopenharmony_ci } 134662306a36Sopenharmony_ci} 134762306a36Sopenharmony_ci 134862306a36Sopenharmony_ci/* 134962306a36Sopenharmony_ci * Compute padding position. skb must contain an IEEE 802.11 frame 135062306a36Sopenharmony_ci */ 135162306a36Sopenharmony_cistatic int ath5k_common_padpos(struct sk_buff *skb) 135262306a36Sopenharmony_ci{ 135362306a36Sopenharmony_ci struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data; 135462306a36Sopenharmony_ci __le16 frame_control = hdr->frame_control; 135562306a36Sopenharmony_ci int padpos = 24; 135662306a36Sopenharmony_ci 135762306a36Sopenharmony_ci if (ieee80211_has_a4(frame_control)) 135862306a36Sopenharmony_ci padpos += ETH_ALEN; 135962306a36Sopenharmony_ci 136062306a36Sopenharmony_ci if (ieee80211_is_data_qos(frame_control)) 136162306a36Sopenharmony_ci padpos += IEEE80211_QOS_CTL_LEN; 136262306a36Sopenharmony_ci 136362306a36Sopenharmony_ci return padpos; 136462306a36Sopenharmony_ci} 136562306a36Sopenharmony_ci 136662306a36Sopenharmony_ci/* 136762306a36Sopenharmony_ci * This function expects an 802.11 frame and returns the number of 136862306a36Sopenharmony_ci * bytes added, or -1 if we don't have enough header room. 136962306a36Sopenharmony_ci */ 137062306a36Sopenharmony_cistatic int ath5k_add_padding(struct sk_buff *skb) 137162306a36Sopenharmony_ci{ 137262306a36Sopenharmony_ci int padpos = ath5k_common_padpos(skb); 137362306a36Sopenharmony_ci int padsize = padpos & 3; 137462306a36Sopenharmony_ci 137562306a36Sopenharmony_ci if (padsize && skb->len > padpos) { 137662306a36Sopenharmony_ci 137762306a36Sopenharmony_ci if (skb_headroom(skb) < padsize) 137862306a36Sopenharmony_ci return -1; 137962306a36Sopenharmony_ci 138062306a36Sopenharmony_ci skb_push(skb, padsize); 138162306a36Sopenharmony_ci memmove(skb->data, skb->data + padsize, padpos); 138262306a36Sopenharmony_ci return padsize; 138362306a36Sopenharmony_ci } 138462306a36Sopenharmony_ci 138562306a36Sopenharmony_ci return 0; 138662306a36Sopenharmony_ci} 138762306a36Sopenharmony_ci 138862306a36Sopenharmony_ci/* 138962306a36Sopenharmony_ci * The MAC header is padded to have 32-bit boundary if the 139062306a36Sopenharmony_ci * packet payload is non-zero. The general calculation for 139162306a36Sopenharmony_ci * padsize would take into account odd header lengths: 139262306a36Sopenharmony_ci * padsize = 4 - (hdrlen & 3); however, since only 139362306a36Sopenharmony_ci * even-length headers are used, padding can only be 0 or 2 139462306a36Sopenharmony_ci * bytes and we can optimize this a bit. We must not try to 139562306a36Sopenharmony_ci * remove padding from short control frames that do not have a 139662306a36Sopenharmony_ci * payload. 139762306a36Sopenharmony_ci * 139862306a36Sopenharmony_ci * This function expects an 802.11 frame and returns the number of 139962306a36Sopenharmony_ci * bytes removed. 140062306a36Sopenharmony_ci */ 140162306a36Sopenharmony_cistatic int ath5k_remove_padding(struct sk_buff *skb) 140262306a36Sopenharmony_ci{ 140362306a36Sopenharmony_ci int padpos = ath5k_common_padpos(skb); 140462306a36Sopenharmony_ci int padsize = padpos & 3; 140562306a36Sopenharmony_ci 140662306a36Sopenharmony_ci if (padsize && skb->len >= padpos + padsize) { 140762306a36Sopenharmony_ci memmove(skb->data + padsize, skb->data, padpos); 140862306a36Sopenharmony_ci skb_pull(skb, padsize); 140962306a36Sopenharmony_ci return padsize; 141062306a36Sopenharmony_ci } 141162306a36Sopenharmony_ci 141262306a36Sopenharmony_ci return 0; 141362306a36Sopenharmony_ci} 141462306a36Sopenharmony_ci 141562306a36Sopenharmony_cistatic void 141662306a36Sopenharmony_ciath5k_receive_frame(struct ath5k_hw *ah, struct sk_buff *skb, 141762306a36Sopenharmony_ci struct ath5k_rx_status *rs) 141862306a36Sopenharmony_ci{ 141962306a36Sopenharmony_ci struct ieee80211_rx_status *rxs; 142062306a36Sopenharmony_ci struct ath_common *common = ath5k_hw_common(ah); 142162306a36Sopenharmony_ci 142262306a36Sopenharmony_ci ath5k_remove_padding(skb); 142362306a36Sopenharmony_ci 142462306a36Sopenharmony_ci rxs = IEEE80211_SKB_RXCB(skb); 142562306a36Sopenharmony_ci 142662306a36Sopenharmony_ci rxs->flag = 0; 142762306a36Sopenharmony_ci if (unlikely(rs->rs_status & AR5K_RXERR_MIC)) 142862306a36Sopenharmony_ci rxs->flag |= RX_FLAG_MMIC_ERROR; 142962306a36Sopenharmony_ci if (unlikely(rs->rs_status & AR5K_RXERR_CRC)) 143062306a36Sopenharmony_ci rxs->flag |= RX_FLAG_FAILED_FCS_CRC; 143162306a36Sopenharmony_ci 143262306a36Sopenharmony_ci 143362306a36Sopenharmony_ci /* 143462306a36Sopenharmony_ci * always extend the mac timestamp, since this information is 143562306a36Sopenharmony_ci * also needed for proper IBSS merging. 143662306a36Sopenharmony_ci * 143762306a36Sopenharmony_ci * XXX: it might be too late to do it here, since rs_tstamp is 143862306a36Sopenharmony_ci * 15bit only. that means TSF extension has to be done within 143962306a36Sopenharmony_ci * 32768usec (about 32ms). it might be necessary to move this to 144062306a36Sopenharmony_ci * the interrupt handler, like it is done in madwifi. 144162306a36Sopenharmony_ci */ 144262306a36Sopenharmony_ci rxs->mactime = ath5k_extend_tsf(ah, rs->rs_tstamp); 144362306a36Sopenharmony_ci rxs->flag |= RX_FLAG_MACTIME_END; 144462306a36Sopenharmony_ci 144562306a36Sopenharmony_ci rxs->freq = ah->curchan->center_freq; 144662306a36Sopenharmony_ci rxs->band = ah->curchan->band; 144762306a36Sopenharmony_ci 144862306a36Sopenharmony_ci rxs->signal = ah->ah_noise_floor + rs->rs_rssi; 144962306a36Sopenharmony_ci 145062306a36Sopenharmony_ci rxs->antenna = rs->rs_antenna; 145162306a36Sopenharmony_ci 145262306a36Sopenharmony_ci if (rs->rs_antenna > 0 && rs->rs_antenna < 5) 145362306a36Sopenharmony_ci ah->stats.antenna_rx[rs->rs_antenna]++; 145462306a36Sopenharmony_ci else 145562306a36Sopenharmony_ci ah->stats.antenna_rx[0]++; /* invalid */ 145662306a36Sopenharmony_ci 145762306a36Sopenharmony_ci rxs->rate_idx = ath5k_hw_to_driver_rix(ah, rs->rs_rate); 145862306a36Sopenharmony_ci rxs->flag |= ath5k_rx_decrypted(ah, skb, rs); 145962306a36Sopenharmony_ci switch (ah->ah_bwmode) { 146062306a36Sopenharmony_ci case AR5K_BWMODE_5MHZ: 146162306a36Sopenharmony_ci rxs->bw = RATE_INFO_BW_5; 146262306a36Sopenharmony_ci break; 146362306a36Sopenharmony_ci case AR5K_BWMODE_10MHZ: 146462306a36Sopenharmony_ci rxs->bw = RATE_INFO_BW_10; 146562306a36Sopenharmony_ci break; 146662306a36Sopenharmony_ci default: 146762306a36Sopenharmony_ci break; 146862306a36Sopenharmony_ci } 146962306a36Sopenharmony_ci 147062306a36Sopenharmony_ci if (rs->rs_rate == 147162306a36Sopenharmony_ci ah->sbands[ah->curchan->band].bitrates[rxs->rate_idx].hw_value_short) 147262306a36Sopenharmony_ci rxs->enc_flags |= RX_ENC_FLAG_SHORTPRE; 147362306a36Sopenharmony_ci 147462306a36Sopenharmony_ci trace_ath5k_rx(ah, skb); 147562306a36Sopenharmony_ci 147662306a36Sopenharmony_ci if (ath_is_mybeacon(common, (struct ieee80211_hdr *)skb->data)) { 147762306a36Sopenharmony_ci ewma_beacon_rssi_add(&ah->ah_beacon_rssi_avg, rs->rs_rssi); 147862306a36Sopenharmony_ci 147962306a36Sopenharmony_ci /* check beacons in IBSS mode */ 148062306a36Sopenharmony_ci if (ah->opmode == NL80211_IFTYPE_ADHOC) 148162306a36Sopenharmony_ci ath5k_check_ibss_tsf(ah, skb, rxs); 148262306a36Sopenharmony_ci } 148362306a36Sopenharmony_ci 148462306a36Sopenharmony_ci ieee80211_rx(ah->hw, skb); 148562306a36Sopenharmony_ci} 148662306a36Sopenharmony_ci 148762306a36Sopenharmony_ci/** ath5k_frame_receive_ok() - Do we want to receive this frame or not? 148862306a36Sopenharmony_ci * 148962306a36Sopenharmony_ci * Check if we want to further process this frame or not. Also update 149062306a36Sopenharmony_ci * statistics. Return true if we want this frame, false if not. 149162306a36Sopenharmony_ci */ 149262306a36Sopenharmony_cistatic bool 149362306a36Sopenharmony_ciath5k_receive_frame_ok(struct ath5k_hw *ah, struct ath5k_rx_status *rs) 149462306a36Sopenharmony_ci{ 149562306a36Sopenharmony_ci ah->stats.rx_all_count++; 149662306a36Sopenharmony_ci ah->stats.rx_bytes_count += rs->rs_datalen; 149762306a36Sopenharmony_ci 149862306a36Sopenharmony_ci if (unlikely(rs->rs_status)) { 149962306a36Sopenharmony_ci unsigned int filters; 150062306a36Sopenharmony_ci 150162306a36Sopenharmony_ci if (rs->rs_status & AR5K_RXERR_CRC) 150262306a36Sopenharmony_ci ah->stats.rxerr_crc++; 150362306a36Sopenharmony_ci if (rs->rs_status & AR5K_RXERR_FIFO) 150462306a36Sopenharmony_ci ah->stats.rxerr_fifo++; 150562306a36Sopenharmony_ci if (rs->rs_status & AR5K_RXERR_PHY) { 150662306a36Sopenharmony_ci ah->stats.rxerr_phy++; 150762306a36Sopenharmony_ci if (rs->rs_phyerr > 0 && rs->rs_phyerr < 32) 150862306a36Sopenharmony_ci ah->stats.rxerr_phy_code[rs->rs_phyerr]++; 150962306a36Sopenharmony_ci 151062306a36Sopenharmony_ci /* 151162306a36Sopenharmony_ci * Treat packets that underwent a CCK or OFDM reset as having a bad CRC. 151262306a36Sopenharmony_ci * These restarts happen when the radio resynchronizes to a stronger frame 151362306a36Sopenharmony_ci * while receiving a weaker frame. Here we receive the prefix of the weak 151462306a36Sopenharmony_ci * frame. Since these are incomplete packets, mark their CRC as invalid. 151562306a36Sopenharmony_ci */ 151662306a36Sopenharmony_ci if (rs->rs_phyerr == AR5K_RX_PHY_ERROR_OFDM_RESTART || 151762306a36Sopenharmony_ci rs->rs_phyerr == AR5K_RX_PHY_ERROR_CCK_RESTART) { 151862306a36Sopenharmony_ci rs->rs_status |= AR5K_RXERR_CRC; 151962306a36Sopenharmony_ci rs->rs_status &= ~AR5K_RXERR_PHY; 152062306a36Sopenharmony_ci } else { 152162306a36Sopenharmony_ci return false; 152262306a36Sopenharmony_ci } 152362306a36Sopenharmony_ci } 152462306a36Sopenharmony_ci if (rs->rs_status & AR5K_RXERR_DECRYPT) { 152562306a36Sopenharmony_ci /* 152662306a36Sopenharmony_ci * Decrypt error. If the error occurred 152762306a36Sopenharmony_ci * because there was no hardware key, then 152862306a36Sopenharmony_ci * let the frame through so the upper layers 152962306a36Sopenharmony_ci * can process it. This is necessary for 5210 153062306a36Sopenharmony_ci * parts which have no way to setup a ``clear'' 153162306a36Sopenharmony_ci * key cache entry. 153262306a36Sopenharmony_ci * 153362306a36Sopenharmony_ci * XXX do key cache faulting 153462306a36Sopenharmony_ci */ 153562306a36Sopenharmony_ci ah->stats.rxerr_decrypt++; 153662306a36Sopenharmony_ci if (rs->rs_keyix == AR5K_RXKEYIX_INVALID && 153762306a36Sopenharmony_ci !(rs->rs_status & AR5K_RXERR_CRC)) 153862306a36Sopenharmony_ci return true; 153962306a36Sopenharmony_ci } 154062306a36Sopenharmony_ci if (rs->rs_status & AR5K_RXERR_MIC) { 154162306a36Sopenharmony_ci ah->stats.rxerr_mic++; 154262306a36Sopenharmony_ci return true; 154362306a36Sopenharmony_ci } 154462306a36Sopenharmony_ci 154562306a36Sopenharmony_ci /* 154662306a36Sopenharmony_ci * Reject any frames with non-crypto errors, and take into account the 154762306a36Sopenharmony_ci * current FIF_* filters. 154862306a36Sopenharmony_ci */ 154962306a36Sopenharmony_ci filters = AR5K_RXERR_DECRYPT; 155062306a36Sopenharmony_ci if (ah->fif_filter_flags & FIF_FCSFAIL) 155162306a36Sopenharmony_ci filters |= AR5K_RXERR_CRC; 155262306a36Sopenharmony_ci 155362306a36Sopenharmony_ci if (rs->rs_status & ~filters) 155462306a36Sopenharmony_ci return false; 155562306a36Sopenharmony_ci } 155662306a36Sopenharmony_ci 155762306a36Sopenharmony_ci if (unlikely(rs->rs_more)) { 155862306a36Sopenharmony_ci ah->stats.rxerr_jumbo++; 155962306a36Sopenharmony_ci return false; 156062306a36Sopenharmony_ci } 156162306a36Sopenharmony_ci return true; 156262306a36Sopenharmony_ci} 156362306a36Sopenharmony_ci 156462306a36Sopenharmony_cistatic void 156562306a36Sopenharmony_ciath5k_set_current_imask(struct ath5k_hw *ah) 156662306a36Sopenharmony_ci{ 156762306a36Sopenharmony_ci enum ath5k_int imask; 156862306a36Sopenharmony_ci unsigned long flags; 156962306a36Sopenharmony_ci 157062306a36Sopenharmony_ci if (test_bit(ATH_STAT_RESET, ah->status)) 157162306a36Sopenharmony_ci return; 157262306a36Sopenharmony_ci 157362306a36Sopenharmony_ci spin_lock_irqsave(&ah->irqlock, flags); 157462306a36Sopenharmony_ci imask = ah->imask; 157562306a36Sopenharmony_ci if (ah->rx_pending) 157662306a36Sopenharmony_ci imask &= ~AR5K_INT_RX_ALL; 157762306a36Sopenharmony_ci if (ah->tx_pending) 157862306a36Sopenharmony_ci imask &= ~AR5K_INT_TX_ALL; 157962306a36Sopenharmony_ci ath5k_hw_set_imr(ah, imask); 158062306a36Sopenharmony_ci spin_unlock_irqrestore(&ah->irqlock, flags); 158162306a36Sopenharmony_ci} 158262306a36Sopenharmony_ci 158362306a36Sopenharmony_cistatic void 158462306a36Sopenharmony_ciath5k_tasklet_rx(struct tasklet_struct *t) 158562306a36Sopenharmony_ci{ 158662306a36Sopenharmony_ci struct ath5k_rx_status rs = {}; 158762306a36Sopenharmony_ci struct sk_buff *skb, *next_skb; 158862306a36Sopenharmony_ci dma_addr_t next_skb_addr; 158962306a36Sopenharmony_ci struct ath5k_hw *ah = from_tasklet(ah, t, rxtq); 159062306a36Sopenharmony_ci struct ath_common *common = ath5k_hw_common(ah); 159162306a36Sopenharmony_ci struct ath5k_buf *bf; 159262306a36Sopenharmony_ci struct ath5k_desc *ds; 159362306a36Sopenharmony_ci int ret; 159462306a36Sopenharmony_ci 159562306a36Sopenharmony_ci spin_lock(&ah->rxbuflock); 159662306a36Sopenharmony_ci if (list_empty(&ah->rxbuf)) { 159762306a36Sopenharmony_ci ATH5K_WARN(ah, "empty rx buf pool\n"); 159862306a36Sopenharmony_ci goto unlock; 159962306a36Sopenharmony_ci } 160062306a36Sopenharmony_ci do { 160162306a36Sopenharmony_ci bf = list_first_entry(&ah->rxbuf, struct ath5k_buf, list); 160262306a36Sopenharmony_ci BUG_ON(bf->skb == NULL); 160362306a36Sopenharmony_ci skb = bf->skb; 160462306a36Sopenharmony_ci ds = bf->desc; 160562306a36Sopenharmony_ci 160662306a36Sopenharmony_ci /* bail if HW is still using self-linked descriptor */ 160762306a36Sopenharmony_ci if (ath5k_hw_get_rxdp(ah) == bf->daddr) 160862306a36Sopenharmony_ci break; 160962306a36Sopenharmony_ci 161062306a36Sopenharmony_ci ret = ah->ah_proc_rx_desc(ah, ds, &rs); 161162306a36Sopenharmony_ci if (unlikely(ret == -EINPROGRESS)) 161262306a36Sopenharmony_ci break; 161362306a36Sopenharmony_ci else if (unlikely(ret)) { 161462306a36Sopenharmony_ci ATH5K_ERR(ah, "error in processing rx descriptor\n"); 161562306a36Sopenharmony_ci ah->stats.rxerr_proc++; 161662306a36Sopenharmony_ci break; 161762306a36Sopenharmony_ci } 161862306a36Sopenharmony_ci 161962306a36Sopenharmony_ci if (ath5k_receive_frame_ok(ah, &rs)) { 162062306a36Sopenharmony_ci next_skb = ath5k_rx_skb_alloc(ah, &next_skb_addr); 162162306a36Sopenharmony_ci 162262306a36Sopenharmony_ci /* 162362306a36Sopenharmony_ci * If we can't replace bf->skb with a new skb under 162462306a36Sopenharmony_ci * memory pressure, just skip this packet 162562306a36Sopenharmony_ci */ 162662306a36Sopenharmony_ci if (!next_skb) 162762306a36Sopenharmony_ci goto next; 162862306a36Sopenharmony_ci 162962306a36Sopenharmony_ci dma_unmap_single(ah->dev, bf->skbaddr, 163062306a36Sopenharmony_ci common->rx_bufsize, 163162306a36Sopenharmony_ci DMA_FROM_DEVICE); 163262306a36Sopenharmony_ci 163362306a36Sopenharmony_ci skb_put(skb, rs.rs_datalen); 163462306a36Sopenharmony_ci 163562306a36Sopenharmony_ci ath5k_receive_frame(ah, skb, &rs); 163662306a36Sopenharmony_ci 163762306a36Sopenharmony_ci bf->skb = next_skb; 163862306a36Sopenharmony_ci bf->skbaddr = next_skb_addr; 163962306a36Sopenharmony_ci } 164062306a36Sopenharmony_cinext: 164162306a36Sopenharmony_ci list_move_tail(&bf->list, &ah->rxbuf); 164262306a36Sopenharmony_ci } while (ath5k_rxbuf_setup(ah, bf) == 0); 164362306a36Sopenharmony_ciunlock: 164462306a36Sopenharmony_ci spin_unlock(&ah->rxbuflock); 164562306a36Sopenharmony_ci ah->rx_pending = false; 164662306a36Sopenharmony_ci ath5k_set_current_imask(ah); 164762306a36Sopenharmony_ci} 164862306a36Sopenharmony_ci 164962306a36Sopenharmony_ci 165062306a36Sopenharmony_ci/*************\ 165162306a36Sopenharmony_ci* TX Handling * 165262306a36Sopenharmony_ci\*************/ 165362306a36Sopenharmony_ci 165462306a36Sopenharmony_civoid 165562306a36Sopenharmony_ciath5k_tx_queue(struct ieee80211_hw *hw, struct sk_buff *skb, 165662306a36Sopenharmony_ci struct ath5k_txq *txq, struct ieee80211_tx_control *control) 165762306a36Sopenharmony_ci{ 165862306a36Sopenharmony_ci struct ath5k_hw *ah = hw->priv; 165962306a36Sopenharmony_ci struct ath5k_buf *bf; 166062306a36Sopenharmony_ci unsigned long flags; 166162306a36Sopenharmony_ci int padsize; 166262306a36Sopenharmony_ci 166362306a36Sopenharmony_ci trace_ath5k_tx(ah, skb, txq); 166462306a36Sopenharmony_ci 166562306a36Sopenharmony_ci /* 166662306a36Sopenharmony_ci * The hardware expects the header padded to 4 byte boundaries. 166762306a36Sopenharmony_ci * If this is not the case, we add the padding after the header. 166862306a36Sopenharmony_ci */ 166962306a36Sopenharmony_ci padsize = ath5k_add_padding(skb); 167062306a36Sopenharmony_ci if (padsize < 0) { 167162306a36Sopenharmony_ci ATH5K_ERR(ah, "tx hdrlen not %%4: not enough" 167262306a36Sopenharmony_ci " headroom to pad"); 167362306a36Sopenharmony_ci goto drop_packet; 167462306a36Sopenharmony_ci } 167562306a36Sopenharmony_ci 167662306a36Sopenharmony_ci if (txq->txq_len >= txq->txq_max && 167762306a36Sopenharmony_ci txq->qnum <= AR5K_TX_QUEUE_ID_DATA_MAX) 167862306a36Sopenharmony_ci ieee80211_stop_queue(hw, txq->qnum); 167962306a36Sopenharmony_ci 168062306a36Sopenharmony_ci spin_lock_irqsave(&ah->txbuflock, flags); 168162306a36Sopenharmony_ci if (list_empty(&ah->txbuf)) { 168262306a36Sopenharmony_ci ATH5K_ERR(ah, "no further txbuf available, dropping packet\n"); 168362306a36Sopenharmony_ci spin_unlock_irqrestore(&ah->txbuflock, flags); 168462306a36Sopenharmony_ci ieee80211_stop_queues(hw); 168562306a36Sopenharmony_ci goto drop_packet; 168662306a36Sopenharmony_ci } 168762306a36Sopenharmony_ci bf = list_first_entry(&ah->txbuf, struct ath5k_buf, list); 168862306a36Sopenharmony_ci list_del(&bf->list); 168962306a36Sopenharmony_ci ah->txbuf_len--; 169062306a36Sopenharmony_ci if (list_empty(&ah->txbuf)) 169162306a36Sopenharmony_ci ieee80211_stop_queues(hw); 169262306a36Sopenharmony_ci spin_unlock_irqrestore(&ah->txbuflock, flags); 169362306a36Sopenharmony_ci 169462306a36Sopenharmony_ci bf->skb = skb; 169562306a36Sopenharmony_ci 169662306a36Sopenharmony_ci if (ath5k_txbuf_setup(ah, bf, txq, padsize, control)) { 169762306a36Sopenharmony_ci bf->skb = NULL; 169862306a36Sopenharmony_ci spin_lock_irqsave(&ah->txbuflock, flags); 169962306a36Sopenharmony_ci list_add_tail(&bf->list, &ah->txbuf); 170062306a36Sopenharmony_ci ah->txbuf_len++; 170162306a36Sopenharmony_ci spin_unlock_irqrestore(&ah->txbuflock, flags); 170262306a36Sopenharmony_ci goto drop_packet; 170362306a36Sopenharmony_ci } 170462306a36Sopenharmony_ci return; 170562306a36Sopenharmony_ci 170662306a36Sopenharmony_cidrop_packet: 170762306a36Sopenharmony_ci ieee80211_free_txskb(hw, skb); 170862306a36Sopenharmony_ci} 170962306a36Sopenharmony_ci 171062306a36Sopenharmony_cistatic void 171162306a36Sopenharmony_ciath5k_tx_frame_completed(struct ath5k_hw *ah, struct sk_buff *skb, 171262306a36Sopenharmony_ci struct ath5k_txq *txq, struct ath5k_tx_status *ts, 171362306a36Sopenharmony_ci struct ath5k_buf *bf) 171462306a36Sopenharmony_ci{ 171562306a36Sopenharmony_ci struct ieee80211_tx_info *info; 171662306a36Sopenharmony_ci u8 tries[3]; 171762306a36Sopenharmony_ci int i; 171862306a36Sopenharmony_ci int size = 0; 171962306a36Sopenharmony_ci 172062306a36Sopenharmony_ci ah->stats.tx_all_count++; 172162306a36Sopenharmony_ci ah->stats.tx_bytes_count += skb->len; 172262306a36Sopenharmony_ci info = IEEE80211_SKB_CB(skb); 172362306a36Sopenharmony_ci 172462306a36Sopenharmony_ci size = min_t(int, sizeof(info->status.rates), sizeof(bf->rates)); 172562306a36Sopenharmony_ci memcpy(info->status.rates, bf->rates, size); 172662306a36Sopenharmony_ci 172762306a36Sopenharmony_ci tries[0] = info->status.rates[0].count; 172862306a36Sopenharmony_ci tries[1] = info->status.rates[1].count; 172962306a36Sopenharmony_ci tries[2] = info->status.rates[2].count; 173062306a36Sopenharmony_ci 173162306a36Sopenharmony_ci ieee80211_tx_info_clear_status(info); 173262306a36Sopenharmony_ci 173362306a36Sopenharmony_ci for (i = 0; i < ts->ts_final_idx; i++) { 173462306a36Sopenharmony_ci struct ieee80211_tx_rate *r = 173562306a36Sopenharmony_ci &info->status.rates[i]; 173662306a36Sopenharmony_ci 173762306a36Sopenharmony_ci r->count = tries[i]; 173862306a36Sopenharmony_ci } 173962306a36Sopenharmony_ci 174062306a36Sopenharmony_ci info->status.rates[ts->ts_final_idx].count = ts->ts_final_retry; 174162306a36Sopenharmony_ci info->status.rates[ts->ts_final_idx + 1].idx = -1; 174262306a36Sopenharmony_ci 174362306a36Sopenharmony_ci if (unlikely(ts->ts_status)) { 174462306a36Sopenharmony_ci ah->stats.ack_fail++; 174562306a36Sopenharmony_ci if (ts->ts_status & AR5K_TXERR_FILT) { 174662306a36Sopenharmony_ci info->flags |= IEEE80211_TX_STAT_TX_FILTERED; 174762306a36Sopenharmony_ci ah->stats.txerr_filt++; 174862306a36Sopenharmony_ci } 174962306a36Sopenharmony_ci if (ts->ts_status & AR5K_TXERR_XRETRY) 175062306a36Sopenharmony_ci ah->stats.txerr_retry++; 175162306a36Sopenharmony_ci if (ts->ts_status & AR5K_TXERR_FIFO) 175262306a36Sopenharmony_ci ah->stats.txerr_fifo++; 175362306a36Sopenharmony_ci } else { 175462306a36Sopenharmony_ci info->flags |= IEEE80211_TX_STAT_ACK; 175562306a36Sopenharmony_ci info->status.ack_signal = ts->ts_rssi; 175662306a36Sopenharmony_ci 175762306a36Sopenharmony_ci /* count the successful attempt as well */ 175862306a36Sopenharmony_ci info->status.rates[ts->ts_final_idx].count++; 175962306a36Sopenharmony_ci } 176062306a36Sopenharmony_ci 176162306a36Sopenharmony_ci /* 176262306a36Sopenharmony_ci * Remove MAC header padding before giving the frame 176362306a36Sopenharmony_ci * back to mac80211. 176462306a36Sopenharmony_ci */ 176562306a36Sopenharmony_ci ath5k_remove_padding(skb); 176662306a36Sopenharmony_ci 176762306a36Sopenharmony_ci if (ts->ts_antenna > 0 && ts->ts_antenna < 5) 176862306a36Sopenharmony_ci ah->stats.antenna_tx[ts->ts_antenna]++; 176962306a36Sopenharmony_ci else 177062306a36Sopenharmony_ci ah->stats.antenna_tx[0]++; /* invalid */ 177162306a36Sopenharmony_ci 177262306a36Sopenharmony_ci trace_ath5k_tx_complete(ah, skb, txq, ts); 177362306a36Sopenharmony_ci ieee80211_tx_status(ah->hw, skb); 177462306a36Sopenharmony_ci} 177562306a36Sopenharmony_ci 177662306a36Sopenharmony_cistatic void 177762306a36Sopenharmony_ciath5k_tx_processq(struct ath5k_hw *ah, struct ath5k_txq *txq) 177862306a36Sopenharmony_ci{ 177962306a36Sopenharmony_ci struct ath5k_tx_status ts = {}; 178062306a36Sopenharmony_ci struct ath5k_buf *bf, *bf0; 178162306a36Sopenharmony_ci struct ath5k_desc *ds; 178262306a36Sopenharmony_ci struct sk_buff *skb; 178362306a36Sopenharmony_ci int ret; 178462306a36Sopenharmony_ci 178562306a36Sopenharmony_ci spin_lock(&txq->lock); 178662306a36Sopenharmony_ci list_for_each_entry_safe(bf, bf0, &txq->q, list) { 178762306a36Sopenharmony_ci 178862306a36Sopenharmony_ci txq->txq_poll_mark = false; 178962306a36Sopenharmony_ci 179062306a36Sopenharmony_ci /* skb might already have been processed last time. */ 179162306a36Sopenharmony_ci if (bf->skb != NULL) { 179262306a36Sopenharmony_ci ds = bf->desc; 179362306a36Sopenharmony_ci 179462306a36Sopenharmony_ci ret = ah->ah_proc_tx_desc(ah, ds, &ts); 179562306a36Sopenharmony_ci if (unlikely(ret == -EINPROGRESS)) 179662306a36Sopenharmony_ci break; 179762306a36Sopenharmony_ci else if (unlikely(ret)) { 179862306a36Sopenharmony_ci ATH5K_ERR(ah, 179962306a36Sopenharmony_ci "error %d while processing " 180062306a36Sopenharmony_ci "queue %u\n", ret, txq->qnum); 180162306a36Sopenharmony_ci break; 180262306a36Sopenharmony_ci } 180362306a36Sopenharmony_ci 180462306a36Sopenharmony_ci skb = bf->skb; 180562306a36Sopenharmony_ci bf->skb = NULL; 180662306a36Sopenharmony_ci 180762306a36Sopenharmony_ci dma_unmap_single(ah->dev, bf->skbaddr, skb->len, 180862306a36Sopenharmony_ci DMA_TO_DEVICE); 180962306a36Sopenharmony_ci ath5k_tx_frame_completed(ah, skb, txq, &ts, bf); 181062306a36Sopenharmony_ci } 181162306a36Sopenharmony_ci 181262306a36Sopenharmony_ci /* 181362306a36Sopenharmony_ci * It's possible that the hardware can say the buffer is 181462306a36Sopenharmony_ci * completed when it hasn't yet loaded the ds_link from 181562306a36Sopenharmony_ci * host memory and moved on. 181662306a36Sopenharmony_ci * Always keep the last descriptor to avoid HW races... 181762306a36Sopenharmony_ci */ 181862306a36Sopenharmony_ci if (ath5k_hw_get_txdp(ah, txq->qnum) != bf->daddr) { 181962306a36Sopenharmony_ci spin_lock(&ah->txbuflock); 182062306a36Sopenharmony_ci list_move_tail(&bf->list, &ah->txbuf); 182162306a36Sopenharmony_ci ah->txbuf_len++; 182262306a36Sopenharmony_ci txq->txq_len--; 182362306a36Sopenharmony_ci spin_unlock(&ah->txbuflock); 182462306a36Sopenharmony_ci } 182562306a36Sopenharmony_ci } 182662306a36Sopenharmony_ci spin_unlock(&txq->lock); 182762306a36Sopenharmony_ci if (txq->txq_len < ATH5K_TXQ_LEN_LOW && txq->qnum < 4) 182862306a36Sopenharmony_ci ieee80211_wake_queue(ah->hw, txq->qnum); 182962306a36Sopenharmony_ci} 183062306a36Sopenharmony_ci 183162306a36Sopenharmony_cistatic void 183262306a36Sopenharmony_ciath5k_tasklet_tx(struct tasklet_struct *t) 183362306a36Sopenharmony_ci{ 183462306a36Sopenharmony_ci int i; 183562306a36Sopenharmony_ci struct ath5k_hw *ah = from_tasklet(ah, t, txtq); 183662306a36Sopenharmony_ci 183762306a36Sopenharmony_ci for (i = 0; i < AR5K_NUM_TX_QUEUES; i++) 183862306a36Sopenharmony_ci if (ah->txqs[i].setup && (ah->ah_txq_isr_txok_all & BIT(i))) 183962306a36Sopenharmony_ci ath5k_tx_processq(ah, &ah->txqs[i]); 184062306a36Sopenharmony_ci 184162306a36Sopenharmony_ci ah->tx_pending = false; 184262306a36Sopenharmony_ci ath5k_set_current_imask(ah); 184362306a36Sopenharmony_ci} 184462306a36Sopenharmony_ci 184562306a36Sopenharmony_ci 184662306a36Sopenharmony_ci/*****************\ 184762306a36Sopenharmony_ci* Beacon handling * 184862306a36Sopenharmony_ci\*****************/ 184962306a36Sopenharmony_ci 185062306a36Sopenharmony_ci/* 185162306a36Sopenharmony_ci * Setup the beacon frame for transmit. 185262306a36Sopenharmony_ci */ 185362306a36Sopenharmony_cistatic int 185462306a36Sopenharmony_ciath5k_beacon_setup(struct ath5k_hw *ah, struct ath5k_buf *bf) 185562306a36Sopenharmony_ci{ 185662306a36Sopenharmony_ci struct sk_buff *skb = bf->skb; 185762306a36Sopenharmony_ci struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); 185862306a36Sopenharmony_ci struct ath5k_desc *ds; 185962306a36Sopenharmony_ci int ret = 0; 186062306a36Sopenharmony_ci u8 antenna; 186162306a36Sopenharmony_ci u32 flags; 186262306a36Sopenharmony_ci const int padsize = 0; 186362306a36Sopenharmony_ci 186462306a36Sopenharmony_ci bf->skbaddr = dma_map_single(ah->dev, skb->data, skb->len, 186562306a36Sopenharmony_ci DMA_TO_DEVICE); 186662306a36Sopenharmony_ci ATH5K_DBG(ah, ATH5K_DEBUG_BEACON, "skb %p [data %p len %u] " 186762306a36Sopenharmony_ci "skbaddr %llx\n", skb, skb->data, skb->len, 186862306a36Sopenharmony_ci (unsigned long long)bf->skbaddr); 186962306a36Sopenharmony_ci 187062306a36Sopenharmony_ci if (dma_mapping_error(ah->dev, bf->skbaddr)) { 187162306a36Sopenharmony_ci ATH5K_ERR(ah, "beacon DMA mapping failed\n"); 187262306a36Sopenharmony_ci dev_kfree_skb_any(skb); 187362306a36Sopenharmony_ci bf->skb = NULL; 187462306a36Sopenharmony_ci return -EIO; 187562306a36Sopenharmony_ci } 187662306a36Sopenharmony_ci 187762306a36Sopenharmony_ci ds = bf->desc; 187862306a36Sopenharmony_ci antenna = ah->ah_tx_ant; 187962306a36Sopenharmony_ci 188062306a36Sopenharmony_ci flags = AR5K_TXDESC_NOACK; 188162306a36Sopenharmony_ci if (ah->opmode == NL80211_IFTYPE_ADHOC && ath5k_hw_hasveol(ah)) { 188262306a36Sopenharmony_ci ds->ds_link = bf->daddr; /* self-linked */ 188362306a36Sopenharmony_ci flags |= AR5K_TXDESC_VEOL; 188462306a36Sopenharmony_ci } else 188562306a36Sopenharmony_ci ds->ds_link = 0; 188662306a36Sopenharmony_ci 188762306a36Sopenharmony_ci /* 188862306a36Sopenharmony_ci * If we use multiple antennas on AP and use 188962306a36Sopenharmony_ci * the Sectored AP scenario, switch antenna every 189062306a36Sopenharmony_ci * 4 beacons to make sure everybody hears our AP. 189162306a36Sopenharmony_ci * When a client tries to associate, hw will keep 189262306a36Sopenharmony_ci * track of the tx antenna to be used for this client 189362306a36Sopenharmony_ci * automatically, based on ACKed packets. 189462306a36Sopenharmony_ci * 189562306a36Sopenharmony_ci * Note: AP still listens and transmits RTS on the 189662306a36Sopenharmony_ci * default antenna which is supposed to be an omni. 189762306a36Sopenharmony_ci * 189862306a36Sopenharmony_ci * Note2: On sectored scenarios it's possible to have 189962306a36Sopenharmony_ci * multiple antennas (1 omni -- the default -- and 14 190062306a36Sopenharmony_ci * sectors), so if we choose to actually support this 190162306a36Sopenharmony_ci * mode, we need to allow the user to set how many antennas 190262306a36Sopenharmony_ci * we have and tweak the code below to send beacons 190362306a36Sopenharmony_ci * on all of them. 190462306a36Sopenharmony_ci */ 190562306a36Sopenharmony_ci if (ah->ah_ant_mode == AR5K_ANTMODE_SECTOR_AP) 190662306a36Sopenharmony_ci antenna = ah->bsent & 4 ? 2 : 1; 190762306a36Sopenharmony_ci 190862306a36Sopenharmony_ci 190962306a36Sopenharmony_ci /* FIXME: If we are in g mode and rate is a CCK rate 191062306a36Sopenharmony_ci * subtract ah->ah_txpower.txp_cck_ofdm_pwr_delta 191162306a36Sopenharmony_ci * from tx power (value is in dB units already) */ 191262306a36Sopenharmony_ci ds->ds_data = bf->skbaddr; 191362306a36Sopenharmony_ci ret = ah->ah_setup_tx_desc(ah, ds, skb->len, 191462306a36Sopenharmony_ci ieee80211_get_hdrlen_from_skb(skb), padsize, 191562306a36Sopenharmony_ci AR5K_PKT_TYPE_BEACON, 191662306a36Sopenharmony_ci (ah->ah_txpower.txp_requested * 2), 191762306a36Sopenharmony_ci ieee80211_get_tx_rate(ah->hw, info)->hw_value, 191862306a36Sopenharmony_ci 1, AR5K_TXKEYIX_INVALID, 191962306a36Sopenharmony_ci antenna, flags, 0, 0); 192062306a36Sopenharmony_ci if (ret) 192162306a36Sopenharmony_ci goto err_unmap; 192262306a36Sopenharmony_ci 192362306a36Sopenharmony_ci return 0; 192462306a36Sopenharmony_cierr_unmap: 192562306a36Sopenharmony_ci dma_unmap_single(ah->dev, bf->skbaddr, skb->len, DMA_TO_DEVICE); 192662306a36Sopenharmony_ci return ret; 192762306a36Sopenharmony_ci} 192862306a36Sopenharmony_ci 192962306a36Sopenharmony_ci/* 193062306a36Sopenharmony_ci * Updates the beacon that is sent by ath5k_beacon_send. For adhoc, 193162306a36Sopenharmony_ci * this is called only once at config_bss time, for AP we do it every 193262306a36Sopenharmony_ci * SWBA interrupt so that the TIM will reflect buffered frames. 193362306a36Sopenharmony_ci * 193462306a36Sopenharmony_ci * Called with the beacon lock. 193562306a36Sopenharmony_ci */ 193662306a36Sopenharmony_ciint 193762306a36Sopenharmony_ciath5k_beacon_update(struct ieee80211_hw *hw, struct ieee80211_vif *vif) 193862306a36Sopenharmony_ci{ 193962306a36Sopenharmony_ci int ret; 194062306a36Sopenharmony_ci struct ath5k_hw *ah = hw->priv; 194162306a36Sopenharmony_ci struct ath5k_vif *avf; 194262306a36Sopenharmony_ci struct sk_buff *skb; 194362306a36Sopenharmony_ci 194462306a36Sopenharmony_ci if (WARN_ON(!vif)) { 194562306a36Sopenharmony_ci ret = -EINVAL; 194662306a36Sopenharmony_ci goto out; 194762306a36Sopenharmony_ci } 194862306a36Sopenharmony_ci 194962306a36Sopenharmony_ci skb = ieee80211_beacon_get(hw, vif, 0); 195062306a36Sopenharmony_ci 195162306a36Sopenharmony_ci if (!skb) { 195262306a36Sopenharmony_ci ret = -ENOMEM; 195362306a36Sopenharmony_ci goto out; 195462306a36Sopenharmony_ci } 195562306a36Sopenharmony_ci 195662306a36Sopenharmony_ci avf = (void *)vif->drv_priv; 195762306a36Sopenharmony_ci ath5k_txbuf_free_skb(ah, avf->bbuf); 195862306a36Sopenharmony_ci avf->bbuf->skb = skb; 195962306a36Sopenharmony_ci ret = ath5k_beacon_setup(ah, avf->bbuf); 196062306a36Sopenharmony_ciout: 196162306a36Sopenharmony_ci return ret; 196262306a36Sopenharmony_ci} 196362306a36Sopenharmony_ci 196462306a36Sopenharmony_ci/* 196562306a36Sopenharmony_ci * Transmit a beacon frame at SWBA. Dynamic updates to the 196662306a36Sopenharmony_ci * frame contents are done as needed and the slot time is 196762306a36Sopenharmony_ci * also adjusted based on current state. 196862306a36Sopenharmony_ci * 196962306a36Sopenharmony_ci * This is called from software irq context (beacontq tasklets) 197062306a36Sopenharmony_ci * or user context from ath5k_beacon_config. 197162306a36Sopenharmony_ci */ 197262306a36Sopenharmony_cistatic void 197362306a36Sopenharmony_ciath5k_beacon_send(struct ath5k_hw *ah) 197462306a36Sopenharmony_ci{ 197562306a36Sopenharmony_ci struct ieee80211_vif *vif; 197662306a36Sopenharmony_ci struct ath5k_vif *avf; 197762306a36Sopenharmony_ci struct ath5k_buf *bf; 197862306a36Sopenharmony_ci struct sk_buff *skb; 197962306a36Sopenharmony_ci int err; 198062306a36Sopenharmony_ci 198162306a36Sopenharmony_ci ATH5K_DBG_UNLIMIT(ah, ATH5K_DEBUG_BEACON, "in beacon_send\n"); 198262306a36Sopenharmony_ci 198362306a36Sopenharmony_ci /* 198462306a36Sopenharmony_ci * Check if the previous beacon has gone out. If 198562306a36Sopenharmony_ci * not, don't try to post another: skip this 198662306a36Sopenharmony_ci * period and wait for the next. Missed beacons 198762306a36Sopenharmony_ci * indicate a problem and should not occur. If we 198862306a36Sopenharmony_ci * miss too many consecutive beacons reset the device. 198962306a36Sopenharmony_ci */ 199062306a36Sopenharmony_ci if (unlikely(ath5k_hw_num_tx_pending(ah, ah->bhalq) != 0)) { 199162306a36Sopenharmony_ci ah->bmisscount++; 199262306a36Sopenharmony_ci ATH5K_DBG(ah, ATH5K_DEBUG_BEACON, 199362306a36Sopenharmony_ci "missed %u consecutive beacons\n", ah->bmisscount); 199462306a36Sopenharmony_ci if (ah->bmisscount > 10) { /* NB: 10 is a guess */ 199562306a36Sopenharmony_ci ATH5K_DBG(ah, ATH5K_DEBUG_BEACON, 199662306a36Sopenharmony_ci "stuck beacon time (%u missed)\n", 199762306a36Sopenharmony_ci ah->bmisscount); 199862306a36Sopenharmony_ci ATH5K_DBG(ah, ATH5K_DEBUG_RESET, 199962306a36Sopenharmony_ci "stuck beacon, resetting\n"); 200062306a36Sopenharmony_ci ieee80211_queue_work(ah->hw, &ah->reset_work); 200162306a36Sopenharmony_ci } 200262306a36Sopenharmony_ci return; 200362306a36Sopenharmony_ci } 200462306a36Sopenharmony_ci if (unlikely(ah->bmisscount != 0)) { 200562306a36Sopenharmony_ci ATH5K_DBG(ah, ATH5K_DEBUG_BEACON, 200662306a36Sopenharmony_ci "resume beacon xmit after %u misses\n", 200762306a36Sopenharmony_ci ah->bmisscount); 200862306a36Sopenharmony_ci ah->bmisscount = 0; 200962306a36Sopenharmony_ci } 201062306a36Sopenharmony_ci 201162306a36Sopenharmony_ci if ((ah->opmode == NL80211_IFTYPE_AP && ah->num_ap_vifs + 201262306a36Sopenharmony_ci ah->num_mesh_vifs > 1) || 201362306a36Sopenharmony_ci ah->opmode == NL80211_IFTYPE_MESH_POINT) { 201462306a36Sopenharmony_ci u64 tsf = ath5k_hw_get_tsf64(ah); 201562306a36Sopenharmony_ci u32 tsftu = TSF_TO_TU(tsf); 201662306a36Sopenharmony_ci int slot = ((tsftu % ah->bintval) * ATH_BCBUF) / ah->bintval; 201762306a36Sopenharmony_ci vif = ah->bslot[(slot + 1) % ATH_BCBUF]; 201862306a36Sopenharmony_ci ATH5K_DBG(ah, ATH5K_DEBUG_BEACON, 201962306a36Sopenharmony_ci "tsf %llx tsftu %x intval %u slot %u vif %p\n", 202062306a36Sopenharmony_ci (unsigned long long)tsf, tsftu, ah->bintval, slot, vif); 202162306a36Sopenharmony_ci } else /* only one interface */ 202262306a36Sopenharmony_ci vif = ah->bslot[0]; 202362306a36Sopenharmony_ci 202462306a36Sopenharmony_ci if (!vif) 202562306a36Sopenharmony_ci return; 202662306a36Sopenharmony_ci 202762306a36Sopenharmony_ci avf = (void *)vif->drv_priv; 202862306a36Sopenharmony_ci bf = avf->bbuf; 202962306a36Sopenharmony_ci 203062306a36Sopenharmony_ci /* 203162306a36Sopenharmony_ci * Stop any current dma and put the new frame on the queue. 203262306a36Sopenharmony_ci * This should never fail since we check above that no frames 203362306a36Sopenharmony_ci * are still pending on the queue. 203462306a36Sopenharmony_ci */ 203562306a36Sopenharmony_ci if (unlikely(ath5k_hw_stop_beacon_queue(ah, ah->bhalq))) { 203662306a36Sopenharmony_ci ATH5K_WARN(ah, "beacon queue %u didn't start/stop ?\n", ah->bhalq); 203762306a36Sopenharmony_ci /* NB: hw still stops DMA, so proceed */ 203862306a36Sopenharmony_ci } 203962306a36Sopenharmony_ci 204062306a36Sopenharmony_ci /* refresh the beacon for AP or MESH mode */ 204162306a36Sopenharmony_ci if (ah->opmode == NL80211_IFTYPE_AP || 204262306a36Sopenharmony_ci ah->opmode == NL80211_IFTYPE_MESH_POINT) { 204362306a36Sopenharmony_ci err = ath5k_beacon_update(ah->hw, vif); 204462306a36Sopenharmony_ci if (err) 204562306a36Sopenharmony_ci return; 204662306a36Sopenharmony_ci } 204762306a36Sopenharmony_ci 204862306a36Sopenharmony_ci if (unlikely(bf->skb == NULL || ah->opmode == NL80211_IFTYPE_STATION || 204962306a36Sopenharmony_ci ah->opmode == NL80211_IFTYPE_MONITOR)) { 205062306a36Sopenharmony_ci ATH5K_WARN(ah, "bf=%p bf_skb=%p\n", bf, bf->skb); 205162306a36Sopenharmony_ci return; 205262306a36Sopenharmony_ci } 205362306a36Sopenharmony_ci 205462306a36Sopenharmony_ci trace_ath5k_tx(ah, bf->skb, &ah->txqs[ah->bhalq]); 205562306a36Sopenharmony_ci 205662306a36Sopenharmony_ci ath5k_hw_set_txdp(ah, ah->bhalq, bf->daddr); 205762306a36Sopenharmony_ci ath5k_hw_start_tx_dma(ah, ah->bhalq); 205862306a36Sopenharmony_ci ATH5K_DBG(ah, ATH5K_DEBUG_BEACON, "TXDP[%u] = %llx (%p)\n", 205962306a36Sopenharmony_ci ah->bhalq, (unsigned long long)bf->daddr, bf->desc); 206062306a36Sopenharmony_ci 206162306a36Sopenharmony_ci skb = ieee80211_get_buffered_bc(ah->hw, vif); 206262306a36Sopenharmony_ci while (skb) { 206362306a36Sopenharmony_ci ath5k_tx_queue(ah->hw, skb, ah->cabq, NULL); 206462306a36Sopenharmony_ci 206562306a36Sopenharmony_ci if (ah->cabq->txq_len >= ah->cabq->txq_max) 206662306a36Sopenharmony_ci break; 206762306a36Sopenharmony_ci 206862306a36Sopenharmony_ci skb = ieee80211_get_buffered_bc(ah->hw, vif); 206962306a36Sopenharmony_ci } 207062306a36Sopenharmony_ci 207162306a36Sopenharmony_ci ah->bsent++; 207262306a36Sopenharmony_ci} 207362306a36Sopenharmony_ci 207462306a36Sopenharmony_ci/** 207562306a36Sopenharmony_ci * ath5k_beacon_update_timers - update beacon timers 207662306a36Sopenharmony_ci * 207762306a36Sopenharmony_ci * @ah: struct ath5k_hw pointer we are operating on 207862306a36Sopenharmony_ci * @bc_tsf: the timestamp of the beacon. 0 to reset the TSF. -1 to perform a 207962306a36Sopenharmony_ci * beacon timer update based on the current HW TSF. 208062306a36Sopenharmony_ci * 208162306a36Sopenharmony_ci * Calculate the next target beacon transmit time (TBTT) based on the timestamp 208262306a36Sopenharmony_ci * of a received beacon or the current local hardware TSF and write it to the 208362306a36Sopenharmony_ci * beacon timer registers. 208462306a36Sopenharmony_ci * 208562306a36Sopenharmony_ci * This is called in a variety of situations, e.g. when a beacon is received, 208662306a36Sopenharmony_ci * when a TSF update has been detected, but also when an new IBSS is created or 208762306a36Sopenharmony_ci * when we otherwise know we have to update the timers, but we keep it in this 208862306a36Sopenharmony_ci * function to have it all together in one place. 208962306a36Sopenharmony_ci */ 209062306a36Sopenharmony_civoid 209162306a36Sopenharmony_ciath5k_beacon_update_timers(struct ath5k_hw *ah, u64 bc_tsf) 209262306a36Sopenharmony_ci{ 209362306a36Sopenharmony_ci u32 nexttbtt, intval, hw_tu, bc_tu; 209462306a36Sopenharmony_ci u64 hw_tsf; 209562306a36Sopenharmony_ci 209662306a36Sopenharmony_ci intval = ah->bintval & AR5K_BEACON_PERIOD; 209762306a36Sopenharmony_ci if (ah->opmode == NL80211_IFTYPE_AP && ah->num_ap_vifs 209862306a36Sopenharmony_ci + ah->num_mesh_vifs > 1) { 209962306a36Sopenharmony_ci intval /= ATH_BCBUF; /* staggered multi-bss beacons */ 210062306a36Sopenharmony_ci if (intval < 15) 210162306a36Sopenharmony_ci ATH5K_WARN(ah, "intval %u is too low, min 15\n", 210262306a36Sopenharmony_ci intval); 210362306a36Sopenharmony_ci } 210462306a36Sopenharmony_ci if (WARN_ON(!intval)) 210562306a36Sopenharmony_ci return; 210662306a36Sopenharmony_ci 210762306a36Sopenharmony_ci /* beacon TSF converted to TU */ 210862306a36Sopenharmony_ci bc_tu = TSF_TO_TU(bc_tsf); 210962306a36Sopenharmony_ci 211062306a36Sopenharmony_ci /* current TSF converted to TU */ 211162306a36Sopenharmony_ci hw_tsf = ath5k_hw_get_tsf64(ah); 211262306a36Sopenharmony_ci hw_tu = TSF_TO_TU(hw_tsf); 211362306a36Sopenharmony_ci 211462306a36Sopenharmony_ci#define FUDGE (AR5K_TUNE_SW_BEACON_RESP + 3) 211562306a36Sopenharmony_ci /* We use FUDGE to make sure the next TBTT is ahead of the current TU. 211662306a36Sopenharmony_ci * Since we later subtract AR5K_TUNE_SW_BEACON_RESP (10) in the timer 211762306a36Sopenharmony_ci * configuration we need to make sure it is bigger than that. */ 211862306a36Sopenharmony_ci 211962306a36Sopenharmony_ci if (bc_tsf == -1) { 212062306a36Sopenharmony_ci /* 212162306a36Sopenharmony_ci * no beacons received, called internally. 212262306a36Sopenharmony_ci * just need to refresh timers based on HW TSF. 212362306a36Sopenharmony_ci */ 212462306a36Sopenharmony_ci nexttbtt = roundup(hw_tu + FUDGE, intval); 212562306a36Sopenharmony_ci } else if (bc_tsf == 0) { 212662306a36Sopenharmony_ci /* 212762306a36Sopenharmony_ci * no beacon received, probably called by ath5k_reset_tsf(). 212862306a36Sopenharmony_ci * reset TSF to start with 0. 212962306a36Sopenharmony_ci */ 213062306a36Sopenharmony_ci nexttbtt = intval; 213162306a36Sopenharmony_ci intval |= AR5K_BEACON_RESET_TSF; 213262306a36Sopenharmony_ci } else if (bc_tsf > hw_tsf) { 213362306a36Sopenharmony_ci /* 213462306a36Sopenharmony_ci * beacon received, SW merge happened but HW TSF not yet updated. 213562306a36Sopenharmony_ci * not possible to reconfigure timers yet, but next time we 213662306a36Sopenharmony_ci * receive a beacon with the same BSSID, the hardware will 213762306a36Sopenharmony_ci * automatically update the TSF and then we need to reconfigure 213862306a36Sopenharmony_ci * the timers. 213962306a36Sopenharmony_ci */ 214062306a36Sopenharmony_ci ATH5K_DBG_UNLIMIT(ah, ATH5K_DEBUG_BEACON, 214162306a36Sopenharmony_ci "need to wait for HW TSF sync\n"); 214262306a36Sopenharmony_ci return; 214362306a36Sopenharmony_ci } else { 214462306a36Sopenharmony_ci /* 214562306a36Sopenharmony_ci * most important case for beacon synchronization between STA. 214662306a36Sopenharmony_ci * 214762306a36Sopenharmony_ci * beacon received and HW TSF has been already updated by HW. 214862306a36Sopenharmony_ci * update next TBTT based on the TSF of the beacon, but make 214962306a36Sopenharmony_ci * sure it is ahead of our local TSF timer. 215062306a36Sopenharmony_ci */ 215162306a36Sopenharmony_ci nexttbtt = bc_tu + roundup(hw_tu + FUDGE - bc_tu, intval); 215262306a36Sopenharmony_ci } 215362306a36Sopenharmony_ci#undef FUDGE 215462306a36Sopenharmony_ci 215562306a36Sopenharmony_ci ah->nexttbtt = nexttbtt; 215662306a36Sopenharmony_ci 215762306a36Sopenharmony_ci intval |= AR5K_BEACON_ENA; 215862306a36Sopenharmony_ci ath5k_hw_init_beacon_timers(ah, nexttbtt, intval); 215962306a36Sopenharmony_ci 216062306a36Sopenharmony_ci /* 216162306a36Sopenharmony_ci * debugging output last in order to preserve the time critical aspect 216262306a36Sopenharmony_ci * of this function 216362306a36Sopenharmony_ci */ 216462306a36Sopenharmony_ci if (bc_tsf == -1) 216562306a36Sopenharmony_ci ATH5K_DBG_UNLIMIT(ah, ATH5K_DEBUG_BEACON, 216662306a36Sopenharmony_ci "reconfigured timers based on HW TSF\n"); 216762306a36Sopenharmony_ci else if (bc_tsf == 0) 216862306a36Sopenharmony_ci ATH5K_DBG_UNLIMIT(ah, ATH5K_DEBUG_BEACON, 216962306a36Sopenharmony_ci "reset HW TSF and timers\n"); 217062306a36Sopenharmony_ci else 217162306a36Sopenharmony_ci ATH5K_DBG_UNLIMIT(ah, ATH5K_DEBUG_BEACON, 217262306a36Sopenharmony_ci "updated timers based on beacon TSF\n"); 217362306a36Sopenharmony_ci 217462306a36Sopenharmony_ci ATH5K_DBG_UNLIMIT(ah, ATH5K_DEBUG_BEACON, 217562306a36Sopenharmony_ci "bc_tsf %llx hw_tsf %llx bc_tu %u hw_tu %u nexttbtt %u\n", 217662306a36Sopenharmony_ci (unsigned long long) bc_tsf, 217762306a36Sopenharmony_ci (unsigned long long) hw_tsf, bc_tu, hw_tu, nexttbtt); 217862306a36Sopenharmony_ci ATH5K_DBG_UNLIMIT(ah, ATH5K_DEBUG_BEACON, "intval %u %s %s\n", 217962306a36Sopenharmony_ci intval & AR5K_BEACON_PERIOD, 218062306a36Sopenharmony_ci intval & AR5K_BEACON_ENA ? "AR5K_BEACON_ENA" : "", 218162306a36Sopenharmony_ci intval & AR5K_BEACON_RESET_TSF ? "AR5K_BEACON_RESET_TSF" : ""); 218262306a36Sopenharmony_ci} 218362306a36Sopenharmony_ci 218462306a36Sopenharmony_ci/** 218562306a36Sopenharmony_ci * ath5k_beacon_config - Configure the beacon queues and interrupts 218662306a36Sopenharmony_ci * 218762306a36Sopenharmony_ci * @ah: struct ath5k_hw pointer we are operating on 218862306a36Sopenharmony_ci * 218962306a36Sopenharmony_ci * In IBSS mode we use a self-linked tx descriptor if possible. We enable SWBA 219062306a36Sopenharmony_ci * interrupts to detect TSF updates only. 219162306a36Sopenharmony_ci */ 219262306a36Sopenharmony_civoid 219362306a36Sopenharmony_ciath5k_beacon_config(struct ath5k_hw *ah) 219462306a36Sopenharmony_ci{ 219562306a36Sopenharmony_ci spin_lock_bh(&ah->block); 219662306a36Sopenharmony_ci ah->bmisscount = 0; 219762306a36Sopenharmony_ci ah->imask &= ~(AR5K_INT_BMISS | AR5K_INT_SWBA); 219862306a36Sopenharmony_ci 219962306a36Sopenharmony_ci if (ah->enable_beacon) { 220062306a36Sopenharmony_ci /* 220162306a36Sopenharmony_ci * In IBSS mode we use a self-linked tx descriptor and let the 220262306a36Sopenharmony_ci * hardware send the beacons automatically. We have to load it 220362306a36Sopenharmony_ci * only once here. 220462306a36Sopenharmony_ci * We use the SWBA interrupt only to keep track of the beacon 220562306a36Sopenharmony_ci * timers in order to detect automatic TSF updates. 220662306a36Sopenharmony_ci */ 220762306a36Sopenharmony_ci ath5k_beaconq_config(ah); 220862306a36Sopenharmony_ci 220962306a36Sopenharmony_ci ah->imask |= AR5K_INT_SWBA; 221062306a36Sopenharmony_ci 221162306a36Sopenharmony_ci if (ah->opmode == NL80211_IFTYPE_ADHOC) { 221262306a36Sopenharmony_ci if (ath5k_hw_hasveol(ah)) 221362306a36Sopenharmony_ci ath5k_beacon_send(ah); 221462306a36Sopenharmony_ci } else 221562306a36Sopenharmony_ci ath5k_beacon_update_timers(ah, -1); 221662306a36Sopenharmony_ci } else { 221762306a36Sopenharmony_ci ath5k_hw_stop_beacon_queue(ah, ah->bhalq); 221862306a36Sopenharmony_ci } 221962306a36Sopenharmony_ci 222062306a36Sopenharmony_ci ath5k_hw_set_imr(ah, ah->imask); 222162306a36Sopenharmony_ci spin_unlock_bh(&ah->block); 222262306a36Sopenharmony_ci} 222362306a36Sopenharmony_ci 222462306a36Sopenharmony_cistatic void ath5k_tasklet_beacon(struct tasklet_struct *t) 222562306a36Sopenharmony_ci{ 222662306a36Sopenharmony_ci struct ath5k_hw *ah = from_tasklet(ah, t, beacontq); 222762306a36Sopenharmony_ci 222862306a36Sopenharmony_ci /* 222962306a36Sopenharmony_ci * Software beacon alert--time to send a beacon. 223062306a36Sopenharmony_ci * 223162306a36Sopenharmony_ci * In IBSS mode we use this interrupt just to 223262306a36Sopenharmony_ci * keep track of the next TBTT (target beacon 223362306a36Sopenharmony_ci * transmission time) in order to detect whether 223462306a36Sopenharmony_ci * automatic TSF updates happened. 223562306a36Sopenharmony_ci */ 223662306a36Sopenharmony_ci if (ah->opmode == NL80211_IFTYPE_ADHOC) { 223762306a36Sopenharmony_ci /* XXX: only if VEOL supported */ 223862306a36Sopenharmony_ci u64 tsf = ath5k_hw_get_tsf64(ah); 223962306a36Sopenharmony_ci ah->nexttbtt += ah->bintval; 224062306a36Sopenharmony_ci ATH5K_DBG(ah, ATH5K_DEBUG_BEACON, 224162306a36Sopenharmony_ci "SWBA nexttbtt: %x hw_tu: %x " 224262306a36Sopenharmony_ci "TSF: %llx\n", 224362306a36Sopenharmony_ci ah->nexttbtt, 224462306a36Sopenharmony_ci TSF_TO_TU(tsf), 224562306a36Sopenharmony_ci (unsigned long long) tsf); 224662306a36Sopenharmony_ci } else { 224762306a36Sopenharmony_ci spin_lock(&ah->block); 224862306a36Sopenharmony_ci ath5k_beacon_send(ah); 224962306a36Sopenharmony_ci spin_unlock(&ah->block); 225062306a36Sopenharmony_ci } 225162306a36Sopenharmony_ci} 225262306a36Sopenharmony_ci 225362306a36Sopenharmony_ci 225462306a36Sopenharmony_ci/********************\ 225562306a36Sopenharmony_ci* Interrupt handling * 225662306a36Sopenharmony_ci\********************/ 225762306a36Sopenharmony_ci 225862306a36Sopenharmony_cistatic void 225962306a36Sopenharmony_ciath5k_intr_calibration_poll(struct ath5k_hw *ah) 226062306a36Sopenharmony_ci{ 226162306a36Sopenharmony_ci if (time_is_before_eq_jiffies(ah->ah_cal_next_ani) && 226262306a36Sopenharmony_ci !(ah->ah_cal_mask & AR5K_CALIBRATION_FULL) && 226362306a36Sopenharmony_ci !(ah->ah_cal_mask & AR5K_CALIBRATION_SHORT)) { 226462306a36Sopenharmony_ci 226562306a36Sopenharmony_ci /* Run ANI only when calibration is not active */ 226662306a36Sopenharmony_ci 226762306a36Sopenharmony_ci ah->ah_cal_next_ani = jiffies + 226862306a36Sopenharmony_ci msecs_to_jiffies(ATH5K_TUNE_CALIBRATION_INTERVAL_ANI); 226962306a36Sopenharmony_ci tasklet_schedule(&ah->ani_tasklet); 227062306a36Sopenharmony_ci 227162306a36Sopenharmony_ci } else if (time_is_before_eq_jiffies(ah->ah_cal_next_short) && 227262306a36Sopenharmony_ci !(ah->ah_cal_mask & AR5K_CALIBRATION_FULL) && 227362306a36Sopenharmony_ci !(ah->ah_cal_mask & AR5K_CALIBRATION_SHORT)) { 227462306a36Sopenharmony_ci 227562306a36Sopenharmony_ci /* Run calibration only when another calibration 227662306a36Sopenharmony_ci * is not running. 227762306a36Sopenharmony_ci * 227862306a36Sopenharmony_ci * Note: This is for both full/short calibration, 227962306a36Sopenharmony_ci * if it's time for a full one, ath5k_calibrate_work will deal 228062306a36Sopenharmony_ci * with it. */ 228162306a36Sopenharmony_ci 228262306a36Sopenharmony_ci ah->ah_cal_next_short = jiffies + 228362306a36Sopenharmony_ci msecs_to_jiffies(ATH5K_TUNE_CALIBRATION_INTERVAL_SHORT); 228462306a36Sopenharmony_ci ieee80211_queue_work(ah->hw, &ah->calib_work); 228562306a36Sopenharmony_ci } 228662306a36Sopenharmony_ci /* we could use SWI to generate enough interrupts to meet our 228762306a36Sopenharmony_ci * calibration interval requirements, if necessary: 228862306a36Sopenharmony_ci * AR5K_REG_ENABLE_BITS(ah, AR5K_CR, AR5K_CR_SWI); */ 228962306a36Sopenharmony_ci} 229062306a36Sopenharmony_ci 229162306a36Sopenharmony_cistatic void 229262306a36Sopenharmony_ciath5k_schedule_rx(struct ath5k_hw *ah) 229362306a36Sopenharmony_ci{ 229462306a36Sopenharmony_ci ah->rx_pending = true; 229562306a36Sopenharmony_ci tasklet_schedule(&ah->rxtq); 229662306a36Sopenharmony_ci} 229762306a36Sopenharmony_ci 229862306a36Sopenharmony_cistatic void 229962306a36Sopenharmony_ciath5k_schedule_tx(struct ath5k_hw *ah) 230062306a36Sopenharmony_ci{ 230162306a36Sopenharmony_ci ah->tx_pending = true; 230262306a36Sopenharmony_ci tasklet_schedule(&ah->txtq); 230362306a36Sopenharmony_ci} 230462306a36Sopenharmony_ci 230562306a36Sopenharmony_cistatic irqreturn_t 230662306a36Sopenharmony_ciath5k_intr(int irq, void *dev_id) 230762306a36Sopenharmony_ci{ 230862306a36Sopenharmony_ci struct ath5k_hw *ah = dev_id; 230962306a36Sopenharmony_ci enum ath5k_int status; 231062306a36Sopenharmony_ci unsigned int counter = 1000; 231162306a36Sopenharmony_ci 231262306a36Sopenharmony_ci 231362306a36Sopenharmony_ci /* 231462306a36Sopenharmony_ci * If hw is not ready (or detached) and we get an 231562306a36Sopenharmony_ci * interrupt, or if we have no interrupts pending 231662306a36Sopenharmony_ci * (that means it's not for us) skip it. 231762306a36Sopenharmony_ci * 231862306a36Sopenharmony_ci * NOTE: Group 0/1 PCI interface registers are not 231962306a36Sopenharmony_ci * supported on WiSOCs, so we can't check for pending 232062306a36Sopenharmony_ci * interrupts (ISR belongs to another register group 232162306a36Sopenharmony_ci * so we are ok). 232262306a36Sopenharmony_ci */ 232362306a36Sopenharmony_ci if (unlikely(test_bit(ATH_STAT_INVALID, ah->status) || 232462306a36Sopenharmony_ci ((ath5k_get_bus_type(ah) != ATH_AHB) && 232562306a36Sopenharmony_ci !ath5k_hw_is_intr_pending(ah)))) 232662306a36Sopenharmony_ci return IRQ_NONE; 232762306a36Sopenharmony_ci 232862306a36Sopenharmony_ci /** Main loop **/ 232962306a36Sopenharmony_ci do { 233062306a36Sopenharmony_ci ath5k_hw_get_isr(ah, &status); /* NB: clears IRQ too */ 233162306a36Sopenharmony_ci 233262306a36Sopenharmony_ci ATH5K_DBG(ah, ATH5K_DEBUG_INTR, "status 0x%x/0x%x\n", 233362306a36Sopenharmony_ci status, ah->imask); 233462306a36Sopenharmony_ci 233562306a36Sopenharmony_ci /* 233662306a36Sopenharmony_ci * Fatal hw error -> Log and reset 233762306a36Sopenharmony_ci * 233862306a36Sopenharmony_ci * Fatal errors are unrecoverable so we have to 233962306a36Sopenharmony_ci * reset the card. These errors include bus and 234062306a36Sopenharmony_ci * dma errors. 234162306a36Sopenharmony_ci */ 234262306a36Sopenharmony_ci if (unlikely(status & AR5K_INT_FATAL)) { 234362306a36Sopenharmony_ci 234462306a36Sopenharmony_ci ATH5K_DBG(ah, ATH5K_DEBUG_RESET, 234562306a36Sopenharmony_ci "fatal int, resetting\n"); 234662306a36Sopenharmony_ci ieee80211_queue_work(ah->hw, &ah->reset_work); 234762306a36Sopenharmony_ci 234862306a36Sopenharmony_ci /* 234962306a36Sopenharmony_ci * RX Overrun -> Count and reset if needed 235062306a36Sopenharmony_ci * 235162306a36Sopenharmony_ci * Receive buffers are full. Either the bus is busy or 235262306a36Sopenharmony_ci * the CPU is not fast enough to process all received 235362306a36Sopenharmony_ci * frames. 235462306a36Sopenharmony_ci */ 235562306a36Sopenharmony_ci } else if (unlikely(status & AR5K_INT_RXORN)) { 235662306a36Sopenharmony_ci 235762306a36Sopenharmony_ci /* 235862306a36Sopenharmony_ci * Older chipsets need a reset to come out of this 235962306a36Sopenharmony_ci * condition, but we treat it as RX for newer chips. 236062306a36Sopenharmony_ci * We don't know exactly which versions need a reset 236162306a36Sopenharmony_ci * this guess is copied from the HAL. 236262306a36Sopenharmony_ci */ 236362306a36Sopenharmony_ci ah->stats.rxorn_intr++; 236462306a36Sopenharmony_ci 236562306a36Sopenharmony_ci if (ah->ah_mac_srev < AR5K_SREV_AR5212) { 236662306a36Sopenharmony_ci ATH5K_DBG(ah, ATH5K_DEBUG_RESET, 236762306a36Sopenharmony_ci "rx overrun, resetting\n"); 236862306a36Sopenharmony_ci ieee80211_queue_work(ah->hw, &ah->reset_work); 236962306a36Sopenharmony_ci } else 237062306a36Sopenharmony_ci ath5k_schedule_rx(ah); 237162306a36Sopenharmony_ci 237262306a36Sopenharmony_ci } else { 237362306a36Sopenharmony_ci 237462306a36Sopenharmony_ci /* Software Beacon Alert -> Schedule beacon tasklet */ 237562306a36Sopenharmony_ci if (status & AR5K_INT_SWBA) 237662306a36Sopenharmony_ci tasklet_hi_schedule(&ah->beacontq); 237762306a36Sopenharmony_ci 237862306a36Sopenharmony_ci /* 237962306a36Sopenharmony_ci * No more RX descriptors -> Just count 238062306a36Sopenharmony_ci * 238162306a36Sopenharmony_ci * NB: the hardware should re-read the link when 238262306a36Sopenharmony_ci * RXE bit is written, but it doesn't work at 238362306a36Sopenharmony_ci * least on older hardware revs. 238462306a36Sopenharmony_ci */ 238562306a36Sopenharmony_ci if (status & AR5K_INT_RXEOL) 238662306a36Sopenharmony_ci ah->stats.rxeol_intr++; 238762306a36Sopenharmony_ci 238862306a36Sopenharmony_ci 238962306a36Sopenharmony_ci /* TX Underrun -> Bump tx trigger level */ 239062306a36Sopenharmony_ci if (status & AR5K_INT_TXURN) 239162306a36Sopenharmony_ci ath5k_hw_update_tx_triglevel(ah, true); 239262306a36Sopenharmony_ci 239362306a36Sopenharmony_ci /* RX -> Schedule rx tasklet */ 239462306a36Sopenharmony_ci if (status & (AR5K_INT_RXOK | AR5K_INT_RXERR)) 239562306a36Sopenharmony_ci ath5k_schedule_rx(ah); 239662306a36Sopenharmony_ci 239762306a36Sopenharmony_ci /* TX -> Schedule tx tasklet */ 239862306a36Sopenharmony_ci if (status & (AR5K_INT_TXOK 239962306a36Sopenharmony_ci | AR5K_INT_TXDESC 240062306a36Sopenharmony_ci | AR5K_INT_TXERR 240162306a36Sopenharmony_ci | AR5K_INT_TXEOL)) 240262306a36Sopenharmony_ci ath5k_schedule_tx(ah); 240362306a36Sopenharmony_ci 240462306a36Sopenharmony_ci /* Missed beacon -> TODO 240562306a36Sopenharmony_ci if (status & AR5K_INT_BMISS) 240662306a36Sopenharmony_ci */ 240762306a36Sopenharmony_ci 240862306a36Sopenharmony_ci /* MIB event -> Update counters and notify ANI */ 240962306a36Sopenharmony_ci if (status & AR5K_INT_MIB) { 241062306a36Sopenharmony_ci ah->stats.mib_intr++; 241162306a36Sopenharmony_ci ath5k_hw_update_mib_counters(ah); 241262306a36Sopenharmony_ci ath5k_ani_mib_intr(ah); 241362306a36Sopenharmony_ci } 241462306a36Sopenharmony_ci 241562306a36Sopenharmony_ci /* GPIO -> Notify RFKill layer */ 241662306a36Sopenharmony_ci if (status & AR5K_INT_GPIO) 241762306a36Sopenharmony_ci tasklet_schedule(&ah->rf_kill.toggleq); 241862306a36Sopenharmony_ci 241962306a36Sopenharmony_ci } 242062306a36Sopenharmony_ci 242162306a36Sopenharmony_ci if (ath5k_get_bus_type(ah) == ATH_AHB) 242262306a36Sopenharmony_ci break; 242362306a36Sopenharmony_ci 242462306a36Sopenharmony_ci } while (ath5k_hw_is_intr_pending(ah) && --counter > 0); 242562306a36Sopenharmony_ci 242662306a36Sopenharmony_ci /* 242762306a36Sopenharmony_ci * Until we handle rx/tx interrupts mask them on IMR 242862306a36Sopenharmony_ci * 242962306a36Sopenharmony_ci * NOTE: ah->(rx/tx)_pending are set when scheduling the tasklets 243062306a36Sopenharmony_ci * and unset after we 've handled the interrupts. 243162306a36Sopenharmony_ci */ 243262306a36Sopenharmony_ci if (ah->rx_pending || ah->tx_pending) 243362306a36Sopenharmony_ci ath5k_set_current_imask(ah); 243462306a36Sopenharmony_ci 243562306a36Sopenharmony_ci if (unlikely(!counter)) 243662306a36Sopenharmony_ci ATH5K_WARN(ah, "too many interrupts, giving up for now\n"); 243762306a36Sopenharmony_ci 243862306a36Sopenharmony_ci /* Fire up calibration poll */ 243962306a36Sopenharmony_ci ath5k_intr_calibration_poll(ah); 244062306a36Sopenharmony_ci 244162306a36Sopenharmony_ci return IRQ_HANDLED; 244262306a36Sopenharmony_ci} 244362306a36Sopenharmony_ci 244462306a36Sopenharmony_ci/* 244562306a36Sopenharmony_ci * Periodically recalibrate the PHY to account 244662306a36Sopenharmony_ci * for temperature/environment changes. 244762306a36Sopenharmony_ci */ 244862306a36Sopenharmony_cistatic void 244962306a36Sopenharmony_ciath5k_calibrate_work(struct work_struct *work) 245062306a36Sopenharmony_ci{ 245162306a36Sopenharmony_ci struct ath5k_hw *ah = container_of(work, struct ath5k_hw, 245262306a36Sopenharmony_ci calib_work); 245362306a36Sopenharmony_ci 245462306a36Sopenharmony_ci /* Should we run a full calibration ? */ 245562306a36Sopenharmony_ci if (time_is_before_eq_jiffies(ah->ah_cal_next_full)) { 245662306a36Sopenharmony_ci 245762306a36Sopenharmony_ci ah->ah_cal_next_full = jiffies + 245862306a36Sopenharmony_ci msecs_to_jiffies(ATH5K_TUNE_CALIBRATION_INTERVAL_FULL); 245962306a36Sopenharmony_ci ah->ah_cal_mask |= AR5K_CALIBRATION_FULL; 246062306a36Sopenharmony_ci 246162306a36Sopenharmony_ci ATH5K_DBG(ah, ATH5K_DEBUG_CALIBRATE, 246262306a36Sopenharmony_ci "running full calibration\n"); 246362306a36Sopenharmony_ci 246462306a36Sopenharmony_ci if (ath5k_hw_gainf_calibrate(ah) == AR5K_RFGAIN_NEED_CHANGE) { 246562306a36Sopenharmony_ci /* 246662306a36Sopenharmony_ci * Rfgain is out of bounds, reset the chip 246762306a36Sopenharmony_ci * to load new gain values. 246862306a36Sopenharmony_ci */ 246962306a36Sopenharmony_ci ATH5K_DBG(ah, ATH5K_DEBUG_RESET, 247062306a36Sopenharmony_ci "got new rfgain, resetting\n"); 247162306a36Sopenharmony_ci ieee80211_queue_work(ah->hw, &ah->reset_work); 247262306a36Sopenharmony_ci } 247362306a36Sopenharmony_ci } else 247462306a36Sopenharmony_ci ah->ah_cal_mask |= AR5K_CALIBRATION_SHORT; 247562306a36Sopenharmony_ci 247662306a36Sopenharmony_ci 247762306a36Sopenharmony_ci ATH5K_DBG(ah, ATH5K_DEBUG_CALIBRATE, "channel %u/%x\n", 247862306a36Sopenharmony_ci ieee80211_frequency_to_channel(ah->curchan->center_freq), 247962306a36Sopenharmony_ci ah->curchan->hw_value); 248062306a36Sopenharmony_ci 248162306a36Sopenharmony_ci if (ath5k_hw_phy_calibrate(ah, ah->curchan)) 248262306a36Sopenharmony_ci ATH5K_ERR(ah, "calibration of channel %u failed\n", 248362306a36Sopenharmony_ci ieee80211_frequency_to_channel( 248462306a36Sopenharmony_ci ah->curchan->center_freq)); 248562306a36Sopenharmony_ci 248662306a36Sopenharmony_ci /* Clear calibration flags */ 248762306a36Sopenharmony_ci if (ah->ah_cal_mask & AR5K_CALIBRATION_FULL) 248862306a36Sopenharmony_ci ah->ah_cal_mask &= ~AR5K_CALIBRATION_FULL; 248962306a36Sopenharmony_ci else if (ah->ah_cal_mask & AR5K_CALIBRATION_SHORT) 249062306a36Sopenharmony_ci ah->ah_cal_mask &= ~AR5K_CALIBRATION_SHORT; 249162306a36Sopenharmony_ci} 249262306a36Sopenharmony_ci 249362306a36Sopenharmony_ci 249462306a36Sopenharmony_cistatic void 249562306a36Sopenharmony_ciath5k_tasklet_ani(struct tasklet_struct *t) 249662306a36Sopenharmony_ci{ 249762306a36Sopenharmony_ci struct ath5k_hw *ah = from_tasklet(ah, t, ani_tasklet); 249862306a36Sopenharmony_ci 249962306a36Sopenharmony_ci ah->ah_cal_mask |= AR5K_CALIBRATION_ANI; 250062306a36Sopenharmony_ci ath5k_ani_calibration(ah); 250162306a36Sopenharmony_ci ah->ah_cal_mask &= ~AR5K_CALIBRATION_ANI; 250262306a36Sopenharmony_ci} 250362306a36Sopenharmony_ci 250462306a36Sopenharmony_ci 250562306a36Sopenharmony_cistatic void 250662306a36Sopenharmony_ciath5k_tx_complete_poll_work(struct work_struct *work) 250762306a36Sopenharmony_ci{ 250862306a36Sopenharmony_ci struct ath5k_hw *ah = container_of(work, struct ath5k_hw, 250962306a36Sopenharmony_ci tx_complete_work.work); 251062306a36Sopenharmony_ci struct ath5k_txq *txq; 251162306a36Sopenharmony_ci int i; 251262306a36Sopenharmony_ci bool needreset = false; 251362306a36Sopenharmony_ci 251462306a36Sopenharmony_ci if (!test_bit(ATH_STAT_STARTED, ah->status)) 251562306a36Sopenharmony_ci return; 251662306a36Sopenharmony_ci 251762306a36Sopenharmony_ci mutex_lock(&ah->lock); 251862306a36Sopenharmony_ci 251962306a36Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(ah->txqs); i++) { 252062306a36Sopenharmony_ci if (ah->txqs[i].setup) { 252162306a36Sopenharmony_ci txq = &ah->txqs[i]; 252262306a36Sopenharmony_ci spin_lock_bh(&txq->lock); 252362306a36Sopenharmony_ci if (txq->txq_len > 1) { 252462306a36Sopenharmony_ci if (txq->txq_poll_mark) { 252562306a36Sopenharmony_ci ATH5K_DBG(ah, ATH5K_DEBUG_XMIT, 252662306a36Sopenharmony_ci "TX queue stuck %d\n", 252762306a36Sopenharmony_ci txq->qnum); 252862306a36Sopenharmony_ci needreset = true; 252962306a36Sopenharmony_ci txq->txq_stuck++; 253062306a36Sopenharmony_ci spin_unlock_bh(&txq->lock); 253162306a36Sopenharmony_ci break; 253262306a36Sopenharmony_ci } else { 253362306a36Sopenharmony_ci txq->txq_poll_mark = true; 253462306a36Sopenharmony_ci } 253562306a36Sopenharmony_ci } 253662306a36Sopenharmony_ci spin_unlock_bh(&txq->lock); 253762306a36Sopenharmony_ci } 253862306a36Sopenharmony_ci } 253962306a36Sopenharmony_ci 254062306a36Sopenharmony_ci if (needreset) { 254162306a36Sopenharmony_ci ATH5K_DBG(ah, ATH5K_DEBUG_RESET, 254262306a36Sopenharmony_ci "TX queues stuck, resetting\n"); 254362306a36Sopenharmony_ci ath5k_reset(ah, NULL, true); 254462306a36Sopenharmony_ci } 254562306a36Sopenharmony_ci 254662306a36Sopenharmony_ci mutex_unlock(&ah->lock); 254762306a36Sopenharmony_ci 254862306a36Sopenharmony_ci ieee80211_queue_delayed_work(ah->hw, &ah->tx_complete_work, 254962306a36Sopenharmony_ci msecs_to_jiffies(ATH5K_TX_COMPLETE_POLL_INT)); 255062306a36Sopenharmony_ci} 255162306a36Sopenharmony_ci 255262306a36Sopenharmony_ci 255362306a36Sopenharmony_ci/*************************\ 255462306a36Sopenharmony_ci* Initialization routines * 255562306a36Sopenharmony_ci\*************************/ 255662306a36Sopenharmony_ci 255762306a36Sopenharmony_cistatic const struct ieee80211_iface_limit if_limits[] = { 255862306a36Sopenharmony_ci { .max = 2048, .types = BIT(NL80211_IFTYPE_STATION) }, 255962306a36Sopenharmony_ci { .max = 4, .types = 256062306a36Sopenharmony_ci#ifdef CONFIG_MAC80211_MESH 256162306a36Sopenharmony_ci BIT(NL80211_IFTYPE_MESH_POINT) | 256262306a36Sopenharmony_ci#endif 256362306a36Sopenharmony_ci BIT(NL80211_IFTYPE_AP) }, 256462306a36Sopenharmony_ci}; 256562306a36Sopenharmony_ci 256662306a36Sopenharmony_cistatic const struct ieee80211_iface_combination if_comb = { 256762306a36Sopenharmony_ci .limits = if_limits, 256862306a36Sopenharmony_ci .n_limits = ARRAY_SIZE(if_limits), 256962306a36Sopenharmony_ci .max_interfaces = 2048, 257062306a36Sopenharmony_ci .num_different_channels = 1, 257162306a36Sopenharmony_ci}; 257262306a36Sopenharmony_ci 257362306a36Sopenharmony_ciint 257462306a36Sopenharmony_ciath5k_init_ah(struct ath5k_hw *ah, const struct ath_bus_ops *bus_ops) 257562306a36Sopenharmony_ci{ 257662306a36Sopenharmony_ci struct ieee80211_hw *hw = ah->hw; 257762306a36Sopenharmony_ci struct ath_common *common; 257862306a36Sopenharmony_ci int ret; 257962306a36Sopenharmony_ci int csz; 258062306a36Sopenharmony_ci 258162306a36Sopenharmony_ci /* Initialize driver private data */ 258262306a36Sopenharmony_ci SET_IEEE80211_DEV(hw, ah->dev); 258362306a36Sopenharmony_ci ieee80211_hw_set(hw, SUPPORTS_RC_TABLE); 258462306a36Sopenharmony_ci ieee80211_hw_set(hw, REPORTS_TX_ACK_STATUS); 258562306a36Sopenharmony_ci ieee80211_hw_set(hw, MFP_CAPABLE); 258662306a36Sopenharmony_ci ieee80211_hw_set(hw, SIGNAL_DBM); 258762306a36Sopenharmony_ci ieee80211_hw_set(hw, RX_INCLUDES_FCS); 258862306a36Sopenharmony_ci ieee80211_hw_set(hw, HOST_BROADCAST_PS_BUFFERING); 258962306a36Sopenharmony_ci 259062306a36Sopenharmony_ci hw->wiphy->interface_modes = 259162306a36Sopenharmony_ci BIT(NL80211_IFTYPE_AP) | 259262306a36Sopenharmony_ci BIT(NL80211_IFTYPE_STATION) | 259362306a36Sopenharmony_ci BIT(NL80211_IFTYPE_ADHOC) | 259462306a36Sopenharmony_ci BIT(NL80211_IFTYPE_MESH_POINT); 259562306a36Sopenharmony_ci 259662306a36Sopenharmony_ci hw->wiphy->iface_combinations = &if_comb; 259762306a36Sopenharmony_ci hw->wiphy->n_iface_combinations = 1; 259862306a36Sopenharmony_ci 259962306a36Sopenharmony_ci /* SW support for IBSS_RSN is provided by mac80211 */ 260062306a36Sopenharmony_ci hw->wiphy->flags |= WIPHY_FLAG_IBSS_RSN; 260162306a36Sopenharmony_ci 260262306a36Sopenharmony_ci hw->wiphy->flags |= WIPHY_FLAG_SUPPORTS_5_10_MHZ; 260362306a36Sopenharmony_ci 260462306a36Sopenharmony_ci /* both antennas can be configured as RX or TX */ 260562306a36Sopenharmony_ci hw->wiphy->available_antennas_tx = 0x3; 260662306a36Sopenharmony_ci hw->wiphy->available_antennas_rx = 0x3; 260762306a36Sopenharmony_ci 260862306a36Sopenharmony_ci hw->extra_tx_headroom = 2; 260962306a36Sopenharmony_ci 261062306a36Sopenharmony_ci wiphy_ext_feature_set(hw->wiphy, NL80211_EXT_FEATURE_CQM_RSSI_LIST); 261162306a36Sopenharmony_ci 261262306a36Sopenharmony_ci /* 261362306a36Sopenharmony_ci * Mark the device as detached to avoid processing 261462306a36Sopenharmony_ci * interrupts until setup is complete. 261562306a36Sopenharmony_ci */ 261662306a36Sopenharmony_ci __set_bit(ATH_STAT_INVALID, ah->status); 261762306a36Sopenharmony_ci 261862306a36Sopenharmony_ci ah->opmode = NL80211_IFTYPE_STATION; 261962306a36Sopenharmony_ci ah->bintval = 1000; 262062306a36Sopenharmony_ci mutex_init(&ah->lock); 262162306a36Sopenharmony_ci spin_lock_init(&ah->rxbuflock); 262262306a36Sopenharmony_ci spin_lock_init(&ah->txbuflock); 262362306a36Sopenharmony_ci spin_lock_init(&ah->block); 262462306a36Sopenharmony_ci spin_lock_init(&ah->irqlock); 262562306a36Sopenharmony_ci 262662306a36Sopenharmony_ci /* Setup interrupt handler */ 262762306a36Sopenharmony_ci ret = request_irq(ah->irq, ath5k_intr, IRQF_SHARED, "ath", ah); 262862306a36Sopenharmony_ci if (ret) { 262962306a36Sopenharmony_ci ATH5K_ERR(ah, "request_irq failed\n"); 263062306a36Sopenharmony_ci goto err; 263162306a36Sopenharmony_ci } 263262306a36Sopenharmony_ci 263362306a36Sopenharmony_ci common = ath5k_hw_common(ah); 263462306a36Sopenharmony_ci common->ops = &ath5k_common_ops; 263562306a36Sopenharmony_ci common->bus_ops = bus_ops; 263662306a36Sopenharmony_ci common->ah = ah; 263762306a36Sopenharmony_ci common->hw = hw; 263862306a36Sopenharmony_ci common->priv = ah; 263962306a36Sopenharmony_ci common->clockrate = 40; 264062306a36Sopenharmony_ci 264162306a36Sopenharmony_ci /* 264262306a36Sopenharmony_ci * Cache line size is used to size and align various 264362306a36Sopenharmony_ci * structures used to communicate with the hardware. 264462306a36Sopenharmony_ci */ 264562306a36Sopenharmony_ci ath5k_read_cachesize(common, &csz); 264662306a36Sopenharmony_ci common->cachelsz = csz << 2; /* convert to bytes */ 264762306a36Sopenharmony_ci 264862306a36Sopenharmony_ci spin_lock_init(&common->cc_lock); 264962306a36Sopenharmony_ci 265062306a36Sopenharmony_ci /* Initialize device */ 265162306a36Sopenharmony_ci ret = ath5k_hw_init(ah); 265262306a36Sopenharmony_ci if (ret) 265362306a36Sopenharmony_ci goto err_irq; 265462306a36Sopenharmony_ci 265562306a36Sopenharmony_ci /* Set up multi-rate retry capabilities */ 265662306a36Sopenharmony_ci if (ah->ah_capabilities.cap_has_mrr_support) { 265762306a36Sopenharmony_ci hw->max_rates = 4; 265862306a36Sopenharmony_ci hw->max_rate_tries = max(AR5K_INIT_RETRY_SHORT, 265962306a36Sopenharmony_ci AR5K_INIT_RETRY_LONG); 266062306a36Sopenharmony_ci } 266162306a36Sopenharmony_ci 266262306a36Sopenharmony_ci hw->vif_data_size = sizeof(struct ath5k_vif); 266362306a36Sopenharmony_ci 266462306a36Sopenharmony_ci /* Finish private driver data initialization */ 266562306a36Sopenharmony_ci ret = ath5k_init(hw); 266662306a36Sopenharmony_ci if (ret) 266762306a36Sopenharmony_ci goto err_ah; 266862306a36Sopenharmony_ci 266962306a36Sopenharmony_ci ATH5K_INFO(ah, "Atheros AR%s chip found (MAC: 0x%x, PHY: 0x%x)\n", 267062306a36Sopenharmony_ci ath5k_chip_name(AR5K_VERSION_MAC, ah->ah_mac_srev), 267162306a36Sopenharmony_ci ah->ah_mac_srev, 267262306a36Sopenharmony_ci ah->ah_phy_revision); 267362306a36Sopenharmony_ci 267462306a36Sopenharmony_ci if (!ah->ah_single_chip) { 267562306a36Sopenharmony_ci /* Single chip radio (!RF5111) */ 267662306a36Sopenharmony_ci if (ah->ah_radio_5ghz_revision && 267762306a36Sopenharmony_ci !ah->ah_radio_2ghz_revision) { 267862306a36Sopenharmony_ci /* No 5GHz support -> report 2GHz radio */ 267962306a36Sopenharmony_ci if (!test_bit(AR5K_MODE_11A, 268062306a36Sopenharmony_ci ah->ah_capabilities.cap_mode)) { 268162306a36Sopenharmony_ci ATH5K_INFO(ah, "RF%s 2GHz radio found (0x%x)\n", 268262306a36Sopenharmony_ci ath5k_chip_name(AR5K_VERSION_RAD, 268362306a36Sopenharmony_ci ah->ah_radio_5ghz_revision), 268462306a36Sopenharmony_ci ah->ah_radio_5ghz_revision); 268562306a36Sopenharmony_ci /* No 2GHz support (5110 and some 268662306a36Sopenharmony_ci * 5GHz only cards) -> report 5GHz radio */ 268762306a36Sopenharmony_ci } else if (!test_bit(AR5K_MODE_11B, 268862306a36Sopenharmony_ci ah->ah_capabilities.cap_mode)) { 268962306a36Sopenharmony_ci ATH5K_INFO(ah, "RF%s 5GHz radio found (0x%x)\n", 269062306a36Sopenharmony_ci ath5k_chip_name(AR5K_VERSION_RAD, 269162306a36Sopenharmony_ci ah->ah_radio_5ghz_revision), 269262306a36Sopenharmony_ci ah->ah_radio_5ghz_revision); 269362306a36Sopenharmony_ci /* Multiband radio */ 269462306a36Sopenharmony_ci } else { 269562306a36Sopenharmony_ci ATH5K_INFO(ah, "RF%s multiband radio found" 269662306a36Sopenharmony_ci " (0x%x)\n", 269762306a36Sopenharmony_ci ath5k_chip_name(AR5K_VERSION_RAD, 269862306a36Sopenharmony_ci ah->ah_radio_5ghz_revision), 269962306a36Sopenharmony_ci ah->ah_radio_5ghz_revision); 270062306a36Sopenharmony_ci } 270162306a36Sopenharmony_ci } 270262306a36Sopenharmony_ci /* Multi chip radio (RF5111 - RF2111) -> 270362306a36Sopenharmony_ci * report both 2GHz/5GHz radios */ 270462306a36Sopenharmony_ci else if (ah->ah_radio_5ghz_revision && 270562306a36Sopenharmony_ci ah->ah_radio_2ghz_revision) { 270662306a36Sopenharmony_ci ATH5K_INFO(ah, "RF%s 5GHz radio found (0x%x)\n", 270762306a36Sopenharmony_ci ath5k_chip_name(AR5K_VERSION_RAD, 270862306a36Sopenharmony_ci ah->ah_radio_5ghz_revision), 270962306a36Sopenharmony_ci ah->ah_radio_5ghz_revision); 271062306a36Sopenharmony_ci ATH5K_INFO(ah, "RF%s 2GHz radio found (0x%x)\n", 271162306a36Sopenharmony_ci ath5k_chip_name(AR5K_VERSION_RAD, 271262306a36Sopenharmony_ci ah->ah_radio_2ghz_revision), 271362306a36Sopenharmony_ci ah->ah_radio_2ghz_revision); 271462306a36Sopenharmony_ci } 271562306a36Sopenharmony_ci } 271662306a36Sopenharmony_ci 271762306a36Sopenharmony_ci ath5k_debug_init_device(ah); 271862306a36Sopenharmony_ci 271962306a36Sopenharmony_ci /* ready to process interrupts */ 272062306a36Sopenharmony_ci __clear_bit(ATH_STAT_INVALID, ah->status); 272162306a36Sopenharmony_ci 272262306a36Sopenharmony_ci return 0; 272362306a36Sopenharmony_cierr_ah: 272462306a36Sopenharmony_ci ath5k_hw_deinit(ah); 272562306a36Sopenharmony_cierr_irq: 272662306a36Sopenharmony_ci free_irq(ah->irq, ah); 272762306a36Sopenharmony_cierr: 272862306a36Sopenharmony_ci return ret; 272962306a36Sopenharmony_ci} 273062306a36Sopenharmony_ci 273162306a36Sopenharmony_cistatic int 273262306a36Sopenharmony_ciath5k_stop_locked(struct ath5k_hw *ah) 273362306a36Sopenharmony_ci{ 273462306a36Sopenharmony_ci 273562306a36Sopenharmony_ci ATH5K_DBG(ah, ATH5K_DEBUG_RESET, "invalid %u\n", 273662306a36Sopenharmony_ci test_bit(ATH_STAT_INVALID, ah->status)); 273762306a36Sopenharmony_ci 273862306a36Sopenharmony_ci /* 273962306a36Sopenharmony_ci * Shutdown the hardware and driver: 274062306a36Sopenharmony_ci * stop output from above 274162306a36Sopenharmony_ci * disable interrupts 274262306a36Sopenharmony_ci * turn off timers 274362306a36Sopenharmony_ci * turn off the radio 274462306a36Sopenharmony_ci * clear transmit machinery 274562306a36Sopenharmony_ci * clear receive machinery 274662306a36Sopenharmony_ci * drain and release tx queues 274762306a36Sopenharmony_ci * reclaim beacon resources 274862306a36Sopenharmony_ci * power down hardware 274962306a36Sopenharmony_ci * 275062306a36Sopenharmony_ci * Note that some of this work is not possible if the 275162306a36Sopenharmony_ci * hardware is gone (invalid). 275262306a36Sopenharmony_ci */ 275362306a36Sopenharmony_ci ieee80211_stop_queues(ah->hw); 275462306a36Sopenharmony_ci 275562306a36Sopenharmony_ci if (!test_bit(ATH_STAT_INVALID, ah->status)) { 275662306a36Sopenharmony_ci ath5k_led_off(ah); 275762306a36Sopenharmony_ci ath5k_hw_set_imr(ah, 0); 275862306a36Sopenharmony_ci synchronize_irq(ah->irq); 275962306a36Sopenharmony_ci ath5k_rx_stop(ah); 276062306a36Sopenharmony_ci ath5k_hw_dma_stop(ah); 276162306a36Sopenharmony_ci ath5k_drain_tx_buffs(ah); 276262306a36Sopenharmony_ci ath5k_hw_phy_disable(ah); 276362306a36Sopenharmony_ci } 276462306a36Sopenharmony_ci 276562306a36Sopenharmony_ci return 0; 276662306a36Sopenharmony_ci} 276762306a36Sopenharmony_ci 276862306a36Sopenharmony_ciint ath5k_start(struct ieee80211_hw *hw) 276962306a36Sopenharmony_ci{ 277062306a36Sopenharmony_ci struct ath5k_hw *ah = hw->priv; 277162306a36Sopenharmony_ci struct ath_common *common = ath5k_hw_common(ah); 277262306a36Sopenharmony_ci int ret, i; 277362306a36Sopenharmony_ci 277462306a36Sopenharmony_ci mutex_lock(&ah->lock); 277562306a36Sopenharmony_ci 277662306a36Sopenharmony_ci ATH5K_DBG(ah, ATH5K_DEBUG_RESET, "mode %d\n", ah->opmode); 277762306a36Sopenharmony_ci 277862306a36Sopenharmony_ci /* 277962306a36Sopenharmony_ci * Stop anything previously setup. This is safe 278062306a36Sopenharmony_ci * no matter this is the first time through or not. 278162306a36Sopenharmony_ci */ 278262306a36Sopenharmony_ci ath5k_stop_locked(ah); 278362306a36Sopenharmony_ci 278462306a36Sopenharmony_ci /* 278562306a36Sopenharmony_ci * The basic interface to setting the hardware in a good 278662306a36Sopenharmony_ci * state is ``reset''. On return the hardware is known to 278762306a36Sopenharmony_ci * be powered up and with interrupts disabled. This must 278862306a36Sopenharmony_ci * be followed by initialization of the appropriate bits 278962306a36Sopenharmony_ci * and then setup of the interrupt mask. 279062306a36Sopenharmony_ci */ 279162306a36Sopenharmony_ci ah->curchan = ah->hw->conf.chandef.chan; 279262306a36Sopenharmony_ci ah->imask = AR5K_INT_RXOK 279362306a36Sopenharmony_ci | AR5K_INT_RXERR 279462306a36Sopenharmony_ci | AR5K_INT_RXEOL 279562306a36Sopenharmony_ci | AR5K_INT_RXORN 279662306a36Sopenharmony_ci | AR5K_INT_TXDESC 279762306a36Sopenharmony_ci | AR5K_INT_TXEOL 279862306a36Sopenharmony_ci | AR5K_INT_FATAL 279962306a36Sopenharmony_ci | AR5K_INT_GLOBAL 280062306a36Sopenharmony_ci | AR5K_INT_MIB; 280162306a36Sopenharmony_ci 280262306a36Sopenharmony_ci ret = ath5k_reset(ah, NULL, false); 280362306a36Sopenharmony_ci if (ret) 280462306a36Sopenharmony_ci goto done; 280562306a36Sopenharmony_ci 280662306a36Sopenharmony_ci if (!ath5k_modparam_no_hw_rfkill_switch) 280762306a36Sopenharmony_ci ath5k_rfkill_hw_start(ah); 280862306a36Sopenharmony_ci 280962306a36Sopenharmony_ci /* 281062306a36Sopenharmony_ci * Reset the key cache since some parts do not reset the 281162306a36Sopenharmony_ci * contents on initial power up or resume from suspend. 281262306a36Sopenharmony_ci */ 281362306a36Sopenharmony_ci for (i = 0; i < common->keymax; i++) 281462306a36Sopenharmony_ci ath_hw_keyreset(common, (u16) i); 281562306a36Sopenharmony_ci 281662306a36Sopenharmony_ci /* Use higher rates for acks instead of base 281762306a36Sopenharmony_ci * rate */ 281862306a36Sopenharmony_ci ah->ah_ack_bitrate_high = true; 281962306a36Sopenharmony_ci 282062306a36Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(ah->bslot); i++) 282162306a36Sopenharmony_ci ah->bslot[i] = NULL; 282262306a36Sopenharmony_ci 282362306a36Sopenharmony_ci ret = 0; 282462306a36Sopenharmony_cidone: 282562306a36Sopenharmony_ci mutex_unlock(&ah->lock); 282662306a36Sopenharmony_ci 282762306a36Sopenharmony_ci set_bit(ATH_STAT_STARTED, ah->status); 282862306a36Sopenharmony_ci ieee80211_queue_delayed_work(ah->hw, &ah->tx_complete_work, 282962306a36Sopenharmony_ci msecs_to_jiffies(ATH5K_TX_COMPLETE_POLL_INT)); 283062306a36Sopenharmony_ci 283162306a36Sopenharmony_ci return ret; 283262306a36Sopenharmony_ci} 283362306a36Sopenharmony_ci 283462306a36Sopenharmony_cistatic void ath5k_stop_tasklets(struct ath5k_hw *ah) 283562306a36Sopenharmony_ci{ 283662306a36Sopenharmony_ci ah->rx_pending = false; 283762306a36Sopenharmony_ci ah->tx_pending = false; 283862306a36Sopenharmony_ci tasklet_kill(&ah->rxtq); 283962306a36Sopenharmony_ci tasklet_kill(&ah->txtq); 284062306a36Sopenharmony_ci tasklet_kill(&ah->beacontq); 284162306a36Sopenharmony_ci tasklet_kill(&ah->ani_tasklet); 284262306a36Sopenharmony_ci} 284362306a36Sopenharmony_ci 284462306a36Sopenharmony_ci/* 284562306a36Sopenharmony_ci * Stop the device, grabbing the top-level lock to protect 284662306a36Sopenharmony_ci * against concurrent entry through ath5k_init (which can happen 284762306a36Sopenharmony_ci * if another thread does a system call and the thread doing the 284862306a36Sopenharmony_ci * stop is preempted). 284962306a36Sopenharmony_ci */ 285062306a36Sopenharmony_civoid ath5k_stop(struct ieee80211_hw *hw) 285162306a36Sopenharmony_ci{ 285262306a36Sopenharmony_ci struct ath5k_hw *ah = hw->priv; 285362306a36Sopenharmony_ci int ret; 285462306a36Sopenharmony_ci 285562306a36Sopenharmony_ci mutex_lock(&ah->lock); 285662306a36Sopenharmony_ci ret = ath5k_stop_locked(ah); 285762306a36Sopenharmony_ci if (ret == 0 && !test_bit(ATH_STAT_INVALID, ah->status)) { 285862306a36Sopenharmony_ci /* 285962306a36Sopenharmony_ci * Don't set the card in full sleep mode! 286062306a36Sopenharmony_ci * 286162306a36Sopenharmony_ci * a) When the device is in this state it must be carefully 286262306a36Sopenharmony_ci * woken up or references to registers in the PCI clock 286362306a36Sopenharmony_ci * domain may freeze the bus (and system). This varies 286462306a36Sopenharmony_ci * by chip and is mostly an issue with newer parts 286562306a36Sopenharmony_ci * (madwifi sources mentioned srev >= 0x78) that go to 286662306a36Sopenharmony_ci * sleep more quickly. 286762306a36Sopenharmony_ci * 286862306a36Sopenharmony_ci * b) On older chips full sleep results a weird behaviour 286962306a36Sopenharmony_ci * during wakeup. I tested various cards with srev < 0x78 287062306a36Sopenharmony_ci * and they don't wake up after module reload, a second 287162306a36Sopenharmony_ci * module reload is needed to bring the card up again. 287262306a36Sopenharmony_ci * 287362306a36Sopenharmony_ci * Until we figure out what's going on don't enable 287462306a36Sopenharmony_ci * full chip reset on any chip (this is what Legacy HAL 287562306a36Sopenharmony_ci * and Sam's HAL do anyway). Instead Perform a full reset 287662306a36Sopenharmony_ci * on the device (same as initial state after attach) and 287762306a36Sopenharmony_ci * leave it idle (keep MAC/BB on warm reset) */ 287862306a36Sopenharmony_ci ret = ath5k_hw_on_hold(ah); 287962306a36Sopenharmony_ci 288062306a36Sopenharmony_ci ATH5K_DBG(ah, ATH5K_DEBUG_RESET, 288162306a36Sopenharmony_ci "putting device to sleep\n"); 288262306a36Sopenharmony_ci } 288362306a36Sopenharmony_ci 288462306a36Sopenharmony_ci mutex_unlock(&ah->lock); 288562306a36Sopenharmony_ci 288662306a36Sopenharmony_ci ath5k_stop_tasklets(ah); 288762306a36Sopenharmony_ci 288862306a36Sopenharmony_ci clear_bit(ATH_STAT_STARTED, ah->status); 288962306a36Sopenharmony_ci cancel_delayed_work_sync(&ah->tx_complete_work); 289062306a36Sopenharmony_ci 289162306a36Sopenharmony_ci if (!ath5k_modparam_no_hw_rfkill_switch) 289262306a36Sopenharmony_ci ath5k_rfkill_hw_stop(ah); 289362306a36Sopenharmony_ci} 289462306a36Sopenharmony_ci 289562306a36Sopenharmony_ci/* 289662306a36Sopenharmony_ci * Reset the hardware. If chan is not NULL, then also pause rx/tx 289762306a36Sopenharmony_ci * and change to the given channel. 289862306a36Sopenharmony_ci * 289962306a36Sopenharmony_ci * This should be called with ah->lock. 290062306a36Sopenharmony_ci */ 290162306a36Sopenharmony_cistatic int 290262306a36Sopenharmony_ciath5k_reset(struct ath5k_hw *ah, struct ieee80211_channel *chan, 290362306a36Sopenharmony_ci bool skip_pcu) 290462306a36Sopenharmony_ci{ 290562306a36Sopenharmony_ci struct ath_common *common = ath5k_hw_common(ah); 290662306a36Sopenharmony_ci int ret, ani_mode; 290762306a36Sopenharmony_ci bool fast = chan && modparam_fastchanswitch ? 1 : 0; 290862306a36Sopenharmony_ci 290962306a36Sopenharmony_ci ATH5K_DBG(ah, ATH5K_DEBUG_RESET, "resetting\n"); 291062306a36Sopenharmony_ci 291162306a36Sopenharmony_ci __set_bit(ATH_STAT_RESET, ah->status); 291262306a36Sopenharmony_ci 291362306a36Sopenharmony_ci ath5k_hw_set_imr(ah, 0); 291462306a36Sopenharmony_ci synchronize_irq(ah->irq); 291562306a36Sopenharmony_ci ath5k_stop_tasklets(ah); 291662306a36Sopenharmony_ci 291762306a36Sopenharmony_ci /* Save ani mode and disable ANI during 291862306a36Sopenharmony_ci * reset. If we don't we might get false 291962306a36Sopenharmony_ci * PHY error interrupts. */ 292062306a36Sopenharmony_ci ani_mode = ah->ani_state.ani_mode; 292162306a36Sopenharmony_ci ath5k_ani_init(ah, ATH5K_ANI_MODE_OFF); 292262306a36Sopenharmony_ci 292362306a36Sopenharmony_ci /* We are going to empty hw queues 292462306a36Sopenharmony_ci * so we should also free any remaining 292562306a36Sopenharmony_ci * tx buffers */ 292662306a36Sopenharmony_ci ath5k_drain_tx_buffs(ah); 292762306a36Sopenharmony_ci 292862306a36Sopenharmony_ci /* Stop PCU */ 292962306a36Sopenharmony_ci ath5k_hw_stop_rx_pcu(ah); 293062306a36Sopenharmony_ci 293162306a36Sopenharmony_ci /* Stop DMA 293262306a36Sopenharmony_ci * 293362306a36Sopenharmony_ci * Note: If DMA didn't stop continue 293462306a36Sopenharmony_ci * since only a reset will fix it. 293562306a36Sopenharmony_ci */ 293662306a36Sopenharmony_ci ret = ath5k_hw_dma_stop(ah); 293762306a36Sopenharmony_ci 293862306a36Sopenharmony_ci /* RF Bus grant won't work if we have pending 293962306a36Sopenharmony_ci * frames 294062306a36Sopenharmony_ci */ 294162306a36Sopenharmony_ci if (ret && fast) { 294262306a36Sopenharmony_ci ATH5K_DBG(ah, ATH5K_DEBUG_RESET, 294362306a36Sopenharmony_ci "DMA didn't stop, falling back to normal reset\n"); 294462306a36Sopenharmony_ci fast = false; 294562306a36Sopenharmony_ci } 294662306a36Sopenharmony_ci 294762306a36Sopenharmony_ci if (chan) 294862306a36Sopenharmony_ci ah->curchan = chan; 294962306a36Sopenharmony_ci 295062306a36Sopenharmony_ci ret = ath5k_hw_reset(ah, ah->opmode, ah->curchan, fast, skip_pcu); 295162306a36Sopenharmony_ci if (ret) { 295262306a36Sopenharmony_ci ATH5K_ERR(ah, "can't reset hardware (%d)\n", ret); 295362306a36Sopenharmony_ci goto err; 295462306a36Sopenharmony_ci } 295562306a36Sopenharmony_ci 295662306a36Sopenharmony_ci ret = ath5k_rx_start(ah); 295762306a36Sopenharmony_ci if (ret) { 295862306a36Sopenharmony_ci ATH5K_ERR(ah, "can't start recv logic\n"); 295962306a36Sopenharmony_ci goto err; 296062306a36Sopenharmony_ci } 296162306a36Sopenharmony_ci 296262306a36Sopenharmony_ci ath5k_ani_init(ah, ani_mode); 296362306a36Sopenharmony_ci 296462306a36Sopenharmony_ci /* 296562306a36Sopenharmony_ci * Set calibration intervals 296662306a36Sopenharmony_ci * 296762306a36Sopenharmony_ci * Note: We don't need to run calibration imediately 296862306a36Sopenharmony_ci * since some initial calibration is done on reset 296962306a36Sopenharmony_ci * even for fast channel switching. Also on scanning 297062306a36Sopenharmony_ci * this will get set again and again and it won't get 297162306a36Sopenharmony_ci * executed unless we connect somewhere and spend some 297262306a36Sopenharmony_ci * time on the channel (that's what calibration needs 297362306a36Sopenharmony_ci * anyway to be accurate). 297462306a36Sopenharmony_ci */ 297562306a36Sopenharmony_ci ah->ah_cal_next_full = jiffies + 297662306a36Sopenharmony_ci msecs_to_jiffies(ATH5K_TUNE_CALIBRATION_INTERVAL_FULL); 297762306a36Sopenharmony_ci ah->ah_cal_next_ani = jiffies + 297862306a36Sopenharmony_ci msecs_to_jiffies(ATH5K_TUNE_CALIBRATION_INTERVAL_ANI); 297962306a36Sopenharmony_ci ah->ah_cal_next_short = jiffies + 298062306a36Sopenharmony_ci msecs_to_jiffies(ATH5K_TUNE_CALIBRATION_INTERVAL_SHORT); 298162306a36Sopenharmony_ci 298262306a36Sopenharmony_ci ewma_beacon_rssi_init(&ah->ah_beacon_rssi_avg); 298362306a36Sopenharmony_ci 298462306a36Sopenharmony_ci /* clear survey data and cycle counters */ 298562306a36Sopenharmony_ci memset(&ah->survey, 0, sizeof(ah->survey)); 298662306a36Sopenharmony_ci spin_lock_bh(&common->cc_lock); 298762306a36Sopenharmony_ci ath_hw_cycle_counters_update(common); 298862306a36Sopenharmony_ci memset(&common->cc_survey, 0, sizeof(common->cc_survey)); 298962306a36Sopenharmony_ci memset(&common->cc_ani, 0, sizeof(common->cc_ani)); 299062306a36Sopenharmony_ci spin_unlock_bh(&common->cc_lock); 299162306a36Sopenharmony_ci 299262306a36Sopenharmony_ci /* 299362306a36Sopenharmony_ci * Change channels and update the h/w rate map if we're switching; 299462306a36Sopenharmony_ci * e.g. 11a to 11b/g. 299562306a36Sopenharmony_ci * 299662306a36Sopenharmony_ci * We may be doing a reset in response to an ioctl that changes the 299762306a36Sopenharmony_ci * channel so update any state that might change as a result. 299862306a36Sopenharmony_ci * 299962306a36Sopenharmony_ci * XXX needed? 300062306a36Sopenharmony_ci */ 300162306a36Sopenharmony_ci/* ath5k_chan_change(ah, c); */ 300262306a36Sopenharmony_ci 300362306a36Sopenharmony_ci __clear_bit(ATH_STAT_RESET, ah->status); 300462306a36Sopenharmony_ci 300562306a36Sopenharmony_ci ath5k_beacon_config(ah); 300662306a36Sopenharmony_ci /* intrs are enabled by ath5k_beacon_config */ 300762306a36Sopenharmony_ci 300862306a36Sopenharmony_ci ieee80211_wake_queues(ah->hw); 300962306a36Sopenharmony_ci 301062306a36Sopenharmony_ci return 0; 301162306a36Sopenharmony_cierr: 301262306a36Sopenharmony_ci return ret; 301362306a36Sopenharmony_ci} 301462306a36Sopenharmony_ci 301562306a36Sopenharmony_cistatic void ath5k_reset_work(struct work_struct *work) 301662306a36Sopenharmony_ci{ 301762306a36Sopenharmony_ci struct ath5k_hw *ah = container_of(work, struct ath5k_hw, 301862306a36Sopenharmony_ci reset_work); 301962306a36Sopenharmony_ci 302062306a36Sopenharmony_ci mutex_lock(&ah->lock); 302162306a36Sopenharmony_ci ath5k_reset(ah, NULL, true); 302262306a36Sopenharmony_ci mutex_unlock(&ah->lock); 302362306a36Sopenharmony_ci} 302462306a36Sopenharmony_ci 302562306a36Sopenharmony_cistatic int 302662306a36Sopenharmony_ciath5k_init(struct ieee80211_hw *hw) 302762306a36Sopenharmony_ci{ 302862306a36Sopenharmony_ci 302962306a36Sopenharmony_ci struct ath5k_hw *ah = hw->priv; 303062306a36Sopenharmony_ci struct ath_regulatory *regulatory = ath5k_hw_regulatory(ah); 303162306a36Sopenharmony_ci struct ath5k_txq *txq; 303262306a36Sopenharmony_ci u8 mac[ETH_ALEN] = {}; 303362306a36Sopenharmony_ci int ret; 303462306a36Sopenharmony_ci 303562306a36Sopenharmony_ci 303662306a36Sopenharmony_ci /* 303762306a36Sopenharmony_ci * Collect the channel list. The 802.11 layer 303862306a36Sopenharmony_ci * is responsible for filtering this list based 303962306a36Sopenharmony_ci * on settings like the phy mode and regulatory 304062306a36Sopenharmony_ci * domain restrictions. 304162306a36Sopenharmony_ci */ 304262306a36Sopenharmony_ci ret = ath5k_setup_bands(hw); 304362306a36Sopenharmony_ci if (ret) { 304462306a36Sopenharmony_ci ATH5K_ERR(ah, "can't get channels\n"); 304562306a36Sopenharmony_ci goto err; 304662306a36Sopenharmony_ci } 304762306a36Sopenharmony_ci 304862306a36Sopenharmony_ci /* 304962306a36Sopenharmony_ci * Allocate tx+rx descriptors and populate the lists. 305062306a36Sopenharmony_ci */ 305162306a36Sopenharmony_ci ret = ath5k_desc_alloc(ah); 305262306a36Sopenharmony_ci if (ret) { 305362306a36Sopenharmony_ci ATH5K_ERR(ah, "can't allocate descriptors\n"); 305462306a36Sopenharmony_ci goto err; 305562306a36Sopenharmony_ci } 305662306a36Sopenharmony_ci 305762306a36Sopenharmony_ci /* 305862306a36Sopenharmony_ci * Allocate hardware transmit queues: one queue for 305962306a36Sopenharmony_ci * beacon frames and one data queue for each QoS 306062306a36Sopenharmony_ci * priority. Note that hw functions handle resetting 306162306a36Sopenharmony_ci * these queues at the needed time. 306262306a36Sopenharmony_ci */ 306362306a36Sopenharmony_ci ret = ath5k_beaconq_setup(ah); 306462306a36Sopenharmony_ci if (ret < 0) { 306562306a36Sopenharmony_ci ATH5K_ERR(ah, "can't setup a beacon xmit queue\n"); 306662306a36Sopenharmony_ci goto err_desc; 306762306a36Sopenharmony_ci } 306862306a36Sopenharmony_ci ah->bhalq = ret; 306962306a36Sopenharmony_ci ah->cabq = ath5k_txq_setup(ah, AR5K_TX_QUEUE_CAB, 0); 307062306a36Sopenharmony_ci if (IS_ERR(ah->cabq)) { 307162306a36Sopenharmony_ci ATH5K_ERR(ah, "can't setup cab queue\n"); 307262306a36Sopenharmony_ci ret = PTR_ERR(ah->cabq); 307362306a36Sopenharmony_ci goto err_bhal; 307462306a36Sopenharmony_ci } 307562306a36Sopenharmony_ci 307662306a36Sopenharmony_ci /* 5211 and 5212 usually support 10 queues but we better rely on the 307762306a36Sopenharmony_ci * capability information */ 307862306a36Sopenharmony_ci if (ah->ah_capabilities.cap_queues.q_tx_num >= 6) { 307962306a36Sopenharmony_ci /* This order matches mac80211's queue priority, so we can 308062306a36Sopenharmony_ci * directly use the mac80211 queue number without any mapping */ 308162306a36Sopenharmony_ci txq = ath5k_txq_setup(ah, AR5K_TX_QUEUE_DATA, AR5K_WME_AC_VO); 308262306a36Sopenharmony_ci if (IS_ERR(txq)) { 308362306a36Sopenharmony_ci ATH5K_ERR(ah, "can't setup xmit queue\n"); 308462306a36Sopenharmony_ci ret = PTR_ERR(txq); 308562306a36Sopenharmony_ci goto err_queues; 308662306a36Sopenharmony_ci } 308762306a36Sopenharmony_ci txq = ath5k_txq_setup(ah, AR5K_TX_QUEUE_DATA, AR5K_WME_AC_VI); 308862306a36Sopenharmony_ci if (IS_ERR(txq)) { 308962306a36Sopenharmony_ci ATH5K_ERR(ah, "can't setup xmit queue\n"); 309062306a36Sopenharmony_ci ret = PTR_ERR(txq); 309162306a36Sopenharmony_ci goto err_queues; 309262306a36Sopenharmony_ci } 309362306a36Sopenharmony_ci txq = ath5k_txq_setup(ah, AR5K_TX_QUEUE_DATA, AR5K_WME_AC_BE); 309462306a36Sopenharmony_ci if (IS_ERR(txq)) { 309562306a36Sopenharmony_ci ATH5K_ERR(ah, "can't setup xmit queue\n"); 309662306a36Sopenharmony_ci ret = PTR_ERR(txq); 309762306a36Sopenharmony_ci goto err_queues; 309862306a36Sopenharmony_ci } 309962306a36Sopenharmony_ci txq = ath5k_txq_setup(ah, AR5K_TX_QUEUE_DATA, AR5K_WME_AC_BK); 310062306a36Sopenharmony_ci if (IS_ERR(txq)) { 310162306a36Sopenharmony_ci ATH5K_ERR(ah, "can't setup xmit queue\n"); 310262306a36Sopenharmony_ci ret = PTR_ERR(txq); 310362306a36Sopenharmony_ci goto err_queues; 310462306a36Sopenharmony_ci } 310562306a36Sopenharmony_ci hw->queues = 4; 310662306a36Sopenharmony_ci } else { 310762306a36Sopenharmony_ci /* older hardware (5210) can only support one data queue */ 310862306a36Sopenharmony_ci txq = ath5k_txq_setup(ah, AR5K_TX_QUEUE_DATA, AR5K_WME_AC_BE); 310962306a36Sopenharmony_ci if (IS_ERR(txq)) { 311062306a36Sopenharmony_ci ATH5K_ERR(ah, "can't setup xmit queue\n"); 311162306a36Sopenharmony_ci ret = PTR_ERR(txq); 311262306a36Sopenharmony_ci goto err_queues; 311362306a36Sopenharmony_ci } 311462306a36Sopenharmony_ci hw->queues = 1; 311562306a36Sopenharmony_ci } 311662306a36Sopenharmony_ci 311762306a36Sopenharmony_ci tasklet_setup(&ah->rxtq, ath5k_tasklet_rx); 311862306a36Sopenharmony_ci tasklet_setup(&ah->txtq, ath5k_tasklet_tx); 311962306a36Sopenharmony_ci tasklet_setup(&ah->beacontq, ath5k_tasklet_beacon); 312062306a36Sopenharmony_ci tasklet_setup(&ah->ani_tasklet, ath5k_tasklet_ani); 312162306a36Sopenharmony_ci 312262306a36Sopenharmony_ci INIT_WORK(&ah->reset_work, ath5k_reset_work); 312362306a36Sopenharmony_ci INIT_WORK(&ah->calib_work, ath5k_calibrate_work); 312462306a36Sopenharmony_ci INIT_DELAYED_WORK(&ah->tx_complete_work, ath5k_tx_complete_poll_work); 312562306a36Sopenharmony_ci 312662306a36Sopenharmony_ci ret = ath5k_hw_common(ah)->bus_ops->eeprom_read_mac(ah, mac); 312762306a36Sopenharmony_ci if (ret) { 312862306a36Sopenharmony_ci ATH5K_ERR(ah, "unable to read address from EEPROM\n"); 312962306a36Sopenharmony_ci goto err_queues; 313062306a36Sopenharmony_ci } 313162306a36Sopenharmony_ci 313262306a36Sopenharmony_ci SET_IEEE80211_PERM_ADDR(hw, mac); 313362306a36Sopenharmony_ci /* All MAC address bits matter for ACKs */ 313462306a36Sopenharmony_ci ath5k_update_bssid_mask_and_opmode(ah, NULL); 313562306a36Sopenharmony_ci 313662306a36Sopenharmony_ci regulatory->current_rd = ah->ah_capabilities.cap_eeprom.ee_regdomain; 313762306a36Sopenharmony_ci ret = ath_regd_init(regulatory, hw->wiphy, ath5k_reg_notifier); 313862306a36Sopenharmony_ci if (ret) { 313962306a36Sopenharmony_ci ATH5K_ERR(ah, "can't initialize regulatory system\n"); 314062306a36Sopenharmony_ci goto err_queues; 314162306a36Sopenharmony_ci } 314262306a36Sopenharmony_ci 314362306a36Sopenharmony_ci ret = ieee80211_register_hw(hw); 314462306a36Sopenharmony_ci if (ret) { 314562306a36Sopenharmony_ci ATH5K_ERR(ah, "can't register ieee80211 hw\n"); 314662306a36Sopenharmony_ci goto err_queues; 314762306a36Sopenharmony_ci } 314862306a36Sopenharmony_ci 314962306a36Sopenharmony_ci if (!ath_is_world_regd(regulatory)) 315062306a36Sopenharmony_ci regulatory_hint(hw->wiphy, regulatory->alpha2); 315162306a36Sopenharmony_ci 315262306a36Sopenharmony_ci ath5k_init_leds(ah); 315362306a36Sopenharmony_ci 315462306a36Sopenharmony_ci ath5k_sysfs_register(ah); 315562306a36Sopenharmony_ci 315662306a36Sopenharmony_ci return 0; 315762306a36Sopenharmony_cierr_queues: 315862306a36Sopenharmony_ci ath5k_txq_release(ah); 315962306a36Sopenharmony_cierr_bhal: 316062306a36Sopenharmony_ci ath5k_hw_release_tx_queue(ah, ah->bhalq); 316162306a36Sopenharmony_cierr_desc: 316262306a36Sopenharmony_ci ath5k_desc_free(ah); 316362306a36Sopenharmony_cierr: 316462306a36Sopenharmony_ci return ret; 316562306a36Sopenharmony_ci} 316662306a36Sopenharmony_ci 316762306a36Sopenharmony_civoid 316862306a36Sopenharmony_ciath5k_deinit_ah(struct ath5k_hw *ah) 316962306a36Sopenharmony_ci{ 317062306a36Sopenharmony_ci struct ieee80211_hw *hw = ah->hw; 317162306a36Sopenharmony_ci 317262306a36Sopenharmony_ci /* 317362306a36Sopenharmony_ci * NB: the order of these is important: 317462306a36Sopenharmony_ci * o call the 802.11 layer before detaching ath5k_hw to 317562306a36Sopenharmony_ci * ensure callbacks into the driver to delete global 317662306a36Sopenharmony_ci * key cache entries can be handled 317762306a36Sopenharmony_ci * o reclaim the tx queue data structures after calling 317862306a36Sopenharmony_ci * the 802.11 layer as we'll get called back to reclaim 317962306a36Sopenharmony_ci * node state and potentially want to use them 318062306a36Sopenharmony_ci * o to cleanup the tx queues the hal is called, so detach 318162306a36Sopenharmony_ci * it last 318262306a36Sopenharmony_ci * XXX: ??? detach ath5k_hw ??? 318362306a36Sopenharmony_ci * Other than that, it's straightforward... 318462306a36Sopenharmony_ci */ 318562306a36Sopenharmony_ci ieee80211_unregister_hw(hw); 318662306a36Sopenharmony_ci ath5k_desc_free(ah); 318762306a36Sopenharmony_ci ath5k_txq_release(ah); 318862306a36Sopenharmony_ci ath5k_hw_release_tx_queue(ah, ah->bhalq); 318962306a36Sopenharmony_ci ath5k_unregister_leds(ah); 319062306a36Sopenharmony_ci 319162306a36Sopenharmony_ci ath5k_sysfs_unregister(ah); 319262306a36Sopenharmony_ci /* 319362306a36Sopenharmony_ci * NB: can't reclaim these until after ieee80211_ifdetach 319462306a36Sopenharmony_ci * returns because we'll get called back to reclaim node 319562306a36Sopenharmony_ci * state and potentially want to use them. 319662306a36Sopenharmony_ci */ 319762306a36Sopenharmony_ci ath5k_hw_deinit(ah); 319862306a36Sopenharmony_ci free_irq(ah->irq, ah); 319962306a36Sopenharmony_ci} 320062306a36Sopenharmony_ci 320162306a36Sopenharmony_cibool 320262306a36Sopenharmony_ciath5k_any_vif_assoc(struct ath5k_hw *ah) 320362306a36Sopenharmony_ci{ 320462306a36Sopenharmony_ci struct ath5k_vif_iter_data iter_data; 320562306a36Sopenharmony_ci iter_data.hw_macaddr = NULL; 320662306a36Sopenharmony_ci iter_data.any_assoc = false; 320762306a36Sopenharmony_ci iter_data.need_set_hw_addr = false; 320862306a36Sopenharmony_ci iter_data.found_active = true; 320962306a36Sopenharmony_ci 321062306a36Sopenharmony_ci ieee80211_iterate_active_interfaces_atomic( 321162306a36Sopenharmony_ci ah->hw, IEEE80211_IFACE_ITER_RESUME_ALL, 321262306a36Sopenharmony_ci ath5k_vif_iter, &iter_data); 321362306a36Sopenharmony_ci return iter_data.any_assoc; 321462306a36Sopenharmony_ci} 321562306a36Sopenharmony_ci 321662306a36Sopenharmony_civoid 321762306a36Sopenharmony_ciath5k_set_beacon_filter(struct ieee80211_hw *hw, bool enable) 321862306a36Sopenharmony_ci{ 321962306a36Sopenharmony_ci struct ath5k_hw *ah = hw->priv; 322062306a36Sopenharmony_ci u32 rfilt; 322162306a36Sopenharmony_ci rfilt = ath5k_hw_get_rx_filter(ah); 322262306a36Sopenharmony_ci if (enable) 322362306a36Sopenharmony_ci rfilt |= AR5K_RX_FILTER_BEACON; 322462306a36Sopenharmony_ci else 322562306a36Sopenharmony_ci rfilt &= ~AR5K_RX_FILTER_BEACON; 322662306a36Sopenharmony_ci ath5k_hw_set_rx_filter(ah, rfilt); 322762306a36Sopenharmony_ci ah->filter_flags = rfilt; 322862306a36Sopenharmony_ci} 322962306a36Sopenharmony_ci 323062306a36Sopenharmony_civoid _ath5k_printk(const struct ath5k_hw *ah, const char *level, 323162306a36Sopenharmony_ci const char *fmt, ...) 323262306a36Sopenharmony_ci{ 323362306a36Sopenharmony_ci struct va_format vaf; 323462306a36Sopenharmony_ci va_list args; 323562306a36Sopenharmony_ci 323662306a36Sopenharmony_ci va_start(args, fmt); 323762306a36Sopenharmony_ci 323862306a36Sopenharmony_ci vaf.fmt = fmt; 323962306a36Sopenharmony_ci vaf.va = &args; 324062306a36Sopenharmony_ci 324162306a36Sopenharmony_ci if (ah && ah->hw) 324262306a36Sopenharmony_ci printk("%s" pr_fmt("%s: %pV"), 324362306a36Sopenharmony_ci level, wiphy_name(ah->hw->wiphy), &vaf); 324462306a36Sopenharmony_ci else 324562306a36Sopenharmony_ci printk("%s" pr_fmt("%pV"), level, &vaf); 324662306a36Sopenharmony_ci 324762306a36Sopenharmony_ci va_end(args); 324862306a36Sopenharmony_ci} 3249