summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--Documentation/feature-removal-schedule.txt22
-rw-r--r--MAINTAINERS18
-rw-r--r--drivers/bcma/driver_chipcommon_pmu.c4
-rw-r--r--drivers/bcma/sprom.c4
-rw-r--r--drivers/net/wireless/ath/ath6kl/cfg80211.c36
-rw-r--r--drivers/net/wireless/ath/ath6kl/core.h3
-rw-r--r--drivers/net/wireless/ath/ath6kl/main.c1
-rw-r--r--drivers/net/wireless/ath/ath9k/Makefile4
-rw-r--r--drivers/net/wireless/ath/ath9k/ahb.c2
-rw-r--r--drivers/net/wireless/ath/ath9k/antenna.c776
-rw-r--r--drivers/net/wireless/ath/ath9k/ar9003_calib.c20
-rw-r--r--drivers/net/wireless/ath/ath9k/ar9003_eeprom.c5
-rw-r--r--drivers/net/wireless/ath/ath9k/ar9003_mci.c457
-rw-r--r--drivers/net/wireless/ath/ath9k/ar9003_mci.h10
-rw-r--r--drivers/net/wireless/ath/ath9k/ar9003_phy.c4
-rw-r--r--drivers/net/wireless/ath/ath9k/ar9003_phy.h32
-rw-r--r--drivers/net/wireless/ath/ath9k/ar9462_2p0_initvals.h4
-rw-r--r--drivers/net/wireless/ath/ath9k/ath9k.h49
-rw-r--r--drivers/net/wireless/ath/ath9k/beacon.c23
-rw-r--r--drivers/net/wireless/ath/ath9k/btcoex.c10
-rw-r--r--drivers/net/wireless/ath/ath9k/btcoex.h4
-rw-r--r--drivers/net/wireless/ath/ath9k/debug.c9
-rw-r--r--drivers/net/wireless/ath/ath9k/debug.h1
-rw-r--r--drivers/net/wireless/ath/ath9k/eeprom_4k.c2
-rw-r--r--drivers/net/wireless/ath/ath9k/eeprom_9287.c2
-rw-r--r--drivers/net/wireless/ath/ath9k/eeprom_def.c4
-rw-r--r--drivers/net/wireless/ath/ath9k/gpio.c36
-rw-r--r--drivers/net/wireless/ath/ath9k/hw.c212
-rw-r--r--drivers/net/wireless/ath/ath9k/hw.h10
-rw-r--r--drivers/net/wireless/ath/ath9k/init.c18
-rw-r--r--drivers/net/wireless/ath/ath9k/link.c502
-rw-r--r--drivers/net/wireless/ath/ath9k/main.c692
-rw-r--r--drivers/net/wireless/ath/ath9k/mci.c65
-rw-r--r--drivers/net/wireless/ath/ath9k/mci.h11
-rw-r--r--drivers/net/wireless/ath/ath9k/pci.c7
-rw-r--r--drivers/net/wireless/ath/ath9k/recv.c768
-rw-r--r--drivers/net/wireless/ath/ath9k/reg.h2
-rw-r--r--drivers/net/wireless/ath/ath9k/xmit.c51
-rw-r--r--drivers/net/wireless/b43legacy/main.c2
-rw-r--r--drivers/net/wireless/brcm80211/brcmfmac/bcmsdh.c4
-rw-r--r--drivers/net/wireless/brcm80211/brcmsmac/aiutils.c3
-rw-r--r--drivers/net/wireless/brcm80211/brcmsmac/aiutils.h2
-rw-r--r--drivers/net/wireless/brcm80211/brcmsmac/phy/phy_n.c2
-rw-r--r--drivers/net/wireless/brcm80211/brcmutil/utils.c2
-rw-r--r--drivers/net/wireless/ipw2x00/ipw2200.c23
-rw-r--r--drivers/net/wireless/iwlegacy/4965-mac.c13
-rw-r--r--drivers/net/wireless/iwlwifi/Kconfig5
-rw-r--r--drivers/net/wireless/iwlwifi/Makefile30
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-agn-sta.c1
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-agn.c16
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-commands.h3
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-config.h2
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-debug.c6
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-debug.h12
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-devtrace.c5
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-drv.c122
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-eeprom.c18
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-io.c19
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-mac80211.c14
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-notif-wait.c8
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-op-mode.h3
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-trans-pcie-int.h12
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-trans-pcie-rx.c73
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-trans-pcie-tx.c93
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-trans-pcie.c208
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-trans.h5
-rw-r--r--drivers/net/wireless/libertas/cfg.c39
-rw-r--r--drivers/net/wireless/libertas/dev.h1
-rw-r--r--drivers/net/wireless/libertas/mesh.c7
-rw-r--r--drivers/net/wireless/mac80211_hwsim.c21
-rw-r--r--drivers/net/wireless/mwifiex/cfg80211.c13
-rw-r--r--drivers/net/wireless/mwifiex/fw.h6
-rw-r--r--drivers/net/wireless/mwifiex/uap_cmd.c10
-rw-r--r--drivers/net/wireless/orinoco/cfg.c9
-rw-r--r--drivers/net/wireless/rt2x00/rt2800.h8
-rw-r--r--drivers/net/wireless/rt2x00/rt2800lib.c27
-rw-r--r--drivers/net/wireless/rt2x00/rt2800pci.c1
-rw-r--r--drivers/net/wireless/rt2x00/rt2800usb.c3
-rw-r--r--drivers/net/wireless/rt2x00/rt2x00.h3
-rw-r--r--drivers/net/wireless/rt2x00/rt2x00dev.c2
-rw-r--r--drivers/net/wireless/rt2x00/rt2x00mac.c15
-rw-r--r--drivers/net/wireless/rt2x00/rt2x00queue.c13
-rw-r--r--drivers/ssb/scan.c2
-rw-r--r--include/linux/nl80211.h8
-rw-r--r--include/linux/ssb/ssb.h1
-rw-r--r--include/net/cfg80211.h45
-rw-r--r--include/net/mac80211.h44
-rw-r--r--net/bluetooth/af_bluetooth.c2
-rw-r--r--net/core/net-sysfs.c74
-rw-r--r--net/mac80211/Makefile1
-rw-r--r--net/mac80211/agg-rx.c37
-rw-r--r--net/mac80211/agg-tx.c109
-rw-r--r--net/mac80211/cfg.c585
-rw-r--r--net/mac80211/chan.c4
-rw-r--r--net/mac80211/debugfs_netdev.c3
-rw-r--r--net/mac80211/ibss.c114
-rw-r--r--net/mac80211/ieee80211_i.h92
-rw-r--r--net/mac80211/iface.c30
-rw-r--r--net/mac80211/main.c17
-rw-r--r--net/mac80211/mesh.c3
-rw-r--r--net/mac80211/mesh_hwmp.c2
-rw-r--r--net/mac80211/mesh_pathtbl.c2
-rw-r--r--net/mac80211/mesh_plink.c2
-rw-r--r--net/mac80211/mesh_sync.c2
-rw-r--r--net/mac80211/mlme.c225
-rw-r--r--net/mac80211/offchannel.c272
-rw-r--r--net/mac80211/pm.c1
-rw-r--r--net/mac80211/rx.c22
-rw-r--r--net/mac80211/scan.c4
-rw-r--r--net/mac80211/sta_info.c27
-rw-r--r--net/mac80211/status.c30
-rw-r--r--net/mac80211/tkip.c21
-rw-r--r--net/mac80211/tx.c23
-rw-r--r--net/mac80211/util.c117
-rw-r--r--net/mac80211/work.c370
-rw-r--r--net/rfkill/core.c2
-rw-r--r--net/wireless/Kconfig14
-rw-r--r--net/wireless/chan.c55
-rw-r--r--net/wireless/core.h12
-rw-r--r--net/wireless/ibss.c6
-rw-r--r--net/wireless/mesh.c91
-rw-r--r--net/wireless/mlme.c2
-rw-r--r--net/wireless/nl80211.c129
-rw-r--r--net/wireless/util.c19
-rw-r--r--net/wireless/wext-compat.c21
-rw-r--r--net/wireless/wext-sme.c10
126 files changed, 3921 insertions, 3495 deletions
diff --git a/Documentation/feature-removal-schedule.txt b/Documentation/feature-removal-schedule.txt
index 56000b33340..dec901554ef 100644
--- a/Documentation/feature-removal-schedule.txt
+++ b/Documentation/feature-removal-schedule.txt
@@ -249,15 +249,6 @@ Who: Ravikiran Thirumalai <kiran@scalex86.org>
---------------------------
-What: Code that is now under CONFIG_WIRELESS_EXT_SYSFS
- (in net/core/net-sysfs.c)
-When: 3.5
-Why: Over 1K .text/.data size reduction, data is available in other
- ways (ioctls)
-Who: Johannes Berg <johannes@sipsolutions.net>
-
----------------------------
-
What: sysfs ui for changing p4-clockmod parameters
When: September 2009
Why: See commits 129f8ae9b1b5be94517da76009ea956e89104ce8 and
@@ -449,6 +440,19 @@ Who: Hans Verkuil <hans.verkuil@cisco.com>
----------------------------
+What: CONFIG_CFG80211_WEXT
+When: as soon as distributions ship new wireless tools, ie. wpa_supplicant 1.0
+ and NetworkManager/connman/etc. that are able to use nl80211
+Why: Wireless extensions are deprecated, and userland tools are moving to
+ using nl80211. New drivers are no longer using wireless extensions,
+ and while there might still be old drivers, both new drivers and new
+ userland no longer needs them and they can't be used for an feature
+ developed in the past couple of years. As such, compatibility with
+ wireless extensions in new drivers will be removed.
+Who: Johannes Berg <johannes@sipsolutions.net>
+
+----------------------------
+
What: g_file_storage driver
When: 3.8
Why: This driver has been superseded by g_mass_storage.
diff --git a/MAINTAINERS b/MAINTAINERS
index 55f0fda602e..c5fd905206e 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -329,7 +329,7 @@ F: drivers/hwmon/adm1029.c
ADM8211 WIRELESS DRIVER
L: linux-wireless@vger.kernel.org
-W: http://linuxwireless.org/
+W: http://wireless.kernel.org/
S: Orphan
F: drivers/net/wireless/adm8211.*
@@ -1423,7 +1423,7 @@ B43 WIRELESS DRIVER
M: Stefano Brivio <stefano.brivio@polimi.it>
L: linux-wireless@vger.kernel.org
L: b43-dev@lists.infradead.org
-W: http://linuxwireless.org/en/users/Drivers/b43
+W: http://wireless.kernel.org/en/users/Drivers/b43
S: Maintained
F: drivers/net/wireless/b43/
@@ -1432,7 +1432,7 @@ M: Larry Finger <Larry.Finger@lwfinger.net>
M: Stefano Brivio <stefano.brivio@polimi.it>
L: linux-wireless@vger.kernel.org
L: b43-dev@lists.infradead.org
-W: http://linuxwireless.org/en/users/Drivers/b43
+W: http://wireless.kernel.org/en/users/Drivers/b43
S: Maintained
F: drivers/net/wireless/b43legacy/
@@ -4339,7 +4339,7 @@ F: arch/m68k/hp300/
MAC80211
M: Johannes Berg <johannes@sipsolutions.net>
L: linux-wireless@vger.kernel.org
-W: http://linuxwireless.org/
+W: http://wireless.kernel.org/
T: git git://git.kernel.org/pub/scm/linux/kernel/git/linville/wireless.git
S: Maintained
F: Documentation/networking/mac80211-injection.txt
@@ -4350,7 +4350,7 @@ MAC80211 PID RATE CONTROL
M: Stefano Brivio <stefano.brivio@polimi.it>
M: Mattias Nissler <mattias.nissler@gmx.de>
L: linux-wireless@vger.kernel.org
-W: http://linuxwireless.org/en/developers/Documentation/mac80211/RateControl/PID
+W: http://wireless.kernel.org/en/developers/Documentation/mac80211/RateControl/PID
T: git git://git.kernel.org/pub/scm/linux/kernel/git/linville/wireless.git
S: Maintained
F: net/mac80211/rc80211_pid*
@@ -5027,7 +5027,7 @@ F: fs/ocfs2/
ORINOCO DRIVER
L: linux-wireless@vger.kernel.org
-W: http://linuxwireless.org/en/users/Drivers/orinoco
+W: http://wireless.kernel.org/en/users/Drivers/orinoco
W: http://www.nongnu.org/orinoco/
S: Orphan
F: drivers/net/wireless/orinoco/
@@ -5729,7 +5729,7 @@ F: net/rose/
RTL8180 WIRELESS DRIVER
M: "John W. Linville" <linville@tuxdriver.com>
L: linux-wireless@vger.kernel.org
-W: http://linuxwireless.org/
+W: http://wireless.kernel.org/
T: git git://git.kernel.org/pub/scm/linux/kernel/git/linville/wireless-testing.git
S: Maintained
F: drivers/net/wireless/rtl818x/rtl8180/
@@ -5739,7 +5739,7 @@ M: Herton Ronaldo Krzesinski <herton@canonical.com>
M: Hin-Tak Leung <htl10@users.sourceforge.net>
M: Larry Finger <Larry.Finger@lwfinger.net>
L: linux-wireless@vger.kernel.org
-W: http://linuxwireless.org/
+W: http://wireless.kernel.org/
T: git git://git.kernel.org/pub/scm/linux/kernel/git/linville/wireless-testing.git
S: Maintained
F: drivers/net/wireless/rtl818x/rtl8187/
@@ -5748,7 +5748,7 @@ RTL8192CE WIRELESS DRIVER
M: Larry Finger <Larry.Finger@lwfinger.net>
M: Chaoming Li <chaoming_li@realsil.com.cn>
L: linux-wireless@vger.kernel.org
-W: http://linuxwireless.org/
+W: http://wireless.kernel.org/
T: git git://git.kernel.org/pub/scm/linux/kernel/git/linville/wireless-testing.git
S: Maintained
F: drivers/net/wireless/rtlwifi/
diff --git a/drivers/bcma/driver_chipcommon_pmu.c b/drivers/bcma/driver_chipcommon_pmu.c
index a058842f14f..61ce4054b3c 100644
--- a/drivers/bcma/driver_chipcommon_pmu.c
+++ b/drivers/bcma/driver_chipcommon_pmu.c
@@ -139,7 +139,9 @@ void bcma_pmu_workarounds(struct bcma_drv_cc *cc)
bcma_chipco_chipctl_maskset(cc, 0, ~0, 0x7);
break;
case 0x4331:
- /* BCM4331 workaround is SPROM-related, we put it in sprom.c */
+ case 43431:
+ /* Ext PA lines must be enabled for tx on BCM4331 */
+ bcma_chipco_bcm4331_ext_pa_lines_ctl(cc, true);
break;
case 43224:
if (bus->chipinfo.rev == 0) {
diff --git a/drivers/bcma/sprom.c b/drivers/bcma/sprom.c
index c7f93359acb..f16f42d3607 100644
--- a/drivers/bcma/sprom.c
+++ b/drivers/bcma/sprom.c
@@ -579,13 +579,13 @@ int bcma_sprom_get(struct bcma_bus *bus)
if (!sprom)
return -ENOMEM;
- if (bus->chipinfo.id == 0x4331)
+ if (bus->chipinfo.id == 0x4331 || bus->chipinfo.id == 43431)
bcma_chipco_bcm4331_ext_pa_lines_ctl(&bus->drv_cc, false);
pr_debug("SPROM offset 0x%x\n", offset);
bcma_sprom_read(bus, offset, sprom);
- if (bus->chipinfo.id == 0x4331)
+ if (bus->chipinfo.id == 0x4331 || bus->chipinfo.id == 43431)
bcma_chipco_bcm4331_ext_pa_lines_ctl(&bus->drv_cc, true);
err = bcma_sprom_valid(sprom);
diff --git a/drivers/net/wireless/ath/ath6kl/cfg80211.c b/drivers/net/wireless/ath/ath6kl/cfg80211.c
index b869a358ce4..f27e9732951 100644
--- a/drivers/net/wireless/ath/ath6kl/cfg80211.c
+++ b/drivers/net/wireless/ath/ath6kl/cfg80211.c
@@ -2585,35 +2585,6 @@ static int ath6kl_set_ies(struct ath6kl_vif *vif,
return 0;
}
-static int ath6kl_set_channel(struct wiphy *wiphy, struct net_device *dev,
- struct ieee80211_channel *chan,
- enum nl80211_channel_type channel_type)
-{
- struct ath6kl_vif *vif;
-
- /*
- * 'dev' could be NULL if a channel change is required for the hardware
- * device itself, instead of a particular VIF.
- *
- * FIXME: To be handled properly when monitor mode is supported.
- */
- if (!dev)
- return -EBUSY;
-
- vif = netdev_priv(dev);
-
- if (!ath6kl_cfg80211_ready(vif))
- return -EIO;
-
- ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "%s: center_freq=%u hw_value=%u\n",
- __func__, chan->center_freq, chan->hw_value);
- vif->next_chan = chan->center_freq;
- vif->next_ch_type = channel_type;
- vif->next_ch_band = chan->band;
-
- return 0;
-}
-
static int ath6kl_get_rsn_capab(struct cfg80211_beacon_data *beacon,
u8 *rsn_capab)
{
@@ -2791,7 +2762,7 @@ static int ath6kl_start_ap(struct wiphy *wiphy, struct net_device *dev,
p.ssid_len = vif->ssid_len;
memcpy(p.ssid, vif->ssid, vif->ssid_len);
p.dot11_auth_mode = vif->dot11_auth_mode;
- p.ch = cpu_to_le16(vif->next_chan);
+ p.ch = cpu_to_le16(info->channel->center_freq);
/* Enable uAPSD support by default */
res = ath6kl_wmi_ap_set_apsd(ar->wmi, vif->fw_vif_idx, true);
@@ -2815,8 +2786,8 @@ static int ath6kl_start_ap(struct wiphy *wiphy, struct net_device *dev,
return res;
}
- if (ath6kl_set_htcap(vif, vif->next_ch_band,
- vif->next_ch_type != NL80211_CHAN_NO_HT))
+ if (ath6kl_set_htcap(vif, info->channel->band,
+ info->channel_type != NL80211_CHAN_NO_HT))
return -EIO;
/*
@@ -3271,7 +3242,6 @@ static struct cfg80211_ops ath6kl_cfg80211_ops = {
.suspend = __ath6kl_cfg80211_suspend,
.resume = __ath6kl_cfg80211_resume,
#endif
- .set_channel = ath6kl_set_channel,
.start_ap = ath6kl_start_ap,
.change_beacon = ath6kl_change_beacon,
.stop_ap = ath6kl_stop_ap,
diff --git a/drivers/net/wireless/ath/ath6kl/core.h b/drivers/net/wireless/ath/ath6kl/core.h
index 4d9c6f14269..8443b2a4133 100644
--- a/drivers/net/wireless/ath/ath6kl/core.h
+++ b/drivers/net/wireless/ath/ath6kl/core.h
@@ -553,9 +553,6 @@ struct ath6kl_vif {
u32 last_cancel_roc_id;
u32 send_action_id;
bool probe_req_report;
- u16 next_chan;
- enum nl80211_channel_type next_ch_type;
- enum ieee80211_band next_ch_band;
u16 assoc_bss_beacon_int;
u16 listen_intvl_t;
u16 bmiss_time_t;
diff --git a/drivers/net/wireless/ath/ath6kl/main.c b/drivers/net/wireless/ath/ath6kl/main.c
index e5524470529..b836f279511 100644
--- a/drivers/net/wireless/ath/ath6kl/main.c
+++ b/drivers/net/wireless/ath/ath6kl/main.c
@@ -598,7 +598,6 @@ static int ath6kl_commit_ch_switch(struct ath6kl_vif *vif, u16 channel)
struct ath6kl *ar = vif->ar;
- vif->next_chan = channel;
vif->profile.ch = cpu_to_le16(channel);
switch (vif->nw_type) {
diff --git a/drivers/net/wireless/ath/ath9k/Makefile b/drivers/net/wireless/ath/ath9k/Makefile
index 3f0b8472378..9c41232b0cd 100644
--- a/drivers/net/wireless/ath/ath9k/Makefile
+++ b/drivers/net/wireless/ath/ath9k/Makefile
@@ -3,7 +3,9 @@ ath9k-y += beacon.o \
init.o \
main.o \
recv.o \
- xmit.o
+ xmit.o \
+ link.o \
+ antenna.o
ath9k-$(CONFIG_ATH9K_BTCOEX_SUPPORT) += mci.o
ath9k-$(CONFIG_ATH9K_RATE_CONTROL) += rc.o
diff --git a/drivers/net/wireless/ath/ath9k/ahb.c b/drivers/net/wireless/ath/ath9k/ahb.c
index 5e47ca6d16a..4a4e8a2b9d2 100644
--- a/drivers/net/wireless/ath/ath9k/ahb.c
+++ b/drivers/net/wireless/ath/ath9k/ahb.c
@@ -126,7 +126,7 @@ static int ath_ahb_probe(struct platform_device *pdev)
sc->irq = irq;
/* Will be cleared in ath9k_start() */
- sc->sc_flags |= SC_OP_INVALID;
+ set_bit(SC_OP_INVALID, &sc->sc_flags);
ret = request_irq(irq, ath_isr, IRQF_SHARED, "ath9k", sc);
if (ret) {
diff --git a/drivers/net/wireless/ath/ath9k/antenna.c b/drivers/net/wireless/ath/ath9k/antenna.c
new file mode 100644
index 00000000000..bbcfeb3b2a6
--- /dev/null
+++ b/drivers/net/wireless/ath/ath9k/antenna.c
@@ -0,0 +1,776 @@
+/*
+ * Copyright (c) 2012 Qualcomm Atheros, Inc.
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include "ath9k.h"
+
+static inline bool ath_is_alt_ant_ratio_better(int alt_ratio, int maxdelta,
+ int mindelta, int main_rssi_avg,
+ int alt_rssi_avg, int pkt_count)
+{
+ return (((alt_ratio >= ATH_ANT_DIV_COMB_ALT_ANT_RATIO2) &&
+ (alt_rssi_avg > main_rssi_avg + maxdelta)) ||
+ (alt_rssi_avg > main_rssi_avg + mindelta)) && (pkt_count > 50);
+}
+
+static inline bool ath_ant_div_comb_alt_check(u8 div_group, int alt_ratio,
+ int curr_main_set, int curr_alt_set,
+ int alt_rssi_avg, int main_rssi_avg)
+{
+ bool result = false;
+ switch (div_group) {
+ case 0:
+ if (alt_ratio > ATH_ANT_DIV_COMB_ALT_ANT_RATIO)
+ result = true;
+ break;
+ case 1:
+ case 2:
+ if ((((curr_main_set == ATH_ANT_DIV_COMB_LNA2) &&
+ (curr_alt_set == ATH_ANT_DIV_COMB_LNA1) &&
+ (alt_rssi_avg >= (main_rssi_avg - 5))) ||
+ ((curr_main_set == ATH_ANT_DIV_COMB_LNA1) &&
+ (curr_alt_set == ATH_ANT_DIV_COMB_LNA2) &&
+ (alt_rssi_avg >= (main_rssi_avg - 2)))) &&
+ (alt_rssi_avg >= 4))
+ result = true;
+ else
+ result = false;
+ break;
+ }
+
+ return result;
+}
+
+static void ath_lnaconf_alt_good_scan(struct ath_ant_comb *antcomb,
+ struct ath_hw_antcomb_conf ant_conf,
+ int main_rssi_avg)
+{
+ antcomb->quick_scan_cnt = 0;
+
+ if (ant_conf.main_lna_conf == ATH_ANT_DIV_COMB_LNA2)
+ antcomb->rssi_lna2 = main_rssi_avg;
+ else if (ant_conf.main_lna_conf == ATH_ANT_DIV_COMB_LNA1)
+ antcomb->rssi_lna1 = main_rssi_avg;
+
+ switch ((ant_conf.main_lna_conf << 4) | ant_conf.alt_lna_conf) {
+ case 0x10: /* LNA2 A-B */
+ antcomb->main_conf = ATH_ANT_DIV_COMB_LNA1_MINUS_LNA2;
+ antcomb->first_quick_scan_conf =
+ ATH_ANT_DIV_COMB_LNA1_PLUS_LNA2;
+ antcomb->second_quick_scan_conf = ATH_ANT_DIV_COMB_LNA1;
+ break;
+ case 0x20: /* LNA1 A-B */
+ antcomb->main_conf = ATH_ANT_DIV_COMB_LNA1_MINUS_LNA2;
+ antcomb->first_quick_scan_conf =
+ ATH_ANT_DIV_COMB_LNA1_PLUS_LNA2;
+ antcomb->second_quick_scan_conf = ATH_ANT_DIV_COMB_LNA2;
+ break;
+ case 0x21: /* LNA1 LNA2 */
+ antcomb->main_conf = ATH_ANT_DIV_COMB_LNA2;
+ antcomb->first_quick_scan_conf =
+ ATH_ANT_DIV_COMB_LNA1_MINUS_LNA2;
+ antcomb->second_quick_scan_conf =
+ ATH_ANT_DIV_COMB_LNA1_PLUS_LNA2;
+ break;
+ case 0x12: /* LNA2 LNA1 */
+ antcomb->main_conf = ATH_ANT_DIV_COMB_LNA1;
+ antcomb->first_quick_scan_conf =
+ ATH_ANT_DIV_COMB_LNA1_MINUS_LNA2;
+ antcomb->second_quick_scan_conf =
+ ATH_ANT_DIV_COMB_LNA1_PLUS_LNA2;
+ break;
+ case 0x13: /* LNA2 A+B */
+ antcomb->main_conf = ATH_ANT_DIV_COMB_LNA1_PLUS_LNA2;
+ antcomb->first_quick_scan_conf =
+ ATH_ANT_DIV_COMB_LNA1_MINUS_LNA2;
+ antcomb->second_quick_scan_conf = ATH_ANT_DIV_COMB_LNA1;
+ break;
+ case 0x23: /* LNA1 A+B */
+ antcomb->main_conf = ATH_ANT_DIV_COMB_LNA1_PLUS_LNA2;
+ antcomb->first_quick_scan_conf =
+ ATH_ANT_DIV_COMB_LNA1_MINUS_LNA2;
+ antcomb->second_quick_scan_conf = ATH_ANT_DIV_COMB_LNA2;
+ break;
+ default:
+ break;
+ }
+}
+
+static void ath_select_ant_div_from_quick_scan(struct ath_ant_comb *antcomb,
+ struct ath_hw_antcomb_conf *div_ant_conf,
+ int main_rssi_avg, int alt_rssi_avg,
+ int alt_ratio)
+{
+ /* alt_good */
+ switch (antcomb->quick_scan_cnt) {
+ case 0:
+ /* set alt to main, and alt to first conf */
+ div_ant_conf->main_lna_conf = antcomb->main_conf;
+ div_ant_conf->alt_lna_conf = antcomb->first_quick_scan_conf;
+ break;
+ case 1:
+ /* set alt to main, and alt to first conf */
+ div_ant_conf->main_lna_conf = antcomb->main_conf;
+ div_ant_conf->alt_lna_conf = antcomb->second_quick_scan_conf;
+ antcomb->rssi_first = main_rssi_avg;
+ antcomb->rssi_second = alt_rssi_avg;
+
+ if (antcomb->main_conf == ATH_ANT_DIV_COMB_LNA1) {
+ /* main is LNA1 */
+ if (ath_is_alt_ant_ratio_better(alt_ratio,
+ ATH_ANT_DIV_COMB_LNA1_DELTA_HI,
+ ATH_ANT_DIV_COMB_LNA1_DELTA_LOW,
+ main_rssi_avg, alt_rssi_avg,
+ antcomb->total_pkt_count))
+ antcomb->first_ratio = true;
+ else
+ antcomb->first_ratio = false;
+ } else if (antcomb->main_conf == ATH_ANT_DIV_COMB_LNA2) {
+ if (ath_is_alt_ant_ratio_better(alt_ratio,
+ ATH_ANT_DIV_COMB_LNA1_DELTA_MID,
+ ATH_ANT_DIV_COMB_LNA1_DELTA_LOW,
+ main_rssi_avg, alt_rssi_avg,
+ antcomb->total_pkt_count))
+ antcomb->first_ratio = true;
+ else
+ antcomb->first_ratio = false;
+ } else {
+ if ((((alt_ratio >= ATH_ANT_DIV_COMB_ALT_ANT_RATIO2) &&
+ (alt_rssi_avg > main_rssi_avg +
+ ATH_ANT_DIV_COMB_LNA1_DELTA_HI)) ||
+ (alt_rssi_avg > main_rssi_avg)) &&
+ (antcomb->total_pkt_count > 50))
+ antcomb->first_ratio = true;
+ else
+ antcomb->first_ratio = false;
+ }
+ break;
+ case 2:
+ antcomb->alt_good = false;
+ antcomb->scan_not_start = false;
+ antcomb->scan = false;
+ antcomb->rssi_first = main_rssi_avg;
+ antcomb->rssi_third = alt_rssi_avg;
+
+ if (antcomb->second_quick_scan_conf == ATH_ANT_DIV_COMB_LNA1)
+ antcomb->rssi_lna1 = alt_rssi_avg;
+ else if (antcomb->second_quick_scan_conf ==
+ ATH_ANT_DIV_COMB_LNA2)
+ antcomb->rssi_lna2 = alt_rssi_avg;
+ else if (antcomb->second_quick_scan_conf ==
+ ATH_ANT_DIV_COMB_LNA1_PLUS_LNA2) {
+ if (antcomb->main_conf == ATH_ANT_DIV_COMB_LNA2)
+ antcomb->rssi_lna2 = main_rssi_avg;
+ else if (antcomb->main_conf == ATH_ANT_DIV_COMB_LNA1)
+ antcomb->rssi_lna1 = main_rssi_avg;
+ }
+
+ if (antcomb->rssi_lna2 > antcomb->rssi_lna1 +
+ ATH_ANT_DIV_COMB_LNA1_LNA2_SWITCH_DELTA)
+ div_ant_conf->main_lna_conf = ATH_ANT_DIV_COMB_LNA2;
+ else
+ div_ant_conf->main_lna_conf = ATH_ANT_DIV_COMB_LNA1;
+
+ if (antcomb->main_conf == ATH_ANT_DIV_COMB_LNA1) {
+ if (ath_is_alt_ant_ratio_better(alt_ratio,
+ ATH_ANT_DIV_COMB_LNA1_DELTA_HI,
+ ATH_ANT_DIV_COMB_LNA1_DELTA_LOW,
+ main_rssi_avg, alt_rssi_avg,
+ antcomb->total_pkt_count))
+ antcomb->second_ratio = true;
+ else
+ antcomb->second_ratio = false;
+ } else if (antcomb->main_conf == ATH_ANT_DIV_COMB_LNA2) {
+ if (ath_is_alt_ant_ratio_better(alt_ratio,
+ ATH_ANT_DIV_COMB_LNA1_DELTA_MID,
+ ATH_ANT_DIV_COMB_LNA1_DELTA_LOW,
+ main_rssi_avg, alt_rssi_avg,
+ antcomb->total_pkt_count))
+ antcomb->second_ratio = true;
+ else
+ antcomb->second_ratio = false;
+ } else {
+ if ((((alt_ratio >= ATH_ANT_DIV_COMB_ALT_ANT_RATIO2) &&
+ (alt_rssi_avg > main_rssi_avg +
+ ATH_ANT_DIV_COMB_LNA1_DELTA_HI)) ||
+ (alt_rssi_avg > main_rssi_avg)) &&
+ (antcomb->total_pkt_count > 50))
+ antcomb->second_ratio = true;
+ else
+ antcomb->second_ratio = false;
+ }
+
+ /* set alt to the conf with maximun ratio */
+ if (antcomb->first_ratio && antcomb->second_ratio) {
+ if (antcomb->rssi_second > antcomb->rssi_third) {
+ /* first alt*/
+ if ((antcomb->first_quick_scan_conf ==
+ ATH_ANT_DIV_COMB_LNA1) ||
+ (antcomb->first_quick_scan_conf ==
+ ATH_ANT_DIV_COMB_LNA2))
+ /* Set alt LNA1 or LNA2*/
+ if (div_ant_conf->main_lna_conf ==
+ ATH_ANT_DIV_COMB_LNA2)
+ div_ant_conf->alt_lna_conf =
+ ATH_ANT_DIV_COMB_LNA1;
+ else
+ div_ant_conf->alt_lna_conf =
+ ATH_ANT_DIV_COMB_LNA2;
+ else
+ /* Set alt to A+B or A-B */
+ div_ant_conf->alt_lna_conf =
+ antcomb->first_quick_scan_conf;
+ } else if ((antcomb->second_quick_scan_conf ==
+ ATH_ANT_DIV_COMB_LNA1) ||
+ (antcomb->second_quick_scan_conf ==
+ ATH_ANT_DIV_COMB_LNA2)) {
+ /* Set alt LNA1 or LNA2 */
+ if (div_ant_conf->main_lna_conf ==
+ ATH_ANT_DIV_COMB_LNA2)
+ div_ant_conf->alt_lna_conf =
+ ATH_ANT_DIV_COMB_LNA1;
+ else
+ div_ant_conf->alt_lna_conf =
+ ATH_ANT_DIV_COMB_LNA2;
+ } else {
+ /* Set alt to A+B or A-B */
+ div_ant_conf->alt_lna_conf =
+ antcomb->second_quick_scan_conf;
+ }
+ } else if (antcomb->first_ratio) {
+ /* first alt */
+ if ((antcomb->first_quick_scan_conf ==
+ ATH_ANT_DIV_COMB_LNA1) ||
+ (antcomb->first_quick_scan_conf ==
+ ATH_ANT_DIV_COMB_LNA2))
+ /* Set alt LNA1 or LNA2 */
+ if (div_ant_conf->main_lna_conf ==
+ ATH_ANT_DIV_COMB_LNA2)
+ div_ant_conf->alt_lna_conf =
+ ATH_ANT_DIV_COMB_LNA1;
+ else
+ div_ant_conf->alt_lna_conf =
+ ATH_ANT_DIV_COMB_LNA2;
+ else
+ /* Set alt to A+B or A-B */
+ div_ant_conf->alt_lna_conf =
+ antcomb->first_quick_scan_conf;
+ } else if (antcomb->second_ratio) {
+ /* second alt */
+ if ((antcomb->second_quick_scan_conf ==
+ ATH_ANT_DIV_COMB_LNA1) ||
+ (antcomb->second_quick_scan_conf ==
+ ATH_ANT_DIV_COMB_LNA2))
+ /* Set alt LNA1 or LNA2 */
+ if (div_ant_conf->main_lna_conf ==
+ ATH_ANT_DIV_COMB_LNA2)
+ div_ant_conf->alt_lna_conf =
+ ATH_ANT_DIV_COMB_LNA1;
+ else
+ div_ant_conf->alt_lna_conf =
+ ATH_ANT_DIV_COMB_LNA2;
+ else
+ /* Set alt to A+B or A-B */
+ div_ant_conf->alt_lna_conf =
+ antcomb->second_quick_scan_conf;
+ } else {
+ /* main is largest */
+ if ((antcomb->main_conf == ATH_ANT_DIV_COMB_LNA1) ||
+ (antcomb->main_conf == ATH_ANT_DIV_COMB_LNA2))
+ /* Set alt LNA1 or LNA2 */
+ if (div_ant_conf->main_lna_conf ==
+ ATH_ANT_DIV_COMB_LNA2)
+ div_ant_conf->alt_lna_conf =
+ ATH_ANT_DIV_COMB_LNA1;
+ else
+ div_ant_conf->alt_lna_conf =
+ ATH_ANT_DIV_COMB_LNA2;
+ else
+ /* Set alt to A+B or A-B */
+ div_ant_conf->alt_lna_conf = antcomb->main_conf;
+ }
+ break;
+ default:
+ break;
+ }
+}
+
+static void ath_ant_div_conf_fast_divbias(struct ath_hw_antcomb_conf *ant_conf,
+ struct ath_ant_comb *antcomb,
+ int alt_ratio)
+{
+ if (ant_conf->div_group == 0) {
+ /* Adjust the fast_div_bias based on main and alt lna conf */
+ switch ((ant_conf->main_lna_conf << 4) |
+ ant_conf->alt_lna_conf) {
+ case 0x01: /* A-B LNA2 */
+ ant_conf->fast_div_bias = 0x3b;
+ break;
+ case 0x02: /* A-B LNA1 */
+ ant_conf->fast_div_bias = 0x3d;
+ break;
+ case 0x03: /* A-B A+B */
+ ant_conf->fast_div_bias = 0x1;
+ break;
+ case 0x10: /* LNA2 A-B */
+ ant_conf->fast_div_bias = 0x7;
+ break;
+ case 0x12: /* LNA2 LNA1 */
+ ant_conf->fast_div_bias = 0x2;
+ break;
+ case 0x13: /* LNA2 A+B */
+ ant_conf->fast_div_bias = 0x7;
+ break;
+ case 0x20: /* LNA1 A-B */
+ ant_conf->fast_div_bias = 0x6;
+ break;
+ case 0x21: /* LNA1 LNA2 */
+ ant_conf->fast_div_bias = 0x0;
+ break;
+ case 0x23: /* LNA1 A+B */
+ ant_conf->fast_div_bias = 0x6;
+ break;
+ case 0x30: /* A+B A-B */
+ ant_conf->fast_div_bias = 0x1;
+ break;
+ case 0x31: /* A+B LNA2 */
+ ant_conf->fast_div_bias = 0x3b;
+ break;
+ case 0x32: /* A+B LNA1 */
+ ant_conf->fast_div_bias = 0x3d;
+ break;
+ default:
+ break;
+ }
+ } else if (ant_conf->div_group == 1) {
+ /* Adjust the fast_div_bias based on main and alt_lna_conf */
+ switch ((ant_conf->main_lna_conf << 4) |
+ ant_conf->alt_lna_conf) {
+ case 0x01: /* A-B LNA2 */
+ ant_conf->fast_div_bias = 0x1;
+ ant_conf->main_gaintb = 0;
+ ant_conf->alt_gaintb = 0;
+ break;
+ case 0x02: /* A-B LNA1 */
+ ant_conf->fast_div_bias = 0x1;
+ ant_conf->main_gaintb = 0;
+ ant_conf->alt_gaintb = 0;
+ break;
+ case 0x03: /* A-B A+B */
+ ant_conf->fast_div_bias = 0x1;
+ ant_conf->main_gaintb = 0;
+ ant_conf->alt_gaintb = 0;
+ break;
+ case 0x10: /* LNA2 A-B */
+ if (!(antcomb->scan) &&
+ (alt_ratio > ATH_ANT_DIV_COMB_ALT_ANT_RATIO))
+ ant_conf->fast_div_bias = 0x3f;
+ else
+ ant_conf->fast_div_bias = 0x1;
+ ant_conf->main_gaintb = 0;
+ ant_conf->alt_gaintb = 0;
+ break;
+ case 0x12: /* LNA2 LNA1 */
+ ant_conf->fast_div_bias = 0x1;
+ ant_conf->main_gaintb = 0;
+ ant_conf->alt_gaintb = 0;
+ break;
+ case 0x13: /* LNA2 A+B */
+ if (!(antcomb->scan) &&
+ (alt_ratio > ATH_ANT_DIV_COMB_ALT_ANT_RATIO))
+ ant_conf->fast_div_bias = 0x3f;
+ else
+ ant_conf->fast_div_bias = 0x1;
+ ant_conf->main_gaintb = 0;
+ ant_conf->alt_gaintb = 0;
+ break;
+ case 0x20: /* LNA1 A-B */
+ if (!(antcomb->scan) &&
+ (alt_ratio > ATH_ANT_DIV_COMB_ALT_ANT_RATIO))
+ ant_conf->fast_div_bias = 0x3f;
+ else
+ ant_conf->fast_div_bias = 0x1;
+ ant_conf->main_gaintb = 0;
+ ant_conf->alt_gaintb = 0;
+ break;
+ case 0x21: /* LNA1 LNA2 */
+ ant_conf->fast_div_bias = 0x1;
+ ant_conf->main_gaintb = 0;
+ ant_conf->alt_gaintb = 0;
+ break;
+ case 0x23: /* LNA1 A+B */
+ if (!(antcomb->scan) &&
+ (alt_ratio > ATH_ANT_DIV_COMB_ALT_ANT_RATIO))
+ ant_conf->fast_div_bias = 0x3f;
+ else
+ ant_conf->fast_div_bias = 0x1;
+ ant_conf->main_gaintb = 0;
+ ant_conf->alt_gaintb = 0;
+ break;
+ case 0x30: /* A+B A-B */
+ ant_conf->fast_div_bias = 0x1;
+ ant_conf->main_gaintb = 0;
+ ant_conf->alt_gaintb = 0;
+ break;
+ case 0x31: /* A+B LNA2 */
+ ant_conf->fast_div_bias = 0x1;
+ ant_conf->main_gaintb = 0;
+ ant_conf->alt_gaintb = 0;
+ break;
+ case 0x32: /* A+B LNA1 */
+ ant_conf->fast_div_bias = 0x1;
+ ant_conf->main_gaintb = 0;
+ ant_conf->alt_gaintb = 0;
+ break;
+ default:
+ break;
+ }
+ } else if (ant_conf->div_group == 2) {
+ /* Adjust the fast_div_bias based on main and alt_lna_conf */
+ switch ((ant_conf->main_lna_conf << 4) |
+ ant_conf->alt_lna_conf) {
+ case 0x01: /* A-B LNA2 */
+ ant_conf->fast_div_bias = 0x1;
+ ant_conf->main_gaintb = 0;
+ ant_conf->alt_gaintb = 0;
+ break;
+ case 0x02: /* A-B LNA1 */
+ ant_conf->fast_div_bias = 0x1;
+ ant_conf->main_gaintb = 0;
+ ant_conf->alt_gaintb = 0;
+ break;
+ case 0x03: /* A-B A+B */
+ ant_conf->fast_div_bias = 0x1;
+ ant_conf->main_gaintb = 0;
+ ant_conf->alt_gaintb = 0;
+ break;
+ case 0x10: /* LNA2 A-B */
+ if (!(antcomb->scan) &&
+ (alt_ratio > ATH_ANT_DIV_COMB_ALT_ANT_RATIO))
+ ant_conf->fast_div_bias = 0x1;
+ else
+ ant_conf->fast_div_bias = 0x2;
+ ant_conf->main_gaintb = 0;
+ ant_conf->alt_gaintb = 0;
+ break;
+ case 0x12: /* LNA2 LNA1 */
+ ant_conf->fast_div_bias = 0x1;
+ ant_conf->main_gaintb = 0;
+ ant_conf->alt_gaintb = 0;
+ break;
+ case 0x13: /* LNA2 A+B */
+ if (!(antcomb->scan) &&
+ (alt_ratio > ATH_ANT_DIV_COMB_ALT_ANT_RATIO))
+ ant_conf->fast_div_bias = 0x1;
+ else
+ ant_conf->fast_div_bias = 0x2;
+ ant_conf->main_gaintb = 0;
+ ant_conf->alt_gaintb = 0;
+ break;
+ case 0x20: /* LNA1 A-B */
+ if (!(antcomb->scan) &&
+ (alt_ratio > ATH_ANT_DIV_COMB_ALT_ANT_RATIO))
+ ant_conf->fast_div_bias = 0x1;
+ else
+ ant_conf->fast_div_bias = 0x2;
+ ant_conf->main_gaintb = 0;
+ ant_conf->alt_gaintb = 0;
+ break;
+ case 0x21: /* LNA1 LNA2 */
+ ant_conf->fast_div_bias = 0x1;
+ ant_conf->main_gaintb = 0;
+ ant_conf->alt_gaintb = 0;
+ break;
+ case 0x23: /* LNA1 A+B */
+ if (!(antcomb->scan) &&
+ (alt_ratio > ATH_ANT_DIV_COMB_ALT_ANT_RATIO))
+ ant_conf->fast_div_bias = 0x1;
+ else
+ ant_conf->fast_div_bias = 0x2;
+ ant_conf->main_gaintb = 0;
+ ant_conf->alt_gaintb = 0;
+ break;
+ case 0x30: /* A+B A-B */
+ ant_conf->fast_div_bias = 0x1;
+ ant_conf->main_gaintb = 0;
+ ant_conf->alt_gaintb = 0;
+ break;
+ case 0x31: /* A+B LNA2 */
+ ant_conf->fast_div_bias = 0x1;
+ ant_conf->main_gaintb = 0;
+ ant_conf->alt_gaintb = 0;
+ break;
+ case 0x32: /* A+B LNA1 */
+ ant_conf->fast_div_bias = 0x1;
+ ant_conf->main_gaintb = 0;
+ ant_conf->alt_gaintb = 0;
+ break;
+ default:
+ break;
+ }
+ }
+}
+
+void ath_ant_comb_scan(struct ath_softc *sc, struct ath_rx_status *rs)
+{
+ struct ath_hw_antcomb_conf div_ant_conf;
+ struct ath_ant_comb *antcomb = &sc->ant_comb;
+ int alt_ratio = 0, alt_rssi_avg = 0, main_rssi_avg = 0, curr_alt_set;
+ int curr_main_set;
+ int main_rssi = rs->rs_rssi_ctl0;
+ int alt_rssi = rs->rs_rssi_ctl1;
+ int rx_ant_conf, main_ant_conf;
+ bool short_scan = false;
+
+ rx_ant_conf = (rs->rs_rssi_ctl2 >> ATH_ANT_RX_CURRENT_SHIFT) &
+ ATH_ANT_RX_MASK;
+ main_ant_conf = (rs->rs_rssi_ctl2 >> ATH_ANT_RX_MAIN_SHIFT) &
+ ATH_ANT_RX_MASK;
+
+ /* Record packet only when both main_rssi and alt_rssi is positive */
+ if (main_rssi > 0 && alt_rssi > 0) {
+ antcomb->total_pkt_count++;
+ antcomb->main_total_rssi += main_rssi;
+ antcomb->alt_total_rssi += alt_rssi;
+ if (main_ant_conf == rx_ant_conf)
+ antcomb->main_recv_cnt++;
+ else
+ antcomb->alt_recv_cnt++;
+ }
+
+ /* Short scan check */
+ if (antcomb->scan && antcomb->alt_good) {
+ if (time_after(jiffies, antcomb->scan_start_time +
+ msecs_to_jiffies(ATH_ANT_DIV_COMB_SHORT_SCAN_INTR)))
+ short_scan = true;
+ else
+ if (antcomb->total_pkt_count ==
+ ATH_ANT_DIV_COMB_SHORT_SCAN_PKTCOUNT) {
+ alt_ratio = ((antcomb->alt_recv_cnt * 100) /
+ antcomb->total_pkt_count);
+ if (alt_ratio < ATH_ANT_DIV_COMB_ALT_ANT_RATIO)
+ short_scan = true;
+ }
+ }
+
+ if (((antcomb->total_pkt_count < ATH_ANT_DIV_COMB_MAX_PKTCOUNT) ||
+ rs->rs_moreaggr) && !short_scan)
+ return;
+
+ if (antcomb->total_pkt_count) {
+ alt_ratio = ((antcomb->alt_recv_cnt * 100) /
+ antcomb->total_pkt_count);
+ main_rssi_avg = (antcomb->main_total_rssi /
+ antcomb->total_pkt_count);
+ alt_rssi_avg = (antcomb->alt_total_rssi /
+ antcomb->total_pkt_count);
+ }
+
+
+ ath9k_hw_antdiv_comb_conf_get(sc->sc_ah, &div_ant_conf);
+ curr_alt_set = div_ant_conf.alt_lna_conf;
+ curr_main_set = div_ant_conf.main_lna_conf;
+
+ antcomb->count++;
+
+ if (antcomb->count == ATH_ANT_DIV_COMB_MAX_COUNT) {
+ if (alt_ratio > ATH_ANT_DIV_COMB_ALT_ANT_RATIO) {
+ ath_lnaconf_alt_good_scan(antcomb, div_ant_conf,
+ main_rssi_avg);
+ antcomb->alt_good = true;
+ } else {
+ antcomb->alt_good = false;
+ }
+
+ antcomb->count = 0;
+ antcomb->scan = true;
+ antcomb->scan_not_start = true;
+ }
+
+ if (!antcomb->scan) {
+ if (ath_ant_div_comb_alt_check(div_ant_conf.div_group,
+ alt_ratio, curr_main_set, curr_alt_set,
+ alt_rssi_avg, main_rssi_avg)) {
+ if (curr_alt_set == ATH_ANT_DIV_COMB_LNA2) {
+ /* Switch main and alt LNA */
+ div_ant_conf.main_lna_conf =
+ ATH_ANT_DIV_COMB_LNA2;
+ div_ant_conf.alt_lna_conf =
+ ATH_ANT_DIV_COMB_LNA1;
+ } else if (curr_alt_set == ATH_ANT_DIV_COMB_LNA1) {
+ div_ant_conf.main_lna_conf =
+ ATH_ANT_DIV_COMB_LNA1;
+ div_ant_conf.alt_lna_conf =
+ ATH_ANT_DIV_COMB_LNA2;
+ }
+
+ goto div_comb_done;
+ } else if ((curr_alt_set != ATH_ANT_DIV_COMB_LNA1) &&
+ (curr_alt_set != ATH_ANT_DIV_COMB_LNA2)) {
+ /* Set alt to another LNA */
+ if (curr_main_set == ATH_ANT_DIV_COMB_LNA2)
+ div_ant_conf.alt_lna_conf =
+ ATH_ANT_DIV_COMB_LNA1;
+ else if (curr_main_set == ATH_ANT_DIV_COMB_LNA1)
+ div_ant_conf.alt_lna_conf =
+ ATH_ANT_DIV_COMB_LNA2;
+
+ goto div_comb_done;
+ }
+
+ if ((alt_rssi_avg < (main_rssi_avg +
+ div_ant_conf.lna1_lna2_delta)))
+ goto div_comb_done;
+ }
+
+ if (!antcomb->scan_not_start) {
+ switch (curr_alt_set) {
+ case ATH_ANT_DIV_COMB_LNA2:
+ antcomb->rssi_lna2 = alt_rssi_avg;
+ antcomb->rssi_lna1 = main_rssi_avg;
+ antcomb->scan = true;
+ /* set to A+B */
+ div_ant_conf.main_lna_conf =
+ ATH_ANT_DIV_COMB_LNA1;
+ div_ant_conf.alt_lna_conf =
+ ATH_ANT_DIV_COMB_LNA1_PLUS_LNA2;
+ break;
+ case ATH_ANT_DIV_COMB_LNA1:
+ antcomb->rssi_lna1 = alt_rssi_avg;
+ antcomb->rssi_lna2 = main_rssi_avg;
+ antcomb->scan = true;
+ /* set to A+B */
+ div_ant_conf.main_lna_conf = ATH_ANT_DIV_COMB_LNA2;
+ div_ant_conf.alt_lna_conf =
+ ATH_ANT_DIV_COMB_LNA1_PLUS_LNA2;
+ break;
+ case ATH_ANT_DIV_COMB_LNA1_PLUS_LNA2:
+ antcomb->rssi_add = alt_rssi_avg;
+ antcomb->scan = true;
+ /* set to A-B */
+ div_ant_conf.alt_lna_conf =
+ ATH_ANT_DIV_COMB_LNA1_MINUS_LNA2;
+ break;
+ case ATH_ANT_DIV_COMB_LNA1_MINUS_LNA2:
+ antcomb->rssi_sub = alt_rssi_avg;
+ antcomb->scan = false;
+ if (antcomb->rssi_lna2 >
+ (antcomb->rssi_lna1 +
+ ATH_ANT_DIV_COMB_LNA1_LNA2_SWITCH_DELTA)) {
+ /* use LNA2 as main LNA */
+ if ((antcomb->rssi_add > antcomb->rssi_lna1) &&
+ (antcomb->rssi_add > antcomb->rssi_sub)) {
+ /* set to A+B */
+ div_ant_conf.main_lna_conf =
+ ATH_ANT_DIV_COMB_LNA2;
+ div_ant_conf.alt_lna_conf =
+ ATH_ANT_DIV_COMB_LNA1_PLUS_LNA2;
+ } else if (antcomb->rssi_sub >
+ antcomb->rssi_lna1) {
+ /* set to A-B */
+ div_ant_conf.main_lna_conf =
+ ATH_ANT_DIV_COMB_LNA2;
+ div_ant_conf.alt_lna_conf =
+ ATH_ANT_DIV_COMB_LNA1_MINUS_LNA2;
+ } else {
+ /* set to LNA1 */
+ div_ant_conf.main_lna_conf =
+ ATH_ANT_DIV_COMB_LNA2;
+ div_ant_conf.alt_lna_conf =
+ ATH_ANT_DIV_COMB_LNA1;
+ }
+ } else {
+ /* use LNA1 as main LNA */
+ if ((antcomb->rssi_add > antcomb->rssi_lna2) &&
+ (antcomb->rssi_add > antcomb->rssi_sub)) {
+ /* set to A+B */
+ div_ant_conf.main_lna_conf =
+ ATH_ANT_DIV_COMB_LNA1;
+ div_ant_conf.alt_lna_conf =
+ ATH_ANT_DIV_COMB_LNA1_PLUS_LNA2;
+ } else if (antcomb->rssi_sub >
+ antcomb->rssi_lna1) {
+ /* set to A-B */
+ div_ant_conf.main_lna_conf =
+ ATH_ANT_DIV_COMB_LNA1;
+ div_ant_conf.alt_lna_conf =
+ ATH_ANT_DIV_COMB_LNA1_MINUS_LNA2;
+ } else {
+ /* set to LNA2 */
+ div_ant_conf.main_lna_conf =
+ ATH_ANT_DIV_COMB_LNA1;
+ div_ant_conf.alt_lna_conf =
+ ATH_ANT_DIV_COMB_LNA2;
+ }
+ }
+ break;
+ default:
+ break;
+ }
+ } else {
+ if (!antcomb->alt_good) {
+ antcomb->scan_not_start = false;
+ /* Set alt to another LNA */
+ if (curr_main_set == ATH_ANT_DIV_COMB_LNA2) {
+ div_ant_conf.main_lna_conf =
+ ATH_ANT_DIV_COMB_LNA2;
+ div_ant_conf.alt_lna_conf =
+ ATH_ANT_DIV_COMB_LNA1;
+ } else if (curr_main_set == ATH_ANT_DIV_COMB_LNA1) {
+ div_ant_conf.main_lna_conf =
+ ATH_ANT_DIV_COMB_LNA1;
+ div_ant_conf.alt_lna_conf =
+ ATH_ANT_DIV_COMB_LNA2;
+ }
+ goto div_comb_done;
+ }
+ }
+
+ ath_select_ant_div_from_quick_scan(antcomb, &div_ant_conf,
+ main_rssi_avg, alt_rssi_avg,
+ alt_ratio);
+
+ antcomb->quick_scan_cnt++;
+
+div_comb_done:
+ ath_ant_div_conf_fast_divbias(&div_ant_conf, antcomb, alt_ratio);
+ ath9k_hw_antdiv_comb_conf_set(sc->sc_ah, &div_ant_conf);
+
+ antcomb->scan_start_time = jiffies;
+ antcomb->total_pkt_count = 0;
+ antcomb->main_total_rssi = 0;
+ antcomb->alt_total_rssi = 0;
+ antcomb->main_recv_cnt = 0;
+ antcomb->alt_recv_cnt = 0;
+}
+
+void ath_ant_comb_update(struct ath_softc *sc)
+{
+ struct ath_hw *ah = sc->sc_ah;
+ struct ath_hw_antcomb_conf div_ant_conf;
+ u8 lna_conf;
+
+ ath9k_hw_antdiv_comb_conf_get(ah, &div_ant_conf);
+
+ if (sc->ant_rx == 1)
+ lna_conf = ATH_ANT_DIV_COMB_LNA1;
+ else
+ lna_conf = ATH_ANT_DIV_COMB_LNA2;
+
+ div_ant_conf.main_lna_conf = lna_conf;
+ div_ant_conf.alt_lna_conf = lna_conf;
+
+ ath9k_hw_antdiv_comb_conf_set(ah, &div_ant_conf);
+}
diff --git a/drivers/net/wireless/ath/ath9k/ar9003_calib.c b/drivers/net/wireless/ath/ath9k/ar9003_calib.c
index 9fdd70fcaf5..d7deb8c9f29 100644
--- a/drivers/net/wireless/ath/ath9k/ar9003_calib.c
+++ b/drivers/net/wireless/ath/ath9k/ar9003_calib.c
@@ -653,7 +653,6 @@ static void ar9003_hw_detect_outlier(int *mp_coeff, int nmeasurement,
}
static void ar9003_hw_tx_iqcal_load_avg_2_passes(struct ath_hw *ah,
- u8 num_chains,
struct coeff *coeff,
bool is_reusable)
{
@@ -677,7 +676,9 @@ static void ar9003_hw_tx_iqcal_load_avg_2_passes(struct ath_hw *ah,
}
/* Load the average of 2 passes */
- for (i = 0; i < num_chains; i++) {
+ for (i = 0; i < AR9300_MAX_CHAINS; i++) {
+ if (!(ah->txchainmask & (1 << i)))
+ continue;
nmeasurement = REG_READ_FIELD(ah,
AR_PHY_TX_IQCAL_STATUS_B0,
AR_PHY_CALIBRATED_GAINS_0);
@@ -767,16 +768,13 @@ static void ar9003_hw_tx_iq_cal_post_proc(struct ath_hw *ah, bool is_reusable)
};
struct coeff coeff;
s32 iq_res[6];
- u8 num_chains = 0;
int i, im, j;
int nmeasurement;
for (i = 0; i < AR9300_MAX_CHAINS; i++) {
- if (ah->txchainmask & (1 << i))
- num_chains++;
- }
+ if (!(ah->txchainmask & (1 << i)))
+ continue;
- for (i = 0; i < num_chains; i++) {
nmeasurement = REG_READ_FIELD(ah,
AR_PHY_TX_IQCAL_STATUS_B0,
AR_PHY_CALIBRATED_GAINS_0);
@@ -839,8 +837,7 @@ static void ar9003_hw_tx_iq_cal_post_proc(struct ath_hw *ah, bool is_reusable)
coeff.phs_coeff[i][im] -= 128;
}
}
- ar9003_hw_tx_iqcal_load_avg_2_passes(ah, num_chains,
- &coeff, is_reusable);
+ ar9003_hw_tx_iqcal_load_avg_2_passes(ah, &coeff, is_reusable);
return;
@@ -901,7 +898,6 @@ static bool ar9003_hw_init_cal(struct ath_hw *ah,
bool is_reusable = true, status = true;
bool run_rtt_cal = false, run_agc_cal;
bool rtt = !!(ah->caps.hw_caps & ATH9K_HW_CAP_RTT);
- bool mci = !!(ah->caps.hw_caps & ATH9K_HW_CAP_MCI);
u32 agc_ctrl = 0, agc_supp_cals = AR_PHY_AGC_CONTROL_OFFSET_CAL |
AR_PHY_AGC_CONTROL_FLTR_CAL |
AR_PHY_AGC_CONTROL_PKDET_CAL;
@@ -970,7 +966,7 @@ static bool ar9003_hw_init_cal(struct ath_hw *ah,
} else if (caldata && !caldata->done_txiqcal_once)
run_agc_cal = true;
- if (mci && IS_CHAN_2GHZ(chan) && run_agc_cal)
+ if (ath9k_hw_mci_is_enabled(ah) && IS_CHAN_2GHZ(chan) && run_agc_cal)
ar9003_mci_init_cal_req(ah, &is_reusable);
if (!(IS_CHAN_HALF_RATE(chan) || IS_CHAN_QUARTER_RATE(chan))) {
@@ -993,7 +989,7 @@ skip_tx_iqcal:
0, AH_WAIT_TIMEOUT);
}
- if (mci && IS_CHAN_2GHZ(chan) && run_agc_cal)
+ if (ath9k_hw_mci_is_enabled(ah) && IS_CHAN_2GHZ(chan) && run_agc_cal)
ar9003_mci_init_cal_done(ah);
if (rtt && !run_rtt_cal) {
diff --git a/drivers/net/wireless/ath/ath9k/ar9003_eeprom.c b/drivers/net/wireless/ath/ath9k/ar9003_eeprom.c
index dfb0441f406..2cdf82bdb11 100644
--- a/drivers/net/wireless/ath/ath9k/ar9003_eeprom.c
+++ b/drivers/net/wireless/ath/ath9k/ar9003_eeprom.c
@@ -3412,11 +3412,11 @@ static u32 ath9k_hw_ar9003_dump_eeprom(struct ath_hw *ah, bool dump_base_hdr,
if (!dump_base_hdr) {
len += snprintf(buf + len, size - len,
"%20s :\n", "2GHz modal Header");
- len += ar9003_dump_modal_eeprom(buf, len, size,
+ len = ar9003_dump_modal_eeprom(buf, len, size,
&eep->modalHeader2G);
len += snprintf(buf + len, size - len,
"%20s :\n", "5GHz modal Header");
- len += ar9003_dump_modal_eeprom(buf, len, size,
+ len = ar9003_dump_modal_eeprom(buf, len, size,
&eep->modalHeader5G);
goto out;
}
@@ -3613,6 +3613,7 @@ static void ar9003_hw_ant_ctrl_apply(struct ath_hw *ah, bool is2ghz)
value = ar9003_switch_com_spdt_get(ah, is2ghz);
REG_RMW_FIELD(ah, AR_PHY_GLB_CONTROL,
AR_SWITCH_TABLE_COM_SPDT_ALL, value);
+ REG_SET_BIT(ah, AR_PHY_GLB_CONTROL, AR_BTCOEX_CTRL_SPDT_ENABLE);
}
value = ar9003_hw_ant_ctrl_common_2_get(ah, is2ghz);
diff --git a/drivers/net/wireless/ath/ath9k/ar9003_mci.c b/drivers/net/wireless/ath/ath9k/ar9003_mci.c
index ffbb180f91e..b1ced2a76da 100644
--- a/drivers/net/wireless/ath/ath9k/ar9003_mci.c
+++ b/drivers/net/wireless/ath/ath9k/ar9003_mci.c
@@ -35,31 +35,30 @@ static int ar9003_mci_wait_for_interrupt(struct ath_hw *ah, u32 address,
struct ath_common *common = ath9k_hw_common(ah);
while (time_out) {
- if (REG_READ(ah, address) & bit_position) {
- REG_WRITE(ah, address, bit_position);
-
- if (address == AR_MCI_INTERRUPT_RX_MSG_RAW) {
- if (bit_position &
- AR_MCI_INTERRUPT_RX_MSG_REQ_WAKE)
- ar9003_mci_reset_req_wakeup(ah);
-
- if (bit_position &
- (AR_MCI_INTERRUPT_RX_MSG_SYS_SLEEPING |
- AR_MCI_INTERRUPT_RX_MSG_SYS_WAKING))
- REG_WRITE(ah, AR_MCI_INTERRUPT_RAW,
- AR_MCI_INTERRUPT_REMOTE_SLEEP_UPDATE);
-
- REG_WRITE(ah, AR_MCI_INTERRUPT_RAW,
- AR_MCI_INTERRUPT_RX_MSG);
- }
- break;
- }
+ if (!(REG_READ(ah, address) & bit_position)) {
+ udelay(10);
+ time_out -= 10;
- udelay(10);
- time_out -= 10;
+ if (time_out < 0)
+ break;
+ else
+ continue;
+ }
+ REG_WRITE(ah, address, bit_position);
- if (time_out < 0)
+ if (address != AR_MCI_INTERRUPT_RX_MSG_RAW)
break;
+
+ if (bit_position & AR_MCI_INTERRUPT_RX_MSG_REQ_WAKE)
+ ar9003_mci_reset_req_wakeup(ah);
+
+ if (bit_position & (AR_MCI_INTERRUPT_RX_MSG_SYS_SLEEPING |
+ AR_MCI_INTERRUPT_RX_MSG_SYS_WAKING))
+ REG_WRITE(ah, AR_MCI_INTERRUPT_RAW,
+ AR_MCI_INTERRUPT_REMOTE_SLEEP_UPDATE);
+
+ REG_WRITE(ah, AR_MCI_INTERRUPT_RAW, AR_MCI_INTERRUPT_RX_MSG);
+ break;
}
if (time_out <= 0) {
@@ -127,14 +126,13 @@ static void ar9003_mci_send_coex_version_query(struct ath_hw *ah,
struct ath9k_hw_mci *mci = &ah->btcoex_hw.mci;
u32 payload[4] = {0, 0, 0, 0};
- if (!mci->bt_version_known &&
- (mci->bt_state != MCI_BT_SLEEP)) {
- MCI_GPM_SET_TYPE_OPCODE(payload,
- MCI_GPM_COEX_AGENT,
- MCI_GPM_COEX_VERSION_QUERY);
- ar9003_mci_send_message(ah, MCI_GPM, 0, payload, 16,
- wait_done, true);
- }
+ if (mci->bt_version_known ||
+ (mci->bt_state == MCI_BT_SLEEP))
+ return;
+
+ MCI_GPM_SET_TYPE_OPCODE(payload, MCI_GPM_COEX_AGENT,
+ MCI_GPM_COEX_VERSION_QUERY);
+ ar9003_mci_send_message(ah, MCI_GPM, 0, payload, 16, wait_done, true);
}
static void ar9003_mci_send_coex_version_response(struct ath_hw *ah,
@@ -158,15 +156,14 @@ static void ar9003_mci_send_coex_wlan_channels(struct ath_hw *ah,
struct ath9k_hw_mci *mci = &ah->btcoex_hw.mci;
u32 *payload = &mci->wlan_channels[0];
- if ((mci->wlan_channels_update == true) &&
- (mci->bt_state != MCI_BT_SLEEP)) {
- MCI_GPM_SET_TYPE_OPCODE(payload,
- MCI_GPM_COEX_AGENT,
- MCI_GPM_COEX_WLAN_CHANNELS);
- ar9003_mci_send_message(ah, MCI_GPM, 0, payload, 16,
- wait_done, true);
- MCI_GPM_SET_TYPE_OPCODE(payload, 0xff, 0xff);
- }
+ if (!mci->wlan_channels_update ||
+ (mci->bt_state == MCI_BT_SLEEP))
+ return;
+
+ MCI_GPM_SET_TYPE_OPCODE(payload, MCI_GPM_COEX_AGENT,
+ MCI_GPM_COEX_WLAN_CHANNELS);
+ ar9003_mci_send_message(ah, MCI_GPM, 0, payload, 16, wait_done, true);
+ MCI_GPM_SET_TYPE_OPCODE(payload, 0xff, 0xff);
}
static void ar9003_mci_send_coex_bt_status_query(struct ath_hw *ah,
@@ -174,29 +171,30 @@ static void ar9003_mci_send_coex_bt_status_query(struct ath_hw *ah,
{
struct ath9k_hw_mci *mci = &ah->btcoex_hw.mci;
u32 payload[4] = {0, 0, 0, 0};
- bool query_btinfo = !!(query_type & (MCI_GPM_COEX_QUERY_BT_ALL_INFO |
- MCI_GPM_COEX_QUERY_BT_TOPOLOGY));
-
- if (mci->bt_state != MCI_BT_SLEEP) {
+ bool query_btinfo;
- MCI_GPM_SET_TYPE_OPCODE(payload, MCI_GPM_COEX_AGENT,
- MCI_GPM_COEX_STATUS_QUERY);
+ if (mci->bt_state == MCI_BT_SLEEP)
+ return;
- *(((u8 *)payload) + MCI_GPM_COEX_B_BT_BITMAP) = query_type;
+ query_btinfo = !!(query_type & (MCI_GPM_COEX_QUERY_BT_ALL_INFO |
+ MCI_GPM_COEX_QUERY_BT_TOPOLOGY));
+ MCI_GPM_SET_TYPE_OPCODE(payload, MCI_GPM_COEX_AGENT,
+ MCI_GPM_COEX_STATUS_QUERY);
- /*
- * If bt_status_query message is not sent successfully,
- * then need_flush_btinfo should be set again.
- */
- if (!ar9003_mci_send_message(ah, MCI_GPM, 0, payload, 16,
- wait_done, true)) {
- if (query_btinfo)
- mci->need_flush_btinfo = true;
- }
+ *(((u8 *)payload) + MCI_GPM_COEX_B_BT_BITMAP) = query_type;
+ /*
+ * If bt_status_query message is not sent successfully,
+ * then need_flush_btinfo should be set again.
+ */
+ if (!ar9003_mci_send_message(ah, MCI_GPM, 0, payload, 16,
+ wait_done, true)) {
if (query_btinfo)
- mci->query_bt = false;
+ mci->need_flush_btinfo = true;
}
+
+ if (query_btinfo)
+ mci->query_bt = false;
}
static void ar9003_mci_send_coex_halt_bt_gpm(struct ath_hw *ah, bool halt,
@@ -241,73 +239,73 @@ static void ar9003_mci_prep_interface(struct ath_hw *ah)
ar9003_mci_remote_reset(ah, true);
ar9003_mci_send_req_wake(ah, true);
- if (ar9003_mci_wait_for_interrupt(ah, AR_MCI_INTERRUPT_RX_MSG_RAW,
- AR_MCI_INTERRUPT_RX_MSG_SYS_WAKING, 500)) {
+ if (!ar9003_mci_wait_for_interrupt(ah, AR_MCI_INTERRUPT_RX_MSG_RAW,
+ AR_MCI_INTERRUPT_RX_MSG_SYS_WAKING, 500))
+ goto clear_redunt;
- mci->bt_state = MCI_BT_AWAKE;
+ mci->bt_state = MCI_BT_AWAKE;
- /*
- * we don't need to send more remote_reset at this moment.
- * If BT receive first remote_reset, then BT HW will
- * be cleaned up and will be able to receive req_wake
- * and BT HW will respond sys_waking.
- * In this case, WLAN will receive BT's HW sys_waking.
- * Otherwise, if BT SW missed initial remote_reset,
- * that remote_reset will still clean up BT MCI RX,
- * and the req_wake will wake BT up,
- * and BT SW will respond this req_wake with a remote_reset and
- * sys_waking. In this case, WLAN will receive BT's SW
- * sys_waking. In either case, BT's RX is cleaned up. So we
- * don't need to reply BT's remote_reset now, if any.
- * Similarly, if in any case, WLAN can receive BT's sys_waking,
- * that means WLAN's RX is also fine.
- */
- ar9003_mci_send_sys_waking(ah, true);
- udelay(10);
+ /*
+ * we don't need to send more remote_reset at this moment.
+ * If BT receive first remote_reset, then BT HW will
+ * be cleaned up and will be able to receive req_wake
+ * and BT HW will respond sys_waking.
+ * In this case, WLAN will receive BT's HW sys_waking.
+ * Otherwise, if BT SW missed initial remote_reset,
+ * that remote_reset will still clean up BT MCI RX,
+ * and the req_wake will wake BT up,
+ * and BT SW will respond this req_wake with a remote_reset and
+ * sys_waking. In this case, WLAN will receive BT's SW
+ * sys_waking. In either case, BT's RX is cleaned up. So we
+ * don't need to reply BT's remote_reset now, if any.
+ * Similarly, if in any case, WLAN can receive BT's sys_waking,
+ * that means WLAN's RX is also fine.
+ */
+ ar9003_mci_send_sys_waking(ah, true);
+ udelay(10);
- /*
- * Set BT priority interrupt value to be 0xff to
- * avoid having too many BT PRIORITY interrupts.
- */
- REG_WRITE(ah, AR_MCI_BT_PRI0, 0xFFFFFFFF);
- REG_WRITE(ah, AR_MCI_BT_PRI1, 0xFFFFFFFF);
- REG_WRITE(ah, AR_MCI_BT_PRI2, 0xFFFFFFFF);
- REG_WRITE(ah, AR_MCI_BT_PRI3, 0xFFFFFFFF);
- REG_WRITE(ah, AR_MCI_BT_PRI, 0X000000FF);
+ /*
+ * Set BT priority interrupt value to be 0xff to
+ * avoid having too many BT PRIORITY interrupts.
+ */
+ REG_WRITE(ah, AR_MCI_BT_PRI0, 0xFFFFFFFF);
+ REG_WRITE(ah, AR_MCI_BT_PRI1, 0xFFFFFFFF);
+ REG_WRITE(ah, AR_MCI_BT_PRI2, 0xFFFFFFFF);
+ REG_WRITE(ah, AR_MCI_BT_PRI3, 0xFFFFFFFF);
+ REG_WRITE(ah, AR_MCI_BT_PRI, 0X000000FF);
- /*
- * A contention reset will be received after send out
- * sys_waking. Also BT priority interrupt bits will be set.
- * Clear those bits before the next step.
- */
+ /*
+ * A contention reset will be received after send out
+ * sys_waking. Also BT priority interrupt bits will be set.
+ * Clear those bits before the next step.
+ */
- REG_WRITE(ah, AR_MCI_INTERRUPT_RX_MSG_RAW,
- AR_MCI_INTERRUPT_RX_MSG_CONT_RST);
- REG_WRITE(ah, AR_MCI_INTERRUPT_RAW,
- AR_MCI_INTERRUPT_BT_PRI);
+ REG_WRITE(ah, AR_MCI_INTERRUPT_RX_MSG_RAW,
+ AR_MCI_INTERRUPT_RX_MSG_CONT_RST);
+ REG_WRITE(ah, AR_MCI_INTERRUPT_RAW, AR_MCI_INTERRUPT_BT_PRI);
- if (mci->is_2g) {
- ar9003_mci_send_lna_transfer(ah, true);
- udelay(5);
- }
+ if (mci->is_2g) {
+ ar9003_mci_send_lna_transfer(ah, true);
+ udelay(5);
+ }
- if ((mci->is_2g && !mci->update_2g5g)) {
- if (ar9003_mci_wait_for_interrupt(ah,
- AR_MCI_INTERRUPT_RX_MSG_RAW,
- AR_MCI_INTERRUPT_RX_MSG_LNA_INFO,
- mci_timeout))
- ath_dbg(common, MCI,
- "MCI WLAN has control over the LNA & BT obeys it\n");
- else
- ath_dbg(common, MCI,
- "MCI BT didn't respond to LNA_TRANS\n");
- }
+ if ((mci->is_2g && !mci->update_2g5g)) {
+ if (ar9003_mci_wait_for_interrupt(ah,
+ AR_MCI_INTERRUPT_RX_MSG_RAW,
+ AR_MCI_INTERRUPT_RX_MSG_LNA_INFO,
+ mci_timeout))
+ ath_dbg(common, MCI,
+ "MCI WLAN has control over the LNA & BT obeys it\n");
+ else
+ ath_dbg(common, MCI,
+ "MCI BT didn't respond to LNA_TRANS\n");
}
+clear_redunt:
/* Clear the extra redundant SYS_WAKING from BT */
if ((mci->bt_state == MCI_BT_AWAKE) &&
- (REG_READ_FIELD(ah, AR_MCI_INTERRUPT_RX_MSG_RAW,
- AR_MCI_INTERRUPT_RX_MSG_SYS_WAKING)) &&
+ (REG_READ_FIELD(ah, AR_MCI_INTERRUPT_RX_MSG_RAW,
+ AR_MCI_INTERRUPT_RX_MSG_SYS_WAKING)) &&
(REG_READ_FIELD(ah, AR_MCI_INTERRUPT_RX_MSG_RAW,
AR_MCI_INTERRUPT_RX_MSG_SYS_SLEEPING) == 0)) {
REG_WRITE(ah, AR_MCI_INTERRUPT_RX_MSG_RAW,
@@ -330,7 +328,6 @@ void ar9003_mci_set_full_sleep(struct ath_hw *ah)
}
mci->ready = false;
- REG_WRITE(ah, AR_RTC_KEEP_AWAKE, 0x2);
}
static void ar9003_mci_disable_interrupt(struct ath_hw *ah)
@@ -615,9 +612,9 @@ static u32 ar9003_mci_wait_for_gpm(struct ath_hw *ah, u8 gpm_type,
}
break;
}
- } else if ((recv_type == gpm_type) && (recv_opcode == gpm_opcode)) {
+ } else if ((recv_type == gpm_type) &&
+ (recv_opcode == gpm_opcode))
break;
- }
/*
* check if it's cal_grant
@@ -731,38 +728,38 @@ int ar9003_mci_end_reset(struct ath_hw *ah, struct ath9k_channel *chan,
if (!IS_CHAN_2GHZ(chan) || (mci_hw->bt_state != MCI_BT_SLEEP))
goto exit;
- if (ar9003_mci_check_int(ah, AR_MCI_INTERRUPT_RX_MSG_REMOTE_RESET) ||
- ar9003_mci_check_int(ah, AR_MCI_INTERRUPT_RX_MSG_REQ_WAKE)) {
+ if (!ar9003_mci_check_int(ah, AR_MCI_INTERRUPT_RX_MSG_REMOTE_RESET) &&
+ !ar9003_mci_check_int(ah, AR_MCI_INTERRUPT_RX_MSG_REQ_WAKE))
+ goto exit;
- /*
- * BT is sleeping. Check if BT wakes up during
- * WLAN calibration. If BT wakes up during
- * WLAN calibration, need to go through all
- * message exchanges again and recal.
- */
- REG_WRITE(ah, AR_MCI_INTERRUPT_RX_MSG_RAW,
- AR_MCI_INTERRUPT_RX_MSG_REMOTE_RESET |
- AR_MCI_INTERRUPT_RX_MSG_REQ_WAKE);
+ /*
+ * BT is sleeping. Check if BT wakes up during
+ * WLAN calibration. If BT wakes up during
+ * WLAN calibration, need to go through all
+ * message exchanges again and recal.
+ */
+ REG_WRITE(ah, AR_MCI_INTERRUPT_RX_MSG_RAW,
+ (AR_MCI_INTERRUPT_RX_MSG_REMOTE_RESET |
+ AR_MCI_INTERRUPT_RX_MSG_REQ_WAKE));
- ar9003_mci_remote_reset(ah, true);
- ar9003_mci_send_sys_waking(ah, true);
- udelay(1);
+ ar9003_mci_remote_reset(ah, true);
+ ar9003_mci_send_sys_waking(ah, true);
+ udelay(1);
- if (IS_CHAN_2GHZ(chan))
- ar9003_mci_send_lna_transfer(ah, true);
+ if (IS_CHAN_2GHZ(chan))
+ ar9003_mci_send_lna_transfer(ah, true);
- mci_hw->bt_state = MCI_BT_AWAKE;
+ mci_hw->bt_state = MCI_BT_AWAKE;
- if (caldata) {
- caldata->done_txiqcal_once = false;
- caldata->done_txclcal_once = false;
- caldata->rtt_done = false;
- }
+ if (caldata) {
+ caldata->done_txiqcal_once = false;
+ caldata->done_txclcal_once = false;
+ caldata->rtt_done = false;
+ }
- if (!ath9k_hw_init_cal(ah, chan))
- return -EIO;
+ if (!ath9k_hw_init_cal(ah, chan))
+ return -EIO;
- }
exit:
ar9003_mci_enable_interrupt(ah);
return 0;
@@ -798,29 +795,27 @@ static void ar9003_mci_osla_setup(struct ath_hw *ah, bool enable)
struct ath9k_hw_mci *mci = &ah->btcoex_hw.mci;
u32 thresh;
- if (enable) {
- REG_RMW_FIELD(ah, AR_MCI_SCHD_TABLE_2,
- AR_MCI_SCHD_TABLE_2_HW_BASED, 1);
- REG_RMW_FIELD(ah, AR_MCI_SCHD_TABLE_2,
- AR_MCI_SCHD_TABLE_2_MEM_BASED, 1);
-
- if (!(mci->config & ATH_MCI_CONFIG_DISABLE_AGGR_THRESH)) {
- thresh = MS(mci->config, ATH_MCI_CONFIG_AGGR_THRESH);
- REG_RMW_FIELD(ah, AR_BTCOEX_CTRL,
- AR_BTCOEX_CTRL_AGGR_THRESH, thresh);
- REG_RMW_FIELD(ah, AR_BTCOEX_CTRL,
- AR_BTCOEX_CTRL_TIME_TO_NEXT_BT_THRESH_EN, 1);
- } else {
- REG_RMW_FIELD(ah, AR_BTCOEX_CTRL,
- AR_BTCOEX_CTRL_TIME_TO_NEXT_BT_THRESH_EN, 0);
- }
-
- REG_RMW_FIELD(ah, AR_BTCOEX_CTRL,
- AR_BTCOEX_CTRL_ONE_STEP_LOOK_AHEAD_EN, 1);
- } else {
+ if (!enable) {
REG_CLR_BIT(ah, AR_BTCOEX_CTRL,
AR_BTCOEX_CTRL_ONE_STEP_LOOK_AHEAD_EN);
+ return;
}
+ REG_RMW_FIELD(ah, AR_MCI_SCHD_TABLE_2, AR_MCI_SCHD_TABLE_2_HW_BASED, 1);
+ REG_RMW_FIELD(ah, AR_MCI_SCHD_TABLE_2,
+ AR_MCI_SCHD_TABLE_2_MEM_BASED, 1);
+
+ if (!(mci->config & ATH_MCI_CONFIG_DISABLE_AGGR_THRESH)) {
+ thresh = MS(mci->config, ATH_MCI_CONFIG_AGGR_THRESH);
+ REG_RMW_FIELD(ah, AR_BTCOEX_CTRL,
+ AR_BTCOEX_CTRL_AGGR_THRESH, thresh);
+ REG_RMW_FIELD(ah, AR_BTCOEX_CTRL,
+ AR_BTCOEX_CTRL_TIME_TO_NEXT_BT_THRESH_EN, 1);
+ } else
+ REG_RMW_FIELD(ah, AR_BTCOEX_CTRL,
+ AR_BTCOEX_CTRL_TIME_TO_NEXT_BT_THRESH_EN, 0);
+
+ REG_RMW_FIELD(ah, AR_BTCOEX_CTRL,
+ AR_BTCOEX_CTRL_ONE_STEP_LOOK_AHEAD_EN, 1);
}
void ar9003_mci_reset(struct ath_hw *ah, bool en_int, bool is_2g,
@@ -943,26 +938,27 @@ static void ar9003_mci_send_2g5g_status(struct ath_hw *ah, bool wait_done)
struct ath9k_hw_mci *mci = &ah->btcoex_hw.mci;
u32 new_flags, to_set, to_clear;
- if (mci->update_2g5g && (mci->bt_state != MCI_BT_SLEEP)) {
- if (mci->is_2g) {
- new_flags = MCI_2G_FLAGS;
- to_clear = MCI_2G_FLAGS_CLEAR_MASK;
- to_set = MCI_2G_FLAGS_SET_MASK;
- } else {
- new_flags = MCI_5G_FLAGS;
- to_clear = MCI_5G_FLAGS_CLEAR_MASK;
- to_set = MCI_5G_FLAGS_SET_MASK;
- }
+ if (!mci->update_2g5g || (mci->bt_state == MCI_BT_SLEEP))
+ return;
+
+ if (mci->is_2g) {
+ new_flags = MCI_2G_FLAGS;
+ to_clear = MCI_2G_FLAGS_CLEAR_MASK;
+ to_set = MCI_2G_FLAGS_SET_MASK;
+ } else {
+ new_flags = MCI_5G_FLAGS;
+ to_clear = MCI_5G_FLAGS_CLEAR_MASK;
+ to_set = MCI_5G_FLAGS_SET_MASK;
+ }
- if (to_clear)
- ar9003_mci_send_coex_bt_flags(ah, wait_done,
+ if (to_clear)
+ ar9003_mci_send_coex_bt_flags(ah, wait_done,
MCI_GPM_COEX_BT_FLAGS_CLEAR,
to_clear);
- if (to_set)
- ar9003_mci_send_coex_bt_flags(ah, wait_done,
+ if (to_set)
+ ar9003_mci_send_coex_bt_flags(ah, wait_done,
MCI_GPM_COEX_BT_FLAGS_SET,
to_set);
- }
}
static void ar9003_mci_queue_unsent_gpm(struct ath_hw *ah, u8 header,
@@ -1018,34 +1014,34 @@ void ar9003_mci_2g5g_switch(struct ath_hw *ah, bool wait_done)
{
struct ath9k_hw_mci *mci = &ah->btcoex_hw.mci;
- if (mci->update_2g5g) {
- if (mci->is_2g) {
- ar9003_mci_send_2g5g_status(ah, true);
- ar9003_mci_send_lna_transfer(ah, true);
- udelay(5);
+ if (!mci->update_2g5g)
+ return;
- REG_CLR_BIT(ah, AR_MCI_TX_CTRL,
- AR_MCI_TX_CTRL_DISABLE_LNA_UPDATE);
- REG_CLR_BIT(ah, AR_PHY_GLB_CONTROL,
- AR_BTCOEX_CTRL_BT_OWN_SPDT_CTRL);
+ if (mci->is_2g) {
+ ar9003_mci_send_2g5g_status(ah, true);
+ ar9003_mci_send_lna_transfer(ah, true);
+ udelay(5);
- if (!(mci->config & ATH_MCI_CONFIG_DISABLE_OSLA)) {
- REG_SET_BIT(ah, AR_BTCOEX_CTRL,
- AR_BTCOEX_CTRL_ONE_STEP_LOOK_AHEAD_EN);
- }
- } else {
- ar9003_mci_send_lna_take(ah, true);
- udelay(5);
-
- REG_SET_BIT(ah, AR_MCI_TX_CTRL,
- AR_MCI_TX_CTRL_DISABLE_LNA_UPDATE);
- REG_SET_BIT(ah, AR_PHY_GLB_CONTROL,
- AR_BTCOEX_CTRL_BT_OWN_SPDT_CTRL);
- REG_CLR_BIT(ah, AR_BTCOEX_CTRL,
+ REG_CLR_BIT(ah, AR_MCI_TX_CTRL,
+ AR_MCI_TX_CTRL_DISABLE_LNA_UPDATE);
+ REG_CLR_BIT(ah, AR_PHY_GLB_CONTROL,
+ AR_BTCOEX_CTRL_BT_OWN_SPDT_CTRL);
+
+ if (!(mci->config & ATH_MCI_CONFIG_DISABLE_OSLA))
+ REG_SET_BIT(ah, AR_BTCOEX_CTRL,
AR_BTCOEX_CTRL_ONE_STEP_LOOK_AHEAD_EN);
+ } else {
+ ar9003_mci_send_lna_take(ah, true);
+ udelay(5);
- ar9003_mci_send_2g5g_status(ah, true);
- }
+ REG_SET_BIT(ah, AR_MCI_TX_CTRL,
+ AR_MCI_TX_CTRL_DISABLE_LNA_UPDATE);
+ REG_SET_BIT(ah, AR_PHY_GLB_CONTROL,
+ AR_BTCOEX_CTRL_BT_OWN_SPDT_CTRL);
+ REG_CLR_BIT(ah, AR_BTCOEX_CTRL,
+ AR_BTCOEX_CTRL_ONE_STEP_LOOK_AHEAD_EN);
+
+ ar9003_mci_send_2g5g_status(ah, true);
}
}
@@ -1132,7 +1128,7 @@ void ar9003_mci_init_cal_req(struct ath_hw *ah, bool *is_reusable)
if (ar9003_mci_wait_for_gpm(ah, MCI_GPM_BT_CAL_GRANT, 0, 50000)) {
ath_dbg(common, MCI, "MCI BT_CAL_GRANT received\n");
} else {
- is_reusable = false;
+ *is_reusable = false;
ath_dbg(common, MCI, "MCI BT_CAL_GRANT not received\n");
}
}
@@ -1259,12 +1255,12 @@ u32 ar9003_mci_state(struct ath_hw *ah, u32 state_type, u32 *p_data)
}
if (p_data)
*p_data = more_gpm;
- }
+ }
- if (value != MCI_GPM_INVALID)
- value <<= 4;
+ if (value != MCI_GPM_INVALID)
+ value <<= 4;
- break;
+ break;
case MCI_STATE_LAST_SCHD_MSG_OFFSET:
value = MS(REG_READ(ah, AR_MCI_RX_STATUS),
AR_MCI_RX_LAST_SCHD_MSG_INDEX);
@@ -1359,24 +1355,22 @@ u32 ar9003_mci_state(struct ath_hw *ah, u32 state_type, u32 *p_data)
ar9003_mci_send_coex_bt_status_query(ah, true, query_type);
break;
case MCI_STATE_NEED_FLUSH_BT_INFO:
- /*
- * btcoex_hw.mci.unhalt_bt_gpm means whether it's
- * needed to send UNHALT message. It's set whenever
- * there's a request to send HALT message.
- * mci_halted_bt_gpm means whether HALT message is sent
- * out successfully.
- *
- * Checking (mci_unhalt_bt_gpm == false) instead of
- * checking (ah->mci_halted_bt_gpm == false) will make
- * sure currently is in UNHALT-ed mode and BT can
- * respond to status query.
- */
- value = (!mci->unhalt_bt_gpm &&
- mci->need_flush_btinfo) ? 1 : 0;
- if (p_data)
- mci->need_flush_btinfo =
- (*p_data != 0) ? true : false;
- break;
+ /*
+ * btcoex_hw.mci.unhalt_bt_gpm means whether it's
+ * needed to send UNHALT message. It's set whenever
+ * there's a request to send HALT message.
+ * mci_halted_bt_gpm means whether HALT message is sent
+ * out successfully.
+ *
+ * Checking (mci_unhalt_bt_gpm == false) instead of
+ * checking (ah->mci_halted_bt_gpm == false) will make
+ * sure currently is in UNHALT-ed mode and BT can
+ * respond to status query.
+ */
+ value = (!mci->unhalt_bt_gpm && mci->need_flush_btinfo) ? 1 : 0;
+ if (p_data)
+ mci->need_flush_btinfo = (*p_data != 0) ? true : false;
+ break;
case MCI_STATE_RECOVER_RX:
ar9003_mci_prep_interface(ah);
mci->query_bt = true;
@@ -1387,9 +1381,6 @@ u32 ar9003_mci_state(struct ath_hw *ah, u32 state_type, u32 *p_data)
case MCI_STATE_NEED_FTP_STOMP:
value = !(mci->config & ATH_MCI_CONFIG_DISABLE_FTP_STOMP);
break;
- case MCI_STATE_NEED_TUNING:
- value = !(mci->config & ATH_MCI_CONFIG_DISABLE_TUNING);
- break;
default:
break;
}
@@ -1397,3 +1388,19 @@ u32 ar9003_mci_state(struct ath_hw *ah, u32 state_type, u32 *p_data)
return value;
}
EXPORT_SYMBOL(ar9003_mci_state);
+
+void ar9003_mci_bt_gain_ctrl(struct ath_hw *ah)
+{
+ struct ath_common *common = ath9k_hw_common(ah);
+ struct ath9k_hw_mci *mci = &ah->btcoex_hw.mci;
+
+ ath_dbg(common, MCI, "Give LNA and SPDT control to BT\n");
+
+ REG_SET_BIT(ah, AR_PHY_GLB_CONTROL, AR_BTCOEX_CTRL_BT_OWN_SPDT_CTRL);
+ mci->is_2g = false;
+ mci->update_2g5g = true;
+ ar9003_mci_send_2g5g_status(ah, true);
+
+ /* Force another 2g5g update at next scanning */
+ mci->update_2g5g = true;
+}
diff --git a/drivers/net/wireless/ath/ath9k/ar9003_mci.h b/drivers/net/wireless/ath/ath9k/ar9003_mci.h
index 4842f6c06b8..10282e2bcdc 100644
--- a/drivers/net/wireless/ath/ath9k/ar9003_mci.h
+++ b/drivers/net/wireless/ath/ath9k/ar9003_mci.h
@@ -212,7 +212,6 @@ enum mci_state_type {
MCI_STATE_SET_CONCUR_TX_PRI,
MCI_STATE_RECOVER_RX,
MCI_STATE_NEED_FTP_STOMP,
- MCI_STATE_NEED_TUNING,
MCI_STATE_DEBUG,
MCI_STATE_MAX
};
@@ -266,6 +265,7 @@ void ar9003_mci_setup(struct ath_hw *ah, u32 gpm_addr, void *gpm_buf,
void ar9003_mci_cleanup(struct ath_hw *ah);
void ar9003_mci_get_interrupt(struct ath_hw *ah, u32 *raw_intr,
u32 *rx_msg_intr);
+void ar9003_mci_bt_gain_ctrl(struct ath_hw *ah);
/*
* These functions are used by ath9k_hw.
@@ -273,10 +273,6 @@ void ar9003_mci_get_interrupt(struct ath_hw *ah, u32 *raw_intr,
#ifdef CONFIG_ATH9K_BTCOEX_SUPPORT
-static inline bool ar9003_mci_is_ready(struct ath_hw *ah)
-{
- return ah->btcoex_hw.mci.ready;
-}
void ar9003_mci_stop_bt(struct ath_hw *ah, bool save_fullsleep);
void ar9003_mci_init_cal_req(struct ath_hw *ah, bool *is_reusable);
void ar9003_mci_init_cal_done(struct ath_hw *ah);
@@ -292,10 +288,6 @@ void ar9003_mci_get_isr(struct ath_hw *ah, enum ath9k_int *masked);
#else
-static inline bool ar9003_mci_is_ready(struct ath_hw *ah)
-{
- return false;
-}
static inline void ar9003_mci_stop_bt(struct ath_hw *ah, bool save_fullsleep)
{
}
diff --git a/drivers/net/wireless/ath/ath9k/ar9003_phy.c b/drivers/net/wireless/ath/ath9k/ar9003_phy.c
index 11abb972be1..d6baf69cdc1 100644
--- a/drivers/net/wireless/ath/ath9k/ar9003_phy.c
+++ b/drivers/net/wireless/ath/ath9k/ar9003_phy.c
@@ -676,6 +676,10 @@ static int ar9003_hw_process_ini(struct ath_hw *ah,
if (chan->channel == 2484)
ar9003_hw_prog_ini(ah, &ah->ini_japan2484, 1);
+ if (AR_SREV_9462(ah))
+ REG_WRITE(ah, AR_GLB_SWREG_DISCONT_MODE,
+ AR_GLB_SWREG_DISCONT_EN_BT_WLAN);
+
ah->modes_index = modesIndex;
ar9003_hw_override_ini(ah);
ar9003_hw_set_channel_regs(ah, chan);
diff --git a/drivers/net/wireless/ath/ath9k/ar9003_phy.h b/drivers/net/wireless/ath/ath9k/ar9003_phy.h
index 7268a48a92a..ed662c3bae5 100644
--- a/drivers/net/wireless/ath/ath9k/ar9003_phy.h
+++ b/drivers/net/wireless/ath/ath9k/ar9003_phy.h
@@ -820,18 +820,26 @@
#define AR_PHY_CHAN_INFO_MEMORY_CAPTURE_MASK 0x0001
#define AR_PHY_RX_DELAY_DELAY 0x00003FFF
#define AR_PHY_CCK_TX_CTRL_JAPAN 0x00000010
-#define AR_PHY_SPECTRAL_SCAN_ENABLE 0x00000001
-#define AR_PHY_SPECTRAL_SCAN_ENABLE_S 0
-#define AR_PHY_SPECTRAL_SCAN_ACTIVE 0x00000002
-#define AR_PHY_SPECTRAL_SCAN_ACTIVE_S 1
-#define AR_PHY_SPECTRAL_SCAN_FFT_PERIOD 0x000000F0
-#define AR_PHY_SPECTRAL_SCAN_FFT_PERIOD_S 4
-#define AR_PHY_SPECTRAL_SCAN_PERIOD 0x0000FF00
-#define AR_PHY_SPECTRAL_SCAN_PERIOD_S 8
-#define AR_PHY_SPECTRAL_SCAN_COUNT 0x00FF0000
-#define AR_PHY_SPECTRAL_SCAN_COUNT_S 16
-#define AR_PHY_SPECTRAL_SCAN_SHORT_REPEAT 0x01000000
-#define AR_PHY_SPECTRAL_SCAN_SHORT_REPEAT_S 24
+
+#define AR_PHY_SPECTRAL_SCAN_ENABLE 0x00000001
+#define AR_PHY_SPECTRAL_SCAN_ENABLE_S 0
+#define AR_PHY_SPECTRAL_SCAN_ACTIVE 0x00000002
+#define AR_PHY_SPECTRAL_SCAN_ACTIVE_S 1
+#define AR_PHY_SPECTRAL_SCAN_FFT_PERIOD 0x000000F0
+#define AR_PHY_SPECTRAL_SCAN_FFT_PERIOD_S 4
+#define AR_PHY_SPECTRAL_SCAN_PERIOD 0x0000FF00
+#define AR_PHY_SPECTRAL_SCAN_PERIOD_S 8
+#define AR_PHY_SPECTRAL_SCAN_COUNT 0x0FFF0000
+#define AR_PHY_SPECTRAL_SCAN_COUNT_S 16
+#define AR_PHY_SPECTRAL_SCAN_SHORT_REPEAT 0x10000000
+#define AR_PHY_SPECTRAL_SCAN_SHORT_REPEAT_S 28
+#define AR_PHY_SPECTRAL_SCAN_PRIORITY 0x20000000
+#define AR_PHY_SPECTRAL_SCAN_PRIORITY_S 29
+#define AR_PHY_SPECTRAL_SCAN_USE_ERR5 0x40000000
+#define AR_PHY_SPECTRAL_SCAN_USE_ERR5_S 30
+#define AR_PHY_SPECTRAL_SCAN_COMPRESSED_RPT 0x80000000
+#define AR_PHY_SPECTRAL_SCAN_COMPRESSED_RPT_S 31
+
#define AR_PHY_CHANNEL_STATUS_RX_CLEAR 0x00000004
#define AR_PHY_RTT_CTRL_ENA_RADIO_RETENTION 0x00000001
#define AR_PHY_RTT_CTRL_ENA_RADIO_RETENTION_S 0
diff --git a/drivers/net/wireless/ath/ath9k/ar9462_2p0_initvals.h b/drivers/net/wireless/ath/ath9k/ar9462_2p0_initvals.h
index 1d6658e139b..a10ece0cb6c 100644
--- a/drivers/net/wireless/ath/ath9k/ar9462_2p0_initvals.h
+++ b/drivers/net/wireless/ath/ath9k/ar9462_2p0_initvals.h
@@ -958,7 +958,7 @@ static const u32 ar9462_2p0_radio_core[][2] = {
{0x0001604c, 0x2699e04f},
{0x00016050, 0x6db6db6c},
{0x00016058, 0x6c200000},
- {0x00016080, 0x00040000},
+ {0x00016080, 0x000c0000},
{0x00016084, 0x9a68048c},
{0x00016088, 0x54214514},
{0x0001608c, 0x1203040b},
@@ -981,7 +981,7 @@ static const u32 ar9462_2p0_radio_core[][2] = {
{0x00016144, 0x02084080},
{0x00016148, 0x000080c0},
{0x00016280, 0x050a0001},
- {0x00016284, 0x3d841400},
+ {0x00016284, 0x3d841418},
{0x00016288, 0x00000000},
{0x0001628c, 0xe3000000},
{0x00016290, 0xa1005080},
diff --git a/drivers/net/wireless/ath/ath9k/ath9k.h b/drivers/net/wireless/ath/ath9k/ath9k.h
index a277cf6f339..02fc1c1e5ee 100644
--- a/drivers/net/wireless/ath/ath9k/ath9k.h
+++ b/drivers/net/wireless/ath/ath9k/ath9k.h
@@ -307,6 +307,7 @@ struct ath_rx {
u8 defant;
u8 rxotherant;
u32 *rxlink;
+ u32 num_pkts;
unsigned int rxfilter;
spinlock_t rxbuflock;
struct list_head rxbuf;
@@ -325,6 +326,9 @@ int ath_rx_init(struct ath_softc *sc, int nbufs);
void ath_rx_cleanup(struct ath_softc *sc);
int ath_rx_tasklet(struct ath_softc *sc, int flush, bool hp);
struct ath_txq *ath_txq_setup(struct ath_softc *sc, int qtype, int subtype);
+void ath_txq_lock(struct ath_softc *sc, struct ath_txq *txq);
+void ath_txq_unlock(struct ath_softc *sc, struct ath_txq *txq);
+void ath_txq_unlock_complete(struct ath_softc *sc, struct ath_txq *txq);
void ath_tx_cleanupq(struct ath_softc *sc, struct ath_txq *txq);
bool ath_drain_all_txq(struct ath_softc *sc, bool retry_tx);
void ath_draintxq(struct ath_softc *sc,
@@ -414,9 +418,9 @@ int ath_beaconq_config(struct ath_softc *sc);
void ath_set_beacon(struct ath_softc *sc);
void ath9k_set_beaconing_status(struct ath_softc *sc, bool status);
-/*******/
-/* ANI */
-/*******/
+/*******************/
+/* Link Monitoring */
+/*******************/
#define ATH_STA_SHORT_CALINTERVAL 1000 /* 1 second */
#define ATH_AP_SHORT_CALINTERVAL 100 /* 100 ms */
@@ -427,7 +431,9 @@ void ath9k_set_beaconing_status(struct ath_softc *sc, bool status);
#define ATH_RESTART_CALINTERVAL 1200000 /* 20 minutes */
#define ATH_PAPRD_TIMEOUT 100 /* msecs */
+#define ATH_PLL_WORK_INTERVAL 100
+void ath_tx_complete_poll_work(struct work_struct *work);
void ath_reset_work(struct work_struct *work);
void ath_hw_check(struct work_struct *work);
void ath_hw_pll_work(struct work_struct *work);
@@ -436,22 +442,31 @@ void ath_start_rx_poll(struct ath_softc *sc, u8 nbeacon);
void ath_paprd_calibrate(struct work_struct *work);
void ath_ani_calibrate(unsigned long data);
void ath_start_ani(struct ath_common *common);
+int ath_update_survey_stats(struct ath_softc *sc);
+void ath_update_survey_nf(struct ath_softc *sc, int channel);
/**********/
/* BTCOEX */
/**********/
+enum bt_op_flags {
+ BT_OP_PRIORITY_DETECTED,
+ BT_OP_SCAN,
+};
+
struct ath_btcoex {
bool hw_timer_enabled;
spinlock_t btcoex_lock;
struct timer_list period_timer; /* Timer for BT period */
u32 bt_priority_cnt;
unsigned long bt_priority_time;
+ unsigned long op_flags;
int bt_stomp_type; /* Types of BT stomping */
u32 btcoex_no_stomp; /* in usec */
u32 btcoex_period; /* in usec */
u32 btscan_no_stomp; /* in usec */
u32 duty_cycle;
+ u32 bt_wait_time;
struct ath_gen_timer *no_stomp_timer; /* Timer for no BT stomping */
struct ath_mci_profile mci;
};
@@ -513,8 +528,10 @@ static inline void ath_deinit_leds(struct ath_softc *sc)
}
#endif
-
+/*******************************/
/* Antenna diversity/combining */
+/*******************************/
+
#define ATH_ANT_RX_CURRENT_SHIFT 4
#define ATH_ANT_RX_MAIN_SHIFT 2
#define ATH_ANT_RX_MASK 0x3
@@ -567,6 +584,9 @@ struct ath_ant_comb {
unsigned long scan_start_time;
};
+void ath_ant_comb_scan(struct ath_softc *sc, struct ath_rx_status *rs);
+void ath_ant_comb_update(struct ath_softc *sc);
+
/********************/
/* Main driver core */
/********************/
@@ -584,15 +604,15 @@ struct ath_ant_comb {
#define ATH_TXPOWER_MAX 100 /* .5 dBm units */
#define ATH_RATE_DUMMY_MARKER 0
-#define SC_OP_INVALID BIT(0)
-#define SC_OP_BEACONS BIT(1)
-#define SC_OP_OFFCHANNEL BIT(2)
-#define SC_OP_RXFLUSH BIT(3)
-#define SC_OP_TSF_RESET BIT(4)
-#define SC_OP_BT_PRIORITY_DETECTED BIT(5)
-#define SC_OP_BT_SCAN BIT(6)
-#define SC_OP_ANI_RUN BIT(7)
-#define SC_OP_PRIM_STA_VIF BIT(8)
+enum sc_op_flags {
+ SC_OP_INVALID,
+ SC_OP_BEACONS,
+ SC_OP_RXFLUSH,
+ SC_OP_TSF_RESET,
+ SC_OP_ANI_RUN,
+ SC_OP_PRIM_STA_VIF,
+ SC_OP_HW_RESET,
+};
/* Powersave flags */
#define PS_WAIT_FOR_BEACON BIT(0)
@@ -638,9 +658,9 @@ struct ath_softc {
struct completion paprd_complete;
unsigned int hw_busy_count;
+ unsigned long sc_flags;
u32 intrstatus;
- u32 sc_flags; /* SC_OP_* */
u16 ps_flags; /* PS_* */
u16 curtxpow;
bool ps_enabled;
@@ -736,5 +756,4 @@ void ath9k_calculate_iter_data(struct ieee80211_hw *hw,
struct ieee80211_vif *vif,
struct ath9k_vif_iter_data *iter_data);
-
#endif /* ATH9K_H */
diff --git a/drivers/net/wireless/ath/ath9k/beacon.c b/drivers/net/wireless/ath/ath9k/beacon.c
index 11bc55e3d69..40775da8941 100644
--- a/drivers/net/wireless/ath/ath9k/beacon.c
+++ b/drivers/net/wireless/ath/ath9k/beacon.c
@@ -48,7 +48,10 @@ int ath_beaconq_config(struct ath_softc *sc)
txq = sc->tx.txq_map[WME_AC_BE];
ath9k_hw_get_txq_props(ah, txq->axq_qnum, &qi_be);
qi.tqi_aifs = qi_be.tqi_aifs;
- qi.tqi_cwmin = 4*qi_be.tqi_cwmin;
+ if (ah->slottime == ATH9K_SLOT_TIME_20)
+ qi.tqi_cwmin = 2*qi_be.tqi_cwmin;
+ else
+ qi.tqi_cwmin = 4*qi_be.tqi_cwmin;
qi.tqi_cwmax = qi_be.tqi_cwmax;
}
@@ -387,7 +390,7 @@ void ath_beacon_tasklet(unsigned long data)
} else if (sc->beacon.bmisscnt >= BSTUCK_THRESH) {
ath_dbg(common, BSTUCK, "beacon is officially stuck\n");
sc->beacon.bmisscnt = 0;
- sc->sc_flags |= SC_OP_TSF_RESET;
+ set_bit(SC_OP_TSF_RESET, &sc->sc_flags);
ieee80211_queue_work(sc->hw, &sc->hw_reset_work);
}
@@ -477,16 +480,16 @@ static void ath9k_beacon_init(struct ath_softc *sc,
u32 next_beacon,
u32 beacon_period)
{
- if (sc->sc_flags & SC_OP_TSF_RESET) {
+ if (test_bit(SC_OP_TSF_RESET, &sc->sc_flags)) {
ath9k_ps_wakeup(sc);
ath9k_hw_reset_tsf(sc->sc_ah);
}
ath9k_hw_beaconinit(sc->sc_ah, next_beacon, beacon_period);
- if (sc->sc_flags & SC_OP_TSF_RESET) {
+ if (test_bit(SC_OP_TSF_RESET, &sc->sc_flags)) {
ath9k_ps_restore(sc);
- sc->sc_flags &= ~SC_OP_TSF_RESET;
+ clear_bit(SC_OP_TSF_RESET, &sc->sc_flags);
}
}
@@ -516,7 +519,7 @@ static void ath_beacon_config_ap(struct ath_softc *sc,
/* Set the computed AP beacon timers */
ath9k_hw_disable_interrupts(ah);
- sc->sc_flags |= SC_OP_TSF_RESET;
+ set_bit(SC_OP_TSF_RESET, &sc->sc_flags);
ath9k_beacon_init(sc, nexttbtt, intval);
sc->beacon.bmisscnt = 0;
ath9k_hw_set_interrupts(ah);
@@ -659,7 +662,7 @@ static void ath_beacon_config_adhoc(struct ath_softc *sc,
u32 tsf, intval, nexttbtt;
ath9k_reset_beacon_status(sc);
- if (!(sc->sc_flags & SC_OP_BEACONS))
+ if (!test_bit(SC_OP_BEACONS, &sc->sc_flags))
ath9k_hw_settsf64(ah, sc->beacon.bc_tstamp);
intval = TU_TO_USEC(conf->beacon_interval);
@@ -724,7 +727,7 @@ static bool ath9k_allow_beacon_config(struct ath_softc *sc,
*/
if ((sc->sc_ah->opmode == NL80211_IFTYPE_STATION) &&
(vif->type == NL80211_IFTYPE_STATION) &&
- (sc->sc_flags & SC_OP_BEACONS) &&
+ test_bit(SC_OP_BEACONS, &sc->sc_flags) &&
!avp->primary_sta_vif) {
ath_dbg(common, CONFIG,
"Beacon already configured for a station interface\n");
@@ -810,7 +813,7 @@ void ath_set_beacon(struct ath_softc *sc)
return;
}
- sc->sc_flags |= SC_OP_BEACONS;
+ set_bit(SC_OP_BEACONS, &sc->sc_flags);
}
void ath9k_set_beaconing_status(struct ath_softc *sc, bool status)
@@ -818,7 +821,7 @@ void ath9k_set_beaconing_status(struct ath_softc *sc, bool status)
struct ath_hw *ah = sc->sc_ah;
if (!ath_has_valid_bslot(sc)) {
- sc->sc_flags &= ~SC_OP_BEACONS;
+ clear_bit(SC_OP_BEACONS, &sc->sc_flags);
return;
}
diff --git a/drivers/net/wireless/ath/ath9k/btcoex.c b/drivers/net/wireless/ath/ath9k/btcoex.c
index 1ca6da80d4a..acd437384fe 100644
--- a/drivers/net/wireless/ath/ath9k/btcoex.c
+++ b/drivers/net/wireless/ath/ath9k/btcoex.c
@@ -336,10 +336,16 @@ static void ar9003_btcoex_bt_stomp(struct ath_hw *ah,
enum ath_stomp_type stomp_type)
{
struct ath_btcoex_hw *btcoex = &ah->btcoex_hw;
- const u32 *weight = AR_SREV_9462(ah) ? ar9003_wlan_weights[stomp_type] :
- ar9462_wlan_weights[stomp_type];
+ const u32 *weight = ar9003_wlan_weights[stomp_type];
int i;
+ if (AR_SREV_9462(ah)) {
+ if ((stomp_type == ATH_BTCOEX_STOMP_LOW) &&
+ btcoex->mci.stomp_ftp)
+ stomp_type = ATH_BTCOEX_STOMP_LOW_FTP;
+ weight = ar9462_wlan_weights[stomp_type];
+ }
+
for (i = 0; i < AR9300_NUM_WLAN_WEIGHTS; i++) {
btcoex->bt_weight[i] = AR9300_BT_WGHT;
btcoex->wlan_weight[i] = weight[i];
diff --git a/drivers/net/wireless/ath/ath9k/btcoex.h b/drivers/net/wireless/ath/ath9k/btcoex.h
index 3a1e1cfabd5..20092f98658 100644
--- a/drivers/net/wireless/ath/ath9k/btcoex.h
+++ b/drivers/net/wireless/ath/ath9k/btcoex.h
@@ -36,6 +36,9 @@
#define ATH_BT_CNT_THRESHOLD 3
#define ATH_BT_CNT_SCAN_THRESHOLD 15
+#define ATH_BTCOEX_RX_WAIT_TIME 100
+#define ATH_BTCOEX_STOMP_FTP_THRESH 5
+
#define AR9300_NUM_BT_WEIGHTS 4
#define AR9300_NUM_WLAN_WEIGHTS 4
/* Defines the BT AR_BT_COEX_WGHT used */
@@ -80,6 +83,7 @@ struct ath9k_hw_mci {
u8 bt_ver_major;
u8 bt_ver_minor;
u8 bt_state;
+ u8 stomp_ftp;
};
struct ath_btcoex_hw {
diff --git a/drivers/net/wireless/ath/ath9k/debug.c b/drivers/net/wireless/ath/ath9k/debug.c
index fde700c4e49..2831258d950 100644
--- a/drivers/net/wireless/ath/ath9k/debug.c
+++ b/drivers/net/wireless/ath/ath9k/debug.c
@@ -205,10 +205,10 @@ static ssize_t write_file_disable_ani(struct file *file,
common->disable_ani = !!disable_ani;
if (disable_ani) {
- sc->sc_flags &= ~SC_OP_ANI_RUN;
+ clear_bit(SC_OP_ANI_RUN, &sc->sc_flags);
del_timer_sync(&common->ani.timer);
} else {
- sc->sc_flags |= SC_OP_ANI_RUN;
+ set_bit(SC_OP_ANI_RUN, &sc->sc_flags);
ath_start_ani(common);
}
@@ -374,6 +374,8 @@ void ath_debug_stat_interrupt(struct ath_softc *sc, enum ath9k_int status)
sc->debug.stats.istats.dtim++;
if (status & ATH9K_INT_TSFOOR)
sc->debug.stats.istats.tsfoor++;
+ if (status & ATH9K_INT_MCI)
+ sc->debug.stats.istats.mci++;
}
static ssize_t read_file_interrupt(struct file *file, char __user *user_buf,
@@ -418,6 +420,7 @@ static ssize_t read_file_interrupt(struct file *file, char __user *user_buf,
PR_IS("DTIMSYNC", dtimsync);
PR_IS("DTIM", dtim);
PR_IS("TSFOOR", tsfoor);
+ PR_IS("MCI", mci);
PR_IS("TOTAL", total);
len += snprintf(buf + len, mxlen - len,
@@ -1318,7 +1321,7 @@ static int open_file_bb_mac_samps(struct inode *inode, struct file *file)
u8 chainmask = (ah->rxchainmask << 3) | ah->rxchainmask;
u8 nread;
- if (sc->sc_flags & SC_OP_INVALID)
+ if (test_bit(SC_OP_INVALID, &sc->sc_flags))
return -EAGAIN;
buf = vmalloc(size);
diff --git a/drivers/net/wireless/ath/ath9k/debug.h b/drivers/net/wireless/ath/ath9k/debug.h
index c34da09d910..d0f851cea43 100644
--- a/drivers/net/wireless/ath/ath9k/debug.h
+++ b/drivers/net/wireless/ath/ath9k/debug.h
@@ -86,6 +86,7 @@ struct ath_interrupt_stats {
u32 dtim;
u32 bb_watchdog;
u32 tsfoor;
+ u32 mci;
/* Sync-cause stats */
u32 sync_cause_all;
diff --git a/drivers/net/wireless/ath/ath9k/eeprom_4k.c b/drivers/net/wireless/ath/ath9k/eeprom_4k.c
index 4322ac80c20..a850f44fa76 100644
--- a/drivers/net/wireless/ath/ath9k/eeprom_4k.c
+++ b/drivers/net/wireless/ath/ath9k/eeprom_4k.c
@@ -135,7 +135,7 @@ static u32 ath9k_hw_4k_dump_eeprom(struct ath_hw *ah, bool dump_base_hdr,
if (!dump_base_hdr) {
len += snprintf(buf + len, size - len,
"%20s :\n", "2GHz modal Header");
- len += ath9k_dump_4k_modal_eeprom(buf, len, size,
+ len = ath9k_dump_4k_modal_eeprom(buf, len, size,
&eep->modalHeader);
goto out;
}
diff --git a/drivers/net/wireless/ath/ath9k/eeprom_9287.c b/drivers/net/wireless/ath/ath9k/eeprom_9287.c
index aa614767adf..cd742fb944c 100644
--- a/drivers/net/wireless/ath/ath9k/eeprom_9287.c
+++ b/drivers/net/wireless/ath/ath9k/eeprom_9287.c
@@ -132,7 +132,7 @@ static u32 ath9k_hw_ar9287_dump_eeprom(struct ath_hw *ah, bool dump_base_hdr,
if (!dump_base_hdr) {
len += snprintf(buf + len, size - len,
"%20s :\n", "2GHz modal Header");
- len += ar9287_dump_modal_eeprom(buf, len, size,
+ len = ar9287_dump_modal_eeprom(buf, len, size,
&eep->modalHeader);
goto out;
}
diff --git a/drivers/net/wireless/ath/ath9k/eeprom_def.c b/drivers/net/wireless/ath/ath9k/eeprom_def.c
index b5fba8b18b8..56290f31852 100644
--- a/drivers/net/wireless/ath/ath9k/eeprom_def.c
+++ b/drivers/net/wireless/ath/ath9k/eeprom_def.c
@@ -211,11 +211,11 @@ static u32 ath9k_hw_def_dump_eeprom(struct ath_hw *ah, bool dump_base_hdr,
if (!dump_base_hdr) {
len += snprintf(buf + len, size - len,
"%20s :\n", "2GHz modal Header");
- len += ath9k_def_dump_modal_eeprom(buf, len, size,
+ len = ath9k_def_dump_modal_eeprom(buf, len, size,
&eep->modalHeader[0]);
len += snprintf(buf + len, size - len,
"%20s :\n", "5GHz modal Header");
- len += ath9k_def_dump_modal_eeprom(buf, len, size,
+ len = ath9k_def_dump_modal_eeprom(buf, len, size,
&eep->modalHeader[1]);
goto out;
}
diff --git a/drivers/net/wireless/ath/ath9k/gpio.c b/drivers/net/wireless/ath/ath9k/gpio.c
index 281a9af0f1b..af6d2735029 100644
--- a/drivers/net/wireless/ath/ath9k/gpio.c
+++ b/drivers/net/wireless/ath/ath9k/gpio.c
@@ -132,17 +132,18 @@ static void ath_detect_bt_priority(struct ath_softc *sc)
if (time_after(jiffies, btcoex->bt_priority_time +
msecs_to_jiffies(ATH_BT_PRIORITY_TIME_THRESHOLD))) {
- sc->sc_flags &= ~(SC_OP_BT_PRIORITY_DETECTED | SC_OP_BT_SCAN);
+ clear_bit(BT_OP_PRIORITY_DETECTED, &btcoex->op_flags);
+ clear_bit(BT_OP_SCAN, &btcoex->op_flags);
/* Detect if colocated bt started scanning */
if (btcoex->bt_priority_cnt >= ATH_BT_CNT_SCAN_THRESHOLD) {
ath_dbg(ath9k_hw_common(sc->sc_ah), BTCOEX,
"BT scan detected\n");
- sc->sc_flags |= (SC_OP_BT_SCAN |
- SC_OP_BT_PRIORITY_DETECTED);
+ set_bit(BT_OP_PRIORITY_DETECTED, &btcoex->op_flags);
+ set_bit(BT_OP_SCAN, &btcoex->op_flags);
} else if (btcoex->bt_priority_cnt >= ATH_BT_CNT_THRESHOLD) {
ath_dbg(ath9k_hw_common(sc->sc_ah), BTCOEX,
"BT priority traffic detected\n");
- sc->sc_flags |= SC_OP_BT_PRIORITY_DETECTED;
+ set_bit(BT_OP_PRIORITY_DETECTED, &btcoex->op_flags);
}
btcoex->bt_priority_cnt = 0;
@@ -190,13 +191,26 @@ static void ath_btcoex_period_timer(unsigned long data)
struct ath_softc *sc = (struct ath_softc *) data;
struct ath_hw *ah = sc->sc_ah;
struct ath_btcoex *btcoex = &sc->btcoex;
+ struct ath_mci_profile *mci = &btcoex->mci;
u32 timer_period;
bool is_btscan;
ath9k_ps_wakeup(sc);
if (!(ah->caps.hw_caps & ATH9K_HW_CAP_MCI))
ath_detect_bt_priority(sc);
- is_btscan = sc->sc_flags & SC_OP_BT_SCAN;
+ is_btscan = test_bit(BT_OP_SCAN, &btcoex->op_flags);
+
+ btcoex->bt_wait_time += btcoex->btcoex_period;
+ if (btcoex->bt_wait_time > ATH_BTCOEX_RX_WAIT_TIME) {
+ if (ar9003_mci_state(ah, MCI_STATE_NEED_FTP_STOMP, NULL) &&
+ (mci->num_pan || mci->num_other_acl))
+ ah->btcoex_hw.mci.stomp_ftp =
+ (sc->rx.num_pkts < ATH_BTCOEX_STOMP_FTP_THRESH);
+ else
+ ah->btcoex_hw.mci.stomp_ftp = false;
+ btcoex->bt_wait_time = 0;
+ sc->rx.num_pkts = 0;
+ }
spin_lock_bh(&btcoex->btcoex_lock);
@@ -219,8 +233,7 @@ static void ath_btcoex_period_timer(unsigned long data)
ath9k_ps_restore(sc);
timer_period = btcoex->btcoex_period / 1000;
- mod_timer(&btcoex->period_timer, jiffies +
- msecs_to_jiffies(timer_period));
+ mod_timer(&btcoex->period_timer, jiffies + msecs_to_jiffies(timer_period));
}
/*
@@ -233,14 +246,14 @@ static void ath_btcoex_no_stomp_timer(void *arg)
struct ath_hw *ah = sc->sc_ah;
struct ath_btcoex *btcoex = &sc->btcoex;
struct ath_common *common = ath9k_hw_common(ah);
- bool is_btscan = sc->sc_flags & SC_OP_BT_SCAN;
ath_dbg(common, BTCOEX, "no stomp timer running\n");
ath9k_ps_wakeup(sc);
spin_lock_bh(&btcoex->btcoex_lock);
- if (btcoex->bt_stomp_type == ATH_BTCOEX_STOMP_LOW || is_btscan)
+ if (btcoex->bt_stomp_type == ATH_BTCOEX_STOMP_LOW ||
+ test_bit(BT_OP_SCAN, &btcoex->op_flags))
ath9k_hw_btcoex_bt_stomp(ah, ATH_BTCOEX_STOMP_NONE);
else if (btcoex->bt_stomp_type == ATH_BTCOEX_STOMP_ALL)
ath9k_hw_btcoex_bt_stomp(ah, ATH_BTCOEX_STOMP_LOW);
@@ -292,7 +305,7 @@ void ath9k_btcoex_timer_resume(struct ath_softc *sc)
btcoex->bt_priority_cnt = 0;
btcoex->bt_priority_time = jiffies;
- sc->sc_flags &= ~(SC_OP_BT_PRIORITY_DETECTED | SC_OP_BT_SCAN);
+ btcoex->op_flags &= ~(BT_OP_PRIORITY_DETECTED | BT_OP_SCAN);
mod_timer(&btcoex->period_timer, jiffies);
}
@@ -316,12 +329,13 @@ void ath9k_btcoex_timer_pause(struct ath_softc *sc)
u16 ath9k_btcoex_aggr_limit(struct ath_softc *sc, u32 max_4ms_framelen)
{
+ struct ath_btcoex *btcoex = &sc->btcoex;
struct ath_mci_profile *mci = &sc->btcoex.mci;
u16 aggr_limit = 0;
if ((sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_MCI) && mci->aggr_limit)
aggr_limit = (max_4ms_framelen * mci->aggr_limit) >> 4;
- else if (sc->sc_flags & SC_OP_BT_PRIORITY_DETECTED)
+ else if (test_bit(BT_OP_PRIORITY_DETECTED, &btcoex->op_flags))
aggr_limit = min((max_4ms_framelen * 3) / 8,
(u32)ATH_AMPDU_LIMIT_MAX);
diff --git a/drivers/net/wireless/ath/ath9k/hw.c b/drivers/net/wireless/ath/ath9k/hw.c
index 7db1890448f..45e670087e1 100644
--- a/drivers/net/wireless/ath/ath9k/hw.c
+++ b/drivers/net/wireless/ath/ath9k/hw.c
@@ -390,14 +390,6 @@ static void ath9k_hw_disablepcie(struct ath_hw *ah)
REG_WRITE(ah, AR_PCIE_SERDES2, 0x00000000);
}
-static void ath9k_hw_aspm_init(struct ath_hw *ah)
-{
- struct ath_common *common = ath9k_hw_common(ah);
-
- if (common->bus_ops->aspm_init)
- common->bus_ops->aspm_init(common);
-}
-
/* This should work for all families including legacy */
static bool ath9k_hw_chip_test(struct ath_hw *ah)
{
@@ -693,9 +685,6 @@ static int __ath9k_hw_init(struct ath_hw *ah)
if (r)
return r;
- if (ah->is_pciexpress)
- ath9k_hw_aspm_init(ah);
-
r = ath9k_hw_init_macaddr(ah);
if (r) {
ath_err(common, "Failed to initialize MAC address\n");
@@ -1443,9 +1432,6 @@ static bool ath9k_hw_set_reset_reg(struct ath_hw *ah, u32 type)
break;
}
- if (ah->caps.hw_caps & ATH9K_HW_CAP_MCI)
- REG_WRITE(ah, AR_RTC_KEEP_AWAKE, 0x2);
-
return ret;
}
@@ -1721,7 +1707,7 @@ static int ath9k_hw_do_fastcc(struct ath_hw *ah, struct ath9k_channel *chan)
ath9k_hw_loadnf(ah, ah->curchan);
ath9k_hw_start_nfcal(ah, true);
- if ((ah->caps.hw_caps & ATH9K_HW_CAP_MCI) && ar9003_mci_is_ready(ah))
+ if (ath9k_hw_mci_is_enabled(ah))
ar9003_mci_2g5g_switch(ah, true);
if (AR_SREV_9271(ah))
@@ -1742,10 +1728,9 @@ int ath9k_hw_reset(struct ath_hw *ah, struct ath9k_channel *chan,
u64 tsf = 0;
int i, r;
bool start_mci_reset = false;
- bool mci = !!(ah->caps.hw_caps & ATH9K_HW_CAP_MCI);
bool save_fullsleep = ah->chip_fullsleep;
- if (mci) {
+ if (ath9k_hw_mci_is_enabled(ah)) {
start_mci_reset = ar9003_mci_start_reset(ah, chan);
if (start_mci_reset)
return 0;
@@ -1774,7 +1759,7 @@ int ath9k_hw_reset(struct ath_hw *ah, struct ath9k_channel *chan,
return r;
}
- if (mci)
+ if (ath9k_hw_mci_is_enabled(ah))
ar9003_mci_stop_bt(ah, save_fullsleep);
saveDefAntenna = REG_READ(ah, AR_DEF_ANTENNA);
@@ -1832,7 +1817,7 @@ int ath9k_hw_reset(struct ath_hw *ah, struct ath9k_channel *chan,
if (r)
return r;
- if (mci)
+ if (ath9k_hw_mci_is_enabled(ah))
ar9003_mci_reset(ah, false, IS_CHAN_2GHZ(chan), save_fullsleep);
/*
@@ -1951,7 +1936,7 @@ int ath9k_hw_reset(struct ath_hw *ah, struct ath9k_channel *chan,
ath9k_hw_loadnf(ah, chan);
ath9k_hw_start_nfcal(ah, true);
- if (mci && ar9003_mci_end_reset(ah, chan, caldata))
+ if (ath9k_hw_mci_is_enabled(ah) && ar9003_mci_end_reset(ah, chan, caldata))
return -EIO;
ENABLE_REGWRITE_BUFFER(ah);
@@ -1996,7 +1981,7 @@ int ath9k_hw_reset(struct ath_hw *ah, struct ath9k_channel *chan,
if (ath9k_hw_btcoex_is_enabled(ah))
ath9k_hw_btcoex_enable(ah);
- if (mci)
+ if (ath9k_hw_mci_is_enabled(ah))
ar9003_mci_check_bt(ah);
if (AR_SREV_9300_20_OR_LATER(ah)) {
@@ -2019,39 +2004,35 @@ EXPORT_SYMBOL(ath9k_hw_reset);
* Notify Power Mgt is disabled in self-generated frames.
* If requested, force chip to sleep.
*/
-static void ath9k_set_power_sleep(struct ath_hw *ah, int setChip)
+static void ath9k_set_power_sleep(struct ath_hw *ah)
{
REG_SET_BIT(ah, AR_STA_ID1, AR_STA_ID1_PWR_SAV);
- if (setChip) {
- if (AR_SREV_9462(ah)) {
- REG_WRITE(ah, AR_TIMER_MODE,
- REG_READ(ah, AR_TIMER_MODE) & 0xFFFFFF00);
- REG_WRITE(ah, AR_NDP2_TIMER_MODE, REG_READ(ah,
- AR_NDP2_TIMER_MODE) & 0xFFFFFF00);
- REG_WRITE(ah, AR_SLP32_INC,
- REG_READ(ah, AR_SLP32_INC) & 0xFFF00000);
- /* xxx Required for WLAN only case ? */
- REG_WRITE(ah, AR_MCI_INTERRUPT_RX_MSG_EN, 0);
- udelay(100);
- }
- /*
- * Clear the RTC force wake bit to allow the
- * mac to go to sleep.
- */
- REG_CLR_BIT(ah, AR_RTC_FORCE_WAKE, AR_RTC_FORCE_WAKE_EN);
+ if (AR_SREV_9462(ah)) {
+ REG_CLR_BIT(ah, AR_TIMER_MODE, 0xff);
+ REG_CLR_BIT(ah, AR_NDP2_TIMER_MODE, 0xff);
+ REG_CLR_BIT(ah, AR_SLP32_INC, 0xfffff);
+ /* xxx Required for WLAN only case ? */
+ REG_WRITE(ah, AR_MCI_INTERRUPT_RX_MSG_EN, 0);
+ udelay(100);
+ }
- if (AR_SREV_9462(ah))
- udelay(100);
+ /*
+ * Clear the RTC force wake bit to allow the
+ * mac to go to sleep.
+ */
+ REG_CLR_BIT(ah, AR_RTC_FORCE_WAKE, AR_RTC_FORCE_WAKE_EN);
+
+ if (ath9k_hw_mci_is_enabled(ah))
+ udelay(100);
- if (!AR_SREV_9100(ah) && !AR_SREV_9300_20_OR_LATER(ah))
- REG_WRITE(ah, AR_RC, AR_RC_AHB | AR_RC_HOSTIF);
+ if (!AR_SREV_9100(ah) && !AR_SREV_9300_20_OR_LATER(ah))
+ REG_WRITE(ah, AR_RC, AR_RC_AHB | AR_RC_HOSTIF);
- /* Shutdown chip. Active low */
- if (!AR_SREV_5416(ah) && !AR_SREV_9271(ah)) {
- REG_CLR_BIT(ah, AR_RTC_RESET, AR_RTC_RESET_EN);
- udelay(2);
- }
+ /* Shutdown chip. Active low */
+ if (!AR_SREV_5416(ah) && !AR_SREV_9271(ah)) {
+ REG_CLR_BIT(ah, AR_RTC_RESET, AR_RTC_RESET_EN);
+ udelay(2);
}
/* Clear Bit 14 of AR_WA after putting chip into Full Sleep mode. */
@@ -2064,44 +2045,38 @@ static void ath9k_set_power_sleep(struct ath_hw *ah, int setChip)
* frames. If request, set power mode of chip to
* auto/normal. Duration in units of 128us (1/8 TU).
*/
-static void ath9k_set_power_network_sleep(struct ath_hw *ah, int setChip)
+static void ath9k_set_power_network_sleep(struct ath_hw *ah)
{
- u32 val;
+ struct ath9k_hw_capabilities *pCap = &ah->caps;
REG_SET_BIT(ah, AR_STA_ID1, AR_STA_ID1_PWR_SAV);
- if (setChip) {
- struct ath9k_hw_capabilities *pCap = &ah->caps;
- if (!(pCap->hw_caps & ATH9K_HW_CAP_AUTOSLEEP)) {
- /* Set WakeOnInterrupt bit; clear ForceWake bit */
- REG_WRITE(ah, AR_RTC_FORCE_WAKE,
- AR_RTC_FORCE_WAKE_ON_INT);
- } else {
+ if (!(pCap->hw_caps & ATH9K_HW_CAP_AUTOSLEEP)) {
+ /* Set WakeOnInterrupt bit; clear ForceWake bit */
+ REG_WRITE(ah, AR_RTC_FORCE_WAKE,
+ AR_RTC_FORCE_WAKE_ON_INT);
+ } else {
- /* When chip goes into network sleep, it could be waken
- * up by MCI_INT interrupt caused by BT's HW messages
- * (LNA_xxx, CONT_xxx) which chould be in a very fast
- * rate (~100us). This will cause chip to leave and
- * re-enter network sleep mode frequently, which in
- * consequence will have WLAN MCI HW to generate lots of
- * SYS_WAKING and SYS_SLEEPING messages which will make
- * BT CPU to busy to process.
- */
- if (AR_SREV_9462(ah)) {
- val = REG_READ(ah, AR_MCI_INTERRUPT_RX_MSG_EN) &
- ~AR_MCI_INTERRUPT_RX_HW_MSG_MASK;
- REG_WRITE(ah, AR_MCI_INTERRUPT_RX_MSG_EN, val);
- }
- /*
- * Clear the RTC force wake bit to allow the
- * mac to go to sleep.
- */
- REG_CLR_BIT(ah, AR_RTC_FORCE_WAKE,
- AR_RTC_FORCE_WAKE_EN);
-
- if (AR_SREV_9462(ah))
- udelay(30);
- }
+ /* When chip goes into network sleep, it could be waken
+ * up by MCI_INT interrupt caused by BT's HW messages
+ * (LNA_xxx, CONT_xxx) which chould be in a very fast
+ * rate (~100us). This will cause chip to leave and
+ * re-enter network sleep mode frequently, which in
+ * consequence will have WLAN MCI HW to generate lots of
+ * SYS_WAKING and SYS_SLEEPING messages which will make
+ * BT CPU to busy to process.
+ */
+ if (ath9k_hw_mci_is_enabled(ah))
+ REG_CLR_BIT(ah, AR_MCI_INTERRUPT_RX_MSG_EN,
+ AR_MCI_INTERRUPT_RX_HW_MSG_MASK);
+ /*
+ * Clear the RTC force wake bit to allow the
+ * mac to go to sleep.
+ */
+ REG_CLR_BIT(ah, AR_RTC_FORCE_WAKE, AR_RTC_FORCE_WAKE_EN);
+
+ if (ath9k_hw_mci_is_enabled(ah))
+ udelay(30);
}
/* Clear Bit 14 of AR_WA after putting chip into Net Sleep mode. */
@@ -2109,7 +2084,7 @@ static void ath9k_set_power_network_sleep(struct ath_hw *ah, int setChip)
REG_WRITE(ah, AR_WA, ah->WARegVal & ~AR_WA_D3_L1_DISABLE);
}
-static bool ath9k_hw_set_power_awake(struct ath_hw *ah, int setChip)
+static bool ath9k_hw_set_power_awake(struct ath_hw *ah)
{
u32 val;
int i;
@@ -2120,37 +2095,35 @@ static bool ath9k_hw_set_power_awake(struct ath_hw *ah, int setChip)
udelay(10);
}
- if (setChip) {
- if ((REG_READ(ah, AR_RTC_STATUS) &
- AR_RTC_STATUS_M) == AR_RTC_STATUS_SHUTDOWN) {
- if (!ath9k_hw_set_reset_reg(ah, ATH9K_RESET_POWER_ON)) {
- return false;
- }
- if (!AR_SREV_9300_20_OR_LATER(ah))
- ath9k_hw_init_pll(ah, NULL);
+ if ((REG_READ(ah, AR_RTC_STATUS) &
+ AR_RTC_STATUS_M) == AR_RTC_STATUS_SHUTDOWN) {
+ if (!ath9k_hw_set_reset_reg(ah, ATH9K_RESET_POWER_ON)) {
+ return false;
}
- if (AR_SREV_9100(ah))
- REG_SET_BIT(ah, AR_RTC_RESET,
- AR_RTC_RESET_EN);
+ if (!AR_SREV_9300_20_OR_LATER(ah))
+ ath9k_hw_init_pll(ah, NULL);
+ }
+ if (AR_SREV_9100(ah))
+ REG_SET_BIT(ah, AR_RTC_RESET,
+ AR_RTC_RESET_EN);
+ REG_SET_BIT(ah, AR_RTC_FORCE_WAKE,
+ AR_RTC_FORCE_WAKE_EN);
+ udelay(50);
+
+ for (i = POWER_UP_TIME / 50; i > 0; i--) {
+ val = REG_READ(ah, AR_RTC_STATUS) & AR_RTC_STATUS_M;
+ if (val == AR_RTC_STATUS_ON)
+ break;
+ udelay(50);
REG_SET_BIT(ah, AR_RTC_FORCE_WAKE,
AR_RTC_FORCE_WAKE_EN);
- udelay(50);
-
- for (i = POWER_UP_TIME / 50; i > 0; i--) {
- val = REG_READ(ah, AR_RTC_STATUS) & AR_RTC_STATUS_M;
- if (val == AR_RTC_STATUS_ON)
- break;
- udelay(50);
- REG_SET_BIT(ah, AR_RTC_FORCE_WAKE,
- AR_RTC_FORCE_WAKE_EN);
- }
- if (i == 0) {
- ath_err(ath9k_hw_common(ah),
- "Failed to wakeup in %uus\n",
- POWER_UP_TIME / 20);
- return false;
- }
+ }
+ if (i == 0) {
+ ath_err(ath9k_hw_common(ah),
+ "Failed to wakeup in %uus\n",
+ POWER_UP_TIME / 20);
+ return false;
}
REG_CLR_BIT(ah, AR_STA_ID1, AR_STA_ID1_PWR_SAV);
@@ -2161,7 +2134,7 @@ static bool ath9k_hw_set_power_awake(struct ath_hw *ah, int setChip)
bool ath9k_hw_setpower(struct ath_hw *ah, enum ath9k_power_mode mode)
{
struct ath_common *common = ath9k_hw_common(ah);
- int status = true, setChip = true;
+ int status = true;
static const char *modes[] = {
"AWAKE",
"FULL-SLEEP",
@@ -2177,25 +2150,17 @@ bool ath9k_hw_setpower(struct ath_hw *ah, enum ath9k_power_mode mode)
switch (mode) {
case ATH9K_PM_AWAKE:
- status = ath9k_hw_set_power_awake(ah, setChip);
-
- if (ah->caps.hw_caps & ATH9K_HW_CAP_MCI)
- REG_WRITE(ah, AR_RTC_KEEP_AWAKE, 0x2);
-
+ status = ath9k_hw_set_power_awake(ah);
break;
case ATH9K_PM_FULL_SLEEP:
- if (ah->caps.hw_caps & ATH9K_HW_CAP_MCI)
+ if (ath9k_hw_mci_is_enabled(ah))
ar9003_mci_set_full_sleep(ah);
- ath9k_set_power_sleep(ah, setChip);
+ ath9k_set_power_sleep(ah);
ah->chip_fullsleep = true;
break;
case ATH9K_PM_NETWORK_SLEEP:
-
- if (ah->caps.hw_caps & ATH9K_HW_CAP_MCI)
- REG_WRITE(ah, AR_RTC_KEEP_AWAKE, 0x2);
-
- ath9k_set_power_network_sleep(ah, setChip);
+ ath9k_set_power_network_sleep(ah);
break;
default:
ath_err(common, "Unknown power mode %u\n", mode);
@@ -2765,6 +2730,9 @@ EXPORT_SYMBOL(ath9k_hw_setrxfilter);
bool ath9k_hw_phy_disable(struct ath_hw *ah)
{
+ if (ath9k_hw_mci_is_enabled(ah))
+ ar9003_mci_bt_gain_ctrl(ah);
+
if (!ath9k_hw_set_reset_reg(ah, ATH9K_RESET_WARM))
return false;
diff --git a/drivers/net/wireless/ath/ath9k/hw.h b/drivers/net/wireless/ath/ath9k/hw.h
index b620c557c2a..03d590924c6 100644
--- a/drivers/net/wireless/ath/ath9k/hw.h
+++ b/drivers/net/wireless/ath/ath9k/hw.h
@@ -824,7 +824,6 @@ struct ath_hw {
struct ar5416IniArray ini_japan2484;
struct ar5416IniArray iniModes_9271_ANI_reg;
struct ar5416IniArray ini_radio_post_sys2ant;
- struct ar5416IniArray ini_BTCOEX_MAX_TXPWR;
struct ar5416IniArray iniMac[ATH_INI_NUM_SPLIT];
struct ar5416IniArray iniBB[ATH_INI_NUM_SPLIT];
@@ -1037,6 +1036,11 @@ static inline bool ath9k_hw_btcoex_is_enabled(struct ath_hw *ah)
{
return ah->btcoex_hw.enabled;
}
+static inline bool ath9k_hw_mci_is_enabled(struct ath_hw *ah)
+{
+ return ah->btcoex_hw.enabled && (ah->caps.hw_caps & ATH9K_HW_CAP_MCI);
+
+}
void ath9k_hw_btcoex_enable(struct ath_hw *ah);
static inline enum ath_btcoex_scheme
ath9k_hw_get_btcoex_scheme(struct ath_hw *ah)
@@ -1048,6 +1052,10 @@ static inline bool ath9k_hw_btcoex_is_enabled(struct ath_hw *ah)
{
return false;
}
+static inline bool ath9k_hw_mci_is_enabled(struct ath_hw *ah)
+{
+ return false;
+}
static inline void ath9k_hw_btcoex_enable(struct ath_hw *ah)
{
}
diff --git a/drivers/net/wireless/ath/ath9k/init.c b/drivers/net/wireless/ath/ath9k/init.c
index dee9e092449..9dfce1a69c7 100644
--- a/drivers/net/wireless/ath/ath9k/init.c
+++ b/drivers/net/wireless/ath/ath9k/init.c
@@ -489,6 +489,7 @@ static void ath9k_init_misc(struct ath_softc *sc)
setup_timer(&common->ani.timer, ath_ani_calibrate, (unsigned long)sc);
+ sc->last_rssi = ATH_RSSI_DUMMY_MARKER;
sc->config.txpowlimit = ATH_TXPOWER_MAX;
memcpy(common->bssidmask, ath_bcast_mac, ETH_ALEN);
sc->beacon.slottime = ATH9K_SLOT_TIME_9;
@@ -560,6 +561,12 @@ static int ath9k_init_softc(u16 devid, struct ath_softc *sc,
tasklet_init(&sc->bcon_tasklet, ath_beacon_tasklet,
(unsigned long)sc);
+ INIT_WORK(&sc->hw_reset_work, ath_reset_work);
+ INIT_WORK(&sc->hw_check_work, ath_hw_check);
+ INIT_WORK(&sc->paprd_work, ath_paprd_calibrate);
+ INIT_DELAYED_WORK(&sc->hw_pll_work, ath_hw_pll_work);
+ setup_timer(&sc->rx_poll_timer, ath_rx_poll, (unsigned long)sc);
+
/*
* Cache line size is used to size and align various
* structures used to communicate with the hardware.
@@ -590,6 +597,9 @@ static int ath9k_init_softc(u16 devid, struct ath_softc *sc,
ath9k_cmn_init_crypto(sc->sc_ah);
ath9k_init_misc(sc);
+ if (common->bus_ops->aspm_init)
+ common->bus_ops->aspm_init(common);
+
return 0;
err_btcoex:
@@ -782,11 +792,6 @@ int ath9k_init_device(u16 devid, struct ath_softc *sc,
ARRAY_SIZE(ath9k_tpt_blink));
#endif
- INIT_WORK(&sc->hw_reset_work, ath_reset_work);
- INIT_WORK(&sc->hw_check_work, ath_hw_check);
- INIT_WORK(&sc->paprd_work, ath_paprd_calibrate);
- INIT_DELAYED_WORK(&sc->hw_pll_work, ath_hw_pll_work);
-
/* Register with mac80211 */
error = ieee80211_register_hw(hw);
if (error)
@@ -805,9 +810,6 @@ int ath9k_init_device(u16 devid, struct ath_softc *sc,
goto error_world;
}
- setup_timer(&sc->rx_poll_timer, ath_rx_poll, (unsigned long)sc);
- sc->last_rssi = ATH_RSSI_DUMMY_MARKER;
-
ath_init_leds(sc);
ath_start_rfkill_poll(sc);
diff --git a/drivers/net/wireless/ath/ath9k/link.c b/drivers/net/wireless/ath/ath9k/link.c
new file mode 100644
index 00000000000..0cc4c70f7f0
--- /dev/null
+++ b/drivers/net/wireless/ath/ath9k/link.c
@@ -0,0 +1,502 @@
+/*
+ * Copyright (c) 2012 Qualcomm Atheros, Inc.
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include "ath9k.h"
+
+/*
+ * TX polling - checks if the TX engine is stuck somewhere
+ * and issues a chip reset if so.
+ */
+void ath_tx_complete_poll_work(struct work_struct *work)
+{
+ struct ath_softc *sc = container_of(work, struct ath_softc,
+ tx_complete_work.work);
+ struct ath_txq *txq;
+ int i;
+ bool needreset = false;
+#ifdef CONFIG_ATH9K_DEBUGFS
+ sc->tx_complete_poll_work_seen++;
+#endif
+
+ for (i = 0; i < ATH9K_NUM_TX_QUEUES; i++)
+ if (ATH_TXQ_SETUP(sc, i)) {
+ txq = &sc->tx.txq[i];
+ ath_txq_lock(sc, txq);
+ if (txq->axq_depth) {
+ if (txq->axq_tx_inprogress) {
+ needreset = true;
+ ath_txq_unlock(sc, txq);
+ break;
+ } else {
+ txq->axq_tx_inprogress = true;
+ }
+ }
+ ath_txq_unlock_complete(sc, txq);
+ }
+
+ if (needreset) {
+ ath_dbg(ath9k_hw_common(sc->sc_ah), RESET,
+ "tx hung, resetting the chip\n");
+ RESET_STAT_INC(sc, RESET_TYPE_TX_HANG);
+ ieee80211_queue_work(sc->hw, &sc->hw_reset_work);
+ return;
+ }
+
+ ieee80211_queue_delayed_work(sc->hw, &sc->tx_complete_work,
+ msecs_to_jiffies(ATH_TX_COMPLETE_POLL_INT));
+}
+
+/*
+ * Checks if the BB/MAC is hung.
+ */
+void ath_hw_check(struct work_struct *work)
+{
+ struct ath_softc *sc = container_of(work, struct ath_softc, hw_check_work);
+ struct ath_common *common = ath9k_hw_common(sc->sc_ah);
+ unsigned long flags;
+ int busy;
+ u8 is_alive, nbeacon = 1;
+
+ ath9k_ps_wakeup(sc);
+ is_alive = ath9k_hw_check_alive(sc->sc_ah);
+
+ if (is_alive && !AR_SREV_9300(sc->sc_ah))
+ goto out;
+ else if (!is_alive && AR_SREV_9300(sc->sc_ah)) {
+ ath_dbg(common, RESET,
+ "DCU stuck is detected. Schedule chip reset\n");
+ RESET_STAT_INC(sc, RESET_TYPE_MAC_HANG);
+ goto sched_reset;
+ }
+
+ spin_lock_irqsave(&common->cc_lock, flags);
+ busy = ath_update_survey_stats(sc);
+ spin_unlock_irqrestore(&common->cc_lock, flags);
+
+ ath_dbg(common, RESET, "Possible baseband hang, busy=%d (try %d)\n",
+ busy, sc->hw_busy_count + 1);
+ if (busy >= 99) {
+ if (++sc->hw_busy_count >= 3) {
+ RESET_STAT_INC(sc, RESET_TYPE_BB_HANG);
+ goto sched_reset;
+ }
+ } else if (busy >= 0) {
+ sc->hw_busy_count = 0;
+ nbeacon = 3;
+ }
+
+ ath_start_rx_poll(sc, nbeacon);
+ goto out;
+
+sched_reset:
+ ieee80211_queue_work(sc->hw, &sc->hw_reset_work);
+out:
+ ath9k_ps_restore(sc);
+}
+
+/*
+ * PLL-WAR for AR9485/AR9340
+ */
+static bool ath_hw_pll_rx_hang_check(struct ath_softc *sc, u32 pll_sqsum)
+{
+ static int count;
+ struct ath_common *common = ath9k_hw_common(sc->sc_ah);
+
+ if (pll_sqsum >= 0x40000) {
+ count++;
+ if (count == 3) {
+ ath_dbg(common, RESET, "PLL WAR, resetting the chip\n");
+ RESET_STAT_INC(sc, RESET_TYPE_PLL_HANG);
+ ieee80211_queue_work(sc->hw, &sc->hw_reset_work);
+ count = 0;
+ return true;
+ }
+ } else {
+ count = 0;
+ }
+
+ return false;
+}
+
+void ath_hw_pll_work(struct work_struct *work)
+{
+ u32 pll_sqsum;
+ struct ath_softc *sc = container_of(work, struct ath_softc,
+ hw_pll_work.work);
+
+ ath9k_ps_wakeup(sc);
+ pll_sqsum = ar9003_get_pll_sqsum_dvc(sc->sc_ah);
+ ath9k_ps_restore(sc);
+ if (ath_hw_pll_rx_hang_check(sc, pll_sqsum))
+ return;
+
+ ieee80211_queue_delayed_work(sc->hw, &sc->hw_pll_work,
+ msecs_to_jiffies(ATH_PLL_WORK_INTERVAL));
+}
+
+/*
+ * RX Polling - monitors baseband hangs.
+ */
+void ath_start_rx_poll(struct ath_softc *sc, u8 nbeacon)
+{
+ if (!AR_SREV_9300(sc->sc_ah))
+ return;
+
+ if (!test_bit(SC_OP_PRIM_STA_VIF, &sc->sc_flags))
+ return;
+
+ mod_timer(&sc->rx_poll_timer, jiffies + msecs_to_jiffies
+ (nbeacon * sc->cur_beacon_conf.beacon_interval));
+}
+
+void ath_rx_poll(unsigned long data)
+{
+ struct ath_softc *sc = (struct ath_softc *)data;
+
+ ieee80211_queue_work(sc->hw, &sc->hw_check_work);
+}
+
+/*
+ * PA Pre-distortion.
+ */
+static void ath_paprd_activate(struct ath_softc *sc)
+{
+ struct ath_hw *ah = sc->sc_ah;
+ struct ath9k_hw_cal_data *caldata = ah->caldata;
+ int chain;
+
+ if (!caldata || !caldata->paprd_done)
+ return;
+
+ ath9k_ps_wakeup(sc);
+ ar9003_paprd_enable(ah, false);
+ for (chain = 0; chain < AR9300_MAX_CHAINS; chain++) {
+ if (!(ah->txchainmask & BIT(chain)))
+ continue;
+
+ ar9003_paprd_populate_single_table(ah, caldata, chain);
+ }
+
+ ar9003_paprd_enable(ah, true);
+ ath9k_ps_restore(sc);
+}
+
+static bool ath_paprd_send_frame(struct ath_softc *sc, struct sk_buff *skb, int chain)
+{
+ struct ieee80211_hw *hw = sc->hw;
+ struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb);
+ struct ath_hw *ah = sc->sc_ah;
+ struct ath_common *common = ath9k_hw_common(ah);
+ struct ath_tx_control txctl;
+ int time_left;
+
+ memset(&txctl, 0, sizeof(txctl));
+ txctl.txq = sc->tx.txq_map[WME_AC_BE];
+
+ memset(tx_info, 0, sizeof(*tx_info));
+ tx_info->band = hw->conf.channel->band;
+ tx_info->flags |= IEEE80211_TX_CTL_NO_ACK;
+ tx_info->control.rates[0].idx = 0;
+ tx_info->control.rates[0].count = 1;
+ tx_info->control.rates[0].flags = IEEE80211_TX_RC_MCS;
+ tx_info->control.rates[1].idx = -1;
+
+ init_completion(&sc->paprd_complete);
+ txctl.paprd = BIT(chain);
+
+ if (ath_tx_start(hw, skb, &txctl) != 0) {
+ ath_dbg(common, CALIBRATE, "PAPRD TX failed\n");
+ dev_kfree_skb_any(skb);
+ return false;
+ }
+
+ time_left = wait_for_completion_timeout(&sc->paprd_complete,
+ msecs_to_jiffies(ATH_PAPRD_TIMEOUT));
+
+ if (!time_left)
+ ath_dbg(common, CALIBRATE,
+ "Timeout waiting for paprd training on TX chain %d\n",
+ chain);
+
+ return !!time_left;
+}
+
+void ath_paprd_calibrate(struct work_struct *work)
+{
+ struct ath_softc *sc = container_of(work, struct ath_softc, paprd_work);
+ struct ieee80211_hw *hw = sc->hw;
+ struct ath_hw *ah = sc->sc_ah;
+ struct ieee80211_hdr *hdr;
+ struct sk_buff *skb = NULL;
+ struct ath9k_hw_cal_data *caldata = ah->caldata;
+ struct ath_common *common = ath9k_hw_common(ah);
+ int ftype;
+ int chain_ok = 0;
+ int chain;
+ int len = 1800;
+
+ if (!caldata)
+ return;
+
+ ath9k_ps_wakeup(sc);
+
+ if (ar9003_paprd_init_table(ah) < 0)
+ goto fail_paprd;
+
+ skb = alloc_skb(len, GFP_KERNEL);
+ if (!skb)
+ goto fail_paprd;
+
+ skb_put(skb, len);
+ memset(skb->data, 0, len);
+ hdr = (struct ieee80211_hdr *)skb->data;
+ ftype = IEEE80211_FTYPE_DATA | IEEE80211_STYPE_NULLFUNC;
+ hdr->frame_control = cpu_to_le16(ftype);
+ hdr->duration_id = cpu_to_le16(10);
+ memcpy(hdr->addr1, hw->wiphy->perm_addr, ETH_ALEN);
+ memcpy(hdr->addr2, hw->wiphy->perm_addr, ETH_ALEN);
+ memcpy(hdr->addr3, hw->wiphy->perm_addr, ETH_ALEN);
+
+ for (chain = 0; chain < AR9300_MAX_CHAINS; chain++) {
+ if (!(ah->txchainmask & BIT(chain)))
+ continue;
+
+ chain_ok = 0;
+
+ ath_dbg(common, CALIBRATE,
+ "Sending PAPRD frame for thermal measurement on chain %d\n",
+ chain);
+ if (!ath_paprd_send_frame(sc, skb, chain))
+ goto fail_paprd;
+
+ ar9003_paprd_setup_gain_table(ah, chain);
+
+ ath_dbg(common, CALIBRATE,
+ "Sending PAPRD training frame on chain %d\n", chain);
+ if (!ath_paprd_send_frame(sc, skb, chain))
+ goto fail_paprd;
+
+ if (!ar9003_paprd_is_done(ah)) {
+ ath_dbg(common, CALIBRATE,
+ "PAPRD not yet done on chain %d\n", chain);
+ break;
+ }
+
+ if (ar9003_paprd_create_curve(ah, caldata, chain)) {
+ ath_dbg(common, CALIBRATE,
+ "PAPRD create curve failed on chain %d\n",
+ chain);
+ break;
+ }
+
+ chain_ok = 1;
+ }
+ kfree_skb(skb);
+
+ if (chain_ok) {
+ caldata->paprd_done = true;
+ ath_paprd_activate(sc);
+ }
+
+fail_paprd:
+ ath9k_ps_restore(sc);
+}
+
+/*
+ * ANI performs periodic noise floor calibration
+ * that is used to adjust and optimize the chip performance. This
+ * takes environmental changes (location, temperature) into account.
+ * When the task is complete, it reschedules itself depending on the
+ * appropriate interval that was calculated.
+ */
+void ath_ani_calibrate(unsigned long data)
+{
+ struct ath_softc *sc = (struct ath_softc *)data;
+ struct ath_hw *ah = sc->sc_ah;
+ struct ath_common *common = ath9k_hw_common(ah);
+ bool longcal = false;
+ bool shortcal = false;
+ bool aniflag = false;
+ unsigned int timestamp = jiffies_to_msecs(jiffies);
+ u32 cal_interval, short_cal_interval, long_cal_interval;
+ unsigned long flags;
+
+ if (ah->caldata && ah->caldata->nfcal_interference)
+ long_cal_interval = ATH_LONG_CALINTERVAL_INT;
+ else
+ long_cal_interval = ATH_LONG_CALINTERVAL;
+
+ short_cal_interval = (ah->opmode == NL80211_IFTYPE_AP) ?
+ ATH_AP_SHORT_CALINTERVAL : ATH_STA_SHORT_CALINTERVAL;
+
+ /* Only calibrate if awake */
+ if (sc->sc_ah->power_mode != ATH9K_PM_AWAKE)
+ goto set_timer;
+
+ ath9k_ps_wakeup(sc);
+
+ /* Long calibration runs independently of short calibration. */
+ if ((timestamp - common->ani.longcal_timer) >= long_cal_interval) {
+ longcal = true;
+ common->ani.longcal_timer = timestamp;
+ }
+
+ /* Short calibration applies only while caldone is false */
+ if (!common->ani.caldone) {
+ if ((timestamp - common->ani.shortcal_timer) >= short_cal_interval) {
+ shortcal = true;
+ common->ani.shortcal_timer = timestamp;
+ common->ani.resetcal_timer = timestamp;
+ }
+ } else {
+ if ((timestamp - common->ani.resetcal_timer) >=
+ ATH_RESTART_CALINTERVAL) {
+ common->ani.caldone = ath9k_hw_reset_calvalid(ah);
+ if (common->ani.caldone)
+ common->ani.resetcal_timer = timestamp;
+ }
+ }
+
+ /* Verify whether we must check ANI */
+ if (sc->sc_ah->config.enable_ani
+ && (timestamp - common->ani.checkani_timer) >=
+ ah->config.ani_poll_interval) {
+ aniflag = true;
+ common->ani.checkani_timer = timestamp;
+ }
+
+ /* Call ANI routine if necessary */
+ if (aniflag) {
+ spin_lock_irqsave(&common->cc_lock, flags);
+ ath9k_hw_ani_monitor(ah, ah->curchan);
+ ath_update_survey_stats(sc);
+ spin_unlock_irqrestore(&common->cc_lock, flags);
+ }
+
+ /* Perform calibration if necessary */
+ if (longcal || shortcal) {
+ common->ani.caldone =
+ ath9k_hw_calibrate(ah, ah->curchan,
+ ah->rxchainmask, longcal);
+ }
+
+ ath_dbg(common, ANI,
+ "Calibration @%lu finished: %s %s %s, caldone: %s\n",
+ jiffies,
+ longcal ? "long" : "", shortcal ? "short" : "",
+ aniflag ? "ani" : "", common->ani.caldone ? "true" : "false");
+
+ ath9k_ps_restore(sc);
+
+set_timer:
+ /*
+ * Set timer interval based on previous results.
+ * The interval must be the shortest necessary to satisfy ANI,
+ * short calibration and long calibration.
+ */
+ ath9k_debug_samp_bb_mac(sc);
+ cal_interval = ATH_LONG_CALINTERVAL;
+ if (sc->sc_ah->config.enable_ani)
+ cal_interval = min(cal_interval,
+ (u32)ah->config.ani_poll_interval);
+ if (!common->ani.caldone)
+ cal_interval = min(cal_interval, (u32)short_cal_interval);
+
+ mod_timer(&common->ani.timer, jiffies + msecs_to_jiffies(cal_interval));
+ if ((sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_PAPRD) && ah->caldata) {
+ if (!ah->caldata->paprd_done)
+ ieee80211_queue_work(sc->hw, &sc->paprd_work);
+ else if (!ah->paprd_table_write_done)
+ ath_paprd_activate(sc);
+ }
+}
+
+void ath_start_ani(struct ath_common *common)
+{
+ struct ath_hw *ah = common->ah;
+ unsigned long timestamp = jiffies_to_msecs(jiffies);
+ struct ath_softc *sc = (struct ath_softc *) common->priv;
+
+ if (!test_bit(SC_OP_ANI_RUN, &sc->sc_flags))
+ return;
+
+ if (sc->hw->conf.flags & IEEE80211_CONF_OFFCHANNEL)
+ return;
+
+ common->ani.longcal_timer = timestamp;
+ common->ani.shortcal_timer = timestamp;
+ common->ani.checkani_timer = timestamp;
+
+ mod_timer(&common->ani.timer,
+ jiffies + msecs_to_jiffies((u32)ah->config.ani_poll_interval));
+}
+
+void ath_update_survey_nf(struct ath_softc *sc, int channel)
+{
+ struct ath_hw *ah = sc->sc_ah;
+ struct ath9k_channel *chan = &ah->channels[channel];
+ struct survey_info *survey = &sc->survey[channel];
+
+ if (chan->noisefloor) {
+ survey->filled |= SURVEY_INFO_NOISE_DBM;
+ survey->noise = ath9k_hw_getchan_noise(ah, chan);
+ }
+}
+
+/*
+ * Updates the survey statistics and returns the busy time since last
+ * update in %, if the measurement duration was long enough for the
+ * result to be useful, -1 otherwise.
+ */
+int ath_update_survey_stats(struct ath_softc *sc)
+{
+ struct ath_hw *ah = sc->sc_ah;
+ struct ath_common *common = ath9k_hw_common(ah);
+ int pos = ah->curchan - &ah->channels[0];
+ struct survey_info *survey = &sc->survey[pos];
+ struct ath_cycle_counters *cc = &common->cc_survey;
+ unsigned int div = common->clockrate * 1000;
+ int ret = 0;
+
+ if (!ah->curchan)
+ return -1;
+
+ if (ah->power_mode == ATH9K_PM_AWAKE)
+ ath_hw_cycle_counters_update(common);
+
+ if (cc->cycles > 0) {
+ survey->filled |= SURVEY_INFO_CHANNEL_TIME |
+ SURVEY_INFO_CHANNEL_TIME_BUSY |
+ SURVEY_INFO_CHANNEL_TIME_RX |
+ SURVEY_INFO_CHANNEL_TIME_TX;
+ survey->channel_time += cc->cycles / div;
+ survey->channel_time_busy += cc->rx_busy / div;
+ survey->channel_time_rx += cc->rx_frame / div;
+ survey->channel_time_tx += cc->tx_frame / div;
+ }
+
+ if (cc->cycles < div)
+ return -1;
+
+ if (cc->cycles > 0)
+ ret = cc->rx_busy * 100 / cc->cycles;
+
+ memset(cc, 0, sizeof(*cc));
+
+ ath_update_survey_nf(sc, pos);
+
+ return ret;
+}
diff --git a/drivers/net/wireless/ath/ath9k/main.c b/drivers/net/wireless/ath/ath9k/main.c
index 4de4473776a..c0f478b0a9a 100644
--- a/drivers/net/wireless/ath/ath9k/main.c
+++ b/drivers/net/wireless/ath/ath9k/main.c
@@ -101,6 +101,7 @@ void ath9k_ps_wakeup(struct ath_softc *sc)
spin_lock(&common->cc_lock);
ath_hw_cycle_counters_update(common);
memset(&common->cc_survey, 0, sizeof(common->cc_survey));
+ memset(&common->cc_ani, 0, sizeof(common->cc_ani));
spin_unlock(&common->cc_lock);
}
@@ -143,84 +144,6 @@ void ath9k_ps_restore(struct ath_softc *sc)
spin_unlock_irqrestore(&sc->sc_pm_lock, flags);
}
-void ath_start_ani(struct ath_common *common)
-{
- struct ath_hw *ah = common->ah;
- unsigned long timestamp = jiffies_to_msecs(jiffies);
- struct ath_softc *sc = (struct ath_softc *) common->priv;
-
- if (!(sc->sc_flags & SC_OP_ANI_RUN))
- return;
-
- if (sc->sc_flags & SC_OP_OFFCHANNEL)
- return;
-
- common->ani.longcal_timer = timestamp;
- common->ani.shortcal_timer = timestamp;
- common->ani.checkani_timer = timestamp;
-
- mod_timer(&common->ani.timer,
- jiffies +
- msecs_to_jiffies((u32)ah->config.ani_poll_interval));
-}
-
-static void ath_update_survey_nf(struct ath_softc *sc, int channel)
-{
- struct ath_hw *ah = sc->sc_ah;
- struct ath9k_channel *chan = &ah->channels[channel];
- struct survey_info *survey = &sc->survey[channel];
-
- if (chan->noisefloor) {
- survey->filled |= SURVEY_INFO_NOISE_DBM;
- survey->noise = ath9k_hw_getchan_noise(ah, chan);
- }
-}
-
-/*
- * Updates the survey statistics and returns the busy time since last
- * update in %, if the measurement duration was long enough for the
- * result to be useful, -1 otherwise.
- */
-static int ath_update_survey_stats(struct ath_softc *sc)
-{
- struct ath_hw *ah = sc->sc_ah;
- struct ath_common *common = ath9k_hw_common(ah);
- int pos = ah->curchan - &ah->channels[0];
- struct survey_info *survey = &sc->survey[pos];
- struct ath_cycle_counters *cc = &common->cc_survey;
- unsigned int div = common->clockrate * 1000;
- int ret = 0;
-
- if (!ah->curchan)
- return -1;
-
- if (ah->power_mode == ATH9K_PM_AWAKE)
- ath_hw_cycle_counters_update(common);
-
- if (cc->cycles > 0) {
- survey->filled |= SURVEY_INFO_CHANNEL_TIME |
- SURVEY_INFO_CHANNEL_TIME_BUSY |
- SURVEY_INFO_CHANNEL_TIME_RX |
- SURVEY_INFO_CHANNEL_TIME_TX;
- survey->channel_time += cc->cycles / div;
- survey->channel_time_busy += cc->rx_busy / div;
- survey->channel_time_rx += cc->rx_frame / div;
- survey->channel_time_tx += cc->tx_frame / div;
- }
-
- if (cc->cycles < div)
- return -1;
-
- if (cc->cycles > 0)
- ret = cc->rx_busy * 100 / cc->cycles;
-
- memset(cc, 0, sizeof(*cc));
-
- ath_update_survey_nf(sc, pos);
-
- return ret;
-}
-
static void __ath_cancel_work(struct ath_softc *sc)
{
cancel_work_sync(&sc->paprd_work);
@@ -235,6 +158,22 @@ static void ath_cancel_work(struct ath_softc *sc)
cancel_work_sync(&sc->hw_reset_work);
}
+static void ath_restart_work(struct ath_softc *sc)
+{
+ struct ath_common *common = ath9k_hw_common(sc->sc_ah);
+
+ ieee80211_queue_delayed_work(sc->hw, &sc->tx_complete_work, 0);
+
+ if (AR_SREV_9485(sc->sc_ah) || AR_SREV_9340(sc->sc_ah))
+ ieee80211_queue_delayed_work(sc->hw, &sc->hw_pll_work,
+ msecs_to_jiffies(ATH_PLL_WORK_INTERVAL));
+
+ ath_start_rx_poll(sc, 3);
+
+ if (!common->disable_ani)
+ ath_start_ani(common);
+}
+
static bool ath_prepare_reset(struct ath_softc *sc, bool retry_tx, bool flush)
{
struct ath_hw *ah = sc->sc_ah;
@@ -271,6 +210,7 @@ static bool ath_complete_reset(struct ath_softc *sc, bool start)
{
struct ath_hw *ah = sc->sc_ah;
struct ath_common *common = ath9k_hw_common(ah);
+ unsigned long flags;
if (ath_startrecv(sc) != 0) {
ath_err(common, "Unable to restart recv logic\n");
@@ -279,36 +219,30 @@ static bool ath_complete_reset(struct ath_softc *sc, bool start)
ath9k_cmn_update_txpow(ah, sc->curtxpow,
sc->config.txpowlimit, &sc->curtxpow);
+
+ clear_bit(SC_OP_HW_RESET, &sc->sc_flags);
ath9k_hw_set_interrupts(ah);
ath9k_hw_enable_interrupts(ah);
- if (!(sc->sc_flags & (SC_OP_OFFCHANNEL)) && start) {
- if (sc->sc_flags & SC_OP_BEACONS)
- ath_set_beacon(sc);
+ if (!(sc->hw->conf.flags & IEEE80211_CONF_OFFCHANNEL) && start) {
+ if (!test_bit(SC_OP_BEACONS, &sc->sc_flags))
+ goto work;
- ieee80211_queue_delayed_work(sc->hw, &sc->tx_complete_work, 0);
- ieee80211_queue_delayed_work(sc->hw, &sc->hw_pll_work, HZ/2);
- ath_start_rx_poll(sc, 3);
- if (!common->disable_ani)
- ath_start_ani(common);
- }
-
- if ((ah->caps.hw_caps & ATH9K_HW_CAP_ANT_DIV_COMB) && sc->ant_rx != 3) {
- struct ath_hw_antcomb_conf div_ant_conf;
- u8 lna_conf;
-
- ath9k_hw_antdiv_comb_conf_get(ah, &div_ant_conf);
-
- if (sc->ant_rx == 1)
- lna_conf = ATH_ANT_DIV_COMB_LNA1;
- else
- lna_conf = ATH_ANT_DIV_COMB_LNA2;
- div_ant_conf.main_lna_conf = lna_conf;
- div_ant_conf.alt_lna_conf = lna_conf;
+ ath_set_beacon(sc);
- ath9k_hw_antdiv_comb_conf_set(ah, &div_ant_conf);
+ if (ah->opmode == NL80211_IFTYPE_STATION &&
+ test_bit(SC_OP_PRIM_STA_VIF, &sc->sc_flags)) {
+ spin_lock_irqsave(&sc->sc_pm_lock, flags);
+ sc->ps_flags |= PS_BEACON_SYNC | PS_WAIT_FOR_BEACON;
+ spin_unlock_irqrestore(&sc->sc_pm_lock, flags);
+ }
+ work:
+ ath_restart_work(sc);
}
+ if ((ah->caps.hw_caps & ATH9K_HW_CAP_ANT_DIV_COMB) && sc->ant_rx != 3)
+ ath_ant_comb_update(sc);
+
ieee80211_wake_queues(sc->hw);
return true;
@@ -328,7 +262,7 @@ static int ath_reset_internal(struct ath_softc *sc, struct ath9k_channel *hchan,
spin_lock_bh(&sc->sc_pcu_lock);
- if (!(sc->sc_flags & SC_OP_OFFCHANNEL)) {
+ if (!(sc->hw->conf.flags & IEEE80211_CONF_OFFCHANNEL)) {
fastcc = false;
caldata = &sc->caldata;
}
@@ -371,7 +305,7 @@ static int ath_set_channel(struct ath_softc *sc, struct ieee80211_hw *hw,
{
int r;
- if (sc->sc_flags & SC_OP_INVALID)
+ if (test_bit(SC_OP_INVALID, &sc->sc_flags))
return -EIO;
r = ath_reset_internal(sc, hchan, false);
@@ -379,258 +313,6 @@ static int ath_set_channel(struct ath_softc *sc, struct ieee80211_hw *hw,
return r;
}
-static void ath_paprd_activate(struct ath_softc *sc)
-{
- struct ath_hw *ah = sc->sc_ah;
- struct ath9k_hw_cal_data *caldata = ah->caldata;
- int chain;
-
- if (!caldata || !caldata->paprd_done)
- return;
-
- ath9k_ps_wakeup(sc);
- ar9003_paprd_enable(ah, false);
- for (chain = 0; chain < AR9300_MAX_CHAINS; chain++) {
- if (!(ah->txchainmask & BIT(chain)))
- continue;
-
- ar9003_paprd_populate_single_table(ah, caldata, chain);
- }
-
- ar9003_paprd_enable(ah, true);
- ath9k_ps_restore(sc);
-}
-
-static bool ath_paprd_send_frame(struct ath_softc *sc, struct sk_buff *skb, int chain)
-{
- struct ieee80211_hw *hw = sc->hw;
- struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb);
- struct ath_hw *ah = sc->sc_ah;
- struct ath_common *common = ath9k_hw_common(ah);
- struct ath_tx_control txctl;
- int time_left;
-
- memset(&txctl, 0, sizeof(txctl));
- txctl.txq = sc->tx.txq_map[WME_AC_BE];
-
- memset(tx_info, 0, sizeof(*tx_info));
- tx_info->band = hw->conf.channel->band;
- tx_info->flags |= IEEE80211_TX_CTL_NO_ACK;
- tx_info->control.rates[0].idx = 0;
- tx_info->control.rates[0].count = 1;
- tx_info->control.rates[0].flags = IEEE80211_TX_RC_MCS;
- tx_info->control.rates[1].idx = -1;
-
- init_completion(&sc->paprd_complete);
- txctl.paprd = BIT(chain);
-
- if (ath_tx_start(hw, skb, &txctl) != 0) {
- ath_dbg(common, CALIBRATE, "PAPRD TX failed\n");
- dev_kfree_skb_any(skb);
- return false;
- }
-
- time_left = wait_for_completion_timeout(&sc->paprd_complete,
- msecs_to_jiffies(ATH_PAPRD_TIMEOUT));
-
- if (!time_left)
- ath_dbg(common, CALIBRATE,
- "Timeout waiting for paprd training on TX chain %d\n",
- chain);
-
- return !!time_left;
-}
-
-void ath_paprd_calibrate(struct work_struct *work)
-{
- struct ath_softc *sc = container_of(work, struct ath_softc, paprd_work);
- struct ieee80211_hw *hw = sc->hw;
- struct ath_hw *ah = sc->sc_ah;
- struct ieee80211_hdr *hdr;
- struct sk_buff *skb = NULL;
- struct ath9k_hw_cal_data *caldata = ah->caldata;
- struct ath_common *common = ath9k_hw_common(ah);
- int ftype;
- int chain_ok = 0;
- int chain;
- int len = 1800;
-
- if (!caldata)
- return;
-
- ath9k_ps_wakeup(sc);
-
- if (ar9003_paprd_init_table(ah) < 0)
- goto fail_paprd;
-
- skb = alloc_skb(len, GFP_KERNEL);
- if (!skb)
- goto fail_paprd;
-
- skb_put(skb, len);
- memset(skb->data, 0, len);
- hdr = (struct ieee80211_hdr *)skb->data;
- ftype = IEEE80211_FTYPE_DATA | IEEE80211_STYPE_NULLFUNC;
- hdr->frame_control = cpu_to_le16(ftype);
- hdr->duration_id = cpu_to_le16(10);
- memcpy(hdr->addr1, hw->wiphy->perm_addr, ETH_ALEN);
- memcpy(hdr->addr2, hw->wiphy->perm_addr, ETH_ALEN);
- memcpy(hdr->addr3, hw->wiphy->perm_addr, ETH_ALEN);
-
- for (chain = 0; chain < AR9300_MAX_CHAINS; chain++) {
- if (!(ah->txchainmask & BIT(chain)))
- continue;
-
- chain_ok = 0;
-
- ath_dbg(common, CALIBRATE,
- "Sending PAPRD frame for thermal measurement on chain %d\n",
- chain);
- if (!ath_paprd_send_frame(sc, skb, chain))
- goto fail_paprd;
-
- ar9003_paprd_setup_gain_table(ah, chain);
-
- ath_dbg(common, CALIBRATE,
- "Sending PAPRD training frame on chain %d\n", chain);
- if (!ath_paprd_send_frame(sc, skb, chain))
- goto fail_paprd;
-
- if (!ar9003_paprd_is_done(ah)) {
- ath_dbg(common, CALIBRATE,
- "PAPRD not yet done on chain %d\n", chain);
- break;
- }
-
- if (ar9003_paprd_create_curve(ah, caldata, chain)) {
- ath_dbg(common, CALIBRATE,
- "PAPRD create curve failed on chain %d\n",
- chain);
- break;
- }
-
- chain_ok = 1;
- }
- kfree_skb(skb);
-
- if (chain_ok) {
- caldata->paprd_done = true;
- ath_paprd_activate(sc);
- }
-
-fail_paprd:
- ath9k_ps_restore(sc);
-}
-
-/*
- * This routine performs the periodic noise floor calibration function
- * that is used to adjust and optimize the chip performance. This
- * takes environmental changes (location, temperature) into account.
- * When the task is complete, it reschedules itself depending on the
- * appropriate interval that was calculated.
- */
-void ath_ani_calibrate(unsigned long data)
-{
- struct ath_softc *sc = (struct ath_softc *)data;
- struct ath_hw *ah = sc->sc_ah;
- struct ath_common *common = ath9k_hw_common(ah);
- bool longcal = false;
- bool shortcal = false;
- bool aniflag = false;
- unsigned int timestamp = jiffies_to_msecs(jiffies);
- u32 cal_interval, short_cal_interval, long_cal_interval;
- unsigned long flags;
-
- if (ah->caldata && ah->caldata->nfcal_interference)
- long_cal_interval = ATH_LONG_CALINTERVAL_INT;
- else
- long_cal_interval = ATH_LONG_CALINTERVAL;
-
- short_cal_interval = (ah->opmode == NL80211_IFTYPE_AP) ?
- ATH_AP_SHORT_CALINTERVAL : ATH_STA_SHORT_CALINTERVAL;
-
- /* Only calibrate if awake */
- if (sc->sc_ah->power_mode != ATH9K_PM_AWAKE)
- goto set_timer;
-
- ath9k_ps_wakeup(sc);
-
- /* Long calibration runs independently of short calibration. */
- if ((timestamp - common->ani.longcal_timer) >= long_cal_interval) {
- longcal = true;
- common->ani.longcal_timer = timestamp;
- }
-
- /* Short calibration applies only while caldone is false */
- if (!common->ani.caldone) {
- if ((timestamp - common->ani.shortcal_timer) >= short_cal_interval) {
- shortcal = true;
- common->ani.shortcal_timer = timestamp;
- common->ani.resetcal_timer = timestamp;
- }
- } else {
- if ((timestamp - common->ani.resetcal_timer) >=
- ATH_RESTART_CALINTERVAL) {
- common->ani.caldone = ath9k_hw_reset_calvalid(ah);
- if (common->ani.caldone)
- common->ani.resetcal_timer = timestamp;
- }
- }
-
- /* Verify whether we must check ANI */
- if (sc->sc_ah->config.enable_ani
- && (timestamp - common->ani.checkani_timer) >=
- ah->config.ani_poll_interval) {
- aniflag = true;
- common->ani.checkani_timer = timestamp;
- }
-
- /* Call ANI routine if necessary */
- if (aniflag) {
- spin_lock_irqsave(&common->cc_lock, flags);
- ath9k_hw_ani_monitor(ah, ah->curchan);
- ath_update_survey_stats(sc);
- spin_unlock_irqrestore(&common->cc_lock, flags);
- }
-
- /* Perform calibration if necessary */
- if (longcal || shortcal) {
- common->ani.caldone =
- ath9k_hw_calibrate(ah, ah->curchan,
- ah->rxchainmask, longcal);
- }
-
- ath_dbg(common, ANI,
- "Calibration @%lu finished: %s %s %s, caldone: %s\n",
- jiffies,
- longcal ? "long" : "", shortcal ? "short" : "",
- aniflag ? "ani" : "", common->ani.caldone ? "true" : "false");
-
- ath9k_ps_restore(sc);
-
-set_timer:
- /*
- * Set timer interval based on previous results.
- * The interval must be the shortest necessary to satisfy ANI,
- * short calibration and long calibration.
- */
- ath9k_debug_samp_bb_mac(sc);
- cal_interval = ATH_LONG_CALINTERVAL;
- if (sc->sc_ah->config.enable_ani)
- cal_interval = min(cal_interval,
- (u32)ah->config.ani_poll_interval);
- if (!common->ani.caldone)
- cal_interval = min(cal_interval, (u32)short_cal_interval);
-
- mod_timer(&common->ani.timer, jiffies + msecs_to_jiffies(cal_interval));
- if ((sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_PAPRD) && ah->caldata) {
- if (!ah->caldata->paprd_done)
- ieee80211_queue_work(sc->hw, &sc->paprd_work);
- else if (!ah->paprd_table_write_done)
- ath_paprd_activate(sc);
- }
-}
-
static void ath_node_attach(struct ath_softc *sc, struct ieee80211_sta *sta,
struct ieee80211_vif *vif)
{
@@ -668,13 +350,12 @@ static void ath_node_detach(struct ath_softc *sc, struct ieee80211_sta *sta)
ath_tx_node_cleanup(sc, an);
}
-
void ath9k_tasklet(unsigned long data)
{
struct ath_softc *sc = (struct ath_softc *)data;
struct ath_hw *ah = sc->sc_ah;
struct ath_common *common = ath9k_hw_common(ah);
-
+ unsigned long flags;
u32 status = sc->intrstatus;
u32 rxmask;
@@ -693,10 +374,12 @@ void ath9k_tasklet(unsigned long data)
RESET_STAT_INC(sc, type);
#endif
+ set_bit(SC_OP_HW_RESET, &sc->sc_flags);
ieee80211_queue_work(sc->hw, &sc->hw_reset_work);
goto out;
}
+ spin_lock_irqsave(&sc->sc_pm_lock, flags);
if ((status & ATH9K_INT_TSFOOR) && sc->ps_enabled) {
/*
* TSF sync does not look correct; remain awake to sync with
@@ -705,6 +388,7 @@ void ath9k_tasklet(unsigned long data)
ath_dbg(common, PS, "TSFOOR - Sync with next Beacon\n");
sc->ps_flags |= PS_WAIT_FOR_BEACON | PS_BEACON_SYNC;
}
+ spin_unlock_irqrestore(&sc->sc_pm_lock, flags);
if (ah->caps.hw_caps & ATH9K_HW_CAP_EDMA)
rxmask = (ATH9K_INT_RXHP | ATH9K_INT_RXLP | ATH9K_INT_RXEOL |
@@ -766,15 +450,17 @@ irqreturn_t ath_isr(int irq, void *dev)
* touch anything. Note this can happen early
* on if the IRQ is shared.
*/
- if (sc->sc_flags & SC_OP_INVALID)
+ if (test_bit(SC_OP_INVALID, &sc->sc_flags))
return IRQ_NONE;
-
/* shared irq, not for us */
if (!ath9k_hw_intrpend(ah))
return IRQ_NONE;
+ if(test_bit(SC_OP_HW_RESET, &sc->sc_flags))
+ return IRQ_HANDLED;
+
/*
* Figure out the reason(s) for the interrupt. Note
* that the hal returns a pseudo-ISR that may include
@@ -852,8 +538,10 @@ irqreturn_t ath_isr(int irq, void *dev)
/* Clear RxAbort bit so that we can
* receive frames */
ath9k_setpower(sc, ATH9K_PM_AWAKE);
+ spin_lock(&sc->sc_pm_lock);
ath9k_hw_setrxabort(sc->sc_ah, 0);
sc->ps_flags |= PS_WAIT_FOR_BEACON;
+ spin_unlock(&sc->sc_pm_lock);
}
chip_reset:
@@ -902,87 +590,6 @@ void ath_reset_work(struct work_struct *work)
ath_reset(sc, true);
}
-void ath_hw_check(struct work_struct *work)
-{
- struct ath_softc *sc = container_of(work, struct ath_softc, hw_check_work);
- struct ath_common *common = ath9k_hw_common(sc->sc_ah);
- unsigned long flags;
- int busy;
- u8 is_alive, nbeacon = 1;
-
- ath9k_ps_wakeup(sc);
- is_alive = ath9k_hw_check_alive(sc->sc_ah);
-
- if (is_alive && !AR_SREV_9300(sc->sc_ah))
- goto out;
- else if (!is_alive && AR_SREV_9300(sc->sc_ah)) {
- ath_dbg(common, RESET,
- "DCU stuck is detected. Schedule chip reset\n");
- RESET_STAT_INC(sc, RESET_TYPE_MAC_HANG);
- goto sched_reset;
- }
-
- spin_lock_irqsave(&common->cc_lock, flags);
- busy = ath_update_survey_stats(sc);
- spin_unlock_irqrestore(&common->cc_lock, flags);
-
- ath_dbg(common, RESET, "Possible baseband hang, busy=%d (try %d)\n",
- busy, sc->hw_busy_count + 1);
- if (busy >= 99) {
- if (++sc->hw_busy_count >= 3) {
- RESET_STAT_INC(sc, RESET_TYPE_BB_HANG);
- goto sched_reset;
- }
- } else if (busy >= 0) {
- sc->hw_busy_count = 0;
- nbeacon = 3;
- }
-
- ath_start_rx_poll(sc, nbeacon);
- goto out;
-
-sched_reset:
- ieee80211_queue_work(sc->hw, &sc->hw_reset_work);
-out:
- ath9k_ps_restore(sc);
-}
-
-static void ath_hw_pll_rx_hang_check(struct ath_softc *sc, u32 pll_sqsum)
-{
- static int count;
- struct ath_common *common = ath9k_hw_common(sc->sc_ah);
-
- if (pll_sqsum >= 0x40000) {
- count++;
- if (count == 3) {
- /* Rx is hung for more than 500ms. Reset it */
- ath_dbg(common, RESET, "Possible RX hang, resetting\n");
- RESET_STAT_INC(sc, RESET_TYPE_PLL_HANG);
- ieee80211_queue_work(sc->hw, &sc->hw_reset_work);
- count = 0;
- }
- } else
- count = 0;
-}
-
-void ath_hw_pll_work(struct work_struct *work)
-{
- struct ath_softc *sc = container_of(work, struct ath_softc,
- hw_pll_work.work);
- u32 pll_sqsum;
-
- if (AR_SREV_9485(sc->sc_ah)) {
-
- ath9k_ps_wakeup(sc);
- pll_sqsum = ar9003_get_pll_sqsum_dvc(sc->sc_ah);
- ath9k_ps_restore(sc);
-
- ath_hw_pll_rx_hang_check(sc, pll_sqsum);
-
- ieee80211_queue_delayed_work(sc->hw, &sc->hw_pll_work, HZ/5);
- }
-}
-
/**********************/
/* mac80211 callbacks */
/**********************/
@@ -1045,10 +652,9 @@ static int ath9k_start(struct ieee80211_hw *hw)
if (ah->caps.hw_caps & ATH9K_HW_CAP_HT)
ah->imask |= ATH9K_INT_CST;
- if (ah->caps.hw_caps & ATH9K_HW_CAP_MCI)
- ah->imask |= ATH9K_INT_MCI;
+ ath_mci_enable(sc);
- sc->sc_flags &= ~SC_OP_INVALID;
+ clear_bit(SC_OP_INVALID, &sc->sc_flags);
sc->sc_ah->is_monitoring = false;
if (!ath_complete_reset(sc, false)) {
@@ -1090,6 +696,7 @@ static void ath9k_tx(struct ieee80211_hw *hw, struct sk_buff *skb)
struct ath_common *common = ath9k_hw_common(sc->sc_ah);
struct ath_tx_control txctl;
struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data;
+ unsigned long flags;
if (sc->ps_enabled) {
/*
@@ -1112,6 +719,7 @@ static void ath9k_tx(struct ieee80211_hw *hw, struct sk_buff *skb)
* completed and if needed, also for RX of buffered frames.
*/
ath9k_ps_wakeup(sc);
+ spin_lock_irqsave(&sc->sc_pm_lock, flags);
if (!(sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_AUTOSLEEP))
ath9k_hw_setrxabort(sc->sc_ah, 0);
if (ieee80211_is_pspoll(hdr->frame_control)) {
@@ -1127,6 +735,7 @@ static void ath9k_tx(struct ieee80211_hw *hw, struct sk_buff *skb)
* the ps_flags bit is cleared. We are just dropping
* the ps_usecount here.
*/
+ spin_unlock_irqrestore(&sc->sc_pm_lock, flags);
ath9k_ps_restore(sc);
}
@@ -1167,7 +776,7 @@ static void ath9k_stop(struct ieee80211_hw *hw)
ath_cancel_work(sc);
del_timer_sync(&sc->rx_poll_timer);
- if (sc->sc_flags & SC_OP_INVALID) {
+ if (test_bit(SC_OP_INVALID, &sc->sc_flags)) {
ath_dbg(common, ANY, "Device not present\n");
mutex_unlock(&sc->mutex);
return;
@@ -1224,7 +833,7 @@ static void ath9k_stop(struct ieee80211_hw *hw)
ath9k_ps_restore(sc);
- sc->sc_flags |= SC_OP_INVALID;
+ set_bit(SC_OP_INVALID, &sc->sc_flags);
sc->ps_idle = prev_idle;
mutex_unlock(&sc->mutex);
@@ -1328,11 +937,11 @@ static void ath9k_calculate_summary_state(struct ieee80211_hw *hw,
/* Set op-mode & TSF */
if (iter_data.naps > 0) {
ath9k_hw_set_tsfadjust(ah, 1);
- sc->sc_flags |= SC_OP_TSF_RESET;
+ set_bit(SC_OP_TSF_RESET, &sc->sc_flags);
ah->opmode = NL80211_IFTYPE_AP;
} else {
ath9k_hw_set_tsfadjust(ah, 0);
- sc->sc_flags &= ~SC_OP_TSF_RESET;
+ clear_bit(SC_OP_TSF_RESET, &sc->sc_flags);
if (iter_data.nmeshes)
ah->opmode = NL80211_IFTYPE_MESH_POINT;
@@ -1363,12 +972,12 @@ static void ath9k_calculate_summary_state(struct ieee80211_hw *hw,
sc->sc_ah->stats.avgbrssi = ATH_RSSI_DUMMY_MARKER;
if (!common->disable_ani) {
- sc->sc_flags |= SC_OP_ANI_RUN;
+ set_bit(SC_OP_ANI_RUN, &sc->sc_flags);
ath_start_ani(common);
}
} else {
- sc->sc_flags &= ~SC_OP_ANI_RUN;
+ clear_bit(SC_OP_ANI_RUN, &sc->sc_flags);
del_timer_sync(&common->ani.timer);
}
}
@@ -1389,25 +998,6 @@ static void ath9k_do_vif_add_setup(struct ieee80211_hw *hw,
}
}
-void ath_start_rx_poll(struct ath_softc *sc, u8 nbeacon)
-{
- if (!AR_SREV_9300(sc->sc_ah))
- return;
-
- if (!(sc->sc_flags & SC_OP_PRIM_STA_VIF))
- return;
-
- mod_timer(&sc->rx_poll_timer, jiffies + msecs_to_jiffies
- (nbeacon * sc->cur_beacon_conf.beacon_interval));
-}
-
-void ath_rx_poll(unsigned long data)
-{
- struct ath_softc *sc = (struct ath_softc *)data;
-
- ieee80211_queue_work(sc->hw, &sc->hw_check_work);
-}
-
static int ath9k_add_interface(struct ieee80211_hw *hw,
struct ieee80211_vif *vif)
{
@@ -1627,11 +1217,6 @@ static int ath9k_config(struct ieee80211_hw *hw, u32 changed)
if (ah->curchan)
old_pos = ah->curchan - &ah->channels[0];
- if (hw->conf.flags & IEEE80211_CONF_OFFCHANNEL)
- sc->sc_flags |= SC_OP_OFFCHANNEL;
- else
- sc->sc_flags &= ~SC_OP_OFFCHANNEL;
-
ath_dbg(common, CONFIG, "Set channel: %d MHz type: %d\n",
curchan->center_freq, conf->channel_type);
@@ -1911,16 +1496,16 @@ static void ath9k_bss_iter(void *data, u8 *mac, struct ieee80211_vif *vif)
struct ath_common *common = ath9k_hw_common(sc->sc_ah);
struct ieee80211_bss_conf *bss_conf = &vif->bss_conf;
struct ath_vif *avp = (void *)vif->drv_priv;
-
+ unsigned long flags;
/*
* Skip iteration if primary station vif's bss info
* was not changed
*/
- if (sc->sc_flags & SC_OP_PRIM_STA_VIF)
+ if (test_bit(SC_OP_PRIM_STA_VIF, &sc->sc_flags))
return;
if (bss_conf->assoc) {
- sc->sc_flags |= SC_OP_PRIM_STA_VIF;
+ set_bit(SC_OP_PRIM_STA_VIF, &sc->sc_flags);
avp->primary_sta_vif = true;
memcpy(common->curbssid, bss_conf->bssid, ETH_ALEN);
common->curaid = bss_conf->aid;
@@ -1933,7 +1518,10 @@ static void ath9k_bss_iter(void *data, u8 *mac, struct ieee80211_vif *vif)
* on the receipt of the first Beacon frame (i.e.,
* after time sync with the AP).
*/
+ spin_lock_irqsave(&sc->sc_pm_lock, flags);
sc->ps_flags |= PS_BEACON_SYNC | PS_WAIT_FOR_BEACON;
+ spin_unlock_irqrestore(&sc->sc_pm_lock, flags);
+
/* Reset rssi stats */
sc->last_rssi = ATH_RSSI_DUMMY_MARKER;
sc->sc_ah->stats.avgbrssi = ATH_RSSI_DUMMY_MARKER;
@@ -1941,7 +1529,7 @@ static void ath9k_bss_iter(void *data, u8 *mac, struct ieee80211_vif *vif)
ath_start_rx_poll(sc, 3);
if (!common->disable_ani) {
- sc->sc_flags |= SC_OP_ANI_RUN;
+ set_bit(SC_OP_ANI_RUN, &sc->sc_flags);
ath_start_ani(common);
}
@@ -1961,7 +1549,8 @@ static void ath9k_config_bss(struct ath_softc *sc, struct ieee80211_vif *vif)
if (avp->primary_sta_vif && !bss_conf->assoc) {
ath_dbg(common, CONFIG, "Bss Info DISASSOC %d, bssid %pM\n",
common->curaid, common->curbssid);
- sc->sc_flags &= ~(SC_OP_PRIM_STA_VIF | SC_OP_BEACONS);
+ clear_bit(SC_OP_PRIM_STA_VIF, &sc->sc_flags);
+ clear_bit(SC_OP_BEACONS, &sc->sc_flags);
avp->primary_sta_vif = false;
memset(common->curbssid, 0, ETH_ALEN);
common->curaid = 0;
@@ -1974,10 +1563,9 @@ static void ath9k_config_bss(struct ath_softc *sc, struct ieee80211_vif *vif)
* None of station vifs are associated.
* Clear bssid & aid
*/
- if (!(sc->sc_flags & SC_OP_PRIM_STA_VIF)) {
+ if (!test_bit(SC_OP_PRIM_STA_VIF, &sc->sc_flags)) {
ath9k_hw_write_associd(sc->sc_ah);
- /* Stop ANI */
- sc->sc_flags &= ~SC_OP_ANI_RUN;
+ clear_bit(SC_OP_ANI_RUN, &sc->sc_flags);
del_timer_sync(&common->ani.timer);
del_timer_sync(&sc->rx_poll_timer);
memset(&sc->caldata, 0, sizeof(sc->caldata));
@@ -2015,12 +1603,12 @@ static void ath9k_bss_info_changed(struct ieee80211_hw *hw,
sc->sc_ah->stats.avgbrssi = ATH_RSSI_DUMMY_MARKER;
if (!common->disable_ani) {
- sc->sc_flags |= SC_OP_ANI_RUN;
+ set_bit(SC_OP_ANI_RUN, &sc->sc_flags);
ath_start_ani(common);
}
} else {
- sc->sc_flags &= ~SC_OP_ANI_RUN;
+ clear_bit(SC_OP_ANI_RUN, &sc->sc_flags);
del_timer_sync(&common->ani.timer);
del_timer_sync(&sc->rx_poll_timer);
}
@@ -2032,7 +1620,7 @@ static void ath9k_bss_info_changed(struct ieee80211_hw *hw,
*/
if ((changed & BSS_CHANGED_BEACON_INT) &&
(vif->type == NL80211_IFTYPE_AP))
- sc->sc_flags |= SC_OP_TSF_RESET;
+ set_bit(SC_OP_TSF_RESET, &sc->sc_flags);
/* Configure beaconing (AP, IBSS, MESH) */
if (ath9k_uses_beacons(vif->type) &&
@@ -2224,7 +1812,7 @@ static void ath9k_flush(struct ieee80211_hw *hw, bool drop)
return;
}
- if (sc->sc_flags & SC_OP_INVALID) {
+ if (test_bit(SC_OP_INVALID, &sc->sc_flags)) {
ath_dbg(common, ANY, "Device not present\n");
mutex_unlock(&sc->mutex);
return;
@@ -2389,6 +1977,134 @@ static int ath9k_get_antenna(struct ieee80211_hw *hw, u32 *tx_ant, u32 *rx_ant)
return 0;
}
+#ifdef CONFIG_ATH9K_DEBUGFS
+
+/* Ethtool support for get-stats */
+
+#define AMKSTR(nm) #nm "_BE", #nm "_BK", #nm "_VI", #nm "_VO"
+static const char ath9k_gstrings_stats[][ETH_GSTRING_LEN] = {
+ "tx_pkts_nic",
+ "tx_bytes_nic",
+ "rx_pkts_nic",
+ "rx_bytes_nic",
+ AMKSTR(d_tx_pkts),
+ AMKSTR(d_tx_bytes),
+ AMKSTR(d_tx_mpdus_queued),
+ AMKSTR(d_tx_mpdus_completed),
+ AMKSTR(d_tx_mpdu_xretries),
+ AMKSTR(d_tx_aggregates),
+ AMKSTR(d_tx_ampdus_queued_hw),
+ AMKSTR(d_tx_ampdus_queued_sw),
+ AMKSTR(d_tx_ampdus_completed),
+ AMKSTR(d_tx_ampdu_retries),
+ AMKSTR(d_tx_ampdu_xretries),
+ AMKSTR(d_tx_fifo_underrun),
+ AMKSTR(d_tx_op_exceeded),
+ AMKSTR(d_tx_timer_expiry),
+ AMKSTR(d_tx_desc_cfg_err),
+ AMKSTR(d_tx_data_underrun),
+ AMKSTR(d_tx_delim_underrun),
+
+ "d_rx_decrypt_crc_err",
+ "d_rx_phy_err",
+ "d_rx_mic_err",
+ "d_rx_pre_delim_crc_err",
+ "d_rx_post_delim_crc_err",
+ "d_rx_decrypt_busy_err",
+
+ "d_rx_phyerr_radar",
+ "d_rx_phyerr_ofdm_timing",
+ "d_rx_phyerr_cck_timing",
+
+};
+#define ATH9K_SSTATS_LEN ARRAY_SIZE(ath9k_gstrings_stats)
+
+static void ath9k_get_et_strings(struct ieee80211_hw *hw,
+ struct ieee80211_vif *vif,
+ u32 sset, u8 *data)
+{
+ if (sset == ETH_SS_STATS)
+ memcpy(data, *ath9k_gstrings_stats,
+ sizeof(ath9k_gstrings_stats));
+}
+
+static int ath9k_get_et_sset_count(struct ieee80211_hw *hw,
+ struct ieee80211_vif *vif, int sset)
+{
+ if (sset == ETH_SS_STATS)
+ return ATH9K_SSTATS_LEN;
+ return 0;
+}
+
+#define PR_QNUM(_n) (sc->tx.txq_map[_n]->axq_qnum)
+#define AWDATA(elem) \
+ do { \
+ data[i++] = sc->debug.stats.txstats[PR_QNUM(WME_AC_BE)].elem; \
+ data[i++] = sc->debug.stats.txstats[PR_QNUM(WME_AC_BK)].elem; \
+ data[i++] = sc->debug.stats.txstats[PR_QNUM(WME_AC_VI)].elem; \
+ data[i++] = sc->debug.stats.txstats[PR_QNUM(WME_AC_VO)].elem; \
+ } while (0)
+
+#define AWDATA_RX(elem) \
+ do { \
+ data[i++] = sc->debug.stats.rxstats.elem; \
+ } while (0)
+
+static void ath9k_get_et_stats(struct ieee80211_hw *hw,
+ struct ieee80211_vif *vif,
+ struct ethtool_stats *stats, u64 *data)
+{
+ struct ath_softc *sc = hw->priv;
+ int i = 0;
+
+ data[i++] = (sc->debug.stats.txstats[PR_QNUM(WME_AC_BE)].tx_pkts_all +
+ sc->debug.stats.txstats[PR_QNUM(WME_AC_BK)].tx_pkts_all +
+ sc->debug.stats.txstats[PR_QNUM(WME_AC_VI)].tx_pkts_all +
+ sc->debug.stats.txstats[PR_QNUM(WME_AC_VO)].tx_pkts_all);
+ data[i++] = (sc->debug.stats.txstats[PR_QNUM(WME_AC_BE)].tx_bytes_all +
+ sc->debug.stats.txstats[PR_QNUM(WME_AC_BK)].tx_bytes_all +
+ sc->debug.stats.txstats[PR_QNUM(WME_AC_VI)].tx_bytes_all +
+ sc->debug.stats.txstats[PR_QNUM(WME_AC_VO)].tx_bytes_all);
+ AWDATA_RX(rx_pkts_all);
+ AWDATA_RX(rx_bytes_all);
+
+ AWDATA(tx_pkts_all);
+ AWDATA(tx_bytes_all);
+ AWDATA(queued);
+ AWDATA(completed);
+ AWDATA(xretries);
+ AWDATA(a_aggr);
+ AWDATA(a_queued_hw);
+ AWDATA(a_queued_sw);
+ AWDATA(a_completed);
+ AWDATA(a_retries);
+ AWDATA(a_xretries);
+ AWDATA(fifo_underrun);
+ AWDATA(xtxop);
+ AWDATA(timer_exp);
+ AWDATA(desc_cfg_err);
+ AWDATA(data_underrun);
+ AWDATA(delim_underrun);
+
+ AWDATA_RX(decrypt_crc_err);
+ AWDATA_RX(phy_err);
+ AWDATA_RX(mic_err);
+ AWDATA_RX(pre_delim_crc_err);
+ AWDATA_RX(post_delim_crc_err);
+ AWDATA_RX(decrypt_busy_err);
+
+ AWDATA_RX(phy_err_stats[ATH9K_PHYERR_RADAR]);
+ AWDATA_RX(phy_err_stats[ATH9K_PHYERR_OFDM_TIMING]);
+ AWDATA_RX(phy_err_stats[ATH9K_PHYERR_CCK_TIMING]);
+
+ WARN_ON(i != ATH9K_SSTATS_LEN);
+}
+
+/* End of ethtool get-stats functions */
+
+#endif
+
+
struct ieee80211_ops ath9k_ops = {
.tx = ath9k_tx,
.start = ath9k_start,
@@ -2417,4 +2133,10 @@ struct ieee80211_ops ath9k_ops = {
.get_stats = ath9k_get_stats,
.set_antenna = ath9k_set_antenna,
.get_antenna = ath9k_get_antenna,
+
+#ifdef CONFIG_ATH9K_DEBUGFS
+ .get_et_sset_count = ath9k_get_et_sset_count,
+ .get_et_stats = ath9k_get_et_stats,
+ .get_et_strings = ath9k_get_et_strings,
+#endif
};
diff --git a/drivers/net/wireless/ath/ath9k/mci.c b/drivers/net/wireless/ath/ath9k/mci.c
index 29fe52d6997..49137f477b0 100644
--- a/drivers/net/wireless/ath/ath9k/mci.c
+++ b/drivers/net/wireless/ath/ath9k/mci.c
@@ -116,42 +116,58 @@ static void ath_mci_update_scheme(struct ath_softc *sc)
struct ath_common *common = ath9k_hw_common(sc->sc_ah);
struct ath_btcoex *btcoex = &sc->btcoex;
struct ath_mci_profile *mci = &btcoex->mci;
+ struct ath9k_hw_mci *mci_hw = &sc->sc_ah->btcoex_hw.mci;
struct ath_mci_profile_info *info;
u32 num_profile = NUM_PROF(mci);
+ if (mci_hw->config & ATH_MCI_CONFIG_DISABLE_TUNING)
+ goto skip_tuning;
+
if (num_profile == 1) {
info = list_first_entry(&mci->info,
struct ath_mci_profile_info,
list);
- if (mci->num_sco && info->T == 12) {
- mci->aggr_limit = 8;
+ if (mci->num_sco) {
+ if (info->T == 12)
+ mci->aggr_limit = 8;
+ else if (info->T == 6) {
+ mci->aggr_limit = 6;
+ btcoex->duty_cycle = 30;
+ }
ath_dbg(common, MCI,
- "Single SCO, aggregation limit 2 ms\n");
- } else if ((info->type == MCI_GPM_COEX_PROFILE_BNEP) &&
- !info->master) {
- btcoex->btcoex_period = 60;
+ "Single SCO, aggregation limit %d 1/4 ms\n",
+ mci->aggr_limit);
+ } else if (mci->num_pan || mci->num_other_acl) {
+ /*
+ * For single PAN/FTP profile, allocate 35% for BT
+ * to improve WLAN throughput.
+ */
+ btcoex->duty_cycle = 35;
+ btcoex->btcoex_period = 53;
ath_dbg(common, MCI,
- "Single slave PAN/FTP, bt period 60 ms\n");
- } else if ((info->type == MCI_GPM_COEX_PROFILE_HID) &&
- (info->T > 0 && info->T < 50) &&
- (info->A > 1 || info->W > 1)) {
+ "Single PAN/FTP bt period %d ms dutycycle %d\n",
+ btcoex->duty_cycle, btcoex->btcoex_period);
+ } else if (mci->num_hid) {
btcoex->duty_cycle = 30;
- mci->aggr_limit = 8;
+ mci->aggr_limit = 6;
ath_dbg(common, MCI,
"Multiple attempt/timeout single HID "
- "aggregation limit 2 ms dutycycle 30%%\n");
+ "aggregation limit 1.5 ms dutycycle 30%%\n");
}
- } else if ((num_profile == 2) && (mci->num_hid == 2)) {
- btcoex->duty_cycle = 30;
- mci->aggr_limit = 8;
- ath_dbg(common, MCI,
- "Two HIDs aggregation limit 2 ms dutycycle 30%%\n");
- } else if (num_profile > 3) {
+ } else if (num_profile == 2) {
+ if (mci->num_hid == 2)
+ btcoex->duty_cycle = 30;
mci->aggr_limit = 6;
ath_dbg(common, MCI,
- "Three or more profiles aggregation limit 1.5 ms\n");
+ "Two BT profiles aggr limit 1.5 ms dutycycle %d%%\n",
+ btcoex->duty_cycle);
+ } else if (num_profile >= 3) {
+ mci->aggr_limit = 4;
+ ath_dbg(common, MCI,
+ "Three or more profiles aggregation limit 1 ms\n");
}
+skip_tuning:
if (IS_CHAN_2GHZ(sc->sc_ah->curchan)) {
if (IS_CHAN_HT(sc->sc_ah->curchan))
ath_mci_adjust_aggr_limit(btcoex);
@@ -538,3 +554,14 @@ void ath_mci_intr(struct ath_softc *sc)
mci_int &= ~(AR_MCI_INTERRUPT_RX_INVALID_HDR |
AR_MCI_INTERRUPT_CONT_INFO_TIMEOUT);
}
+
+void ath_mci_enable(struct ath_softc *sc)
+{
+ struct ath_common *common = ath9k_hw_common(sc->sc_ah);
+
+ if (!common->btcoex_enabled)
+ return;
+
+ if (sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_MCI)
+ sc->sc_ah->imask |= ATH9K_INT_MCI;
+}
diff --git a/drivers/net/wireless/ath/ath9k/mci.h b/drivers/net/wireless/ath/ath9k/mci.h
index c841444f53c..fc14eea034e 100644
--- a/drivers/net/wireless/ath/ath9k/mci.h
+++ b/drivers/net/wireless/ath/ath9k/mci.h
@@ -130,4 +130,13 @@ void ath_mci_flush_profile(struct ath_mci_profile *mci);
int ath_mci_setup(struct ath_softc *sc);
void ath_mci_cleanup(struct ath_softc *sc);
void ath_mci_intr(struct ath_softc *sc);
-#endif
+
+#ifdef CONFIG_ATH9K_BTCOEX_SUPPORT
+void ath_mci_enable(struct ath_softc *sc);
+#else
+static inline void ath_mci_enable(struct ath_softc *sc)
+{
+}
+#endif /* CONFIG_ATH9K_BTCOEX_SUPPORT */
+
+#endif /* MCI_H*/
diff --git a/drivers/net/wireless/ath/ath9k/pci.c b/drivers/net/wireless/ath/ath9k/pci.c
index a856b51255f..aa0e83ac51f 100644
--- a/drivers/net/wireless/ath/ath9k/pci.c
+++ b/drivers/net/wireless/ath/ath9k/pci.c
@@ -115,6 +115,9 @@ static void ath_pci_aspm_init(struct ath_common *common)
int pos;
u8 aspm;
+ if (!ah->is_pciexpress)
+ return;
+
pos = pci_pcie_cap(pdev);
if (!pos)
return;
@@ -138,6 +141,7 @@ static void ath_pci_aspm_init(struct ath_common *common)
aspm &= ~(PCIE_LINK_STATE_L0S | PCIE_LINK_STATE_L1);
pci_write_config_byte(parent, pos + PCI_EXP_LNKCTL, aspm);
+ ath_info(common, "Disabling ASPM since BTCOEX is enabled\n");
return;
}
@@ -147,6 +151,7 @@ static void ath_pci_aspm_init(struct ath_common *common)
ah->aspm_enabled = true;
/* Initialize PCIe PM and SERDES registers. */
ath9k_hw_configpcipowersave(ah, false);
+ ath_info(common, "ASPM enabled: 0x%x\n", aspm);
}
}
@@ -246,7 +251,7 @@ static int ath_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id)
sc->mem = mem;
/* Will be cleared in ath9k_start() */
- sc->sc_flags |= SC_OP_INVALID;
+ set_bit(SC_OP_INVALID, &sc->sc_flags);
ret = request_irq(pdev->irq, ath_isr, IRQF_SHARED, "ath9k", sc);
if (ret) {
diff --git a/drivers/net/wireless/ath/ath9k/recv.c b/drivers/net/wireless/ath/ath9k/recv.c
index e1fcc68124d..fbdcc80437f 100644
--- a/drivers/net/wireless/ath/ath9k/recv.c
+++ b/drivers/net/wireless/ath/ath9k/recv.c
@@ -20,43 +20,6 @@
#define SKB_CB_ATHBUF(__skb) (*((struct ath_buf **)__skb->cb))
-static inline bool ath_is_alt_ant_ratio_better(int alt_ratio, int maxdelta,
- int mindelta, int main_rssi_avg,
- int alt_rssi_avg, int pkt_count)
-{
- return (((alt_ratio >= ATH_ANT_DIV_COMB_ALT_ANT_RATIO2) &&
- (alt_rssi_avg > main_rssi_avg + maxdelta)) ||
- (alt_rssi_avg > main_rssi_avg + mindelta)) && (pkt_count > 50);
-}
-
-static inline bool ath_ant_div_comb_alt_check(u8 div_group, int alt_ratio,
- int curr_main_set, int curr_alt_set,
- int alt_rssi_avg, int main_rssi_avg)
-{
- bool result = false;
- switch (div_group) {
- case 0:
- if (alt_ratio > ATH_ANT_DIV_COMB_ALT_ANT_RATIO)
- result = true;
- break;
- case 1:
- case 2:
- if ((((curr_main_set == ATH_ANT_DIV_COMB_LNA2) &&
- (curr_alt_set == ATH_ANT_DIV_COMB_LNA1) &&
- (alt_rssi_avg >= (main_rssi_avg - 5))) ||
- ((curr_main_set == ATH_ANT_DIV_COMB_LNA1) &&
- (curr_alt_set == ATH_ANT_DIV_COMB_LNA2) &&
- (alt_rssi_avg >= (main_rssi_avg - 2)))) &&
- (alt_rssi_avg >= 4))
- result = true;
- else
- result = false;
- break;
- }
-
- return result;
-}
-
static inline bool ath9k_check_auto_sleep(struct ath_softc *sc)
{
return sc->ps_enabled &&
@@ -303,7 +266,7 @@ static void ath_edma_start_recv(struct ath_softc *sc)
ath_opmode_init(sc);
- ath9k_hw_startpcureceive(sc->sc_ah, (sc->sc_flags & SC_OP_OFFCHANNEL));
+ ath9k_hw_startpcureceive(sc->sc_ah, !!(sc->hw->conf.flags & IEEE80211_CONF_OFFCHANNEL));
spin_unlock_bh(&sc->rx.rxbuflock);
}
@@ -322,8 +285,8 @@ int ath_rx_init(struct ath_softc *sc, int nbufs)
int error = 0;
spin_lock_init(&sc->sc_pcu_lock);
- sc->sc_flags &= ~SC_OP_RXFLUSH;
spin_lock_init(&sc->rx.rxbuflock);
+ clear_bit(SC_OP_RXFLUSH, &sc->sc_flags);
common->rx_bufsize = IEEE80211_MAX_MPDU_LEN / 2 +
sc->sc_ah->caps.rx_status_len;
@@ -500,7 +463,7 @@ int ath_startrecv(struct ath_softc *sc)
start_recv:
ath_opmode_init(sc);
- ath9k_hw_startpcureceive(ah, (sc->sc_flags & SC_OP_OFFCHANNEL));
+ ath9k_hw_startpcureceive(ah, !!(sc->hw->conf.flags & IEEE80211_CONF_OFFCHANNEL));
spin_unlock_bh(&sc->rx.rxbuflock);
@@ -535,11 +498,11 @@ bool ath_stoprecv(struct ath_softc *sc)
void ath_flushrecv(struct ath_softc *sc)
{
- sc->sc_flags |= SC_OP_RXFLUSH;
+ set_bit(SC_OP_RXFLUSH, &sc->sc_flags);
if (sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_EDMA)
ath_rx_tasklet(sc, 1, true);
ath_rx_tasklet(sc, 1, false);
- sc->sc_flags &= ~SC_OP_RXFLUSH;
+ clear_bit(SC_OP_RXFLUSH, &sc->sc_flags);
}
static bool ath_beacon_dtim_pending_cab(struct sk_buff *skb)
@@ -624,13 +587,13 @@ static void ath_rx_ps(struct ath_softc *sc, struct sk_buff *skb, bool mybeacon)
/* Process Beacon and CAB receive in PS state */
if (((sc->ps_flags & PS_WAIT_FOR_BEACON) || ath9k_check_auto_sleep(sc))
- && mybeacon)
+ && mybeacon) {
ath_rx_ps_beacon(sc, skb);
- else if ((sc->ps_flags & PS_WAIT_FOR_CAB) &&
- (ieee80211_is_data(hdr->frame_control) ||
- ieee80211_is_action(hdr->frame_control)) &&
- is_multicast_ether_addr(hdr->addr1) &&
- !ieee80211_has_moredata(hdr->frame_control)) {
+ } else if ((sc->ps_flags & PS_WAIT_FOR_CAB) &&
+ (ieee80211_is_data(hdr->frame_control) ||
+ ieee80211_is_action(hdr->frame_control)) &&
+ is_multicast_ether_addr(hdr->addr1) &&
+ !ieee80211_has_moredata(hdr->frame_control)) {
/*
* No more broadcast/multicast frames to be received at this
* point.
@@ -1067,709 +1030,6 @@ static void ath9k_rx_skb_postprocess(struct ath_common *common,
rxs->flag &= ~RX_FLAG_DECRYPTED;
}
-static void ath_lnaconf_alt_good_scan(struct ath_ant_comb *antcomb,
- struct ath_hw_antcomb_conf ant_conf,
- int main_rssi_avg)
-{
- antcomb->quick_scan_cnt = 0;
-
- if (ant_conf.main_lna_conf == ATH_ANT_DIV_COMB_LNA2)
- antcomb->rssi_lna2 = main_rssi_avg;
- else if (ant_conf.main_lna_conf == ATH_ANT_DIV_COMB_LNA1)
- antcomb->rssi_lna1 = main_rssi_avg;
-
- switch ((ant_conf.main_lna_conf << 4) | ant_conf.alt_lna_conf) {
- case 0x10: /* LNA2 A-B */
- antcomb->main_conf = ATH_ANT_DIV_COMB_LNA1_MINUS_LNA2;
- antcomb->first_quick_scan_conf =
- ATH_ANT_DIV_COMB_LNA1_PLUS_LNA2;
- antcomb->second_quick_scan_conf = ATH_ANT_DIV_COMB_LNA1;
- break;
- case 0x20: /* LNA1 A-B */
- antcomb->main_conf = ATH_ANT_DIV_COMB_LNA1_MINUS_LNA2;
- antcomb->first_quick_scan_conf =
- ATH_ANT_DIV_COMB_LNA1_PLUS_LNA2;
- antcomb->second_quick_scan_conf = ATH_ANT_DIV_COMB_LNA2;
- break;
- case 0x21: /* LNA1 LNA2 */
- antcomb->main_conf = ATH_ANT_DIV_COMB_LNA2;
- antcomb->first_quick_scan_conf =
- ATH_ANT_DIV_COMB_LNA1_MINUS_LNA2;
- antcomb->second_quick_scan_conf =
- ATH_ANT_DIV_COMB_LNA1_PLUS_LNA2;
- break;
- case 0x12: /* LNA2 LNA1 */
- antcomb->main_conf = ATH_ANT_DIV_COMB_LNA1;
- antcomb->first_quick_scan_conf =
- ATH_ANT_DIV_COMB_LNA1_MINUS_LNA2;
- antcomb->second_quick_scan_conf =
- ATH_ANT_DIV_COMB_LNA1_PLUS_LNA2;
- break;
- case 0x13: /* LNA2 A+B */
- antcomb->main_conf = ATH_ANT_DIV_COMB_LNA1_PLUS_LNA2;
- antcomb->first_quick_scan_conf =
- ATH_ANT_DIV_COMB_LNA1_MINUS_LNA2;
- antcomb->second_quick_scan_conf = ATH_ANT_DIV_COMB_LNA1;
- break;
- case 0x23: /* LNA1 A+B */
- antcomb->main_conf = ATH_ANT_DIV_COMB_LNA1_PLUS_LNA2;
- antcomb->first_quick_scan_conf =
- ATH_ANT_DIV_COMB_LNA1_MINUS_LNA2;
- antcomb->second_quick_scan_conf = ATH_ANT_DIV_COMB_LNA2;
- break;
- default:
- break;
- }
-}
-
-static void ath_select_ant_div_from_quick_scan(struct ath_ant_comb *antcomb,
- struct ath_hw_antcomb_conf *div_ant_conf,
- int main_rssi_avg, int alt_rssi_avg,
- int alt_ratio)
-{
- /* alt_good */
- switch (antcomb->quick_scan_cnt) {
- case 0:
- /* set alt to main, and alt to first conf */
- div_ant_conf->main_lna_conf = antcomb->main_conf;
- div_ant_conf->alt_lna_conf = antcomb->first_quick_scan_conf;
- break;
- case 1:
- /* set alt to main, and alt to first conf */
- div_ant_conf->main_lna_conf = antcomb->main_conf;
- div_ant_conf->alt_lna_conf = antcomb->second_quick_scan_conf;
- antcomb->rssi_first = main_rssi_avg;
- antcomb->rssi_second = alt_rssi_avg;
-
- if (antcomb->main_conf == ATH_ANT_DIV_COMB_LNA1) {
- /* main is LNA1 */
- if (ath_is_alt_ant_ratio_better(alt_ratio,
- ATH_ANT_DIV_COMB_LNA1_DELTA_HI,
- ATH_ANT_DIV_COMB_LNA1_DELTA_LOW,
- main_rssi_avg, alt_rssi_avg,
- antcomb->total_pkt_count))
- antcomb->first_ratio = true;
- else
- antcomb->first_ratio = false;
- } else if (antcomb->main_conf == ATH_ANT_DIV_COMB_LNA2) {
- if (ath_is_alt_ant_ratio_better(alt_ratio,
- ATH_ANT_DIV_COMB_LNA1_DELTA_MID,
- ATH_ANT_DIV_COMB_LNA1_DELTA_LOW,
- main_rssi_avg, alt_rssi_avg,
- antcomb->total_pkt_count))
- antcomb->first_ratio = true;
- else
- antcomb->first_ratio = false;
- } else {
- if ((((alt_ratio >= ATH_ANT_DIV_COMB_ALT_ANT_RATIO2) &&
- (alt_rssi_avg > main_rssi_avg +
- ATH_ANT_DIV_COMB_LNA1_DELTA_HI)) ||
- (alt_rssi_avg > main_rssi_avg)) &&
- (antcomb->total_pkt_count > 50))
- antcomb->first_ratio = true;
- else
- antcomb->first_ratio = false;
- }
- break;
- case 2:
- antcomb->alt_good = false;
- antcomb->scan_not_start = false;
- antcomb->scan = false;
- antcomb->rssi_first = main_rssi_avg;
- antcomb->rssi_third = alt_rssi_avg;
-
- if (antcomb->second_quick_scan_conf == ATH_ANT_DIV_COMB_LNA1)
- antcomb->rssi_lna1 = alt_rssi_avg;
- else if (antcomb->second_quick_scan_conf ==
- ATH_ANT_DIV_COMB_LNA2)
- antcomb->rssi_lna2 = alt_rssi_avg;
- else if (antcomb->second_quick_scan_conf ==
- ATH_ANT_DIV_COMB_LNA1_PLUS_LNA2) {
- if (antcomb->main_conf == ATH_ANT_DIV_COMB_LNA2)
- antcomb->rssi_lna2 = main_rssi_avg;
- else if (antcomb->main_conf == ATH_ANT_DIV_COMB_LNA1)
- antcomb->rssi_lna1 = main_rssi_avg;
- }
-
- if (antcomb->rssi_lna2 > antcomb->rssi_lna1 +
- ATH_ANT_DIV_COMB_LNA1_LNA2_SWITCH_DELTA)
- div_ant_conf->main_lna_conf = ATH_ANT_DIV_COMB_LNA2;
- else
- div_ant_conf->main_lna_conf = ATH_ANT_DIV_COMB_LNA1;
-
- if (antcomb->main_conf == ATH_ANT_DIV_COMB_LNA1) {
- if (ath_is_alt_ant_ratio_better(alt_ratio,
- ATH_ANT_DIV_COMB_LNA1_DELTA_HI,
- ATH_ANT_DIV_COMB_LNA1_DELTA_LOW,
- main_rssi_avg, alt_rssi_avg,
- antcomb->total_pkt_count))
- antcomb->second_ratio = true;
- else
- antcomb->second_ratio = false;
- } else if (antcomb->main_conf == ATH_ANT_DIV_COMB_LNA2) {
- if (ath_is_alt_ant_ratio_better(alt_ratio,
- ATH_ANT_DIV_COMB_LNA1_DELTA_MID,
- ATH_ANT_DIV_COMB_LNA1_DELTA_LOW,
- main_rssi_avg, alt_rssi_avg,
- antcomb->total_pkt_count))
- antcomb->second_ratio = true;
- else
- antcomb->second_ratio = false;
- } else {
- if ((((alt_ratio >= ATH_ANT_DIV_COMB_ALT_ANT_RATIO2) &&
- (alt_rssi_avg > main_rssi_avg +
- ATH_ANT_DIV_COMB_LNA1_DELTA_HI)) ||
- (alt_rssi_avg > main_rssi_avg)) &&
- (antcomb->total_pkt_count > 50))
- antcomb->second_ratio = true;
- else
- antcomb->second_ratio = false;
- }
-
- /* set alt to the conf with maximun ratio */
- if (antcomb->first_ratio && antcomb->second_ratio) {
- if (antcomb->rssi_second > antcomb->rssi_third) {
- /* first alt*/
- if ((antcomb->first_quick_scan_conf ==
- ATH_ANT_DIV_COMB_LNA1) ||
- (antcomb->first_quick_scan_conf ==
- ATH_ANT_DIV_COMB_LNA2))
- /* Set alt LNA1 or LNA2*/
- if (div_ant_conf->main_lna_conf ==
- ATH_ANT_DIV_COMB_LNA2)
- div_ant_conf->alt_lna_conf =
- ATH_ANT_DIV_COMB_LNA1;
- else
- div_ant_conf->alt_lna_conf =
- ATH_ANT_DIV_COMB_LNA2;
- else
- /* Set alt to A+B or A-B */
- div_ant_conf->alt_lna_conf =
- antcomb->first_quick_scan_conf;
- } else if ((antcomb->second_quick_scan_conf ==
- ATH_ANT_DIV_COMB_LNA1) ||
- (antcomb->second_quick_scan_conf ==
- ATH_ANT_DIV_COMB_LNA2)) {
- /* Set alt LNA1 or LNA2 */
- if (div_ant_conf->main_lna_conf ==
- ATH_ANT_DIV_COMB_LNA2)
- div_ant_conf->alt_lna_conf =
- ATH_ANT_DIV_COMB_LNA1;
- else
- div_ant_conf->alt_lna_conf =
- ATH_ANT_DIV_COMB_LNA2;
- } else {
- /* Set alt to A+B or A-B */
- div_ant_conf->alt_lna_conf =
- antcomb->second_quick_scan_conf;
- }
- } else if (antcomb->first_ratio) {
- /* first alt */
- if ((antcomb->first_quick_scan_conf ==
- ATH_ANT_DIV_COMB_LNA1) ||
- (antcomb->first_quick_scan_conf ==
- ATH_ANT_DIV_COMB_LNA2))
- /* Set alt LNA1 or LNA2 */
- if (div_ant_conf->main_lna_conf ==
- ATH_ANT_DIV_COMB_LNA2)
- div_ant_conf->alt_lna_conf =
- ATH_ANT_DIV_COMB_LNA1;
- else
- div_ant_conf->alt_lna_conf =
- ATH_ANT_DIV_COMB_LNA2;
- else
- /* Set alt to A+B or A-B */
- div_ant_conf->alt_lna_conf =
- antcomb->first_quick_scan_conf;
- } else if (antcomb->second_ratio) {
- /* second alt */
- if ((antcomb->second_quick_scan_conf ==
- ATH_ANT_DIV_COMB_LNA1) ||
- (antcomb->second_quick_scan_conf ==
- ATH_ANT_DIV_COMB_LNA2))
- /* Set alt LNA1 or LNA2 */
- if (div_ant_conf->main_lna_conf ==
- ATH_ANT_DIV_COMB_LNA2)
- div_ant_conf->alt_lna_conf =
- ATH_ANT_DIV_COMB_LNA1;
- else
- div_ant_conf->alt_lna_conf =
- ATH_ANT_DIV_COMB_LNA2;
- else
- /* Set alt to A+B or A-B */
- div_ant_conf->alt_lna_conf =
- antcomb->second_quick_scan_conf;
- } else {
- /* main is largest */
- if ((antcomb->main_conf == ATH_ANT_DIV_COMB_LNA1) ||
- (antcomb->main_conf == ATH_ANT_DIV_COMB_LNA2))
- /* Set alt LNA1 or LNA2 */
- if (div_ant_conf->main_lna_conf ==
- ATH_ANT_DIV_COMB_LNA2)
- div_ant_conf->alt_lna_conf =
- ATH_ANT_DIV_COMB_LNA1;
- else
- div_ant_conf->alt_lna_conf =
- ATH_ANT_DIV_COMB_LNA2;
- else
- /* Set alt to A+B or A-B */
- div_ant_conf->alt_lna_conf = antcomb->main_conf;
- }
- break;
- default:
- break;
- }
-}
-
-static void ath_ant_div_conf_fast_divbias(struct ath_hw_antcomb_conf *ant_conf,
- struct ath_ant_comb *antcomb, int alt_ratio)
-{
- if (ant_conf->div_group == 0) {
- /* Adjust the fast_div_bias based on main and alt lna conf */
- switch ((ant_conf->main_lna_conf << 4) |
- ant_conf->alt_lna_conf) {
- case 0x01: /* A-B LNA2 */
- ant_conf->fast_div_bias = 0x3b;
- break;
- case 0x02: /* A-B LNA1 */
- ant_conf->fast_div_bias = 0x3d;
- break;
- case 0x03: /* A-B A+B */
- ant_conf->fast_div_bias = 0x1;
- break;
- case 0x10: /* LNA2 A-B */
- ant_conf->fast_div_bias = 0x7;
- break;
- case 0x12: /* LNA2 LNA1 */
- ant_conf->fast_div_bias = 0x2;
- break;
- case 0x13: /* LNA2 A+B */
- ant_conf->fast_div_bias = 0x7;
- break;
- case 0x20: /* LNA1 A-B */
- ant_conf->fast_div_bias = 0x6;
- break;
- case 0x21: /* LNA1 LNA2 */
- ant_conf->fast_div_bias = 0x0;
- break;
- case 0x23: /* LNA1 A+B */
- ant_conf->fast_div_bias = 0x6;
- break;
- case 0x30: /* A+B A-B */
- ant_conf->fast_div_bias = 0x1;
- break;
- case 0x31: /* A+B LNA2 */
- ant_conf->fast_div_bias = 0x3b;
- break;
- case 0x32: /* A+B LNA1 */
- ant_conf->fast_div_bias = 0x3d;
- break;
- default:
- break;
- }
- } else if (ant_conf->div_group == 1) {
- /* Adjust the fast_div_bias based on main and alt_lna_conf */
- switch ((ant_conf->main_lna_conf << 4) |
- ant_conf->alt_lna_conf) {
- case 0x01: /* A-B LNA2 */
- ant_conf->fast_div_bias = 0x1;
- ant_conf->main_gaintb = 0;
- ant_conf->alt_gaintb = 0;
- break;
- case 0x02: /* A-B LNA1 */
- ant_conf->fast_div_bias = 0x1;
- ant_conf->main_gaintb = 0;
- ant_conf->alt_gaintb = 0;
- break;
- case 0x03: /* A-B A+B */
- ant_conf->fast_div_bias = 0x1;
- ant_conf->main_gaintb = 0;
- ant_conf->alt_gaintb = 0;
- break;
- case 0x10: /* LNA2 A-B */
- if (!(antcomb->scan) &&
- (alt_ratio > ATH_ANT_DIV_COMB_ALT_ANT_RATIO))
- ant_conf->fast_div_bias = 0x3f;
- else
- ant_conf->fast_div_bias = 0x1;
- ant_conf->main_gaintb = 0;
- ant_conf->alt_gaintb = 0;
- break;
- case 0x12: /* LNA2 LNA1 */
- ant_conf->fast_div_bias = 0x1;
- ant_conf->main_gaintb = 0;
- ant_conf->alt_gaintb = 0;
- break;
- case 0x13: /* LNA2 A+B */
- if (!(antcomb->scan) &&
- (alt_ratio > ATH_ANT_DIV_COMB_ALT_ANT_RATIO))
- ant_conf->fast_div_bias = 0x3f;
- else
- ant_conf->fast_div_bias = 0x1;
- ant_conf->main_gaintb = 0;
- ant_conf->alt_gaintb = 0;
- break;
- case 0x20: /* LNA1 A-B */
- if (!(antcomb->scan) &&
- (alt_ratio > ATH_ANT_DIV_COMB_ALT_ANT_RATIO))
- ant_conf->fast_div_bias = 0x3f;
- else
- ant_conf->fast_div_bias = 0x1;
- ant_conf->main_gaintb = 0;
- ant_conf->alt_gaintb = 0;
- break;
- case 0x21: /* LNA1 LNA2 */
- ant_conf->fast_div_bias = 0x1;
- ant_conf->main_gaintb = 0;
- ant_conf->alt_gaintb = 0;
- break;
- case 0x23: /* LNA1 A+B */
- if (!(antcomb->scan) &&
- (alt_ratio > ATH_ANT_DIV_COMB_ALT_ANT_RATIO))
- ant_conf->fast_div_bias = 0x3f;
- else
- ant_conf->fast_div_bias = 0x1;
- ant_conf->main_gaintb = 0;
- ant_conf->alt_gaintb = 0;
- break;
- case 0x30: /* A+B A-B */
- ant_conf->fast_div_bias = 0x1;
- ant_conf->main_gaintb = 0;
- ant_conf->alt_gaintb = 0;
- break;
- case 0x31: /* A+B LNA2 */
- ant_conf->fast_div_bias = 0x1;
- ant_conf->main_gaintb = 0;
- ant_conf->alt_gaintb = 0;
- break;
- case 0x32: /* A+B LNA1 */
- ant_conf->fast_div_bias = 0x1;
- ant_conf->main_gaintb = 0;
- ant_conf->alt_gaintb = 0;
- break;
- default:
- break;
- }
- } else if (ant_conf->div_group == 2) {
- /* Adjust the fast_div_bias based on main and alt_lna_conf */
- switch ((ant_conf->main_lna_conf << 4) |
- ant_conf->alt_lna_conf) {
- case 0x01: /* A-B LNA2 */
- ant_conf->fast_div_bias = 0x1;
- ant_conf->main_gaintb = 0;
- ant_conf->alt_gaintb = 0;
- break;
- case 0x02: /* A-B LNA1 */
- ant_conf->fast_div_bias = 0x1;
- ant_conf->main_gaintb = 0;
- ant_conf->alt_gaintb = 0;
- break;
- case 0x03: /* A-B A+B */
- ant_conf->fast_div_bias = 0x1;
- ant_conf->main_gaintb = 0;
- ant_conf->alt_gaintb = 0;
- break;
- case 0x10: /* LNA2 A-B */
- if (!(antcomb->scan) &&
- (alt_ratio > ATH_ANT_DIV_COMB_ALT_ANT_RATIO))
- ant_conf->fast_div_bias = 0x1;
- else
- ant_conf->fast_div_bias = 0x2;
- ant_conf->main_gaintb = 0;
- ant_conf->alt_gaintb = 0;
- break;
- case 0x12: /* LNA2 LNA1 */
- ant_conf->fast_div_bias = 0x1;
- ant_conf->main_gaintb = 0;
- ant_conf->alt_gaintb = 0;
- break;
- case 0x13: /* LNA2 A+B */
- if (!(antcomb->scan) &&
- (alt_ratio > ATH_ANT_DIV_COMB_ALT_ANT_RATIO))
- ant_conf->fast_div_bias = 0x1;
- else
- ant_conf->fast_div_bias = 0x2;
- ant_conf->main_gaintb = 0;
- ant_conf->alt_gaintb = 0;
- break;
- case 0x20: /* LNA1 A-B */
- if (!(antcomb->scan) &&
- (alt_ratio > ATH_ANT_DIV_COMB_ALT_ANT_RATIO))
- ant_conf->fast_div_bias = 0x1;
- else
- ant_conf->fast_div_bias = 0x2;
- ant_conf->main_gaintb = 0;
- ant_conf->alt_gaintb = 0;
- break;
- case 0x21: /* LNA1 LNA2 */
- ant_conf->fast_div_bias = 0x1;
- ant_conf->main_gaintb = 0;
- ant_conf->alt_gaintb = 0;
- break;
- case 0x23: /* LNA1 A+B */
- if (!(antcomb->scan) &&
- (alt_ratio > ATH_ANT_DIV_COMB_ALT_ANT_RATIO))
- ant_conf->fast_div_bias = 0x1;
- else
- ant_conf->fast_div_bias = 0x2;
- ant_conf->main_gaintb = 0;
- ant_conf->alt_gaintb = 0;
- break;
- case 0x30: /* A+B A-B */
- ant_conf->fast_div_bias = 0x1;
- ant_conf->main_gaintb = 0;
- ant_conf->alt_gaintb = 0;
- break;
- case 0x31: /* A+B LNA2 */
- ant_conf->fast_div_bias = 0x1;
- ant_conf->main_gaintb = 0;
- ant_conf->alt_gaintb = 0;
- break;
- case 0x32: /* A+B LNA1 */
- ant_conf->fast_div_bias = 0x1;
- ant_conf->main_gaintb = 0;
- ant_conf->alt_gaintb = 0;
- break;
- default:
- break;
- }
- }
-}
-
-/* Antenna diversity and combining */
-static void ath_ant_comb_scan(struct ath_softc *sc, struct ath_rx_status *rs)
-{
- struct ath_hw_antcomb_conf div_ant_conf;
- struct ath_ant_comb *antcomb = &sc->ant_comb;
- int alt_ratio = 0, alt_rssi_avg = 0, main_rssi_avg = 0, curr_alt_set;
- int curr_main_set;
- int main_rssi = rs->rs_rssi_ctl0;
- int alt_rssi = rs->rs_rssi_ctl1;
- int rx_ant_conf, main_ant_conf;
- bool short_scan = false;
-
- rx_ant_conf = (rs->rs_rssi_ctl2 >> ATH_ANT_RX_CURRENT_SHIFT) &
- ATH_ANT_RX_MASK;
- main_ant_conf = (rs->rs_rssi_ctl2 >> ATH_ANT_RX_MAIN_SHIFT) &
- ATH_ANT_RX_MASK;
-
- /* Record packet only when both main_rssi and alt_rssi is positive */
- if (main_rssi > 0 && alt_rssi > 0) {
- antcomb->total_pkt_count++;
- antcomb->main_total_rssi += main_rssi;
- antcomb->alt_total_rssi += alt_rssi;
- if (main_ant_conf == rx_ant_conf)
- antcomb->main_recv_cnt++;
- else
- antcomb->alt_recv_cnt++;
- }
-
- /* Short scan check */
- if (antcomb->scan && antcomb->alt_good) {
- if (time_after(jiffies, antcomb->scan_start_time +
- msecs_to_jiffies(ATH_ANT_DIV_COMB_SHORT_SCAN_INTR)))
- short_scan = true;
- else
- if (antcomb->total_pkt_count ==
- ATH_ANT_DIV_COMB_SHORT_SCAN_PKTCOUNT) {
- alt_ratio = ((antcomb->alt_recv_cnt * 100) /
- antcomb->total_pkt_count);
- if (alt_ratio < ATH_ANT_DIV_COMB_ALT_ANT_RATIO)
- short_scan = true;
- }
- }
-
- if (((antcomb->total_pkt_count < ATH_ANT_DIV_COMB_MAX_PKTCOUNT) ||
- rs->rs_moreaggr) && !short_scan)
- return;
-
- if (antcomb->total_pkt_count) {
- alt_ratio = ((antcomb->alt_recv_cnt * 100) /
- antcomb->total_pkt_count);
- main_rssi_avg = (antcomb->main_total_rssi /
- antcomb->total_pkt_count);
- alt_rssi_avg = (antcomb->alt_total_rssi /
- antcomb->total_pkt_count);
- }
-
-
- ath9k_hw_antdiv_comb_conf_get(sc->sc_ah, &div_ant_conf);
- curr_alt_set = div_ant_conf.alt_lna_conf;
- curr_main_set = div_ant_conf.main_lna_conf;
-
- antcomb->count++;
-
- if (antcomb->count == ATH_ANT_DIV_COMB_MAX_COUNT) {
- if (alt_ratio > ATH_ANT_DIV_COMB_ALT_ANT_RATIO) {
- ath_lnaconf_alt_good_scan(antcomb, div_ant_conf,
- main_rssi_avg);
- antcomb->alt_good = true;
- } else {
- antcomb->alt_good = false;
- }
-
- antcomb->count = 0;
- antcomb->scan = true;
- antcomb->scan_not_start = true;
- }
-
- if (!antcomb->scan) {
- if (ath_ant_div_comb_alt_check(div_ant_conf.div_group,
- alt_ratio, curr_main_set, curr_alt_set,
- alt_rssi_avg, main_rssi_avg)) {
- if (curr_alt_set == ATH_ANT_DIV_COMB_LNA2) {
- /* Switch main and alt LNA */
- div_ant_conf.main_lna_conf =
- ATH_ANT_DIV_COMB_LNA2;
- div_ant_conf.alt_lna_conf =
- ATH_ANT_DIV_COMB_LNA1;
- } else if (curr_alt_set == ATH_ANT_DIV_COMB_LNA1) {
- div_ant_conf.main_lna_conf =
- ATH_ANT_DIV_COMB_LNA1;
- div_ant_conf.alt_lna_conf =
- ATH_ANT_DIV_COMB_LNA2;
- }
-
- goto div_comb_done;
- } else if ((curr_alt_set != ATH_ANT_DIV_COMB_LNA1) &&
- (curr_alt_set != ATH_ANT_DIV_COMB_LNA2)) {
- /* Set alt to another LNA */
- if (curr_main_set == ATH_ANT_DIV_COMB_LNA2)
- div_ant_conf.alt_lna_conf =
- ATH_ANT_DIV_COMB_LNA1;
- else if (curr_main_set == ATH_ANT_DIV_COMB_LNA1)
- div_ant_conf.alt_lna_conf =
- ATH_ANT_DIV_COMB_LNA2;
-
- goto div_comb_done;
- }
-
- if ((alt_rssi_avg < (main_rssi_avg +
- div_ant_conf.lna1_lna2_delta)))
- goto div_comb_done;
- }
-
- if (!antcomb->scan_not_start) {
- switch (curr_alt_set) {
- case ATH_ANT_DIV_COMB_LNA2:
- antcomb->rssi_lna2 = alt_rssi_avg;
- antcomb->rssi_lna1 = main_rssi_avg;
- antcomb->scan = true;
- /* set to A+B */
- div_ant_conf.main_lna_conf =
- ATH_ANT_DIV_COMB_LNA1;
- div_ant_conf.alt_lna_conf =
- ATH_ANT_DIV_COMB_LNA1_PLUS_LNA2;
- break;
- case ATH_ANT_DIV_COMB_LNA1:
- antcomb->rssi_lna1 = alt_rssi_avg;
- antcomb->rssi_lna2 = main_rssi_avg;
- antcomb->scan = true;
- /* set to A+B */
- div_ant_conf.main_lna_conf = ATH_ANT_DIV_COMB_LNA2;
- div_ant_conf.alt_lna_conf =
- ATH_ANT_DIV_COMB_LNA1_PLUS_LNA2;
- break;
- case ATH_ANT_DIV_COMB_LNA1_PLUS_LNA2:
- antcomb->rssi_add = alt_rssi_avg;
- antcomb->scan = true;
- /* set to A-B */
- div_ant_conf.alt_lna_conf =
- ATH_ANT_DIV_COMB_LNA1_MINUS_LNA2;
- break;
- case ATH_ANT_DIV_COMB_LNA1_MINUS_LNA2:
- antcomb->rssi_sub = alt_rssi_avg;
- antcomb->scan = false;
- if (antcomb->rssi_lna2 >
- (antcomb->rssi_lna1 +
- ATH_ANT_DIV_COMB_LNA1_LNA2_SWITCH_DELTA)) {
- /* use LNA2 as main LNA */
- if ((antcomb->rssi_add > antcomb->rssi_lna1) &&
- (antcomb->rssi_add > antcomb->rssi_sub)) {
- /* set to A+B */
- div_ant_conf.main_lna_conf =
- ATH_ANT_DIV_COMB_LNA2;
- div_ant_conf.alt_lna_conf =
- ATH_ANT_DIV_COMB_LNA1_PLUS_LNA2;
- } else if (antcomb->rssi_sub >
- antcomb->rssi_lna1) {
- /* set to A-B */
- div_ant_conf.main_lna_conf =
- ATH_ANT_DIV_COMB_LNA2;
- div_ant_conf.alt_lna_conf =
- ATH_ANT_DIV_COMB_LNA1_MINUS_LNA2;
- } else {
- /* set to LNA1 */
- div_ant_conf.main_lna_conf =
- ATH_ANT_DIV_COMB_LNA2;
- div_ant_conf.alt_lna_conf =
- ATH_ANT_DIV_COMB_LNA1;
- }
- } else {
- /* use LNA1 as main LNA */
- if ((antcomb->rssi_add > antcomb->rssi_lna2) &&
- (antcomb->rssi_add > antcomb->rssi_sub)) {
- /* set to A+B */
- div_ant_conf.main_lna_conf =
- ATH_ANT_DIV_COMB_LNA1;
- div_ant_conf.alt_lna_conf =
- ATH_ANT_DIV_COMB_LNA1_PLUS_LNA2;
- } else if (antcomb->rssi_sub >
- antcomb->rssi_lna1) {
- /* set to A-B */
- div_ant_conf.main_lna_conf =
- ATH_ANT_DIV_COMB_LNA1;
- div_ant_conf.alt_lna_conf =
- ATH_ANT_DIV_COMB_LNA1_MINUS_LNA2;
- } else {
- /* set to LNA2 */
- div_ant_conf.main_lna_conf =
- ATH_ANT_DIV_COMB_LNA1;
- div_ant_conf.alt_lna_conf =
- ATH_ANT_DIV_COMB_LNA2;
- }
- }
- break;
- default:
- break;
- }
- } else {
- if (!antcomb->alt_good) {
- antcomb->scan_not_start = false;
- /* Set alt to another LNA */
- if (curr_main_set == ATH_ANT_DIV_COMB_LNA2) {
- div_ant_conf.main_lna_conf =
- ATH_ANT_DIV_COMB_LNA2;
- div_ant_conf.alt_lna_conf =
- ATH_ANT_DIV_COMB_LNA1;
- } else if (curr_main_set == ATH_ANT_DIV_COMB_LNA1) {
- div_ant_conf.main_lna_conf =
- ATH_ANT_DIV_COMB_LNA1;
- div_ant_conf.alt_lna_conf =
- ATH_ANT_DIV_COMB_LNA2;
- }
- goto div_comb_done;
- }
- }
-
- ath_select_ant_div_from_quick_scan(antcomb, &div_ant_conf,
- main_rssi_avg, alt_rssi_avg,
- alt_ratio);
-
- antcomb->quick_scan_cnt++;
-
-div_comb_done:
- ath_ant_div_conf_fast_divbias(&div_ant_conf, antcomb, alt_ratio);
- ath9k_hw_antdiv_comb_conf_set(sc->sc_ah, &div_ant_conf);
-
- antcomb->scan_start_time = jiffies;
- antcomb->total_pkt_count = 0;
- antcomb->main_total_rssi = 0;
- antcomb->alt_total_rssi = 0;
- antcomb->main_recv_cnt = 0;
- antcomb->alt_recv_cnt = 0;
-}
-
int ath_rx_tasklet(struct ath_softc *sc, int flush, bool hp)
{
struct ath_buf *bf;
@@ -1803,7 +1063,7 @@ int ath_rx_tasklet(struct ath_softc *sc, int flush, bool hp)
do {
/* If handling rx interrupt and flush is in progress => exit */
- if ((sc->sc_flags & SC_OP_RXFLUSH) && (flush == 0))
+ if (test_bit(SC_OP_RXFLUSH, &sc->sc_flags) && (flush == 0))
break;
memset(&rs, 0, sizeof(rs));
@@ -1841,13 +1101,14 @@ int ath_rx_tasklet(struct ath_softc *sc, int flush, bool hp)
else
rs.is_mybeacon = false;
+ sc->rx.num_pkts++;
ath_debug_stat_rx(sc, &rs);
/*
* If we're asked to flush receive queue, directly
* chain it back at the queue without processing it.
*/
- if (sc->sc_flags & SC_OP_RXFLUSH) {
+ if (test_bit(SC_OP_RXFLUSH, &sc->sc_flags)) {
RX_STAT_INC(rx_drop_rxflush);
goto requeue_drop_frag;
}
@@ -1968,7 +1229,6 @@ int ath_rx_tasklet(struct ath_softc *sc, int flush, bool hp)
skb_trim(skb, skb->len - 8);
spin_lock_irqsave(&sc->sc_pm_lock, flags);
-
if ((sc->ps_flags & (PS_WAIT_FOR_BEACON |
PS_WAIT_FOR_CAB |
PS_WAIT_FOR_PSPOLL_DATA)) ||
diff --git a/drivers/net/wireless/ath/ath9k/reg.h b/drivers/net/wireless/ath/ath9k/reg.h
index 458f81b4a7c..560d6effac7 100644
--- a/drivers/net/wireless/ath/ath9k/reg.h
+++ b/drivers/net/wireless/ath/ath9k/reg.h
@@ -2211,5 +2211,7 @@ enum {
#define AR_BTCOEX_CTRL3_CONT_INFO_TIMEOUT 0x00000fff
#define AR_BTCOEX_CTRL3_CONT_INFO_TIMEOUT_S 0
+#define AR_GLB_SWREG_DISCONT_MODE 0x2002c
+#define AR_GLB_SWREG_DISCONT_EN_BT_WLAN 0x3
#endif
diff --git a/drivers/net/wireless/ath/ath9k/xmit.c b/drivers/net/wireless/ath/ath9k/xmit.c
index d59dd01d6cd..f777ddcd117 100644
--- a/drivers/net/wireless/ath/ath9k/xmit.c
+++ b/drivers/net/wireless/ath/ath9k/xmit.c
@@ -105,19 +105,19 @@ static int ath_max_4ms_framelen[4][32] = {
/* Aggregation logic */
/*********************/
-static void ath_txq_lock(struct ath_softc *sc, struct ath_txq *txq)
+void ath_txq_lock(struct ath_softc *sc, struct ath_txq *txq)
__acquires(&txq->axq_lock)
{
spin_lock_bh(&txq->axq_lock);
}
-static void ath_txq_unlock(struct ath_softc *sc, struct ath_txq *txq)
+void ath_txq_unlock(struct ath_softc *sc, struct ath_txq *txq)
__releases(&txq->axq_lock)
{
spin_unlock_bh(&txq->axq_lock);
}
-static void ath_txq_unlock_complete(struct ath_softc *sc, struct ath_txq *txq)
+void ath_txq_unlock_complete(struct ath_softc *sc, struct ath_txq *txq)
__releases(&txq->axq_lock)
{
struct sk_buff_head q;
@@ -1536,7 +1536,7 @@ bool ath_drain_all_txq(struct ath_softc *sc, bool retry_tx)
int i;
u32 npend = 0;
- if (sc->sc_flags & SC_OP_INVALID)
+ if (test_bit(SC_OP_INVALID, &sc->sc_flags))
return true;
ath9k_hw_abort_tx_dma(ah);
@@ -1994,6 +1994,7 @@ static void ath_tx_complete(struct ath_softc *sc, struct sk_buff *skb,
struct ath_common *common = ath9k_hw_common(sc->sc_ah);
struct ieee80211_hdr * hdr = (struct ieee80211_hdr *)skb->data;
int q, padpos, padsize;
+ unsigned long flags;
ath_dbg(common, XMIT, "TX complete: skb: %p\n", skb);
@@ -2012,6 +2013,7 @@ static void ath_tx_complete(struct ath_softc *sc, struct sk_buff *skb,
skb_pull(skb, padsize);
}
+ spin_lock_irqsave(&sc->sc_pm_lock, flags);
if ((sc->ps_flags & PS_WAIT_FOR_TX_ACK) && !txq->axq_depth) {
sc->ps_flags &= ~PS_WAIT_FOR_TX_ACK;
ath_dbg(common, PS,
@@ -2021,6 +2023,7 @@ static void ath_tx_complete(struct ath_softc *sc, struct sk_buff *skb,
PS_WAIT_FOR_PSPOLL_DATA |
PS_WAIT_FOR_TX_ACK));
}
+ spin_unlock_irqrestore(&sc->sc_pm_lock, flags);
q = skb_get_queue_mapping(skb);
if (txq == sc->tx.txq_map[q]) {
@@ -2231,46 +2234,6 @@ static void ath_tx_processq(struct ath_softc *sc, struct ath_txq *txq)
ath_txq_unlock_complete(sc, txq);
}
-static void ath_tx_complete_poll_work(struct work_struct *work)
-{
- struct ath_softc *sc = container_of(work, struct ath_softc,
- tx_complete_work.work);
- struct ath_txq *txq;
- int i;
- bool needreset = false;
-#ifdef CONFIG_ATH9K_DEBUGFS
- sc->tx_complete_poll_work_seen++;
-#endif
-
- for (i = 0; i < ATH9K_NUM_TX_QUEUES; i++)
- if (ATH_TXQ_SETUP(sc, i)) {
- txq = &sc->tx.txq[i];
- ath_txq_lock(sc, txq);
- if (txq->axq_depth) {
- if (txq->axq_tx_inprogress) {
- needreset = true;
- ath_txq_unlock(sc, txq);
- break;
- } else {
- txq->axq_tx_inprogress = true;
- }
- }
- ath_txq_unlock_complete(sc, txq);
- }
-
- if (needreset) {
- ath_dbg(ath9k_hw_common(sc->sc_ah), RESET,
- "tx hung, resetting the chip\n");
- RESET_STAT_INC(sc, RESET_TYPE_TX_HANG);
- ieee80211_queue_work(sc->hw, &sc->hw_reset_work);
- }
-
- ieee80211_queue_delayed_work(sc->hw, &sc->tx_complete_work,
- msecs_to_jiffies(ATH_TX_COMPLETE_POLL_INT));
-}
-
-
-
void ath_tx_tasklet(struct ath_softc *sc)
{
struct ath_hw *ah = sc->sc_ah;
diff --git a/drivers/net/wireless/b43legacy/main.c b/drivers/net/wireless/b43legacy/main.c
index cd9c9bc186d..8b06ca56125 100644
--- a/drivers/net/wireless/b43legacy/main.c
+++ b/drivers/net/wireless/b43legacy/main.c
@@ -1508,7 +1508,7 @@ static void b43legacy_release_firmware(struct b43legacy_wldev *dev)
static void b43legacy_print_fw_helptext(struct b43legacy_wl *wl)
{
- b43legacyerr(wl, "You must go to http://linuxwireless.org/en/users/"
+ b43legacyerr(wl, "You must go to http://wireless.kernel.org/en/users/"
"Drivers/b43#devicefirmware "
"and download the correct firmware (version 3).\n");
}
diff --git a/drivers/net/wireless/brcm80211/brcmfmac/bcmsdh.c b/drivers/net/wireless/brcm80211/brcmfmac/bcmsdh.c
index e2480d19627..8e7e6928c93 100644
--- a/drivers/net/wireless/brcm80211/brcmfmac/bcmsdh.c
+++ b/drivers/net/wireless/brcm80211/brcmfmac/bcmsdh.c
@@ -89,9 +89,9 @@ int brcmf_sdio_intr_register(struct brcmf_sdio_dev *sdiodev)
data |= 1 << SDIO_FUNC_1 | 1 << SDIO_FUNC_2 | 1;
brcmf_sdio_regwb(sdiodev, SDIO_CCCR_IENx, data, &ret);
- /* redirect, configure ane enable io for interrupt signal */
+ /* redirect, configure and enable io for interrupt signal */
data = SDIO_SEPINT_MASK | SDIO_SEPINT_OE;
- if (sdiodev->irq_flags | IRQF_TRIGGER_HIGH)
+ if (sdiodev->irq_flags & IRQF_TRIGGER_HIGH)
data |= SDIO_SEPINT_ACT_HI;
brcmf_sdio_regwb(sdiodev, SDIO_CCCR_BRCM_SEPINT, data, &ret);
diff --git a/drivers/net/wireless/brcm80211/brcmsmac/aiutils.c b/drivers/net/wireless/brcm80211/brcmsmac/aiutils.c
index 6d8b7213643..3c6f9b1e8d0 100644
--- a/drivers/net/wireless/brcm80211/brcmsmac/aiutils.c
+++ b/drivers/net/wireless/brcm80211/brcmsmac/aiutils.c
@@ -631,9 +631,8 @@ uint ai_cc_reg(struct si_pub *sih, uint regoff, u32 mask, u32 val)
cc = sii->icbus->drv_cc.core;
/* mask and set */
- if (mask || val) {
+ if (mask || val)
bcma_maskset32(cc, regoff, ~mask, val);
- }
/* readback */
w = bcma_read32(cc, regoff);
diff --git a/drivers/net/wireless/brcm80211/brcmsmac/aiutils.h b/drivers/net/wireless/brcm80211/brcmsmac/aiutils.h
index d9f04a683bd..d6fa9829af9 100644
--- a/drivers/net/wireless/brcm80211/brcmsmac/aiutils.h
+++ b/drivers/net/wireless/brcm80211/brcmsmac/aiutils.h
@@ -193,7 +193,7 @@ extern void ai_detach(struct si_pub *sih);
extern uint ai_cc_reg(struct si_pub *sih, uint regoff, u32 mask, u32 val);
extern void ai_clkctl_init(struct si_pub *sih);
extern u16 ai_clkctl_fast_pwrup_delay(struct si_pub *sih);
-extern bool ai_clkctl_cc(struct si_pub *sih, uint mode);
+extern bool ai_clkctl_cc(struct si_pub *sih, enum bcma_clkmode mode);
extern bool ai_deviceremoved(struct si_pub *sih);
extern void ai_pci_down(struct si_pub *sih);
diff --git a/drivers/net/wireless/brcm80211/brcmsmac/phy/phy_n.c b/drivers/net/wireless/brcm80211/brcmsmac/phy/phy_n.c
index 13b261517cc..36671814641 100644
--- a/drivers/net/wireless/brcm80211/brcmsmac/phy/phy_n.c
+++ b/drivers/net/wireless/brcm80211/brcmsmac/phy/phy_n.c
@@ -14358,7 +14358,7 @@ void wlc_phy_nphy_tkip_rifs_war(struct brcms_phy *pi, u8 rifs)
wlc_phy_write_txmacreg_nphy(pi, holdoff, delay);
- if (pi && pi->sh && (pi->sh->_rifs_phy != rifs))
+ if (pi->sh && (pi->sh->_rifs_phy != rifs))
pi->sh->_rifs_phy = rifs;
}
diff --git a/drivers/net/wireless/brcm80211/brcmutil/utils.c b/drivers/net/wireless/brcm80211/brcmutil/utils.c
index b45ab34cdfd..3e6405e06ac 100644
--- a/drivers/net/wireless/brcm80211/brcmutil/utils.c
+++ b/drivers/net/wireless/brcm80211/brcmutil/utils.c
@@ -43,6 +43,8 @@ EXPORT_SYMBOL(brcmu_pkt_buf_get_skb);
/* Free the driver packet. Free the tag if present */
void brcmu_pkt_buf_free_skb(struct sk_buff *skb)
{
+ if (!skb)
+ return;
WARN_ON(skb->next);
if (skb->destructor)
/* cannot kfree_skb() on hard IRQ (net/core/skbuff.c) if
diff --git a/drivers/net/wireless/ipw2x00/ipw2200.c b/drivers/net/wireless/ipw2x00/ipw2200.c
index 0036737fe8e..254b8922327 100644
--- a/drivers/net/wireless/ipw2x00/ipw2200.c
+++ b/drivers/net/wireless/ipw2x00/ipw2200.c
@@ -2701,6 +2701,20 @@ static void eeprom_parse_mac(struct ipw_priv *priv, u8 * mac)
memcpy(mac, &priv->eeprom[EEPROM_MAC_ADDRESS], 6);
}
+static void ipw_read_eeprom(struct ipw_priv *priv)
+{
+ int i;
+ __le16 *eeprom = (__le16 *) priv->eeprom;
+
+ IPW_DEBUG_TRACE(">>\n");
+
+ /* read entire contents of eeprom into private buffer */
+ for (i = 0; i < 128; i++)
+ eeprom[i] = cpu_to_le16(eeprom_read_u16(priv, (u8) i));
+
+ IPW_DEBUG_TRACE("<<\n");
+}
+
/*
* Either the device driver (i.e. the host) or the firmware can
* load eeprom data into the designated region in SRAM. If neither
@@ -2712,14 +2726,9 @@ static void eeprom_parse_mac(struct ipw_priv *priv, u8 * mac)
static void ipw_eeprom_init_sram(struct ipw_priv *priv)
{
int i;
- __le16 *eeprom = (__le16 *) priv->eeprom;
IPW_DEBUG_TRACE(">>\n");
- /* read entire contents of eeprom into private buffer */
- for (i = 0; i < 128; i++)
- eeprom[i] = cpu_to_le16(eeprom_read_u16(priv, (u8) i));
-
/*
If the data looks correct, then copy it to our private
copy. Otherwise let the firmware know to perform the operation
@@ -3643,8 +3652,10 @@ static int ipw_load(struct ipw_priv *priv)
/* ack fw init done interrupt */
ipw_write32(priv, IPW_INTA_RW, IPW_INTA_BIT_FW_INITIALIZATION_DONE);
- /* read eeprom data and initialize the eeprom region of sram */
+ /* read eeprom data */
priv->eeprom_delay = 1;
+ ipw_read_eeprom(priv);
+ /* initialize the eeprom region of sram */
ipw_eeprom_init_sram(priv);
/* enable interrupts */
diff --git a/drivers/net/wireless/iwlegacy/4965-mac.c b/drivers/net/wireless/iwlegacy/4965-mac.c
index 509301a5e7e..d24eaf89ffb 100644
--- a/drivers/net/wireless/iwlegacy/4965-mac.c
+++ b/drivers/net/wireless/iwlegacy/4965-mac.c
@@ -5724,7 +5724,8 @@ il4965_mac_setup_register(struct il_priv *il, u32 max_probe_length)
BIT(NL80211_IFTYPE_STATION) | BIT(NL80211_IFTYPE_ADHOC);
hw->wiphy->flags |=
- WIPHY_FLAG_CUSTOM_REGULATORY | WIPHY_FLAG_DISABLE_BEACON_HINTS;
+ WIPHY_FLAG_CUSTOM_REGULATORY | WIPHY_FLAG_DISABLE_BEACON_HINTS |
+ WIPHY_FLAG_IBSS_RSN;
/*
* For now, disable PS by default because it affects
@@ -5873,6 +5874,16 @@ il4965_mac_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd,
return -EOPNOTSUPP;
}
+ /*
+ * To support IBSS RSN, don't program group keys in IBSS, the
+ * hardware will then not attempt to decrypt the frames.
+ */
+ if (vif->type == NL80211_IFTYPE_ADHOC &&
+ !(key->flags & IEEE80211_KEY_FLAG_PAIRWISE)) {
+ D_MAC80211("leave - ad-hoc group key\n");
+ return -EOPNOTSUPP;
+ }
+
sta_id = il_sta_id_or_broadcast(il, sta);
if (sta_id == IL_INVALID_STATION)
return -EINVAL;
diff --git a/drivers/net/wireless/iwlwifi/Kconfig b/drivers/net/wireless/iwlwifi/Kconfig
index 2463c062643..727fbb5db9d 100644
--- a/drivers/net/wireless/iwlwifi/Kconfig
+++ b/drivers/net/wireless/iwlwifi/Kconfig
@@ -6,6 +6,7 @@ config IWLWIFI
select LEDS_CLASS
select LEDS_TRIGGERS
select MAC80211_LEDS
+ select IWLDVM
---help---
Select to build the driver supporting the:
@@ -41,6 +42,10 @@ config IWLWIFI
say M here and read <file:Documentation/kbuild/modules.txt>. The
module will be called iwlwifi.
+config IWLDVM
+ tristate "Intel Wireless WiFi"
+ depends on IWLWIFI
+
menu "Debugging Options"
depends on IWLWIFI
diff --git a/drivers/net/wireless/iwlwifi/Makefile b/drivers/net/wireless/iwlwifi/Makefile
index d615eacbf05..931002738c9 100644
--- a/drivers/net/wireless/iwlwifi/Makefile
+++ b/drivers/net/wireless/iwlwifi/Makefile
@@ -1,27 +1,31 @@
+# DVM
+obj-$(CONFIG_IWLDVM) += iwldvm.o
+iwldvm-objs := iwl-agn.o iwl-agn-rs.o iwl-mac80211.o
+iwldvm-objs += iwl-ucode.o iwl-agn-tx.o
+iwldvm-objs += iwl-agn-lib.o iwl-agn-calib.o
+iwldvm-objs += iwl-agn-tt.o iwl-agn-sta.o iwl-agn-rx.o
+iwldvm-objs += iwl-eeprom.o iwl-power.o
+iwldvm-objs += iwl-scan.o iwl-led.o
+iwldvm-objs += iwl-agn-rxon.o iwl-agn-devices.o
+
+iwldvm-$(CONFIG_IWLWIFI_DEBUGFS) += iwl-debugfs.o
+iwldvm-$(CONFIG_IWLWIFI_DEVICE_TESTMODE) += iwl-testmode.o
+
+CFLAGS_iwl-devtrace.o := -I$(src)
+
# WIFI
obj-$(CONFIG_IWLWIFI) += iwlwifi.o
-iwlwifi-objs := iwl-agn.o iwl-agn-rs.o iwl-mac80211.o
-iwlwifi-objs += iwl-ucode.o iwl-agn-tx.o iwl-debug.o
-iwlwifi-objs += iwl-agn-lib.o iwl-agn-calib.o iwl-io.o
-iwlwifi-objs += iwl-agn-tt.o iwl-agn-sta.o iwl-agn-rx.o
-
-iwlwifi-objs += iwl-eeprom.o iwl-power.o
-iwlwifi-objs += iwl-scan.o iwl-led.o
-iwlwifi-objs += iwl-agn-rxon.o iwl-agn-devices.o
iwlwifi-objs += iwl-5000.o
iwlwifi-objs += iwl-6000.o
iwlwifi-objs += iwl-1000.o
iwlwifi-objs += iwl-2000.o
+iwlwifi-objs += iwl-io.o
iwlwifi-objs += iwl-pci.o
iwlwifi-objs += iwl-drv.o
+iwlwifi-objs += iwl-debug.o
iwlwifi-objs += iwl-notif-wait.o
iwlwifi-objs += iwl-trans-pcie.o iwl-trans-pcie-rx.o iwl-trans-pcie-tx.o
-
-iwlwifi-$(CONFIG_IWLWIFI_DEBUGFS) += iwl-debugfs.o
iwlwifi-$(CONFIG_IWLWIFI_DEVICE_TRACING) += iwl-devtrace.o
-iwlwifi-$(CONFIG_IWLWIFI_DEVICE_TESTMODE) += iwl-testmode.o
-
-CFLAGS_iwl-devtrace.o := -I$(src)
ccflags-y += -D__CHECK_ENDIAN__
diff --git a/drivers/net/wireless/iwlwifi/iwl-agn-sta.c b/drivers/net/wireless/iwlwifi/iwl-agn-sta.c
index aea07aab3c9..36055ed1c06 100644
--- a/drivers/net/wireless/iwlwifi/iwl-agn-sta.c
+++ b/drivers/net/wireless/iwlwifi/iwl-agn-sta.c
@@ -236,6 +236,7 @@ static void iwl_sta_calc_ht_flags(struct iwl_priv *priv,
mimo_ps_mode = (sta_ht_inf->cap & IEEE80211_HT_CAP_SM_PS) >> 2;
IWL_DEBUG_INFO(priv, "STA %pM SM PS mode: %s\n",
+ sta->addr,
(mimo_ps_mode == WLAN_HT_CAP_SM_PS_STATIC) ?
"static" :
(mimo_ps_mode == WLAN_HT_CAP_SM_PS_DYNAMIC) ?
diff --git a/drivers/net/wireless/iwlwifi/iwl-agn.c b/drivers/net/wireless/iwlwifi/iwl-agn.c
index ec36e2b020b..5149e6f7294 100644
--- a/drivers/net/wireless/iwlwifi/iwl-agn.c
+++ b/drivers/net/wireless/iwlwifi/iwl-agn.c
@@ -78,7 +78,6 @@ MODULE_DESCRIPTION(DRV_DESCRIPTION);
MODULE_VERSION(DRV_VERSION);
MODULE_AUTHOR(DRV_COPYRIGHT " " DRV_AUTHOR);
MODULE_LICENSE("GPL");
-MODULE_ALIAS("iwlagn");
void iwl_update_chain_flags(struct iwl_priv *priv)
{
@@ -2344,24 +2343,25 @@ static int __init iwl_init(void)
goto error_rc_register;
}
- ret = iwl_pci_register_driver();
- if (ret)
- goto error_pci_register;
+ ret = iwl_opmode_register("iwldvm", &iwl_dvm_ops);
+ if (ret) {
+ pr_err("Unable to register op_mode: %d\n", ret);
+ goto error_opmode_register;
+ }
return ret;
-error_pci_register:
+error_opmode_register:
iwlagn_rate_control_unregister();
error_rc_register:
kmem_cache_destroy(iwl_tx_cmd_pool);
return ret;
}
+module_init(iwl_init);
static void __exit iwl_exit(void)
{
- iwl_pci_unregister_driver();
+ iwl_opmode_deregister("iwldvm");
iwlagn_rate_control_unregister();
kmem_cache_destroy(iwl_tx_cmd_pool);
}
-
module_exit(iwl_exit);
-module_init(iwl_init);
diff --git a/drivers/net/wireless/iwlwifi/iwl-commands.h b/drivers/net/wireless/iwlwifi/iwl-commands.h
index 9af6a239b38..b9f7361d242 100644
--- a/drivers/net/wireless/iwlwifi/iwl-commands.h
+++ b/drivers/net/wireless/iwlwifi/iwl-commands.h
@@ -197,9 +197,6 @@ enum {
*
*****************************************************************************/
-/* iwl_cmd_header flags value */
-#define IWL_CMD_FAILED_MSK 0x40
-
/**
* iwlagn rate_n_flags bit fields
*
diff --git a/drivers/net/wireless/iwlwifi/iwl-config.h b/drivers/net/wireless/iwlwifi/iwl-config.h
index 67b28aa7f9b..a52818bbfe9 100644
--- a/drivers/net/wireless/iwlwifi/iwl-config.h
+++ b/drivers/net/wireless/iwlwifi/iwl-config.h
@@ -143,7 +143,7 @@ enum iwl_led_mode {
* @chain_noise_scale: default chain noise scale used for gain computation
* @wd_timeout: TX queues watchdog timeout
* @max_event_log_size: size of event log buffer size for ucode event logging
- * @shadow_reg_enable: HW shadhow register bit
+ * @shadow_reg_enable: HW shadow register support
* @hd_v2: v2 of enhanced sensitivity value, used for 2000 series and up
* @no_idle_support: do not support idle mode
*/
diff --git a/drivers/net/wireless/iwlwifi/iwl-debug.c b/drivers/net/wireless/iwlwifi/iwl-debug.c
index 2d1b42847b9..0f8fcd1d4fe 100644
--- a/drivers/net/wireless/iwlwifi/iwl-debug.c
+++ b/drivers/net/wireless/iwlwifi/iwl-debug.c
@@ -62,6 +62,7 @@
*****************************************************************************/
#include <linux/interrupt.h>
+#include <linux/export.h>
#include "iwl-debug.h"
#include "iwl-devtrace.h"
@@ -81,8 +82,11 @@ void __iwl_ ##fn(struct device *dev, const char *fmt, ...) \
}
__iwl_fn(warn)
+EXPORT_SYMBOL_GPL(__iwl_warn);
__iwl_fn(info)
+EXPORT_SYMBOL_GPL(__iwl_info);
__iwl_fn(crit)
+EXPORT_SYMBOL_GPL(__iwl_crit);
void __iwl_err(struct device *dev, bool rfkill_prefix, bool trace_only,
const char *fmt, ...)
@@ -103,6 +107,7 @@ void __iwl_err(struct device *dev, bool rfkill_prefix, bool trace_only,
trace_iwlwifi_err(&vaf);
va_end(args);
}
+EXPORT_SYMBOL_GPL(__iwl_err);
#if defined(CONFIG_IWLWIFI_DEBUG) || defined(CONFIG_IWLWIFI_DEVICE_TRACING)
void __iwl_dbg(struct device *dev,
@@ -125,4 +130,5 @@ void __iwl_dbg(struct device *dev,
trace_iwlwifi_dbg(level, in_interrupt(), function, &vaf);
va_end(args);
}
+EXPORT_SYMBOL_GPL(__iwl_dbg);
#endif
diff --git a/drivers/net/wireless/iwlwifi/iwl-debug.h b/drivers/net/wireless/iwlwifi/iwl-debug.h
index 8376b842bdb..f6bf91c8f77 100644
--- a/drivers/net/wireless/iwlwifi/iwl-debug.h
+++ b/drivers/net/wireless/iwlwifi/iwl-debug.h
@@ -38,10 +38,10 @@ static inline bool iwl_have_debug_level(u32 level)
}
void __iwl_err(struct device *dev, bool rfkill_prefix, bool only_trace,
- const char *fmt, ...);
-void __iwl_warn(struct device *dev, const char *fmt, ...);
-void __iwl_info(struct device *dev, const char *fmt, ...);
-void __iwl_crit(struct device *dev, const char *fmt, ...);
+ const char *fmt, ...) __printf(4, 5);
+void __iwl_warn(struct device *dev, const char *fmt, ...) __printf(2, 3);
+void __iwl_info(struct device *dev, const char *fmt, ...) __printf(2, 3);
+void __iwl_crit(struct device *dev, const char *fmt, ...) __printf(2, 3);
/* No matter what is m (priv, bus, trans), this will work */
#define IWL_ERR(m, f, a...) __iwl_err((m)->dev, false, false, f, ## a)
@@ -52,9 +52,9 @@ void __iwl_crit(struct device *dev, const char *fmt, ...);
#if defined(CONFIG_IWLWIFI_DEBUG) || defined(CONFIG_IWLWIFI_DEVICE_TRACING)
void __iwl_dbg(struct device *dev,
u32 level, bool limit, const char *function,
- const char *fmt, ...);
+ const char *fmt, ...) __printf(5, 6);
#else
-static inline void
+__printf(5, 6) static inline void
__iwl_dbg(struct device *dev,
u32 level, bool limit, const char *function,
const char *fmt, ...)
diff --git a/drivers/net/wireless/iwlwifi/iwl-devtrace.c b/drivers/net/wireless/iwlwifi/iwl-devtrace.c
index 91f45e71e0a..70191ddbd8f 100644
--- a/drivers/net/wireless/iwlwifi/iwl-devtrace.c
+++ b/drivers/net/wireless/iwlwifi/iwl-devtrace.c
@@ -42,4 +42,9 @@ EXPORT_TRACEPOINT_SYMBOL(iwlwifi_dev_ucode_event);
EXPORT_TRACEPOINT_SYMBOL(iwlwifi_dev_ucode_error);
EXPORT_TRACEPOINT_SYMBOL(iwlwifi_dev_ucode_cont_event);
EXPORT_TRACEPOINT_SYMBOL(iwlwifi_dev_ucode_wrap_event);
+EXPORT_TRACEPOINT_SYMBOL(iwlwifi_info);
+EXPORT_TRACEPOINT_SYMBOL(iwlwifi_warn);
+EXPORT_TRACEPOINT_SYMBOL(iwlwifi_crit);
+EXPORT_TRACEPOINT_SYMBOL(iwlwifi_err);
+EXPORT_TRACEPOINT_SYMBOL(iwlwifi_dbg);
#endif
diff --git a/drivers/net/wireless/iwlwifi/iwl-drv.c b/drivers/net/wireless/iwlwifi/iwl-drv.c
index d742900969e..49df0e9d5c5 100644
--- a/drivers/net/wireless/iwlwifi/iwl-drv.c
+++ b/drivers/net/wireless/iwlwifi/iwl-drv.c
@@ -77,8 +77,33 @@
/* private includes */
#include "iwl-fw-file.h"
+/******************************************************************************
+ *
+ * module boiler plate
+ *
+ ******************************************************************************/
+
+/*
+ * module name, copyright, version, etc.
+ */
+#define DRV_DESCRIPTION "Intel(R) Wireless WiFi driver for Linux"
+
+#ifdef CONFIG_IWLWIFI_DEBUG
+#define VD "d"
+#else
+#define VD
+#endif
+
+#define DRV_VERSION IWLWIFI_VERSION VD
+
+MODULE_DESCRIPTION(DRV_DESCRIPTION);
+MODULE_VERSION(DRV_VERSION);
+MODULE_AUTHOR(DRV_COPYRIGHT " " DRV_AUTHOR);
+MODULE_LICENSE("GPL");
+
/**
* struct iwl_drv - drv common data
+ * @list: list of drv structures using this opmode
* @fw: the iwl_fw structure
* @op_mode: the running op_mode
* @trans: transport layer
@@ -89,6 +114,7 @@
* @request_firmware_complete: the firmware has been obtained from user space
*/
struct iwl_drv {
+ struct list_head list;
struct iwl_fw fw;
struct iwl_op_mode *op_mode;
@@ -102,7 +128,17 @@ struct iwl_drv {
struct completion request_firmware_complete;
};
+#define DVM_OP_MODE 0
+#define MVM_OP_MODE 1
+static struct iwlwifi_opmode_table {
+ const char *name; /* name: iwldvm, iwlmvm, etc */
+ const struct iwl_op_mode_ops *ops; /* pointer to op_mode ops */
+ struct list_head drv; /* list of devices using this op_mode */
+} iwlwifi_opmode_table[] = { /* ops set when driver is initialized */
+ { .name = "iwldvm", .ops = NULL },
+ { .name = "iwlmvm", .ops = NULL },
+};
/*
* struct fw_sec: Just for the image parsing proccess.
@@ -721,7 +757,6 @@ static int validate_sec_sizes(struct iwl_drv *drv,
return 0;
}
-
/**
* iwl_ucode_callback - callback when firmware was loaded
*
@@ -733,6 +768,7 @@ static void iwl_ucode_callback(const struct firmware *ucode_raw, void *context)
struct iwl_drv *drv = context;
struct iwl_fw *fw = &drv->fw;
struct iwl_ucode_header *ucode;
+ struct iwlwifi_opmode_table *op;
int err;
struct iwl_firmware_pieces pieces;
const unsigned int api_max = drv->cfg->ucode_api_max;
@@ -861,13 +897,28 @@ static void iwl_ucode_callback(const struct firmware *ucode_raw, void *context)
/* We have our copies now, allow OS release its copies */
release_firmware(ucode_raw);
- complete(&drv->request_firmware_complete);
- drv->op_mode = iwl_dvm_ops.start(drv->trans, drv->cfg, &drv->fw);
+ op = &iwlwifi_opmode_table[DVM_OP_MODE];
- if (!drv->op_mode)
- goto out_free_fw;
+ /* add this device to the list of devices using this op_mode */
+ list_add_tail(&drv->list, &op->drv);
+
+ if (op->ops) {
+ const struct iwl_op_mode_ops *ops = op->ops;
+ drv->op_mode = ops->start(drv->trans, drv->cfg, &drv->fw);
+
+ if (!drv->op_mode)
+ goto out_unbind;
+ } else {
+ request_module_nowait("%s", op->name);
+ }
+ /*
+ * Complete the firmware request last so that
+ * a driver unbind (stop) doesn't run while we
+ * are doing the start() above.
+ */
+ complete(&drv->request_firmware_complete);
return;
try_again:
@@ -938,6 +989,67 @@ struct iwl_mod_params iwlwifi_mod_params = {
.auto_agg = true,
/* the rest are 0 by default */
};
+EXPORT_SYMBOL_GPL(iwlwifi_mod_params);
+
+int iwl_opmode_register(const char *name, const struct iwl_op_mode_ops *ops)
+{
+ int i;
+ struct iwl_drv *drv;
+
+ for (i = 0; i < ARRAY_SIZE(iwlwifi_opmode_table); i++) {
+ if (strcmp(iwlwifi_opmode_table[i].name, name))
+ continue;
+ iwlwifi_opmode_table[i].ops = ops;
+ list_for_each_entry(drv, &iwlwifi_opmode_table[i].drv, list)
+ drv->op_mode = ops->start(drv->trans, drv->cfg,
+ &drv->fw);
+ return 0;
+ }
+ return -EIO;
+}
+EXPORT_SYMBOL_GPL(iwl_opmode_register);
+
+void iwl_opmode_deregister(const char *name)
+{
+ int i;
+ struct iwl_drv *drv;
+
+ for (i = 0; i < ARRAY_SIZE(iwlwifi_opmode_table); i++) {
+ if (strcmp(iwlwifi_opmode_table[i].name, name))
+ continue;
+ iwlwifi_opmode_table[i].ops = NULL;
+
+ /* call the stop routine for all devices */
+ list_for_each_entry(drv, &iwlwifi_opmode_table[i].drv, list) {
+ if (drv->op_mode) {
+ iwl_op_mode_stop(drv->op_mode);
+ drv->op_mode = NULL;
+ }
+ }
+ return;
+ }
+}
+EXPORT_SYMBOL_GPL(iwl_opmode_deregister);
+
+static int __init iwl_drv_init(void)
+{
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(iwlwifi_opmode_table); i++)
+ INIT_LIST_HEAD(&iwlwifi_opmode_table[i].drv);
+
+ pr_info(DRV_DESCRIPTION ", " DRV_VERSION "\n");
+ pr_info(DRV_COPYRIGHT "\n");
+
+ return iwl_pci_register_driver();
+}
+module_init(iwl_drv_init);
+
+static void __exit iwl_drv_exit(void)
+{
+ iwl_pci_unregister_driver();
+}
+module_exit(iwl_drv_exit);
#ifdef CONFIG_IWLWIFI_DEBUG
module_param_named(debug, iwlwifi_mod_params.debug_level, uint,
diff --git a/drivers/net/wireless/iwlwifi/iwl-eeprom.c b/drivers/net/wireless/iwlwifi/iwl-eeprom.c
index 50c58911e71..b8e2b223ac3 100644
--- a/drivers/net/wireless/iwlwifi/iwl-eeprom.c
+++ b/drivers/net/wireless/iwlwifi/iwl-eeprom.c
@@ -568,28 +568,28 @@ static int iwl_find_otp_image(struct iwl_trans *trans,
* iwl_get_max_txpower_avg - get the highest tx power from all chains.
* find the highest tx power from all chains for the channel
*/
-static s8 iwl_get_max_txpower_avg(const struct iwl_cfg *cfg,
+static s8 iwl_get_max_txpower_avg(struct iwl_priv *priv,
struct iwl_eeprom_enhanced_txpwr *enhanced_txpower,
int element, s8 *max_txpower_in_half_dbm)
{
s8 max_txpower_avg = 0; /* (dBm) */
/* Take the highest tx power from any valid chains */
- if ((cfg->valid_tx_ant & ANT_A) &&
+ if ((priv->hw_params.valid_tx_ant & ANT_A) &&
(enhanced_txpower[element].chain_a_max > max_txpower_avg))
max_txpower_avg = enhanced_txpower[element].chain_a_max;
- if ((cfg->valid_tx_ant & ANT_B) &&
+ if ((priv->hw_params.valid_tx_ant & ANT_B) &&
(enhanced_txpower[element].chain_b_max > max_txpower_avg))
max_txpower_avg = enhanced_txpower[element].chain_b_max;
- if ((cfg->valid_tx_ant & ANT_C) &&
+ if ((priv->hw_params.valid_tx_ant & ANT_C) &&
(enhanced_txpower[element].chain_c_max > max_txpower_avg))
max_txpower_avg = enhanced_txpower[element].chain_c_max;
- if (((cfg->valid_tx_ant == ANT_AB) |
- (cfg->valid_tx_ant == ANT_BC) |
- (cfg->valid_tx_ant == ANT_AC)) &&
+ if (((priv->hw_params.valid_tx_ant == ANT_AB) |
+ (priv->hw_params.valid_tx_ant == ANT_BC) |
+ (priv->hw_params.valid_tx_ant == ANT_AC)) &&
(enhanced_txpower[element].mimo2_max > max_txpower_avg))
max_txpower_avg = enhanced_txpower[element].mimo2_max;
- if ((cfg->valid_tx_ant == ANT_ABC) &&
+ if ((priv->hw_params.valid_tx_ant == ANT_ABC) &&
(enhanced_txpower[element].mimo3_max > max_txpower_avg))
max_txpower_avg = enhanced_txpower[element].mimo3_max;
@@ -691,7 +691,7 @@ static void iwl_eeprom_enhanced_txpower(struct iwl_priv *priv)
((txp->delta_20_in_40 & 0xf0) >> 4),
(txp->delta_20_in_40 & 0x0f));
- max_txp_avg = iwl_get_max_txpower_avg(priv->cfg, txp_array, idx,
+ max_txp_avg = iwl_get_max_txpower_avg(priv, txp_array, idx,
&max_txp_avg_halfdbm);
/*
diff --git a/drivers/net/wireless/iwlwifi/iwl-io.c b/drivers/net/wireless/iwlwifi/iwl-io.c
index 081dd34d238..ee93274214d 100644
--- a/drivers/net/wireless/iwlwifi/iwl-io.c
+++ b/drivers/net/wireless/iwlwifi/iwl-io.c
@@ -27,6 +27,7 @@
*****************************************************************************/
#include <linux/delay.h>
#include <linux/device.h>
+#include <linux/export.h>
#include "iwl-io.h"
#include"iwl-csr.h"
@@ -52,6 +53,7 @@ void iwl_set_bit(struct iwl_trans *trans, u32 reg, u32 mask)
__iwl_set_bit(trans, reg, mask);
spin_unlock_irqrestore(&trans->reg_lock, flags);
}
+EXPORT_SYMBOL_GPL(iwl_set_bit);
void iwl_clear_bit(struct iwl_trans *trans, u32 reg, u32 mask)
{
@@ -61,6 +63,7 @@ void iwl_clear_bit(struct iwl_trans *trans, u32 reg, u32 mask)
__iwl_clear_bit(trans, reg, mask);
spin_unlock_irqrestore(&trans->reg_lock, flags);
}
+EXPORT_SYMBOL_GPL(iwl_clear_bit);
int iwl_poll_bit(struct iwl_trans *trans, u32 addr,
u32 bits, u32 mask, int timeout)
@@ -76,6 +79,7 @@ int iwl_poll_bit(struct iwl_trans *trans, u32 addr,
return -ETIMEDOUT;
}
+EXPORT_SYMBOL_GPL(iwl_poll_bit);
int iwl_grab_nic_access_silent(struct iwl_trans *trans)
{
@@ -117,6 +121,7 @@ int iwl_grab_nic_access_silent(struct iwl_trans *trans)
return 0;
}
+EXPORT_SYMBOL_GPL(iwl_grab_nic_access_silent);
bool iwl_grab_nic_access(struct iwl_trans *trans)
{
@@ -130,6 +135,7 @@ bool iwl_grab_nic_access(struct iwl_trans *trans)
return true;
}
+EXPORT_SYMBOL_GPL(iwl_grab_nic_access);
void iwl_release_nic_access(struct iwl_trans *trans)
{
@@ -144,6 +150,7 @@ void iwl_release_nic_access(struct iwl_trans *trans)
*/
mmiowb();
}
+EXPORT_SYMBOL_GPL(iwl_release_nic_access);
u32 iwl_read_direct32(struct iwl_trans *trans, u32 reg)
{
@@ -158,6 +165,7 @@ u32 iwl_read_direct32(struct iwl_trans *trans, u32 reg)
return value;
}
+EXPORT_SYMBOL_GPL(iwl_read_direct32);
void iwl_write_direct32(struct iwl_trans *trans, u32 reg, u32 value)
{
@@ -170,6 +178,7 @@ void iwl_write_direct32(struct iwl_trans *trans, u32 reg, u32 value)
}
spin_unlock_irqrestore(&trans->reg_lock, flags);
}
+EXPORT_SYMBOL_GPL(iwl_write_direct32);
int iwl_poll_direct_bit(struct iwl_trans *trans, u32 addr, u32 mask,
int timeout)
@@ -185,6 +194,7 @@ int iwl_poll_direct_bit(struct iwl_trans *trans, u32 addr, u32 mask,
return -ETIMEDOUT;
}
+EXPORT_SYMBOL_GPL(iwl_poll_direct_bit);
static inline u32 __iwl_read_prph(struct iwl_trans *trans, u32 reg)
{
@@ -211,6 +221,7 @@ u32 iwl_read_prph(struct iwl_trans *trans, u32 reg)
spin_unlock_irqrestore(&trans->reg_lock, flags);
return val;
}
+EXPORT_SYMBOL_GPL(iwl_read_prph);
void iwl_write_prph(struct iwl_trans *trans, u32 addr, u32 val)
{
@@ -223,6 +234,7 @@ void iwl_write_prph(struct iwl_trans *trans, u32 addr, u32 val)
}
spin_unlock_irqrestore(&trans->reg_lock, flags);
}
+EXPORT_SYMBOL_GPL(iwl_write_prph);
void iwl_set_bits_prph(struct iwl_trans *trans, u32 reg, u32 mask)
{
@@ -236,6 +248,7 @@ void iwl_set_bits_prph(struct iwl_trans *trans, u32 reg, u32 mask)
}
spin_unlock_irqrestore(&trans->reg_lock, flags);
}
+EXPORT_SYMBOL_GPL(iwl_set_bits_prph);
void iwl_set_bits_mask_prph(struct iwl_trans *trans, u32 reg,
u32 bits, u32 mask)
@@ -250,6 +263,7 @@ void iwl_set_bits_mask_prph(struct iwl_trans *trans, u32 reg,
}
spin_unlock_irqrestore(&trans->reg_lock, flags);
}
+EXPORT_SYMBOL_GPL(iwl_set_bits_mask_prph);
void iwl_clear_bits_prph(struct iwl_trans *trans, u32 reg, u32 mask)
{
@@ -264,6 +278,7 @@ void iwl_clear_bits_prph(struct iwl_trans *trans, u32 reg, u32 mask)
}
spin_unlock_irqrestore(&trans->reg_lock, flags);
}
+EXPORT_SYMBOL_GPL(iwl_clear_bits_prph);
void _iwl_read_targ_mem_words(struct iwl_trans *trans, u32 addr,
void *buf, int words)
@@ -281,6 +296,7 @@ void _iwl_read_targ_mem_words(struct iwl_trans *trans, u32 addr,
}
spin_unlock_irqrestore(&trans->reg_lock, flags);
}
+EXPORT_SYMBOL_GPL(_iwl_read_targ_mem_words);
u32 iwl_read_targ_mem(struct iwl_trans *trans, u32 addr)
{
@@ -290,6 +306,7 @@ u32 iwl_read_targ_mem(struct iwl_trans *trans, u32 addr)
return value;
}
+EXPORT_SYMBOL_GPL(iwl_read_targ_mem);
int _iwl_write_targ_mem_words(struct iwl_trans *trans, u32 addr,
void *buf, int words)
@@ -310,8 +327,10 @@ int _iwl_write_targ_mem_words(struct iwl_trans *trans, u32 addr,
return result;
}
+EXPORT_SYMBOL_GPL(_iwl_write_targ_mem_words);
int iwl_write_targ_mem(struct iwl_trans *trans, u32 addr, u32 val)
{
return _iwl_write_targ_mem_words(trans, addr, &val, 1);
}
+EXPORT_SYMBOL_GPL(iwl_write_targ_mem);
diff --git a/drivers/net/wireless/iwlwifi/iwl-mac80211.c b/drivers/net/wireless/iwlwifi/iwl-mac80211.c
index ab2f4d7500a..a55012609ca 100644
--- a/drivers/net/wireless/iwlwifi/iwl-mac80211.c
+++ b/drivers/net/wireless/iwlwifi/iwl-mac80211.c
@@ -199,6 +199,7 @@ int iwlagn_mac_setup_register(struct iwl_priv *priv,
WIPHY_FLAG_DISABLE_BEACON_HINTS |
WIPHY_FLAG_IBSS_RSN;
+#ifdef CONFIG_PM_SLEEP
if (priv->fw->img[IWL_UCODE_WOWLAN].sec[0].len &&
priv->trans->ops->wowlan_suspend &&
device_can_wakeup(priv->trans->dev)) {
@@ -217,6 +218,7 @@ int iwlagn_mac_setup_register(struct iwl_priv *priv,
hw->wiphy->wowlan.pattern_max_len =
IWLAGN_WOWLAN_MAX_PATTERN_LEN;
}
+#endif
if (iwlwifi_mod_params.power_save)
hw->wiphy->flags |= WIPHY_FLAG_PS_ON_BY_DEFAULT;
@@ -249,6 +251,7 @@ int iwlagn_mac_setup_register(struct iwl_priv *priv,
ret = ieee80211_register_hw(priv->hw);
if (ret) {
IWL_ERR(priv, "Failed to register hw (error %d)\n", ret);
+ iwl_leds_exit(priv);
return ret;
}
priv->mac80211_registered = 1;
@@ -417,8 +420,6 @@ int iwlagn_mac_suspend(struct ieee80211_hw *hw, struct cfg80211_wowlan *wowlan)
if (ret)
goto error;
- device_set_wakeup_enable(priv->trans->dev, true);
-
iwl_trans_wowlan_suspend(priv->trans);
goto out;
@@ -485,8 +486,6 @@ static int iwlagn_mac_resume(struct ieee80211_hw *hw)
priv->wowlan = false;
- device_set_wakeup_enable(priv->trans->dev, false);
-
iwlagn_prepare_restart(priv);
memset((void *)&ctx->active, 0, sizeof(ctx->active));
@@ -501,6 +500,12 @@ static int iwlagn_mac_resume(struct ieee80211_hw *hw)
return 1;
}
+static void iwlagn_mac_set_wakeup(struct ieee80211_hw *hw, bool enabled)
+{
+ struct iwl_priv *priv = IWL_MAC80211_GET_DVM(hw);
+
+ device_set_wakeup_enable(priv->trans->dev, enabled);
+}
#endif
void iwlagn_mac_tx(struct ieee80211_hw *hw, struct sk_buff *skb)
@@ -1581,6 +1586,7 @@ struct ieee80211_ops iwlagn_hw_ops = {
#ifdef CONFIG_PM_SLEEP
.suspend = iwlagn_mac_suspend,
.resume = iwlagn_mac_resume,
+ .set_wakeup = iwlagn_mac_set_wakeup,
#endif
.add_interface = iwlagn_mac_add_interface,
.remove_interface = iwlagn_mac_remove_interface,
diff --git a/drivers/net/wireless/iwlwifi/iwl-notif-wait.c b/drivers/net/wireless/iwlwifi/iwl-notif-wait.c
index 0066b899fe5..5cfed29b1b1 100644
--- a/drivers/net/wireless/iwlwifi/iwl-notif-wait.c
+++ b/drivers/net/wireless/iwlwifi/iwl-notif-wait.c
@@ -61,6 +61,7 @@
*
*****************************************************************************/
#include <linux/sched.h>
+#include <linux/export.h>
#include "iwl-notif-wait.h"
@@ -71,6 +72,7 @@ void iwl_notification_wait_init(struct iwl_notif_wait_data *notif_wait)
INIT_LIST_HEAD(&notif_wait->notif_waits);
init_waitqueue_head(&notif_wait->notif_waitq);
}
+EXPORT_SYMBOL_GPL(iwl_notification_wait_init);
void iwl_notification_wait_notify(struct iwl_notif_wait_data *notif_wait,
struct iwl_rx_packet *pkt)
@@ -115,6 +117,7 @@ void iwl_notification_wait_notify(struct iwl_notif_wait_data *notif_wait,
if (triggered)
wake_up_all(&notif_wait->notif_waitq);
}
+EXPORT_SYMBOL_GPL(iwl_notification_wait_notify);
void iwl_abort_notification_waits(struct iwl_notif_wait_data *notif_wait)
{
@@ -128,7 +131,7 @@ void iwl_abort_notification_waits(struct iwl_notif_wait_data *notif_wait)
wake_up_all(&notif_wait->notif_waitq);
}
-
+EXPORT_SYMBOL_GPL(iwl_abort_notification_waits);
void
iwl_init_notification_wait(struct iwl_notif_wait_data *notif_wait,
@@ -152,6 +155,7 @@ iwl_init_notification_wait(struct iwl_notif_wait_data *notif_wait,
list_add(&wait_entry->list, &notif_wait->notif_waits);
spin_unlock_bh(&notif_wait->notif_wait_lock);
}
+EXPORT_SYMBOL_GPL(iwl_init_notification_wait);
int iwl_wait_notification(struct iwl_notif_wait_data *notif_wait,
struct iwl_notification_wait *wait_entry,
@@ -175,6 +179,7 @@ int iwl_wait_notification(struct iwl_notif_wait_data *notif_wait,
return -ETIMEDOUT;
return 0;
}
+EXPORT_SYMBOL_GPL(iwl_wait_notification);
void iwl_remove_notification(struct iwl_notif_wait_data *notif_wait,
struct iwl_notification_wait *wait_entry)
@@ -183,3 +188,4 @@ void iwl_remove_notification(struct iwl_notif_wait_data *notif_wait,
list_del(&wait_entry->list);
spin_unlock_bh(&notif_wait->notif_wait_lock);
}
+EXPORT_SYMBOL_GPL(iwl_remove_notification);
diff --git a/drivers/net/wireless/iwlwifi/iwl-op-mode.h b/drivers/net/wireless/iwlwifi/iwl-op-mode.h
index 4ef742b28e0..cec133c87ad 100644
--- a/drivers/net/wireless/iwlwifi/iwl-op-mode.h
+++ b/drivers/net/wireless/iwlwifi/iwl-op-mode.h
@@ -145,6 +145,9 @@ struct iwl_op_mode_ops {
void (*wimax_active)(struct iwl_op_mode *op_mode);
};
+int iwl_opmode_register(const char *name, const struct iwl_op_mode_ops *ops);
+void iwl_opmode_deregister(const char *name);
+
/**
* struct iwl_op_mode - operational mode
*
diff --git a/drivers/net/wireless/iwlwifi/iwl-trans-pcie-int.h b/drivers/net/wireless/iwlwifi/iwl-trans-pcie-int.h
index e959207c630..f027769933d 100644
--- a/drivers/net/wireless/iwlwifi/iwl-trans-pcie-int.h
+++ b/drivers/net/wireless/iwlwifi/iwl-trans-pcie-int.h
@@ -313,7 +313,7 @@ void iwl_bg_rx_replenish(struct work_struct *data);
void iwl_irq_tasklet(struct iwl_trans *trans);
void iwlagn_rx_replenish(struct iwl_trans *trans);
void iwl_rx_queue_update_write_ptr(struct iwl_trans *trans,
- struct iwl_rx_queue *q);
+ struct iwl_rx_queue *q);
/*****************************************************
* ICT
@@ -328,7 +328,7 @@ irqreturn_t iwl_isr_ict(int irq, void *data);
* TX / HCMD
******************************************************/
void iwl_txq_update_write_ptr(struct iwl_trans *trans,
- struct iwl_tx_queue *txq);
+ struct iwl_tx_queue *txq);
int iwlagn_txq_attach_buf_to_tfd(struct iwl_trans *trans,
struct iwl_tx_queue *txq,
dma_addr_t addr, u16 len, u8 reset);
@@ -337,8 +337,8 @@ int iwl_trans_pcie_send_cmd(struct iwl_trans *trans, struct iwl_host_cmd *cmd);
void iwl_tx_cmd_complete(struct iwl_trans *trans,
struct iwl_rx_cmd_buffer *rxb, int handler_status);
void iwl_trans_txq_update_byte_cnt_tbl(struct iwl_trans *trans,
- struct iwl_tx_queue *txq,
- u16 byte_cnt);
+ struct iwl_tx_queue *txq,
+ u16 byte_cnt);
void iwl_trans_pcie_tx_agg_disable(struct iwl_trans *trans, int queue);
void iwl_trans_set_wr_ptrs(struct iwl_trans *trans, int txq_id, u32 index);
void iwl_trans_tx_queue_set_status(struct iwl_trans *trans,
@@ -346,8 +346,8 @@ void iwl_trans_tx_queue_set_status(struct iwl_trans *trans,
int tx_fifo_id, bool active);
void iwl_trans_pcie_tx_agg_setup(struct iwl_trans *trans, int queue, int fifo,
int sta_id, int tid, int frame_limit, u16 ssn);
-void iwlagn_txq_free_tfd(struct iwl_trans *trans, struct iwl_tx_queue *txq,
- enum dma_data_direction dma_dir);
+void iwl_txq_free_tfd(struct iwl_trans *trans, struct iwl_tx_queue *txq,
+ enum dma_data_direction dma_dir);
int iwl_tx_queue_reclaim(struct iwl_trans *trans, int txq_id, int index,
struct sk_buff_head *skbs);
int iwl_queue_space(const struct iwl_queue *q);
diff --git a/drivers/net/wireless/iwlwifi/iwl-trans-pcie-rx.c b/drivers/net/wireless/iwlwifi/iwl-trans-pcie-rx.c
index 08517d3c80b..98605fc7ad3 100644
--- a/drivers/net/wireless/iwlwifi/iwl-trans-pcie-rx.c
+++ b/drivers/net/wireless/iwlwifi/iwl-trans-pcie-rx.c
@@ -130,7 +130,7 @@ static int iwl_rx_queue_space(const struct iwl_rx_queue *q)
* iwl_rx_queue_update_write_ptr - Update the write pointer for the RX queue
*/
void iwl_rx_queue_update_write_ptr(struct iwl_trans *trans,
- struct iwl_rx_queue *q)
+ struct iwl_rx_queue *q)
{
unsigned long flags;
u32 reg;
@@ -201,9 +201,7 @@ static inline __le32 iwlagn_dma_addr2rbd_ptr(dma_addr_t dma_addr)
*/
static void iwlagn_rx_queue_restock(struct iwl_trans *trans)
{
- struct iwl_trans_pcie *trans_pcie =
- IWL_TRANS_GET_PCIE_TRANS(trans);
-
+ struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);
struct iwl_rx_queue *rxq = &trans_pcie->rxq;
struct list_head *element;
struct iwl_rx_mem_buffer *rxb;
@@ -253,9 +251,7 @@ static void iwlagn_rx_queue_restock(struct iwl_trans *trans)
*/
static void iwlagn_rx_allocate(struct iwl_trans *trans, gfp_t priority)
{
- struct iwl_trans_pcie *trans_pcie =
- IWL_TRANS_GET_PCIE_TRANS(trans);
-
+ struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);
struct iwl_rx_queue *rxq = &trans_pcie->rxq;
struct list_head *element;
struct iwl_rx_mem_buffer *rxb;
@@ -278,8 +274,7 @@ static void iwlagn_rx_allocate(struct iwl_trans *trans, gfp_t priority)
gfp_mask |= __GFP_COMP;
/* Alloc a new receive buffer */
- page = alloc_pages(gfp_mask,
- trans_pcie->rx_page_order);
+ page = alloc_pages(gfp_mask, trans_pcie->rx_page_order);
if (!page) {
if (net_ratelimit())
IWL_DEBUG_INFO(trans, "alloc_pages failed, "
@@ -315,9 +310,10 @@ static void iwlagn_rx_allocate(struct iwl_trans *trans, gfp_t priority)
BUG_ON(rxb->page);
rxb->page = page;
/* Get physical address of the RB */
- rxb->page_dma = dma_map_page(trans->dev, page, 0,
- PAGE_SIZE << trans_pcie->rx_page_order,
- DMA_FROM_DEVICE);
+ rxb->page_dma =
+ dma_map_page(trans->dev, page, 0,
+ PAGE_SIZE << trans_pcie->rx_page_order,
+ DMA_FROM_DEVICE);
/* dma address must be no more than 36 bits */
BUG_ON(rxb->page_dma & ~DMA_BIT_MASK(36));
/* and also 256 byte aligned! */
@@ -465,8 +461,8 @@ static void iwl_rx_handle_rxbuf(struct iwl_trans *trans,
if (rxb->page != NULL) {
rxb->page_dma =
dma_map_page(trans->dev, rxb->page, 0,
- PAGE_SIZE << trans_pcie->rx_page_order,
- DMA_FROM_DEVICE);
+ PAGE_SIZE << trans_pcie->rx_page_order,
+ DMA_FROM_DEVICE);
list_add_tail(&rxb->list, &rxq->rx_free);
rxq->free_count++;
} else
@@ -497,7 +493,7 @@ static void iwl_rx_handle(struct iwl_trans *trans)
/* Rx interrupt, but nothing sent from uCode */
if (i == r)
- IWL_DEBUG_RX(trans, "r = %d, i = %d\n", r, i);
+ IWL_DEBUG_RX(trans, "HW = SW = %d\n", r);
/* calculate total frames need to be restock after handling RX */
total_empty = r - rxq->write_actual;
@@ -513,8 +509,8 @@ static void iwl_rx_handle(struct iwl_trans *trans)
rxb = rxq->queue[i];
rxq->queue[i] = NULL;
- IWL_DEBUG_RX(trans, "rxbuf: r = %d, i = %d (%p)\n", rxb);
-
+ IWL_DEBUG_RX(trans, "rxbuf: HW = %d, SW = %d (%p)\n",
+ r, i, rxb);
iwl_rx_handle_rxbuf(trans, rxb);
i = (i + 1) & RX_QUEUE_MASK;
@@ -546,12 +542,12 @@ static void iwl_irq_handle_error(struct iwl_trans *trans)
/* W/A for WiFi/WiMAX coex and WiMAX own the RF */
if (trans->cfg->internal_wimax_coex &&
(!(iwl_read_prph(trans, APMG_CLK_CTRL_REG) &
- APMS_CLK_VAL_MRB_FUNC_MODE) ||
+ APMS_CLK_VAL_MRB_FUNC_MODE) ||
(iwl_read_prph(trans, APMG_PS_CTRL_REG) &
- APMG_PS_CTRL_VAL_RESET_REQ))) {
- struct iwl_trans_pcie *trans_pcie;
+ APMG_PS_CTRL_VAL_RESET_REQ))) {
+ struct iwl_trans_pcie *trans_pcie =
+ IWL_TRANS_GET_PCIE_TRANS(trans);
- trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);
clear_bit(STATUS_HCMD_ACTIVE, &trans_pcie->status);
iwl_op_mode_wimax_active(trans->op_mode);
wake_up(&trans->wait_command_queue);
@@ -567,6 +563,8 @@ static void iwl_irq_handle_error(struct iwl_trans *trans)
/* tasklet for iwlagn interrupt */
void iwl_irq_tasklet(struct iwl_trans *trans)
{
+ struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);
+ struct isr_statistics *isr_stats = &trans_pcie->isr_stats;
u32 inta = 0;
u32 handled = 0;
unsigned long flags;
@@ -575,10 +573,6 @@ void iwl_irq_tasklet(struct iwl_trans *trans)
u32 inta_mask;
#endif
- struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);
- struct isr_statistics *isr_stats = &trans_pcie->isr_stats;
-
-
spin_lock_irqsave(&trans_pcie->irq_lock, flags);
/* Ack/clear/reset pending uCode interrupts.
@@ -593,7 +587,7 @@ void iwl_irq_tasklet(struct iwl_trans *trans)
* interrupt coalescing can still be achieved.
*/
iwl_write32(trans, CSR_INT,
- trans_pcie->inta | ~trans_pcie->inta_mask);
+ trans_pcie->inta | ~trans_pcie->inta_mask);
inta = trans_pcie->inta;
@@ -602,7 +596,7 @@ void iwl_irq_tasklet(struct iwl_trans *trans)
/* just for debug */
inta_mask = iwl_read32(trans, CSR_INT_MASK);
IWL_DEBUG_ISR(trans, "inta 0x%08x, enabled 0x%08x\n",
- inta, inta_mask);
+ inta, inta_mask);
}
#endif
@@ -651,7 +645,7 @@ void iwl_irq_tasklet(struct iwl_trans *trans)
hw_rfkill = iwl_is_rfkill_set(trans);
IWL_WARN(trans, "RF_KILL bit toggled to %s.\n",
- hw_rfkill ? "disable radio" : "enable radio");
+ hw_rfkill ? "disable radio" : "enable radio");
isr_stats->rfkill++;
@@ -693,7 +687,7 @@ void iwl_irq_tasklet(struct iwl_trans *trans)
* Rx "responses" (frame-received notification), and other
* notifications from uCode come through here*/
if (inta & (CSR_INT_BIT_FH_RX | CSR_INT_BIT_SW_RX |
- CSR_INT_BIT_RX_PERIODIC)) {
+ CSR_INT_BIT_RX_PERIODIC)) {
IWL_DEBUG_ISR(trans, "Rx interrupt\n");
if (inta & (CSR_INT_BIT_FH_RX | CSR_INT_BIT_SW_RX)) {
handled |= (CSR_INT_BIT_FH_RX | CSR_INT_BIT_SW_RX);
@@ -733,7 +727,7 @@ void iwl_irq_tasklet(struct iwl_trans *trans)
*/
if (inta & (CSR_INT_BIT_FH_RX | CSR_INT_BIT_SW_RX))
iwl_write8(trans, CSR_INT_PERIODIC_REG,
- CSR_INT_PERIODIC_ENA);
+ CSR_INT_PERIODIC_ENA);
isr_stats->rx++;
}
@@ -782,8 +776,7 @@ void iwl_irq_tasklet(struct iwl_trans *trans)
/* Free dram table */
void iwl_free_isr_ict(struct iwl_trans *trans)
{
- struct iwl_trans_pcie *trans_pcie =
- IWL_TRANS_GET_PCIE_TRANS(trans);
+ struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);
if (trans_pcie->ict_tbl) {
dma_free_coherent(trans->dev, ICT_SIZE,
@@ -802,8 +795,7 @@ void iwl_free_isr_ict(struct iwl_trans *trans)
*/
int iwl_alloc_isr_ict(struct iwl_trans *trans)
{
- struct iwl_trans_pcie *trans_pcie =
- IWL_TRANS_GET_PCIE_TRANS(trans);
+ struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);
trans_pcie->ict_tbl =
dma_alloc_coherent(trans->dev, ICT_SIZE,
@@ -837,10 +829,9 @@ int iwl_alloc_isr_ict(struct iwl_trans *trans)
*/
void iwl_reset_ict(struct iwl_trans *trans)
{
+ struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);
u32 val;
unsigned long flags;
- struct iwl_trans_pcie *trans_pcie =
- IWL_TRANS_GET_PCIE_TRANS(trans);
if (!trans_pcie->ict_tbl)
return;
@@ -868,9 +859,7 @@ void iwl_reset_ict(struct iwl_trans *trans)
/* Device is going down disable ict interrupt usage */
void iwl_disable_ict(struct iwl_trans *trans)
{
- struct iwl_trans_pcie *trans_pcie =
- IWL_TRANS_GET_PCIE_TRANS(trans);
-
+ struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);
unsigned long flags;
spin_lock_irqsave(&trans_pcie->irq_lock, flags);
@@ -934,7 +923,7 @@ static irqreturn_t iwl_isr(int irq, void *data)
if (likely(inta))
tasklet_schedule(&trans_pcie->irq_tasklet);
else if (test_bit(STATUS_INT_ENABLED, &trans_pcie->status) &&
- !trans_pcie->inta)
+ !trans_pcie->inta)
iwl_enable_interrupts(trans);
unplugged:
@@ -945,7 +934,7 @@ static irqreturn_t iwl_isr(int irq, void *data)
/* re-enable interrupts here since we don't have anything to service. */
/* only Re-enable if disabled by irq and no schedules tasklet. */
if (test_bit(STATUS_INT_ENABLED, &trans_pcie->status) &&
- !trans_pcie->inta)
+ !trans_pcie->inta)
iwl_enable_interrupts(trans);
spin_unlock_irqrestore(&trans_pcie->irq_lock, flags);
@@ -1036,7 +1025,7 @@ irqreturn_t iwl_isr_ict(int irq, void *data)
inta = (0xff & val) | ((0xff00 & val) << 16);
IWL_DEBUG_ISR(trans, "ISR inta 0x%08x, enabled 0x%08x ict 0x%08x\n",
- inta, inta_mask, val);
+ inta, inta_mask, val);
inta &= trans_pcie->inta_mask;
trans_pcie->inta |= inta;
diff --git a/drivers/net/wireless/iwlwifi/iwl-trans-pcie-tx.c b/drivers/net/wireless/iwlwifi/iwl-trans-pcie-tx.c
index a8750238ee0..6f601cd05a9 100644
--- a/drivers/net/wireless/iwlwifi/iwl-trans-pcie-tx.c
+++ b/drivers/net/wireless/iwlwifi/iwl-trans-pcie-tx.c
@@ -47,12 +47,11 @@
* iwl_trans_txq_update_byte_cnt_tbl - Set up entry in Tx byte-count array
*/
void iwl_trans_txq_update_byte_cnt_tbl(struct iwl_trans *trans,
- struct iwl_tx_queue *txq,
- u16 byte_cnt)
+ struct iwl_tx_queue *txq,
+ u16 byte_cnt)
{
struct iwlagn_scd_bc_tbl *scd_bc_tbl;
- struct iwl_trans_pcie *trans_pcie =
- IWL_TRANS_GET_PCIE_TRANS(trans);
+ struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);
int write_ptr = txq->q.write_ptr;
int txq_id = txq->q.id;
u8 sec_ctl = 0;
@@ -178,8 +177,8 @@ static inline u8 iwl_tfd_get_num_tbs(struct iwl_tfd *tfd)
return tfd->num_tbs & 0x1f;
}
-static void iwlagn_unmap_tfd(struct iwl_trans *trans, struct iwl_cmd_meta *meta,
- struct iwl_tfd *tfd, enum dma_data_direction dma_dir)
+static void iwl_unmap_tfd(struct iwl_trans *trans, struct iwl_cmd_meta *meta,
+ struct iwl_tfd *tfd, enum dma_data_direction dma_dir)
{
int i;
int num_tbs;
@@ -209,7 +208,7 @@ static void iwlagn_unmap_tfd(struct iwl_trans *trans, struct iwl_cmd_meta *meta,
}
/**
- * iwlagn_txq_free_tfd - Free all chunks referenced by TFD [txq->q.read_ptr]
+ * iwl_txq_free_tfd - Free all chunks referenced by TFD [txq->q.read_ptr]
* @trans - transport private data
* @txq - tx queue
* @dma_dir - the direction of the DMA mapping
@@ -217,8 +216,8 @@ static void iwlagn_unmap_tfd(struct iwl_trans *trans, struct iwl_cmd_meta *meta,
* Does NOT advance any TFD circular buffer read/write indexes
* Does NOT free the TFD itself (which is within circular buffer)
*/
-void iwlagn_txq_free_tfd(struct iwl_trans *trans, struct iwl_tx_queue *txq,
- enum dma_data_direction dma_dir)
+void iwl_txq_free_tfd(struct iwl_trans *trans, struct iwl_tx_queue *txq,
+ enum dma_data_direction dma_dir)
{
struct iwl_tfd *tfd_tmp = txq->tfds;
@@ -229,8 +228,8 @@ void iwlagn_txq_free_tfd(struct iwl_trans *trans, struct iwl_tx_queue *txq,
lockdep_assert_held(&txq->lock);
/* We have only q->n_window txq->entries, but we use q->n_bd tfds */
- iwlagn_unmap_tfd(trans, &txq->entries[idx].meta,
- &tfd_tmp[rd_ptr], dma_dir);
+ iwl_unmap_tfd(trans, &txq->entries[idx].meta, &tfd_tmp[rd_ptr],
+ dma_dir);
/* free SKB */
if (txq->entries) {
@@ -270,7 +269,7 @@ int iwlagn_txq_attach_buf_to_tfd(struct iwl_trans *trans,
/* Each TFD can point to a maximum 20 Tx buffers */
if (num_tbs >= IWL_NUM_OF_TBS) {
IWL_ERR(trans, "Error can not send more than %d chunks\n",
- IWL_NUM_OF_TBS);
+ IWL_NUM_OF_TBS);
return -EINVAL;
}
@@ -279,7 +278,7 @@ int iwlagn_txq_attach_buf_to_tfd(struct iwl_trans *trans,
if (unlikely(addr & ~IWL_TX_DMA_MASK))
IWL_ERR(trans, "Unaligned address = %llx\n",
- (unsigned long long)addr);
+ (unsigned long long)addr);
iwl_tfd_set_tb(tfd, num_tbs, addr, len);
@@ -383,15 +382,13 @@ static void iwlagn_txq_inval_byte_cnt_tbl(struct iwl_trans *trans,
}
static int iwlagn_tx_queue_set_q2ratid(struct iwl_trans *trans, u16 ra_tid,
- u16 txq_id)
+ u16 txq_id)
{
+ struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);
u32 tbl_dw_addr;
u32 tbl_dw;
u16 scd_q2ratid;
- struct iwl_trans_pcie *trans_pcie =
- IWL_TRANS_GET_PCIE_TRANS(trans);
-
scd_q2ratid = ra_tid & SCD_QUEUE_RA_TID_MAP_RATID_MSK;
tbl_dw_addr = trans_pcie->scd_base_addr +
@@ -419,12 +416,11 @@ static void iwlagn_tx_queue_stop_scheduler(struct iwl_trans *trans, u16 txq_id)
(1 << SCD_QUEUE_STTS_REG_POS_SCD_ACT_EN));
}
-void iwl_trans_set_wr_ptrs(struct iwl_trans *trans,
- int txq_id, u32 index)
+void iwl_trans_set_wr_ptrs(struct iwl_trans *trans, int txq_id, u32 index)
{
IWL_DEBUG_TX_QUEUES(trans, "Q %d WrPtr: %d\n", txq_id, index & 0xff);
iwl_write_direct32(trans, HBUS_TARG_WRPTR,
- (index & 0xff) | (txq_id << 8));
+ (index & 0xff) | (txq_id << 8));
iwl_write_prph(trans, SCD_QUEUE_RDPTR(txq_id), index);
}
@@ -615,13 +611,13 @@ static int iwl_enqueue_hcmd(struct iwl_trans *trans, struct iwl_host_cmd *cmd)
}
IWL_DEBUG_HC(trans,
- "Sending command %s (#%x), seq: 0x%04X, %d bytes at %d[%d]:%d\n",
- trans_pcie_get_cmd_string(trans_pcie, out_cmd->hdr.cmd),
- out_cmd->hdr.cmd, le16_to_cpu(out_cmd->hdr.sequence), cmd_size,
- q->write_ptr, idx, trans_pcie->cmd_queue);
+ "Sending command %s (#%x), seq: 0x%04X, %d bytes at %d[%d]:%d\n",
+ trans_pcie_get_cmd_string(trans_pcie, out_cmd->hdr.cmd),
+ out_cmd->hdr.cmd, le16_to_cpu(out_cmd->hdr.sequence),
+ cmd_size, q->write_ptr, idx, trans_pcie->cmd_queue);
phys_addr = dma_map_single(trans->dev, &out_cmd->hdr, copy_size,
- DMA_BIDIRECTIONAL);
+ DMA_BIDIRECTIONAL);
if (unlikely(dma_mapping_error(trans->dev, phys_addr))) {
idx = -ENOMEM;
goto out;
@@ -630,8 +626,7 @@ static int iwl_enqueue_hcmd(struct iwl_trans *trans, struct iwl_host_cmd *cmd)
dma_unmap_addr_set(out_meta, mapping, phys_addr);
dma_unmap_len_set(out_meta, len, copy_size);
- iwlagn_txq_attach_buf_to_tfd(trans, txq,
- phys_addr, copy_size, 1);
+ iwlagn_txq_attach_buf_to_tfd(trans, txq, phys_addr, copy_size, 1);
#ifdef CONFIG_IWLWIFI_DEVICE_TRACING
trace_bufs[0] = &out_cmd->hdr;
trace_lens[0] = copy_size;
@@ -643,13 +638,12 @@ static int iwl_enqueue_hcmd(struct iwl_trans *trans, struct iwl_host_cmd *cmd)
continue;
if (!(cmd->dataflags[i] & IWL_HCMD_DFL_NOCOPY))
continue;
- phys_addr = dma_map_single(trans->dev,
- (void *)cmd->data[i],
+ phys_addr = dma_map_single(trans->dev, (void *)cmd->data[i],
cmd->len[i], DMA_BIDIRECTIONAL);
if (dma_mapping_error(trans->dev, phys_addr)) {
- iwlagn_unmap_tfd(trans, out_meta,
- &txq->tfds[q->write_ptr],
- DMA_BIDIRECTIONAL);
+ iwl_unmap_tfd(trans, out_meta,
+ &txq->tfds[q->write_ptr],
+ DMA_BIDIRECTIONAL);
idx = -ENOMEM;
goto out;
}
@@ -723,9 +717,10 @@ static void iwl_hcmd_queue_reclaim(struct iwl_trans *trans, int txq_id,
lockdep_assert_held(&txq->lock);
if ((idx >= q->n_bd) || (iwl_queue_used(q, idx) == 0)) {
- IWL_ERR(trans, "%s: Read index for DMA queue txq id (%d), "
- "index %d is out of range [0-%d] %d %d.\n", __func__,
- txq_id, idx, q->n_bd, q->write_ptr, q->read_ptr);
+ IWL_ERR(trans,
+ "%s: Read index for DMA queue txq id (%d), index %d is out of range [0-%d] %d %d.\n",
+ __func__, txq_id, idx, q->n_bd,
+ q->write_ptr, q->read_ptr);
return;
}
@@ -733,8 +728,8 @@ static void iwl_hcmd_queue_reclaim(struct iwl_trans *trans, int txq_id,
q->read_ptr = iwl_queue_inc_wrap(q->read_ptr, q->n_bd)) {
if (nfreed++ > 0) {
- IWL_ERR(trans, "HCMD skipped: index (%d) %d %d\n", idx,
- q->write_ptr, q->read_ptr);
+ IWL_ERR(trans, "HCMD skipped: index (%d) %d %d\n",
+ idx, q->write_ptr, q->read_ptr);
iwl_op_mode_nic_error(trans->op_mode);
}
@@ -771,9 +766,9 @@ void iwl_tx_cmd_complete(struct iwl_trans *trans, struct iwl_rx_cmd_buffer *rxb,
* in the queue management code. */
if (WARN(txq_id != trans_pcie->cmd_queue,
"wrong command queue %d (should be %d), sequence 0x%X readp=%d writep=%d\n",
- txq_id, trans_pcie->cmd_queue, sequence,
- trans_pcie->txq[trans_pcie->cmd_queue].q.read_ptr,
- trans_pcie->txq[trans_pcie->cmd_queue].q.write_ptr)) {
+ txq_id, trans_pcie->cmd_queue, sequence,
+ trans_pcie->txq[trans_pcie->cmd_queue].q.read_ptr,
+ trans_pcie->txq[trans_pcie->cmd_queue].q.write_ptr)) {
iwl_print_hex_error(trans, pkt, 32);
return;
}
@@ -784,8 +779,7 @@ void iwl_tx_cmd_complete(struct iwl_trans *trans, struct iwl_rx_cmd_buffer *rxb,
cmd = txq->entries[cmd_index].cmd;
meta = &txq->entries[cmd_index].meta;
- iwlagn_unmap_tfd(trans, meta, &txq->tfds[index],
- DMA_BIDIRECTIONAL);
+ iwl_unmap_tfd(trans, meta, &txq->tfds[index], DMA_BIDIRECTIONAL);
/* Input error checking is done when commands are added to queue. */
if (meta->flags & CMD_WANT_SKB) {
@@ -870,8 +864,9 @@ static int iwl_send_cmd_sync(struct iwl_trans *trans, struct iwl_host_cmd *cmd)
}
ret = wait_event_timeout(trans->wait_command_queue,
- !test_bit(STATUS_HCMD_ACTIVE, &trans_pcie->status),
- HOST_COMPLETE_TIMEOUT);
+ !test_bit(STATUS_HCMD_ACTIVE,
+ &trans_pcie->status),
+ HOST_COMPLETE_TIMEOUT);
if (!ret) {
if (test_bit(STATUS_HCMD_ACTIVE, &trans_pcie->status)) {
struct iwl_tx_queue *txq =
@@ -956,10 +951,10 @@ int iwl_tx_queue_reclaim(struct iwl_trans *trans, int txq_id, int index,
if ((index >= q->n_bd) ||
(iwl_queue_used(q, last_to_free) == 0)) {
- IWL_ERR(trans, "%s: Read index for DMA queue txq id (%d), "
- "last_to_free %d is out of range [0-%d] %d %d.\n",
- __func__, txq_id, last_to_free, q->n_bd,
- q->write_ptr, q->read_ptr);
+ IWL_ERR(trans,
+ "%s: Read index for DMA queue txq id (%d), last_to_free %d is out of range [0-%d] %d %d.\n",
+ __func__, txq_id, last_to_free, q->n_bd,
+ q->write_ptr, q->read_ptr);
return 0;
}
@@ -979,7 +974,7 @@ int iwl_tx_queue_reclaim(struct iwl_trans *trans, int txq_id, int index,
iwlagn_txq_inval_byte_cnt_tbl(trans, txq);
- iwlagn_txq_free_tfd(trans, txq, DMA_TO_DEVICE);
+ iwl_txq_free_tfd(trans, txq, DMA_TO_DEVICE);
freed++;
}
diff --git a/drivers/net/wireless/iwlwifi/iwl-trans-pcie.c b/drivers/net/wireless/iwlwifi/iwl-trans-pcie.c
index ec6fb395b84..1e50401023e 100644
--- a/drivers/net/wireless/iwlwifi/iwl-trans-pcie.c
+++ b/drivers/net/wireless/iwlwifi/iwl-trans-pcie.c
@@ -78,16 +78,13 @@
/* FIXME: need to abstract out TX command (once we know what it looks like) */
#include "iwl-commands.h"
-#define IWL_MASK(lo, hi) ((1 << (hi)) | ((1 << (hi)) - (1 << (lo))))
-
#define SCD_QUEUECHAIN_SEL_ALL(trans, trans_pcie) \
(((1<<trans->cfg->base_params->num_of_queues) - 1) &\
(~(1<<(trans_pcie)->cmd_queue)))
static int iwl_trans_rx_alloc(struct iwl_trans *trans)
{
- struct iwl_trans_pcie *trans_pcie =
- IWL_TRANS_GET_PCIE_TRANS(trans);
+ struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);
struct iwl_rx_queue *rxq = &trans_pcie->rxq;
struct device *dev = trans->dev;
@@ -114,7 +111,7 @@ static int iwl_trans_rx_alloc(struct iwl_trans *trans)
err_rb_stts:
dma_free_coherent(dev, sizeof(__le32) * RX_QUEUE_SIZE,
- rxq->bd, rxq->bd_dma);
+ rxq->bd, rxq->bd_dma);
memset(&rxq->bd_dma, 0, sizeof(rxq->bd_dma));
rxq->bd = NULL;
err_bd:
@@ -123,8 +120,7 @@ err_bd:
static void iwl_trans_rxq_free_rx_bufs(struct iwl_trans *trans)
{
- struct iwl_trans_pcie *trans_pcie =
- IWL_TRANS_GET_PCIE_TRANS(trans);
+ struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);
struct iwl_rx_queue *rxq = &trans_pcie->rxq;
int i;
@@ -134,8 +130,8 @@ static void iwl_trans_rxq_free_rx_bufs(struct iwl_trans *trans)
* to an SKB, so we need to unmap and free potential storage */
if (rxq->pool[i].page != NULL) {
dma_unmap_page(trans->dev, rxq->pool[i].page_dma,
- PAGE_SIZE << trans_pcie->rx_page_order,
- DMA_FROM_DEVICE);
+ PAGE_SIZE << trans_pcie->rx_page_order,
+ DMA_FROM_DEVICE);
__free_pages(rxq->pool[i].page,
trans_pcie->rx_page_order);
rxq->pool[i].page = NULL;
@@ -193,8 +189,7 @@ static void iwl_trans_rx_hw_init(struct iwl_trans *trans,
static int iwl_rx_init(struct iwl_trans *trans)
{
- struct iwl_trans_pcie *trans_pcie =
- IWL_TRANS_GET_PCIE_TRANS(trans);
+ struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);
struct iwl_rx_queue *rxq = &trans_pcie->rxq;
int i, err;
@@ -236,10 +231,8 @@ static int iwl_rx_init(struct iwl_trans *trans)
static void iwl_trans_pcie_rx_free(struct iwl_trans *trans)
{
- struct iwl_trans_pcie *trans_pcie =
- IWL_TRANS_GET_PCIE_TRANS(trans);
+ struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);
struct iwl_rx_queue *rxq = &trans_pcie->rxq;
-
unsigned long flags;
/*if rxq->bd is NULL, it means that nothing has been allocated,
@@ -274,11 +267,11 @@ static int iwl_trans_rx_stop(struct iwl_trans *trans)
/* stop Rx DMA */
iwl_write_direct32(trans, FH_MEM_RCSR_CHNL0_CONFIG_REG, 0);
return iwl_poll_direct_bit(trans, FH_MEM_RSSR_RX_STATUS_REG,
- FH_RSSR_CHNL0_RX_STATUS_CHNL_IDLE, 1000);
+ FH_RSSR_CHNL0_RX_STATUS_CHNL_IDLE, 1000);
}
-static inline int iwlagn_alloc_dma_ptr(struct iwl_trans *trans,
- struct iwl_dma_ptr *ptr, size_t size)
+static int iwlagn_alloc_dma_ptr(struct iwl_trans *trans,
+ struct iwl_dma_ptr *ptr, size_t size)
{
if (WARN_ON(ptr->addr))
return -EINVAL;
@@ -291,8 +284,8 @@ static inline int iwlagn_alloc_dma_ptr(struct iwl_trans *trans,
return 0;
}
-static inline void iwlagn_free_dma_ptr(struct iwl_trans *trans,
- struct iwl_dma_ptr *ptr)
+static void iwlagn_free_dma_ptr(struct iwl_trans *trans,
+ struct iwl_dma_ptr *ptr)
{
if (unlikely(!ptr->addr))
return;
@@ -329,12 +322,12 @@ static void iwl_trans_pcie_queue_stuck_timer(unsigned long data)
}
static int iwl_trans_txq_alloc(struct iwl_trans *trans,
- struct iwl_tx_queue *txq, int slots_num,
- u32 txq_id)
+ struct iwl_tx_queue *txq, int slots_num,
+ u32 txq_id)
{
+ struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);
size_t tfd_sz = sizeof(struct iwl_tfd) * TFD_QUEUE_SIZE_MAX;
int i;
- struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);
if (WARN_ON(txq->entries || txq->tfds))
return -EINVAL;
@@ -435,7 +428,7 @@ static void iwl_tx_queue_unmap(struct iwl_trans *trans, int txq_id)
spin_lock_bh(&txq->lock);
while (q->write_ptr != q->read_ptr) {
- iwlagn_txq_free_tfd(trans, txq, dma_dir);
+ iwl_txq_free_tfd(trans, txq, dma_dir);
q->read_ptr = iwl_queue_inc_wrap(q->read_ptr, q->n_bd);
}
spin_unlock_bh(&txq->lock);
@@ -455,6 +448,7 @@ static void iwl_tx_queue_free(struct iwl_trans *trans, int txq_id)
struct iwl_tx_queue *txq = &trans_pcie->txq[txq_id];
struct device *dev = trans->dev;
int i;
+
if (WARN_ON(!txq))
return;
@@ -574,11 +568,11 @@ error:
}
static int iwl_tx_init(struct iwl_trans *trans)
{
+ struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);
int ret;
int txq_id, slots_num;
unsigned long flags;
bool alloc = false;
- struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);
if (!trans_pcie->txq) {
ret = iwl_trans_tx_alloc(trans);
@@ -643,10 +637,9 @@ static void iwl_set_pwr_vmain(struct iwl_trans *trans)
static u16 iwl_pciexp_link_ctrl(struct iwl_trans *trans)
{
+ struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);
int pos;
u16 pci_lnk_ctl;
- struct iwl_trans_pcie *trans_pcie =
- IWL_TRANS_GET_PCIE_TRANS(trans);
struct pci_dev *pci_dev = trans_pcie->pci_dev;
@@ -700,14 +693,14 @@ static int iwl_apm_init(struct iwl_trans *trans)
/* Disable L0S exit timer (platform NMI Work/Around) */
iwl_set_bit(trans, CSR_GIO_CHICKEN_BITS,
- CSR_GIO_CHICKEN_BITS_REG_BIT_DIS_L0S_EXIT_TIMER);
+ CSR_GIO_CHICKEN_BITS_REG_BIT_DIS_L0S_EXIT_TIMER);
/*
* Disable L0s without affecting L1;
* don't wait for ICH L0s (ICH bug W/A)
*/
iwl_set_bit(trans, CSR_GIO_CHICKEN_BITS,
- CSR_GIO_CHICKEN_BITS_REG_BIT_L1A_NO_L0S_RX);
+ CSR_GIO_CHICKEN_BITS_REG_BIT_L1A_NO_L0S_RX);
/* Set FH wait threshold to maximum (HW error during stress W/A) */
iwl_set_bit(trans, CSR_DBG_HPET_MEM_REG, CSR_DBG_HPET_MEM_REG_VAL);
@@ -717,7 +710,7 @@ static int iwl_apm_init(struct iwl_trans *trans)
* wake device's PCI Express link L1a -> L0s
*/
iwl_set_bit(trans, CSR_HW_IF_CONFIG_REG,
- CSR_HW_IF_CONFIG_REG_BIT_HAP_WAKE_L1A);
+ CSR_HW_IF_CONFIG_REG_BIT_HAP_WAKE_L1A);
iwl_apm_config(trans);
@@ -738,8 +731,8 @@ static int iwl_apm_init(struct iwl_trans *trans)
* and accesses to uCode SRAM.
*/
ret = iwl_poll_bit(trans, CSR_GP_CNTRL,
- CSR_GP_CNTRL_REG_FLAG_MAC_CLOCK_READY,
- CSR_GP_CNTRL_REG_FLAG_MAC_CLOCK_READY, 25000);
+ CSR_GP_CNTRL_REG_FLAG_MAC_CLOCK_READY,
+ CSR_GP_CNTRL_REG_FLAG_MAC_CLOCK_READY, 25000);
if (ret < 0) {
IWL_DEBUG_INFO(trans, "Failed to init the card\n");
goto out;
@@ -773,8 +766,8 @@ static int iwl_apm_stop_master(struct iwl_trans *trans)
iwl_set_bit(trans, CSR_RESET, CSR_RESET_REG_FLAG_STOP_MASTER);
ret = iwl_poll_bit(trans, CSR_RESET,
- CSR_RESET_REG_FLAG_MASTER_DISABLED,
- CSR_RESET_REG_FLAG_MASTER_DISABLED, 100);
+ CSR_RESET_REG_FLAG_MASTER_DISABLED,
+ CSR_RESET_REG_FLAG_MASTER_DISABLED, 100);
if (ret)
IWL_WARN(trans, "Master Disable Timed Out, 100 usec\n");
@@ -816,8 +809,7 @@ static int iwl_nic_init(struct iwl_trans *trans)
iwl_apm_init(trans);
/* Set interrupt coalescing calibration timer to default (512 usecs) */
- iwl_write8(trans, CSR_INT_COALESCING,
- IWL_HOST_INT_CALIB_TIMEOUT_DEF);
+ iwl_write8(trans, CSR_INT_COALESCING, IWL_HOST_INT_CALIB_TIMEOUT_DEF);
spin_unlock_irqrestore(&trans_pcie->irq_lock, flags);
@@ -836,8 +828,8 @@ static int iwl_nic_init(struct iwl_trans *trans)
if (trans->cfg->base_params->shadow_reg_enable) {
/* enable shadow regs in HW */
- iwl_set_bit(trans, CSR_MAC_SHADOW_REG_CTRL,
- 0x800FFFFF);
+ iwl_set_bit(trans, CSR_MAC_SHADOW_REG_CTRL, 0x800FFFFF);
+ IWL_DEBUG_INFO(trans, "Enabling shadow registers in device\n");
}
return 0;
@@ -851,13 +843,13 @@ static int iwl_set_hw_ready(struct iwl_trans *trans)
int ret;
iwl_set_bit(trans, CSR_HW_IF_CONFIG_REG,
- CSR_HW_IF_CONFIG_REG_BIT_NIC_READY);
+ CSR_HW_IF_CONFIG_REG_BIT_NIC_READY);
/* See if we got it */
ret = iwl_poll_bit(trans, CSR_HW_IF_CONFIG_REG,
- CSR_HW_IF_CONFIG_REG_BIT_NIC_READY,
- CSR_HW_IF_CONFIG_REG_BIT_NIC_READY,
- HW_READY_TIMEOUT);
+ CSR_HW_IF_CONFIG_REG_BIT_NIC_READY,
+ CSR_HW_IF_CONFIG_REG_BIT_NIC_READY,
+ HW_READY_TIMEOUT);
IWL_DEBUG_INFO(trans, "hardware%s ready\n", ret < 0 ? " not" : "");
return ret;
@@ -877,11 +869,11 @@ static int iwl_prepare_card_hw(struct iwl_trans *trans)
/* If HW is not ready, prepare the conditions to check again */
iwl_set_bit(trans, CSR_HW_IF_CONFIG_REG,
- CSR_HW_IF_CONFIG_REG_PREPARE);
+ CSR_HW_IF_CONFIG_REG_PREPARE);
ret = iwl_poll_bit(trans, CSR_HW_IF_CONFIG_REG,
- ~CSR_HW_IF_CONFIG_REG_BIT_NIC_PREPARE_DONE,
- CSR_HW_IF_CONFIG_REG_BIT_NIC_PREPARE_DONE, 150000);
+ ~CSR_HW_IF_CONFIG_REG_BIT_NIC_PREPARE_DONE,
+ CSR_HW_IF_CONFIG_REG_BIT_NIC_PREPARE_DONE, 150000);
if (ret < 0)
return ret;
@@ -908,32 +900,33 @@ static int iwl_load_section(struct iwl_trans *trans, u8 section_num,
trans_pcie->ucode_write_complete = false;
iwl_write_direct32(trans,
- FH_TCSR_CHNL_TX_CONFIG_REG(FH_SRVC_CHNL),
- FH_TCSR_TX_CONFIG_REG_VAL_DMA_CHNL_PAUSE);
+ FH_TCSR_CHNL_TX_CONFIG_REG(FH_SRVC_CHNL),
+ FH_TCSR_TX_CONFIG_REG_VAL_DMA_CHNL_PAUSE);
iwl_write_direct32(trans,
- FH_SRVC_CHNL_SRAM_ADDR_REG(FH_SRVC_CHNL), dst_addr);
+ FH_SRVC_CHNL_SRAM_ADDR_REG(FH_SRVC_CHNL),
+ dst_addr);
iwl_write_direct32(trans,
FH_TFDIB_CTRL0_REG(FH_SRVC_CHNL),
phy_addr & FH_MEM_TFDIB_DRAM_ADDR_LSB_MSK);
iwl_write_direct32(trans,
- FH_TFDIB_CTRL1_REG(FH_SRVC_CHNL),
- (iwl_get_dma_hi_addr(phy_addr)
- << FH_MEM_TFDIB_REG1_ADDR_BITSHIFT) | byte_cnt);
+ FH_TFDIB_CTRL1_REG(FH_SRVC_CHNL),
+ (iwl_get_dma_hi_addr(phy_addr)
+ << FH_MEM_TFDIB_REG1_ADDR_BITSHIFT) | byte_cnt);
iwl_write_direct32(trans,
- FH_TCSR_CHNL_TX_BUF_STS_REG(FH_SRVC_CHNL),
- 1 << FH_TCSR_CHNL_TX_BUF_STS_REG_POS_TB_NUM |
- 1 << FH_TCSR_CHNL_TX_BUF_STS_REG_POS_TB_IDX |
- FH_TCSR_CHNL_TX_BUF_STS_REG_VAL_TFDB_VALID);
+ FH_TCSR_CHNL_TX_BUF_STS_REG(FH_SRVC_CHNL),
+ 1 << FH_TCSR_CHNL_TX_BUF_STS_REG_POS_TB_NUM |
+ 1 << FH_TCSR_CHNL_TX_BUF_STS_REG_POS_TB_IDX |
+ FH_TCSR_CHNL_TX_BUF_STS_REG_VAL_TFDB_VALID);
iwl_write_direct32(trans,
- FH_TCSR_CHNL_TX_CONFIG_REG(FH_SRVC_CHNL),
- FH_TCSR_TX_CONFIG_REG_VAL_DMA_CHNL_ENABLE |
- FH_TCSR_TX_CONFIG_REG_VAL_DMA_CREDIT_DISABLE |
- FH_TCSR_TX_CONFIG_REG_VAL_CIRQ_HOST_ENDTFD);
+ FH_TCSR_CHNL_TX_CONFIG_REG(FH_SRVC_CHNL),
+ FH_TCSR_TX_CONFIG_REG_VAL_DMA_CHNL_ENABLE |
+ FH_TCSR_TX_CONFIG_REG_VAL_DMA_CREDIT_DISABLE |
+ FH_TCSR_TX_CONFIG_REG_VAL_CIRQ_HOST_ENDTFD);
IWL_DEBUG_FW(trans, "[%d] uCode section being loaded...\n",
section_num);
@@ -1070,7 +1063,7 @@ static void iwl_tx_start(struct iwl_trans *trans)
reg_val | FH_TX_CHICKEN_BITS_SCD_AUTO_RETRY_EN);
iwl_write_prph(trans, SCD_QUEUECHAIN_SEL,
- SCD_QUEUECHAIN_SEL_ALL(trans, trans_pcie));
+ SCD_QUEUECHAIN_SEL_ALL(trans, trans_pcie));
iwl_write_prph(trans, SCD_AGGR_SEL, 0);
/* initiate the queues */
@@ -1091,7 +1084,7 @@ static void iwl_tx_start(struct iwl_trans *trans)
}
iwl_write_prph(trans, SCD_INTERRUPT_MASK,
- IWL_MASK(0, trans->cfg->base_params->num_of_queues));
+ IWL_MASK(0, trans->cfg->base_params->num_of_queues));
/* Activate all Tx DMA/FIFO channels */
iwl_trans_txq_set_sched(trans, IWL_MASK(0, 7));
@@ -1115,7 +1108,7 @@ static void iwl_tx_start(struct iwl_trans *trans)
/* Enable L1-Active */
iwl_clear_bits_prph(trans, APMG_PCIDEV_STT_REG,
- APMG_PCIDEV_STT_VAL_L1_ACT_DIS);
+ APMG_PCIDEV_STT_VAL_L1_ACT_DIS);
}
static void iwl_trans_pcie_fw_alive(struct iwl_trans *trans)
@@ -1129,9 +1122,9 @@ static void iwl_trans_pcie_fw_alive(struct iwl_trans *trans)
*/
static int iwl_trans_tx_stop(struct iwl_trans *trans)
{
+ struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);
int ch, txq_id, ret;
unsigned long flags;
- struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);
/* Turn off all Tx DMA fifos */
spin_lock_irqsave(&trans_pcie->irq_lock, flags);
@@ -1143,13 +1136,13 @@ static int iwl_trans_tx_stop(struct iwl_trans *trans)
iwl_write_direct32(trans,
FH_TCSR_CHNL_TX_CONFIG_REG(ch), 0x0);
ret = iwl_poll_direct_bit(trans, FH_TSSR_TX_STATUS_REG,
- FH_TSSR_TX_STATUS_REG_MSK_CHNL_IDLE(ch),
- 1000);
+ FH_TSSR_TX_STATUS_REG_MSK_CHNL_IDLE(ch), 1000);
if (ret < 0)
- IWL_ERR(trans, "Failing on timeout while stopping"
- " DMA channel %d [0x%08x]", ch,
- iwl_read_direct32(trans,
- FH_TSSR_TX_STATUS_REG));
+ IWL_ERR(trans,
+ "Failing on timeout while stopping DMA channel %d [0x%08x]",
+ ch,
+ iwl_read_direct32(trans,
+ FH_TSSR_TX_STATUS_REG));
}
spin_unlock_irqrestore(&trans_pcie->irq_lock, flags);
@@ -1168,8 +1161,8 @@ static int iwl_trans_tx_stop(struct iwl_trans *trans)
static void iwl_trans_pcie_stop_device(struct iwl_trans *trans)
{
- unsigned long flags;
struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);
+ unsigned long flags;
/* tell the device to stop sending interrupts */
spin_lock_irqsave(&trans_pcie->irq_lock, flags);
@@ -1199,7 +1192,7 @@ static void iwl_trans_pcie_stop_device(struct iwl_trans *trans)
/* Make sure (redundant) we've released our request to stay awake */
iwl_clear_bit(trans, CSR_GP_CNTRL,
- CSR_GP_CNTRL_REG_FLAG_MAC_ACCESS_REQ);
+ CSR_GP_CNTRL_REG_FLAG_MAC_ACCESS_REQ);
/* Stop the device, and put it in low power state */
iwl_apm_stop(trans);
@@ -1273,8 +1266,9 @@ static int iwl_trans_pcie_tx(struct iwl_trans *trans, struct sk_buff *skb,
txq->entries[q->write_ptr].cmd = dev_cmd;
dev_cmd->hdr.cmd = REPLY_TX;
- dev_cmd->hdr.sequence = cpu_to_le16((u16)(QUEUE_TO_SEQ(txq_id) |
- INDEX_TO_SEQ(q->write_ptr)));
+ dev_cmd->hdr.sequence =
+ cpu_to_le16((u16)(QUEUE_TO_SEQ(txq_id) |
+ INDEX_TO_SEQ(q->write_ptr)));
/* Set up first empty entry in queue's array of Tx/cmd buffers */
out_meta = &txq->entries[q->write_ptr].meta;
@@ -1339,7 +1333,7 @@ static int iwl_trans_pcie_tx(struct iwl_trans *trans, struct sk_buff *skb,
/* take back ownership of DMA buffer to enable update */
dma_sync_single_for_cpu(trans->dev, txcmd_phys, firstlen,
- DMA_BIDIRECTIONAL);
+ DMA_BIDIRECTIONAL);
tx_cmd->dram_lsb_ptr = cpu_to_le32(scratch_phys);
tx_cmd->dram_msb_ptr = iwl_get_dma_hi_addr(scratch_phys);
@@ -1351,7 +1345,7 @@ static int iwl_trans_pcie_tx(struct iwl_trans *trans, struct sk_buff *skb,
iwl_trans_txq_update_byte_cnt_tbl(trans, txq, le16_to_cpu(tx_cmd->len));
dma_sync_single_for_device(trans->dev, txcmd_phys, firstlen,
- DMA_BIDIRECTIONAL);
+ DMA_BIDIRECTIONAL);
trace_iwlwifi_dev_tx(trans->dev,
&((struct iwl_tfd *)txq->tfds)[txq->q.write_ptr],
@@ -1390,8 +1384,7 @@ static int iwl_trans_pcie_tx(struct iwl_trans *trans, struct sk_buff *skb,
static int iwl_trans_pcie_start_hw(struct iwl_trans *trans)
{
- struct iwl_trans_pcie *trans_pcie =
- IWL_TRANS_GET_PCIE_TRANS(trans);
+ struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);
int err;
bool hw_rfkill;
@@ -1404,7 +1397,7 @@ static int iwl_trans_pcie_start_hw(struct iwl_trans *trans)
iwl_alloc_isr_ict(trans);
err = request_irq(trans_pcie->irq, iwl_isr_ict, IRQF_SHARED,
- DRV_NAME, trans);
+ DRV_NAME, trans);
if (err) {
IWL_ERR(trans, "Error allocating IRQ %d\n",
trans_pcie->irq);
@@ -1442,9 +1435,9 @@ error:
static void iwl_trans_pcie_stop_hw(struct iwl_trans *trans,
bool op_mode_leaving)
{
+ struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);
bool hw_rfkill;
unsigned long flags;
- struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);
iwl_apm_stop(trans);
@@ -1548,8 +1541,7 @@ static void iwl_trans_pcie_configure(struct iwl_trans *trans,
void iwl_trans_pcie_free(struct iwl_trans *trans)
{
- struct iwl_trans_pcie *trans_pcie =
- IWL_TRANS_GET_PCIE_TRANS(trans);
+ struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);
iwl_trans_pcie_tx_free(trans);
#ifndef CONFIG_IWLWIFI_IDI
@@ -1811,8 +1803,8 @@ static const struct file_operations iwl_dbgfs_##name##_ops = { \
};
static ssize_t iwl_dbgfs_tx_queue_read(struct file *file,
- char __user *user_buf,
- size_t count, loff_t *ppos)
+ char __user *user_buf,
+ size_t count, loff_t *ppos)
{
struct iwl_trans *trans = file->private_data;
struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);
@@ -1848,11 +1840,11 @@ static ssize_t iwl_dbgfs_tx_queue_read(struct file *file,
}
static ssize_t iwl_dbgfs_rx_queue_read(struct file *file,
- char __user *user_buf,
- size_t count, loff_t *ppos) {
+ char __user *user_buf,
+ size_t count, loff_t *ppos)
+{
struct iwl_trans *trans = file->private_data;
- struct iwl_trans_pcie *trans_pcie =
- IWL_TRANS_GET_PCIE_TRANS(trans);
+ struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);
struct iwl_rx_queue *rxq = &trans_pcie->rxq;
char buf[256];
int pos = 0;
@@ -1876,11 +1868,10 @@ static ssize_t iwl_dbgfs_rx_queue_read(struct file *file,
static ssize_t iwl_dbgfs_interrupt_read(struct file *file,
char __user *user_buf,
- size_t count, loff_t *ppos) {
-
+ size_t count, loff_t *ppos)
+{
struct iwl_trans *trans = file->private_data;
- struct iwl_trans_pcie *trans_pcie =
- IWL_TRANS_GET_PCIE_TRANS(trans);
+ struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);
struct isr_statistics *isr_stats = &trans_pcie->isr_stats;
int pos = 0;
@@ -1938,8 +1929,7 @@ static ssize_t iwl_dbgfs_interrupt_write(struct file *file,
size_t count, loff_t *ppos)
{
struct iwl_trans *trans = file->private_data;
- struct iwl_trans_pcie *trans_pcie =
- IWL_TRANS_GET_PCIE_TRANS(trans);
+ struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);
struct isr_statistics *isr_stats = &trans_pcie->isr_stats;
char buf[8];
@@ -1959,8 +1949,8 @@ static ssize_t iwl_dbgfs_interrupt_write(struct file *file,
}
static ssize_t iwl_dbgfs_csr_write(struct file *file,
- const char __user *user_buf,
- size_t count, loff_t *ppos)
+ const char __user *user_buf,
+ size_t count, loff_t *ppos)
{
struct iwl_trans *trans = file->private_data;
char buf[8];
@@ -1980,8 +1970,8 @@ static ssize_t iwl_dbgfs_csr_write(struct file *file,
}
static ssize_t iwl_dbgfs_fh_reg_read(struct file *file,
- char __user *user_buf,
- size_t count, loff_t *ppos)
+ char __user *user_buf,
+ size_t count, loff_t *ppos)
{
struct iwl_trans *trans = file->private_data;
char *buf;
@@ -2024,7 +2014,7 @@ DEBUGFS_WRITE_FILE_OPS(fw_restart);
*
*/
static int iwl_trans_pcie_dbgfs_register(struct iwl_trans *trans,
- struct dentry *dir)
+ struct dentry *dir)
{
DEBUGFS_ADD_FILE(rx_queue, dir, S_IRUSR);
DEBUGFS_ADD_FILE(tx_queue, dir, S_IRUSR);
@@ -2036,9 +2026,10 @@ static int iwl_trans_pcie_dbgfs_register(struct iwl_trans *trans,
}
#else
static int iwl_trans_pcie_dbgfs_register(struct iwl_trans *trans,
- struct dentry *dir)
-{ return 0; }
-
+ struct dentry *dir)
+{
+ return 0;
+}
#endif /*CONFIG_IWLWIFI_DEBUGFS */
static const struct iwl_trans_ops trans_ops_pcie = {
@@ -2083,7 +2074,7 @@ struct iwl_trans *iwl_trans_pcie_alloc(struct pci_dev *pdev,
int err;
trans = kzalloc(sizeof(struct iwl_trans) +
- sizeof(struct iwl_trans_pcie), GFP_KERNEL);
+ sizeof(struct iwl_trans_pcie), GFP_KERNEL);
if (WARN_ON(!trans))
return NULL;
@@ -2099,7 +2090,7 @@ struct iwl_trans *iwl_trans_pcie_alloc(struct pci_dev *pdev,
/* W/A - seems to solve weird behavior. We need to remove this if we
* don't want to stay in L1 all the time. This wastes a lot of power */
pci_disable_link_state(pdev, PCIE_LINK_STATE_L0S | PCIE_LINK_STATE_L1 |
- PCIE_LINK_STATE_CLKPM);
+ PCIE_LINK_STATE_CLKPM);
if (pci_enable_device(pdev)) {
err = -ENODEV;
@@ -2115,7 +2106,7 @@ struct iwl_trans *iwl_trans_pcie_alloc(struct pci_dev *pdev,
err = pci_set_dma_mask(pdev, DMA_BIT_MASK(32));
if (!err)
err = pci_set_consistent_dma_mask(pdev,
- DMA_BIT_MASK(32));
+ DMA_BIT_MASK(32));
/* both attempts failed: */
if (err) {
dev_printk(KERN_ERR, &pdev->dev,
@@ -2138,13 +2129,13 @@ struct iwl_trans *iwl_trans_pcie_alloc(struct pci_dev *pdev,
}
dev_printk(KERN_INFO, &pdev->dev,
- "pci_resource_len = 0x%08llx\n",
- (unsigned long long) pci_resource_len(pdev, 0));
+ "pci_resource_len = 0x%08llx\n",
+ (unsigned long long) pci_resource_len(pdev, 0));
dev_printk(KERN_INFO, &pdev->dev,
- "pci_resource_base = %p\n", trans_pcie->hw_base);
+ "pci_resource_base = %p\n", trans_pcie->hw_base);
dev_printk(KERN_INFO, &pdev->dev,
- "HW Revision ID = 0x%X\n", pdev->revision);
+ "HW Revision ID = 0x%X\n", pdev->revision);
/* We disable the RETRY_TIMEOUT register (0x41) to keep
* PCI Tx retries from interfering with C3 CPU state */
@@ -2153,7 +2144,7 @@ struct iwl_trans *iwl_trans_pcie_alloc(struct pci_dev *pdev,
err = pci_enable_msi(pdev);
if (err)
dev_printk(KERN_ERR, &pdev->dev,
- "pci_enable_msi failed(0X%x)", err);
+ "pci_enable_msi failed(0X%x)", err);
trans->dev = &pdev->dev;
trans_pcie->irq = pdev->irq;
@@ -2185,4 +2176,3 @@ out_no_pci:
kfree(trans);
return NULL;
}
-
diff --git a/drivers/net/wireless/iwlwifi/iwl-trans.h b/drivers/net/wireless/iwlwifi/iwl-trans.h
index 79a1e7ae499..0aeeb7ce91c 100644
--- a/drivers/net/wireless/iwlwifi/iwl-trans.h
+++ b/drivers/net/wireless/iwlwifi/iwl-trans.h
@@ -154,6 +154,9 @@ struct iwl_cmd_header {
__le16 sequence;
} __packed;
+/* iwl_cmd_header flags value */
+#define IWL_CMD_FAILED_MSK 0x40
+
#define FH_RSCSR_FRAME_SIZE_MSK 0x00003FFF /* bits 0-13 */
#define FH_RSCSR_FRAME_INVALID 0x55550000
@@ -280,6 +283,8 @@ static inline struct page *rxb_steal_page(struct iwl_rx_cmd_buffer *r)
#define MAX_NO_RECLAIM_CMDS 6
+#define IWL_MASK(lo, hi) ((1 << (hi)) | ((1 << (hi)) - (1 << (lo))))
+
/*
* Maximum number of HW queues the transport layer
* currently supports
diff --git a/drivers/net/wireless/libertas/cfg.c b/drivers/net/wireless/libertas/cfg.c
index 2fa879b015b..f4a203049fb 100644
--- a/drivers/net/wireless/libertas/cfg.c
+++ b/drivers/net/wireless/libertas/cfg.c
@@ -435,24 +435,40 @@ static int lbs_add_wpa_tlv(u8 *tlv, const u8 *ie, u8 ie_len)
* Set Channel
*/
-static int lbs_cfg_set_channel(struct wiphy *wiphy,
- struct net_device *netdev,
- struct ieee80211_channel *channel,
- enum nl80211_channel_type channel_type)
+static int lbs_cfg_set_monitor_channel(struct wiphy *wiphy,
+ struct ieee80211_channel *channel,
+ enum nl80211_channel_type channel_type)
{
struct lbs_private *priv = wiphy_priv(wiphy);
int ret = -ENOTSUPP;
- lbs_deb_enter_args(LBS_DEB_CFG80211, "iface %s freq %d, type %d",
- netdev_name(netdev), channel->center_freq, channel_type);
+ lbs_deb_enter_args(LBS_DEB_CFG80211, "freq %d, type %d",
+ channel->center_freq, channel_type);
if (channel_type != NL80211_CHAN_NO_HT)
goto out;
- if (netdev == priv->mesh_dev)
- ret = lbs_mesh_set_channel(priv, channel->hw_value);
- else
- ret = lbs_set_channel(priv, channel->hw_value);
+ ret = lbs_set_channel(priv, channel->hw_value);
+
+ out:
+ lbs_deb_leave_args(LBS_DEB_CFG80211, "ret %d", ret);
+ return ret;
+}
+
+static int lbs_cfg_set_mesh_channel(struct wiphy *wiphy,
+ struct net_device *netdev,
+ struct ieee80211_channel *channel)
+{
+ struct lbs_private *priv = wiphy_priv(wiphy);
+ int ret = -ENOTSUPP;
+
+ lbs_deb_enter_args(LBS_DEB_CFG80211, "iface %s freq %d",
+ netdev_name(netdev), channel->center_freq);
+
+ if (netdev != priv->mesh_dev)
+ goto out;
+
+ ret = lbs_mesh_set_channel(priv, channel->hw_value);
out:
lbs_deb_leave_args(LBS_DEB_CFG80211, "ret %d", ret);
@@ -2029,7 +2045,8 @@ static int lbs_leave_ibss(struct wiphy *wiphy, struct net_device *dev)
*/
static struct cfg80211_ops lbs_cfg80211_ops = {
- .set_channel = lbs_cfg_set_channel,
+ .set_monitor_channel = lbs_cfg_set_monitor_channel,
+ .libertas_set_mesh_channel = lbs_cfg_set_mesh_channel,
.scan = lbs_cfg_scan,
.connect = lbs_cfg_connect,
.disconnect = lbs_cfg_disconnect,
diff --git a/drivers/net/wireless/libertas/dev.h b/drivers/net/wireless/libertas/dev.h
index 672005430ac..60996ce89f7 100644
--- a/drivers/net/wireless/libertas/dev.h
+++ b/drivers/net/wireless/libertas/dev.h
@@ -58,6 +58,7 @@ struct lbs_private {
uint16_t mesh_tlv;
u8 mesh_ssid[IEEE80211_MAX_SSID_LEN + 1];
u8 mesh_ssid_len;
+ u8 mesh_channel;
#endif
/* Debugfs */
diff --git a/drivers/net/wireless/libertas/mesh.c b/drivers/net/wireless/libertas/mesh.c
index e87c031b298..97807751ebc 100644
--- a/drivers/net/wireless/libertas/mesh.c
+++ b/drivers/net/wireless/libertas/mesh.c
@@ -131,16 +131,13 @@ static int lbs_mesh_config(struct lbs_private *priv, uint16_t action,
int lbs_mesh_set_channel(struct lbs_private *priv, u8 channel)
{
+ priv->mesh_channel = channel;
return lbs_mesh_config(priv, CMD_ACT_MESH_CONFIG_START, channel);
}
static uint16_t lbs_mesh_get_channel(struct lbs_private *priv)
{
- struct wireless_dev *mesh_wdev = priv->mesh_dev->ieee80211_ptr;
- if (mesh_wdev->channel)
- return mesh_wdev->channel->hw_value;
- else
- return 1;
+ return priv->mesh_channel ?: 1;
}
/***************************************************************************
diff --git a/drivers/net/wireless/mac80211_hwsim.c b/drivers/net/wireless/mac80211_hwsim.c
index fb787df0166..4c9336cee81 100644
--- a/drivers/net/wireless/mac80211_hwsim.c
+++ b/drivers/net/wireless/mac80211_hwsim.c
@@ -1721,6 +1721,24 @@ static void hwsim_exit_netlink(void)
"unregister family %i\n", ret);
}
+static const struct ieee80211_iface_limit hwsim_if_limits[] = {
+ { .max = 1, .types = BIT(NL80211_IFTYPE_ADHOC) },
+ { .max = 2048, .types = BIT(NL80211_IFTYPE_STATION) |
+ BIT(NL80211_IFTYPE_P2P_CLIENT) |
+#ifdef CONFIG_MAC80211_MESH
+ BIT(NL80211_IFTYPE_MESH_POINT) |
+#endif
+ BIT(NL80211_IFTYPE_AP) |
+ BIT(NL80211_IFTYPE_P2P_GO) },
+};
+
+static const struct ieee80211_iface_combination hwsim_if_comb = {
+ .limits = hwsim_if_limits,
+ .n_limits = ARRAY_SIZE(hwsim_if_limits),
+ .max_interfaces = 2048,
+ .num_different_channels = 1,
+};
+
static int __init init_mac80211_hwsim(void)
{
int i, err = 0;
@@ -1782,6 +1800,9 @@ static int __init init_mac80211_hwsim(void)
hw->wiphy->n_addresses = 2;
hw->wiphy->addresses = data->addresses;
+ hw->wiphy->iface_combinations = &hwsim_if_comb;
+ hw->wiphy->n_iface_combinations = 1;
+
if (fake_hw_scan) {
hw->wiphy->max_scan_ssids = 255;
hw->wiphy->max_scan_ie_len = IEEE80211_MAX_DATA_LEN;
diff --git a/drivers/net/wireless/mwifiex/cfg80211.c b/drivers/net/wireless/mwifiex/cfg80211.c
index 87671446e24..015fec3371a 100644
--- a/drivers/net/wireless/mwifiex/cfg80211.c
+++ b/drivers/net/wireless/mwifiex/cfg80211.c
@@ -948,6 +948,19 @@ static int mwifiex_cfg80211_start_ap(struct wiphy *wiphy,
bss_cfg->ssid.ssid_len = params->ssid_len;
}
+ switch (params->hidden_ssid) {
+ case NL80211_HIDDEN_SSID_NOT_IN_USE:
+ bss_cfg->bcast_ssid_ctl = 1;
+ break;
+ case NL80211_HIDDEN_SSID_ZERO_LEN:
+ bss_cfg->bcast_ssid_ctl = 0;
+ break;
+ case NL80211_HIDDEN_SSID_ZERO_CONTENTS:
+ /* firmware doesn't support this type of hidden SSID */
+ default:
+ return -EINVAL;
+ }
+
if (mwifiex_set_secure_params(priv, bss_cfg, params)) {
kfree(bss_cfg);
wiphy_err(wiphy, "Failed to parse secuirty parameters!\n");
diff --git a/drivers/net/wireless/mwifiex/fw.h b/drivers/net/wireless/mwifiex/fw.h
index 9f674bbebe6..561452a5c81 100644
--- a/drivers/net/wireless/mwifiex/fw.h
+++ b/drivers/net/wireless/mwifiex/fw.h
@@ -122,6 +122,7 @@ enum MWIFIEX_802_11_PRIVACY_FILTER {
#define TLV_TYPE_CHANNELBANDLIST (PROPRIETARY_TLV_BASE_ID + 42)
#define TLV_TYPE_UAP_BEACON_PERIOD (PROPRIETARY_TLV_BASE_ID + 44)
#define TLV_TYPE_UAP_DTIM_PERIOD (PROPRIETARY_TLV_BASE_ID + 45)
+#define TLV_TYPE_UAP_BCAST_SSID (PROPRIETARY_TLV_BASE_ID + 48)
#define TLV_TYPE_UAP_RTS_THRESHOLD (PROPRIETARY_TLV_BASE_ID + 51)
#define TLV_TYPE_UAP_WPA_PASSPHRASE (PROPRIETARY_TLV_BASE_ID + 60)
#define TLV_TYPE_UAP_ENCRY_PROTOCOL (PROPRIETARY_TLV_BASE_ID + 64)
@@ -1209,6 +1210,11 @@ struct host_cmd_tlv_ssid {
u8 ssid[0];
} __packed;
+struct host_cmd_tlv_bcast_ssid {
+ struct host_cmd_tlv tlv;
+ u8 bcast_ctl;
+} __packed;
+
struct host_cmd_tlv_beacon_period {
struct host_cmd_tlv tlv;
__le16 period;
diff --git a/drivers/net/wireless/mwifiex/uap_cmd.c b/drivers/net/wireless/mwifiex/uap_cmd.c
index 76dfbc42a73..8173ab66066 100644
--- a/drivers/net/wireless/mwifiex/uap_cmd.c
+++ b/drivers/net/wireless/mwifiex/uap_cmd.c
@@ -132,6 +132,7 @@ mwifiex_uap_bss_param_prepare(u8 *tlv, void *cmd_buf, u16 *param_size)
struct host_cmd_tlv_dtim_period *dtim_period;
struct host_cmd_tlv_beacon_period *beacon_period;
struct host_cmd_tlv_ssid *ssid;
+ struct host_cmd_tlv_bcast_ssid *bcast_ssid;
struct host_cmd_tlv_channel_band *chan_band;
struct host_cmd_tlv_frag_threshold *frag_threshold;
struct host_cmd_tlv_rts_threshold *rts_threshold;
@@ -153,6 +154,14 @@ mwifiex_uap_bss_param_prepare(u8 *tlv, void *cmd_buf, u16 *param_size)
cmd_size += sizeof(struct host_cmd_tlv) +
bss_cfg->ssid.ssid_len;
tlv += sizeof(struct host_cmd_tlv) + bss_cfg->ssid.ssid_len;
+
+ bcast_ssid = (struct host_cmd_tlv_bcast_ssid *)tlv;
+ bcast_ssid->tlv.type = cpu_to_le16(TLV_TYPE_UAP_BCAST_SSID);
+ bcast_ssid->tlv.len =
+ cpu_to_le16(sizeof(bcast_ssid->bcast_ctl));
+ bcast_ssid->bcast_ctl = bss_cfg->bcast_ssid_ctl;
+ cmd_size += sizeof(struct host_cmd_tlv_bcast_ssid);
+ tlv += sizeof(struct host_cmd_tlv_bcast_ssid);
}
if (bss_cfg->channel && bss_cfg->channel <= MAX_CHANNEL_BAND_BG) {
chan_band = (struct host_cmd_tlv_channel_band *)tlv;
@@ -416,6 +425,7 @@ int mwifiex_uap_set_channel(struct mwifiex_private *priv, int channel)
if (!bss_cfg)
return -ENOMEM;
+ mwifiex_set_sys_config_invalid_data(bss_cfg);
bss_cfg->band_cfg = BAND_CONFIG_MANUAL;
bss_cfg->channel = channel;
diff --git a/drivers/net/wireless/orinoco/cfg.c b/drivers/net/wireless/orinoco/cfg.c
index f7b15b8934f..e15675585fb 100644
--- a/drivers/net/wireless/orinoco/cfg.c
+++ b/drivers/net/wireless/orinoco/cfg.c
@@ -160,10 +160,9 @@ static int orinoco_scan(struct wiphy *wiphy, struct net_device *dev,
return err;
}
-static int orinoco_set_channel(struct wiphy *wiphy,
- struct net_device *netdev,
- struct ieee80211_channel *chan,
- enum nl80211_channel_type channel_type)
+static int orinoco_set_monitor_channel(struct wiphy *wiphy,
+ struct ieee80211_channel *chan,
+ enum nl80211_channel_type channel_type)
{
struct orinoco_private *priv = wiphy_priv(wiphy);
int err = 0;
@@ -286,7 +285,7 @@ static int orinoco_set_wiphy_params(struct wiphy *wiphy, u32 changed)
const struct cfg80211_ops orinoco_cfg_ops = {
.change_virtual_intf = orinoco_change_vif,
- .set_channel = orinoco_set_channel,
+ .set_monitor_channel = orinoco_set_monitor_channel,
.scan = orinoco_scan,
.set_wiphy_params = orinoco_set_wiphy_params,
};
diff --git a/drivers/net/wireless/rt2x00/rt2800.h b/drivers/net/wireless/rt2x00/rt2800.h
index 9348521e083..1ca88cdc6ec 100644
--- a/drivers/net/wireless/rt2x00/rt2800.h
+++ b/drivers/net/wireless/rt2x00/rt2800.h
@@ -51,6 +51,7 @@
* RF3320 2.4G 1T1R(RT3350/RT3370/RT3390)
* RF3322 2.4G 2T2R(RT3352/RT3371/RT3372/RT3391/RT3392)
* RF3053 2.4G/5G 3T3R(RT3883/RT3563/RT3573/RT3593/RT3662)
+ * RF5360 2.4G 1T1R
* RF5370 2.4G 1T1R
* RF5390 2.4G 1T1R
*/
@@ -67,9 +68,11 @@
#define RF3320 0x000b
#define RF3322 0x000c
#define RF3053 0x000d
+#define RF5360 0x5360
#define RF5370 0x5370
#define RF5372 0x5372
#define RF5390 0x5390
+#define RF5392 0x5392
/*
* Chipset revisions.
@@ -1944,6 +1947,11 @@ struct mac_iveiv_entry {
#define RFCSR49_TX FIELD8(0x3f)
/*
+ * RFCSR 50:
+ */
+#define RFCSR50_TX FIELD8(0x3f)
+
+/*
* RF registers
*/
diff --git a/drivers/net/wireless/rt2x00/rt2800lib.c b/drivers/net/wireless/rt2x00/rt2800lib.c
index dfc90d34be6..4d3747c3010 100644
--- a/drivers/net/wireless/rt2x00/rt2800lib.c
+++ b/drivers/net/wireless/rt2x00/rt2800lib.c
@@ -1958,7 +1958,22 @@ static void rt2800_config_channel_rf53xx(struct rt2x00_dev *rt2x00dev,
rt2x00_set_field8(&rfcsr, RFCSR49_TX, info->default_power1);
rt2800_rfcsr_write(rt2x00dev, 49, rfcsr);
+ if (rt2x00_rt(rt2x00dev, RT5392)) {
+ rt2800_rfcsr_read(rt2x00dev, 50, &rfcsr);
+ if (info->default_power1 > RT5390_POWER_BOUND)
+ rt2x00_set_field8(&rfcsr, RFCSR50_TX,
+ RT5390_POWER_BOUND);
+ else
+ rt2x00_set_field8(&rfcsr, RFCSR50_TX,
+ info->default_power2);
+ rt2800_rfcsr_write(rt2x00dev, 50, rfcsr);
+ }
+
rt2800_rfcsr_read(rt2x00dev, 1, &rfcsr);
+ if (rt2x00_rt(rt2x00dev, RT5392)) {
+ rt2x00_set_field8(&rfcsr, RFCSR1_RX1_PD, 1);
+ rt2x00_set_field8(&rfcsr, RFCSR1_TX1_PD, 1);
+ }
rt2x00_set_field8(&rfcsr, RFCSR1_RF_BLOCK_EN, 1);
rt2x00_set_field8(&rfcsr, RFCSR1_PLL_PD, 1);
rt2x00_set_field8(&rfcsr, RFCSR1_RX0_PD, 1);
@@ -2060,9 +2075,11 @@ static void rt2800_config_channel(struct rt2x00_dev *rt2x00dev,
case RF3052:
rt2800_config_channel_rf3052(rt2x00dev, conf, rf, info);
break;
+ case RF5360:
case RF5370:
case RF5372:
case RF5390:
+ case RF5392:
rt2800_config_channel_rf53xx(rt2x00dev, conf, rf, info);
break;
default:
@@ -2549,9 +2566,11 @@ void rt2800_vco_calibration(struct rt2x00_dev *rt2x00dev)
rt2x00_set_field8(&rfcsr, RFCSR7_RF_TUNING, 1);
rt2800_rfcsr_write(rt2x00dev, 7, rfcsr);
break;
+ case RF5360:
case RF5370:
case RF5372:
case RF5390:
+ case RF5392:
rt2800_rfcsr_read(rt2x00dev, 3, &rfcsr);
rt2x00_set_field8(&rfcsr, RFCSR30_RF_CALIBRATION, 1);
rt2800_rfcsr_write(rt2x00dev, 3, rfcsr);
@@ -4263,9 +4282,11 @@ int rt2800_init_eeprom(struct rt2x00_dev *rt2x00dev)
case RF3022:
case RF3052:
case RF3320:
+ case RF5360:
case RF5370:
case RF5372:
case RF5390:
+ case RF5392:
break;
default:
ERROR(rt2x00dev, "Invalid RF chipset 0x%04x detected.\n",
@@ -4577,9 +4598,11 @@ int rt2800_probe_hw_mode(struct rt2x00_dev *rt2x00dev)
rt2x00_rf(rt2x00dev, RF3021) ||
rt2x00_rf(rt2x00dev, RF3022) ||
rt2x00_rf(rt2x00dev, RF3320) ||
+ rt2x00_rf(rt2x00dev, RF5360) ||
rt2x00_rf(rt2x00dev, RF5370) ||
rt2x00_rf(rt2x00dev, RF5372) ||
- rt2x00_rf(rt2x00dev, RF5390)) {
+ rt2x00_rf(rt2x00dev, RF5390) ||
+ rt2x00_rf(rt2x00dev, RF5392)) {
spec->num_channels = 14;
spec->channels = rf_vals_3x;
} else if (rt2x00_rf(rt2x00dev, RF3052)) {
@@ -4662,9 +4685,11 @@ int rt2800_probe_hw_mode(struct rt2x00_dev *rt2x00dev)
case RF3022:
case RF3320:
case RF3052:
+ case RF5360:
case RF5370:
case RF5372:
case RF5390:
+ case RF5392:
__set_bit(CAPABILITY_VCO_RECALIBRATION, &rt2x00dev->cap_flags);
break;
}
diff --git a/drivers/net/wireless/rt2x00/rt2800pci.c b/drivers/net/wireless/rt2x00/rt2800pci.c
index cad25bfebd7..206158b6742 100644
--- a/drivers/net/wireless/rt2x00/rt2800pci.c
+++ b/drivers/net/wireless/rt2x00/rt2800pci.c
@@ -1188,6 +1188,7 @@ static DEFINE_PCI_DEVICE_TABLE(rt2800pci_device_table) = {
{ PCI_DEVICE(0x1814, 0x3593) },
#endif
#ifdef CONFIG_RT2800PCI_RT53XX
+ { PCI_DEVICE(0x1814, 0x5360) },
{ PCI_DEVICE(0x1814, 0x5362) },
{ PCI_DEVICE(0x1814, 0x5390) },
{ PCI_DEVICE(0x1814, 0x5392) },
diff --git a/drivers/net/wireless/rt2x00/rt2800usb.c b/drivers/net/wireless/rt2x00/rt2800usb.c
index bf78317a6ad..20a50407289 100644
--- a/drivers/net/wireless/rt2x00/rt2800usb.c
+++ b/drivers/net/wireless/rt2x00/rt2800usb.c
@@ -1137,6 +1137,8 @@ static struct usb_device_id rt2800usb_device_table[] = {
#ifdef CONFIG_RT2800USB_RT33XX
/* Belkin */
{ USB_DEVICE(0x050d, 0x945b) },
+ /* D-Link */
+ { USB_DEVICE(0x2001, 0x3c17) },
/* Panasonic */
{ USB_DEVICE(0x083a, 0xb511) },
/* Philips */
@@ -1237,7 +1239,6 @@ static struct usb_device_id rt2800usb_device_table[] = {
/* D-Link */
{ USB_DEVICE(0x07d1, 0x3c0b) },
{ USB_DEVICE(0x07d1, 0x3c17) },
- { USB_DEVICE(0x2001, 0x3c17) },
/* Encore */
{ USB_DEVICE(0x203d, 0x14a1) },
/* Gemtek */
diff --git a/drivers/net/wireless/rt2x00/rt2x00.h b/drivers/net/wireless/rt2x00/rt2x00.h
index ca36cccaba3..8f754025b06 100644
--- a/drivers/net/wireless/rt2x00/rt2x00.h
+++ b/drivers/net/wireless/rt2x00/rt2x00.h
@@ -396,8 +396,7 @@ struct rt2x00_intf {
* for hardware which doesn't support hardware
* sequence counting.
*/
- spinlock_t seqlock;
- u16 seqno;
+ atomic_t seqno;
};
static inline struct rt2x00_intf* vif_to_intf(struct ieee80211_vif *vif)
diff --git a/drivers/net/wireless/rt2x00/rt2x00dev.c b/drivers/net/wireless/rt2x00/rt2x00dev.c
index e5404e57625..a6b88bd4a1a 100644
--- a/drivers/net/wireless/rt2x00/rt2x00dev.c
+++ b/drivers/net/wireless/rt2x00/rt2x00dev.c
@@ -1161,6 +1161,8 @@ int rt2x00lib_probe_dev(struct rt2x00_dev *rt2x00dev)
BIT(NL80211_IFTYPE_MESH_POINT) |
BIT(NL80211_IFTYPE_WDS);
+ rt2x00dev->hw->wiphy->flags |= WIPHY_FLAG_IBSS_RSN;
+
/*
* Initialize work.
*/
diff --git a/drivers/net/wireless/rt2x00/rt2x00mac.c b/drivers/net/wireless/rt2x00/rt2x00mac.c
index b49773ef72f..4ff26c2159b 100644
--- a/drivers/net/wireless/rt2x00/rt2x00mac.c
+++ b/drivers/net/wireless/rt2x00/rt2x00mac.c
@@ -277,7 +277,6 @@ int rt2x00mac_add_interface(struct ieee80211_hw *hw,
else
rt2x00dev->intf_sta_count++;
- spin_lock_init(&intf->seqlock);
mutex_init(&intf->beacon_skb_mutex);
intf->beacon = entry;
@@ -507,9 +506,19 @@ int rt2x00mac_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd,
if (!test_bit(DEVICE_STATE_PRESENT, &rt2x00dev->flags))
return 0;
- else if (!test_bit(CAPABILITY_HW_CRYPTO, &rt2x00dev->cap_flags))
+
+ if (!test_bit(CAPABILITY_HW_CRYPTO, &rt2x00dev->cap_flags))
+ return -EOPNOTSUPP;
+
+ /*
+ * To support IBSS RSN, don't program group keys in IBSS, the
+ * hardware will then not attempt to decrypt the frames.
+ */
+ if (vif->type == NL80211_IFTYPE_ADHOC &&
+ !(key->flags & IEEE80211_KEY_FLAG_PAIRWISE))
return -EOPNOTSUPP;
- else if (key->keylen > 32)
+
+ if (key->keylen > 32)
return -ENOSPC;
memset(&crypto, 0, sizeof(crypto));
diff --git a/drivers/net/wireless/rt2x00/rt2x00queue.c b/drivers/net/wireless/rt2x00/rt2x00queue.c
index 4c662eccf53..2fd83010341 100644
--- a/drivers/net/wireless/rt2x00/rt2x00queue.c
+++ b/drivers/net/wireless/rt2x00/rt2x00queue.c
@@ -207,6 +207,7 @@ static void rt2x00queue_create_tx_descriptor_seq(struct rt2x00_dev *rt2x00dev,
struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb);
struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data;
struct rt2x00_intf *intf = vif_to_intf(tx_info->control.vif);
+ u16 seqno;
if (!(tx_info->flags & IEEE80211_TX_CTL_ASSIGN_SEQ))
return;
@@ -238,15 +239,13 @@ static void rt2x00queue_create_tx_descriptor_seq(struct rt2x00_dev *rt2x00dev,
* sequence counting per-frame, since those will override the
* sequence counter given by mac80211.
*/
- spin_lock(&intf->seqlock);
-
if (test_bit(ENTRY_TXD_FIRST_FRAGMENT, &txdesc->flags))
- intf->seqno += 0x10;
- hdr->seq_ctrl &= cpu_to_le16(IEEE80211_SCTL_FRAG);
- hdr->seq_ctrl |= cpu_to_le16(intf->seqno);
-
- spin_unlock(&intf->seqlock);
+ seqno = atomic_add_return(0x10, &intf->seqno);
+ else
+ seqno = atomic_read(&intf->seqno);
+ hdr->seq_ctrl &= cpu_to_le16(IEEE80211_SCTL_FRAG);
+ hdr->seq_ctrl |= cpu_to_le16(seqno);
}
static void rt2x00queue_create_tx_descriptor_plcp(struct rt2x00_dev *rt2x00dev,
diff --git a/drivers/ssb/scan.c b/drivers/ssb/scan.c
index 266c7c5c86d..ab4627cf111 100644
--- a/drivers/ssb/scan.c
+++ b/drivers/ssb/scan.c
@@ -90,6 +90,8 @@ const char *ssb_core_name(u16 coreid)
return "ARM 1176";
case SSB_DEV_ARM_7TDMI:
return "ARM 7TDMI";
+ case SSB_DEV_ARM_CM3:
+ return "ARM Cortex M3";
}
return "UNKNOWN";
}
diff --git a/include/linux/nl80211.h b/include/linux/nl80211.h
index a6959f72745..970afdf5a60 100644
--- a/include/linux/nl80211.h
+++ b/include/linux/nl80211.h
@@ -170,6 +170,8 @@
* %NL80211_ATTR_CIPHER_GROUP, %NL80211_ATTR_WPA_VERSIONS,
* %NL80211_ATTR_AKM_SUITES, %NL80211_ATTR_PRIVACY,
* %NL80211_ATTR_AUTH_TYPE and %NL80211_ATTR_INACTIVITY_TIMEOUT.
+ * The channel to use can be set on the interface or be given using the
+ * %NL80211_ATTR_WIPHY_FREQ and %NL80211_ATTR_WIPHY_CHANNEL_TYPE attrs.
* @NL80211_CMD_NEW_BEACON: old alias for %NL80211_CMD_START_AP
* @NL80211_CMD_STOP_AP: Stop AP operation on the given interface
* @NL80211_CMD_DEL_BEACON: old alias for %NL80211_CMD_STOP_AP
@@ -1520,6 +1522,8 @@ enum nl80211_attrs {
#define NL80211_MAX_NR_CIPHER_SUITES 5
#define NL80211_MAX_NR_AKM_SUITES 2
+#define NL80211_MIN_REMAIN_ON_CHANNEL_TIME 10
+
/**
* enum nl80211_iftype - (virtual) interface types
*
@@ -2534,10 +2538,14 @@ enum nl80211_attr_cqm {
* configured threshold
* @NL80211_CQM_RSSI_THRESHOLD_EVENT_HIGH: The RSSI is higher than the
* configured threshold
+ * @NL80211_CQM_RSSI_BEACON_LOSS_EVENT: The device experienced beacon loss.
+ * (Note that deauth/disassoc will still follow if the AP is not
+ * available. This event might get used as roaming event, etc.)
*/
enum nl80211_cqm_rssi_threshold_event {
NL80211_CQM_RSSI_THRESHOLD_EVENT_LOW,
NL80211_CQM_RSSI_THRESHOLD_EVENT_HIGH,
+ NL80211_CQM_RSSI_BEACON_LOSS_EVENT,
};
diff --git a/include/linux/ssb/ssb.h b/include/linux/ssb/ssb.h
index bc14bd738ad..bb674c02f30 100644
--- a/include/linux/ssb/ssb.h
+++ b/include/linux/ssb/ssb.h
@@ -243,6 +243,7 @@ struct ssb_bus_ops {
#define SSB_DEV_MINI_MACPHY 0x823
#define SSB_DEV_ARM_1176 0x824
#define SSB_DEV_ARM_7TDMI 0x825
+#define SSB_DEV_ARM_CM3 0x82A
/* Vendor-ID values */
#define SSB_VENDOR_BROADCOM 0x4243
diff --git a/include/net/cfg80211.h b/include/net/cfg80211.h
index 0289d4ce707..7319f25250b 100644
--- a/include/net/cfg80211.h
+++ b/include/net/cfg80211.h
@@ -404,6 +404,8 @@ struct cfg80211_beacon_data {
*
* Used to configure an AP interface.
*
+ * @channel: the channel to start the AP on
+ * @channel_type: the channel type to use
* @beacon: beacon data
* @beacon_interval: beacon interval
* @dtim_period: DTIM period
@@ -417,6 +419,9 @@ struct cfg80211_beacon_data {
* @inactivity_timeout: time in seconds to determine station's inactivity.
*/
struct cfg80211_ap_settings {
+ struct ieee80211_channel *channel;
+ enum nl80211_channel_type channel_type;
+
struct cfg80211_beacon_data beacon;
int beacon_interval, dtim_period;
@@ -826,6 +831,8 @@ struct mesh_config {
/**
* struct mesh_setup - 802.11s mesh setup configuration
+ * @channel: the channel to start the mesh network on
+ * @channel_type: the channel type to use
* @mesh_id: the mesh ID
* @mesh_id_len: length of the mesh ID, at least 1 and at most 32 bytes
* @sync_method: which synchronization method to use
@@ -840,6 +847,8 @@ struct mesh_config {
* These parameters are fixed when the mesh is created.
*/
struct mesh_setup {
+ struct ieee80211_channel *channel;
+ enum nl80211_channel_type channel_type;
const u8 *mesh_id;
u8 mesh_id_len;
u8 sync_method;
@@ -1411,11 +1420,14 @@ struct cfg80211_gtk_rekey_data {
*
* @set_txq_params: Set TX queue parameters
*
- * @set_channel: Set channel for a given wireless interface. Some devices
- * may support multi-channel operation (by channel hopping) so cfg80211
- * doesn't verify much. Note, however, that the passed netdev may be
- * %NULL as well if the user requested changing the channel for the
- * device itself, or for a monitor interface.
+ * @libertas_set_mesh_channel: Only for backward compatibility for libertas,
+ * as it doesn't implement join_mesh and needs to set the channel to
+ * join the mesh instead.
+ *
+ * @set_monitor_channel: Set the monitor mode channel for the device. If other
+ * interfaces are active this callback should reject the configuration.
+ * If no interfaces are active or the device is down, the channel should
+ * be stored for when a monitor interface becomes active.
* @get_channel: Get the current operating channel, should return %NULL if
* there's no single defined operating channel if for example the
* device implements channel hopping for multi-channel virtual interfaces.
@@ -1605,9 +1617,13 @@ struct cfg80211_ops {
int (*set_txq_params)(struct wiphy *wiphy, struct net_device *dev,
struct ieee80211_txq_params *params);
- int (*set_channel)(struct wiphy *wiphy, struct net_device *dev,
- struct ieee80211_channel *chan,
- enum nl80211_channel_type channel_type);
+ int (*libertas_set_mesh_channel)(struct wiphy *wiphy,
+ struct net_device *dev,
+ struct ieee80211_channel *chan);
+
+ int (*set_monitor_channel)(struct wiphy *wiphy,
+ struct ieee80211_channel *chan,
+ enum nl80211_channel_type channel_type);
int (*scan)(struct wiphy *wiphy, struct net_device *dev,
struct cfg80211_scan_request *request);
@@ -2263,7 +2279,10 @@ struct cfg80211_cached_keys;
* @netdev: (private) Used to reference back to the netdev
* @current_bss: (private) Used by the internal configuration code
* @channel: (private) Used by the internal configuration code to track
- * user-set AP, monitor and WDS channels for wireless extensions
+ * the user-set AP, monitor and WDS channel
+ * @preset_chan: (private) Used by the internal configuration code to
+ * track the channel to be used for AP later
+ * @preset_chantype: (private) the corresponding channel type
* @bssid: (private) Used by the internal configuration code
* @ssid: (private) Used by the internal configuration code
* @ssid_len: (private) Used by the internal configuration code
@@ -2313,7 +2332,8 @@ struct wireless_dev {
spinlock_t event_lock;
struct cfg80211_internal_bss *current_bss; /* associated / joined */
- struct ieee80211_channel *channel;
+ struct ieee80211_channel *preset_chan;
+ enum nl80211_channel_type preset_chantype;
bool ps;
int ps_timeout;
@@ -3359,11 +3379,14 @@ void cfg80211_report_obss_beacon(struct wiphy *wiphy,
const u8 *frame, size_t len,
int freq, int sig_dbm, gfp_t gfp);
-/*
+/**
* cfg80211_can_beacon_sec_chan - test if ht40 on extension channel can be used
* @wiphy: the wiphy
* @chan: main channel
* @channel_type: HT mode
+ *
+ * This function returns true if there is no secondary channel or the secondary
+ * channel can be used for beaconing (i.e. is not a radar channel etc.)
*/
bool cfg80211_can_beacon_sec_chan(struct wiphy *wiphy,
struct ieee80211_channel *chan,
diff --git a/include/net/mac80211.h b/include/net/mac80211.h
index 1937c7d9830..d152f54064f 100644
--- a/include/net/mac80211.h
+++ b/include/net/mac80211.h
@@ -1297,6 +1297,10 @@ enum ieee80211_hw_flags {
* reports, by default it is set to _MCS, _GI and _BW but doesn't
* include _FMT. Use %IEEE80211_RADIOTAP_MCS_HAVE_* values, only
* adding _BW is supported today.
+ *
+ * @netdev_features: netdev features to be set in each netdev created
+ * from this HW. Note only HW checksum features are currently
+ * compatible with mac80211. Other feature bits will be rejected.
*/
struct ieee80211_hw {
struct ieee80211_conf conf;
@@ -1319,6 +1323,7 @@ struct ieee80211_hw {
u8 max_tx_aggregation_subframes;
u8 offchannel_tx_hw_queue;
u8 radiotap_mcs_details;
+ netdev_features_t netdev_features;
};
/**
@@ -2178,7 +2183,10 @@ enum ieee80211_rate_control_changed {
* offload. Frames to transmit on the off-channel channel are transmitted
* normally except for the %IEEE80211_TX_CTL_TX_OFFCHAN flag. When the
* duration (which will always be non-zero) expires, the driver must call
- * ieee80211_remain_on_channel_expired(). This callback may sleep.
+ * ieee80211_remain_on_channel_expired().
+ * Note that this callback may be called while the device is in IDLE and
+ * must be accepted in this case.
+ * This callback may sleep.
* @cancel_remain_on_channel: Requests that an ongoing off-channel period is
* aborted before it expires. This callback may sleep.
*
@@ -3551,16 +3559,6 @@ void ieee80211_cqm_rssi_notify(struct ieee80211_vif *vif,
gfp_t gfp);
/**
- * ieee80211_get_operstate - get the operstate of the vif
- *
- * @vif: &struct ieee80211_vif pointer from the add_interface callback.
- *
- * The driver might need to know the operstate of the net_device
- * (specifically, whether the link is IF_OPER_UP after resume)
- */
-unsigned char ieee80211_get_operstate(struct ieee80211_vif *vif);
-
-/**
* ieee80211_chswitch_done - Complete channel switch process
* @vif: &struct ieee80211_vif pointer from the add_interface callback.
* @success: make the channel switch successful or not
@@ -3839,4 +3837,28 @@ int ieee80211_add_ext_srates_ie(struct ieee80211_vif *vif,
*/
int ieee80211_ave_rssi(struct ieee80211_vif *vif);
+/* Extra debugging macros */
+
+#ifdef CONFIG_MAC80211_HT_DEBUG
+#define ht_vdbg(fmt, ...) \
+ pr_debug(fmt, ##__VA_ARGS__)
+#else
+#define ht_vdbg(fmt, ...) \
+do { \
+ if (0) \
+ pr_debug(fmt, ##__VA_ARGS__); \
+} while (0)
+#endif
+
+#ifdef CONFIG_MAC80211_IBSS_DEBUG
+#define ibss_vdbg(fmt, ...) \
+ pr_debug(fmt, ##__VA_ARGS__)
+#else
+#define ibss_vdbg(fmt, ...) \
+do { \
+ if (0) \
+ pr_debug(fmt, ##__VA_ARGS__); \
+} while (0)
+#endif
+
#endif /* MAC80211_H */
diff --git a/net/bluetooth/af_bluetooth.c b/net/bluetooth/af_bluetooth.c
index 46e7f86acfc..3e18af4dadc 100644
--- a/net/bluetooth/af_bluetooth.c
+++ b/net/bluetooth/af_bluetooth.c
@@ -210,7 +210,7 @@ struct sock *bt_accept_dequeue(struct sock *parent, struct socket *newsock)
}
if (sk->sk_state == BT_CONNECTED || !newsock ||
- test_bit(BT_DEFER_SETUP, &bt_sk(parent)->flags)) {
+ test_bit(BT_SK_DEFER_SETUP, &bt_sk(parent)->flags)) {
bt_accept_unlink(sk);
if (newsock)
sock_graft(sk, newsock);
diff --git a/net/core/net-sysfs.c b/net/core/net-sysfs.c
index fdf9e61d065..72607174ea5 100644
--- a/net/core/net-sysfs.c
+++ b/net/core/net-sysfs.c
@@ -417,72 +417,6 @@ static struct attribute_group netstat_group = {
.name = "statistics",
.attrs = netstat_attrs,
};
-
-#ifdef CONFIG_WIRELESS_EXT_SYSFS
-/* helper function that does all the locking etc for wireless stats */
-static ssize_t wireless_show(struct device *d, char *buf,
- ssize_t (*format)(const struct iw_statistics *,
- char *))
-{
- struct net_device *dev = to_net_dev(d);
- const struct iw_statistics *iw;
- ssize_t ret = -EINVAL;
-
- if (!rtnl_trylock())
- return restart_syscall();
- if (dev_isalive(dev)) {
- iw = get_wireless_stats(dev);
- if (iw)
- ret = (*format)(iw, buf);
- }
- rtnl_unlock();
-
- return ret;
-}
-
-/* show function template for wireless fields */
-#define WIRELESS_SHOW(name, field, format_string) \
-static ssize_t format_iw_##name(const struct iw_statistics *iw, char *buf) \
-{ \
- return sprintf(buf, format_string, iw->field); \
-} \
-static ssize_t show_iw_##name(struct device *d, \
- struct device_attribute *attr, char *buf) \
-{ \
- return wireless_show(d, buf, format_iw_##name); \
-} \
-static DEVICE_ATTR(name, S_IRUGO, show_iw_##name, NULL)
-
-WIRELESS_SHOW(status, status, fmt_hex);
-WIRELESS_SHOW(link, qual.qual, fmt_dec);
-WIRELESS_SHOW(level, qual.level, fmt_dec);
-WIRELESS_SHOW(noise, qual.noise, fmt_dec);
-WIRELESS_SHOW(nwid, discard.nwid, fmt_dec);
-WIRELESS_SHOW(crypt, discard.code, fmt_dec);
-WIRELESS_SHOW(fragment, discard.fragment, fmt_dec);
-WIRELESS_SHOW(misc, discard.misc, fmt_dec);
-WIRELESS_SHOW(retries, discard.retries, fmt_dec);
-WIRELESS_SHOW(beacon, miss.beacon, fmt_dec);
-
-static struct attribute *wireless_attrs[] = {
- &dev_attr_status.attr,
- &dev_attr_link.attr,
- &dev_attr_level.attr,
- &dev_attr_noise.attr,
- &dev_attr_nwid.attr,
- &dev_attr_crypt.attr,
- &dev_attr_fragment.attr,
- &dev_attr_retries.attr,
- &dev_attr_misc.attr,
- &dev_attr_beacon.attr,
- NULL
-};
-
-static struct attribute_group wireless_group = {
- .name = "wireless",
- .attrs = wireless_attrs,
-};
-#endif
#endif /* CONFIG_SYSFS */
#ifdef CONFIG_RPS
@@ -1463,14 +1397,6 @@ int netdev_register_kobject(struct net_device *net)
groups++;
*groups++ = &netstat_group;
-#ifdef CONFIG_WIRELESS_EXT_SYSFS
- if (net->ieee80211_ptr)
- *groups++ = &wireless_group;
-#ifdef CONFIG_WIRELESS_EXT
- else if (net->wireless_handlers)
- *groups++ = &wireless_group;
-#endif
-#endif
#endif /* CONFIG_SYSFS */
error = device_add(dev);
diff --git a/net/mac80211/Makefile b/net/mac80211/Makefile
index 3e9d931bba3..2b1470bac17 100644
--- a/net/mac80211/Makefile
+++ b/net/mac80211/Makefile
@@ -9,7 +9,6 @@ mac80211-y := \
scan.o offchannel.o \
ht.o agg-tx.o agg-rx.o \
ibss.o \
- work.o \
iface.o \
rate.o \
michael.o \
diff --git a/net/mac80211/agg-rx.c b/net/mac80211/agg-rx.c
index 26ddb699d69..32ef11d6979 100644
--- a/net/mac80211/agg-rx.c
+++ b/net/mac80211/agg-rx.c
@@ -74,18 +74,15 @@ void ___ieee80211_stop_rx_ba_session(struct sta_info *sta, u16 tid,
RCU_INIT_POINTER(sta->ampdu_mlme.tid_rx[tid], NULL);
-#ifdef CONFIG_MAC80211_HT_DEBUG
- printk(KERN_DEBUG
- "Rx BA session stop requested for %pM tid %u %s reason: %d\n",
- sta->sta.addr, tid,
- initiator == WLAN_BACK_RECIPIENT ? "recipient" : "inititator",
- (int)reason);
-#endif /* CONFIG_MAC80211_HT_DEBUG */
+ ht_vdbg("Rx BA session stop requested for %pM tid %u %s reason: %d\n",
+ sta->sta.addr, tid,
+ initiator == WLAN_BACK_RECIPIENT ? "recipient" : "inititator",
+ (int)reason);
if (drv_ampdu_action(local, sta->sdata, IEEE80211_AMPDU_RX_STOP,
&sta->sta, tid, NULL, 0))
- printk(KERN_DEBUG "HW problem - can not stop rx "
- "aggregation for tid %d\n", tid);
+ pr_debug("HW problem - can not stop rx aggregation for tid %d\n",
+ tid);
/* check if this is a self generated aggregation halt */
if (initiator == WLAN_BACK_RECIPIENT && tx)
@@ -145,19 +142,23 @@ static void sta_rx_agg_session_timer_expired(unsigned long data)
struct tid_ampdu_rx *tid_rx;
unsigned long timeout;
+ rcu_read_lock();
tid_rx = rcu_dereference(sta->ampdu_mlme.tid_rx[*ptid]);
- if (!tid_rx)
+ if (!tid_rx) {
+ rcu_read_unlock();
return;
+ }
timeout = tid_rx->last_rx + TU_TO_JIFFIES(tid_rx->timeout);
if (time_is_after_jiffies(timeout)) {
mod_timer(&tid_rx->session_timer, timeout);
+ rcu_read_unlock();
return;
}
+ rcu_read_unlock();
+
+ ht_vdbg("rx session timer expired on tid %d\n", (u16)*ptid);
-#ifdef CONFIG_MAC80211_HT_DEBUG
- printk(KERN_DEBUG "rx session timer expired on tid %d\n", (u16)*ptid);
-#endif
set_bit(*ptid, sta->ampdu_mlme.tid_rx_timer_expired);
ieee80211_queue_work(&sta->local->hw, &sta->ampdu_mlme.work);
}
@@ -244,10 +245,7 @@ void ieee80211_process_addba_request(struct ieee80211_local *local,
status = WLAN_STATUS_REQUEST_DECLINED;
if (test_sta_flag(sta, WLAN_STA_BLOCK_BA)) {
-#ifdef CONFIG_MAC80211_HT_DEBUG
- printk(KERN_DEBUG "Suspend in progress. "
- "Denying ADDBA request\n");
-#endif
+ ht_vdbg("Suspend in progress - Denying ADDBA request\n");
goto end_no_lock;
}
@@ -319,10 +317,7 @@ void ieee80211_process_addba_request(struct ieee80211_local *local,
ret = drv_ampdu_action(local, sta->sdata, IEEE80211_AMPDU_RX_START,
&sta->sta, tid, &start_seq_num, 0);
-#ifdef CONFIG_MAC80211_HT_DEBUG
- printk(KERN_DEBUG "Rx A-MPDU request on tid %d result %d\n", tid, ret);
-#endif /* CONFIG_MAC80211_HT_DEBUG */
-
+ ht_vdbg("Rx A-MPDU request on tid %d result %d\n", tid, ret);
if (ret) {
kfree(tid_agg_rx->reorder_buf);
kfree(tid_agg_rx->reorder_time);
diff --git a/net/mac80211/agg-tx.c b/net/mac80211/agg-tx.c
index 7cf07158805..da07f01cfe4 100644
--- a/net/mac80211/agg-tx.c
+++ b/net/mac80211/agg-tx.c
@@ -184,10 +184,8 @@ int ___ieee80211_stop_tx_ba_session(struct sta_info *sta, u16 tid,
spin_unlock_bh(&sta->lock);
-#ifdef CONFIG_MAC80211_HT_DEBUG
- printk(KERN_DEBUG "Tx BA session stop requested for %pM tid %u\n",
- sta->sta.addr, tid);
-#endif /* CONFIG_MAC80211_HT_DEBUG */
+ ht_vdbg("Tx BA session stop requested for %pM tid %u\n",
+ sta->sta.addr, tid);
del_timer_sync(&tid_tx->addba_resp_timer);
del_timer_sync(&tid_tx->session_timer);
@@ -253,17 +251,12 @@ static void sta_addba_resp_timer_expired(unsigned long data)
if (!tid_tx ||
test_bit(HT_AGG_STATE_RESPONSE_RECEIVED, &tid_tx->state)) {
rcu_read_unlock();
-#ifdef CONFIG_MAC80211_HT_DEBUG
- printk(KERN_DEBUG "timer expired on tid %d but we are not "
- "(or no longer) expecting addBA response there\n",
+ ht_vdbg("timer expired on tid %d but we are not (or no longer) expecting addBA response there\n",
tid);
-#endif
return;
}
-#ifdef CONFIG_MAC80211_HT_DEBUG
- printk(KERN_DEBUG "addBA response timer expired on tid %d\n", tid);
-#endif
+ ht_vdbg("addBA response timer expired on tid %d\n", tid);
ieee80211_stop_tx_ba_session(&sta->sta, tid);
rcu_read_unlock();
@@ -372,10 +365,7 @@ void ieee80211_tx_ba_session_handle_start(struct sta_info *sta, int tid)
ret = drv_ampdu_action(local, sdata, IEEE80211_AMPDU_TX_START,
&sta->sta, tid, &start_seq_num, 0);
if (ret) {
-#ifdef CONFIG_MAC80211_HT_DEBUG
- printk(KERN_DEBUG "BA request denied - HW unavailable for"
- " tid %d\n", tid);
-#endif
+ ht_vdbg("BA request denied - HW unavailable for tid %d\n", tid);
spin_lock_bh(&sta->lock);
ieee80211_agg_splice_packets(sdata, tid_tx, tid);
ieee80211_assign_tid_tx(sta, tid, NULL);
@@ -388,9 +378,7 @@ void ieee80211_tx_ba_session_handle_start(struct sta_info *sta, int tid)
/* activate the timer for the recipient's addBA response */
mod_timer(&tid_tx->addba_resp_timer, jiffies + ADDBA_RESP_INTERVAL);
-#ifdef CONFIG_MAC80211_HT_DEBUG
- printk(KERN_DEBUG "activated addBA response timer on tid %d\n", tid);
-#endif
+ ht_vdbg("activated addBA response timer on tid %d\n", tid);
spin_lock_bh(&sta->lock);
sta->ampdu_mlme.last_addba_req_time[tid] = jiffies;
@@ -437,9 +425,7 @@ static void sta_tx_agg_session_timer_expired(unsigned long data)
rcu_read_unlock();
-#ifdef CONFIG_MAC80211_HT_DEBUG
- printk(KERN_DEBUG "tx session timer expired on tid %d\n", (u16)*ptid);
-#endif
+ ht_vdbg("tx session timer expired on tid %d\n", (u16)*ptid);
ieee80211_stop_tx_ba_session(&sta->sta, *ptid);
}
@@ -463,10 +449,8 @@ int ieee80211_start_tx_ba_session(struct ieee80211_sta *pubsta, u16 tid,
(local->hw.flags & IEEE80211_HW_TX_AMPDU_SETUP_IN_HW))
return -EINVAL;
-#ifdef CONFIG_MAC80211_HT_DEBUG
- printk(KERN_DEBUG "Open BA session requested for %pM tid %u\n",
- pubsta->addr, tid);
-#endif /* CONFIG_MAC80211_HT_DEBUG */
+ ht_vdbg("Open BA session requested for %pM tid %u\n",
+ pubsta->addr, tid);
if (sdata->vif.type != NL80211_IFTYPE_STATION &&
sdata->vif.type != NL80211_IFTYPE_MESH_POINT &&
@@ -476,10 +460,7 @@ int ieee80211_start_tx_ba_session(struct ieee80211_sta *pubsta, u16 tid,
return -EINVAL;
if (test_sta_flag(sta, WLAN_STA_BLOCK_BA)) {
-#ifdef CONFIG_MAC80211_HT_DEBUG
- printk(KERN_DEBUG "BA sessions blocked. "
- "Denying BA session request\n");
-#endif
+ ht_vdbg("BA sessions blocked - Denying BA session request\n");
return -EINVAL;
}
@@ -497,10 +478,8 @@ int ieee80211_start_tx_ba_session(struct ieee80211_sta *pubsta, u16 tid,
*/
if (sta->sdata->vif.type == NL80211_IFTYPE_ADHOC &&
!sta->sta.ht_cap.ht_supported) {
-#ifdef CONFIG_MAC80211_HT_DEBUG
- printk(KERN_DEBUG "BA request denied - IBSS STA %pM"
- "does not advertise HT support\n", pubsta->addr);
-#endif /* CONFIG_MAC80211_HT_DEBUG */
+ ht_vdbg("BA request denied - IBSS STA %pM does not advertise HT support\n",
+ pubsta->addr);
return -EINVAL;
}
@@ -520,12 +499,8 @@ int ieee80211_start_tx_ba_session(struct ieee80211_sta *pubsta, u16 tid,
if (sta->ampdu_mlme.addba_req_num[tid] > HT_AGG_BURST_RETRIES &&
time_before(jiffies, sta->ampdu_mlme.last_addba_req_time[tid] +
HT_AGG_RETRIES_PERIOD)) {
-#ifdef CONFIG_MAC80211_HT_DEBUG
- printk(KERN_DEBUG "BA request denied - "
- "waiting a grace period after %d failed requests "
- "on tid %u\n",
- sta->ampdu_mlme.addba_req_num[tid], tid);
-#endif /* CONFIG_MAC80211_HT_DEBUG */
+ ht_vdbg("BA request denied - waiting a grace period after %d failed requests on tid %u\n",
+ sta->ampdu_mlme.addba_req_num[tid], tid);
ret = -EBUSY;
goto err_unlock_sta;
}
@@ -533,10 +508,8 @@ int ieee80211_start_tx_ba_session(struct ieee80211_sta *pubsta, u16 tid,
tid_tx = rcu_dereference_protected_tid_tx(sta, tid);
/* check if the TID is not in aggregation flow already */
if (tid_tx || sta->ampdu_mlme.tid_start_tx[tid]) {
-#ifdef CONFIG_MAC80211_HT_DEBUG
- printk(KERN_DEBUG "BA request denied - session is not "
- "idle on tid %u\n", tid);
-#endif /* CONFIG_MAC80211_HT_DEBUG */
+ ht_vdbg("BA request denied - session is not idle on tid %u\n",
+ tid);
ret = -EAGAIN;
goto err_unlock_sta;
}
@@ -591,9 +564,7 @@ static void ieee80211_agg_tx_operational(struct ieee80211_local *local,
tid_tx = rcu_dereference_protected_tid_tx(sta, tid);
-#ifdef CONFIG_MAC80211_HT_DEBUG
- printk(KERN_DEBUG "Aggregation is on for tid %d\n", tid);
-#endif
+ ht_vdbg("Aggregation is on for tid %d\n", tid);
drv_ampdu_action(local, sta->sdata,
IEEE80211_AMPDU_TX_OPERATIONAL,
@@ -627,10 +598,7 @@ void ieee80211_start_tx_ba_cb(struct ieee80211_vif *vif, u8 *ra, u16 tid)
trace_api_start_tx_ba_cb(sdata, ra, tid);
if (tid >= STA_TID_NUM) {
-#ifdef CONFIG_MAC80211_HT_DEBUG
- printk(KERN_DEBUG "Bad TID value: tid = %d (>= %d)\n",
- tid, STA_TID_NUM);
-#endif
+ ht_vdbg("Bad TID value: tid = %d (>= %d)\n", tid, STA_TID_NUM);
return;
}
@@ -638,9 +606,7 @@ void ieee80211_start_tx_ba_cb(struct ieee80211_vif *vif, u8 *ra, u16 tid)
sta = sta_info_get_bss(sdata, ra);
if (!sta) {
mutex_unlock(&local->sta_mtx);
-#ifdef CONFIG_MAC80211_HT_DEBUG
- printk(KERN_DEBUG "Could not find station: %pM\n", ra);
-#endif
+ ht_vdbg("Could not find station: %pM\n", ra);
return;
}
@@ -648,9 +614,7 @@ void ieee80211_start_tx_ba_cb(struct ieee80211_vif *vif, u8 *ra, u16 tid)
tid_tx = rcu_dereference_protected_tid_tx(sta, tid);
if (WARN_ON(!tid_tx)) {
-#ifdef CONFIG_MAC80211_HT_DEBUG
- printk(KERN_DEBUG "addBA was not requested!\n");
-#endif
+ ht_vdbg("addBA was not requested!\n");
goto unlock;
}
@@ -750,25 +714,17 @@ void ieee80211_stop_tx_ba_cb(struct ieee80211_vif *vif, u8 *ra, u8 tid)
trace_api_stop_tx_ba_cb(sdata, ra, tid);
if (tid >= STA_TID_NUM) {
-#ifdef CONFIG_MAC80211_HT_DEBUG
- printk(KERN_DEBUG "Bad TID value: tid = %d (>= %d)\n",
- tid, STA_TID_NUM);
-#endif
+ ht_vdbg("Bad TID value: tid = %d (>= %d)\n", tid, STA_TID_NUM);
return;
}
-#ifdef CONFIG_MAC80211_HT_DEBUG
- printk(KERN_DEBUG "Stopping Tx BA session for %pM tid %d\n",
- ra, tid);
-#endif /* CONFIG_MAC80211_HT_DEBUG */
+ ht_vdbg("Stopping Tx BA session for %pM tid %d\n", ra, tid);
mutex_lock(&local->sta_mtx);
sta = sta_info_get_bss(sdata, ra);
if (!sta) {
-#ifdef CONFIG_MAC80211_HT_DEBUG
- printk(KERN_DEBUG "Could not find station: %pM\n", ra);
-#endif
+ ht_vdbg("Could not find station: %pM\n", ra);
goto unlock;
}
@@ -777,9 +733,7 @@ void ieee80211_stop_tx_ba_cb(struct ieee80211_vif *vif, u8 *ra, u8 tid)
tid_tx = rcu_dereference_protected_tid_tx(sta, tid);
if (!tid_tx || !test_bit(HT_AGG_STATE_STOPPING, &tid_tx->state)) {
-#ifdef CONFIG_MAC80211_HT_DEBUG
- printk(KERN_DEBUG "unexpected callback to A-MPDU stop\n");
-#endif
+ ht_vdbg("unexpected callback to A-MPDU stop\n");
goto unlock_sta;
}
@@ -855,17 +809,13 @@ void ieee80211_process_addba_resp(struct ieee80211_local *local,
goto out;
if (mgmt->u.action.u.addba_resp.dialog_token != tid_tx->dialog_token) {
-#ifdef CONFIG_MAC80211_HT_DEBUG
- printk(KERN_DEBUG "wrong addBA response token, tid %d\n", tid);
-#endif
+ ht_vdbg("wrong addBA response token, tid %d\n", tid);
goto out;
}
del_timer_sync(&tid_tx->addba_resp_timer);
-#ifdef CONFIG_MAC80211_HT_DEBUG
- printk(KERN_DEBUG "switched off addBA timer for tid %d\n", tid);
-#endif
+ ht_vdbg("switched off addBA timer for tid %d\n", tid);
/*
* addba_resp_timer may have fired before we got here, and
@@ -874,11 +824,8 @@ void ieee80211_process_addba_resp(struct ieee80211_local *local,
*/
if (test_bit(HT_AGG_STATE_WANT_STOP, &tid_tx->state) ||
test_bit(HT_AGG_STATE_STOPPING, &tid_tx->state)) {
-#ifdef CONFIG_MAC80211_HT_DEBUG
- printk(KERN_DEBUG
- "got addBA resp for tid %d but we already gave up\n",
- tid);
-#endif
+ ht_vdbg("got addBA resp for tid %d but we already gave up\n",
+ tid);
goto out;
}
diff --git a/net/mac80211/cfg.c b/net/mac80211/cfg.c
index 495831ee48f..498c94e3442 100644
--- a/net/mac80211/cfg.c
+++ b/net/mac80211/cfg.c
@@ -533,16 +533,16 @@ static void ieee80211_get_et_stats(struct wiphy *wiphy,
sinfo.filled = 0;
sta_set_sinfo(sta, &sinfo);
- if (sinfo.filled | STATION_INFO_TX_BITRATE)
+ if (sinfo.filled & STATION_INFO_TX_BITRATE)
data[i] = 100000 *
cfg80211_calculate_bitrate(&sinfo.txrate);
i++;
- if (sinfo.filled | STATION_INFO_RX_BITRATE)
+ if (sinfo.filled & STATION_INFO_RX_BITRATE)
data[i] = 100000 *
cfg80211_calculate_bitrate(&sinfo.rxrate);
i++;
- if (sinfo.filled | STATION_INFO_SIGNAL_AVG)
+ if (sinfo.filled & STATION_INFO_SIGNAL_AVG)
data[i] = (u8)sinfo.signal_avg;
i++;
} else {
@@ -674,6 +674,48 @@ static int ieee80211_get_station(struct wiphy *wiphy, struct net_device *dev,
return ret;
}
+static int ieee80211_set_channel(struct wiphy *wiphy,
+ struct net_device *netdev,
+ struct ieee80211_channel *chan,
+ enum nl80211_channel_type channel_type)
+{
+ struct ieee80211_local *local = wiphy_priv(wiphy);
+ struct ieee80211_sub_if_data *sdata = NULL;
+
+ if (netdev)
+ sdata = IEEE80211_DEV_TO_SUB_IF(netdev);
+
+ switch (ieee80211_get_channel_mode(local, NULL)) {
+ case CHAN_MODE_HOPPING:
+ return -EBUSY;
+ case CHAN_MODE_FIXED:
+ if (local->oper_channel != chan)
+ return -EBUSY;
+ if (!sdata && local->_oper_channel_type == channel_type)
+ return 0;
+ break;
+ case CHAN_MODE_UNDEFINED:
+ break;
+ }
+
+ if (!ieee80211_set_channel_type(local, sdata, channel_type))
+ return -EBUSY;
+
+ local->oper_channel = chan;
+
+ /* auto-detects changes */
+ ieee80211_hw_config(local, 0);
+
+ return 0;
+}
+
+static int ieee80211_set_monitor_channel(struct wiphy *wiphy,
+ struct ieee80211_channel *chan,
+ enum nl80211_channel_type channel_type)
+{
+ return ieee80211_set_channel(wiphy, NULL, chan, channel_type);
+}
+
static int ieee80211_set_probe_resp(struct ieee80211_sub_if_data *sdata,
const u8 *resp, size_t resp_len)
{
@@ -788,6 +830,11 @@ static int ieee80211_start_ap(struct wiphy *wiphy, struct net_device *dev,
if (old)
return -EALREADY;
+ err = ieee80211_set_channel(wiphy, dev, params->channel,
+ params->channel_type);
+ if (err)
+ return err;
+
/*
* Apply control port protocol, this allows us to
* not encrypt dynamic WEP control frames.
@@ -1558,6 +1605,12 @@ static int ieee80211_join_mesh(struct wiphy *wiphy, struct net_device *dev,
err = copy_mesh_setup(ifmsh, setup);
if (err)
return err;
+
+ err = ieee80211_set_channel(wiphy, dev, setup->channel,
+ setup->channel_type);
+ if (err)
+ return err;
+
ieee80211_start_mesh(sdata);
return 0;
@@ -1677,55 +1730,6 @@ static int ieee80211_set_txq_params(struct wiphy *wiphy,
return 0;
}
-static int ieee80211_set_channel(struct wiphy *wiphy,
- struct net_device *netdev,
- struct ieee80211_channel *chan,
- enum nl80211_channel_type channel_type)
-{
- struct ieee80211_local *local = wiphy_priv(wiphy);
- struct ieee80211_sub_if_data *sdata = NULL;
- struct ieee80211_channel *old_oper;
- enum nl80211_channel_type old_oper_type;
- enum nl80211_channel_type old_vif_oper_type= NL80211_CHAN_NO_HT;
-
- if (netdev)
- sdata = IEEE80211_DEV_TO_SUB_IF(netdev);
-
- switch (ieee80211_get_channel_mode(local, NULL)) {
- case CHAN_MODE_HOPPING:
- return -EBUSY;
- case CHAN_MODE_FIXED:
- if (local->oper_channel != chan)
- return -EBUSY;
- if (!sdata && local->_oper_channel_type == channel_type)
- return 0;
- break;
- case CHAN_MODE_UNDEFINED:
- break;
- }
-
- if (sdata)
- old_vif_oper_type = sdata->vif.bss_conf.channel_type;
- old_oper_type = local->_oper_channel_type;
-
- if (!ieee80211_set_channel_type(local, sdata, channel_type))
- return -EBUSY;
-
- old_oper = local->oper_channel;
- local->oper_channel = chan;
-
- /* Update driver if changes were actually made. */
- if ((old_oper != local->oper_channel) ||
- (old_oper_type != local->_oper_channel_type))
- ieee80211_hw_config(local, IEEE80211_CONF_CHANGE_CHANNEL);
-
- if (sdata && sdata->vif.type != NL80211_IFTYPE_MONITOR &&
- old_vif_oper_type != sdata->vif.bss_conf.channel_type)
- ieee80211_bss_info_change_notify(sdata, BSS_CHANGED_HT);
-
- return 0;
-}
-
#ifdef CONFIG_PM
static int ieee80211_suspend(struct wiphy *wiphy,
struct cfg80211_wowlan *wowlan)
@@ -2108,35 +2112,171 @@ static int ieee80211_set_bitrate_mask(struct wiphy *wiphy,
return 0;
}
-static int ieee80211_remain_on_channel_hw(struct ieee80211_local *local,
- struct net_device *dev,
- struct ieee80211_channel *chan,
- enum nl80211_channel_type chantype,
- unsigned int duration, u64 *cookie)
+static int ieee80211_start_roc_work(struct ieee80211_local *local,
+ struct ieee80211_sub_if_data *sdata,
+ struct ieee80211_channel *channel,
+ enum nl80211_channel_type channel_type,
+ unsigned int duration, u64 *cookie,
+ struct sk_buff *txskb)
{
+ struct ieee80211_roc_work *roc, *tmp;
+ bool queued = false;
int ret;
- u32 random_cookie;
lockdep_assert_held(&local->mtx);
- if (local->hw_roc_cookie)
- return -EBUSY;
- /* must be nonzero */
- random_cookie = random32() | 1;
-
- *cookie = random_cookie;
- local->hw_roc_dev = dev;
- local->hw_roc_cookie = random_cookie;
- local->hw_roc_channel = chan;
- local->hw_roc_channel_type = chantype;
- local->hw_roc_duration = duration;
- ret = drv_remain_on_channel(local, chan, chantype, duration);
+ roc = kzalloc(sizeof(*roc), GFP_KERNEL);
+ if (!roc)
+ return -ENOMEM;
+
+ roc->chan = channel;
+ roc->chan_type = channel_type;
+ roc->duration = duration;
+ roc->req_duration = duration;
+ roc->frame = txskb;
+ roc->mgmt_tx_cookie = (unsigned long)txskb;
+ roc->sdata = sdata;
+ INIT_DELAYED_WORK(&roc->work, ieee80211_sw_roc_work);
+ INIT_LIST_HEAD(&roc->dependents);
+
+ /* if there's one pending or we're scanning, queue this one */
+ if (!list_empty(&local->roc_list) || local->scanning)
+ goto out_check_combine;
+
+ /* if not HW assist, just queue & schedule work */
+ if (!local->ops->remain_on_channel) {
+ ieee80211_queue_delayed_work(&local->hw, &roc->work, 0);
+ goto out_queue;
+ }
+
+ /* otherwise actually kick it off here (for error handling) */
+
+ /*
+ * If the duration is zero, then the driver
+ * wouldn't actually do anything. Set it to
+ * 10 for now.
+ *
+ * TODO: cancel the off-channel operation
+ * when we get the SKB's TX status and
+ * the wait time was zero before.
+ */
+ if (!duration)
+ duration = 10;
+
+ ret = drv_remain_on_channel(local, channel, channel_type, duration);
if (ret) {
- local->hw_roc_channel = NULL;
- local->hw_roc_cookie = 0;
+ kfree(roc);
+ return ret;
}
- return ret;
+ roc->started = true;
+ goto out_queue;
+
+ out_check_combine:
+ list_for_each_entry(tmp, &local->roc_list, list) {
+ if (tmp->chan != channel || tmp->chan_type != channel_type)
+ continue;
+
+ /*
+ * Extend this ROC if possible:
+ *
+ * If it hasn't started yet, just increase the duration
+ * and add the new one to the list of dependents.
+ */
+ if (!tmp->started) {
+ list_add_tail(&roc->list, &tmp->dependents);
+ tmp->duration = max(tmp->duration, roc->duration);
+ queued = true;
+ break;
+ }
+
+ /* If it has already started, it's more difficult ... */
+ if (local->ops->remain_on_channel) {
+ unsigned long j = jiffies;
+
+ /*
+ * In the offloaded ROC case, if it hasn't begun, add
+ * this new one to the dependent list to be handled
+ * when the the master one begins. If it has begun,
+ * check that there's still a minimum time left and
+ * if so, start this one, transmitting the frame, but
+ * add it to the list directly after this one with a
+ * a reduced time so we'll ask the driver to execute
+ * it right after finishing the previous one, in the
+ * hope that it'll also be executed right afterwards,
+ * effectively extending the old one.
+ * If there's no minimum time left, just add it to the
+ * normal list.
+ */
+ if (!tmp->hw_begun) {
+ list_add_tail(&roc->list, &tmp->dependents);
+ queued = true;
+ break;
+ }
+
+ if (time_before(j + IEEE80211_ROC_MIN_LEFT,
+ tmp->hw_start_time +
+ msecs_to_jiffies(tmp->duration))) {
+ int new_dur;
+
+ ieee80211_handle_roc_started(roc);
+
+ new_dur = roc->duration -
+ jiffies_to_msecs(tmp->hw_start_time +
+ msecs_to_jiffies(
+ tmp->duration) -
+ j);
+
+ if (new_dur > 0) {
+ /* add right after tmp */
+ list_add(&roc->list, &tmp->list);
+ } else {
+ list_add_tail(&roc->list,
+ &tmp->dependents);
+ }
+ queued = true;
+ }
+ } else if (del_timer_sync(&tmp->work.timer)) {
+ unsigned long new_end;
+
+ /*
+ * In the software ROC case, cancel the timer, if
+ * that fails then the finish work is already
+ * queued/pending and thus we queue the new ROC
+ * normally, if that succeeds then we can extend
+ * the timer duration and TX the frame (if any.)
+ */
+
+ list_add_tail(&roc->list, &tmp->dependents);
+ queued = true;
+
+ new_end = jiffies + msecs_to_jiffies(roc->duration);
+
+ /* ok, it was started & we canceled timer */
+ if (time_after(new_end, tmp->work.timer.expires))
+ mod_timer(&tmp->work.timer, new_end);
+ else
+ add_timer(&tmp->work.timer);
+
+ ieee80211_handle_roc_started(roc);
+ }
+ break;
+ }
+
+ out_queue:
+ if (!queued)
+ list_add_tail(&roc->list, &local->roc_list);
+
+ /*
+ * cookie is either the roc (for normal roc)
+ * or the SKB (for mgmt TX)
+ */
+ if (txskb)
+ *cookie = (unsigned long)txskb;
+ else
+ *cookie = (unsigned long)roc;
+
+ return 0;
}
static int ieee80211_remain_on_channel(struct wiphy *wiphy,
@@ -2148,42 +2288,64 @@ static int ieee80211_remain_on_channel(struct wiphy *wiphy,
{
struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
struct ieee80211_local *local = sdata->local;
+ int ret;
- if (local->ops->remain_on_channel) {
- int ret;
-
- mutex_lock(&local->mtx);
- ret = ieee80211_remain_on_channel_hw(local, dev,
- chan, channel_type,
- duration, cookie);
- local->hw_roc_for_tx = false;
- mutex_unlock(&local->mtx);
-
- return ret;
- }
+ mutex_lock(&local->mtx);
+ ret = ieee80211_start_roc_work(local, sdata, chan, channel_type,
+ duration, cookie, NULL);
+ mutex_unlock(&local->mtx);
- return ieee80211_wk_remain_on_channel(sdata, chan, channel_type,
- duration, cookie);
+ return ret;
}
-static int ieee80211_cancel_remain_on_channel_hw(struct ieee80211_local *local,
- u64 cookie)
+static int ieee80211_cancel_roc(struct ieee80211_local *local,
+ u64 cookie, bool mgmt_tx)
{
+ struct ieee80211_roc_work *roc, *tmp, *found = NULL;
int ret;
- lockdep_assert_held(&local->mtx);
+ mutex_lock(&local->mtx);
+ list_for_each_entry_safe(roc, tmp, &local->roc_list, list) {
+ if (!mgmt_tx && (unsigned long)roc != cookie)
+ continue;
+ else if (mgmt_tx && roc->mgmt_tx_cookie != cookie)
+ continue;
+
+ found = roc;
+ break;
+ }
- if (local->hw_roc_cookie != cookie)
+ if (!found) {
+ mutex_unlock(&local->mtx);
return -ENOENT;
+ }
- ret = drv_cancel_remain_on_channel(local);
- if (ret)
- return ret;
+ if (local->ops->remain_on_channel) {
+ if (found->started) {
+ ret = drv_cancel_remain_on_channel(local);
+ if (WARN_ON_ONCE(ret)) {
+ mutex_unlock(&local->mtx);
+ return ret;
+ }
+ }
- local->hw_roc_cookie = 0;
- local->hw_roc_channel = NULL;
+ list_del(&found->list);
- ieee80211_recalc_idle(local);
+ ieee80211_run_deferred_scan(local);
+ ieee80211_start_next_roc(local);
+ mutex_unlock(&local->mtx);
+
+ ieee80211_roc_notify_destroy(found);
+ } else {
+ /* work may be pending so use it all the time */
+ found->abort = true;
+ ieee80211_queue_delayed_work(&local->hw, &found->work, 0);
+
+ mutex_unlock(&local->mtx);
+
+ /* work will clean up etc */
+ flush_delayed_work(&found->work);
+ }
return 0;
}
@@ -2195,39 +2357,7 @@ static int ieee80211_cancel_remain_on_channel(struct wiphy *wiphy,
struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
struct ieee80211_local *local = sdata->local;
- if (local->ops->cancel_remain_on_channel) {
- int ret;
-
- mutex_lock(&local->mtx);
- ret = ieee80211_cancel_remain_on_channel_hw(local, cookie);
- mutex_unlock(&local->mtx);
-
- return ret;
- }
-
- return ieee80211_wk_cancel_remain_on_channel(sdata, cookie);
-}
-
-static enum work_done_result
-ieee80211_offchan_tx_done(struct ieee80211_work *wk, struct sk_buff *skb)
-{
- /*
- * Use the data embedded in the work struct for reporting
- * here so if the driver mangled the SKB before dropping
- * it (which is the only way we really should get here)
- * then we don't report mangled data.
- *
- * If there was no wait time, then by the time we get here
- * the driver will likely not have reported the status yet,
- * so in that case userspace will have to deal with it.
- */
-
- if (wk->offchan_tx.wait && !wk->offchan_tx.status)
- cfg80211_mgmt_tx_status(wk->sdata->dev,
- (unsigned long) wk->offchan_tx.frame,
- wk->data, wk->data_len, false, GFP_KERNEL);
-
- return WORK_DONE_DESTROY;
+ return ieee80211_cancel_roc(local, cookie, false);
}
static int ieee80211_mgmt_tx(struct wiphy *wiphy, struct net_device *dev,
@@ -2241,10 +2371,10 @@ static int ieee80211_mgmt_tx(struct wiphy *wiphy, struct net_device *dev,
struct ieee80211_local *local = sdata->local;
struct sk_buff *skb;
struct sta_info *sta;
- struct ieee80211_work *wk;
const struct ieee80211_mgmt *mgmt = (void *)buf;
+ bool need_offchan = false;
u32 flags;
- bool is_offchan = false;
+ int ret;
if (dont_wait_for_ack)
flags = IEEE80211_TX_CTL_NO_ACK;
@@ -2252,33 +2382,28 @@ static int ieee80211_mgmt_tx(struct wiphy *wiphy, struct net_device *dev,
flags = IEEE80211_TX_INTFL_NL80211_FRAME_TX |
IEEE80211_TX_CTL_REQ_TX_STATUS;
- /* Check that we are on the requested channel for transmission */
- if (chan != local->tmp_channel &&
- chan != local->oper_channel)
- is_offchan = true;
- if (channel_type_valid &&
- (channel_type != local->tmp_channel_type &&
- channel_type != local->_oper_channel_type))
- is_offchan = true;
-
- if (chan == local->hw_roc_channel) {
- /* TODO: check channel type? */
- is_offchan = false;
- flags |= IEEE80211_TX_CTL_TX_OFFCHAN;
- }
-
if (no_cck)
flags |= IEEE80211_TX_CTL_NO_CCK_RATE;
- if (is_offchan && !offchan)
- return -EBUSY;
-
switch (sdata->vif.type) {
case NL80211_IFTYPE_ADHOC:
+ if (!sdata->vif.bss_conf.ibss_joined)
+ need_offchan = true;
+ /* fall through */
+#ifdef CONFIG_MAC80211_MESH
+ case NL80211_IFTYPE_MESH_POINT:
+ if (ieee80211_vif_is_mesh(&sdata->vif) &&
+ !sdata->u.mesh.mesh_id_len)
+ need_offchan = true;
+ /* fall through */
+#endif
case NL80211_IFTYPE_AP:
case NL80211_IFTYPE_AP_VLAN:
case NL80211_IFTYPE_P2P_GO:
- case NL80211_IFTYPE_MESH_POINT:
+ if (sdata->vif.type != NL80211_IFTYPE_ADHOC &&
+ !ieee80211_vif_is_mesh(&sdata->vif) &&
+ !rcu_access_pointer(sdata->bss->beacon))
+ need_offchan = true;
if (!ieee80211_is_action(mgmt->frame_control) ||
mgmt->u.action.category == WLAN_CATEGORY_PUBLIC)
break;
@@ -2290,103 +2415,60 @@ static int ieee80211_mgmt_tx(struct wiphy *wiphy, struct net_device *dev,
break;
case NL80211_IFTYPE_STATION:
case NL80211_IFTYPE_P2P_CLIENT:
+ if (!sdata->u.mgd.associated)
+ need_offchan = true;
break;
default:
return -EOPNOTSUPP;
}
+ mutex_lock(&local->mtx);
+
+ /* Check if the operating channel is the requested channel */
+ if (!need_offchan) {
+ need_offchan = chan != local->oper_channel;
+ if (channel_type_valid &&
+ channel_type != local->_oper_channel_type)
+ need_offchan = true;
+ }
+
+ if (need_offchan && !offchan) {
+ ret = -EBUSY;
+ goto out_unlock;
+ }
+
skb = dev_alloc_skb(local->hw.extra_tx_headroom + len);
- if (!skb)
- return -ENOMEM;
+ if (!skb) {
+ ret = -ENOMEM;
+ goto out_unlock;
+ }
skb_reserve(skb, local->hw.extra_tx_headroom);
memcpy(skb_put(skb, len), buf, len);
IEEE80211_SKB_CB(skb)->flags = flags;
- if (flags & IEEE80211_TX_CTL_TX_OFFCHAN)
- IEEE80211_SKB_CB(skb)->hw_queue =
- local->hw.offchannel_tx_hw_queue;
-
skb->dev = sdata->dev;
- *cookie = (unsigned long) skb;
-
- if (is_offchan && local->ops->remain_on_channel) {
- unsigned int duration;
- int ret;
-
- mutex_lock(&local->mtx);
- /*
- * If the duration is zero, then the driver
- * wouldn't actually do anything. Set it to
- * 100 for now.
- *
- * TODO: cancel the off-channel operation
- * when we get the SKB's TX status and
- * the wait time was zero before.
- */
- duration = 100;
- if (wait)
- duration = wait;
- ret = ieee80211_remain_on_channel_hw(local, dev, chan,
- channel_type,
- duration, cookie);
- if (ret) {
- kfree_skb(skb);
- mutex_unlock(&local->mtx);
- return ret;
- }
-
- local->hw_roc_for_tx = true;
- local->hw_roc_duration = wait;
-
- /*
- * queue up frame for transmission after
- * ieee80211_ready_on_channel call
- */
+ if (!need_offchan) {
+ ieee80211_tx_skb(sdata, skb);
+ ret = 0;
+ goto out_unlock;
+ }
- /* modify cookie to prevent API mismatches */
- *cookie ^= 2;
- IEEE80211_SKB_CB(skb)->flags |= IEEE80211_TX_CTL_TX_OFFCHAN;
+ IEEE80211_SKB_CB(skb)->flags |= IEEE80211_TX_CTL_TX_OFFCHAN;
+ if (local->hw.flags & IEEE80211_HW_QUEUE_CONTROL)
IEEE80211_SKB_CB(skb)->hw_queue =
local->hw.offchannel_tx_hw_queue;
- local->hw_roc_skb = skb;
- local->hw_roc_skb_for_status = skb;
- mutex_unlock(&local->mtx);
-
- return 0;
- }
-
- /*
- * Can transmit right away if the channel was the
- * right one and there's no wait involved... If a
- * wait is involved, we might otherwise not be on
- * the right channel for long enough!
- */
- if (!is_offchan && !wait && !sdata->vif.bss_conf.idle) {
- ieee80211_tx_skb(sdata, skb);
- return 0;
- }
- wk = kzalloc(sizeof(*wk) + len, GFP_KERNEL);
- if (!wk) {
+ /* This will handle all kinds of coalescing and immediate TX */
+ ret = ieee80211_start_roc_work(local, sdata, chan, channel_type,
+ wait, cookie, skb);
+ if (ret)
kfree_skb(skb);
- return -ENOMEM;
- }
-
- wk->type = IEEE80211_WORK_OFFCHANNEL_TX;
- wk->chan = chan;
- wk->chan_type = channel_type;
- wk->sdata = sdata;
- wk->done = ieee80211_offchan_tx_done;
- wk->offchan_tx.frame = skb;
- wk->offchan_tx.wait = wait;
- wk->data_len = len;
- memcpy(wk->data, buf, len);
-
- ieee80211_add_work(wk);
- return 0;
+ out_unlock:
+ mutex_unlock(&local->mtx);
+ return ret;
}
static int ieee80211_mgmt_tx_cancel_wait(struct wiphy *wiphy,
@@ -2395,45 +2477,8 @@ static int ieee80211_mgmt_tx_cancel_wait(struct wiphy *wiphy,
{
struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
struct ieee80211_local *local = sdata->local;
- struct ieee80211_work *wk;
- int ret = -ENOENT;
-
- mutex_lock(&local->mtx);
-
- if (local->ops->cancel_remain_on_channel) {
- cookie ^= 2;
- ret = ieee80211_cancel_remain_on_channel_hw(local, cookie);
-
- if (ret == 0) {
- kfree_skb(local->hw_roc_skb);
- local->hw_roc_skb = NULL;
- local->hw_roc_skb_for_status = NULL;
- }
-
- mutex_unlock(&local->mtx);
- return ret;
- }
-
- list_for_each_entry(wk, &local->work_list, list) {
- if (wk->sdata != sdata)
- continue;
-
- if (wk->type != IEEE80211_WORK_OFFCHANNEL_TX)
- continue;
-
- if (cookie != (unsigned long) wk->offchan_tx.frame)
- continue;
-
- wk->timeout = jiffies;
-
- ieee80211_queue_work(&local->hw, &local->work_work);
- ret = 0;
- break;
- }
- mutex_unlock(&local->mtx);
-
- return ret;
+ return ieee80211_cancel_roc(local, cookie, true);
}
static void ieee80211_mgmt_frame_register(struct wiphy *wiphy,
@@ -2677,7 +2722,7 @@ static int ieee80211_tdls_mgmt(struct wiphy *wiphy, struct net_device *dev,
return -EINVAL;
#ifdef CONFIG_MAC80211_VERBOSE_TDLS_DEBUG
- printk(KERN_DEBUG "TDLS mgmt action %d peer %pM\n", action_code, peer);
+ pr_debug("TDLS mgmt action %d peer %pM\n", action_code, peer);
#endif
skb = dev_alloc_skb(local->hw.extra_tx_headroom +
@@ -2788,7 +2833,7 @@ static int ieee80211_tdls_oper(struct wiphy *wiphy, struct net_device *dev,
return -EINVAL;
#ifdef CONFIG_MAC80211_VERBOSE_TDLS_DEBUG
- printk(KERN_DEBUG "TDLS oper %d peer %pM\n", oper, peer);
+ pr_debug("TDLS oper %d peer %pM\n", oper, peer);
#endif
switch (oper) {
@@ -2933,7 +2978,7 @@ struct cfg80211_ops mac80211_config_ops = {
#endif
.change_bss = ieee80211_change_bss,
.set_txq_params = ieee80211_set_txq_params,
- .set_channel = ieee80211_set_channel,
+ .set_monitor_channel = ieee80211_set_monitor_channel,
.suspend = ieee80211_suspend,
.resume = ieee80211_resume,
.scan = ieee80211_scan,
diff --git a/net/mac80211/chan.c b/net/mac80211/chan.c
index c76cf7230c7..f0f87e5a1d3 100644
--- a/net/mac80211/chan.c
+++ b/net/mac80211/chan.c
@@ -41,6 +41,10 @@ __ieee80211_get_channel_mode(struct ieee80211_local *local,
if (!sdata->u.ap.beacon)
continue;
break;
+ case NL80211_IFTYPE_MESH_POINT:
+ if (!sdata->wdev.mesh_id_len)
+ continue;
+ break;
default:
break;
}
diff --git a/net/mac80211/debugfs_netdev.c b/net/mac80211/debugfs_netdev.c
index 7ed433c66d6..d4272ff43f7 100644
--- a/net/mac80211/debugfs_netdev.c
+++ b/net/mac80211/debugfs_netdev.c
@@ -607,6 +607,7 @@ static void add_mesh_config(struct ieee80211_sub_if_data *sdata)
MESHPARAMS_ADD(min_discovery_timeout);
MESHPARAMS_ADD(dot11MeshHWMPRootMode);
MESHPARAMS_ADD(dot11MeshHWMPRannInterval);
+ MESHPARAMS_ADD(dot11MeshForwarding);
MESHPARAMS_ADD(dot11MeshGateAnnouncementProtocol);
MESHPARAMS_ADD(rssi_threshold);
MESHPARAMS_ADD(ht_opmode);
@@ -685,6 +686,6 @@ void ieee80211_debugfs_rename_netdev(struct ieee80211_sub_if_data *sdata)
sprintf(buf, "netdev:%s", sdata->name);
if (!debugfs_rename(dir->d_parent, dir, dir->d_parent, buf))
- printk(KERN_ERR "mac80211: debugfs: failed to rename debugfs "
+ pr_err("mac80211: debugfs: failed to rename debugfs "
"dir to %s\n", buf);
}
diff --git a/net/mac80211/ibss.c b/net/mac80211/ibss.c
index 33d9d0c3e3d..725cb4be229 100644
--- a/net/mac80211/ibss.c
+++ b/net/mac80211/ibss.c
@@ -82,8 +82,7 @@ static void __ieee80211_sta_join_ibss(struct ieee80211_sub_if_data *sdata,
local->oper_channel = chan;
channel_type = ifibss->channel_type;
- if (channel_type > NL80211_CHAN_HT20 &&
- !cfg80211_can_beacon_sec_chan(local->hw.wiphy, chan, channel_type))
+ if (!cfg80211_can_beacon_sec_chan(local->hw.wiphy, chan, channel_type))
channel_type = NL80211_CHAN_HT20;
if (!ieee80211_set_channel_type(local, sdata, channel_type)) {
/* can only fail due to HT40+/- mismatch */
@@ -281,11 +280,8 @@ static struct sta_info *ieee80211_ibss_finish_sta(struct sta_info *sta,
if (sta_info_insert_rcu(sta))
return sta_info_get(sdata, addr);
if (auth) {
-#ifdef CONFIG_MAC80211_IBSS_DEBUG
- printk(KERN_DEBUG "TX Auth SA=%pM DA=%pM BSSID=%pM"
- "(auth_transaction=1)\n", sdata->vif.addr,
- sdata->u.ibss.bssid, addr);
-#endif
+ ibss_vdbg("TX Auth SA=%pM DA=%pM BSSID=%pM (auth_transaction=1)\n",
+ sdata->vif.addr, sdata->u.ibss.bssid, addr);
ieee80211_send_auth(sdata, 1, WLAN_AUTH_OPEN, NULL, 0,
addr, sdata->u.ibss.bssid, NULL, 0, 0);
}
@@ -355,11 +351,9 @@ static void ieee80211_rx_mgmt_auth_ibss(struct ieee80211_sub_if_data *sdata,
if (auth_alg != WLAN_AUTH_OPEN || auth_transaction != 1)
return;
-#ifdef CONFIG_MAC80211_IBSS_DEBUG
- printk(KERN_DEBUG "%s: RX Auth SA=%pM DA=%pM BSSID=%pM."
- "(auth_transaction=%d)\n",
- sdata->name, mgmt->sa, mgmt->da, mgmt->bssid, auth_transaction);
-#endif
+ ibss_vdbg("%s: RX Auth SA=%pM DA=%pM BSSID=%pM (auth_transaction=%d)\n",
+ sdata->name, mgmt->sa, mgmt->da, mgmt->bssid,
+ auth_transaction);
sta_info_destroy_addr(sdata, mgmt->sa);
ieee80211_ibss_add_sta(sdata, mgmt->bssid, mgmt->sa, 0, false);
rcu_read_unlock();
@@ -422,15 +416,10 @@ static void ieee80211_rx_bss_info(struct ieee80211_sub_if_data *sdata,
ieee80211_mandatory_rates(local, band);
if (sta->sta.supp_rates[band] != prev_rates) {
-#ifdef CONFIG_MAC80211_IBSS_DEBUG
- printk(KERN_DEBUG
- "%s: updated supp_rates set "
- "for %pM based on beacon"
- "/probe_resp (0x%x -> 0x%x)\n",
- sdata->name, sta->sta.addr,
- prev_rates,
- sta->sta.supp_rates[band]);
-#endif
+ ibss_vdbg("%s: updated supp_rates set for %pM based on beacon/probe_resp (0x%x -> 0x%x)\n",
+ sdata->name, sta->sta.addr,
+ prev_rates,
+ sta->sta.supp_rates[band]);
rates_updated = true;
}
} else {
@@ -545,22 +534,16 @@ static void ieee80211_rx_bss_info(struct ieee80211_sub_if_data *sdata,
rx_timestamp = drv_get_tsf(local, sdata);
}
-#ifdef CONFIG_MAC80211_IBSS_DEBUG
- printk(KERN_DEBUG "RX beacon SA=%pM BSSID="
- "%pM TSF=0x%llx BCN=0x%llx diff=%lld @%lu\n",
- mgmt->sa, mgmt->bssid,
- (unsigned long long)rx_timestamp,
- (unsigned long long)beacon_timestamp,
- (unsigned long long)(rx_timestamp - beacon_timestamp),
- jiffies);
-#endif
+ ibss_vdbg("RX beacon SA=%pM BSSID=%pM TSF=0x%llx BCN=0x%llx diff=%lld @%lu\n",
+ mgmt->sa, mgmt->bssid,
+ (unsigned long long)rx_timestamp,
+ (unsigned long long)beacon_timestamp,
+ (unsigned long long)(rx_timestamp - beacon_timestamp),
+ jiffies);
if (beacon_timestamp > rx_timestamp) {
-#ifdef CONFIG_MAC80211_IBSS_DEBUG
- printk(KERN_DEBUG "%s: beacon TSF higher than "
- "local TSF - IBSS merge with BSSID %pM\n",
- sdata->name, mgmt->bssid);
-#endif
+ ibss_vdbg("%s: beacon TSF higher than local TSF - IBSS merge with BSSID %pM\n",
+ sdata->name, mgmt->bssid);
ieee80211_sta_join_ibss(sdata, bss);
supp_rates = ieee80211_sta_get_rates(local, elems, band, NULL);
ieee80211_ibss_add_sta(sdata, mgmt->bssid, mgmt->sa,
@@ -662,8 +645,8 @@ static void ieee80211_sta_merge_ibss(struct ieee80211_sub_if_data *sdata)
if (ifibss->fixed_channel)
return;
- printk(KERN_DEBUG "%s: No active IBSS STAs - trying to scan for other "
- "IBSS networks with same SSID (merge)\n", sdata->name);
+ pr_debug("%s: No active IBSS STAs - trying to scan for other IBSS networks with same SSID (merge)\n",
+ sdata->name);
ieee80211_request_internal_scan(sdata,
ifibss->ssid, ifibss->ssid_len, NULL);
@@ -691,8 +674,8 @@ static void ieee80211_sta_create_ibss(struct ieee80211_sub_if_data *sdata)
bssid[0] |= 0x02;
}
- printk(KERN_DEBUG "%s: Creating new IBSS network, BSSID %pM\n",
- sdata->name, bssid);
+ pr_debug("%s: Creating new IBSS network, BSSID %pM\n",
+ sdata->name, bssid);
capability = WLAN_CAPABILITY_IBSS;
@@ -723,10 +706,8 @@ static void ieee80211_sta_find_ibss(struct ieee80211_sub_if_data *sdata)
lockdep_assert_held(&ifibss->mtx);
active_ibss = ieee80211_sta_active_ibss(sdata);
-#ifdef CONFIG_MAC80211_IBSS_DEBUG
- printk(KERN_DEBUG "%s: sta_find_ibss (active_ibss=%d)\n",
- sdata->name, active_ibss);
-#endif /* CONFIG_MAC80211_IBSS_DEBUG */
+ ibss_vdbg("%s: sta_find_ibss (active_ibss=%d)\n",
+ sdata->name, active_ibss);
if (active_ibss)
return;
@@ -749,29 +730,23 @@ static void ieee80211_sta_find_ibss(struct ieee80211_sub_if_data *sdata)
struct ieee80211_bss *bss;
bss = (void *)cbss->priv;
-#ifdef CONFIG_MAC80211_IBSS_DEBUG
- printk(KERN_DEBUG " sta_find_ibss: selected %pM current "
- "%pM\n", cbss->bssid, ifibss->bssid);
-#endif /* CONFIG_MAC80211_IBSS_DEBUG */
-
- printk(KERN_DEBUG "%s: Selected IBSS BSSID %pM"
- " based on configured SSID\n",
- sdata->name, cbss->bssid);
+ ibss_vdbg(" sta_find_ibss: selected %pM current %pM\n",
+ cbss->bssid, ifibss->bssid);
+ pr_debug("%s: Selected IBSS BSSID %pM based on configured SSID\n",
+ sdata->name, cbss->bssid);
ieee80211_sta_join_ibss(sdata, bss);
ieee80211_rx_bss_put(local, bss);
return;
}
-#ifdef CONFIG_MAC80211_IBSS_DEBUG
- printk(KERN_DEBUG " did not try to join ibss\n");
-#endif /* CONFIG_MAC80211_IBSS_DEBUG */
+ ibss_vdbg(" did not try to join ibss\n");
/* Selected IBSS not found in current scan results - try to scan */
if (time_after(jiffies, ifibss->last_scan_completed +
IEEE80211_SCAN_INTERVAL)) {
- printk(KERN_DEBUG "%s: Trigger new scan to find an IBSS to "
- "join\n", sdata->name);
+ pr_debug("%s: Trigger new scan to find an IBSS to join\n",
+ sdata->name);
ieee80211_request_internal_scan(sdata,
ifibss->ssid, ifibss->ssid_len,
@@ -785,9 +760,9 @@ static void ieee80211_sta_find_ibss(struct ieee80211_sub_if_data *sdata)
ieee80211_sta_create_ibss(sdata);
return;
}
- printk(KERN_DEBUG "%s: IBSS not allowed on"
- " %d MHz\n", sdata->name,
- local->hw.conf.channel->center_freq);
+ pr_debug("%s: IBSS not allowed on %d MHz\n",
+ sdata->name,
+ local->hw.conf.channel->center_freq);
/* No IBSS found - decrease scan interval and continue
* scanning. */
@@ -822,12 +797,9 @@ static void ieee80211_rx_mgmt_probe_req(struct ieee80211_sub_if_data *sdata,
tx_last_beacon = drv_tx_last_beacon(local);
-#ifdef CONFIG_MAC80211_IBSS_DEBUG
- printk(KERN_DEBUG "%s: RX ProbeReq SA=%pM DA=%pM BSSID=%pM"
- " (tx_last_beacon=%d)\n",
- sdata->name, mgmt->sa, mgmt->da,
- mgmt->bssid, tx_last_beacon);
-#endif /* CONFIG_MAC80211_IBSS_DEBUG */
+ ibss_vdbg("%s: RX ProbeReq SA=%pM DA=%pM BSSID=%pM (tx_last_beacon=%d)\n",
+ sdata->name, mgmt->sa, mgmt->da,
+ mgmt->bssid, tx_last_beacon);
if (!tx_last_beacon && is_multicast_ether_addr(mgmt->da))
return;
@@ -840,11 +812,8 @@ static void ieee80211_rx_mgmt_probe_req(struct ieee80211_sub_if_data *sdata,
pos = mgmt->u.probe_req.variable;
if (pos[0] != WLAN_EID_SSID ||
pos + 2 + pos[1] > end) {
-#ifdef CONFIG_MAC80211_IBSS_DEBUG
- printk(KERN_DEBUG "%s: Invalid SSID IE in ProbeReq "
- "from %pM\n",
- sdata->name, mgmt->sa);
-#endif
+ ibss_vdbg("%s: Invalid SSID IE in ProbeReq from %pM\n",
+ sdata->name, mgmt->sa);
return;
}
if (pos[1] != 0 &&
@@ -861,10 +830,7 @@ static void ieee80211_rx_mgmt_probe_req(struct ieee80211_sub_if_data *sdata,
resp = (struct ieee80211_mgmt *) skb->data;
memcpy(resp->da, mgmt->sa, ETH_ALEN);
-#ifdef CONFIG_MAC80211_IBSS_DEBUG
- printk(KERN_DEBUG "%s: Sending ProbeResp to %pM\n",
- sdata->name, resp->da);
-#endif /* CONFIG_MAC80211_IBSS_DEBUG */
+ ibss_vdbg("%s: Sending ProbeResp to %pM\n", sdata->name, resp->da);
IEEE80211_SKB_CB(skb)->flags |= IEEE80211_TX_INTFL_DONT_ENCRYPT;
ieee80211_tx_skb(sdata, skb);
}
diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h
index 3f3cd50fff1..e6cbf5b68c8 100644
--- a/net/mac80211/ieee80211_i.h
+++ b/net/mac80211/ieee80211_i.h
@@ -317,55 +317,30 @@ struct mesh_preq_queue {
u8 flags;
};
-enum ieee80211_work_type {
- IEEE80211_WORK_ABORT,
- IEEE80211_WORK_REMAIN_ON_CHANNEL,
- IEEE80211_WORK_OFFCHANNEL_TX,
-};
-
-/**
- * enum work_done_result - indicates what to do after work was done
- *
- * @WORK_DONE_DESTROY: This work item is no longer needed, destroy.
- * @WORK_DONE_REQUEUE: This work item was reset to be reused, and
- * should be requeued.
- */
-enum work_done_result {
- WORK_DONE_DESTROY,
- WORK_DONE_REQUEUE,
-};
+#if HZ/100 == 0
+#define IEEE80211_ROC_MIN_LEFT 1
+#else
+#define IEEE80211_ROC_MIN_LEFT (HZ/100)
+#endif
-struct ieee80211_work {
+struct ieee80211_roc_work {
struct list_head list;
+ struct list_head dependents;
- struct rcu_head rcu_head;
+ struct delayed_work work;
struct ieee80211_sub_if_data *sdata;
- enum work_done_result (*done)(struct ieee80211_work *wk,
- struct sk_buff *skb);
-
struct ieee80211_channel *chan;
enum nl80211_channel_type chan_type;
- unsigned long timeout;
- enum ieee80211_work_type type;
+ bool started, abort, hw_begun, notified;
- bool started;
+ unsigned long hw_start_time;
- union {
- struct {
- u32 duration;
- } remain;
- struct {
- struct sk_buff *frame;
- u32 wait;
- bool status;
- } offchan_tx;
- };
-
- size_t data_len;
- u8 data[];
+ u32 duration, req_duration;
+ struct sk_buff *frame;
+ u64 mgmt_tx_cookie;
};
/* flags used in struct ieee80211_if_managed.flags */
@@ -399,7 +374,6 @@ struct ieee80211_mgd_auth_data {
struct ieee80211_mgd_assoc_data {
struct cfg80211_bss *bss;
const u8 *supp_rates;
- const u8 *ht_operation_ie;
unsigned long timeout;
int tries;
@@ -414,6 +388,8 @@ struct ieee80211_mgd_assoc_data {
bool sent_assoc;
bool synced;
+ u8 ap_ht_param;
+
size_t ie_len;
u8 ie[];
};
@@ -847,13 +823,6 @@ struct ieee80211_local {
const struct ieee80211_ops *ops;
/*
- * work stuff, potentially off-channel (in the future)
- */
- struct list_head work_list;
- struct timer_list work_timer;
- struct work_struct work_work;
-
- /*
* private workqueue to mac80211. mac80211 makes this accessible
* via ieee80211_queue_work()
*/
@@ -1087,14 +1056,12 @@ struct ieee80211_local {
} debugfs;
#endif
- struct ieee80211_channel *hw_roc_channel;
- struct net_device *hw_roc_dev;
- struct sk_buff *hw_roc_skb, *hw_roc_skb_for_status;
+ /*
+ * Remain-on-channel support
+ */
+ struct list_head roc_list;
struct work_struct hw_roc_start, hw_roc_done;
- enum nl80211_channel_type hw_roc_channel_type;
- unsigned int hw_roc_duration;
- u32 hw_roc_cookie;
- bool hw_roc_for_tx;
+ unsigned long hw_roc_start_time;
struct idr ack_status_frames;
spinlock_t ack_status_lock;
@@ -1290,7 +1257,12 @@ void ieee80211_offchannel_stop_vifs(struct ieee80211_local *local,
bool offchannel_ps_enable);
void ieee80211_offchannel_return(struct ieee80211_local *local,
bool offchannel_ps_disable);
-void ieee80211_hw_roc_setup(struct ieee80211_local *local);
+void ieee80211_roc_setup(struct ieee80211_local *local);
+void ieee80211_start_next_roc(struct ieee80211_local *local);
+void ieee80211_roc_purge(struct ieee80211_sub_if_data *sdata);
+void ieee80211_roc_notify_destroy(struct ieee80211_roc_work *roc);
+void ieee80211_sw_roc_work(struct work_struct *work);
+void ieee80211_handle_roc_started(struct ieee80211_roc_work *roc);
/* interface handling */
int ieee80211_iface_init(void);
@@ -1500,18 +1472,6 @@ u8 *ieee80211_ie_build_ht_oper(u8 *pos, struct ieee80211_sta_ht_cap *ht_cap,
enum nl80211_channel_type channel_type,
u16 prot_mode);
-/* internal work items */
-void ieee80211_work_init(struct ieee80211_local *local);
-void ieee80211_add_work(struct ieee80211_work *wk);
-void free_work(struct ieee80211_work *wk);
-void ieee80211_work_purge(struct ieee80211_sub_if_data *sdata);
-int ieee80211_wk_remain_on_channel(struct ieee80211_sub_if_data *sdata,
- struct ieee80211_channel *chan,
- enum nl80211_channel_type channel_type,
- unsigned int duration, u64 *cookie);
-int ieee80211_wk_cancel_remain_on_channel(
- struct ieee80211_sub_if_data *sdata, u64 cookie);
-
/* channel management */
enum ieee80211_chan_mode {
CHAN_MODE_UNDEFINED,
diff --git a/net/mac80211/iface.c b/net/mac80211/iface.c
index d4c19a7773d..87aeb4f21ff 100644
--- a/net/mac80211/iface.c
+++ b/net/mac80211/iface.c
@@ -58,7 +58,7 @@ static int ieee80211_change_mtu(struct net_device *dev, int new_mtu)
}
#ifdef CONFIG_MAC80211_VERBOSE_DEBUG
- printk(KERN_DEBUG "%s: setting MTU %d\n", dev->name, new_mtu);
+ pr_debug("%s: setting MTU %d\n", dev->name, new_mtu);
#endif /* CONFIG_MAC80211_VERBOSE_DEBUG */
dev->mtu = new_mtu;
return 0;
@@ -528,10 +528,7 @@ static void ieee80211_do_stop(struct ieee80211_sub_if_data *sdata,
*/
netif_tx_stop_all_queues(sdata->dev);
- /*
- * Purge work for this interface.
- */
- ieee80211_work_purge(sdata);
+ ieee80211_roc_purge(sdata);
/*
* Remove all stations associated with this interface.
@@ -1226,7 +1223,7 @@ static void ieee80211_assign_perm_addr(struct ieee80211_local *local,
if (__ffs64(mask) + hweight64(mask) != fls64(mask)) {
/* not a contiguous mask ... not handled now! */
- printk(KERN_DEBUG "not contiguous\n");
+ pr_debug("not contiguous\n");
break;
}
@@ -1352,6 +1349,8 @@ int ieee80211_if_add(struct ieee80211_local *local, const char *name,
sdata->u.mgd.use_4addr = params->use_4addr;
}
+ ndev->features |= local->hw.netdev_features;
+
ret = register_netdevice(ndev);
if (ret)
goto fail;
@@ -1442,9 +1441,9 @@ u32 __ieee80211_recalc_idle(struct ieee80211_local *local)
{
struct ieee80211_sub_if_data *sdata;
int count = 0;
- bool working = false, scanning = false, hw_roc = false;
- struct ieee80211_work *wk;
+ bool working = false, scanning = false;
unsigned int led_trig_start = 0, led_trig_stop = 0;
+ struct ieee80211_roc_work *roc;
#ifdef CONFIG_PROVE_LOCKING
WARN_ON(debug_locks && !lockdep_rtnl_is_held() &&
@@ -1479,9 +1478,11 @@ u32 __ieee80211_recalc_idle(struct ieee80211_local *local)
count++;
}
- list_for_each_entry(wk, &local->work_list, list) {
- working = true;
- wk->sdata->vif.bss_conf.idle = false;
+ if (!local->ops->remain_on_channel) {
+ list_for_each_entry(roc, &local->roc_list, list) {
+ working = true;
+ roc->sdata->vif.bss_conf.idle = false;
+ }
}
if (local->scan_sdata &&
@@ -1490,9 +1491,6 @@ u32 __ieee80211_recalc_idle(struct ieee80211_local *local)
local->scan_sdata->vif.bss_conf.idle = false;
}
- if (local->hw_roc_channel)
- hw_roc = true;
-
list_for_each_entry(sdata, &local->interfaces, list) {
if (sdata->vif.type == NL80211_IFTYPE_MONITOR ||
sdata->vif.type == NL80211_IFTYPE_AP_VLAN)
@@ -1504,7 +1502,7 @@ u32 __ieee80211_recalc_idle(struct ieee80211_local *local)
ieee80211_bss_info_change_notify(sdata, BSS_CHANGED_IDLE);
}
- if (working || scanning || hw_roc)
+ if (working || scanning)
led_trig_start |= IEEE80211_TPT_LEDTRIG_FL_WORK;
else
led_trig_stop |= IEEE80211_TPT_LEDTRIG_FL_WORK;
@@ -1516,8 +1514,6 @@ u32 __ieee80211_recalc_idle(struct ieee80211_local *local)
ieee80211_mod_tpt_led_trig(local, led_trig_start, led_trig_stop);
- if (hw_roc)
- return ieee80211_idle_off(local, "hw remain-on-channel");
if (working)
return ieee80211_idle_off(local, "working");
if (scanning)
diff --git a/net/mac80211/main.c b/net/mac80211/main.c
index f5548e95325..d81c178c771 100644
--- a/net/mac80211/main.c
+++ b/net/mac80211/main.c
@@ -625,8 +625,6 @@ struct ieee80211_hw *ieee80211_alloc_hw(size_t priv_data_len,
INIT_DELAYED_WORK(&local->scan_work, ieee80211_scan_work);
- ieee80211_work_init(local);
-
INIT_WORK(&local->restart_work, ieee80211_restart_work);
INIT_WORK(&local->reconfig_filter, ieee80211_reconfig_filter);
@@ -669,7 +667,7 @@ struct ieee80211_hw *ieee80211_alloc_hw(size_t priv_data_len,
ieee80211_led_names(local);
- ieee80211_hw_roc_setup(local);
+ ieee80211_roc_setup(local);
return &local->hw;
}
@@ -682,6 +680,7 @@ int ieee80211_register_hw(struct ieee80211_hw *hw)
enum ieee80211_band band;
int channels, max_bitrates;
bool supp_ht;
+ netdev_features_t feature_whitelist;
static const u32 cipher_suites[] = {
/* keep WEP first, it may be removed below */
WLAN_CIPHER_SUITE_WEP40,
@@ -708,6 +707,12 @@ int ieee80211_register_hw(struct ieee80211_hw *hw)
if ((hw->flags & IEEE80211_HW_SCAN_WHILE_IDLE) && !local->ops->hw_scan)
return -EINVAL;
+ /* Only HW csum features are currently compatible with mac80211 */
+ feature_whitelist = NETIF_F_IP_CSUM | NETIF_F_IPV6_CSUM |
+ NETIF_F_HW_CSUM;
+ if (WARN_ON(hw->netdev_features & ~feature_whitelist))
+ return -EINVAL;
+
if (hw->max_report_rates == 0)
hw->max_report_rates = hw->max_rates;
@@ -1009,12 +1014,6 @@ void ieee80211_unregister_hw(struct ieee80211_hw *hw)
rtnl_unlock();
- /*
- * Now all work items will be gone, but the
- * timer might still be armed, so delete it
- */
- del_timer_sync(&local->work_timer);
-
cancel_work_sync(&local->restart_work);
cancel_work_sync(&local->reconfig_filter);
diff --git a/net/mac80211/mesh.c b/net/mac80211/mesh.c
index 2913113c583..7cf19509fb6 100644
--- a/net/mac80211/mesh.c
+++ b/net/mac80211/mesh.c
@@ -524,8 +524,7 @@ static void ieee80211_mesh_housekeeping(struct ieee80211_sub_if_data *sdata,
bool free_plinks;
#ifdef CONFIG_MAC80211_VERBOSE_DEBUG
- printk(KERN_DEBUG "%s: running mesh housekeeping\n",
- sdata->name);
+ pr_debug("%s: running mesh housekeeping\n", sdata->name);
#endif
ieee80211_sta_expire(sdata, IEEE80211_MESH_PEER_INACTIVITY_LIMIT);
diff --git a/net/mac80211/mesh_hwmp.c b/net/mac80211/mesh_hwmp.c
index 9b59658e865..fa7c5803524 100644
--- a/net/mac80211/mesh_hwmp.c
+++ b/net/mac80211/mesh_hwmp.c
@@ -15,7 +15,7 @@
#ifdef CONFIG_MAC80211_VERBOSE_MHWMP_DEBUG
#define mhwmp_dbg(fmt, args...) \
- printk(KERN_DEBUG "Mesh HWMP (%s): " fmt "\n", sdata->name, ##args)
+ pr_debug("Mesh HWMP (%s): " fmt "\n", sdata->name, ##args)
#else
#define mhwmp_dbg(fmt, args...) do { (void)(0); } while (0)
#endif
diff --git a/net/mac80211/mesh_pathtbl.c b/net/mac80211/mesh_pathtbl.c
index b39224d8255..572f706fd65 100644
--- a/net/mac80211/mesh_pathtbl.c
+++ b/net/mac80211/mesh_pathtbl.c
@@ -19,7 +19,7 @@
#include "mesh.h"
#ifdef CONFIG_MAC80211_VERBOSE_MPATH_DEBUG
-#define mpath_dbg(fmt, args...) printk(KERN_DEBUG fmt, ##args)
+#define mpath_dbg(fmt, args...) pr_debug(fmt, ##args)
#else
#define mpath_dbg(fmt, args...) do { (void)(0); } while (0)
#endif
diff --git a/net/mac80211/mesh_plink.c b/net/mac80211/mesh_plink.c
index 60ef235c9d9..be4fad128c3 100644
--- a/net/mac80211/mesh_plink.c
+++ b/net/mac80211/mesh_plink.c
@@ -14,7 +14,7 @@
#include "mesh.h"
#ifdef CONFIG_MAC80211_VERBOSE_MPL_DEBUG
-#define mpl_dbg(fmt, args...) printk(KERN_DEBUG fmt, ##args)
+#define mpl_dbg(fmt, args...) pr_debug(fmt, ##args)
#else
#define mpl_dbg(fmt, args...) do { (void)(0); } while (0)
#endif
diff --git a/net/mac80211/mesh_sync.c b/net/mac80211/mesh_sync.c
index 38d30e8ce6d..0ccdad49f98 100644
--- a/net/mac80211/mesh_sync.c
+++ b/net/mac80211/mesh_sync.c
@@ -14,7 +14,7 @@
#ifdef CONFIG_MAC80211_VERBOSE_MESH_SYNC_DEBUG
#define msync_dbg(fmt, args...) \
- printk(KERN_DEBUG "Mesh sync (%s): " fmt "\n", sdata->name, ##args)
+ pr_debug("Mesh sync (%s): " fmt "\n", sdata->name, ##args)
#else
#define msync_dbg(fmt, args...) do { (void)(0); } while (0)
#endif
diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c
index 04c30630898..0f45d02e0ba 100644
--- a/net/mac80211/mlme.c
+++ b/net/mac80211/mlme.c
@@ -258,12 +258,11 @@ static int ieee80211_compatible_rates(const u8 *supp_rates, int supp_rates_len,
}
static void ieee80211_add_ht_ie(struct ieee80211_sub_if_data *sdata,
- struct sk_buff *skb, const u8 *ht_oper_ie,
+ struct sk_buff *skb, u8 ap_ht_param,
struct ieee80211_supported_band *sband,
struct ieee80211_channel *channel,
enum ieee80211_smps_mode smps)
{
- struct ieee80211_ht_operation *ht_oper;
u8 *pos;
u32 flags = channel->flags;
u16 cap;
@@ -271,21 +270,13 @@ static void ieee80211_add_ht_ie(struct ieee80211_sub_if_data *sdata,
BUILD_BUG_ON(sizeof(ht_cap) != sizeof(sband->ht_cap));
- if (!ht_oper_ie)
- return;
-
- if (ht_oper_ie[1] < sizeof(struct ieee80211_ht_operation))
- return;
-
memcpy(&ht_cap, &sband->ht_cap, sizeof(ht_cap));
ieee80211_apply_htcap_overrides(sdata, &ht_cap);
- ht_oper = (struct ieee80211_ht_operation *)(ht_oper_ie + 2);
-
/* determine capability flags */
cap = ht_cap.cap;
- switch (ht_oper->ht_param & IEEE80211_HT_PARAM_CHA_SEC_OFFSET) {
+ switch (ap_ht_param & IEEE80211_HT_PARAM_CHA_SEC_OFFSET) {
case IEEE80211_HT_PARAM_CHA_SEC_ABOVE:
if (flags & IEEE80211_CHAN_NO_HT40PLUS) {
cap &= ~IEEE80211_HT_CAP_SUP_WIDTH_20_40;
@@ -509,7 +500,7 @@ static void ieee80211_send_assoc(struct ieee80211_sub_if_data *sdata)
}
if (!(ifmgd->flags & IEEE80211_STA_DISABLE_11N))
- ieee80211_add_ht_ie(sdata, skb, assoc_data->ht_operation_ie,
+ ieee80211_add_ht_ie(sdata, skb, assoc_data->ap_ht_param,
sband, local->oper_channel, ifmgd->ap_smps);
/* if present, add any custom non-vendor IEs that go after HT */
@@ -939,11 +930,6 @@ void ieee80211_recalc_ps(struct ieee80211_local *local, s32 latency)
return;
}
- if (!list_empty(&local->work_list)) {
- local->ps_sdata = NULL;
- goto change;
- }
-
list_for_each_entry(sdata, &local->interfaces, list) {
if (!ieee80211_sdata_running(sdata))
continue;
@@ -1016,7 +1002,6 @@ void ieee80211_recalc_ps(struct ieee80211_local *local, s32 latency)
local->ps_sdata = NULL;
}
- change:
ieee80211_change_ps(local);
}
@@ -1220,6 +1205,22 @@ static void ieee80211_sta_wmm_params(struct ieee80211_local *local,
sdata->vif.bss_conf.qos = true;
}
+static void __ieee80211_stop_poll(struct ieee80211_sub_if_data *sdata)
+{
+ lockdep_assert_held(&sdata->local->mtx);
+
+ sdata->u.mgd.flags &= ~(IEEE80211_STA_CONNECTION_POLL |
+ IEEE80211_STA_BEACON_POLL);
+ ieee80211_run_deferred_scan(sdata->local);
+}
+
+static void ieee80211_stop_poll(struct ieee80211_sub_if_data *sdata)
+{
+ mutex_lock(&sdata->local->mtx);
+ __ieee80211_stop_poll(sdata);
+ mutex_unlock(&sdata->local->mtx);
+}
+
static u32 ieee80211_handle_bss_capability(struct ieee80211_sub_if_data *sdata,
u16 capab, bool erp_valid, u8 erp)
{
@@ -1285,8 +1286,7 @@ static void ieee80211_set_associated(struct ieee80211_sub_if_data *sdata,
sdata->u.mgd.flags |= IEEE80211_STA_RESET_SIGNAL_AVE;
/* just to be sure */
- sdata->u.mgd.flags &= ~(IEEE80211_STA_CONNECTION_POLL |
- IEEE80211_STA_BEACON_POLL);
+ ieee80211_stop_poll(sdata);
ieee80211_led_assoc(local, 1);
@@ -1456,8 +1456,7 @@ static void ieee80211_reset_ap_probe(struct ieee80211_sub_if_data *sdata)
return;
}
- ifmgd->flags &= ~(IEEE80211_STA_CONNECTION_POLL |
- IEEE80211_STA_BEACON_POLL);
+ __ieee80211_stop_poll(sdata);
mutex_lock(&local->iflist_mtx);
ieee80211_recalc_ps(local, -1);
@@ -1477,7 +1476,6 @@ static void ieee80211_reset_ap_probe(struct ieee80211_sub_if_data *sdata)
round_jiffies_up(jiffies +
IEEE80211_CONNECTION_IDLE_TIME));
out:
- ieee80211_run_deferred_scan(local);
mutex_unlock(&local->mtx);
}
@@ -1572,6 +1570,8 @@ static void ieee80211_mgd_probe_ap(struct ieee80211_sub_if_data *sdata,
net_dbg_ratelimited("%s: detected beacon loss from AP - sending probe request\n",
sdata->name);
#endif
+ ieee80211_cqm_rssi_notify(&sdata->vif,
+ NL80211_CQM_RSSI_BEACON_LOSS_EVENT, GFP_KERNEL);
/*
* The driver/our work has already reported this event or the
@@ -1654,8 +1654,7 @@ static void __ieee80211_connection_loss(struct ieee80211_sub_if_data *sdata)
memcpy(bssid, ifmgd->associated->bssid, ETH_ALEN);
- printk(KERN_DEBUG "%s: Connection to AP %pM lost.\n",
- sdata->name, bssid);
+ pr_debug("%s: Connection to AP %pM lost\n", sdata->name, bssid);
ieee80211_set_disassoc(sdata, IEEE80211_STYPE_DEAUTH,
WLAN_REASON_DISASSOC_DUE_TO_INACTIVITY,
@@ -1789,9 +1788,10 @@ ieee80211_rx_mgmt_auth(struct ieee80211_sub_if_data *sdata,
return RX_MGMT_NONE;
if (status_code != WLAN_STATUS_SUCCESS) {
- printk(KERN_DEBUG "%s: %pM denied authentication (status %d)\n",
- sdata->name, mgmt->sa, status_code);
- goto out;
+ pr_debug("%s: %pM denied authentication (status %d)\n",
+ sdata->name, mgmt->sa, status_code);
+ ieee80211_destroy_auth_data(sdata, false);
+ return RX_MGMT_CFG80211_RX_AUTH;
}
switch (ifmgd->auth_data->algorithm) {
@@ -1812,8 +1812,7 @@ ieee80211_rx_mgmt_auth(struct ieee80211_sub_if_data *sdata,
return RX_MGMT_NONE;
}
- printk(KERN_DEBUG "%s: authenticated\n", sdata->name);
- out:
+ pr_debug("%s: authenticated\n", sdata->name);
ifmgd->auth_data->done = true;
ifmgd->auth_data->timeout = jiffies + IEEE80211_AUTH_WAIT_ASSOC;
run_again(ifmgd, ifmgd->auth_data->timeout);
@@ -1826,8 +1825,7 @@ ieee80211_rx_mgmt_auth(struct ieee80211_sub_if_data *sdata,
goto out_err;
}
if (sta_info_move_state(sta, IEEE80211_STA_AUTH)) {
- printk(KERN_DEBUG "%s: failed moving %pM to auth\n",
- sdata->name, bssid);
+ pr_debug("%s: failed moving %pM to auth\n", sdata->name, bssid);
goto out_err;
}
mutex_unlock(&sdata->local->sta_mtx);
@@ -1861,8 +1859,8 @@ ieee80211_rx_mgmt_deauth(struct ieee80211_sub_if_data *sdata,
reason_code = le16_to_cpu(mgmt->u.deauth.reason_code);
- printk(KERN_DEBUG "%s: deauthenticated from %pM (Reason: %u)\n",
- sdata->name, bssid, reason_code);
+ pr_debug("%s: deauthenticated from %pM (Reason: %u)\n",
+ sdata->name, bssid, reason_code);
ieee80211_set_disassoc(sdata, 0, 0, false, NULL);
@@ -1892,8 +1890,8 @@ ieee80211_rx_mgmt_disassoc(struct ieee80211_sub_if_data *sdata,
reason_code = le16_to_cpu(mgmt->u.disassoc.reason_code);
- printk(KERN_DEBUG "%s: disassociated from %pM (Reason: %u)\n",
- sdata->name, mgmt->sa, reason_code);
+ pr_debug("%s: disassociated from %pM (Reason: %u)\n",
+ sdata->name, mgmt->sa, reason_code);
ieee80211_set_disassoc(sdata, 0, 0, false, NULL);
@@ -1985,17 +1983,15 @@ static bool ieee80211_assoc_success(struct ieee80211_sub_if_data *sdata,
capab_info = le16_to_cpu(mgmt->u.assoc_resp.capab_info);
if ((aid & (BIT(15) | BIT(14))) != (BIT(15) | BIT(14)))
- printk(KERN_DEBUG
- "%s: invalid AID value 0x%x; bits 15:14 not set\n",
- sdata->name, aid);
+ pr_debug("%s: invalid AID value 0x%x; bits 15:14 not set\n",
+ sdata->name, aid);
aid &= ~(BIT(15) | BIT(14));
ifmgd->broken_ap = false;
if (aid == 0 || aid > IEEE80211_MAX_AID) {
- printk(KERN_DEBUG
- "%s: invalid AID value %d (out of range), turn off PS\n",
- sdata->name, aid);
+ pr_debug("%s: invalid AID value %d (out of range), turn off PS\n",
+ sdata->name, aid);
aid = 0;
ifmgd->broken_ap = true;
}
@@ -2004,8 +2000,8 @@ static bool ieee80211_assoc_success(struct ieee80211_sub_if_data *sdata,
ieee802_11_parse_elems(pos, len - (pos - (u8 *) mgmt), &elems);
if (!elems.supp_rates) {
- printk(KERN_DEBUG "%s: no SuppRates element in AssocResp\n",
- sdata->name);
+ pr_debug("%s: no SuppRates element in AssocResp\n",
+ sdata->name);
return false;
}
@@ -2045,9 +2041,8 @@ static bool ieee80211_assoc_success(struct ieee80211_sub_if_data *sdata,
if (!err && !(ifmgd->flags & IEEE80211_STA_CONTROL_PORT))
err = sta_info_move_state(sta, IEEE80211_STA_AUTHORIZED);
if (err) {
- printk(KERN_DEBUG
- "%s: failed to move station %pM to desired state\n",
- sdata->name, sta->sta.addr);
+ pr_debug("%s: failed to move station %pM to desired state\n",
+ sdata->name, sta->sta.addr);
WARN_ON(__sta_info_destroy(sta));
mutex_unlock(&sdata->local->sta_mtx);
return false;
@@ -2130,10 +2125,9 @@ ieee80211_rx_mgmt_assoc_resp(struct ieee80211_sub_if_data *sdata,
status_code = le16_to_cpu(mgmt->u.assoc_resp.status_code);
aid = le16_to_cpu(mgmt->u.assoc_resp.aid);
- printk(KERN_DEBUG "%s: RX %sssocResp from %pM (capab=0x%x "
- "status=%d aid=%d)\n",
- sdata->name, reassoc ? "Rea" : "A", mgmt->sa,
- capab_info, status_code, (u16)(aid & ~(BIT(15) | BIT(14))));
+ pr_debug("%s: RX %sssocResp from %pM (capab=0x%x status=%d aid=%d)\n",
+ sdata->name, reassoc ? "Rea" : "A", mgmt->sa,
+ capab_info, status_code, (u16)(aid & ~(BIT(15) | BIT(14))));
pos = mgmt->u.assoc_resp.variable;
ieee802_11_parse_elems(pos, len - (pos - (u8 *) mgmt), &elems);
@@ -2144,9 +2138,8 @@ ieee80211_rx_mgmt_assoc_resp(struct ieee80211_sub_if_data *sdata,
u32 tu, ms;
tu = get_unaligned_le32(elems.timeout_int + 1);
ms = tu * 1024 / 1000;
- printk(KERN_DEBUG "%s: %pM rejected association temporarily; "
- "comeback duration %u TU (%u ms)\n",
- sdata->name, mgmt->sa, tu, ms);
+ pr_debug("%s: %pM rejected association temporarily; comeback duration %u TU (%u ms)\n",
+ sdata->name, mgmt->sa, tu, ms);
assoc_data->timeout = jiffies + msecs_to_jiffies(ms);
if (ms > IEEE80211_ASSOC_TIMEOUT)
run_again(ifmgd, assoc_data->timeout);
@@ -2156,11 +2149,11 @@ ieee80211_rx_mgmt_assoc_resp(struct ieee80211_sub_if_data *sdata,
*bss = assoc_data->bss;
if (status_code != WLAN_STATUS_SUCCESS) {
- printk(KERN_DEBUG "%s: %pM denied association (code=%d)\n",
- sdata->name, mgmt->sa, status_code);
+ pr_debug("%s: %pM denied association (code=%d)\n",
+ sdata->name, mgmt->sa, status_code);
ieee80211_destroy_assoc_data(sdata, false);
} else {
- printk(KERN_DEBUG "%s: associated\n", sdata->name);
+ pr_debug("%s: associated\n", sdata->name);
if (!ieee80211_assoc_success(sdata, *bss, mgmt, len)) {
/* oops -- internal error -- send timeout for now */
@@ -2268,7 +2261,7 @@ static void ieee80211_rx_mgmt_probe_resp(struct ieee80211_sub_if_data *sdata,
if (ifmgd->auth_data && !ifmgd->auth_data->bss->proberesp_ies &&
ether_addr_equal(mgmt->bssid, ifmgd->auth_data->bss->bssid)) {
/* got probe response, continue with auth */
- printk(KERN_DEBUG "%s: direct probe responded\n", sdata->name);
+ pr_debug("%s: direct probe responded\n", sdata->name);
ifmgd->auth_data->tries = 0;
ifmgd->auth_data->timeout = jiffies;
run_again(ifmgd, ifmgd->auth_data->timeout);
@@ -2408,7 +2401,11 @@ static void ieee80211_rx_mgmt_beacon(struct ieee80211_sub_if_data *sdata,
net_dbg_ratelimited("%s: cancelling probereq poll due to a received beacon\n",
sdata->name);
#endif
+ mutex_lock(&local->mtx);
ifmgd->flags &= ~IEEE80211_STA_BEACON_POLL;
+ ieee80211_run_deferred_scan(local);
+ mutex_unlock(&local->mtx);
+
mutex_lock(&local->iflist_mtx);
ieee80211_recalc_ps(local, -1);
mutex_unlock(&local->iflist_mtx);
@@ -2595,8 +2592,7 @@ static void ieee80211_sta_connection_lost(struct ieee80211_sub_if_data *sdata,
struct ieee80211_if_managed *ifmgd = &sdata->u.mgd;
u8 frame_buf[DEAUTH_DISASSOC_LEN];
- ifmgd->flags &= ~(IEEE80211_STA_CONNECTION_POLL |
- IEEE80211_STA_BEACON_POLL);
+ ieee80211_stop_poll(sdata);
ieee80211_set_disassoc(sdata, IEEE80211_STYPE_DEAUTH, reason,
false, frame_buf);
@@ -2629,8 +2625,8 @@ static int ieee80211_probe_auth(struct ieee80211_sub_if_data *sdata)
auth_data->tries++;
if (auth_data->tries > IEEE80211_AUTH_MAX_TRIES) {
- printk(KERN_DEBUG "%s: authentication with %pM timed out\n",
- sdata->name, auth_data->bss->bssid);
+ pr_debug("%s: authentication with %pM timed out\n",
+ sdata->name, auth_data->bss->bssid);
/*
* Most likely AP is not in the range so remove the
@@ -2642,9 +2638,9 @@ static int ieee80211_probe_auth(struct ieee80211_sub_if_data *sdata)
}
if (auth_data->bss->proberesp_ies) {
- printk(KERN_DEBUG "%s: send auth to %pM (try %d/%d)\n",
- sdata->name, auth_data->bss->bssid, auth_data->tries,
- IEEE80211_AUTH_MAX_TRIES);
+ pr_debug("%s: send auth to %pM (try %d/%d)\n",
+ sdata->name, auth_data->bss->bssid, auth_data->tries,
+ IEEE80211_AUTH_MAX_TRIES);
auth_data->expected_transaction = 2;
ieee80211_send_auth(sdata, 1, auth_data->algorithm,
@@ -2654,9 +2650,9 @@ static int ieee80211_probe_auth(struct ieee80211_sub_if_data *sdata)
} else {
const u8 *ssidie;
- printk(KERN_DEBUG "%s: direct probe to %pM (try %d/%i)\n",
- sdata->name, auth_data->bss->bssid, auth_data->tries,
- IEEE80211_AUTH_MAX_TRIES);
+ pr_debug("%s: direct probe to %pM (try %d/%i)\n",
+ sdata->name, auth_data->bss->bssid, auth_data->tries,
+ IEEE80211_AUTH_MAX_TRIES);
ssidie = ieee80211_bss_get_ie(auth_data->bss, WLAN_EID_SSID);
if (!ssidie)
@@ -2684,8 +2680,8 @@ static int ieee80211_do_assoc(struct ieee80211_sub_if_data *sdata)
assoc_data->tries++;
if (assoc_data->tries > IEEE80211_ASSOC_MAX_TRIES) {
- printk(KERN_DEBUG "%s: association with %pM timed out\n",
- sdata->name, assoc_data->bss->bssid);
+ pr_debug("%s: association with %pM timed out\n",
+ sdata->name, assoc_data->bss->bssid);
/*
* Most likely AP is not in the range so remove the
@@ -2696,9 +2692,9 @@ static int ieee80211_do_assoc(struct ieee80211_sub_if_data *sdata)
return -ETIMEDOUT;
}
- printk(KERN_DEBUG "%s: associate with %pM (try %d/%d)\n",
- sdata->name, assoc_data->bss->bssid, assoc_data->tries,
- IEEE80211_ASSOC_MAX_TRIES);
+ pr_debug("%s: associate with %pM (try %d/%d)\n",
+ sdata->name, assoc_data->bss->bssid, assoc_data->tries,
+ IEEE80211_ASSOC_MAX_TRIES);
ieee80211_send_assoc(sdata);
assoc_data->timeout = jiffies + IEEE80211_ASSOC_TIMEOUT;
@@ -2874,8 +2870,7 @@ static void ieee80211_restart_sta_timer(struct ieee80211_sub_if_data *sdata)
u32 flags;
if (sdata->vif.type == NL80211_IFTYPE_STATION) {
- sdata->u.mgd.flags &= ~(IEEE80211_STA_BEACON_POLL |
- IEEE80211_STA_CONNECTION_POLL);
+ __ieee80211_stop_poll(sdata);
/* let's probe the connection once */
flags = sdata->local->hw.flags;
@@ -2944,7 +2939,10 @@ void ieee80211_sta_restart(struct ieee80211_sub_if_data *sdata)
if (test_and_clear_bit(TMR_RUNNING_CHANSW, &ifmgd->timers_running))
add_timer(&ifmgd->chswitch_timer);
ieee80211_sta_reset_beacon_monitor(sdata);
+
+ mutex_lock(&sdata->local->mtx);
ieee80211_restart_sta_timer(sdata);
+ mutex_unlock(&sdata->local->mtx);
}
#endif
@@ -3067,13 +3065,10 @@ static int ieee80211_prep_connection(struct ieee80211_sub_if_data *sdata,
* since we look at probe response/beacon data here
* it should be OK.
*/
- printk(KERN_DEBUG
- "%s: Wrong control channel: center-freq: %d"
- " ht-cfreq: %d ht->primary_chan: %d"
- " band: %d. Disabling HT.\n",
- sdata->name, cbss->channel->center_freq,
- ht_cfreq, ht_oper->primary_chan,
- cbss->channel->band);
+ pr_debug("%s: Wrong control channel: center-freq: %d ht-cfreq: %d ht->primary_chan: %d band: %d - Disabling HT\n",
+ sdata->name, cbss->channel->center_freq,
+ ht_cfreq, ht_oper->primary_chan,
+ cbss->channel->band);
ht_oper = NULL;
}
}
@@ -3097,9 +3092,8 @@ static int ieee80211_prep_connection(struct ieee80211_sub_if_data *sdata,
if (!ieee80211_set_channel_type(local, sdata, channel_type)) {
/* can only fail due to HT40+/- mismatch */
channel_type = NL80211_CHAN_HT20;
- printk(KERN_DEBUG
- "%s: disabling 40 MHz due to multi-vif mismatch\n",
- sdata->name);
+ pr_debug("%s: disabling 40 MHz due to multi-vif mismatch\n",
+ sdata->name);
ifmgd->flags |= IEEE80211_STA_DISABLE_40MHZ;
WARN_ON(!ieee80211_set_channel_type(local, sdata,
channel_type));
@@ -3128,9 +3122,8 @@ static int ieee80211_prep_connection(struct ieee80211_sub_if_data *sdata,
* we can connect -- with a warning.
*/
if (!basic_rates && min_rate_index >= 0) {
- printk(KERN_DEBUG
- "%s: No basic rates, using min rate instead.\n",
- sdata->name);
+ pr_debug("%s: No basic rates, using min rate instead\n",
+ sdata->name);
basic_rates = BIT(min_rate_index);
}
@@ -3156,9 +3149,8 @@ static int ieee80211_prep_connection(struct ieee80211_sub_if_data *sdata,
err = sta_info_insert(sta);
sta = NULL;
if (err) {
- printk(KERN_DEBUG
- "%s: failed to insert STA entry for the AP (error %d)\n",
- sdata->name, err);
+ pr_debug("%s: failed to insert STA entry for the AP (error %d)\n",
+ sdata->name, err);
return err;
}
} else
@@ -3236,8 +3228,7 @@ int ieee80211_mgd_auth(struct ieee80211_sub_if_data *sdata,
if (ifmgd->associated)
ieee80211_set_disassoc(sdata, 0, 0, false, NULL);
- printk(KERN_DEBUG "%s: authenticate with %pM\n",
- sdata->name, req->bss->bssid);
+ pr_debug("%s: authenticate with %pM\n", sdata->name, req->bss->bssid);
err = ieee80211_prep_connection(sdata, req->bss, false);
if (err)
@@ -3272,7 +3263,7 @@ int ieee80211_mgd_assoc(struct ieee80211_sub_if_data *sdata,
struct ieee80211_bss *bss = (void *)req->bss->priv;
struct ieee80211_mgd_assoc_data *assoc_data;
struct ieee80211_supported_band *sband;
- const u8 *ssidie;
+ const u8 *ssidie, *ht_ie;
int i, err;
ssidie = ieee80211_bss_get_ie(req->bss, WLAN_EID_SSID);
@@ -3320,11 +3311,15 @@ int ieee80211_mgd_assoc(struct ieee80211_sub_if_data *sdata,
* We can set this to true for non-11n hardware, that'll be checked
* separately along with the peer capabilities.
*/
- for (i = 0; i < req->crypto.n_ciphers_pairwise; i++)
+ for (i = 0; i < req->crypto.n_ciphers_pairwise; i++) {
if (req->crypto.ciphers_pairwise[i] == WLAN_CIPHER_SUITE_WEP40 ||
req->crypto.ciphers_pairwise[i] == WLAN_CIPHER_SUITE_TKIP ||
- req->crypto.ciphers_pairwise[i] == WLAN_CIPHER_SUITE_WEP104)
+ req->crypto.ciphers_pairwise[i] == WLAN_CIPHER_SUITE_WEP104) {
ifmgd->flags |= IEEE80211_STA_DISABLE_11N;
+ netdev_info(sdata->dev,
+ "disabling HT due to WEP/TKIP use\n");
+ }
+ }
if (req->flags & ASSOC_REQ_DISABLE_HT)
ifmgd->flags |= IEEE80211_STA_DISABLE_11N;
@@ -3332,8 +3327,11 @@ int ieee80211_mgd_assoc(struct ieee80211_sub_if_data *sdata,
/* Also disable HT if we don't support it or the AP doesn't use WMM */
sband = local->hw.wiphy->bands[req->bss->channel->band];
if (!sband->ht_cap.ht_supported ||
- local->hw.queues < IEEE80211_NUM_ACS || !bss->wmm_used)
+ local->hw.queues < IEEE80211_NUM_ACS || !bss->wmm_used) {
ifmgd->flags |= IEEE80211_STA_DISABLE_11N;
+ netdev_info(sdata->dev,
+ "disabling HT as WMM/QoS is not supported\n");
+ }
memcpy(&ifmgd->ht_capa, &req->ht_capa, sizeof(ifmgd->ht_capa));
memcpy(&ifmgd->ht_capa_mask, &req->ht_capa_mask,
@@ -3359,8 +3357,13 @@ int ieee80211_mgd_assoc(struct ieee80211_sub_if_data *sdata,
(local->hw.queues >= IEEE80211_NUM_ACS);
assoc_data->supp_rates = bss->supp_rates;
assoc_data->supp_rates_len = bss->supp_rates_len;
- assoc_data->ht_operation_ie =
- ieee80211_bss_get_ie(req->bss, WLAN_EID_HT_OPERATION);
+
+ ht_ie = ieee80211_bss_get_ie(req->bss, WLAN_EID_HT_OPERATION);
+ if (ht_ie && ht_ie[1] >= sizeof(struct ieee80211_ht_operation))
+ assoc_data->ap_ht_param =
+ ((struct ieee80211_ht_operation *)(ht_ie + 2))->ht_param;
+ else
+ ifmgd->flags |= IEEE80211_STA_DISABLE_11N;
if (bss->wmm_used && bss->uapsd_supported &&
(sdata->local->hw.flags & IEEE80211_HW_SUPPORTS_UAPSD)) {
@@ -3407,8 +3410,8 @@ int ieee80211_mgd_assoc(struct ieee80211_sub_if_data *sdata,
* Wait up to one beacon interval ...
* should this be more if we miss one?
*/
- printk(KERN_DEBUG "%s: waiting for beacon from %pM\n",
- sdata->name, ifmgd->bssid);
+ pr_debug("%s: waiting for beacon from %pM\n",
+ sdata->name, ifmgd->bssid);
assoc_data->timeout = TU_TO_EXP_TIME(req->bss->beacon_interval);
} else {
assoc_data->have_beacon = true;
@@ -3427,8 +3430,8 @@ int ieee80211_mgd_assoc(struct ieee80211_sub_if_data *sdata,
corrupt_type = "beacon";
} else if (bss->corrupt_data & IEEE80211_BSS_CORRUPT_PROBE_RESP)
corrupt_type = "probe response";
- printk(KERN_DEBUG "%s: associating with AP with corrupt %s\n",
- sdata->name, corrupt_type);
+ pr_debug("%s: associating with AP with corrupt %s\n",
+ sdata->name, corrupt_type);
}
err = 0;
@@ -3457,9 +3460,8 @@ int ieee80211_mgd_deauth(struct ieee80211_sub_if_data *sdata,
return 0;
}
- printk(KERN_DEBUG
- "%s: deauthenticating from %pM by local choice (reason=%d)\n",
- sdata->name, req->bssid, req->reason_code);
+ pr_debug("%s: deauthenticating from %pM by local choice (reason=%d)\n",
+ sdata->name, req->bssid, req->reason_code);
if (ifmgd->associated &&
ether_addr_equal(ifmgd->associated->bssid, req->bssid))
@@ -3501,8 +3503,8 @@ int ieee80211_mgd_disassoc(struct ieee80211_sub_if_data *sdata,
return -ENOLINK;
}
- printk(KERN_DEBUG "%s: disassociating from %pM by local choice (reason=%d)\n",
- sdata->name, req->bss->bssid, req->reason_code);
+ pr_debug("%s: disassociating from %pM by local choice (reason=%d)\n",
+ sdata->name, req->bss->bssid, req->reason_code);
memcpy(bssid, req->bss->bssid, ETH_ALEN);
ieee80211_set_disassoc(sdata, IEEE80211_STYPE_DISASSOC,
@@ -3543,10 +3545,3 @@ void ieee80211_cqm_rssi_notify(struct ieee80211_vif *vif,
cfg80211_cqm_rssi_notify(sdata->dev, rssi_event, gfp);
}
EXPORT_SYMBOL(ieee80211_cqm_rssi_notify);
-
-unsigned char ieee80211_get_operstate(struct ieee80211_vif *vif)
-{
- struct ieee80211_sub_if_data *sdata = vif_to_sdata(vif);
- return sdata->dev->operstate;
-}
-EXPORT_SYMBOL(ieee80211_get_operstate);
diff --git a/net/mac80211/offchannel.c b/net/mac80211/offchannel.c
index f054e94901a..abb226dc475 100644
--- a/net/mac80211/offchannel.c
+++ b/net/mac80211/offchannel.c
@@ -16,6 +16,7 @@
#include <net/mac80211.h>
#include "ieee80211_i.h"
#include "driver-trace.h"
+#include "driver-ops.h"
/*
* Tell our hardware to disable PS.
@@ -181,34 +182,58 @@ void ieee80211_offchannel_return(struct ieee80211_local *local,
mutex_unlock(&local->iflist_mtx);
}
+void ieee80211_handle_roc_started(struct ieee80211_roc_work *roc)
+{
+ if (roc->notified)
+ return;
+
+ if (roc->mgmt_tx_cookie) {
+ if (!WARN_ON(!roc->frame)) {
+ ieee80211_tx_skb(roc->sdata, roc->frame);
+ roc->frame = NULL;
+ }
+ } else {
+ cfg80211_ready_on_channel(roc->sdata->dev, (unsigned long)roc,
+ roc->chan, roc->chan_type,
+ roc->req_duration, GFP_KERNEL);
+ }
+
+ roc->notified = true;
+}
+
static void ieee80211_hw_roc_start(struct work_struct *work)
{
struct ieee80211_local *local =
container_of(work, struct ieee80211_local, hw_roc_start);
- struct ieee80211_sub_if_data *sdata;
+ struct ieee80211_roc_work *roc, *dep, *tmp;
mutex_lock(&local->mtx);
- if (!local->hw_roc_channel) {
- mutex_unlock(&local->mtx);
- return;
- }
+ if (list_empty(&local->roc_list))
+ goto out_unlock;
- if (local->hw_roc_skb) {
- sdata = IEEE80211_DEV_TO_SUB_IF(local->hw_roc_dev);
- ieee80211_tx_skb(sdata, local->hw_roc_skb);
- local->hw_roc_skb = NULL;
- } else {
- cfg80211_ready_on_channel(local->hw_roc_dev,
- local->hw_roc_cookie,
- local->hw_roc_channel,
- local->hw_roc_channel_type,
- local->hw_roc_duration,
- GFP_KERNEL);
- }
+ roc = list_first_entry(&local->roc_list, struct ieee80211_roc_work,
+ list);
+
+ if (!roc->started)
+ goto out_unlock;
- ieee80211_recalc_idle(local);
+ roc->hw_begun = true;
+ roc->hw_start_time = local->hw_roc_start_time;
+ ieee80211_handle_roc_started(roc);
+ list_for_each_entry_safe(dep, tmp, &roc->dependents, list) {
+ ieee80211_handle_roc_started(dep);
+
+ if (dep->duration > roc->duration) {
+ u32 dur = dep->duration;
+ dep->duration = dur - roc->duration;
+ roc->duration = dur;
+ list_del(&dep->list);
+ list_add(&dep->list, &roc->list);
+ }
+ }
+ out_unlock:
mutex_unlock(&local->mtx);
}
@@ -216,36 +241,179 @@ void ieee80211_ready_on_channel(struct ieee80211_hw *hw)
{
struct ieee80211_local *local = hw_to_local(hw);
+ local->hw_roc_start_time = jiffies;
+
trace_api_ready_on_channel(local);
ieee80211_queue_work(hw, &local->hw_roc_start);
}
EXPORT_SYMBOL_GPL(ieee80211_ready_on_channel);
+void ieee80211_start_next_roc(struct ieee80211_local *local)
+{
+ struct ieee80211_roc_work *roc;
+
+ lockdep_assert_held(&local->mtx);
+
+ if (list_empty(&local->roc_list)) {
+ ieee80211_run_deferred_scan(local);
+ return;
+ }
+
+ roc = list_first_entry(&local->roc_list, struct ieee80211_roc_work,
+ list);
+
+ if (local->ops->remain_on_channel) {
+ int ret, duration = roc->duration;
+
+ /* XXX: duplicated, see ieee80211_start_roc_work() */
+ if (!duration)
+ duration = 10;
+
+ ret = drv_remain_on_channel(local, roc->chan,
+ roc->chan_type,
+ duration);
+
+ roc->started = true;
+
+ if (ret) {
+ wiphy_warn(local->hw.wiphy,
+ "failed to start next HW ROC (%d)\n", ret);
+ /*
+ * queue the work struct again to avoid recursion
+ * when multiple failures occur
+ */
+ ieee80211_remain_on_channel_expired(&local->hw);
+ }
+ } else {
+ /* delay it a bit */
+ ieee80211_queue_delayed_work(&local->hw, &roc->work,
+ round_jiffies_relative(HZ/2));
+ }
+}
+
+void ieee80211_roc_notify_destroy(struct ieee80211_roc_work *roc)
+{
+ struct ieee80211_roc_work *dep, *tmp;
+
+ /* was never transmitted */
+ if (roc->frame) {
+ cfg80211_mgmt_tx_status(roc->sdata->dev,
+ (unsigned long)roc->frame,
+ roc->frame->data, roc->frame->len,
+ false, GFP_KERNEL);
+ kfree_skb(roc->frame);
+ }
+
+ if (!roc->mgmt_tx_cookie)
+ cfg80211_remain_on_channel_expired(roc->sdata->dev,
+ (unsigned long)roc,
+ roc->chan, roc->chan_type,
+ GFP_KERNEL);
+
+ list_for_each_entry_safe(dep, tmp, &roc->dependents, list)
+ ieee80211_roc_notify_destroy(dep);
+
+ kfree(roc);
+}
+
+void ieee80211_sw_roc_work(struct work_struct *work)
+{
+ struct ieee80211_roc_work *roc =
+ container_of(work, struct ieee80211_roc_work, work.work);
+ struct ieee80211_sub_if_data *sdata = roc->sdata;
+ struct ieee80211_local *local = sdata->local;
+
+ mutex_lock(&local->mtx);
+
+ if (roc->abort)
+ goto finish;
+
+ if (WARN_ON(list_empty(&local->roc_list)))
+ goto out_unlock;
+
+ if (WARN_ON(roc != list_first_entry(&local->roc_list,
+ struct ieee80211_roc_work,
+ list)))
+ goto out_unlock;
+
+ if (!roc->started) {
+ struct ieee80211_roc_work *dep;
+
+ /* start this ROC */
+
+ /* switch channel etc */
+ ieee80211_recalc_idle(local);
+
+ local->tmp_channel = roc->chan;
+ local->tmp_channel_type = roc->chan_type;
+ ieee80211_hw_config(local, 0);
+
+ /* tell userspace or send frame */
+ ieee80211_handle_roc_started(roc);
+ list_for_each_entry(dep, &roc->dependents, list)
+ ieee80211_handle_roc_started(dep);
+
+ /* if it was pure TX, just finish right away */
+ if (!roc->duration)
+ goto finish;
+
+ roc->started = true;
+ ieee80211_queue_delayed_work(&local->hw, &roc->work,
+ msecs_to_jiffies(roc->duration));
+ } else {
+ /* finish this ROC */
+ finish:
+ list_del(&roc->list);
+ ieee80211_roc_notify_destroy(roc);
+
+ if (roc->started) {
+ drv_flush(local, false);
+
+ local->tmp_channel = NULL;
+ ieee80211_hw_config(local, 0);
+
+ ieee80211_offchannel_return(local, true);
+ }
+
+ ieee80211_recalc_idle(local);
+
+ ieee80211_start_next_roc(local);
+ ieee80211_run_deferred_scan(local);
+ }
+
+ out_unlock:
+ mutex_unlock(&local->mtx);
+}
+
static void ieee80211_hw_roc_done(struct work_struct *work)
{
struct ieee80211_local *local =
container_of(work, struct ieee80211_local, hw_roc_done);
+ struct ieee80211_roc_work *roc;
mutex_lock(&local->mtx);
- if (!local->hw_roc_channel) {
- mutex_unlock(&local->mtx);
- return;
- }
+ if (list_empty(&local->roc_list))
+ goto out_unlock;
- if (!local->hw_roc_for_tx)
- cfg80211_remain_on_channel_expired(local->hw_roc_dev,
- local->hw_roc_cookie,
- local->hw_roc_channel,
- local->hw_roc_channel_type,
- GFP_KERNEL);
+ roc = list_first_entry(&local->roc_list, struct ieee80211_roc_work,
+ list);
+
+ if (!roc->started)
+ goto out_unlock;
- local->hw_roc_channel = NULL;
- local->hw_roc_cookie = 0;
+ list_del(&roc->list);
- ieee80211_recalc_idle(local);
+ ieee80211_roc_notify_destroy(roc);
+ /* if there's another roc, start it now */
+ ieee80211_start_next_roc(local);
+
+ /* or scan maybe */
+ ieee80211_run_deferred_scan(local);
+
+ out_unlock:
mutex_unlock(&local->mtx);
}
@@ -259,8 +427,48 @@ void ieee80211_remain_on_channel_expired(struct ieee80211_hw *hw)
}
EXPORT_SYMBOL_GPL(ieee80211_remain_on_channel_expired);
-void ieee80211_hw_roc_setup(struct ieee80211_local *local)
+void ieee80211_roc_setup(struct ieee80211_local *local)
{
INIT_WORK(&local->hw_roc_start, ieee80211_hw_roc_start);
INIT_WORK(&local->hw_roc_done, ieee80211_hw_roc_done);
+ INIT_LIST_HEAD(&local->roc_list);
+}
+
+void ieee80211_roc_purge(struct ieee80211_sub_if_data *sdata)
+{
+ struct ieee80211_local *local = sdata->local;
+ struct ieee80211_roc_work *roc, *tmp;
+ LIST_HEAD(tmp_list);
+
+ mutex_lock(&local->mtx);
+ list_for_each_entry_safe(roc, tmp, &local->roc_list, list) {
+ if (roc->sdata != sdata)
+ continue;
+
+ if (roc->started && local->ops->remain_on_channel) {
+ /* can race, so ignore return value */
+ drv_cancel_remain_on_channel(local);
+ }
+
+ list_move_tail(&roc->list, &tmp_list);
+ roc->abort = true;
+ }
+
+ ieee80211_start_next_roc(local);
+ ieee80211_run_deferred_scan(local);
+ mutex_unlock(&local->mtx);
+
+ list_for_each_entry_safe(roc, tmp, &tmp_list, list) {
+ if (local->ops->remain_on_channel) {
+ list_del(&roc->list);
+ ieee80211_roc_notify_destroy(roc);
+ } else {
+ ieee80211_queue_delayed_work(&local->hw, &roc->work, 0);
+
+ /* work will clean up etc */
+ flush_delayed_work(&roc->work);
+ }
+ }
+
+ WARN_ON_ONCE(!list_empty(&tmp_list));
}
diff --git a/net/mac80211/pm.c b/net/mac80211/pm.c
index af1c4e26e96..98c128be382 100644
--- a/net/mac80211/pm.c
+++ b/net/mac80211/pm.c
@@ -77,6 +77,7 @@ int __ieee80211_suspend(struct ieee80211_hw *hw, struct cfg80211_wowlan *wowlan)
int err = drv_suspend(local, wowlan);
if (err < 0) {
local->quiescing = false;
+ local->wowlan = false;
return err;
} else if (err > 0) {
WARN_ON(err != 1);
diff --git a/net/mac80211/rx.c b/net/mac80211/rx.c
index 7bcecf73aaf..6fd2cb0838c 100644
--- a/net/mac80211/rx.c
+++ b/net/mac80211/rx.c
@@ -1137,22 +1137,22 @@ static void ap_sta_ps_start(struct sta_info *sta)
if (!(local->hw.flags & IEEE80211_HW_AP_LINK_PS))
drv_sta_notify(local, sdata, STA_NOTIFY_SLEEP, &sta->sta);
#ifdef CONFIG_MAC80211_VERBOSE_PS_DEBUG
- printk(KERN_DEBUG "%s: STA %pM aid %d enters power save mode\n",
- sdata->name, sta->sta.addr, sta->sta.aid);
+ pr_debug("%s: STA %pM aid %d enters power save mode\n",
+ sdata->name, sta->sta.addr, sta->sta.aid);
#endif /* CONFIG_MAC80211_VERBOSE_PS_DEBUG */
}
static void ap_sta_ps_end(struct sta_info *sta)
{
#ifdef CONFIG_MAC80211_VERBOSE_PS_DEBUG
- printk(KERN_DEBUG "%s: STA %pM aid %d exits power save mode\n",
- sta->sdata->name, sta->sta.addr, sta->sta.aid);
+ pr_debug("%s: STA %pM aid %d exits power save mode\n",
+ sta->sdata->name, sta->sta.addr, sta->sta.aid);
#endif /* CONFIG_MAC80211_VERBOSE_PS_DEBUG */
if (test_sta_flag(sta, WLAN_STA_PS_DRIVER)) {
#ifdef CONFIG_MAC80211_VERBOSE_PS_DEBUG
- printk(KERN_DEBUG "%s: STA %pM aid %d driver-ps-blocked\n",
- sta->sdata->name, sta->sta.addr, sta->sta.aid);
+ pr_debug("%s: STA %pM aid %d driver-ps-blocked\n",
+ sta->sdata->name, sta->sta.addr, sta->sta.aid);
#endif /* CONFIG_MAC80211_VERBOSE_PS_DEBUG */
return;
}
@@ -1387,12 +1387,10 @@ ieee80211_reassemble_add(struct ieee80211_sub_if_data *sdata,
#ifdef CONFIG_MAC80211_VERBOSE_DEBUG
struct ieee80211_hdr *hdr =
(struct ieee80211_hdr *) entry->skb_list.next->data;
- printk(KERN_DEBUG "%s: RX reassembly removed oldest "
- "fragment entry (idx=%d age=%lu seq=%d last_frag=%d "
- "addr1=%pM addr2=%pM\n",
- sdata->name, idx,
- jiffies - entry->first_frag_time, entry->seq,
- entry->last_frag, hdr->addr1, hdr->addr2);
+ pr_debug("%s: RX reassembly removed oldest fragment entry (idx=%d age=%lu seq=%d last_frag=%d addr1=%pM addr2=%pM\n",
+ sdata->name, idx,
+ jiffies - entry->first_frag_time, entry->seq,
+ entry->last_frag, hdr->addr1, hdr->addr2);
#endif
__skb_queue_purge(&entry->skb_list);
}
diff --git a/net/mac80211/scan.c b/net/mac80211/scan.c
index 169da0742c8..379f178eab5 100644
--- a/net/mac80211/scan.c
+++ b/net/mac80211/scan.c
@@ -323,7 +323,7 @@ static void __ieee80211_scan_completed(struct ieee80211_hw *hw, bool aborted,
ieee80211_mlme_notify_scan_completed(local);
ieee80211_ibss_notify_scan_completed(local);
ieee80211_mesh_notify_scan_completed(local);
- ieee80211_queue_work(&local->hw, &local->work_work);
+ ieee80211_start_next_roc(local);
}
void ieee80211_scan_completed(struct ieee80211_hw *hw, bool aborted)
@@ -376,7 +376,7 @@ static int ieee80211_start_sw_scan(struct ieee80211_local *local)
static bool ieee80211_can_scan(struct ieee80211_local *local,
struct ieee80211_sub_if_data *sdata)
{
- if (!list_empty(&local->work_list))
+ if (!list_empty(&local->roc_list))
return false;
if (sdata->vif.type == NL80211_IFTYPE_STATION &&
diff --git a/net/mac80211/sta_info.c b/net/mac80211/sta_info.c
index f5b1638fbf8..77dcf2f89d4 100644
--- a/net/mac80211/sta_info.c
+++ b/net/mac80211/sta_info.c
@@ -333,9 +333,8 @@ static int sta_info_insert_drv_state(struct ieee80211_local *local,
}
if (sdata->vif.type == NL80211_IFTYPE_ADHOC) {
- printk(KERN_DEBUG
- "%s: failed to move IBSS STA %pM to state %d (%d) - keeping it anyway.\n",
- sdata->name, sta->sta.addr, state + 1, err);
+ pr_debug("%s: failed to move IBSS STA %pM to state %d (%d) - keeping it anyway\n",
+ sdata->name, sta->sta.addr, state + 1, err);
err = 0;
}
@@ -378,7 +377,7 @@ static int sta_info_insert_finish(struct sta_info *sta) __acquires(RCU)
/* make the station visible */
sta_info_hash_add(local, sta);
- list_add(&sta->list, &local->sta_list);
+ list_add_rcu(&sta->list, &local->sta_list);
set_sta_flag(sta, WLAN_STA_INSERTED);
@@ -619,8 +618,7 @@ static bool sta_info_cleanup_expire_buffered_ac(struct ieee80211_local *local,
local->total_ps_buffered--;
#ifdef CONFIG_MAC80211_VERBOSE_PS_DEBUG
- printk(KERN_DEBUG "Buffered frame expired (STA %pM)\n",
- sta->sta.addr);
+ pr_debug("Buffered frame expired (STA %pM)\n", sta->sta.addr);
#endif
dev_kfree_skb(skb);
}
@@ -688,7 +686,7 @@ int __must_check __sta_info_destroy(struct sta_info *sta)
if (ret)
return ret;
- list_del(&sta->list);
+ list_del_rcu(&sta->list);
mutex_lock(&local->key_mtx);
for (i = 0; i < NUM_DEFAULT_KEYS; i++)
@@ -889,10 +887,8 @@ void ieee80211_sta_expire(struct ieee80211_sub_if_data *sdata,
continue;
if (time_after(jiffies, sta->last_rx + exp_time)) {
-#ifdef CONFIG_MAC80211_IBSS_DEBUG
- printk(KERN_DEBUG "%s: expiring inactive STA %pM\n",
- sdata->name, sta->sta.addr);
-#endif
+ ibss_vdbg("%s: expiring inactive STA %pM\n",
+ sdata->name, sta->sta.addr);
WARN_ON(__sta_info_destroy(sta));
}
}
@@ -991,9 +987,8 @@ void ieee80211_sta_ps_deliver_wakeup(struct sta_info *sta)
sta_info_recalc_tim(sta);
#ifdef CONFIG_MAC80211_VERBOSE_PS_DEBUG
- printk(KERN_DEBUG "%s: STA %pM aid %d sending %d filtered/%d PS frames "
- "since STA not sleeping anymore\n", sdata->name,
- sta->sta.addr, sta->sta.aid, filtered, buffered);
+ pr_debug("%s: STA %pM aid %d sending %d filtered/%d PS frames since STA not sleeping anymore\n",
+ sdata->name, sta->sta.addr, sta->sta.aid, filtered, buffered);
#endif /* CONFIG_MAC80211_VERBOSE_PS_DEBUG */
}
@@ -1385,8 +1380,8 @@ int sta_info_move_state(struct sta_info *sta,
}
#ifdef CONFIG_MAC80211_VERBOSE_DEBUG
- printk(KERN_DEBUG "%s: moving STA %pM to state %d\n",
- sta->sdata->name, sta->sta.addr, new_state);
+ pr_debug("%s: moving STA %pM to state %d\n",
+ sta->sdata->name, sta->sta.addr, new_state);
#endif
/*
diff --git a/net/mac80211/status.c b/net/mac80211/status.c
index 28cfa981cfb..6b4f4252788 100644
--- a/net/mac80211/status.c
+++ b/net/mac80211/status.c
@@ -520,36 +520,16 @@ void ieee80211_tx_status(struct ieee80211_hw *hw, struct sk_buff *skb)
if (info->flags & IEEE80211_TX_INTFL_NL80211_FRAME_TX) {
u64 cookie = (unsigned long)skb;
+ acked = info->flags & IEEE80211_TX_STAT_ACK;
if (ieee80211_is_nullfunc(hdr->frame_control) ||
- ieee80211_is_qos_nullfunc(hdr->frame_control)) {
- acked = info->flags & IEEE80211_TX_STAT_ACK;
-
+ ieee80211_is_qos_nullfunc(hdr->frame_control))
cfg80211_probe_status(skb->dev, hdr->addr1,
cookie, acked, GFP_ATOMIC);
- } else {
- struct ieee80211_work *wk;
-
- rcu_read_lock();
- list_for_each_entry_rcu(wk, &local->work_list, list) {
- if (wk->type != IEEE80211_WORK_OFFCHANNEL_TX)
- continue;
- if (wk->offchan_tx.frame != skb)
- continue;
- wk->offchan_tx.status = true;
- break;
- }
- rcu_read_unlock();
- if (local->hw_roc_skb_for_status == skb) {
- cookie = local->hw_roc_cookie ^ 2;
- local->hw_roc_skb_for_status = NULL;
- }
-
+ else
cfg80211_mgmt_tx_status(
skb->dev, cookie, skb->data, skb->len,
- !!(info->flags & IEEE80211_TX_STAT_ACK),
- GFP_ATOMIC);
- }
+ acked, GFP_ATOMIC);
}
if (unlikely(info->ack_frame_id)) {
@@ -589,7 +569,7 @@ void ieee80211_tx_status(struct ieee80211_hw *hw, struct sk_buff *skb)
/* send frame to monitor interfaces now */
rtap_len = ieee80211_tx_radiotap_len(info);
if (WARN_ON_ONCE(skb_headroom(skb) < rtap_len)) {
- printk(KERN_ERR "ieee80211_tx_status: headroom too small\n");
+ pr_err("ieee80211_tx_status: headroom too small\n");
dev_kfree_skb(skb);
return;
}
diff --git a/net/mac80211/tkip.c b/net/mac80211/tkip.c
index 51077a956a8..68be47ca208 100644
--- a/net/mac80211/tkip.c
+++ b/net/mac80211/tkip.c
@@ -263,12 +263,11 @@ int ieee80211_tkip_decrypt_data(struct crypto_cipher *tfm,
#ifdef CONFIG_MAC80211_TKIP_DEBUG
{
int i;
- printk(KERN_DEBUG "TKIP decrypt: data(len=%zd)", payload_len);
+ pr_debug("TKIP decrypt: data(len=%zd)", payload_len);
for (i = 0; i < payload_len; i++)
printk(" %02x", payload[i]);
printk("\n");
- printk(KERN_DEBUG "TKIP decrypt: iv16=%04x iv32=%08x\n",
- iv16, iv32);
+ pr_debug("TKIP decrypt: iv16=%04x iv32=%08x\n", iv16, iv32);
}
#endif
@@ -283,11 +282,10 @@ int ieee80211_tkip_decrypt_data(struct crypto_cipher *tfm,
(iv32 == key->u.tkip.rx[queue].iv32 &&
iv16 <= key->u.tkip.rx[queue].iv16))) {
#ifdef CONFIG_MAC80211_TKIP_DEBUG
- printk(KERN_DEBUG "TKIP replay detected for RX frame from "
- "%pM (RX IV (%04x,%02x) <= prev. IV (%04x,%02x)\n",
- ta,
- iv32, iv16, key->u.tkip.rx[queue].iv32,
- key->u.tkip.rx[queue].iv16);
+ pr_debug("TKIP replay detected for RX frame from %pM (RX IV (%04x,%02x) <= prev. IV (%04x,%02x)\n",
+ ta, iv32, iv16,
+ key->u.tkip.rx[queue].iv32,
+ key->u.tkip.rx[queue].iv16);
#endif
return TKIP_DECRYPT_REPLAY;
}
@@ -306,13 +304,12 @@ int ieee80211_tkip_decrypt_data(struct crypto_cipher *tfm,
{
int i;
u8 key_offset = NL80211_TKIP_DATA_OFFSET_ENCR_KEY;
- printk(KERN_DEBUG "TKIP decrypt: Phase1 TA=%pM"
- " TK=", ta);
+ pr_debug("TKIP decrypt: Phase1 TA=%pM TK=", ta);
for (i = 0; i < 16; i++)
printk("%02x ",
key->conf.key[key_offset + i]);
printk("\n");
- printk(KERN_DEBUG "TKIP decrypt: P1K=");
+ pr_debug("TKIP decrypt: P1K=");
for (i = 0; i < 5; i++)
printk("%04x ", key->u.tkip.rx[queue].p1k[i]);
printk("\n");
@@ -336,7 +333,7 @@ int ieee80211_tkip_decrypt_data(struct crypto_cipher *tfm,
#ifdef CONFIG_MAC80211_TKIP_DEBUG
{
int i;
- printk(KERN_DEBUG "TKIP decrypt: Phase2 rc4key=");
+ pr_debug("TKIP decrypt: Phase2 rc4key=");
for (i = 0; i < 16; i++)
printk("%02x ", rc4key[i]);
printk("\n");
diff --git a/net/mac80211/tx.c b/net/mac80211/tx.c
index 847215bb2a6..af25c4e7ec5 100644
--- a/net/mac80211/tx.c
+++ b/net/mac80211/tx.c
@@ -297,9 +297,8 @@ ieee80211_tx_h_check_assoc(struct ieee80211_tx_data *tx)
if (unlikely(!assoc &&
ieee80211_is_data(hdr->frame_control))) {
#ifdef CONFIG_MAC80211_VERBOSE_DEBUG
- printk(KERN_DEBUG "%s: dropped data frame to not "
- "associated station %pM\n",
- tx->sdata->name, hdr->addr1);
+ pr_debug("%s: dropped data frame to not associated station %pM\n",
+ tx->sdata->name, hdr->addr1);
#endif /* CONFIG_MAC80211_VERBOSE_DEBUG */
I802_DEBUG_INC(tx->local->tx_handlers_drop_not_assoc);
return TX_DROP;
@@ -467,8 +466,8 @@ ieee80211_tx_h_unicast_ps_buf(struct ieee80211_tx_data *tx)
}
#ifdef CONFIG_MAC80211_VERBOSE_PS_DEBUG
- printk(KERN_DEBUG "STA %pM aid %d: PS buffer for AC %d\n",
- sta->sta.addr, sta->sta.aid, ac);
+ pr_debug("STA %pM aid %d: PS buffer for AC %d\n",
+ sta->sta.addr, sta->sta.aid, ac);
#endif /* CONFIG_MAC80211_VERBOSE_PS_DEBUG */
if (tx->local->total_ps_buffered >= TOTAL_MAX_TX_BUFFER)
purge_old_ps_buffers(tx->local);
@@ -502,9 +501,8 @@ ieee80211_tx_h_unicast_ps_buf(struct ieee80211_tx_data *tx)
}
#ifdef CONFIG_MAC80211_VERBOSE_PS_DEBUG
else if (unlikely(test_sta_flag(sta, WLAN_STA_PS_STA))) {
- printk(KERN_DEBUG
- "%s: STA %pM in PS mode, but polling/in SP -> send frame\n",
- tx->sdata->name, sta->sta.addr);
+ pr_debug("%s: STA %pM in PS mode, but polling/in SP -> send frame\n",
+ tx->sdata->name, sta->sta.addr);
}
#endif /* CONFIG_MAC80211_VERBOSE_PS_DEBUG */
@@ -1737,7 +1735,7 @@ netdev_tx_t ieee80211_subif_start_xmit(struct sk_buff *skb,
__le16 fc;
struct ieee80211_hdr hdr;
struct ieee80211s_hdr mesh_hdr __maybe_unused;
- struct mesh_path __maybe_unused *mppath = NULL;
+ struct mesh_path __maybe_unused *mppath = NULL, *mpath = NULL;
const u8 *encaps_data;
int encaps_len, skip_header_bytes;
int nh_pos, h_pos;
@@ -1803,8 +1801,11 @@ netdev_tx_t ieee80211_subif_start_xmit(struct sk_buff *skb,
goto fail;
}
rcu_read_lock();
- if (!is_multicast_ether_addr(skb->data))
- mppath = mpp_path_lookup(skb->data, sdata);
+ if (!is_multicast_ether_addr(skb->data)) {
+ mpath = mesh_path_lookup(skb->data, sdata);
+ if (!mpath)
+ mppath = mpp_path_lookup(skb->data, sdata);
+ }
/*
* Use address extension if it is a packet from
diff --git a/net/mac80211/util.c b/net/mac80211/util.c
index a44c6807df0..1df4019f294 100644
--- a/net/mac80211/util.c
+++ b/net/mac80211/util.c
@@ -804,7 +804,7 @@ void ieee80211_set_wmm_default(struct ieee80211_sub_if_data *sdata,
struct ieee80211_local *local = sdata->local;
struct ieee80211_tx_queue_params qparam;
int ac;
- bool use_11b;
+ bool use_11b, enable_qos;
int aCWmin, aCWmax;
if (!local->ops->conf_tx)
@@ -818,6 +818,13 @@ void ieee80211_set_wmm_default(struct ieee80211_sub_if_data *sdata,
use_11b = (local->hw.conf.channel->band == IEEE80211_BAND_2GHZ) &&
!(sdata->flags & IEEE80211_SDATA_OPERATING_GMODE);
+ /*
+ * By default disable QoS in STA mode for old access points, which do
+ * not support 802.11e. New APs will provide proper queue parameters,
+ * that we will configure later.
+ */
+ enable_qos = (sdata->vif.type != NL80211_IFTYPE_STATION);
+
for (ac = 0; ac < IEEE80211_NUM_ACS; ac++) {
/* Set defaults according to 802.11-2007 Table 7-37 */
aCWmax = 1023;
@@ -826,38 +833,47 @@ void ieee80211_set_wmm_default(struct ieee80211_sub_if_data *sdata,
else
aCWmin = 15;
- switch (ac) {
- case IEEE80211_AC_BK:
- qparam.cw_max = aCWmax;
- qparam.cw_min = aCWmin;
- qparam.txop = 0;
- qparam.aifs = 7;
- break;
- default: /* never happens but let's not leave undefined */
- case IEEE80211_AC_BE:
+ if (enable_qos) {
+ switch (ac) {
+ case IEEE80211_AC_BK:
+ qparam.cw_max = aCWmax;
+ qparam.cw_min = aCWmin;
+ qparam.txop = 0;
+ qparam.aifs = 7;
+ break;
+ /* never happens but let's not leave undefined */
+ default:
+ case IEEE80211_AC_BE:
+ qparam.cw_max = aCWmax;
+ qparam.cw_min = aCWmin;
+ qparam.txop = 0;
+ qparam.aifs = 3;
+ break;
+ case IEEE80211_AC_VI:
+ qparam.cw_max = aCWmin;
+ qparam.cw_min = (aCWmin + 1) / 2 - 1;
+ if (use_11b)
+ qparam.txop = 6016/32;
+ else
+ qparam.txop = 3008/32;
+ qparam.aifs = 2;
+ break;
+ case IEEE80211_AC_VO:
+ qparam.cw_max = (aCWmin + 1) / 2 - 1;
+ qparam.cw_min = (aCWmin + 1) / 4 - 1;
+ if (use_11b)
+ qparam.txop = 3264/32;
+ else
+ qparam.txop = 1504/32;
+ qparam.aifs = 2;
+ break;
+ }
+ } else {
+ /* Confiure old 802.11b/g medium access rules. */
qparam.cw_max = aCWmax;
qparam.cw_min = aCWmin;
qparam.txop = 0;
- qparam.aifs = 3;
- break;
- case IEEE80211_AC_VI:
- qparam.cw_max = aCWmin;
- qparam.cw_min = (aCWmin + 1) / 2 - 1;
- if (use_11b)
- qparam.txop = 6016/32;
- else
- qparam.txop = 3008/32;
- qparam.aifs = 2;
- break;
- case IEEE80211_AC_VO:
- qparam.cw_max = (aCWmin + 1) / 2 - 1;
- qparam.cw_min = (aCWmin + 1) / 4 - 1;
- if (use_11b)
- qparam.txop = 3264/32;
- else
- qparam.txop = 1504/32;
qparam.aifs = 2;
- break;
}
qparam.uapsd = false;
@@ -866,12 +882,8 @@ void ieee80211_set_wmm_default(struct ieee80211_sub_if_data *sdata,
drv_conf_tx(local, sdata, ac, &qparam);
}
- /* after reinitialize QoS TX queues setting to default,
- * disable QoS at all */
-
if (sdata->vif.type != NL80211_IFTYPE_MONITOR) {
- sdata->vif.bss_conf.qos =
- sdata->vif.type != NL80211_IFTYPE_STATION;
+ sdata->vif.bss_conf.qos = enable_qos;
if (bss_notify)
ieee80211_bss_info_change_notify(sdata,
BSS_CHANGED_QOS);
@@ -1267,14 +1279,19 @@ int ieee80211_reconfig(struct ieee80211_local *local)
/* add STAs back */
mutex_lock(&local->sta_mtx);
list_for_each_entry(sta, &local->sta_list, list) {
- if (sta->uploaded) {
- enum ieee80211_sta_state state;
+ enum ieee80211_sta_state state;
- for (state = IEEE80211_STA_NOTEXIST;
- state < sta->sta_state - 1; state++)
- WARN_ON(drv_sta_state(local, sta->sdata, sta,
- state, state + 1));
- }
+ if (!sta->uploaded)
+ continue;
+
+ /* AP-mode stations will be added later */
+ if (sta->sdata->vif.type == NL80211_IFTYPE_AP)
+ continue;
+
+ for (state = IEEE80211_STA_NOTEXIST;
+ state < sta->sta_state; state++)
+ WARN_ON(drv_sta_state(local, sta->sdata, sta, state,
+ state + 1));
}
mutex_unlock(&local->sta_mtx);
@@ -1371,6 +1388,24 @@ int ieee80211_reconfig(struct ieee80211_local *local)
}
}
+ /* APs are now beaconing, add back stations */
+ mutex_lock(&local->sta_mtx);
+ list_for_each_entry(sta, &local->sta_list, list) {
+ enum ieee80211_sta_state state;
+
+ if (!sta->uploaded)
+ continue;
+
+ if (sta->sdata->vif.type != NL80211_IFTYPE_AP)
+ continue;
+
+ for (state = IEEE80211_STA_NOTEXIST;
+ state < sta->sta_state; state++)
+ WARN_ON(drv_sta_state(local, sta->sdata, sta, state,
+ state + 1));
+ }
+ mutex_unlock(&local->sta_mtx);
+
/* add back keys */
list_for_each_entry(sdata, &local->interfaces, list)
if (ieee80211_sdata_running(sdata))
diff --git a/net/mac80211/work.c b/net/mac80211/work.c
deleted file mode 100644
index b2650a9d45f..00000000000
--- a/net/mac80211/work.c
+++ /dev/null
@@ -1,370 +0,0 @@
-/*
- * mac80211 work implementation
- *
- * Copyright 2003-2008, Jouni Malinen <j@w1.fi>
- * Copyright 2004, Instant802 Networks, Inc.
- * Copyright 2005, Devicescape Software, Inc.
- * Copyright 2006-2007 Jiri Benc <jbenc@suse.cz>
- * Copyright 2007, Michael Wu <flamingice@sourmilk.net>
- * Copyright 2009, Johannes Berg <johannes@sipsolutions.net>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- */
-
-#include <linux/delay.h>
-#include <linux/if_ether.h>
-#include <linux/skbuff.h>
-#include <linux/if_arp.h>
-#include <linux/etherdevice.h>
-#include <linux/crc32.h>
-#include <linux/slab.h>
-#include <net/mac80211.h>
-#include <asm/unaligned.h>
-
-#include "ieee80211_i.h"
-#include "rate.h"
-#include "driver-ops.h"
-
-enum work_action {
- WORK_ACT_NONE,
- WORK_ACT_TIMEOUT,
-};
-
-
-/* utils */
-static inline void ASSERT_WORK_MTX(struct ieee80211_local *local)
-{
- lockdep_assert_held(&local->mtx);
-}
-
-/*
- * We can have multiple work items (and connection probing)
- * scheduling this timer, but we need to take care to only
- * reschedule it when it should fire _earlier_ than it was
- * asked for before, or if it's not pending right now. This
- * function ensures that. Note that it then is required to
- * run this function for all timeouts after the first one
- * has happened -- the work that runs from this timer will
- * do that.
- */
-static void run_again(struct ieee80211_local *local,
- unsigned long timeout)
-{
- ASSERT_WORK_MTX(local);
-
- if (!timer_pending(&local->work_timer) ||
- time_before(timeout, local->work_timer.expires))
- mod_timer(&local->work_timer, timeout);
-}
-
-void free_work(struct ieee80211_work *wk)
-{
- kfree_rcu(wk, rcu_head);
-}
-
-static enum work_action __must_check
-ieee80211_remain_on_channel_timeout(struct ieee80211_work *wk)
-{
- /*
- * First time we run, do nothing -- the generic code will
- * have switched to the right channel etc.
- */
- if (!wk->started) {
- wk->timeout = jiffies + msecs_to_jiffies(wk->remain.duration);
-
- cfg80211_ready_on_channel(wk->sdata->dev, (unsigned long) wk,
- wk->chan, wk->chan_type,
- wk->remain.duration, GFP_KERNEL);
-
- return WORK_ACT_NONE;
- }
-
- return WORK_ACT_TIMEOUT;
-}
-
-static enum work_action __must_check
-ieee80211_offchannel_tx(struct ieee80211_work *wk)
-{
- if (!wk->started) {
- wk->timeout = jiffies + msecs_to_jiffies(wk->offchan_tx.wait);
-
- /*
- * After this, offchan_tx.frame remains but now is no
- * longer a valid pointer -- we still need it as the
- * cookie for canceling this work/status matching.
- */
- ieee80211_tx_skb(wk->sdata, wk->offchan_tx.frame);
-
- return WORK_ACT_NONE;
- }
-
- return WORK_ACT_TIMEOUT;
-}
-
-static void ieee80211_work_timer(unsigned long data)
-{
- struct ieee80211_local *local = (void *) data;
-
- if (local->quiescing)
- return;
-
- ieee80211_queue_work(&local->hw, &local->work_work);
-}
-
-static void ieee80211_work_work(struct work_struct *work)
-{
- struct ieee80211_local *local =
- container_of(work, struct ieee80211_local, work_work);
- struct ieee80211_work *wk, *tmp;
- LIST_HEAD(free_work);
- enum work_action rma;
- bool remain_off_channel = false;
-
- /*
- * ieee80211_queue_work() should have picked up most cases,
- * here we'll pick the rest.
- */
- if (WARN(local->suspended, "work scheduled while going to suspend\n"))
- return;
-
- mutex_lock(&local->mtx);
-
- if (local->scanning) {
- mutex_unlock(&local->mtx);
- return;
- }
-
- ieee80211_recalc_idle(local);
-
- list_for_each_entry_safe(wk, tmp, &local->work_list, list) {
- bool started = wk->started;
-
- /* mark work as started if it's on the current off-channel */
- if (!started && local->tmp_channel &&
- wk->chan == local->tmp_channel &&
- wk->chan_type == local->tmp_channel_type) {
- started = true;
- wk->timeout = jiffies;
- }
-
- if (!started && !local->tmp_channel) {
- ieee80211_offchannel_stop_vifs(local, true);
-
- local->tmp_channel = wk->chan;
- local->tmp_channel_type = wk->chan_type;
-
- ieee80211_hw_config(local, 0);
-
- started = true;
- wk->timeout = jiffies;
- }
-
- /* don't try to work with items that aren't started */
- if (!started)
- continue;
-
- if (time_is_after_jiffies(wk->timeout)) {
- /*
- * This work item isn't supposed to be worked on
- * right now, but take care to adjust the timer
- * properly.
- */
- run_again(local, wk->timeout);
- continue;
- }
-
- switch (wk->type) {
- default:
- WARN_ON(1);
- /* nothing */
- rma = WORK_ACT_NONE;
- break;
- case IEEE80211_WORK_ABORT:
- rma = WORK_ACT_TIMEOUT;
- break;
- case IEEE80211_WORK_REMAIN_ON_CHANNEL:
- rma = ieee80211_remain_on_channel_timeout(wk);
- break;
- case IEEE80211_WORK_OFFCHANNEL_TX:
- rma = ieee80211_offchannel_tx(wk);
- break;
- }
-
- wk->started = started;
-
- switch (rma) {
- case WORK_ACT_NONE:
- /* might have changed the timeout */
- run_again(local, wk->timeout);
- break;
- case WORK_ACT_TIMEOUT:
- list_del_rcu(&wk->list);
- synchronize_rcu();
- list_add(&wk->list, &free_work);
- break;
- default:
- WARN(1, "unexpected: %d", rma);
- }
- }
-
- list_for_each_entry(wk, &local->work_list, list) {
- if (!wk->started)
- continue;
- if (wk->chan != local->tmp_channel ||
- wk->chan_type != local->tmp_channel_type)
- continue;
- remain_off_channel = true;
- }
-
- if (!remain_off_channel && local->tmp_channel) {
- local->tmp_channel = NULL;
- ieee80211_hw_config(local, 0);
-
- ieee80211_offchannel_return(local, true);
-
- /* give connection some time to breathe */
- run_again(local, jiffies + HZ/2);
- }
-
- ieee80211_recalc_idle(local);
- ieee80211_run_deferred_scan(local);
-
- mutex_unlock(&local->mtx);
-
- list_for_each_entry_safe(wk, tmp, &free_work, list) {
- wk->done(wk, NULL);
- list_del(&wk->list);
- kfree(wk);
- }
-}
-
-void ieee80211_add_work(struct ieee80211_work *wk)
-{
- struct ieee80211_local *local;
-
- if (WARN_ON(!wk->chan))
- return;
-
- if (WARN_ON(!wk->sdata))
- return;
-
- if (WARN_ON(!wk->done))
- return;
-
- if (WARN_ON(!ieee80211_sdata_running(wk->sdata)))
- return;
-
- wk->started = false;
-
- local = wk->sdata->local;
- mutex_lock(&local->mtx);
- list_add_tail(&wk->list, &local->work_list);
- mutex_unlock(&local->mtx);
-
- ieee80211_queue_work(&local->hw, &local->work_work);
-}
-
-void ieee80211_work_init(struct ieee80211_local *local)
-{
- INIT_LIST_HEAD(&local->work_list);
- setup_timer(&local->work_timer, ieee80211_work_timer,
- (unsigned long)local);
- INIT_WORK(&local->work_work, ieee80211_work_work);
-}
-
-void ieee80211_work_purge(struct ieee80211_sub_if_data *sdata)
-{
- struct ieee80211_local *local = sdata->local;
- struct ieee80211_work *wk;
- bool cleanup = false;
-
- mutex_lock(&local->mtx);
- list_for_each_entry(wk, &local->work_list, list) {
- if (wk->sdata != sdata)
- continue;
- cleanup = true;
- wk->type = IEEE80211_WORK_ABORT;
- wk->started = true;
- wk->timeout = jiffies;
- }
- mutex_unlock(&local->mtx);
-
- /* run cleanups etc. */
- if (cleanup)
- ieee80211_work_work(&local->work_work);
-
- mutex_lock(&local->mtx);
- list_for_each_entry(wk, &local->work_list, list) {
- if (wk->sdata != sdata)
- continue;
- WARN_ON(1);
- break;
- }
- mutex_unlock(&local->mtx);
-}
-
-static enum work_done_result ieee80211_remain_done(struct ieee80211_work *wk,
- struct sk_buff *skb)
-{
- /*
- * We are done serving the remain-on-channel command.
- */
- cfg80211_remain_on_channel_expired(wk->sdata->dev, (unsigned long) wk,
- wk->chan, wk->chan_type,
- GFP_KERNEL);
-
- return WORK_DONE_DESTROY;
-}
-
-int ieee80211_wk_remain_on_channel(struct ieee80211_sub_if_data *sdata,
- struct ieee80211_channel *chan,
- enum nl80211_channel_type channel_type,
- unsigned int duration, u64 *cookie)
-{
- struct ieee80211_work *wk;
-
- wk = kzalloc(sizeof(*wk), GFP_KERNEL);
- if (!wk)
- return -ENOMEM;
-
- wk->type = IEEE80211_WORK_REMAIN_ON_CHANNEL;
- wk->chan = chan;
- wk->chan_type = channel_type;
- wk->sdata = sdata;
- wk->done = ieee80211_remain_done;
-
- wk->remain.duration = duration;
-
- *cookie = (unsigned long) wk;
-
- ieee80211_add_work(wk);
-
- return 0;
-}
-
-int ieee80211_wk_cancel_remain_on_channel(struct ieee80211_sub_if_data *sdata,
- u64 cookie)
-{
- struct ieee80211_local *local = sdata->local;
- struct ieee80211_work *wk, *tmp;
- bool found = false;
-
- mutex_lock(&local->mtx);
- list_for_each_entry_safe(wk, tmp, &local->work_list, list) {
- if ((unsigned long) wk == cookie) {
- wk->timeout = jiffies;
- found = true;
- break;
- }
- }
- mutex_unlock(&local->mtx);
-
- if (!found)
- return -ENOENT;
-
- ieee80211_queue_work(&local->hw, &local->work_work);
-
- return 0;
-}
diff --git a/net/rfkill/core.c b/net/rfkill/core.c
index f974961754c..752b72360eb 100644
--- a/net/rfkill/core.c
+++ b/net/rfkill/core.c
@@ -325,7 +325,7 @@ static void __rfkill_switch_all(const enum rfkill_type type, bool blocked)
rfkill_global_states[type].cur = blocked;
list_for_each_entry(rfkill, &rfkill_list, node) {
- if (rfkill->type != type)
+ if (rfkill->type != type && type != RFKILL_TYPE_ALL)
continue;
rfkill_set_block(rfkill, blocked);
diff --git a/net/wireless/Kconfig b/net/wireless/Kconfig
index 2e4444fedbe..4d2b1ec6516 100644
--- a/net/wireless/Kconfig
+++ b/net/wireless/Kconfig
@@ -114,24 +114,10 @@ config CFG80211_WEXT
bool "cfg80211 wireless extensions compatibility"
depends on CFG80211
select WEXT_CORE
- default y
help
Enable this option if you need old userspace for wireless
extensions with cfg80211-based drivers.
-config WIRELESS_EXT_SYSFS
- bool "Wireless extensions sysfs files"
- depends on WEXT_CORE && SYSFS
- help
- This option enables the deprecated wireless statistics
- files in /sys/class/net/*/wireless/. The same information
- is available via the ioctls as well.
-
- Say N. If you know you have ancient tools requiring it,
- like very old versions of hal (prior to 0.5.12 release),
- say Y and update the tools as soon as possible as this
- option will be removed soon.
-
config LIB80211
tristate "Common routines for IEEE802.11 drivers"
default n
diff --git a/net/wireless/chan.c b/net/wireless/chan.c
index 884801ac4dd..c1999e45a07 100644
--- a/net/wireless/chan.c
+++ b/net/wireless/chan.c
@@ -60,7 +60,7 @@ bool cfg80211_can_beacon_sec_chan(struct wiphy *wiphy,
diff = -20;
break;
default:
- return false;
+ return true;
}
sec_chan = ieee80211_get_channel(wiphy, chan->center_freq + diff);
@@ -78,60 +78,17 @@ bool cfg80211_can_beacon_sec_chan(struct wiphy *wiphy,
}
EXPORT_SYMBOL(cfg80211_can_beacon_sec_chan);
-int cfg80211_set_freq(struct cfg80211_registered_device *rdev,
- struct wireless_dev *wdev, int freq,
- enum nl80211_channel_type channel_type)
+int cfg80211_set_monitor_channel(struct cfg80211_registered_device *rdev,
+ int freq, enum nl80211_channel_type chantype)
{
struct ieee80211_channel *chan;
- int result;
-
- if (wdev && wdev->iftype == NL80211_IFTYPE_MONITOR)
- wdev = NULL;
-
- if (wdev) {
- ASSERT_WDEV_LOCK(wdev);
-
- if (!netif_running(wdev->netdev))
- return -ENETDOWN;
- }
- if (!rdev->ops->set_channel)
+ if (!rdev->ops->set_monitor_channel)
return -EOPNOTSUPP;
- chan = rdev_freq_to_chan(rdev, freq, channel_type);
+ chan = rdev_freq_to_chan(rdev, freq, chantype);
if (!chan)
return -EINVAL;
- /* Both channels should be able to initiate communication */
- if (wdev && (wdev->iftype == NL80211_IFTYPE_ADHOC ||
- wdev->iftype == NL80211_IFTYPE_AP ||
- wdev->iftype == NL80211_IFTYPE_AP_VLAN ||
- wdev->iftype == NL80211_IFTYPE_MESH_POINT ||
- wdev->iftype == NL80211_IFTYPE_P2P_GO)) {
- switch (channel_type) {
- case NL80211_CHAN_HT40PLUS:
- case NL80211_CHAN_HT40MINUS:
- if (!cfg80211_can_beacon_sec_chan(&rdev->wiphy, chan,
- channel_type)) {
- printk(KERN_DEBUG
- "cfg80211: Secondary channel not "
- "allowed to initiate communication\n");
- return -EINVAL;
- }
- break;
- default:
- break;
- }
- }
-
- result = rdev->ops->set_channel(&rdev->wiphy,
- wdev ? wdev->netdev : NULL,
- chan, channel_type);
- if (result)
- return result;
-
- if (wdev)
- wdev->channel = chan;
-
- return 0;
+ return rdev->ops->set_monitor_channel(&rdev->wiphy, chan, chantype);
}
diff --git a/net/wireless/core.h b/net/wireless/core.h
index 8523f387867..9348a47562a 100644
--- a/net/wireless/core.h
+++ b/net/wireless/core.h
@@ -303,14 +303,17 @@ extern const struct mesh_config default_mesh_config;
extern const struct mesh_setup default_mesh_setup;
int __cfg80211_join_mesh(struct cfg80211_registered_device *rdev,
struct net_device *dev,
- const struct mesh_setup *setup,
+ struct mesh_setup *setup,
const struct mesh_config *conf);
int cfg80211_join_mesh(struct cfg80211_registered_device *rdev,
struct net_device *dev,
- const struct mesh_setup *setup,
+ struct mesh_setup *setup,
const struct mesh_config *conf);
int cfg80211_leave_mesh(struct cfg80211_registered_device *rdev,
struct net_device *dev);
+int cfg80211_set_mesh_freq(struct cfg80211_registered_device *rdev,
+ struct wireless_dev *wdev, int freq,
+ enum nl80211_channel_type channel_type);
/* MLME */
int __cfg80211_mlme_auth(struct cfg80211_registered_device *rdev,
@@ -441,9 +444,8 @@ cfg80211_can_add_interface(struct cfg80211_registered_device *rdev,
struct ieee80211_channel *
rdev_freq_to_chan(struct cfg80211_registered_device *rdev,
int freq, enum nl80211_channel_type channel_type);
-int cfg80211_set_freq(struct cfg80211_registered_device *rdev,
- struct wireless_dev *wdev, int freq,
- enum nl80211_channel_type channel_type);
+int cfg80211_set_monitor_channel(struct cfg80211_registered_device *rdev,
+ int freq, enum nl80211_channel_type chantype);
int ieee80211_get_ratemask(struct ieee80211_supported_band *sband,
const u8 *rates, unsigned int n_rates,
diff --git a/net/wireless/ibss.c b/net/wireless/ibss.c
index d2a19b0ff71..89baa332841 100644
--- a/net/wireless/ibss.c
+++ b/net/wireless/ibss.c
@@ -42,6 +42,7 @@ void __cfg80211_ibss_joined(struct net_device *dev, const u8 *bssid)
cfg80211_hold_bss(bss_from_pub(bss));
wdev->current_bss = bss_from_pub(bss);
+ wdev->sme_state = CFG80211_SME_CONNECTED;
cfg80211_upload_connect_keys(wdev);
nl80211_send_ibss_bssid(wiphy_to_dev(wdev->wiphy), dev, bssid,
@@ -60,7 +61,7 @@ void cfg80211_ibss_joined(struct net_device *dev, const u8 *bssid, gfp_t gfp)
struct cfg80211_event *ev;
unsigned long flags;
- CFG80211_DEV_WARN_ON(!wdev->ssid_len);
+ CFG80211_DEV_WARN_ON(wdev->sme_state != CFG80211_SME_CONNECTING);
ev = kzalloc(sizeof(*ev), gfp);
if (!ev)
@@ -115,9 +116,11 @@ int __cfg80211_join_ibss(struct cfg80211_registered_device *rdev,
#ifdef CONFIG_CFG80211_WEXT
wdev->wext.ibss.channel = params->channel;
#endif
+ wdev->sme_state = CFG80211_SME_CONNECTING;
err = rdev->ops->join_ibss(&rdev->wiphy, dev, params);
if (err) {
wdev->connect_keys = NULL;
+ wdev->sme_state = CFG80211_SME_IDLE;
return err;
}
@@ -169,6 +172,7 @@ static void __cfg80211_clear_ibss(struct net_device *dev, bool nowext)
}
wdev->current_bss = NULL;
+ wdev->sme_state = CFG80211_SME_IDLE;
wdev->ssid_len = 0;
#ifdef CONFIG_CFG80211_WEXT
if (!nowext)
diff --git a/net/wireless/mesh.c b/net/wireless/mesh.c
index 2749cb86b46..b44c736bf9c 100644
--- a/net/wireless/mesh.c
+++ b/net/wireless/mesh.c
@@ -65,6 +65,9 @@ const struct mesh_config default_mesh_config = {
};
const struct mesh_setup default_mesh_setup = {
+ /* cfg80211_join_mesh() will pick a channel if needed */
+ .channel = NULL,
+ .channel_type = NL80211_CHAN_NO_HT,
.sync_method = IEEE80211_SYNC_METHOD_NEIGHBOR_OFFSET,
.path_sel_proto = IEEE80211_PATH_PROTOCOL_HWMP,
.path_metric = IEEE80211_PATH_METRIC_AIRTIME,
@@ -75,7 +78,7 @@ const struct mesh_setup default_mesh_setup = {
int __cfg80211_join_mesh(struct cfg80211_registered_device *rdev,
struct net_device *dev,
- const struct mesh_setup *setup,
+ struct mesh_setup *setup,
const struct mesh_config *conf)
{
struct wireless_dev *wdev = dev->ieee80211_ptr;
@@ -101,6 +104,51 @@ int __cfg80211_join_mesh(struct cfg80211_registered_device *rdev,
if (!rdev->ops->join_mesh)
return -EOPNOTSUPP;
+ if (!setup->channel) {
+ /* if no channel explicitly given, use preset channel */
+ setup->channel = wdev->preset_chan;
+ setup->channel_type = wdev->preset_chantype;
+ }
+
+ if (!setup->channel) {
+ /* if we don't have that either, use the first usable channel */
+ enum ieee80211_band band;
+
+ for (band = 0; band < IEEE80211_NUM_BANDS; band++) {
+ struct ieee80211_supported_band *sband;
+ struct ieee80211_channel *chan;
+ int i;
+
+ sband = rdev->wiphy.bands[band];
+ if (!sband)
+ continue;
+
+ for (i = 0; i < sband->n_channels; i++) {
+ chan = &sband->channels[i];
+ if (chan->flags & (IEEE80211_CHAN_NO_IBSS |
+ IEEE80211_CHAN_PASSIVE_SCAN |
+ IEEE80211_CHAN_DISABLED |
+ IEEE80211_CHAN_RADAR))
+ continue;
+ setup->channel = chan;
+ break;
+ }
+
+ if (setup->channel)
+ break;
+ }
+
+ /* no usable channel ... */
+ if (!setup->channel)
+ return -EINVAL;
+
+ setup->channel_type = NL80211_CHAN_NO_HT;
+ }
+
+ if (!cfg80211_can_beacon_sec_chan(&rdev->wiphy, setup->channel,
+ setup->channel_type))
+ return -EINVAL;
+
err = rdev->ops->join_mesh(&rdev->wiphy, dev, conf, setup);
if (!err) {
memcpy(wdev->ssid, setup->mesh_id, setup->mesh_id_len);
@@ -112,7 +160,7 @@ int __cfg80211_join_mesh(struct cfg80211_registered_device *rdev,
int cfg80211_join_mesh(struct cfg80211_registered_device *rdev,
struct net_device *dev,
- const struct mesh_setup *setup,
+ struct mesh_setup *setup,
const struct mesh_config *conf)
{
struct wireless_dev *wdev = dev->ieee80211_ptr;
@@ -125,6 +173,45 @@ int cfg80211_join_mesh(struct cfg80211_registered_device *rdev,
return err;
}
+int cfg80211_set_mesh_freq(struct cfg80211_registered_device *rdev,
+ struct wireless_dev *wdev, int freq,
+ enum nl80211_channel_type channel_type)
+{
+ struct ieee80211_channel *channel;
+
+ channel = rdev_freq_to_chan(rdev, freq, channel_type);
+ if (!channel || !cfg80211_can_beacon_sec_chan(&rdev->wiphy,
+ channel,
+ channel_type)) {
+ return -EINVAL;
+ }
+
+ /*
+ * Workaround for libertas (only!), it puts the interface
+ * into mesh mode but doesn't implement join_mesh. Instead,
+ * it is configured via sysfs and then joins the mesh when
+ * you set the channel. Note that the libertas mesh isn't
+ * compatible with 802.11 mesh.
+ */
+ if (rdev->ops->libertas_set_mesh_channel) {
+ if (channel_type != NL80211_CHAN_NO_HT)
+ return -EINVAL;
+
+ if (!netif_running(wdev->netdev))
+ return -ENETDOWN;
+ return rdev->ops->libertas_set_mesh_channel(&rdev->wiphy,
+ wdev->netdev,
+ channel);
+ }
+
+ if (wdev->mesh_id_len)
+ return -EBUSY;
+
+ wdev->preset_chan = channel;
+ wdev->preset_chantype = channel_type;
+ return 0;
+}
+
void cfg80211_notify_new_peer_candidate(struct net_device *dev,
const u8 *macaddr, const u8* ie, u8 ie_len, gfp_t gfp)
{
diff --git a/net/wireless/mlme.c b/net/wireless/mlme.c
index eb90988bbd3..da4406f1192 100644
--- a/net/wireless/mlme.c
+++ b/net/wireless/mlme.c
@@ -947,8 +947,6 @@ void cfg80211_ch_switch_notify(struct net_device *dev, int freq,
if (WARN_ON(!chan))
goto out;
- wdev->channel = chan;
-
nl80211_ch_switch_notify(rdev, dev, freq, type, GFP_KERNEL);
out:
wdev_unlock(wdev);
diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c
index 206465dc0ca..7ae54b82291 100644
--- a/net/wireless/nl80211.c
+++ b/net/wireless/nl80211.c
@@ -921,7 +921,12 @@ static int nl80211_send_wiphy(struct sk_buff *msg, u32 pid, u32 seq, int flags,
if (nla_put_u32(msg, i, NL80211_CMD_SET_WIPHY_NETNS))
goto nla_put_failure;
}
- CMD(set_channel, SET_CHANNEL);
+ if (dev->ops->set_monitor_channel || dev->ops->start_ap ||
+ dev->ops->join_mesh) {
+ i++;
+ if (nla_put_u32(msg, i, NL80211_CMD_SET_CHANNEL))
+ goto nla_put_failure;
+ }
CMD(set_wds_peer, SET_WDS_PEER);
if (dev->wiphy.flags & WIPHY_FLAG_SUPPORTS_TDLS) {
CMD(tdls_mgmt, TDLS_MGMT);
@@ -1162,18 +1167,22 @@ static int parse_txq_params(struct nlattr *tb[],
static bool nl80211_can_set_dev_channel(struct wireless_dev *wdev)
{
/*
- * You can only set the channel explicitly for AP, mesh
- * and WDS type interfaces; all others have their channel
- * managed via their respective "establish a connection"
- * command (connect, join, ...)
+ * You can only set the channel explicitly for WDS interfaces,
+ * all others have their channel managed via their respective
+ * "establish a connection" command (connect, join, ...)
+ *
+ * For AP/GO and mesh mode, the channel can be set with the
+ * channel userspace API, but is only stored and passed to the
+ * low-level driver when the AP starts or the mesh is joined.
+ * This is for backward compatibility, userspace can also give
+ * the channel in the start-ap or join-mesh commands instead.
*
* Monitors are special as they are normally slaved to
- * whatever else is going on, so they behave as though
- * you tried setting the wiphy channel itself.
+ * whatever else is going on, so they have their own special
+ * operation to set the monitor channel if possible.
*/
return !wdev ||
wdev->iftype == NL80211_IFTYPE_AP ||
- wdev->iftype == NL80211_IFTYPE_WDS ||
wdev->iftype == NL80211_IFTYPE_MESH_POINT ||
wdev->iftype == NL80211_IFTYPE_MONITOR ||
wdev->iftype == NL80211_IFTYPE_P2P_GO;
@@ -1204,9 +1213,14 @@ static int __nl80211_set_channel(struct cfg80211_registered_device *rdev,
struct wireless_dev *wdev,
struct genl_info *info)
{
+ struct ieee80211_channel *channel;
enum nl80211_channel_type channel_type = NL80211_CHAN_NO_HT;
u32 freq;
int result;
+ enum nl80211_iftype iftype = NL80211_IFTYPE_MONITOR;
+
+ if (wdev)
+ iftype = wdev->iftype;
if (!info->attrs[NL80211_ATTR_WIPHY_FREQ])
return -EINVAL;
@@ -1221,12 +1235,32 @@ static int __nl80211_set_channel(struct cfg80211_registered_device *rdev,
freq = nla_get_u32(info->attrs[NL80211_ATTR_WIPHY_FREQ]);
mutex_lock(&rdev->devlist_mtx);
- if (wdev) {
- wdev_lock(wdev);
- result = cfg80211_set_freq(rdev, wdev, freq, channel_type);
- wdev_unlock(wdev);
- } else {
- result = cfg80211_set_freq(rdev, NULL, freq, channel_type);
+ switch (iftype) {
+ case NL80211_IFTYPE_AP:
+ case NL80211_IFTYPE_P2P_GO:
+ if (wdev->beacon_interval) {
+ result = -EBUSY;
+ break;
+ }
+ channel = rdev_freq_to_chan(rdev, freq, channel_type);
+ if (!channel || !cfg80211_can_beacon_sec_chan(&rdev->wiphy,
+ channel,
+ channel_type)) {
+ result = -EINVAL;
+ break;
+ }
+ wdev->preset_chan = channel;
+ wdev->preset_chantype = channel_type;
+ result = 0;
+ break;
+ case NL80211_IFTYPE_MESH_POINT:
+ result = cfg80211_set_mesh_freq(rdev, wdev, freq, channel_type);
+ break;
+ case NL80211_IFTYPE_MONITOR:
+ result = cfg80211_set_monitor_channel(rdev, freq, channel_type);
+ break;
+ default:
+ result = -EINVAL;
}
mutex_unlock(&rdev->devlist_mtx);
@@ -1310,8 +1344,7 @@ static int nl80211_set_wiphy(struct sk_buff *skb, struct genl_info *info)
result = 0;
mutex_lock(&rdev->mtx);
- } else if (netif_running(netdev) &&
- nl80211_can_set_dev_channel(netdev->ieee80211_ptr))
+ } else if (nl80211_can_set_dev_channel(netdev->ieee80211_ptr))
wdev = netdev->ieee80211_ptr;
else
wdev = NULL;
@@ -2299,6 +2332,29 @@ static int nl80211_start_ap(struct sk_buff *skb, struct genl_info *info)
info->attrs[NL80211_ATTR_INACTIVITY_TIMEOUT]);
}
+ if (info->attrs[NL80211_ATTR_WIPHY_FREQ]) {
+ enum nl80211_channel_type channel_type = NL80211_CHAN_NO_HT;
+
+ if (info->attrs[NL80211_ATTR_WIPHY_CHANNEL_TYPE] &&
+ !nl80211_valid_channel_type(info, &channel_type))
+ return -EINVAL;
+
+ params.channel = rdev_freq_to_chan(rdev,
+ nla_get_u32(info->attrs[NL80211_ATTR_WIPHY_FREQ]),
+ channel_type);
+ if (!params.channel)
+ return -EINVAL;
+ params.channel_type = channel_type;
+ } else if (wdev->preset_chan) {
+ params.channel = wdev->preset_chan;
+ params.channel_type = wdev->preset_chantype;
+ } else
+ return -EINVAL;
+
+ if (!cfg80211_can_beacon_sec_chan(&rdev->wiphy, params.channel,
+ params.channel_type))
+ return -EINVAL;
+
err = rdev->ops->start_ap(&rdev->wiphy, dev, &params);
if (!err)
wdev->beacon_interval = params.beacon_interval;
@@ -5489,18 +5545,18 @@ static int nl80211_remain_on_channel(struct sk_buff *skb,
duration = nla_get_u32(info->attrs[NL80211_ATTR_DURATION]);
+ if (!rdev->ops->remain_on_channel ||
+ !(rdev->wiphy.flags & WIPHY_FLAG_HAS_REMAIN_ON_CHANNEL))
+ return -EOPNOTSUPP;
+
/*
- * We should be on that channel for at least one jiffie,
- * and more than 5 seconds seems excessive.
+ * We should be on that channel for at least a minimum amount of
+ * time (10ms) but no longer than the driver supports.
*/
- if (!duration || !msecs_to_jiffies(duration) ||
+ if (duration < NL80211_MIN_REMAIN_ON_CHANNEL_TIME ||
duration > rdev->wiphy.max_remain_on_channel_duration)
return -EINVAL;
- if (!rdev->ops->remain_on_channel ||
- !(rdev->wiphy.flags & WIPHY_FLAG_HAS_REMAIN_ON_CHANNEL))
- return -EOPNOTSUPP;
-
if (info->attrs[NL80211_ATTR_WIPHY_CHANNEL_TYPE] &&
!nl80211_valid_channel_type(info, &channel_type))
return -EINVAL;
@@ -5771,6 +5827,15 @@ static int nl80211_tx_mgmt(struct sk_buff *skb, struct genl_info *info)
if (!(rdev->wiphy.flags & WIPHY_FLAG_OFFCHAN_TX))
return -EINVAL;
wait = nla_get_u32(info->attrs[NL80211_ATTR_DURATION]);
+
+ /*
+ * We should wait on the channel for at least a minimum amount
+ * of time (10ms) but no longer than the driver supports.
+ */
+ if (wait < NL80211_MIN_REMAIN_ON_CHANNEL_TIME ||
+ wait > rdev->wiphy.max_remain_on_channel_duration)
+ return -EINVAL;
+
}
if (info->attrs[NL80211_ATTR_WIPHY_CHANNEL_TYPE]) {
@@ -6032,6 +6097,24 @@ static int nl80211_join_mesh(struct sk_buff *skb, struct genl_info *info)
return err;
}
+ if (info->attrs[NL80211_ATTR_WIPHY_FREQ]) {
+ enum nl80211_channel_type channel_type = NL80211_CHAN_NO_HT;
+
+ if (info->attrs[NL80211_ATTR_WIPHY_CHANNEL_TYPE] &&
+ !nl80211_valid_channel_type(info, &channel_type))
+ return -EINVAL;
+
+ setup.channel = rdev_freq_to_chan(rdev,
+ nla_get_u32(info->attrs[NL80211_ATTR_WIPHY_FREQ]),
+ channel_type);
+ if (!setup.channel)
+ return -EINVAL;
+ setup.channel_type = channel_type;
+ } else {
+ /* cfg80211_join_mesh() will sort it out */
+ setup.channel = NULL;
+ }
+
return cfg80211_join_mesh(rdev, dev, &setup, &cfg);
}
diff --git a/net/wireless/util.c b/net/wireless/util.c
index 55d99466bab..8f2d68fc3a4 100644
--- a/net/wireless/util.c
+++ b/net/wireless/util.c
@@ -935,6 +935,7 @@ int cfg80211_can_change_interface(struct cfg80211_registered_device *rdev,
enum nl80211_iftype iftype)
{
struct wireless_dev *wdev_iter;
+ u32 used_iftypes = BIT(iftype);
int num[NUM_NL80211_IFTYPES];
int total = 1;
int i, j;
@@ -961,6 +962,7 @@ int cfg80211_can_change_interface(struct cfg80211_registered_device *rdev,
num[wdev_iter->iftype]++;
total++;
+ used_iftypes |= BIT(wdev_iter->iftype);
}
mutex_unlock(&rdev->devlist_mtx);
@@ -970,6 +972,7 @@ int cfg80211_can_change_interface(struct cfg80211_registered_device *rdev,
for (i = 0; i < rdev->wiphy.n_iface_combinations; i++) {
const struct ieee80211_iface_combination *c;
struct ieee80211_iface_limit *limits;
+ u32 all_iftypes = 0;
c = &rdev->wiphy.iface_combinations[i];
@@ -984,6 +987,7 @@ int cfg80211_can_change_interface(struct cfg80211_registered_device *rdev,
if (rdev->wiphy.software_iftypes & BIT(iftype))
continue;
for (j = 0; j < c->n_limits; j++) {
+ all_iftypes |= limits[j].types;
if (!(limits[j].types & BIT(iftype)))
continue;
if (limits[j].max < num[iftype])
@@ -991,7 +995,20 @@ int cfg80211_can_change_interface(struct cfg80211_registered_device *rdev,
limits[j].max -= num[iftype];
}
}
- /* yay, it fits */
+
+ /*
+ * Finally check that all iftypes that we're currently
+ * using are actually part of this combination. If they
+ * aren't then we can't use this combination and have
+ * to continue to the next.
+ */
+ if ((all_iftypes & used_iftypes) != used_iftypes)
+ goto cont;
+
+ /*
+ * This combination covered all interface types and
+ * supported the requested numbers, so we're good.
+ */
kfree(limits);
return 0;
cont:
diff --git a/net/wireless/wext-compat.c b/net/wireless/wext-compat.c
index 6a6181a673c..bc879833b21 100644
--- a/net/wireless/wext-compat.c
+++ b/net/wireless/wext-compat.c
@@ -796,7 +796,15 @@ static int cfg80211_wext_siwfreq(struct net_device *dev,
case NL80211_IFTYPE_ADHOC:
return cfg80211_ibss_wext_siwfreq(dev, info, wextfreq, extra);
case NL80211_IFTYPE_MONITOR:
- case NL80211_IFTYPE_WDS:
+ freq = cfg80211_wext_freq(wdev->wiphy, wextfreq);
+ if (freq < 0)
+ return freq;
+ if (freq == 0)
+ return -EINVAL;
+ mutex_lock(&rdev->devlist_mtx);
+ err = cfg80211_set_monitor_channel(rdev, freq, NL80211_CHAN_NO_HT);
+ mutex_unlock(&rdev->devlist_mtx);
+ return err;
case NL80211_IFTYPE_MESH_POINT:
freq = cfg80211_wext_freq(wdev->wiphy, wextfreq);
if (freq < 0)
@@ -804,9 +812,8 @@ static int cfg80211_wext_siwfreq(struct net_device *dev,
if (freq == 0)
return -EINVAL;
mutex_lock(&rdev->devlist_mtx);
- wdev_lock(wdev);
- err = cfg80211_set_freq(rdev, wdev, freq, NL80211_CHAN_NO_HT);
- wdev_unlock(wdev);
+ err = cfg80211_set_mesh_freq(rdev, wdev, freq,
+ NL80211_CHAN_NO_HT);
mutex_unlock(&rdev->devlist_mtx);
return err;
default:
@@ -839,11 +846,7 @@ static int cfg80211_wext_giwfreq(struct net_device *dev,
freq->e = 6;
return 0;
default:
- if (!wdev->channel)
- return -EINVAL;
- freq->m = wdev->channel->center_freq;
- freq->e = 6;
- return 0;
+ return -EINVAL;
}
}
diff --git a/net/wireless/wext-sme.c b/net/wireless/wext-sme.c
index 7decbd357d5..1f773f668d1 100644
--- a/net/wireless/wext-sme.c
+++ b/net/wireless/wext-sme.c
@@ -111,9 +111,15 @@ int cfg80211_mgd_wext_siwfreq(struct net_device *dev,
wdev->wext.connect.channel = chan;
- /* SSID is not set, we just want to switch channel */
+ /*
+ * SSID is not set, we just want to switch monitor channel,
+ * this is really just backward compatibility, if the SSID
+ * is set then we use the channel to select the BSS to use
+ * to connect to instead. If we were connected on another
+ * channel we disconnected above and reconnect below.
+ */
if (chan && !wdev->wext.connect.ssid_len) {
- err = cfg80211_set_freq(rdev, wdev, freq, NL80211_CHAN_NO_HT);
+ err = cfg80211_set_monitor_channel(rdev, freq, NL80211_CHAN_NO_HT);
goto out;
}