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