summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDavid S. Miller <davem@davemloft.net>2018-03-29 16:24:06 -0400
committerDavid S. Miller <davem@davemloft.net>2018-03-29 16:24:06 -0400
commit18845557fd6fc1998f2d0d8c30467f86db587529 (patch)
tree80e3f239192cb421b54f8e6d85c03270c5ac394d
parente15f20ea33b8e5074145abe464b4b48acea505d9 (diff)
parent14c99949a3398a655c47b262ca8e2e83edfae7fd (diff)
downloadlinux-18845557fd6fc1998f2d0d8c30467f86db587529.tar.gz
linux-18845557fd6fc1998f2d0d8c30467f86db587529.tar.bz2
linux-18845557fd6fc1998f2d0d8c30467f86db587529.zip
Merge tag 'wireless-drivers-next-for-davem-2018-03-29' of git://git.kernel.org/pub/scm/linux/kernel/git/kvalo/wireless-drivers-next
Kalle Valo says: ==================== wireless-drivers-next patches for 4.17 Smaller new features to various drivers but nothing really out of ordinary. Major changes: ath10k * enable chip temperature measurement for QCA6174/QCA9377 * add firmware memory dump for QCA9984 * enable buffer STA on TDLS link for QCA6174 * support different beacon internals in multiple interface scenario for QCA988X/QCA99X0/QCA9984/QCA4019 iwlwifi * support for new PCI IDs for the 9000 family * support for a new firmware API version * support for advanced dwell and Optimized Connectivity Experience (OCE) in scanning btrsi * fix kconfig dependencies wil6210 * support multiple virtual interfaces ==================== Signed-off-by: David S. Miller <davem@davemloft.net>
-rw-r--r--drivers/bluetooth/Kconfig4
-rw-r--r--drivers/net/wireless/ath/ath.h2
-rw-r--r--drivers/net/wireless/ath/ath10k/core.c9
-rw-r--r--drivers/net/wireless/ath/ath10k/core.h88
-rw-r--r--drivers/net/wireless/ath/ath10k/coredump.c90
-rw-r--r--drivers/net/wireless/ath/ath10k/coredump.h2
-rw-r--r--drivers/net/wireless/ath/ath10k/debug.c154
-rw-r--r--drivers/net/wireless/ath/ath10k/debug.h41
-rw-r--r--drivers/net/wireless/ath/ath10k/debugfs_sta.c286
-rw-r--r--drivers/net/wireless/ath/ath10k/htt_rx.c113
-rw-r--r--drivers/net/wireless/ath/ath10k/mac.c54
-rw-r--r--drivers/net/wireless/ath/ath10k/pci.c101
-rw-r--r--drivers/net/wireless/ath/ath10k/trace.h12
-rw-r--r--drivers/net/wireless/ath/ath10k/txrx.c12
-rw-r--r--drivers/net/wireless/ath/ath10k/wmi-ops.h56
-rw-r--r--drivers/net/wireless/ath/ath10k/wmi-tlv.c116
-rw-r--r--drivers/net/wireless/ath/ath10k/wmi-tlv.h18
-rw-r--r--drivers/net/wireless/ath/ath10k/wmi.c462
-rw-r--r--drivers/net/wireless/ath/ath10k/wmi.h94
-rw-r--r--drivers/net/wireless/ath/ath5k/attach.c2
-rw-r--r--drivers/net/wireless/ath/ath5k/base.c6
-rw-r--r--drivers/net/wireless/ath/ath5k/debug.c37
-rw-r--r--drivers/net/wireless/ath/ath5k/qcu.c2
-rw-r--r--drivers/net/wireless/ath/ath5k/sysfs.c8
-rw-r--r--drivers/net/wireless/ath/ath6kl/debug.c43
-rw-r--r--drivers/net/wireless/ath/ath9k/common-debug.c9
-rw-r--r--drivers/net/wireless/ath/ath9k/common-init.c2
-rw-r--r--drivers/net/wireless/ath/ath9k/common-spectral.c22
-rw-r--r--drivers/net/wireless/ath/ath9k/debug.c40
-rw-r--r--drivers/net/wireless/ath/ath9k/debug_sta.c6
-rw-r--r--drivers/net/wireless/ath/ath9k/dfs_debug.c4
-rw-r--r--drivers/net/wireless/ath/ath9k/htc_drv_debug.c16
-rw-r--r--drivers/net/wireless/ath/ath9k/htc_drv_init.c2
-rw-r--r--drivers/net/wireless/ath/ath9k/hw.c14
-rw-r--r--drivers/net/wireless/ath/ath9k/init.c11
-rw-r--r--drivers/net/wireless/ath/ath9k/tx99.c4
-rw-r--r--drivers/net/wireless/ath/ath9k/xmit.c4
-rw-r--r--drivers/net/wireless/ath/carl9170/debug.c8
-rw-r--r--drivers/net/wireless/ath/carl9170/main.c4
-rw-r--r--drivers/net/wireless/ath/dfs_pattern_detector.c2
-rw-r--r--drivers/net/wireless/ath/wcn36xx/debug.c5
-rw-r--r--drivers/net/wireless/ath/wcn36xx/dxe.c69
-rw-r--r--drivers/net/wireless/ath/wcn36xx/dxe.h221
-rw-r--r--drivers/net/wireless/ath/wcn36xx/main.c14
-rw-r--r--drivers/net/wireless/ath/wcn36xx/smd.c115
-rw-r--r--drivers/net/wireless/ath/wcn36xx/txrx.c32
-rw-r--r--drivers/net/wireless/ath/wcn36xx/wcn36xx.h2
-rw-r--r--drivers/net/wireless/ath/wil6210/cfg80211.c741
-rw-r--r--drivers/net/wireless/ath/wil6210/debug.c9
-rw-r--r--drivers/net/wireless/ath/wil6210/debugfs.c117
-rw-r--r--drivers/net/wireless/ath/wil6210/ethtool.c4
-rw-r--r--drivers/net/wireless/ath/wil6210/fw.h38
-rw-r--r--drivers/net/wireless/ath/wil6210/fw_inc.c52
-rw-r--r--drivers/net/wireless/ath/wil6210/interrupt.c8
-rw-r--r--drivers/net/wireless/ath/wil6210/main.c333
-rw-r--r--drivers/net/wireless/ath/wil6210/netdev.c382
-rw-r--r--drivers/net/wireless/ath/wil6210/p2p.c175
-rw-r--r--drivers/net/wireless/ath/wil6210/pcie_bus.c57
-rw-r--r--drivers/net/wireless/ath/wil6210/pm.c132
-rw-r--r--drivers/net/wireless/ath/wil6210/pmc.c8
-rw-r--r--drivers/net/wireless/ath/wil6210/rx_reorder.c45
-rw-r--r--drivers/net/wireless/ath/wil6210/txrx.c177
-rw-r--r--drivers/net/wireless/ath/wil6210/txrx.h22
-rw-r--r--drivers/net/wireless/ath/wil6210/wil6210.h217
-rw-r--r--drivers/net/wireless/ath/wil6210/wmi.c460
-rw-r--r--drivers/net/wireless/broadcom/brcm80211/brcmfmac/bcdc.c6
-rw-r--r--drivers/net/wireless/broadcom/brcm80211/brcmfmac/btcoex.c2
-rw-r--r--drivers/net/wireless/broadcom/brcm80211/brcmfmac/bus.h7
-rw-r--r--drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c88
-rw-r--r--drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.h17
-rw-r--r--drivers/net/wireless/broadcom/brcm80211/brcmfmac/chip.c14
-rw-r--r--drivers/net/wireless/broadcom/brcm80211/brcmfmac/chip.h3
-rw-r--r--drivers/net/wireless/broadcom/brcm80211/brcmfmac/common.c82
-rw-r--r--drivers/net/wireless/broadcom/brcm80211/brcmfmac/common.h1
-rw-r--r--drivers/net/wireless/broadcom/brcm80211/brcmfmac/core.c105
-rw-r--r--drivers/net/wireless/broadcom/brcm80211/brcmfmac/core.h4
-rw-r--r--drivers/net/wireless/broadcom/brcm80211/brcmfmac/debug.c42
-rw-r--r--drivers/net/wireless/broadcom/brcm80211/brcmfmac/debug.h17
-rw-r--r--drivers/net/wireless/broadcom/brcm80211/brcmfmac/feature.c3
-rw-r--r--drivers/net/wireless/broadcom/brcm80211/brcmfmac/feature.h7
-rw-r--r--drivers/net/wireless/broadcom/brcm80211/brcmfmac/firmware.c242
-rw-r--r--drivers/net/wireless/broadcom/brcm80211/brcmfmac/firmware.h82
-rw-r--r--drivers/net/wireless/broadcom/brcm80211/brcmfmac/fwil.c3
-rw-r--r--drivers/net/wireless/broadcom/brcm80211/brcmfmac/fwsignal.c11
-rw-r--r--drivers/net/wireless/broadcom/brcm80211/brcmfmac/fwsignal.h1
-rw-r--r--drivers/net/wireless/broadcom/brcm80211/brcmfmac/msgbuf.c8
-rw-r--r--drivers/net/wireless/broadcom/brcm80211/brcmfmac/p2p.c2
-rw-r--r--drivers/net/wireless/broadcom/brcm80211/brcmfmac/pcie.c157
-rw-r--r--drivers/net/wireless/broadcom/brcm80211/brcmfmac/proto.c3
-rw-r--r--drivers/net/wireless/broadcom/brcm80211/brcmfmac/proto.h7
-rw-r--r--drivers/net/wireless/broadcom/brcm80211/brcmfmac/sdio.c151
-rw-r--r--drivers/net/wireless/broadcom/brcm80211/brcmfmac/usb.c96
-rw-r--r--drivers/net/wireless/broadcom/brcm80211/brcmsmac/debug.c2
-rw-r--r--drivers/net/wireless/broadcom/brcm80211/brcmsmac/mac80211_if.c6
-rw-r--r--drivers/net/wireless/cisco/airo.c6
-rw-r--r--drivers/net/wireless/intel/ipw2x00/ipw2100.c29
-rw-r--r--drivers/net/wireless/intel/ipw2x00/ipw2200.c51
-rw-r--r--drivers/net/wireless/intel/ipw2x00/libipw_module.c2
-rw-r--r--drivers/net/wireless/intel/iwlegacy/3945-mac.c35
-rw-r--r--drivers/net/wireless/intel/iwlegacy/4965-mac.c19
-rw-r--r--drivers/net/wireless/intel/iwlegacy/4965-rs.c8
-rw-r--r--drivers/net/wireless/intel/iwlegacy/common.c4
-rw-r--r--drivers/net/wireless/intel/iwlegacy/debug.c58
-rw-r--r--drivers/net/wireless/intel/iwlwifi/cfg/22000.c4
-rw-r--r--drivers/net/wireless/intel/iwlwifi/cfg/9000.c66
-rw-r--r--drivers/net/wireless/intel/iwlwifi/dvm/debugfs.c78
-rw-r--r--drivers/net/wireless/intel/iwlwifi/dvm/rs.c16
-rw-r--r--drivers/net/wireless/intel/iwlwifi/fw/api/nvm-reg.h20
-rw-r--r--drivers/net/wireless/intel/iwlwifi/fw/api/scan.h73
-rw-r--r--drivers/net/wireless/intel/iwlwifi/fw/dbg.c10
-rw-r--r--drivers/net/wireless/intel/iwlwifi/fw/debugfs.c26
-rw-r--r--drivers/net/wireless/intel/iwlwifi/fw/debugfs.h5
-rw-r--r--drivers/net/wireless/intel/iwlwifi/fw/file.h17
-rw-r--r--drivers/net/wireless/intel/iwlwifi/iwl-config.h5
-rw-r--r--drivers/net/wireless/intel/iwlwifi/iwl-drv.c43
-rw-r--r--drivers/net/wireless/intel/iwlwifi/mvm/constants.h2
-rw-r--r--drivers/net/wireless/intel/iwlwifi/mvm/debugfs-vif.c51
-rw-r--r--drivers/net/wireless/intel/iwlwifi/mvm/debugfs.c110
-rw-r--r--drivers/net/wireless/intel/iwlwifi/mvm/fw.c4
-rw-r--r--drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c24
-rw-r--r--drivers/net/wireless/intel/iwlwifi/mvm/mvm.h51
-rw-r--r--drivers/net/wireless/intel/iwlwifi/mvm/ops.c6
-rw-r--r--drivers/net/wireless/intel/iwlwifi/mvm/phy-ctxt.c21
-rw-r--r--drivers/net/wireless/intel/iwlwifi/mvm/rs-fw.c6
-rw-r--r--drivers/net/wireless/intel/iwlwifi/mvm/rs.c12
-rw-r--r--drivers/net/wireless/intel/iwlwifi/mvm/rxmq.c25
-rw-r--r--drivers/net/wireless/intel/iwlwifi/mvm/scan.c199
-rw-r--r--drivers/net/wireless/intel/iwlwifi/mvm/sta.c74
-rw-r--r--drivers/net/wireless/intel/iwlwifi/mvm/time-event.c15
-rw-r--r--drivers/net/wireless/intel/iwlwifi/mvm/tx.c168
-rw-r--r--drivers/net/wireless/intel/iwlwifi/mvm/utils.c19
-rw-r--r--drivers/net/wireless/intel/iwlwifi/pcie/drv.c195
-rw-r--r--drivers/net/wireless/intel/iwlwifi/pcie/trans.c12
-rw-r--r--drivers/net/wireless/intersil/p54/main.c2
-rw-r--r--drivers/net/wireless/marvell/mwifiex/11n.c10
-rw-r--r--drivers/net/wireless/mediatek/mt76/debugfs.c10
-rw-r--r--drivers/net/wireless/mediatek/mt76/mt76x2_debugfs.c8
-rw-r--r--drivers/net/wireless/mediatek/mt76/mt76x2_main.c11
-rw-r--r--drivers/net/wireless/mediatek/mt76/mt76x2_mcu.c13
-rw-r--r--drivers/net/wireless/mediatek/mt76/mt76x2_tx.c5
-rw-r--r--drivers/net/wireless/mediatek/mt7601u/debugfs.c16
-rw-r--r--drivers/net/wireless/ralink/rt2x00/rt2500usb.c2
-rw-r--r--drivers/net/wireless/ralink/rt2x00/rt2800pci.c2
-rw-r--r--drivers/net/wireless/ralink/rt2x00/rt2800soc.c2
-rw-r--r--drivers/net/wireless/ralink/rt2x00/rt2800usb.c2
-rw-r--r--drivers/net/wireless/ralink/rt2x00/rt2x00debug.c64
-rw-r--r--drivers/net/wireless/ralink/rt2x00/rt61pci.c2
-rw-r--r--drivers/net/wireless/ralink/rt2x00/rt73usb.c2
-rw-r--r--drivers/net/wireless/ray_cs.c8
-rw-r--r--drivers/net/wireless/realtek/rtlwifi/base.c1
-rw-r--r--drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtc8723b1ant.c1
-rw-r--r--drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtc8723b2ant.c6
-rw-r--r--drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtc8821a1ant.c33
-rw-r--r--drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtc8821a2ant.c4
-rw-r--r--drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtcoutsrc.c86
-rw-r--r--drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtcoutsrc.h122
-rw-r--r--drivers/net/wireless/realtek/rtlwifi/rtl8188ee/pwrseq.h4
-rw-r--r--drivers/net/wireless/realtek/rtlwifi/rtl8192ee/pwrseq.h4
-rw-r--r--drivers/net/wireless/realtek/rtlwifi/rtl8723ae/pwrseq.h4
-rw-r--r--drivers/net/wireless/realtek/rtlwifi/rtl8723be/pwrseq.h4
-rw-r--r--drivers/net/wireless/realtek/rtlwifi/rtl8821ae/dm.c16
-rw-r--r--drivers/net/wireless/realtek/rtlwifi/rtl8821ae/pwrseq.h4
-rw-r--r--drivers/net/wireless/realtek/rtlwifi/wifi.h33
-rw-r--r--drivers/net/wireless/rsi/Kconfig4
-rw-r--r--drivers/net/wireless/rsi/rsi_91x_sdio.c65
-rw-r--r--drivers/net/wireless/rsi/rsi_91x_usb.c1
-rw-r--r--drivers/net/wireless/rsi/rsi_sdio.h2
-rw-r--r--drivers/net/wireless/st/cw1200/debug.c6
-rw-r--r--drivers/net/wireless/st/cw1200/main.c2
-rw-r--r--drivers/net/wireless/ti/wl18xx/main.c27
-rw-r--r--drivers/net/wireless/ti/wlcore/main.c8
-rw-r--r--drivers/net/wireless/ti/wlcore/sdio.c2
-rw-r--r--drivers/net/wireless/ti/wlcore/sysfs.c7
173 files changed, 6233 insertions, 2505 deletions
diff --git a/drivers/bluetooth/Kconfig b/drivers/bluetooth/Kconfig
index d8bbd661dbdb..149a38ee1fce 100644
--- a/drivers/bluetooth/Kconfig
+++ b/drivers/bluetooth/Kconfig
@@ -393,9 +393,7 @@ config BT_QCOMSMD
kernel or say M to compile as a module.
config BT_HCIRSI
- tristate "Redpine HCI support"
- default n
- select RSI_COEX
+ tristate
help
Redpine BT driver.
This driver handles BT traffic from upper layers and pass
diff --git a/drivers/net/wireless/ath/ath.h b/drivers/net/wireless/ath/ath.h
index f3f2784f6ebd..7a364eca46d6 100644
--- a/drivers/net/wireless/ath/ath.h
+++ b/drivers/net/wireless/ath/ath.h
@@ -33,8 +33,6 @@
*/
#define ATH_KEYMAX 128 /* max key cache size we handle */
-static const u8 ath_bcast_mac[ETH_ALEN] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff};
-
struct ath_ani {
bool caldone;
unsigned int longcal_timer;
diff --git a/drivers/net/wireless/ath/ath10k/core.c b/drivers/net/wireless/ath/ath10k/core.c
index f3ec13b80b20..8a3020dbd4cf 100644
--- a/drivers/net/wireless/ath/ath10k/core.c
+++ b/drivers/net/wireless/ath/ath10k/core.c
@@ -1,6 +1,7 @@
/*
* Copyright (c) 2005-2011 Atheros Communications Inc.
* Copyright (c) 2011-2017 Qualcomm Atheros, Inc.
+ * Copyright (c) 2018, The Linux Foundation. All rights reserved.
*
* Permission to use, copy, modify, and/or distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
@@ -2040,7 +2041,8 @@ static int ath10k_core_init_firmware_features(struct ath10k *ar)
ar->max_num_vdevs = TARGET_10_4_NUM_VDEVS;
ar->num_tids = TARGET_10_4_TGT_NUM_TIDS;
ar->fw_stats_req_mask = WMI_10_4_STAT_PEER |
- WMI_10_4_STAT_PEER_EXTD;
+ WMI_10_4_STAT_PEER_EXTD |
+ WMI_10_4_STAT_VDEV_EXTD;
ar->max_spatial_stream = ar->hw_params.max_spatial_stream;
ar->max_num_tdls_vdevs = TARGET_10_4_NUM_TDLS_VDEVS;
@@ -2281,6 +2283,9 @@ int ath10k_core_start(struct ath10k *ar, enum ath10k_firmware_mode mode,
if (ath10k_peer_stats_enabled(ar))
val = WMI_10_4_PEER_STATS;
+ /* Enable vdev stats by default */
+ val |= WMI_10_4_VDEV_STATS;
+
if (test_bit(WMI_SERVICE_BSS_CHANNEL_INFO_64, ar->wmi.svc_map))
val |= WMI_10_4_BSS_CHANNEL_INFO_64;
@@ -2439,7 +2444,7 @@ static int ath10k_core_probe_fw(struct ath10k *ar)
ret = ath10k_hif_power_up(ar);
if (ret) {
- ath10k_err(ar, "could not start pci hif (%d)\n", ret);
+ ath10k_err(ar, "could not power on hif bus (%d)\n", ret);
return ret;
}
diff --git a/drivers/net/wireless/ath/ath10k/core.h b/drivers/net/wireless/ath/ath10k/core.h
index fe6b30356d3b..c17d805d68cc 100644
--- a/drivers/net/wireless/ath/ath10k/core.h
+++ b/drivers/net/wireless/ath/ath10k/core.h
@@ -1,6 +1,7 @@
/*
* Copyright (c) 2005-2011 Atheros Communications Inc.
* Copyright (c) 2011-2017 Qualcomm Atheros, Inc.
+ * Copyright (c) 2018, The Linux Foundation. All rights reserved.
*
* Permission to use, copy, modify, and/or distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
@@ -221,6 +222,27 @@ struct ath10k_fw_stats_vdev {
u32 beacon_rssi_history[10];
};
+struct ath10k_fw_stats_vdev_extd {
+ struct list_head list;
+
+ u32 vdev_id;
+ u32 ppdu_aggr_cnt;
+ u32 ppdu_noack;
+ u32 mpdu_queued;
+ u32 ppdu_nonaggr_cnt;
+ u32 mpdu_sw_requeued;
+ u32 mpdu_suc_retry;
+ u32 mpdu_suc_multitry;
+ u32 mpdu_fail_retry;
+ u32 tx_ftm_suc;
+ u32 tx_ftm_suc_retry;
+ u32 tx_ftm_fail;
+ u32 rx_ftmr_cnt;
+ u32 rx_ftmr_dup_cnt;
+ u32 rx_iftmr_cnt;
+ u32 rx_iftmr_dup_cnt;
+};
+
struct ath10k_fw_stats_pdev {
struct list_head list;
@@ -324,6 +346,27 @@ struct ath10k_tpc_stats {
struct ath10k_tpc_table tpc_table[WMI_TPC_FLAG];
};
+struct ath10k_tpc_table_final {
+ u32 pream_idx[WMI_TPC_FINAL_RATE_MAX];
+ u8 rate_code[WMI_TPC_FINAL_RATE_MAX];
+ char tpc_value[WMI_TPC_FINAL_RATE_MAX][WMI_TPC_TX_N_CHAIN * WMI_TPC_BUF_SIZE];
+};
+
+struct ath10k_tpc_stats_final {
+ u32 reg_domain;
+ u32 chan_freq;
+ u32 phy_mode;
+ u32 twice_antenna_reduction;
+ u32 twice_max_rd_power;
+ s32 twice_antenna_gain;
+ u32 power_limit;
+ u32 num_tx_chain;
+ u32 ctl;
+ u32 rate_max;
+ u8 flag[WMI_TPC_FLAG];
+ struct ath10k_tpc_table_final tpc_table_final[WMI_TPC_FLAG];
+};
+
struct ath10k_dfs_stats {
u32 phy_errors;
u32 pulses_total;
@@ -354,6 +397,45 @@ struct ath10k_txq {
unsigned long num_push_allowed;
};
+enum ath10k_pkt_rx_err {
+ ATH10K_PKT_RX_ERR_FCS,
+ ATH10K_PKT_RX_ERR_TKIP,
+ ATH10K_PKT_RX_ERR_CRYPT,
+ ATH10K_PKT_RX_ERR_PEER_IDX_INVAL,
+ ATH10K_PKT_RX_ERR_MAX,
+};
+
+enum ath10k_ampdu_subfrm_num {
+ ATH10K_AMPDU_SUBFRM_NUM_10,
+ ATH10K_AMPDU_SUBFRM_NUM_20,
+ ATH10K_AMPDU_SUBFRM_NUM_30,
+ ATH10K_AMPDU_SUBFRM_NUM_40,
+ ATH10K_AMPDU_SUBFRM_NUM_50,
+ ATH10K_AMPDU_SUBFRM_NUM_60,
+ ATH10K_AMPDU_SUBFRM_NUM_MORE,
+ ATH10K_AMPDU_SUBFRM_NUM_MAX,
+};
+
+enum ath10k_amsdu_subfrm_num {
+ ATH10K_AMSDU_SUBFRM_NUM_1,
+ ATH10K_AMSDU_SUBFRM_NUM_2,
+ ATH10K_AMSDU_SUBFRM_NUM_3,
+ ATH10K_AMSDU_SUBFRM_NUM_4,
+ ATH10K_AMSDU_SUBFRM_NUM_MORE,
+ ATH10K_AMSDU_SUBFRM_NUM_MAX,
+};
+
+struct ath10k_sta_tid_stats {
+ unsigned long int rx_pkt_from_fw;
+ unsigned long int rx_pkt_unchained;
+ unsigned long int rx_pkt_drop_chained;
+ unsigned long int rx_pkt_drop_filter;
+ unsigned long int rx_pkt_err[ATH10K_PKT_RX_ERR_MAX];
+ unsigned long int rx_pkt_queued_for_mac;
+ unsigned long int rx_pkt_ampdu[ATH10K_AMPDU_SUBFRM_NUM_MAX];
+ unsigned long int rx_pkt_amsdu[ATH10K_AMSDU_SUBFRM_NUM_MAX];
+};
+
struct ath10k_sta {
struct ath10k_vif *arvif;
@@ -371,6 +453,9 @@ struct ath10k_sta {
#ifdef CONFIG_MAC80211_DEBUGFS
/* protected by conf_mutex */
bool aggr_mode;
+
+ /* Protected with ar->data_lock */
+ struct ath10k_sta_tid_stats tid_stats[IEEE80211_NUM_TIDS + 1];
#endif
};
@@ -487,6 +572,7 @@ struct ath10k_debug {
/* used for tpc-dump storage, protected by data-lock */
struct ath10k_tpc_stats *tpc_stats;
+ struct ath10k_tpc_stats_final *tpc_stats_final;
struct completion tpc_complete;
@@ -1019,6 +1105,8 @@ struct ath10k {
void *ce_priv;
+ u32 sta_tid_stats_mask;
+
/* must be last */
u8 drv_priv[0] __aligned(sizeof(void *));
};
diff --git a/drivers/net/wireless/ath/ath10k/coredump.c b/drivers/net/wireless/ath/ath10k/coredump.c
index 7173b3743b43..f90cec0ebb1c 100644
--- a/drivers/net/wireless/ath/ath10k/coredump.c
+++ b/drivers/net/wireless/ath/ath10k/coredump.c
@@ -701,6 +701,89 @@ static const struct ath10k_mem_region qca988x_hw20_mem_regions[] = {
},
};
+static const struct ath10k_mem_region qca9984_hw10_mem_regions[] = {
+ {
+ .type = ATH10K_MEM_REGION_TYPE_DRAM,
+ .start = 0x400000,
+ .len = 0x80000,
+ .name = "DRAM",
+ .section_table = {
+ .sections = NULL,
+ .size = 0,
+ },
+ },
+ {
+ .type = ATH10K_MEM_REGION_TYPE_REG,
+ .start = 0x98000,
+ .len = 0x50000,
+ .name = "IRAM",
+ .section_table = {
+ .sections = NULL,
+ .size = 0,
+ },
+ },
+ {
+ .type = ATH10K_MEM_REGION_TYPE_IOSRAM,
+ .start = 0xC0000,
+ .len = 0x40000,
+ .name = "SRAM",
+ .section_table = {
+ .sections = NULL,
+ .size = 0,
+ },
+ },
+ {
+ .type = ATH10K_MEM_REGION_TYPE_IOREG,
+ .start = 0x30000,
+ .len = 0x7000,
+ .name = "APB REG 1",
+ .section_table = {
+ .sections = NULL,
+ .size = 0,
+ },
+ },
+ {
+ .type = ATH10K_MEM_REGION_TYPE_IOREG,
+ .start = 0x3f000,
+ .len = 0x3000,
+ .name = "APB REG 2",
+ .section_table = {
+ .sections = NULL,
+ .size = 0,
+ },
+ },
+ {
+ .type = ATH10K_MEM_REGION_TYPE_IOREG,
+ .start = 0x43000,
+ .len = 0x3000,
+ .name = "WIFI REG",
+ .section_table = {
+ .sections = NULL,
+ .size = 0,
+ },
+ },
+ {
+ .type = ATH10K_MEM_REGION_TYPE_IOREG,
+ .start = 0x4A000,
+ .len = 0x5000,
+ .name = "CE REG",
+ .section_table = {
+ .sections = NULL,
+ .size = 0,
+ },
+ },
+ {
+ .type = ATH10K_MEM_REGION_TYPE_IOREG,
+ .start = 0x80000,
+ .len = 0x6000,
+ .name = "SOC REG",
+ .section_table = {
+ .sections = NULL,
+ .size = 0,
+ },
+ },
+};
+
static const struct ath10k_hw_mem_layout hw_mem_layouts[] = {
{
.hw_id = QCA6174_HW_1_0_VERSION,
@@ -758,6 +841,13 @@ static const struct ath10k_hw_mem_layout hw_mem_layouts[] = {
.size = ARRAY_SIZE(qca988x_hw20_mem_regions),
},
},
+ {
+ .hw_id = QCA9984_HW_1_0_DEV_VERSION,
+ .region_table = {
+ .regions = qca9984_hw10_mem_regions,
+ .size = ARRAY_SIZE(qca9984_hw10_mem_regions),
+ },
+ },
};
static u32 ath10k_coredump_get_ramdump_size(struct ath10k *ar)
diff --git a/drivers/net/wireless/ath/ath10k/coredump.h b/drivers/net/wireless/ath/ath10k/coredump.h
index bfee13038e59..3baaf9d2cbcd 100644
--- a/drivers/net/wireless/ath/ath10k/coredump.h
+++ b/drivers/net/wireless/ath/ath10k/coredump.h
@@ -124,6 +124,8 @@ enum ath10k_mem_region_type {
ATH10K_MEM_REGION_TYPE_AXI = 3,
ATH10K_MEM_REGION_TYPE_IRAM1 = 4,
ATH10K_MEM_REGION_TYPE_IRAM2 = 5,
+ ATH10K_MEM_REGION_TYPE_IOSRAM = 6,
+ ATH10K_MEM_REGION_TYPE_IOREG = 7,
};
/* Define a section of the region which should be copied. As not all parts
diff --git a/drivers/net/wireless/ath/ath10k/debug.c b/drivers/net/wireless/ath/ath10k/debug.c
index 554cd7856cb6..bac832ce1873 100644
--- a/drivers/net/wireless/ath/ath10k/debug.c
+++ b/drivers/net/wireless/ath/ath10k/debug.c
@@ -1480,6 +1480,19 @@ void ath10k_debug_tpc_stats_process(struct ath10k *ar,
spin_unlock_bh(&ar->data_lock);
}
+void
+ath10k_debug_tpc_stats_final_process(struct ath10k *ar,
+ struct ath10k_tpc_stats_final *tpc_stats)
+{
+ spin_lock_bh(&ar->data_lock);
+
+ kfree(ar->debug.tpc_stats_final);
+ ar->debug.tpc_stats_final = tpc_stats;
+ complete(&ar->debug.tpc_complete);
+
+ spin_unlock_bh(&ar->data_lock);
+}
+
static void ath10k_tpc_stats_print(struct ath10k_tpc_stats *tpc_stats,
unsigned int j, char *buf, size_t *len)
{
@@ -2143,6 +2156,137 @@ static const struct file_operations fops_fw_checksums = {
.llseek = default_llseek,
};
+static ssize_t ath10k_sta_tid_stats_mask_read(struct file *file,
+ char __user *user_buf,
+ size_t count, loff_t *ppos)
+{
+ struct ath10k *ar = file->private_data;
+ char buf[32];
+ size_t len;
+
+ len = scnprintf(buf, sizeof(buf), "0x%08x\n", ar->sta_tid_stats_mask);
+ return simple_read_from_buffer(user_buf, count, ppos, buf, len);
+}
+
+static ssize_t ath10k_sta_tid_stats_mask_write(struct file *file,
+ const char __user *user_buf,
+ size_t count, loff_t *ppos)
+{
+ struct ath10k *ar = file->private_data;
+ char buf[32];
+ ssize_t len;
+ u32 mask;
+
+ len = min(count, sizeof(buf) - 1);
+ if (copy_from_user(buf, user_buf, len))
+ return -EFAULT;
+
+ buf[len] = '\0';
+ if (kstrtoint(buf, 0, &mask))
+ return -EINVAL;
+
+ ar->sta_tid_stats_mask = mask;
+
+ return len;
+}
+
+static const struct file_operations fops_sta_tid_stats_mask = {
+ .read = ath10k_sta_tid_stats_mask_read,
+ .write = ath10k_sta_tid_stats_mask_write,
+ .open = simple_open,
+ .owner = THIS_MODULE,
+ .llseek = default_llseek,
+};
+
+static int ath10k_debug_tpc_stats_final_request(struct ath10k *ar)
+{
+ int ret;
+ unsigned long time_left;
+
+ lockdep_assert_held(&ar->conf_mutex);
+
+ reinit_completion(&ar->debug.tpc_complete);
+
+ ret = ath10k_wmi_pdev_get_tpc_table_cmdid(ar, WMI_TPC_CONFIG_PARAM);
+ if (ret) {
+ ath10k_warn(ar, "failed to request tpc table cmdid: %d\n", ret);
+ return ret;
+ }
+
+ time_left = wait_for_completion_timeout(&ar->debug.tpc_complete,
+ 1 * HZ);
+ if (time_left == 0)
+ return -ETIMEDOUT;
+
+ return 0;
+}
+
+static int ath10k_tpc_stats_final_open(struct inode *inode, struct file *file)
+{
+ struct ath10k *ar = inode->i_private;
+ void *buf;
+ int ret;
+
+ mutex_lock(&ar->conf_mutex);
+
+ if (ar->state != ATH10K_STATE_ON) {
+ ret = -ENETDOWN;
+ goto err_unlock;
+ }
+
+ buf = vmalloc(ATH10K_TPC_CONFIG_BUF_SIZE);
+ if (!buf) {
+ ret = -ENOMEM;
+ goto err_unlock;
+ }
+
+ ret = ath10k_debug_tpc_stats_final_request(ar);
+ if (ret) {
+ ath10k_warn(ar, "failed to request tpc stats final: %d\n",
+ ret);
+ goto err_free;
+ }
+
+ ath10k_tpc_stats_fill(ar, ar->debug.tpc_stats, buf);
+ file->private_data = buf;
+
+ mutex_unlock(&ar->conf_mutex);
+ return 0;
+
+err_free:
+ vfree(buf);
+
+err_unlock:
+ mutex_unlock(&ar->conf_mutex);
+ return ret;
+}
+
+static int ath10k_tpc_stats_final_release(struct inode *inode,
+ struct file *file)
+{
+ vfree(file->private_data);
+
+ return 0;
+}
+
+static ssize_t ath10k_tpc_stats_final_read(struct file *file,
+ char __user *user_buf,
+ size_t count, loff_t *ppos)
+{
+ const char *buf = file->private_data;
+ unsigned int len = strlen(buf);
+
+ return simple_read_from_buffer(user_buf, count, ppos, buf, len);
+}
+
+static const struct file_operations fops_tpc_stats_final = {
+ .open = ath10k_tpc_stats_final_open,
+ .release = ath10k_tpc_stats_final_release,
+ .read = ath10k_tpc_stats_final_read,
+ .owner = THIS_MODULE,
+ .llseek = default_llseek,
+};
+
int ath10k_debug_create(struct ath10k *ar)
{
ar->debug.cal_data = vzalloc(ATH10K_DEBUG_CAL_DATA_LEN);
@@ -2258,6 +2402,16 @@ int ath10k_debug_register(struct ath10k *ar)
debugfs_create_file("fw_checksums", 0400, ar->debug.debugfs_phy, ar,
&fops_fw_checksums);
+ if (IS_ENABLED(CONFIG_MAC80211_DEBUGFS))
+ debugfs_create_file("sta_tid_stats_mask", 0600,
+ ar->debug.debugfs_phy,
+ ar, &fops_sta_tid_stats_mask);
+
+ if (test_bit(WMI_SERVICE_TPC_STATS_FINAL, ar->wmi.svc_map))
+ debugfs_create_file("tpc_stats_final", 0400,
+ ar->debug.debugfs_phy, ar,
+ &fops_tpc_stats_final);
+
return 0;
}
diff --git a/drivers/net/wireless/ath/ath10k/debug.h b/drivers/net/wireless/ath/ath10k/debug.h
index e54308889e59..0afca5c106b6 100644
--- a/drivers/net/wireless/ath/ath10k/debug.h
+++ b/drivers/net/wireless/ath/ath10k/debug.h
@@ -1,6 +1,7 @@
/*
* Copyright (c) 2005-2011 Atheros Communications Inc.
* Copyright (c) 2011-2017 Qualcomm Atheros, Inc.
+ * Copyright (c) 2018, The Linux Foundation. All rights reserved.
*
* Permission to use, copy, modify, and/or distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
@@ -101,6 +102,9 @@ void ath10k_debug_unregister(struct ath10k *ar);
void ath10k_debug_fw_stats_process(struct ath10k *ar, struct sk_buff *skb);
void ath10k_debug_tpc_stats_process(struct ath10k *ar,
struct ath10k_tpc_stats *tpc_stats);
+void
+ath10k_debug_tpc_stats_final_process(struct ath10k *ar,
+ struct ath10k_tpc_stats_final *tpc_stats);
void ath10k_debug_dbglog_add(struct ath10k *ar, u8 *buffer, int len);
#define ATH10K_DFS_STAT_INC(ar, c) (ar->debug.dfs_stats.c++)
@@ -164,6 +168,13 @@ static inline void ath10k_debug_tpc_stats_process(struct ath10k *ar,
kfree(tpc_stats);
}
+static inline void
+ath10k_debug_tpc_stats_final_process(struct ath10k *ar,
+ struct ath10k_tpc_stats_final *tpc_stats)
+{
+ kfree(tpc_stats);
+}
+
static inline void ath10k_debug_dbglog_add(struct ath10k *ar, u8 *buffer,
int len)
{
@@ -191,12 +202,42 @@ void ath10k_sta_add_debugfs(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
struct ieee80211_sta *sta, struct dentry *dir);
void ath10k_sta_update_rx_duration(struct ath10k *ar,
struct ath10k_fw_stats *stats);
+void ath10k_sta_update_rx_tid_stats(struct ath10k *ar, u8 *first_hdr,
+ unsigned long int num_msdus,
+ enum ath10k_pkt_rx_err err,
+ unsigned long int unchain_cnt,
+ unsigned long int drop_cnt,
+ unsigned long int drop_cnt_filter,
+ unsigned long int queued_msdus);
+void ath10k_sta_update_rx_tid_stats_ampdu(struct ath10k *ar,
+ u16 peer_id, u8 tid,
+ struct htt_rx_indication_mpdu_range *ranges,
+ int num_ranges);
#else
static inline
void ath10k_sta_update_rx_duration(struct ath10k *ar,
struct ath10k_fw_stats *stats)
{
}
+
+static inline
+void ath10k_sta_update_rx_tid_stats(struct ath10k *ar, u8 *first_hdr,
+ unsigned long int num_msdus,
+ enum ath10k_pkt_rx_err err,
+ unsigned long int unchain_cnt,
+ unsigned long int drop_cnt,
+ unsigned long int drop_cnt_filter,
+ unsigned long int queued_msdus)
+{
+}
+
+static inline
+void ath10k_sta_update_rx_tid_stats_ampdu(struct ath10k *ar,
+ u16 peer_id, u8 tid,
+ struct htt_rx_indication_mpdu_range *ranges,
+ int num_ranges)
+{
+}
#endif /* CONFIG_MAC80211_DEBUGFS */
#ifdef CONFIG_ATH10K_DEBUG
diff --git a/drivers/net/wireless/ath/ath10k/debugfs_sta.c b/drivers/net/wireless/ath/ath10k/debugfs_sta.c
index b260b09dd4d3..8f688f136c22 100644
--- a/drivers/net/wireless/ath/ath10k/debugfs_sta.c
+++ b/drivers/net/wireless/ath/ath10k/debugfs_sta.c
@@ -1,5 +1,6 @@
/*
* Copyright (c) 2014-2017 Qualcomm Atheros, Inc.
+ * Copyright (c) 2018, The Linux Foundation. All rights reserved.
*
* Permission to use, copy, modify, and/or distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
@@ -16,8 +17,125 @@
#include "core.h"
#include "wmi-ops.h"
+#include "txrx.h"
#include "debug.h"
+static void ath10k_rx_stats_update_amsdu_subfrm(struct ath10k *ar,
+ struct ath10k_sta_tid_stats *stats,
+ u32 msdu_count)
+{
+ if (msdu_count == 1)
+ stats->rx_pkt_amsdu[ATH10K_AMSDU_SUBFRM_NUM_1]++;
+ else if (msdu_count == 2)
+ stats->rx_pkt_amsdu[ATH10K_AMSDU_SUBFRM_NUM_2]++;
+ else if (msdu_count == 3)
+ stats->rx_pkt_amsdu[ATH10K_AMSDU_SUBFRM_NUM_3]++;
+ else if (msdu_count == 4)
+ stats->rx_pkt_amsdu[ATH10K_AMSDU_SUBFRM_NUM_4]++;
+ else if (msdu_count > 4)
+ stats->rx_pkt_amsdu[ATH10K_AMSDU_SUBFRM_NUM_MORE]++;
+}
+
+static void ath10k_rx_stats_update_ampdu_subfrm(struct ath10k *ar,
+ struct ath10k_sta_tid_stats *stats,
+ u32 mpdu_count)
+{
+ if (mpdu_count <= 10)
+ stats->rx_pkt_ampdu[ATH10K_AMPDU_SUBFRM_NUM_10]++;
+ else if (mpdu_count <= 20)
+ stats->rx_pkt_ampdu[ATH10K_AMPDU_SUBFRM_NUM_20]++;
+ else if (mpdu_count <= 30)
+ stats->rx_pkt_ampdu[ATH10K_AMPDU_SUBFRM_NUM_30]++;
+ else if (mpdu_count <= 40)
+ stats->rx_pkt_ampdu[ATH10K_AMPDU_SUBFRM_NUM_40]++;
+ else if (mpdu_count <= 50)
+ stats->rx_pkt_ampdu[ATH10K_AMPDU_SUBFRM_NUM_50]++;
+ else if (mpdu_count <= 60)
+ stats->rx_pkt_ampdu[ATH10K_AMPDU_SUBFRM_NUM_60]++;
+ else if (mpdu_count > 60)
+ stats->rx_pkt_ampdu[ATH10K_AMPDU_SUBFRM_NUM_MORE]++;
+}
+
+void ath10k_sta_update_rx_tid_stats_ampdu(struct ath10k *ar, u16 peer_id, u8 tid,
+ struct htt_rx_indication_mpdu_range *ranges,
+ int num_ranges)
+{
+ struct ath10k_sta *arsta;
+ struct ath10k_peer *peer;
+ int i;
+
+ if (tid > IEEE80211_NUM_TIDS || !(ar->sta_tid_stats_mask & BIT(tid)))
+ return;
+
+ rcu_read_lock();
+ spin_lock_bh(&ar->data_lock);
+
+ peer = ath10k_peer_find_by_id(ar, peer_id);
+ if (!peer)
+ goto out;
+
+ arsta = (struct ath10k_sta *)peer->sta->drv_priv;
+
+ for (i = 0; i < num_ranges; i++)
+ ath10k_rx_stats_update_ampdu_subfrm(ar,
+ &arsta->tid_stats[tid],
+ ranges[i].mpdu_count);
+
+out:
+ spin_unlock_bh(&ar->data_lock);
+ rcu_read_unlock();
+}
+
+void ath10k_sta_update_rx_tid_stats(struct ath10k *ar, u8 *first_hdr,
+ unsigned long int num_msdus,
+ enum ath10k_pkt_rx_err err,
+ unsigned long int unchain_cnt,
+ unsigned long int drop_cnt,
+ unsigned long int drop_cnt_filter,
+ unsigned long int queued_msdus)
+{
+ struct ieee80211_sta *sta;
+ struct ath10k_sta *arsta;
+ struct ieee80211_hdr *hdr;
+ struct ath10k_sta_tid_stats *stats;
+ u8 tid = IEEE80211_NUM_TIDS;
+ bool non_data_frm = false;
+
+ hdr = (struct ieee80211_hdr *)first_hdr;
+ if (!ieee80211_is_data(hdr->frame_control))
+ non_data_frm = true;
+
+ if (ieee80211_is_data_qos(hdr->frame_control))
+ tid = *ieee80211_get_qos_ctl(hdr) & IEEE80211_QOS_CTL_TID_MASK;
+
+ if (!(ar->sta_tid_stats_mask & BIT(tid)) || non_data_frm)
+ return;
+
+ rcu_read_lock();
+
+ sta = ieee80211_find_sta_by_ifaddr(ar->hw, hdr->addr2, NULL);
+ if (!sta)
+ goto exit;
+
+ arsta = (struct ath10k_sta *)sta->drv_priv;
+
+ spin_lock_bh(&ar->data_lock);
+ stats = &arsta->tid_stats[tid];
+ stats->rx_pkt_from_fw += num_msdus;
+ stats->rx_pkt_unchained += unchain_cnt;
+ stats->rx_pkt_drop_chained += drop_cnt;
+ stats->rx_pkt_drop_filter += drop_cnt_filter;
+ if (err != ATH10K_PKT_RX_ERR_MAX)
+ stats->rx_pkt_err[err] += queued_msdus;
+ stats->rx_pkt_queued_for_mac += queued_msdus;
+ ath10k_rx_stats_update_amsdu_subfrm(ar, &arsta->tid_stats[tid],
+ num_msdus);
+ spin_unlock_bh(&ar->data_lock);
+
+exit:
+ rcu_read_unlock();
+}
+
static void ath10k_sta_update_extd_stats_rx_duration(struct ath10k *ar,
struct ath10k_fw_stats *stats)
{
@@ -342,6 +460,172 @@ static const struct file_operations fops_peer_debug_trigger = {
.llseek = default_llseek,
};
+static char *get_err_str(enum ath10k_pkt_rx_err i)
+{
+ switch (i) {
+ case ATH10K_PKT_RX_ERR_FCS:
+ return "fcs_err";
+ case ATH10K_PKT_RX_ERR_TKIP:
+ return "tkip_err";
+ case ATH10K_PKT_RX_ERR_CRYPT:
+ return "crypt_err";
+ case ATH10K_PKT_RX_ERR_PEER_IDX_INVAL:
+ return "peer_idx_inval";
+ case ATH10K_PKT_RX_ERR_MAX:
+ return "unknown";
+ }
+
+ return "unknown";
+}
+
+static char *get_num_ampdu_subfrm_str(enum ath10k_ampdu_subfrm_num i)
+{
+ switch (i) {
+ case ATH10K_AMPDU_SUBFRM_NUM_10:
+ return "upto 10";
+ case ATH10K_AMPDU_SUBFRM_NUM_20:
+ return "11-20";
+ case ATH10K_AMPDU_SUBFRM_NUM_30:
+ return "21-30";
+ case ATH10K_AMPDU_SUBFRM_NUM_40:
+ return "31-40";
+ case ATH10K_AMPDU_SUBFRM_NUM_50:
+ return "41-50";
+ case ATH10K_AMPDU_SUBFRM_NUM_60:
+ return "51-60";
+ case ATH10K_AMPDU_SUBFRM_NUM_MORE:
+ return ">60";
+ case ATH10K_AMPDU_SUBFRM_NUM_MAX:
+ return "0";
+ }
+
+ return "0";
+}
+
+static char *get_num_amsdu_subfrm_str(enum ath10k_amsdu_subfrm_num i)
+{
+ switch (i) {
+ case ATH10K_AMSDU_SUBFRM_NUM_1:
+ return "1";
+ case ATH10K_AMSDU_SUBFRM_NUM_2:
+ return "2";
+ case ATH10K_AMSDU_SUBFRM_NUM_3:
+ return "3";
+ case ATH10K_AMSDU_SUBFRM_NUM_4:
+ return "4";
+ case ATH10K_AMSDU_SUBFRM_NUM_MORE:
+ return ">4";
+ case ATH10K_AMSDU_SUBFRM_NUM_MAX:
+ return "0";
+ }
+
+ return "0";
+}
+
+#define PRINT_TID_STATS(_field, _tabs) \
+ do { \
+ int k = 0; \
+ for (j = 0; j <= IEEE80211_NUM_TIDS; j++) { \
+ if (ar->sta_tid_stats_mask & BIT(j)) { \
+ len += scnprintf(buf + len, buf_len - len, \
+ "[%02d] %-10lu ", \
+ j, stats[j]._field); \
+ k++; \
+ if (k % 8 == 0) { \
+ len += scnprintf(buf + len, \
+ buf_len - len, "\n"); \
+ len += scnprintf(buf + len, \
+ buf_len - len, \
+ _tabs); \
+ } \
+ } \
+ } \
+ len += scnprintf(buf + len, buf_len - len, "\n"); \
+ } while (0)
+
+static ssize_t ath10k_dbg_sta_read_tid_stats(struct file *file,
+ char __user *user_buf,
+ size_t count, loff_t *ppos)
+{
+ struct ieee80211_sta *sta = file->private_data;
+ struct ath10k_sta *arsta = (struct ath10k_sta *)sta->drv_priv;
+ struct ath10k *ar = arsta->arvif->ar;
+ struct ath10k_sta_tid_stats *stats = arsta->tid_stats;
+ size_t len = 0, buf_len = 1048 * IEEE80211_NUM_TIDS;
+ char *buf;
+ int i, j;
+ ssize_t ret;
+
+ buf = kzalloc(buf_len, GFP_KERNEL);
+ if (!buf)
+ return -ENOMEM;
+
+ mutex_lock(&ar->conf_mutex);
+
+ spin_lock_bh(&ar->data_lock);
+
+ len += scnprintf(buf + len, buf_len - len,
+ "\n\t\tDriver Rx pkt stats per tid, ([tid] count)\n");
+ len += scnprintf(buf + len, buf_len - len,
+ "\t\t------------------------------------------\n");
+ len += scnprintf(buf + len, buf_len - len, "MSDUs from FW\t\t\t");
+ PRINT_TID_STATS(rx_pkt_from_fw, "\t\t\t\t");
+
+ len += scnprintf(buf + len, buf_len - len, "MSDUs unchained\t\t\t");
+ PRINT_TID_STATS(rx_pkt_unchained, "\t\t\t\t");
+
+ len += scnprintf(buf + len, buf_len - len,
+ "MSDUs locally dropped:chained\t");
+ PRINT_TID_STATS(rx_pkt_drop_chained, "\t\t\t\t");
+
+ len += scnprintf(buf + len, buf_len - len,
+ "MSDUs locally dropped:filtered\t");
+ PRINT_TID_STATS(rx_pkt_drop_filter, "\t\t\t\t");
+
+ len += scnprintf(buf + len, buf_len - len,
+ "MSDUs queued for mac80211\t");
+ PRINT_TID_STATS(rx_pkt_queued_for_mac, "\t\t\t\t");
+
+ for (i = 0; i < ATH10K_PKT_RX_ERR_MAX; i++) {
+ len += scnprintf(buf + len, buf_len - len,
+ "MSDUs with error:%s\t", get_err_str(i));
+ PRINT_TID_STATS(rx_pkt_err[i], "\t\t\t\t");
+ }
+
+ len += scnprintf(buf + len, buf_len - len, "\n");
+ for (i = 0; i < ATH10K_AMPDU_SUBFRM_NUM_MAX; i++) {
+ len += scnprintf(buf + len, buf_len - len,
+ "A-MPDU num subframes %s\t",
+ get_num_ampdu_subfrm_str(i));
+ PRINT_TID_STATS(rx_pkt_ampdu[i], "\t\t\t\t");
+ }
+
+ len += scnprintf(buf + len, buf_len - len, "\n");
+ for (i = 0; i < ATH10K_AMSDU_SUBFRM_NUM_MAX; i++) {
+ len += scnprintf(buf + len, buf_len - len,
+ "A-MSDU num subframes %s\t\t",
+ get_num_amsdu_subfrm_str(i));
+ PRINT_TID_STATS(rx_pkt_amsdu[i], "\t\t\t\t");
+ }
+
+ spin_unlock_bh(&ar->data_lock);
+
+ ret = simple_read_from_buffer(user_buf, count, ppos, buf, len);
+
+ kfree(buf);
+
+ mutex_unlock(&ar->conf_mutex);
+
+ return ret;
+}
+
+static const struct file_operations fops_tid_stats_dump = {
+ .open = simple_open,
+ .read = ath10k_dbg_sta_read_tid_stats,
+ .owner = THIS_MODULE,
+ .llseek = default_llseek,
+};
+
void ath10k_sta_add_debugfs(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
struct ieee80211_sta *sta, struct dentry *dir)
{
@@ -351,4 +635,6 @@ void ath10k_sta_add_debugfs(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
debugfs_create_file("delba", 0200, dir, sta, &fops_delba);
debugfs_create_file("peer_debug_trigger", 0600, dir, sta,
&fops_peer_debug_trigger);
+ debugfs_create_file("dump_tid_stats", 0400, dir, sta,
+ &fops_tid_stats_dump);
}
diff --git a/drivers/net/wireless/ath/ath10k/htt_rx.c b/drivers/net/wireless/ath/ath10k/htt_rx.c
index 6d96f9560950..5e02e26158f6 100644
--- a/drivers/net/wireless/ath/ath10k/htt_rx.c
+++ b/drivers/net/wireless/ath/ath10k/htt_rx.c
@@ -1,6 +1,7 @@
/*
* Copyright (c) 2005-2011 Atheros Communications Inc.
* Copyright (c) 2011-2017 Qualcomm Atheros, Inc.
+ * Copyright (c) 2018, The Linux Foundation. All rights reserved.
*
* Permission to use, copy, modify, and/or distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
@@ -723,6 +724,28 @@ struct amsdu_subframe_hdr {
#define GROUP_ID_IS_SU_MIMO(x) ((x) == 0 || (x) == 63)
+static inline u8 ath10k_bw_to_mac80211_bw(u8 bw)
+{
+ u8 ret = 0;
+
+ switch (bw) {
+ case 0:
+ ret = RATE_INFO_BW_20;
+ break;
+ case 1:
+ ret = RATE_INFO_BW_40;
+ break;
+ case 2:
+ ret = RATE_INFO_BW_80;
+ break;
+ case 3:
+ ret = RATE_INFO_BW_160;
+ break;
+ }
+
+ return ret;
+}
+
static void ath10k_htt_rx_h_rates(struct ath10k *ar,
struct ieee80211_rx_status *status,
struct htt_rx_desc *rxd)
@@ -825,23 +848,7 @@ static void ath10k_htt_rx_h_rates(struct ath10k *ar,
if (sgi)
status->enc_flags |= RX_ENC_FLAG_SHORT_GI;
- switch (bw) {
- /* 20MHZ */
- case 0:
- break;
- /* 40MHZ */
- case 1:
- status->bw = RATE_INFO_BW_40;
- break;
- /* 80MHZ */
- case 2:
- status->bw = RATE_INFO_BW_80;
- break;
- case 3:
- status->bw = RATE_INFO_BW_160;
- break;
- }
-
+ status->bw = ath10k_bw_to_mac80211_bw(bw);
status->encoding = RX_ENC_VHT;
break;
default:
@@ -1502,7 +1509,9 @@ static void ath10k_htt_rx_h_csum_offload(struct sk_buff *msdu)
static void ath10k_htt_rx_h_mpdu(struct ath10k *ar,
struct sk_buff_head *amsdu,
struct ieee80211_rx_status *status,
- bool fill_crypt_header)
+ bool fill_crypt_header,
+ u8 *rx_hdr,
+ enum ath10k_pkt_rx_err *err)
{
struct sk_buff *first;
struct sk_buff *last;
@@ -1538,6 +1547,9 @@ static void ath10k_htt_rx_h_mpdu(struct ath10k *ar,
hdr = (void *)rxd->rx_hdr_status;
memcpy(first_hdr, hdr, RX_HTT_HDR_STATUS_LEN);
+ if (rx_hdr)
+ memcpy(rx_hdr, hdr, RX_HTT_HDR_STATUS_LEN);
+
/* Each A-MSDU subframe will use the original header as the base and be
* reported as a separate MSDU so strip the A-MSDU bit from QoS Ctl.
*/
@@ -1581,6 +1593,17 @@ static void ath10k_htt_rx_h_mpdu(struct ath10k *ar,
if (has_tkip_err)
status->flag |= RX_FLAG_MMIC_ERROR;
+ if (err) {
+ if (has_fcs_err)
+ *err = ATH10K_PKT_RX_ERR_FCS;
+ else if (has_tkip_err)
+ *err = ATH10K_PKT_RX_ERR_TKIP;
+ else if (has_crypto_err)
+ *err = ATH10K_PKT_RX_ERR_CRYPT;
+ else if (has_peer_idx_invalid)
+ *err = ATH10K_PKT_RX_ERR_PEER_IDX_INVAL;
+ }
+
/* Firmware reports all necessary management frames via WMI already.
* They are not reported to monitor interfaces at all so pass the ones
* coming via HTT to monitor interfaces instead. This simplifies
@@ -1651,11 +1674,13 @@ static void ath10k_htt_rx_h_enqueue(struct ath10k *ar,
}
}
-static int ath10k_unchain_msdu(struct sk_buff_head *amsdu)
+static int ath10k_unchain_msdu(struct sk_buff_head *amsdu,
+ unsigned long int *unchain_cnt)
{
struct sk_buff *skb, *first;
int space;
int total_len = 0;
+ int amsdu_len = skb_queue_len(amsdu);
/* TODO: Might could optimize this by using
* skb_try_coalesce or similar method to
@@ -1691,11 +1716,16 @@ static int ath10k_unchain_msdu(struct sk_buff_head *amsdu)
}
__skb_queue_head(amsdu, first);
+
+ *unchain_cnt += amsdu_len - 1;
+
return 0;
}
static void ath10k_htt_rx_h_unchain(struct ath10k *ar,
- struct sk_buff_head *amsdu)
+ struct sk_buff_head *amsdu,
+ unsigned long int *drop_cnt,
+ unsigned long int *unchain_cnt)
{
struct sk_buff *first;
struct htt_rx_desc *rxd;
@@ -1713,11 +1743,12 @@ static void ath10k_htt_rx_h_unchain(struct ath10k *ar,
*/
if (decap != RX_MSDU_DECAP_RAW ||
skb_queue_len(amsdu) != 1 + rxd->frag_info.ring2_more_count) {
+ *drop_cnt += skb_queue_len(amsdu);
__skb_queue_purge(amsdu);
return;
}
- ath10k_unchain_msdu(amsdu);
+ ath10k_unchain_msdu(amsdu, unchain_cnt);
}
static bool ath10k_htt_rx_amsdu_allowed(struct ath10k *ar,
@@ -1743,7 +1774,8 @@ static bool ath10k_htt_rx_amsdu_allowed(struct ath10k *ar,
static void ath10k_htt_rx_h_filter(struct ath10k *ar,
struct sk_buff_head *amsdu,
- struct ieee80211_rx_status *rx_status)
+ struct ieee80211_rx_status *rx_status,
+ unsigned long int *drop_cnt)
{
if (skb_queue_empty(amsdu))
return;
@@ -1751,6 +1783,9 @@ static void ath10k_htt_rx_h_filter(struct ath10k *ar,
if (ath10k_htt_rx_amsdu_allowed(ar, amsdu, rx_status))
return;
+ if (drop_cnt)
+ *drop_cnt += skb_queue_len(amsdu);
+
__skb_queue_purge(amsdu);
}
@@ -1760,6 +1795,12 @@ static int ath10k_htt_rx_handle_amsdu(struct ath10k_htt *htt)
struct ieee80211_rx_status *rx_status = &htt->rx_status;
struct sk_buff_head amsdu;
int ret;
+ unsigned long int drop_cnt = 0;
+ unsigned long int unchain_cnt = 0;
+ unsigned long int drop_cnt_filter = 0;
+ unsigned long int msdus_to_queue, num_msdus;
+ enum ath10k_pkt_rx_err err = ATH10K_PKT_RX_ERR_MAX;
+ u8 first_hdr[RX_HTT_HDR_STATUS_LEN];
__skb_queue_head_init(&amsdu);
@@ -1781,16 +1822,23 @@ static int ath10k_htt_rx_handle_amsdu(struct ath10k_htt *htt)
return ret;
}
+ num_msdus = skb_queue_len(&amsdu);
+
ath10k_htt_rx_h_ppdu(ar, &amsdu, rx_status, 0xffff);
/* only for ret = 1 indicates chained msdus */
if (ret > 0)
- ath10k_htt_rx_h_unchain(ar, &amsdu);
+ ath10k_htt_rx_h_unchain(ar, &amsdu, &drop_cnt, &unchain_cnt);
- ath10k_htt_rx_h_filter(ar, &amsdu, rx_status);
- ath10k_htt_rx_h_mpdu(ar, &amsdu, rx_status, true);
+ ath10k_htt_rx_h_filter(ar, &amsdu, rx_status, &drop_cnt_filter);
+ ath10k_htt_rx_h_mpdu(ar, &amsdu, rx_status, true, first_hdr, &err);
+ msdus_to_queue = skb_queue_len(&amsdu);
ath10k_htt_rx_h_enqueue(ar, &amsdu, rx_status);
+ ath10k_sta_update_rx_tid_stats(ar, first_hdr, num_msdus, err,
+ unchain_cnt, drop_cnt, drop_cnt_filter,
+ msdus_to_queue);
+
return 0;
}
@@ -1801,9 +1849,14 @@ static void ath10k_htt_rx_proc_rx_ind(struct ath10k_htt *htt,
struct htt_rx_indication_mpdu_range *mpdu_ranges;
int num_mpdu_ranges;
int i, mpdu_count = 0;
+ u16 peer_id;
+ u8 tid;
num_mpdu_ranges = MS(__le32_to_cpu(rx->hdr.info1),
HTT_RX_INDICATION_INFO1_NUM_MPDU_RANGES);
+ peer_id = __le16_to_cpu(rx->hdr.peer_id);
+ tid = MS(rx->hdr.info0, HTT_RX_INDICATION_INFO0_EXT_TID);
+
mpdu_ranges = htt_rx_ind_get_mpdu_ranges(rx);
ath10k_dbg_dump(ar, ATH10K_DBG_HTT_DUMP, NULL, "htt rx ind: ",
@@ -1815,6 +1868,9 @@ static void ath10k_htt_rx_proc_rx_ind(struct ath10k_htt *htt,
mpdu_count += mpdu_ranges[i].mpdu_count;
atomic_add(mpdu_count, &htt->num_mpdus_ready);
+
+ ath10k_sta_update_rx_tid_stats_ampdu(ar, peer_id, tid, mpdu_ranges,
+ num_mpdu_ranges);
}
static void ath10k_htt_rx_tx_compl_ind(struct ath10k *ar,
@@ -2124,8 +2180,9 @@ static int ath10k_htt_rx_in_ord_ind(struct ath10k *ar, struct sk_buff *skb)
* should still give an idea about rx rate to the user.
*/
ath10k_htt_rx_h_ppdu(ar, &amsdu, status, vdev_id);
- ath10k_htt_rx_h_filter(ar, &amsdu, status);
- ath10k_htt_rx_h_mpdu(ar, &amsdu, status, false);
+ ath10k_htt_rx_h_filter(ar, &amsdu, status, NULL);
+ ath10k_htt_rx_h_mpdu(ar, &amsdu, status, false, NULL,
+ NULL);
ath10k_htt_rx_h_enqueue(ar, &amsdu, status);
break;
case -EAGAIN:
@@ -2499,7 +2556,7 @@ ath10k_update_per_peer_tx_stats(struct ath10k *ar,
arsta->txrate.flags |= RATE_INFO_FLAGS_SHORT_GI;
arsta->txrate.nss = txrate.nss;
- arsta->txrate.bw = txrate.bw + RATE_INFO_BW_20;
+ arsta->txrate.bw = ath10k_bw_to_mac80211_bw(txrate.bw);
}
static void ath10k_htt_fetch_peer_stats(struct ath10k *ar,
diff --git a/drivers/net/wireless/ath/ath10k/mac.c b/drivers/net/wireless/ath/ath10k/mac.c
index ebb3f1b046f3..bf05a3689558 100644
--- a/drivers/net/wireless/ath/ath10k/mac.c
+++ b/drivers/net/wireless/ath/ath10k/mac.c
@@ -1,6 +1,7 @@
/*
* Copyright (c) 2005-2011 Atheros Communications Inc.
* Copyright (c) 2011-2017 Qualcomm Atheros, Inc.
+ * Copyright (c) 2018, The Linux Foundation. All rights reserved.
*
* Permission to use, copy, modify, and/or distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
@@ -2976,7 +2977,7 @@ static int ath10k_station_assoc(struct ath10k *ar,
}
/* Plumb cached keys only for static WEP */
- if (arvif->def_wep_key_idx != -1) {
+ if ((arvif->def_wep_key_idx != -1) && (!sta->tdls)) {
ret = ath10k_install_peer_wep_keys(arvif, sta->addr);
if (ret) {
ath10k_warn(ar, "failed to install peer wep keys for vdev %i: %d\n",
@@ -3808,6 +3809,7 @@ void ath10k_mgmt_over_wmi_tx_work(struct work_struct *work)
{
struct ath10k *ar = container_of(work, struct ath10k, wmi_mgmt_tx_work);
struct sk_buff *skb;
+ dma_addr_t paddr;
int ret;
for (;;) {
@@ -3815,11 +3817,27 @@ void ath10k_mgmt_over_wmi_tx_work(struct work_struct *work)
if (!skb)
break;
- ret = ath10k_wmi_mgmt_tx(ar, skb);
- if (ret) {
- ath10k_warn(ar, "failed to transmit management frame via WMI: %d\n",
- ret);
- ieee80211_free_txskb(ar->hw, skb);
+ if (test_bit(ATH10K_FW_FEATURE_MGMT_TX_BY_REF,
+ ar->running_fw->fw_file.fw_features)) {
+ paddr = dma_map_single(ar->dev, skb->data,
+ skb->len, DMA_TO_DEVICE);
+ if (!paddr)
+ continue;
+ ret = ath10k_wmi_mgmt_tx_send(ar, skb, paddr);
+ if (ret) {
+ ath10k_warn(ar, "failed to transmit management frame by ref via WMI: %d\n",
+ ret);
+ dma_unmap_single(ar->dev, paddr, skb->len,
+ DMA_FROM_DEVICE);
+ ieee80211_free_txskb(ar->hw, skb);
+ }
+ } else {
+ ret = ath10k_wmi_mgmt_tx(ar, skb);
+ if (ret) {
+ ath10k_warn(ar, "failed to transmit management frame via WMI: %d\n",
+ ret);
+ ieee80211_free_txskb(ar->hw, skb);
+ }
}
}
}
@@ -5914,6 +5932,10 @@ static int ath10k_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd,
ath10k_warn(ar, "Peer %pM disappeared!\n", peer_addr);
spin_unlock_bh(&ar->data_lock);
+ if (sta && sta->tdls)
+ ath10k_wmi_peer_set_param(ar, arvif->vdev_id, sta->addr,
+ WMI_PEER_AUTHORIZE, 1);
+
exit:
mutex_unlock(&ar->conf_mutex);
return ret;
@@ -6028,9 +6050,8 @@ static void ath10k_sta_rc_update_wk(struct work_struct *wk)
sta->addr, smps, err);
}
- if (changed & IEEE80211_RC_SUPP_RATES_CHANGED ||
- changed & IEEE80211_RC_NSS_CHANGED) {
- ath10k_dbg(ar, ATH10K_DBG_MAC, "mac update sta %pM supp rates/nss\n",
+ if (changed & IEEE80211_RC_SUPP_RATES_CHANGED) {
+ ath10k_dbg(ar, ATH10K_DBG_MAC, "mac update sta %pM supp rates\n",
sta->addr);
err = ath10k_station_assoc(ar, arvif->vif, sta, true);
@@ -7085,10 +7106,20 @@ static void ath10k_sta_rc_update(struct ieee80211_hw *hw,
{
struct ath10k *ar = hw->priv;
struct ath10k_sta *arsta = (struct ath10k_sta *)sta->drv_priv;
+ struct ath10k_vif *arvif = (void *)vif->drv_priv;
+ struct ath10k_peer *peer;
u32 bw, smps;
spin_lock_bh(&ar->data_lock);
+ peer = ath10k_peer_find(ar, arvif->vdev_id, sta->addr);
+ if (!peer) {
+ spin_unlock_bh(&ar->data_lock);
+ ath10k_warn(ar, "mac sta rc update failed to find peer %pM on vdev %i\n",
+ sta->addr, arvif->vdev_id);
+ return;
+ }
+
ath10k_dbg(ar, ATH10K_DBG_MAC,
"mac sta rc update for %pM changed %08x bw %d nss %d smps %d\n",
sta->addr, changed, sta->bandwidth, sta->rx_nss,
@@ -7874,6 +7905,7 @@ static const struct ieee80211_iface_combination ath10k_10x_if_comb[] = {
.max_interfaces = 8,
.num_different_channels = 1,
.beacon_int_infra_match = true,
+ .beacon_int_min_gcd = 1,
#ifdef CONFIG_ATH10K_DFS_CERTIFIED
.radar_detect_widths = BIT(NL80211_CHAN_WIDTH_20_NOHT) |
BIT(NL80211_CHAN_WIDTH_20) |
@@ -7997,6 +8029,7 @@ static const struct ieee80211_iface_combination ath10k_10_4_if_comb[] = {
.max_interfaces = 16,
.num_different_channels = 1,
.beacon_int_infra_match = true,
+ .beacon_int_min_gcd = 1,
#ifdef CONFIG_ATH10K_DFS_CERTIFIED
.radar_detect_widths = BIT(NL80211_CHAN_WIDTH_20_NOHT) |
BIT(NL80211_CHAN_WIDTH_20) |
@@ -8298,6 +8331,9 @@ int ath10k_mac_register(struct ath10k *ar)
ieee80211_hw_set(ar->hw, TDLS_WIDER_BW);
}
+ if (test_bit(WMI_SERVICE_TDLS_UAPSD_BUFFER_STA, ar->wmi.svc_map))
+ ieee80211_hw_set(ar->hw, SUPPORTS_TDLS_BUFFER_STA);
+
ar->hw->wiphy->flags |= WIPHY_FLAG_HAS_REMAIN_ON_CHANNEL;
ar->hw->wiphy->flags |= WIPHY_FLAG_HAS_CHANNEL_SWITCH;
ar->hw->wiphy->max_remain_on_channel_duration = 5000;
diff --git a/drivers/net/wireless/ath/ath10k/pci.c b/drivers/net/wireless/ath/ath10k/pci.c
index 1b266cd0c2ec..fd1566cd7d2b 100644
--- a/drivers/net/wireless/ath/ath10k/pci.c
+++ b/drivers/net/wireless/ath/ath10k/pci.c
@@ -57,6 +57,10 @@ MODULE_PARM_DESC(reset_mode, "0: auto, 1: warm only (default: 0)");
*/
#define ATH10K_DIAG_TRANSFER_LIMIT 0x5000
+#define QCA99X0_PCIE_BAR0_START_REG 0x81030
+#define QCA99X0_CPU_MEM_ADDR_REG 0x4d00c
+#define QCA99X0_CPU_MEM_DATA_REG 0x4d010
+
static const struct pci_device_id ath10k_pci_id_table[] = {
/* PCI-E QCA988X V2 (Ubiquiti branded) */
{ PCI_VDEVICE(UBIQUITI, QCA988X_2_0_DEVICE_ID_UBNT) },
@@ -1584,6 +1588,69 @@ static int ath10k_pci_set_ram_config(struct ath10k *ar, u32 config)
return 0;
}
+/* if an error happened returns < 0, otherwise the length */
+static int ath10k_pci_dump_memory_sram(struct ath10k *ar,
+ const struct ath10k_mem_region *region,
+ u8 *buf)
+{
+ struct ath10k_pci *ar_pci = ath10k_pci_priv(ar);
+ u32 base_addr, i;
+
+ base_addr = ioread32(ar_pci->mem + QCA99X0_PCIE_BAR0_START_REG);
+ base_addr += region->start;
+
+ for (i = 0; i < region->len; i += 4) {
+ iowrite32(base_addr + i, ar_pci->mem + QCA99X0_CPU_MEM_ADDR_REG);
+ *(u32 *)(buf + i) = ioread32(ar_pci->mem + QCA99X0_CPU_MEM_DATA_REG);
+ }
+
+ return region->len;
+}
+
+/* if an error happened returns < 0, otherwise the length */
+static int ath10k_pci_dump_memory_reg(struct ath10k *ar,
+ const struct ath10k_mem_region *region,
+ u8 *buf)
+{
+ struct ath10k_pci *ar_pci = ath10k_pci_priv(ar);
+ u32 i;
+
+ for (i = 0; i < region->len; i += 4)
+ *(u32 *)(buf + i) = ioread32(ar_pci->mem + region->start + i);
+
+ return region->len;
+}
+
+/* if an error happened returns < 0, otherwise the length */
+static int ath10k_pci_dump_memory_generic(struct ath10k *ar,
+ const struct ath10k_mem_region *current_region,
+ u8 *buf)
+{
+ int ret;
+
+ if (current_region->section_table.size > 0)
+ /* Copy each section individually. */
+ return ath10k_pci_dump_memory_section(ar,
+ current_region,
+ buf,
+ current_region->len);
+
+ /* No individiual memory sections defined so we can
+ * copy the entire memory region.
+ */
+ ret = ath10k_pci_diag_read_mem(ar,
+ current_region->start,
+ buf,
+ current_region->len);
+ if (ret) {
+ ath10k_warn(ar, "failed to copy ramdump region %s: %d\n",
+ current_region->name, ret);
+ return ret;
+ }
+
+ return current_region->len;
+}
+
static void ath10k_pci_dump_memory(struct ath10k *ar,
struct ath10k_fw_crash_data *crash_data)
{
@@ -1642,27 +1709,20 @@ static void ath10k_pci_dump_memory(struct ath10k *ar,
buf += sizeof(*hdr);
buf_len -= sizeof(*hdr);
- if (current_region->section_table.size > 0) {
- /* Copy each section individually. */
- count = ath10k_pci_dump_memory_section(ar,
- current_region,
- buf,
- current_region->len);
- } else {
- /* No individiual memory sections defined so we can
- * copy the entire memory region.
- */
- ret = ath10k_pci_diag_read_mem(ar,
- current_region->start,
- buf,
- current_region->len);
- if (ret) {
- ath10k_warn(ar, "failed to copy ramdump region %s: %d\n",
- current_region->name, ret);
+ switch (current_region->type) {
+ case ATH10K_MEM_REGION_TYPE_IOSRAM:
+ count = ath10k_pci_dump_memory_sram(ar, current_region, buf);
+ break;
+ case ATH10K_MEM_REGION_TYPE_IOREG:
+ count = ath10k_pci_dump_memory_reg(ar, current_region, buf);
+ break;
+ default:
+ ret = ath10k_pci_dump_memory_generic(ar, current_region, buf);
+ if (ret < 0)
break;
- }
- count = current_region->len;
+ count = ret;
+ break;
}
hdr->region_type = cpu_to_le32(current_region->type);
@@ -2221,7 +2281,7 @@ static int ath10k_pci_get_num_banks(struct ath10k *ar)
}
break;
case QCA9377_1_0_DEVICE_ID:
- return 4;
+ return 9;
}
ath10k_warn(ar, "unknown number of banks, assuming 1\n");
@@ -3718,5 +3778,6 @@ MODULE_FIRMWARE(QCA6174_HW_3_0_FW_DIR "/" QCA6174_HW_3_0_BOARD_DATA_FILE);
MODULE_FIRMWARE(QCA6174_HW_3_0_FW_DIR "/" ATH10K_BOARD_API2_FILE);
/* QCA9377 1.0 firmware files */
+MODULE_FIRMWARE(QCA9377_HW_1_0_FW_DIR "/" ATH10K_FW_API6_FILE);
MODULE_FIRMWARE(QCA9377_HW_1_0_FW_DIR "/" ATH10K_FW_API5_FILE);
MODULE_FIRMWARE(QCA9377_HW_1_0_FW_DIR "/" QCA9377_HW_1_0_BOARD_DATA_FILE);
diff --git a/drivers/net/wireless/ath/ath10k/trace.h b/drivers/net/wireless/ath/ath10k/trace.h
index e40edced1d82..7d2fac342150 100644
--- a/drivers/net/wireless/ath/ath10k/trace.h
+++ b/drivers/net/wireless/ath/ath10k/trace.h
@@ -152,10 +152,9 @@ TRACE_EVENT(ath10k_log_dbg_dump,
);
TRACE_EVENT(ath10k_wmi_cmd,
- TP_PROTO(struct ath10k *ar, int id, const void *buf, size_t buf_len,
- int ret),
+ TP_PROTO(struct ath10k *ar, int id, const void *buf, size_t buf_len),
- TP_ARGS(ar, id, buf, buf_len, ret),
+ TP_ARGS(ar, id, buf, buf_len),
TP_STRUCT__entry(
__string(device, dev_name(ar->dev))
@@ -163,7 +162,6 @@ TRACE_EVENT(ath10k_wmi_cmd,
__field(unsigned int, id)
__field(size_t, buf_len)
__dynamic_array(u8, buf, buf_len)
- __field(int, ret)
),
TP_fast_assign(
@@ -171,17 +169,15 @@ TRACE_EVENT(ath10k_wmi_cmd,
__assign_str(driver, dev_driver_string(ar->dev));
__entry->id = id;
__entry->buf_len = buf_len;
- __entry->ret = ret;
memcpy(__get_dynamic_array(buf), buf, buf_len);
),
TP_printk(
- "%s %s id %d len %zu ret %d",
+ "%s %s id %d len %zu",
__get_str(driver),
__get_str(device),
__entry->id,
- __entry->buf_len,
- __entry->ret
+ __entry->buf_len
)
);
diff --git a/drivers/net/wireless/ath/ath10k/txrx.c b/drivers/net/wireless/ath/ath10k/txrx.c
index 5b3b021526ab..70e23bbf7171 100644
--- a/drivers/net/wireless/ath/ath10k/txrx.c
+++ b/drivers/net/wireless/ath/ath10k/txrx.c
@@ -102,11 +102,6 @@ int ath10k_txrx_tx_unref(struct ath10k_htt *htt,
memset(&info->status, 0, sizeof(info->status));
trace_ath10k_txrx_tx_unref(ar, tx_done->msdu_id);
- if (tx_done->status == HTT_TX_COMPL_STATE_DISCARD) {
- ieee80211_free_txskb(htt->ar->hw, msdu);
- return 0;
- }
-
if (!(info->flags & IEEE80211_TX_CTL_NO_ACK))
info->flags |= IEEE80211_TX_STAT_ACK;
@@ -117,6 +112,13 @@ int ath10k_txrx_tx_unref(struct ath10k_htt *htt,
(info->flags & IEEE80211_TX_CTL_NO_ACK))
info->flags |= IEEE80211_TX_STAT_NOACK_TRANSMITTED;
+ if (tx_done->status == HTT_TX_COMPL_STATE_DISCARD) {
+ if (info->flags & IEEE80211_TX_CTL_NO_ACK)
+ info->flags &= ~IEEE80211_TX_STAT_NOACK_TRANSMITTED;
+ else
+ info->flags &= ~IEEE80211_TX_STAT_ACK;
+ }
+
ieee80211_tx_status(htt->ar->hw, msdu);
/* we do not own the msdu anymore */
diff --git a/drivers/net/wireless/ath/ath10k/wmi-ops.h b/drivers/net/wireless/ath/ath10k/wmi-ops.h
index 14093cfdc505..c35e45340b4f 100644
--- a/drivers/net/wireless/ath/ath10k/wmi-ops.h
+++ b/drivers/net/wireless/ath/ath10k/wmi-ops.h
@@ -1,6 +1,7 @@
/*
* Copyright (c) 2005-2011 Atheros Communications Inc.
* Copyright (c) 2011-2017 Qualcomm Atheros, Inc.
+ * Copyright (c) 2018, The Linux Foundation. All rights reserved.
*
* Permission to use, copy, modify, and/or distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
@@ -125,6 +126,9 @@ struct wmi_ops {
enum wmi_force_fw_hang_type type,
u32 delay_ms);
struct sk_buff *(*gen_mgmt_tx)(struct ath10k *ar, struct sk_buff *skb);
+ struct sk_buff *(*gen_mgmt_tx_send)(struct ath10k *ar,
+ struct sk_buff *skb,
+ dma_addr_t paddr);
struct sk_buff *(*gen_dbglog_cfg)(struct ath10k *ar, u64 module_enable,
u32 log_level);
struct sk_buff *(*gen_pktlog_enable)(struct ath10k *ar, u32 filter);
@@ -197,6 +201,9 @@ struct wmi_ops {
(struct ath10k *ar,
enum wmi_bss_survey_req_type type);
struct sk_buff *(*gen_echo)(struct ath10k *ar, u32 value);
+ struct sk_buff *(*gen_pdev_get_tpc_table_cmdid)(struct ath10k *ar,
+ u32 param);
+
};
int ath10k_wmi_cmd_send(struct ath10k *ar, struct sk_buff *skb, u32 cmd_id);
@@ -372,12 +379,33 @@ ath10k_wmi_get_txbf_conf_scheme(struct ath10k *ar)
}
static inline int
+ath10k_wmi_mgmt_tx_send(struct ath10k *ar, struct sk_buff *msdu,
+ dma_addr_t paddr)
+{
+ struct sk_buff *skb;
+ int ret;
+
+ if (!ar->wmi.ops->gen_mgmt_tx_send)
+ return -EOPNOTSUPP;
+
+ skb = ar->wmi.ops->gen_mgmt_tx_send(ar, msdu, paddr);
+ if (IS_ERR(skb))
+ return PTR_ERR(skb);
+
+ ret = ath10k_wmi_cmd_send(ar, skb,
+ ar->wmi.cmd->mgmt_tx_send_cmdid);
+ if (ret)
+ return ret;
+
+ return 0;
+}
+
+static inline int
ath10k_wmi_mgmt_tx(struct ath10k *ar, struct sk_buff *msdu)
{
struct ieee80211_tx_info *info = IEEE80211_SKB_CB(msdu);
struct sk_buff *skb;
int ret;
- u32 mgmt_tx_cmdid;
if (!ar->wmi.ops->gen_mgmt_tx)
return -EOPNOTSUPP;
@@ -386,13 +414,8 @@ ath10k_wmi_mgmt_tx(struct ath10k *ar, struct sk_buff *msdu)
if (IS_ERR(skb))
return PTR_ERR(skb);
- if (test_bit(ATH10K_FW_FEATURE_MGMT_TX_BY_REF,
- ar->running_fw->fw_file.fw_features))
- mgmt_tx_cmdid = ar->wmi.cmd->mgmt_tx_send_cmdid;
- else
- mgmt_tx_cmdid = ar->wmi.cmd->mgmt_tx_cmdid;
-
- ret = ath10k_wmi_cmd_send(ar, skb, mgmt_tx_cmdid);
+ ret = ath10k_wmi_cmd_send(ar, skb,
+ ar->wmi.cmd->mgmt_tx_cmdid);
if (ret)
return ret;
@@ -1425,4 +1448,21 @@ ath10k_wmi_echo(struct ath10k *ar, u32 value)
return ath10k_wmi_cmd_send(ar, skb, wmi->cmd->echo_cmdid);
}
+static inline int
+ath10k_wmi_pdev_get_tpc_table_cmdid(struct ath10k *ar, u32 param)
+{
+ struct sk_buff *skb;
+
+ if (!ar->wmi.ops->gen_pdev_get_tpc_table_cmdid)
+ return -EOPNOTSUPP;
+
+ skb = ar->wmi.ops->gen_pdev_get_tpc_table_cmdid(ar, param);
+
+ if (IS_ERR(skb))
+ return PTR_ERR(skb);
+
+ return ath10k_wmi_cmd_send(ar, skb,
+ ar->wmi.cmd->pdev_get_tpc_table_cmdid);
+}
+
#endif
diff --git a/drivers/net/wireless/ath/ath10k/wmi-tlv.c b/drivers/net/wireless/ath/ath10k/wmi-tlv.c
index ae77a007ae07..9d1b0a459069 100644
--- a/drivers/net/wireless/ath/ath10k/wmi-tlv.c
+++ b/drivers/net/wireless/ath/ath10k/wmi-tlv.c
@@ -1,6 +1,7 @@
/*
* Copyright (c) 2005-2011 Atheros Communications Inc.
* Copyright (c) 2011-2017 Qualcomm Atheros, Inc.
+ * Copyright (c) 2018, The Linux Foundation. All rights reserved.
*
* Permission to use, copy, modify, and/or distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
@@ -412,6 +413,62 @@ static int ath10k_wmi_tlv_event_tx_pause(struct ath10k *ar,
return 0;
}
+static int ath10k_wmi_tlv_event_temperature(struct ath10k *ar,
+ struct sk_buff *skb)
+{
+ const struct wmi_tlv_pdev_temperature_event *ev;
+
+ ev = (struct wmi_tlv_pdev_temperature_event *)skb->data;
+ if (WARN_ON(skb->len < sizeof(*ev)))
+ return -EPROTO;
+
+ ath10k_thermal_event_temperature(ar, __le32_to_cpu(ev->temperature));
+ return 0;
+}
+
+static void ath10k_wmi_event_tdls_peer(struct ath10k *ar, struct sk_buff *skb)
+{
+ struct ieee80211_sta *station;
+ const struct wmi_tlv_tdls_peer_event *ev;
+ const void **tb;
+ struct ath10k_vif *arvif;
+
+ tb = ath10k_wmi_tlv_parse_alloc(ar, skb->data, skb->len, GFP_ATOMIC);
+ if (IS_ERR(tb)) {
+ ath10k_warn(ar, "tdls peer failed to parse tlv");
+ return;
+ }
+ ev = tb[WMI_TLV_TAG_STRUCT_TDLS_PEER_EVENT];
+ if (!ev) {
+ kfree(tb);
+ ath10k_warn(ar, "tdls peer NULL event");
+ return;
+ }
+
+ switch (__le32_to_cpu(ev->peer_reason)) {
+ case WMI_TDLS_TEARDOWN_REASON_TX:
+ case WMI_TDLS_TEARDOWN_REASON_RSSI:
+ case WMI_TDLS_TEARDOWN_REASON_PTR_TIMEOUT:
+ station = ieee80211_find_sta_by_ifaddr(ar->hw,
+ ev->peer_macaddr.addr,
+ NULL);
+ if (!station) {
+ ath10k_warn(ar, "did not find station from tdls peer event");
+ kfree(tb);
+ return;
+ }
+ arvif = ath10k_get_arvif(ar, __le32_to_cpu(ev->vdev_id));
+ ieee80211_tdls_oper_request(
+ arvif->vif, station->addr,
+ NL80211_TDLS_TEARDOWN,
+ WLAN_REASON_TDLS_TEARDOWN_UNREACHABLE,
+ GFP_ATOMIC
+ );
+ break;
+ }
+ kfree(tb);
+}
+
/***********/
/* TLV ops */
/***********/
@@ -552,6 +609,12 @@ static void ath10k_wmi_tlv_op_rx(struct ath10k *ar, struct sk_buff *skb)
case WMI_TLV_TX_PAUSE_EVENTID:
ath10k_wmi_tlv_event_tx_pause(ar, skb);
break;
+ case WMI_TLV_PDEV_TEMPERATURE_EVENTID:
+ ath10k_wmi_tlv_event_temperature(ar, skb);
+ break;
+ case WMI_TLV_TDLS_PEER_EVENTID:
+ ath10k_wmi_event_tdls_peer(ar, skb);
+ break;
default:
ath10k_warn(ar, "Unknown eventid: %d\n", id);
break;
@@ -2484,19 +2547,19 @@ ath10k_wmi_tlv_op_gen_request_stats(struct ath10k *ar, u32 stats_mask)
}
static struct sk_buff *
-ath10k_wmi_tlv_op_gen_mgmt_tx(struct ath10k *ar, struct sk_buff *msdu)
+ath10k_wmi_tlv_op_gen_mgmt_tx_send(struct ath10k *ar, struct sk_buff *msdu,
+ dma_addr_t paddr)
{
struct ath10k_skb_cb *cb = ATH10K_SKB_CB(msdu);
struct wmi_tlv_mgmt_tx_cmd *cmd;
- struct wmi_tlv *tlv;
struct ieee80211_hdr *hdr;
+ struct ath10k_vif *arvif;
+ u32 buf_len = msdu->len;
+ struct wmi_tlv *tlv;
struct sk_buff *skb;
+ u32 vdev_id;
void *ptr;
int len;
- u32 buf_len = msdu->len;
- struct ath10k_vif *arvif;
- dma_addr_t mgmt_frame_dma;
- u32 vdev_id;
if (!cb->vif)
return ERR_PTR(-EINVAL);
@@ -2537,12 +2600,7 @@ ath10k_wmi_tlv_op_gen_mgmt_tx(struct ath10k *ar, struct sk_buff *msdu)
cmd->chanfreq = 0;
cmd->buf_len = __cpu_to_le32(buf_len);
cmd->frame_len = __cpu_to_le32(msdu->len);
- mgmt_frame_dma = dma_map_single(arvif->ar->dev, msdu->data,
- msdu->len, DMA_TO_DEVICE);
- if (!mgmt_frame_dma)
- return ERR_PTR(-ENOMEM);
-
- cmd->paddr = __cpu_to_le64(mgmt_frame_dma);
+ cmd->paddr = __cpu_to_le64(paddr);
ptr += sizeof(*tlv);
ptr += sizeof(*cmd);
@@ -2662,6 +2720,25 @@ ath10k_wmi_tlv_op_gen_pktlog_enable(struct ath10k *ar, u32 filter)
}
static struct sk_buff *
+ath10k_wmi_tlv_op_gen_pdev_get_temperature(struct ath10k *ar)
+{
+ struct wmi_tlv_pdev_get_temp_cmd *cmd;
+ struct wmi_tlv *tlv;
+ struct sk_buff *skb;
+
+ skb = ath10k_wmi_alloc_skb(ar, sizeof(*tlv) + sizeof(*cmd));
+ if (!skb)
+ return ERR_PTR(-ENOMEM);
+
+ tlv = (void *)skb->data;
+ tlv->tag = __cpu_to_le16(WMI_TLV_TAG_STRUCT_PDEV_GET_TEMPERATURE_CMD);
+ tlv->len = __cpu_to_le16(sizeof(*cmd));
+ cmd = (void *)tlv->value;
+ ath10k_dbg(ar, ATH10K_DBG_WMI, "wmi pdev get temperature tlv\n");
+ return skb;
+}
+
+static struct sk_buff *
ath10k_wmi_tlv_op_gen_pktlog_disable(struct ath10k *ar)
{
struct wmi_tlv_pktlog_disable *cmd;
@@ -2855,6 +2932,15 @@ ath10k_wmi_tlv_op_gen_update_fw_tdls_state(struct ath10k *ar, u32 vdev_id,
*/
u32 options = 0;
+ if (test_bit(WMI_SERVICE_TDLS_UAPSD_BUFFER_STA, ar->wmi.svc_map))
+ options |= WMI_TLV_TDLS_BUFFER_STA_EN;
+
+ /* WMI_TDLS_ENABLE_ACTIVE_EXTERNAL_CONTROL means firm will handle TDLS
+ * link inactivity detecting logic.
+ */
+ if (state == WMI_TDLS_ENABLE_ACTIVE)
+ state = WMI_TDLS_ENABLE_ACTIVE_EXTERNAL_CONTROL;
+
len = sizeof(*tlv) + sizeof(*cmd);
skb = ath10k_wmi_alloc_skb(ar, len);
if (!skb)
@@ -3443,7 +3529,7 @@ static struct wmi_cmd_map wmi_tlv_cmd_map = {
.force_fw_hang_cmdid = WMI_TLV_FORCE_FW_HANG_CMDID,
.gpio_config_cmdid = WMI_TLV_GPIO_CONFIG_CMDID,
.gpio_output_cmdid = WMI_TLV_GPIO_OUTPUT_CMDID,
- .pdev_get_temperature_cmdid = WMI_TLV_CMD_UNSUPPORTED,
+ .pdev_get_temperature_cmdid = WMI_TLV_PDEV_GET_TEMPERATURE_CMDID,
.vdev_set_wmm_params_cmdid = WMI_TLV_VDEV_SET_WMM_PARAMS_CMDID,
.tdls_set_state_cmdid = WMI_TLV_TDLS_SET_STATE_CMDID,
.tdls_peer_update_cmdid = WMI_TLV_TDLS_PEER_UPDATE_CMDID,
@@ -3701,12 +3787,12 @@ static const struct wmi_ops wmi_tlv_ops = {
.gen_request_stats = ath10k_wmi_tlv_op_gen_request_stats,
.gen_force_fw_hang = ath10k_wmi_tlv_op_gen_force_fw_hang,
/* .gen_mgmt_tx = not implemented; HTT is used */
- .gen_mgmt_tx = ath10k_wmi_tlv_op_gen_mgmt_tx,
+ .gen_mgmt_tx_send = ath10k_wmi_tlv_op_gen_mgmt_tx_send,
.gen_dbglog_cfg = ath10k_wmi_tlv_op_gen_dbglog_cfg,
.gen_pktlog_enable = ath10k_wmi_tlv_op_gen_pktlog_enable,
.gen_pktlog_disable = ath10k_wmi_tlv_op_gen_pktlog_disable,
/* .gen_pdev_set_quiet_mode not implemented */
- /* .gen_pdev_get_temperature not implemented */
+ .gen_pdev_get_temperature = ath10k_wmi_tlv_op_gen_pdev_get_temperature,
/* .gen_addba_clear_resp not implemented */
/* .gen_addba_send not implemented */
/* .gen_addba_set_resp not implemented */
diff --git a/drivers/net/wireless/ath/ath10k/wmi-tlv.h b/drivers/net/wireless/ath/ath10k/wmi-tlv.h
index da89128e8dd6..fa3773ec7c68 100644
--- a/drivers/net/wireless/ath/ath10k/wmi-tlv.h
+++ b/drivers/net/wireless/ath/ath10k/wmi-tlv.h
@@ -1340,6 +1340,17 @@ struct wmi_tlv_init_cmd {
__le32 num_host_mem_chunks;
} __packed;
+struct wmi_tlv_pdev_get_temp_cmd {
+ __le32 pdev_id; /* not used */
+} __packed;
+
+struct wmi_tlv_pdev_temperature_event {
+ __le32 tlv_hdr;
+ /* temperature value in Celcius degree */
+ __le32 temperature;
+ __le32 pdev_id;
+} __packed;
+
struct wmi_tlv_pdev_set_param_cmd {
__le32 pdev_id; /* not used yet */
__le32 param_id;
@@ -1746,6 +1757,13 @@ struct wmi_tlv_tx_pause_ev {
__le32 tid_map;
} __packed;
+struct wmi_tlv_tdls_peer_event {
+ struct wmi_mac_addr peer_macaddr;
+ __le32 peer_status;
+ __le32 peer_reason;
+ __le32 vdev_id;
+} __packed;
+
void ath10k_wmi_tlv_attach(struct ath10k *ar);
struct wmi_tlv_mgmt_tx_cmd {
diff --git a/drivers/net/wireless/ath/ath10k/wmi.c b/drivers/net/wireless/ath/ath10k/wmi.c
index 58dc2189ba49..c5e1ca5945db 100644
--- a/drivers/net/wireless/ath/ath10k/wmi.c
+++ b/drivers/net/wireless/ath/ath10k/wmi.c
@@ -1,6 +1,7 @@
/*
* Copyright (c) 2005-2011 Atheros Communications Inc.
* Copyright (c) 2011-2017 Qualcomm Atheros, Inc.
+ * Copyright (c) 2018, The Linux Foundation. All rights reserved.
*
* Permission to use, copy, modify, and/or distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
@@ -196,6 +197,7 @@ static struct wmi_cmd_map wmi_cmd_map = {
.mu_cal_start_cmdid = WMI_CMD_UNSUPPORTED,
.set_cca_params_cmdid = WMI_CMD_UNSUPPORTED,
.pdev_bss_chan_info_request_cmdid = WMI_CMD_UNSUPPORTED,
+ .pdev_get_tpc_table_cmdid = WMI_CMD_UNSUPPORTED,
};
/* 10.X WMI cmd track */
@@ -362,6 +364,7 @@ static struct wmi_cmd_map wmi_10x_cmd_map = {
.mu_cal_start_cmdid = WMI_CMD_UNSUPPORTED,
.set_cca_params_cmdid = WMI_CMD_UNSUPPORTED,
.pdev_bss_chan_info_request_cmdid = WMI_CMD_UNSUPPORTED,
+ .pdev_get_tpc_table_cmdid = WMI_CMD_UNSUPPORTED,
};
/* 10.2.4 WMI cmd track */
@@ -528,6 +531,7 @@ static struct wmi_cmd_map wmi_10_2_4_cmd_map = {
.set_cca_params_cmdid = WMI_CMD_UNSUPPORTED,
.pdev_bss_chan_info_request_cmdid =
WMI_10_2_PDEV_BSS_CHAN_INFO_REQUEST_CMDID,
+ .pdev_get_tpc_table_cmdid = WMI_CMD_UNSUPPORTED,
};
/* 10.4 WMI cmd track */
@@ -1480,6 +1484,7 @@ static struct wmi_cmd_map wmi_10_2_cmd_map = {
.pdev_get_ani_cck_config_cmdid = WMI_CMD_UNSUPPORTED,
.pdev_get_ani_ofdm_config_cmdid = WMI_CMD_UNSUPPORTED,
.pdev_reserve_ast_entry_cmdid = WMI_CMD_UNSUPPORTED,
+ .pdev_get_tpc_table_cmdid = WMI_CMD_UNSUPPORTED,
};
static struct wmi_pdev_param_map wmi_10_4_pdev_param_map = {
@@ -1742,8 +1747,8 @@ int ath10k_wmi_cmd_send_nowait(struct ath10k *ar, struct sk_buff *skb,
cmd_hdr->cmd_id = __cpu_to_le32(cmd);
memset(skb_cb, 0, sizeof(*skb_cb));
+ trace_ath10k_wmi_cmd(ar, cmd_id, skb->data, skb->len);
ret = ath10k_htc_send(&ar->htc, ar->wmi.eid, skb);
- trace_ath10k_wmi_cmd(ar, cmd_id, skb->data, skb->len, ret);
if (ret)
goto err_pull;
@@ -2703,6 +2708,28 @@ ath10k_wmi_10_4_pull_peer_stats(const struct wmi_10_4_peer_stats *src,
dst->peer_rx_rate = __le32_to_cpu(src->peer_rx_rate);
}
+static void
+ath10k_wmi_10_4_pull_vdev_stats(const struct wmi_vdev_stats_extd *src,
+ struct ath10k_fw_stats_vdev_extd *dst)
+{
+ dst->vdev_id = __le32_to_cpu(src->vdev_id);
+ dst->ppdu_aggr_cnt = __le32_to_cpu(src->ppdu_aggr_cnt);
+ dst->ppdu_noack = __le32_to_cpu(src->ppdu_noack);
+ dst->mpdu_queued = __le32_to_cpu(src->mpdu_queued);
+ dst->ppdu_nonaggr_cnt = __le32_to_cpu(src->ppdu_nonaggr_cnt);
+ dst->mpdu_sw_requeued = __le32_to_cpu(src->mpdu_sw_requeued);
+ dst->mpdu_suc_retry = __le32_to_cpu(src->mpdu_suc_retry);
+ dst->mpdu_suc_multitry = __le32_to_cpu(src->mpdu_suc_multitry);
+ dst->mpdu_fail_retry = __le32_to_cpu(src->mpdu_fail_retry);
+ dst->tx_ftm_suc = __le32_to_cpu(src->tx_ftm_suc);
+ dst->tx_ftm_suc_retry = __le32_to_cpu(src->tx_ftm_suc_retry);
+ dst->tx_ftm_fail = __le32_to_cpu(src->tx_ftm_fail);
+ dst->rx_ftmr_cnt = __le32_to_cpu(src->rx_ftmr_cnt);
+ dst->rx_ftmr_dup_cnt = __le32_to_cpu(src->rx_ftmr_dup_cnt);
+ dst->rx_iftmr_cnt = __le32_to_cpu(src->rx_iftmr_cnt);
+ dst->rx_iftmr_dup_cnt = __le32_to_cpu(src->rx_iftmr_dup_cnt);
+}
+
static int ath10k_wmi_main_op_pull_fw_stats(struct ath10k *ar,
struct sk_buff *skb,
struct ath10k_fw_stats *stats)
@@ -3042,7 +3069,16 @@ static int ath10k_wmi_10_4_op_pull_fw_stats(struct ath10k *ar,
*/
}
- /* fw doesn't implement vdev stats */
+ for (i = 0; i < num_vdev_stats; i++) {
+ const struct wmi_vdev_stats *src;
+
+ /* Ignore vdev stats here as it has only vdev id. Actual vdev
+ * stats will be retrieved from vdev extended stats.
+ */
+ src = (void *)skb->data;
+ if (!skb_pull(skb, sizeof(*src)))
+ return -EPROTO;
+ }
for (i = 0; i < num_peer_stats; i++) {
const struct wmi_10_4_peer_stats *src;
@@ -3074,26 +3110,43 @@ static int ath10k_wmi_10_4_op_pull_fw_stats(struct ath10k *ar,
*/
}
- if ((stats_id & WMI_10_4_STAT_PEER_EXTD) == 0)
- return 0;
+ if (stats_id & WMI_10_4_STAT_PEER_EXTD) {
+ stats->extended = true;
- stats->extended = true;
+ for (i = 0; i < num_peer_stats; i++) {
+ const struct wmi_10_4_peer_extd_stats *src;
+ struct ath10k_fw_extd_stats_peer *dst;
- for (i = 0; i < num_peer_stats; i++) {
- const struct wmi_10_4_peer_extd_stats *src;
- struct ath10k_fw_extd_stats_peer *dst;
+ src = (void *)skb->data;
+ if (!skb_pull(skb, sizeof(*src)))
+ return -EPROTO;
- src = (void *)skb->data;
- if (!skb_pull(skb, sizeof(*src)))
- return -EPROTO;
+ dst = kzalloc(sizeof(*dst), GFP_ATOMIC);
+ if (!dst)
+ continue;
- dst = kzalloc(sizeof(*dst), GFP_ATOMIC);
- if (!dst)
- continue;
+ ether_addr_copy(dst->peer_macaddr,
+ src->peer_macaddr.addr);
+ dst->rx_duration = __le32_to_cpu(src->rx_duration);
+ list_add_tail(&dst->list, &stats->peers_extd);
+ }
+ }
+
+ if (stats_id & WMI_10_4_STAT_VDEV_EXTD) {
+ for (i = 0; i < num_vdev_stats; i++) {
+ const struct wmi_vdev_stats_extd *src;
+ struct ath10k_fw_stats_vdev_extd *dst;
- ether_addr_copy(dst->peer_macaddr, src->peer_macaddr.addr);
- dst->rx_duration = __le32_to_cpu(src->rx_duration);
- list_add_tail(&dst->list, &stats->peers_extd);
+ src = (void *)skb->data;
+ if (!skb_pull(skb, sizeof(*src)))
+ return -EPROTO;
+
+ dst = kzalloc(sizeof(*dst), GFP_ATOMIC);
+ if (!dst)
+ continue;
+ ath10k_wmi_10_4_pull_vdev_stats(src, dst);
+ list_add_tail(&dst->list, &stats->vdevs);
+ }
}
return 0;
@@ -4313,19 +4366,11 @@ static void ath10k_tpc_config_disp_tables(struct ath10k *ar,
}
}
-void ath10k_wmi_event_pdev_tpc_config(struct ath10k *ar, struct sk_buff *skb)
+void ath10k_wmi_tpc_config_get_rate_code(u8 *rate_code, u16 *pream_table,
+ u32 num_tx_chain)
{
- u32 i, j, pream_idx, num_tx_chain;
- u8 rate_code[WMI_TPC_RATE_MAX], rate_idx;
- u16 pream_table[WMI_TPC_PREAM_TABLE_MAX];
- struct wmi_pdev_tpc_config_event *ev;
- struct ath10k_tpc_stats *tpc_stats;
-
- ev = (struct wmi_pdev_tpc_config_event *)skb->data;
-
- tpc_stats = kzalloc(sizeof(*tpc_stats), GFP_ATOMIC);
- if (!tpc_stats)
- return;
+ u32 i, j, pream_idx;
+ u8 rate_idx;
/* Create the rate code table based on the chains supported */
rate_idx = 0;
@@ -4349,8 +4394,6 @@ void ath10k_wmi_event_pdev_tpc_config(struct ath10k *ar, struct sk_buff *skb)
pream_table[pream_idx] = rate_idx;
pream_idx++;
- num_tx_chain = __le32_to_cpu(ev->num_tx_chain);
-
/* Fill HT20 rate code */
for (i = 0; i < num_tx_chain; i++) {
for (j = 0; j < 8; j++) {
@@ -4374,7 +4417,7 @@ void ath10k_wmi_event_pdev_tpc_config(struct ath10k *ar, struct sk_buff *skb)
pream_idx++;
/* Fill VHT20 rate code */
- for (i = 0; i < __le32_to_cpu(ev->num_tx_chain); i++) {
+ for (i = 0; i < num_tx_chain; i++) {
for (j = 0; j < 10; j++) {
rate_code[rate_idx] =
ATH10K_HW_RATECODE(j, i, WMI_RATE_PREAMBLE_VHT);
@@ -4418,6 +4461,26 @@ void ath10k_wmi_event_pdev_tpc_config(struct ath10k *ar, struct sk_buff *skb)
ATH10K_HW_RATECODE(0, 0, WMI_RATE_PREAMBLE_OFDM);
pream_table[pream_idx] = ATH10K_TPC_PREAM_TABLE_END;
+}
+
+void ath10k_wmi_event_pdev_tpc_config(struct ath10k *ar, struct sk_buff *skb)
+{
+ u32 num_tx_chain;
+ u8 rate_code[WMI_TPC_RATE_MAX];
+ u16 pream_table[WMI_TPC_PREAM_TABLE_MAX];
+ struct wmi_pdev_tpc_config_event *ev;
+ struct ath10k_tpc_stats *tpc_stats;
+
+ ev = (struct wmi_pdev_tpc_config_event *)skb->data;
+
+ tpc_stats = kzalloc(sizeof(*tpc_stats), GFP_ATOMIC);
+ if (!tpc_stats)
+ return;
+
+ num_tx_chain = __le32_to_cpu(ev->num_tx_chain);
+
+ ath10k_wmi_tpc_config_get_rate_code(rate_code, pream_table,
+ num_tx_chain);
tpc_stats->chan_freq = __le32_to_cpu(ev->chan_freq);
tpc_stats->phy_mode = __le32_to_cpu(ev->phy_mode);
@@ -4457,6 +4520,246 @@ void ath10k_wmi_event_pdev_tpc_config(struct ath10k *ar, struct sk_buff *skb)
__le32_to_cpu(ev->rate_max));
}
+static u8
+ath10k_wmi_tpc_final_get_rate(struct ath10k *ar,
+ struct wmi_pdev_tpc_final_table_event *ev,
+ u32 rate_idx, u32 num_chains,
+ u32 rate_code, u8 type, u32 pream_idx)
+{
+ u8 tpc, num_streams, preamble, ch, stm_idx;
+ s8 pow_agcdd, pow_agstbc, pow_agtxbf;
+ int pream;
+
+ num_streams = ATH10K_HW_NSS(rate_code);
+ preamble = ATH10K_HW_PREAMBLE(rate_code);
+ ch = num_chains - 1;
+ stm_idx = num_streams - 1;
+ pream = -1;
+
+ if (__le32_to_cpu(ev->chan_freq) <= 2483) {
+ switch (pream_idx) {
+ case WMI_TPC_PREAM_2GHZ_CCK:
+ pream = 0;
+ break;
+ case WMI_TPC_PREAM_2GHZ_OFDM:
+ pream = 1;
+ break;
+ case WMI_TPC_PREAM_2GHZ_HT20:
+ case WMI_TPC_PREAM_2GHZ_VHT20:
+ pream = 2;
+ break;
+ case WMI_TPC_PREAM_2GHZ_HT40:
+ case WMI_TPC_PREAM_2GHZ_VHT40:
+ pream = 3;
+ break;
+ case WMI_TPC_PREAM_2GHZ_VHT80:
+ pream = 4;
+ break;
+ default:
+ pream = -1;
+ break;
+ }
+ }
+
+ if (__le32_to_cpu(ev->chan_freq) >= 5180) {
+ switch (pream_idx) {
+ case WMI_TPC_PREAM_5GHZ_OFDM:
+ pream = 0;
+ break;
+ case WMI_TPC_PREAM_5GHZ_HT20:
+ case WMI_TPC_PREAM_5GHZ_VHT20:
+ pream = 1;
+ break;
+ case WMI_TPC_PREAM_5GHZ_HT40:
+ case WMI_TPC_PREAM_5GHZ_VHT40:
+ pream = 2;
+ break;
+ case WMI_TPC_PREAM_5GHZ_VHT80:
+ pream = 3;
+ break;
+ case WMI_TPC_PREAM_5GHZ_HTCUP:
+ pream = 4;
+ break;
+ default:
+ pream = -1;
+ break;
+ }
+ }
+
+ if (pream == 4)
+ tpc = min_t(u8, ev->rates_array[rate_idx],
+ ev->max_reg_allow_pow[ch]);
+ else
+ tpc = min_t(u8, min_t(u8, ev->rates_array[rate_idx],
+ ev->max_reg_allow_pow[ch]),
+ ev->ctl_power_table[0][pream][stm_idx]);
+
+ if (__le32_to_cpu(ev->num_tx_chain) <= 1)
+ goto out;
+
+ if (preamble == WMI_RATE_PREAMBLE_CCK)
+ goto out;
+
+ if (num_chains <= num_streams)
+ goto out;
+
+ switch (type) {
+ case WMI_TPC_TABLE_TYPE_STBC:
+ pow_agstbc = ev->max_reg_allow_pow_agstbc[ch - 1][stm_idx];
+ if (pream == 4)
+ tpc = min_t(u8, tpc, pow_agstbc);
+ else
+ tpc = min_t(u8, min_t(u8, tpc, pow_agstbc),
+ ev->ctl_power_table[0][pream][stm_idx]);
+ break;
+ case WMI_TPC_TABLE_TYPE_TXBF:
+ pow_agtxbf = ev->max_reg_allow_pow_agtxbf[ch - 1][stm_idx];
+ if (pream == 4)
+ tpc = min_t(u8, tpc, pow_agtxbf);
+ else
+ tpc = min_t(u8, min_t(u8, tpc, pow_agtxbf),
+ ev->ctl_power_table[1][pream][stm_idx]);
+ break;
+ case WMI_TPC_TABLE_TYPE_CDD:
+ pow_agcdd = ev->max_reg_allow_pow_agcdd[ch - 1][stm_idx];
+ if (pream == 4)
+ tpc = min_t(u8, tpc, pow_agcdd);
+ else
+ tpc = min_t(u8, min_t(u8, tpc, pow_agcdd),
+ ev->ctl_power_table[0][pream][stm_idx]);
+ break;
+ default:
+ ath10k_warn(ar, "unknown wmi tpc final table type: %d\n", type);
+ tpc = 0;
+ break;
+ }
+
+out:
+ return tpc;
+}
+
+static void
+ath10k_wmi_tpc_stats_final_disp_tables(struct ath10k *ar,
+ struct wmi_pdev_tpc_final_table_event *ev,
+ struct ath10k_tpc_stats_final *tpc_stats,
+ u8 *rate_code, u16 *pream_table, u8 type)
+{
+ u32 i, j, pream_idx, flags;
+ u8 tpc[WMI_TPC_TX_N_CHAIN];
+ char tpc_value[WMI_TPC_TX_N_CHAIN * WMI_TPC_BUF_SIZE];
+ char buff[WMI_TPC_BUF_SIZE];
+
+ flags = __le32_to_cpu(ev->flags);
+
+ switch (type) {
+ case WMI_TPC_TABLE_TYPE_CDD:
+ if (!(flags & WMI_TPC_CONFIG_EVENT_FLAG_TABLE_CDD)) {
+ ath10k_dbg(ar, ATH10K_DBG_WMI, "CDD not supported\n");
+ tpc_stats->flag[type] = ATH10K_TPC_TABLE_TYPE_FLAG;
+ return;
+ }
+ break;
+ case WMI_TPC_TABLE_TYPE_STBC:
+ if (!(flags & WMI_TPC_CONFIG_EVENT_FLAG_TABLE_STBC)) {
+ ath10k_dbg(ar, ATH10K_DBG_WMI, "STBC not supported\n");
+ tpc_stats->flag[type] = ATH10K_TPC_TABLE_TYPE_FLAG;
+ return;
+ }
+ break;
+ case WMI_TPC_TABLE_TYPE_TXBF:
+ if (!(flags & WMI_TPC_CONFIG_EVENT_FLAG_TABLE_TXBF)) {
+ ath10k_dbg(ar, ATH10K_DBG_WMI, "TXBF not supported\n");
+ tpc_stats->flag[type] = ATH10K_TPC_TABLE_TYPE_FLAG;
+ return;
+ }
+ break;
+ default:
+ ath10k_dbg(ar, ATH10K_DBG_WMI,
+ "invalid table type in wmi tpc event: %d\n", type);
+ return;
+ }
+
+ pream_idx = 0;
+ for (i = 0; i < __le32_to_cpu(ev->rate_max); i++) {
+ memset(tpc_value, 0, sizeof(tpc_value));
+ memset(buff, 0, sizeof(buff));
+ if (i == pream_table[pream_idx])
+ pream_idx++;
+
+ for (j = 0; j < WMI_TPC_TX_N_CHAIN; j++) {
+ if (j >= __le32_to_cpu(ev->num_tx_chain))
+ break;
+
+ tpc[j] = ath10k_wmi_tpc_final_get_rate(ar, ev, i, j + 1,
+ rate_code[i],
+ type, pream_idx);
+ snprintf(buff, sizeof(buff), "%8d ", tpc[j]);
+ strncat(tpc_value, buff, strlen(buff));
+ }
+ tpc_stats->tpc_table_final[type].pream_idx[i] = pream_idx;
+ tpc_stats->tpc_table_final[type].rate_code[i] = rate_code[i];
+ memcpy(tpc_stats->tpc_table_final[type].tpc_value[i],
+ tpc_value, sizeof(tpc_value));
+ }
+}
+
+void ath10k_wmi_event_tpc_final_table(struct ath10k *ar, struct sk_buff *skb)
+{
+ u32 num_tx_chain;
+ u8 rate_code[WMI_TPC_FINAL_RATE_MAX];
+ u16 pream_table[WMI_TPC_PREAM_TABLE_MAX];
+ struct wmi_pdev_tpc_final_table_event *ev;
+ struct ath10k_tpc_stats_final *tpc_stats;
+
+ ev = (struct wmi_pdev_tpc_final_table_event *)skb->data;
+
+ tpc_stats = kzalloc(sizeof(*tpc_stats), GFP_ATOMIC);
+ if (!tpc_stats)
+ return;
+
+ num_tx_chain = __le32_to_cpu(ev->num_tx_chain);
+
+ ath10k_wmi_tpc_config_get_rate_code(rate_code, pream_table,
+ num_tx_chain);
+
+ tpc_stats->chan_freq = __le32_to_cpu(ev->chan_freq);
+ tpc_stats->phy_mode = __le32_to_cpu(ev->phy_mode);
+ tpc_stats->ctl = __le32_to_cpu(ev->ctl);
+ tpc_stats->reg_domain = __le32_to_cpu(ev->reg_domain);
+ tpc_stats->twice_antenna_gain = a_sle32_to_cpu(ev->twice_antenna_gain);
+ tpc_stats->twice_antenna_reduction =
+ __le32_to_cpu(ev->twice_antenna_reduction);
+ tpc_stats->power_limit = __le32_to_cpu(ev->power_limit);
+ tpc_stats->twice_max_rd_power = __le32_to_cpu(ev->twice_max_rd_power);
+ tpc_stats->num_tx_chain = __le32_to_cpu(ev->num_tx_chain);
+ tpc_stats->rate_max = __le32_to_cpu(ev->rate_max);
+
+ ath10k_wmi_tpc_stats_final_disp_tables(ar, ev, tpc_stats,
+ rate_code, pream_table,
+ WMI_TPC_TABLE_TYPE_CDD);
+ ath10k_wmi_tpc_stats_final_disp_tables(ar, ev, tpc_stats,
+ rate_code, pream_table,
+ WMI_TPC_TABLE_TYPE_STBC);
+ ath10k_wmi_tpc_stats_final_disp_tables(ar, ev, tpc_stats,
+ rate_code, pream_table,
+ WMI_TPC_TABLE_TYPE_TXBF);
+
+ ath10k_debug_tpc_stats_final_process(ar, tpc_stats);
+
+ ath10k_dbg(ar, ATH10K_DBG_WMI,
+ "wmi event tpc final table channel %d mode %d ctl %d regd %d gain %d %d limit %d max_power %d tx_chanins %d rates %d\n",
+ __le32_to_cpu(ev->chan_freq),
+ __le32_to_cpu(ev->phy_mode),
+ __le32_to_cpu(ev->ctl),
+ __le32_to_cpu(ev->reg_domain),
+ a_sle32_to_cpu(ev->twice_antenna_gain),
+ __le32_to_cpu(ev->twice_antenna_reduction),
+ __le32_to_cpu(ev->power_limit),
+ __le32_to_cpu(ev->twice_max_rd_power) / 2,
+ __le32_to_cpu(ev->num_tx_chain),
+ __le32_to_cpu(ev->rate_max));
+}
+
static void
ath10k_wmi_handle_tdls_peer_event(struct ath10k *ar, struct sk_buff *skb)
{
@@ -5531,6 +5834,7 @@ static void ath10k_wmi_10_4_op_rx(struct ath10k *ar, struct sk_buff *skb)
case WMI_10_4_WOW_WAKEUP_HOST_EVENTID:
case WMI_10_4_PEER_RATECODE_LIST_EVENTID:
case WMI_10_4_WDS_PEER_EVENTID:
+ case WMI_10_4_DEBUG_FATAL_CONDITION_EVENTID:
ath10k_dbg(ar, ATH10K_DBG_WMI,
"received event id %d not implemented\n", id);
break;
@@ -5549,6 +5853,9 @@ static void ath10k_wmi_10_4_op_rx(struct ath10k *ar, struct sk_buff *skb)
case WMI_10_4_TDLS_PEER_EVENTID:
ath10k_wmi_handle_tdls_peer_event(ar, skb);
break;
+ case WMI_10_4_PDEV_TPC_TABLE_EVENTID:
+ ath10k_wmi_event_tpc_final_table(ar, skb);
+ break;
default:
ath10k_warn(ar, "Unknown eventid: %d\n", id);
break;
@@ -7745,6 +8052,72 @@ ath10k_wmi_op_gen_pdev_enable_adaptive_cca(struct ath10k *ar, u8 enable,
return skb;
}
+static void
+ath10k_wmi_fw_vdev_stats_extd_fill(const struct ath10k_fw_stats_vdev_extd *vdev,
+ char *buf, u32 *length)
+{
+ u32 len = *length;
+ u32 buf_len = ATH10K_FW_STATS_BUF_SIZE;
+ u32 val;
+
+ len += scnprintf(buf + len, buf_len - len, "%30s %u\n",
+ "vdev id", vdev->vdev_id);
+ len += scnprintf(buf + len, buf_len - len, "%30s %u\n",
+ "ppdu aggr count", vdev->ppdu_aggr_cnt);
+ len += scnprintf(buf + len, buf_len - len, "%30s %u\n",
+ "ppdu noack", vdev->ppdu_noack);
+ len += scnprintf(buf + len, buf_len - len, "%30s %u\n",
+ "mpdu queued", vdev->mpdu_queued);
+ len += scnprintf(buf + len, buf_len - len, "%30s %u\n",
+ "ppdu nonaggr count", vdev->ppdu_nonaggr_cnt);
+ len += scnprintf(buf + len, buf_len - len, "%30s %u\n",
+ "mpdu sw requeued", vdev->mpdu_sw_requeued);
+ len += scnprintf(buf + len, buf_len - len, "%30s %u\n",
+ "mpdu success retry", vdev->mpdu_suc_retry);
+ len += scnprintf(buf + len, buf_len - len, "%30s %u\n",
+ "mpdu success multitry", vdev->mpdu_suc_multitry);
+ len += scnprintf(buf + len, buf_len - len, "%30s %u\n",
+ "mpdu fail retry", vdev->mpdu_fail_retry);
+ val = vdev->tx_ftm_suc;
+ if (val & WMI_VDEV_STATS_FTM_COUNT_VALID)
+ len += scnprintf(buf + len, buf_len - len, "%30s %u\n",
+ "tx ftm success",
+ MS(val, WMI_VDEV_STATS_FTM_COUNT));
+ val = vdev->tx_ftm_suc_retry;
+ if (val & WMI_VDEV_STATS_FTM_COUNT_VALID)
+ len += scnprintf(buf + len, buf_len - len, "%30s %u\n",
+ "tx ftm success retry",
+ MS(val, WMI_VDEV_STATS_FTM_COUNT));
+ val = vdev->tx_ftm_fail;
+ if (val & WMI_VDEV_STATS_FTM_COUNT_VALID)
+ len += scnprintf(buf + len, buf_len - len, "%30s %u\n",
+ "tx ftm fail",
+ MS(val, WMI_VDEV_STATS_FTM_COUNT));
+ val = vdev->rx_ftmr_cnt;
+ if (val & WMI_VDEV_STATS_FTM_COUNT_VALID)
+ len += scnprintf(buf + len, buf_len - len, "%30s %u\n",
+ "rx ftm request count",
+ MS(val, WMI_VDEV_STATS_FTM_COUNT));
+ val = vdev->rx_ftmr_dup_cnt;
+ if (val & WMI_VDEV_STATS_FTM_COUNT_VALID)
+ len += scnprintf(buf + len, buf_len - len, "%30s %u\n",
+ "rx ftm request dup count",
+ MS(val, WMI_VDEV_STATS_FTM_COUNT));
+ val = vdev->rx_iftmr_cnt;
+ if (val & WMI_VDEV_STATS_FTM_COUNT_VALID)
+ len += scnprintf(buf + len, buf_len - len, "%30s %u\n",
+ "rx initial ftm req count",
+ MS(val, WMI_VDEV_STATS_FTM_COUNT));
+ val = vdev->rx_iftmr_dup_cnt;
+ if (val & WMI_VDEV_STATS_FTM_COUNT_VALID)
+ len += scnprintf(buf + len, buf_len - len, "%30s %u\n",
+ "rx initial ftm req dup cnt",
+ MS(val, WMI_VDEV_STATS_FTM_COUNT));
+ len += scnprintf(buf + len, buf_len - len, "\n");
+
+ *length = len;
+}
+
void ath10k_wmi_10_4_op_fw_stats_fill(struct ath10k *ar,
struct ath10k_fw_stats *fw_stats,
char *buf)
@@ -7752,7 +8125,7 @@ void ath10k_wmi_10_4_op_fw_stats_fill(struct ath10k *ar,
u32 len = 0;
u32 buf_len = ATH10K_FW_STATS_BUF_SIZE;
const struct ath10k_fw_stats_pdev *pdev;
- const struct ath10k_fw_stats_vdev *vdev;
+ const struct ath10k_fw_stats_vdev_extd *vdev;
const struct ath10k_fw_stats_peer *peer;
size_t num_peers;
size_t num_vdevs;
@@ -7805,9 +8178,8 @@ void ath10k_wmi_10_4_op_fw_stats_fill(struct ath10k *ar,
"ath10k VDEV stats", num_vdevs);
len += scnprintf(buf + len, buf_len - len, "%30s\n\n",
"=================");
-
list_for_each_entry(vdev, &fw_stats->vdevs, list) {
- ath10k_wmi_fw_vdev_stats_fill(vdev, buf, &len);
+ ath10k_wmi_fw_vdev_stats_extd_fill(vdev, buf, &len);
}
len += scnprintf(buf + len, buf_len - len, "\n");
@@ -7990,6 +8362,24 @@ static u32 ath10k_wmi_prepare_peer_qos(u8 uapsd_queues, u8 sp)
}
static struct sk_buff *
+ath10k_wmi_10_4_op_gen_pdev_get_tpc_table_cmdid(struct ath10k *ar, u32 param)
+{
+ struct wmi_pdev_get_tpc_table_cmd *cmd;
+ struct sk_buff *skb;
+
+ skb = ath10k_wmi_alloc_skb(ar, sizeof(*cmd));
+ if (!skb)
+ return ERR_PTR(-ENOMEM);
+
+ cmd = (struct wmi_pdev_get_tpc_table_cmd *)skb->data;
+ cmd->param = __cpu_to_le32(param);
+
+ ath10k_dbg(ar, ATH10K_DBG_WMI,
+ "wmi pdev get tpc table param:%d\n", param);
+ return skb;
+}
+
+static struct sk_buff *
ath10k_wmi_10_4_gen_tdls_peer_update(struct ath10k *ar,
const struct wmi_tdls_peer_update_cmd_arg *arg,
const struct wmi_tdls_peer_capab_arg *cap,
@@ -8430,6 +8820,8 @@ static const struct wmi_ops wmi_10_4_ops = {
.ext_resource_config = ath10k_wmi_10_4_ext_resource_config,
.gen_update_fw_tdls_state = ath10k_wmi_10_4_gen_update_fw_tdls_state,
.gen_tdls_peer_update = ath10k_wmi_10_4_gen_tdls_peer_update,
+ .gen_pdev_get_tpc_table_cmdid =
+ ath10k_wmi_10_4_op_gen_pdev_get_tpc_table_cmdid,
/* shared with 10.2 */
.pull_echo_ev = ath10k_wmi_op_pull_echo_ev,
diff --git a/drivers/net/wireless/ath/ath10k/wmi.h b/drivers/net/wireless/ath/ath10k/wmi.h
index c7b30ed9015d..6fbc84c29521 100644
--- a/drivers/net/wireless/ath/ath10k/wmi.h
+++ b/drivers/net/wireless/ath/ath10k/wmi.h
@@ -1,6 +1,7 @@
/*
* Copyright (c) 2005-2011 Atheros Communications Inc.
* Copyright (c) 2011-2017 Qualcomm Atheros, Inc.
+ * Copyright (c) 2018, The Linux Foundation. All rights reserved.
*
* Permission to use, copy, modify, and/or distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
@@ -197,6 +198,9 @@ enum wmi_service {
WMI_SERVICE_TDLS_EXPLICIT_MODE_ONLY,
WMI_SERVICE_MGMT_TX_WMI,
WMI_SERVICE_TDLS_WIDER_BANDWIDTH,
+ WMI_SERVICE_HTT_MGMT_TX_COMP_VALID_FLAGS,
+ WMI_SERVICE_HOST_DFS_CHECK_SUPPORT,
+ WMI_SERVICE_TPC_STATS_FINAL,
/* keep last */
WMI_SERVICE_MAX,
@@ -339,6 +343,9 @@ enum wmi_10_4_service {
WMI_10_4_SERVICE_TDLS_CONN_TRACKER_IN_HOST_MODE,
WMI_10_4_SERVICE_TDLS_EXPLICIT_MODE_ONLY,
WMI_10_4_SERVICE_TDLS_WIDER_BANDWIDTH,
+ WMI_10_4_SERVICE_HTT_MGMT_TX_COMP_VALID_FLAGS,
+ WMI_10_4_SERVICE_HOST_DFS_CHECK_SUPPORT,
+ WMI_10_4_SERVICE_TPC_STATS_FINAL,
};
static inline char *wmi_service_name(int service_id)
@@ -448,6 +455,9 @@ static inline char *wmi_service_name(int service_id)
SVCSTR(WMI_SERVICE_TDLS_CONN_TRACKER_IN_HOST_MODE);
SVCSTR(WMI_SERVICE_TDLS_EXPLICIT_MODE_ONLY);
SVCSTR(WMI_SERVICE_TDLS_WIDER_BANDWIDTH);
+ SVCSTR(WMI_SERVICE_HTT_MGMT_TX_COMP_VALID_FLAGS);
+ SVCSTR(WMI_SERVICE_HOST_DFS_CHECK_SUPPORT);
+ SVCSTR(WMI_SERVICE_TPC_STATS_FINAL);
default:
return NULL;
}
@@ -746,6 +756,12 @@ static inline void wmi_10_4_svc_map(const __le32 *in, unsigned long *out,
WMI_SERVICE_TDLS_EXPLICIT_MODE_ONLY, len);
SVCMAP(WMI_10_4_SERVICE_TDLS_WIDER_BANDWIDTH,
WMI_SERVICE_TDLS_WIDER_BANDWIDTH, len);
+ SVCMAP(WMI_10_4_SERVICE_HTT_MGMT_TX_COMP_VALID_FLAGS,
+ WMI_SERVICE_HTT_MGMT_TX_COMP_VALID_FLAGS, len);
+ SVCMAP(WMI_10_4_SERVICE_HOST_DFS_CHECK_SUPPORT,
+ WMI_SERVICE_HOST_DFS_CHECK_SUPPORT, len);
+ SVCMAP(WMI_10_4_SERVICE_TPC_STATS_FINAL,
+ WMI_SERVICE_TPC_STATS_FINAL, len);
}
#undef SVCMAP
@@ -3993,10 +4009,12 @@ struct wmi_pdev_get_tpc_config_cmd {
#define WMI_TPC_CONFIG_PARAM 1
#define WMI_TPC_RATE_MAX 160
+#define WMI_TPC_FINAL_RATE_MAX 240
#define WMI_TPC_TX_N_CHAIN 4
#define WMI_TPC_PREAM_TABLE_MAX 10
#define WMI_TPC_FLAG 3
#define WMI_TPC_BUF_SIZE 10
+#define WMI_TPC_BEAMFORMING 2
enum wmi_tpc_table_type {
WMI_TPC_TABLE_TYPE_CDD = 0,
@@ -4039,6 +4057,51 @@ enum wmi_tp_scale {
WMI_TP_SCALE_SIZE = 5, /* max num of enum */
};
+struct wmi_pdev_tpc_final_table_event {
+ __le32 reg_domain;
+ __le32 chan_freq;
+ __le32 phy_mode;
+ __le32 twice_antenna_reduction;
+ __le32 twice_max_rd_power;
+ a_sle32 twice_antenna_gain;
+ __le32 power_limit;
+ __le32 rate_max;
+ __le32 num_tx_chain;
+ __le32 ctl;
+ __le32 flags;
+ s8 max_reg_allow_pow[WMI_TPC_TX_N_CHAIN];
+ s8 max_reg_allow_pow_agcdd[WMI_TPC_TX_N_CHAIN][WMI_TPC_TX_N_CHAIN];
+ s8 max_reg_allow_pow_agstbc[WMI_TPC_TX_N_CHAIN][WMI_TPC_TX_N_CHAIN];
+ s8 max_reg_allow_pow_agtxbf[WMI_TPC_TX_N_CHAIN][WMI_TPC_TX_N_CHAIN];
+ u8 rates_array[WMI_TPC_FINAL_RATE_MAX];
+ u8 ctl_power_table[WMI_TPC_BEAMFORMING][WMI_TPC_TX_N_CHAIN]
+ [WMI_TPC_TX_N_CHAIN];
+} __packed;
+
+struct wmi_pdev_get_tpc_table_cmd {
+ __le32 param;
+} __packed;
+
+enum wmi_tpc_pream_2ghz {
+ WMI_TPC_PREAM_2GHZ_CCK = 0,
+ WMI_TPC_PREAM_2GHZ_OFDM,
+ WMI_TPC_PREAM_2GHZ_HT20,
+ WMI_TPC_PREAM_2GHZ_HT40,
+ WMI_TPC_PREAM_2GHZ_VHT20,
+ WMI_TPC_PREAM_2GHZ_VHT40,
+ WMI_TPC_PREAM_2GHZ_VHT80,
+};
+
+enum wmi_tpc_pream_5ghz {
+ WMI_TPC_PREAM_5GHZ_OFDM = 1,
+ WMI_TPC_PREAM_5GHZ_HT20,
+ WMI_TPC_PREAM_5GHZ_HT40,
+ WMI_TPC_PREAM_5GHZ_VHT20,
+ WMI_TPC_PREAM_5GHZ_VHT40,
+ WMI_TPC_PREAM_5GHZ_VHT80,
+ WMI_TPC_PREAM_5GHZ_HTCUP,
+};
+
struct wmi_pdev_chanlist_update_event {
/* number of channels */
__le32 num_chan;
@@ -4350,6 +4413,7 @@ enum wmi_10_4_stats_id {
WMI_10_4_STAT_AP = BIT(1),
WMI_10_4_STAT_INST = BIT(2),
WMI_10_4_STAT_PEER_EXTD = BIT(3),
+ WMI_10_4_STAT_VDEV_EXTD = BIT(4),
};
struct wlan_inst_rssi_args {
@@ -4489,12 +4553,36 @@ struct wmi_10_4_pdev_stats {
/*
* VDEV statistics
- * TODO: add all VDEV stats here
*/
+
+#define WMI_VDEV_STATS_FTM_COUNT_VALID BIT(31)
+#define WMI_VDEV_STATS_FTM_COUNT_LSB 0
+#define WMI_VDEV_STATS_FTM_COUNT_MASK 0x7fffffff
+
struct wmi_vdev_stats {
__le32 vdev_id;
} __packed;
+struct wmi_vdev_stats_extd {
+ __le32 vdev_id;
+ __le32 ppdu_aggr_cnt;
+ __le32 ppdu_noack;
+ __le32 mpdu_queued;
+ __le32 ppdu_nonaggr_cnt;
+ __le32 mpdu_sw_requeued;
+ __le32 mpdu_suc_retry;
+ __le32 mpdu_suc_multitry;
+ __le32 mpdu_fail_retry;
+ __le32 tx_ftm_suc;
+ __le32 tx_ftm_suc_retry;
+ __le32 tx_ftm_fail;
+ __le32 rx_ftmr_cnt;
+ __le32 rx_ftmr_dup_cnt;
+ __le32 rx_iftmr_cnt;
+ __le32 rx_iftmr_dup_cnt;
+ __le32 reserved[6];
+} __packed;
+
/*
* peer statistics.
* TODO: add more stats
@@ -6729,6 +6817,7 @@ enum wmi_tdls_state {
WMI_TDLS_DISABLE,
WMI_TDLS_ENABLE_PASSIVE,
WMI_TDLS_ENABLE_ACTIVE,
+ WMI_TDLS_ENABLE_ACTIVE_EXTERNAL_CONTROL,
};
enum wmi_tdls_peer_state {
@@ -6979,5 +7068,8 @@ void ath10k_wmi_10_4_op_fw_stats_fill(struct ath10k *ar,
int ath10k_wmi_op_get_vdev_subtype(struct ath10k *ar,
enum wmi_vdev_subtype subtype);
int ath10k_wmi_barrier(struct ath10k *ar);
+void ath10k_wmi_tpc_config_get_rate_code(u8 *rate_code, u16 *pream_table,
+ u32 num_tx_chain);
+void ath10k_wmi_event_tpc_final_table(struct ath10k *ar, struct sk_buff *skb);
#endif /* _WMI_H_ */
diff --git a/drivers/net/wireless/ath/ath5k/attach.c b/drivers/net/wireless/ath/ath5k/attach.c
index 233054bd6b52..12d3a6c92ba4 100644
--- a/drivers/net/wireless/ath/ath5k/attach.c
+++ b/drivers/net/wireless/ath/ath5k/attach.c
@@ -327,7 +327,7 @@ int ath5k_hw_init(struct ath5k_hw *ah)
ath5k_hw_set_lladdr(ah, zero_mac);
/* Set BSSID to bcast address: ff:ff:ff:ff:ff:ff for now */
- memcpy(common->curbssid, ath_bcast_mac, ETH_ALEN);
+ eth_broadcast_addr(common->curbssid);
ath5k_hw_set_bssid(ah);
ath5k_hw_set_opmode(ah, ah->opmode);
diff --git a/drivers/net/wireless/ath/ath5k/base.c b/drivers/net/wireless/ath/ath5k/base.c
index 527afcf39246..a2351ef45ae0 100644
--- a/drivers/net/wireless/ath/ath5k/base.c
+++ b/drivers/net/wireless/ath/ath5k/base.c
@@ -73,16 +73,16 @@
#include "trace.h"
bool ath5k_modparam_nohwcrypt;
-module_param_named(nohwcrypt, ath5k_modparam_nohwcrypt, bool, S_IRUGO);
+module_param_named(nohwcrypt, ath5k_modparam_nohwcrypt, bool, 0444);
MODULE_PARM_DESC(nohwcrypt, "Disable hardware encryption.");
static bool modparam_fastchanswitch;
-module_param_named(fastchanswitch, modparam_fastchanswitch, bool, S_IRUGO);
+module_param_named(fastchanswitch, modparam_fastchanswitch, bool, 0444);
MODULE_PARM_DESC(fastchanswitch, "Enable fast channel switching for AR2413/AR5413 radios.");
static bool ath5k_modparam_no_hw_rfkill_switch;
module_param_named(no_hw_rfkill_switch, ath5k_modparam_no_hw_rfkill_switch,
- bool, S_IRUGO);
+ bool, 0444);
MODULE_PARM_DESC(no_hw_rfkill_switch, "Ignore the GPIO RFKill switch state");
diff --git a/drivers/net/wireless/ath/ath5k/debug.c b/drivers/net/wireless/ath/ath5k/debug.c
index bd7f6d7b199e..3513bbec4639 100644
--- a/drivers/net/wireless/ath/ath5k/debug.c
+++ b/drivers/net/wireless/ath/ath5k/debug.c
@@ -1004,32 +1004,17 @@ ath5k_debug_init_device(struct ath5k_hw *ah)
if (!phydir)
return;
- debugfs_create_file("debug", S_IWUSR | S_IRUSR, phydir, ah,
- &fops_debug);
-
- debugfs_create_file("registers", S_IRUSR, phydir, ah, &fops_registers);
-
- debugfs_create_file("beacon", S_IWUSR | S_IRUSR, phydir, ah,
- &fops_beacon);
-
- debugfs_create_file("reset", S_IWUSR, phydir, ah, &fops_reset);
-
- debugfs_create_file("antenna", S_IWUSR | S_IRUSR, phydir, ah,
- &fops_antenna);
-
- debugfs_create_file("misc", S_IRUSR, phydir, ah, &fops_misc);
-
- debugfs_create_file("eeprom", S_IRUSR, phydir, ah, &fops_eeprom);
-
- debugfs_create_file("frameerrors", S_IWUSR | S_IRUSR, phydir, ah,
- &fops_frameerrors);
-
- debugfs_create_file("ani", S_IWUSR | S_IRUSR, phydir, ah, &fops_ani);
-
- debugfs_create_file("queue", S_IWUSR | S_IRUSR, phydir, ah,
- &fops_queue);
-
- debugfs_create_bool("32khz_clock", S_IWUSR | S_IRUSR, phydir,
+ debugfs_create_file("debug", 0600, phydir, ah, &fops_debug);
+ debugfs_create_file("registers", 0400, phydir, ah, &fops_registers);
+ debugfs_create_file("beacon", 0600, phydir, ah, &fops_beacon);
+ debugfs_create_file("reset", 0200, phydir, ah, &fops_reset);
+ debugfs_create_file("antenna", 0600, phydir, ah, &fops_antenna);
+ debugfs_create_file("misc", 0400, phydir, ah, &fops_misc);
+ debugfs_create_file("eeprom", 0400, phydir, ah, &fops_eeprom);
+ debugfs_create_file("frameerrors", 0600, phydir, ah, &fops_frameerrors);
+ debugfs_create_file("ani", 0600, phydir, ah, &fops_ani);
+ debugfs_create_file("queue", 0600, phydir, ah, &fops_queue);
+ debugfs_create_bool("32khz_clock", 0600, phydir,
&ah->ah_use_32khz_clock);
}
diff --git a/drivers/net/wireless/ath/ath5k/qcu.c b/drivers/net/wireless/ath/ath5k/qcu.c
index beda11ce34a7..147947f632f7 100644
--- a/drivers/net/wireless/ath/ath5k/qcu.c
+++ b/drivers/net/wireless/ath/ath5k/qcu.c
@@ -327,8 +327,6 @@ ath5k_hw_reset_tx_queue(struct ath5k_hw *ah, unsigned int queue)
AR5K_ASSERT_ENTRY(queue, ah->ah_capabilities.cap_queues.q_tx_num);
- tq = &ah->ah_txq[queue];
-
/* Skip if queue inactive or if we are on AR5210
* that doesn't have QCU/DCU */
if ((ah->ah_version == AR5K_AR5210) ||
diff --git a/drivers/net/wireless/ath/ath5k/sysfs.c b/drivers/net/wireless/ath/ath5k/sysfs.c
index 25978c732fe1..8113baddd8fc 100644
--- a/drivers/net/wireless/ath/ath5k/sysfs.c
+++ b/drivers/net/wireless/ath/ath5k/sysfs.c
@@ -31,7 +31,7 @@ static ssize_t ath5k_attr_store_##name(struct device *dev, \
set(ah, val); \
return count; \
} \
-static DEVICE_ATTR(name, S_IRUGO | S_IWUSR, \
+static DEVICE_ATTR(name, 0644, \
ath5k_attr_show_##name, ath5k_attr_store_##name)
#define SIMPLE_SHOW(name, get) \
@@ -43,7 +43,7 @@ static ssize_t ath5k_attr_show_##name(struct device *dev, \
struct ath5k_hw *ah = hw->priv; \
return snprintf(buf, PAGE_SIZE, "%d\n", get); \
} \
-static DEVICE_ATTR(name, S_IRUGO, ath5k_attr_show_##name, NULL)
+static DEVICE_ATTR(name, 0444, ath5k_attr_show_##name, NULL)
/*** ANI ***/
@@ -66,7 +66,7 @@ static ssize_t ath5k_attr_show_noise_immunity_level_max(struct device *dev,
{
return snprintf(buf, PAGE_SIZE, "%d\n", ATH5K_ANI_MAX_NOISE_IMM_LVL);
}
-static DEVICE_ATTR(noise_immunity_level_max, S_IRUGO,
+static DEVICE_ATTR(noise_immunity_level_max, 0444,
ath5k_attr_show_noise_immunity_level_max, NULL);
static ssize_t ath5k_attr_show_firstep_level_max(struct device *dev,
@@ -75,7 +75,7 @@ static ssize_t ath5k_attr_show_firstep_level_max(struct device *dev,
{
return snprintf(buf, PAGE_SIZE, "%d\n", ATH5K_ANI_MAX_FIRSTEP_LVL);
}
-static DEVICE_ATTR(firstep_level_max, S_IRUGO,
+static DEVICE_ATTR(firstep_level_max, 0444,
ath5k_attr_show_firstep_level_max, NULL);
static struct attribute *ath5k_sysfs_entries_ani[] = {
diff --git a/drivers/net/wireless/ath/ath6kl/debug.c b/drivers/net/wireless/ath/ath6kl/debug.c
index 1eea6c23976f..0f965e9f38a4 100644
--- a/drivers/net/wireless/ath/ath6kl/debug.c
+++ b/drivers/net/wireless/ath/ath6kl/debug.c
@@ -1794,69 +1794,68 @@ int ath6kl_debug_init_fs(struct ath6kl *ar)
if (!ar->debugfs_phy)
return -ENOMEM;
- debugfs_create_file("tgt_stats", S_IRUSR, ar->debugfs_phy, ar,
+ debugfs_create_file("tgt_stats", 0400, ar->debugfs_phy, ar,
&fops_tgt_stats);
if (ar->hif_type == ATH6KL_HIF_TYPE_SDIO)
- debugfs_create_file("credit_dist_stats", S_IRUSR,
+ debugfs_create_file("credit_dist_stats", 0400,
ar->debugfs_phy, ar,
&fops_credit_dist_stats);
- debugfs_create_file("endpoint_stats", S_IRUSR | S_IWUSR,
+ debugfs_create_file("endpoint_stats", 0600,
ar->debugfs_phy, ar, &fops_endpoint_stats);
- debugfs_create_file("fwlog", S_IRUSR, ar->debugfs_phy, ar,
- &fops_fwlog);
+ debugfs_create_file("fwlog", 0400, ar->debugfs_phy, ar, &fops_fwlog);
- debugfs_create_file("fwlog_block", S_IRUSR, ar->debugfs_phy, ar,
+ debugfs_create_file("fwlog_block", 0400, ar->debugfs_phy, ar,
&fops_fwlog_block);
- debugfs_create_file("fwlog_mask", S_IRUSR | S_IWUSR, ar->debugfs_phy,
+ debugfs_create_file("fwlog_mask", 0600, ar->debugfs_phy,
ar, &fops_fwlog_mask);
- debugfs_create_file("reg_addr", S_IRUSR | S_IWUSR, ar->debugfs_phy, ar,
+ debugfs_create_file("reg_addr", 0600, ar->debugfs_phy, ar,
&fops_diag_reg_read);
- debugfs_create_file("reg_dump", S_IRUSR, ar->debugfs_phy, ar,
+ debugfs_create_file("reg_dump", 0400, ar->debugfs_phy, ar,
&fops_reg_dump);
- debugfs_create_file("lrssi_roam_threshold", S_IRUSR | S_IWUSR,
+ debugfs_create_file("lrssi_roam_threshold", 0600,
ar->debugfs_phy, ar, &fops_lrssi_roam_threshold);
- debugfs_create_file("reg_write", S_IRUSR | S_IWUSR,
+ debugfs_create_file("reg_write", 0600,
ar->debugfs_phy, ar, &fops_diag_reg_write);
- debugfs_create_file("war_stats", S_IRUSR, ar->debugfs_phy, ar,
+ debugfs_create_file("war_stats", 0400, ar->debugfs_phy, ar,
&fops_war_stats);
- debugfs_create_file("roam_table", S_IRUSR, ar->debugfs_phy, ar,
+ debugfs_create_file("roam_table", 0400, ar->debugfs_phy, ar,
&fops_roam_table);
- debugfs_create_file("force_roam", S_IWUSR, ar->debugfs_phy, ar,
+ debugfs_create_file("force_roam", 0200, ar->debugfs_phy, ar,
&fops_force_roam);
- debugfs_create_file("roam_mode", S_IWUSR, ar->debugfs_phy, ar,
+ debugfs_create_file("roam_mode", 0200, ar->debugfs_phy, ar,
&fops_roam_mode);
- debugfs_create_file("keepalive", S_IRUSR | S_IWUSR, ar->debugfs_phy, ar,
+ debugfs_create_file("keepalive", 0600, ar->debugfs_phy, ar,
&fops_keepalive);
- debugfs_create_file("disconnect_timeout", S_IRUSR | S_IWUSR,
+ debugfs_create_file("disconnect_timeout", 0600,
ar->debugfs_phy, ar, &fops_disconnect_timeout);
- debugfs_create_file("create_qos", S_IWUSR, ar->debugfs_phy, ar,
+ debugfs_create_file("create_qos", 0200, ar->debugfs_phy, ar,
&fops_create_qos);
- debugfs_create_file("delete_qos", S_IWUSR, ar->debugfs_phy, ar,
+ debugfs_create_file("delete_qos", 0200, ar->debugfs_phy, ar,
&fops_delete_qos);
- debugfs_create_file("bgscan_interval", S_IWUSR,
+ debugfs_create_file("bgscan_interval", 0200,
ar->debugfs_phy, ar, &fops_bgscan_int);
- debugfs_create_file("listen_interval", S_IRUSR | S_IWUSR,
+ debugfs_create_file("listen_interval", 0600,
ar->debugfs_phy, ar, &fops_listen_int);
- debugfs_create_file("power_params", S_IWUSR, ar->debugfs_phy, ar,
+ debugfs_create_file("power_params", 0200, ar->debugfs_phy, ar,
&fops_power_params);
return 0;
diff --git a/drivers/net/wireless/ath/ath9k/common-debug.c b/drivers/net/wireless/ath/ath9k/common-debug.c
index 84afcf78151f..239429f10378 100644
--- a/drivers/net/wireless/ath/ath9k/common-debug.c
+++ b/drivers/net/wireless/ath/ath9k/common-debug.c
@@ -47,7 +47,7 @@ static const struct file_operations fops_modal_eeprom = {
void ath9k_cmn_debug_modal_eeprom(struct dentry *debugfs_phy,
struct ath_hw *ah)
{
- debugfs_create_file("modal_eeprom", S_IRUSR, debugfs_phy, ah,
+ debugfs_create_file("modal_eeprom", 0400, debugfs_phy, ah,
&fops_modal_eeprom);
}
EXPORT_SYMBOL(ath9k_cmn_debug_modal_eeprom);
@@ -82,7 +82,7 @@ static const struct file_operations fops_base_eeprom = {
void ath9k_cmn_debug_base_eeprom(struct dentry *debugfs_phy,
struct ath_hw *ah)
{
- debugfs_create_file("base_eeprom", S_IRUSR, debugfs_phy, ah,
+ debugfs_create_file("base_eeprom", 0400, debugfs_phy, ah,
&fops_base_eeprom);
}
EXPORT_SYMBOL(ath9k_cmn_debug_base_eeprom);
@@ -178,8 +178,7 @@ static const struct file_operations fops_recv = {
void ath9k_cmn_debug_recv(struct dentry *debugfs_phy,
struct ath_rx_stats *rxstats)
{
- debugfs_create_file("recv", S_IRUSR, debugfs_phy, rxstats,
- &fops_recv);
+ debugfs_create_file("recv", 0400, debugfs_phy, rxstats, &fops_recv);
}
EXPORT_SYMBOL(ath9k_cmn_debug_recv);
@@ -255,7 +254,7 @@ static const struct file_operations fops_phy_err = {
void ath9k_cmn_debug_phy_err(struct dentry *debugfs_phy,
struct ath_rx_stats *rxstats)
{
- debugfs_create_file("phy_err", S_IRUSR, debugfs_phy, rxstats,
+ debugfs_create_file("phy_err", 0400, debugfs_phy, rxstats,
&fops_phy_err);
}
EXPORT_SYMBOL(ath9k_cmn_debug_phy_err);
diff --git a/drivers/net/wireless/ath/ath9k/common-init.c b/drivers/net/wireless/ath/ath9k/common-init.c
index 8b4f7fdabf58..82de0fadbc95 100644
--- a/drivers/net/wireless/ath/ath9k/common-init.c
+++ b/drivers/net/wireless/ath/ath9k/common-init.c
@@ -88,7 +88,7 @@ static const struct ieee80211_channel ath9k_5ghz_chantable[] = {
CHAN5G(5825, 37), /* Channel 165 */
};
-/* Atheros hardware rate code addition for short premble */
+/* Atheros hardware rate code addition for short preamble */
#define SHPCHECK(__hw_rate, __flags) \
((__flags & IEEE80211_RATE_SHORT_PREAMBLE) ? (__hw_rate | 0x04 ) : 0)
diff --git a/drivers/net/wireless/ath/ath9k/common-spectral.c b/drivers/net/wireless/ath/ath9k/common-spectral.c
index 5e77fe1f5b0d..440e16e641e4 100644
--- a/drivers/net/wireless/ath/ath9k/common-spectral.c
+++ b/drivers/net/wireless/ath/ath9k/common-spectral.c
@@ -479,14 +479,16 @@ ath_cmn_is_fft_buf_full(struct ath_spec_scan_priv *spec_priv)
{
int i = 0;
int ret = 0;
+ struct rchan_buf *buf;
struct rchan *rc = spec_priv->rfs_chan_spec_scan;
- for_each_online_cpu(i)
- ret += relay_buf_full(*per_cpu_ptr(rc->buf, i));
-
- i = num_online_cpus();
+ for_each_possible_cpu(i) {
+ if ((buf = *per_cpu_ptr(rc->buf, i))) {
+ ret += relay_buf_full(buf);
+ }
+ }
- if (ret == i)
+ if (ret)
return 1;
else
return 0;
@@ -1096,23 +1098,23 @@ void ath9k_cmn_spectral_init_debug(struct ath_spec_scan_priv *spec_priv,
return;
debugfs_create_file("spectral_scan_ctl",
- S_IRUSR | S_IWUSR,
+ 0600,
debugfs_phy, spec_priv,
&fops_spec_scan_ctl);
debugfs_create_file("spectral_short_repeat",
- S_IRUSR | S_IWUSR,
+ 0600,
debugfs_phy, spec_priv,
&fops_spectral_short_repeat);
debugfs_create_file("spectral_count",
- S_IRUSR | S_IWUSR,
+ 0600,
debugfs_phy, spec_priv,
&fops_spectral_count);
debugfs_create_file("spectral_period",
- S_IRUSR | S_IWUSR,
+ 0600,
debugfs_phy, spec_priv,
&fops_spectral_period);
debugfs_create_file("spectral_fft_period",
- S_IRUSR | S_IWUSR,
+ 0600,
debugfs_phy, spec_priv,
&fops_spectral_fft_period);
}
diff --git a/drivers/net/wireless/ath/ath9k/debug.c b/drivers/net/wireless/ath/ath9k/debug.c
index 9e8aed5c478c..f685843a2ff3 100644
--- a/drivers/net/wireless/ath/ath9k/debug.c
+++ b/drivers/net/wireless/ath/ath9k/debug.c
@@ -1385,7 +1385,7 @@ int ath9k_init_debug(struct ath_hw *ah)
return -ENOMEM;
#ifdef CONFIG_ATH_DEBUG
- debugfs_create_file("debug", S_IRUSR | S_IWUSR, sc->debug.debugfs_phy,
+ debugfs_create_file("debug", 0600, sc->debug.debugfs_phy,
sc, &fops_debug);
#endif
@@ -1409,22 +1409,22 @@ int ath9k_init_debug(struct ath_hw *ah)
ath9k_cmn_debug_recv(sc->debug.debugfs_phy, &sc->debug.stats.rxstats);
ath9k_cmn_debug_phy_err(sc->debug.debugfs_phy, &sc->debug.stats.rxstats);
- debugfs_create_u8("rx_chainmask", S_IRUSR, sc->debug.debugfs_phy,
+ debugfs_create_u8("rx_chainmask", 0400, sc->debug.debugfs_phy,
&ah->rxchainmask);
- debugfs_create_u8("tx_chainmask", S_IRUSR, sc->debug.debugfs_phy,
+ debugfs_create_u8("tx_chainmask", 0400, sc->debug.debugfs_phy,
&ah->txchainmask);
- debugfs_create_file("ani", S_IRUSR | S_IWUSR,
+ debugfs_create_file("ani", 0600,
sc->debug.debugfs_phy, sc, &fops_ani);
- debugfs_create_bool("paprd", S_IRUSR | S_IWUSR, sc->debug.debugfs_phy,
+ debugfs_create_bool("paprd", 0600, sc->debug.debugfs_phy,
&sc->sc_ah->config.enable_paprd);
- debugfs_create_file("regidx", S_IRUSR | S_IWUSR, sc->debug.debugfs_phy,
+ debugfs_create_file("regidx", 0600, sc->debug.debugfs_phy,
sc, &fops_regidx);
- debugfs_create_file("regval", S_IRUSR | S_IWUSR, sc->debug.debugfs_phy,
+ debugfs_create_file("regval", 0600, sc->debug.debugfs_phy,
sc, &fops_regval);
- debugfs_create_bool("ignore_extcca", S_IRUSR | S_IWUSR,
+ debugfs_create_bool("ignore_extcca", 0600,
sc->debug.debugfs_phy,
&ah->config.cwm_ignore_extcca);
- debugfs_create_file("regdump", S_IRUSR, sc->debug.debugfs_phy, sc,
+ debugfs_create_file("regdump", 0400, sc->debug.debugfs_phy, sc,
&fops_regdump);
debugfs_create_devm_seqfile(sc->dev, "dump_nfcal",
sc->debug.debugfs_phy,
@@ -1433,35 +1433,33 @@ int ath9k_init_debug(struct ath_hw *ah)
ath9k_cmn_debug_base_eeprom(sc->debug.debugfs_phy, sc->sc_ah);
ath9k_cmn_debug_modal_eeprom(sc->debug.debugfs_phy, sc->sc_ah);
- debugfs_create_u32("gpio_mask", S_IRUSR | S_IWUSR,
+ debugfs_create_u32("gpio_mask", 0600,
sc->debug.debugfs_phy, &sc->sc_ah->gpio_mask);
- debugfs_create_u32("gpio_val", S_IRUSR | S_IWUSR,
+ debugfs_create_u32("gpio_val", 0600,
sc->debug.debugfs_phy, &sc->sc_ah->gpio_val);
- debugfs_create_file("antenna_diversity", S_IRUSR,
+ debugfs_create_file("antenna_diversity", 0400,
sc->debug.debugfs_phy, sc, &fops_antenna_diversity);
#ifdef CONFIG_ATH9K_BTCOEX_SUPPORT
- debugfs_create_file("bt_ant_diversity", S_IRUSR | S_IWUSR,
+ debugfs_create_file("bt_ant_diversity", 0600,
sc->debug.debugfs_phy, sc, &fops_bt_ant_diversity);
- debugfs_create_file("btcoex", S_IRUSR, sc->debug.debugfs_phy, sc,
+ debugfs_create_file("btcoex", 0400, sc->debug.debugfs_phy, sc,
&fops_btcoex);
#endif
#ifdef CONFIG_ATH9K_WOW
- debugfs_create_file("wow", S_IRUSR | S_IWUSR,
- sc->debug.debugfs_phy, sc, &fops_wow);
+ debugfs_create_file("wow", 0600, sc->debug.debugfs_phy, sc, &fops_wow);
#endif
#ifdef CONFIG_ATH9K_DYNACK
- debugfs_create_file("ack_to", S_IRUSR, sc->debug.debugfs_phy,
+ debugfs_create_file("ack_to", 0400, sc->debug.debugfs_phy,
sc, &fops_ackto);
#endif
- debugfs_create_file("tpc", S_IRUSR | S_IWUSR,
- sc->debug.debugfs_phy, sc, &fops_tpc);
+ debugfs_create_file("tpc", 0600, sc->debug.debugfs_phy, sc, &fops_tpc);
- debugfs_create_u16("airtime_flags", S_IRUSR | S_IWUSR,
+ debugfs_create_u16("airtime_flags", 0600,
sc->debug.debugfs_phy, &sc->airtime_flags);
- debugfs_create_file("nf_override", S_IRUSR | S_IWUSR,
+ debugfs_create_file("nf_override", 0600,
sc->debug.debugfs_phy, sc, &fops_nf_override);
return 0;
diff --git a/drivers/net/wireless/ath/ath9k/debug_sta.c b/drivers/net/wireless/ath/ath9k/debug_sta.c
index efc692ee67d4..a6f45f1bb5bb 100644
--- a/drivers/net/wireless/ath/ath9k/debug_sta.c
+++ b/drivers/net/wireless/ath/ath9k/debug_sta.c
@@ -302,7 +302,7 @@ void ath9k_sta_add_debugfs(struct ieee80211_hw *hw,
{
struct ath_node *an = (struct ath_node *)sta->drv_priv;
- debugfs_create_file("node_aggr", S_IRUGO, dir, an, &fops_node_aggr);
- debugfs_create_file("node_recv", S_IRUGO, dir, an, &fops_node_recv);
- debugfs_create_file("airtime", S_IRUGO, dir, an, &fops_airtime);
+ debugfs_create_file("node_aggr", 0444, dir, an, &fops_node_aggr);
+ debugfs_create_file("node_recv", 0444, dir, an, &fops_node_recv);
+ debugfs_create_file("airtime", 0444, dir, an, &fops_airtime);
}
diff --git a/drivers/net/wireless/ath/ath9k/dfs_debug.c b/drivers/net/wireless/ath/ath9k/dfs_debug.c
index 8824610c21fb..3251c9abe270 100644
--- a/drivers/net/wireless/ath/ath9k/dfs_debug.c
+++ b/drivers/net/wireless/ath/ath9k/dfs_debug.c
@@ -144,8 +144,8 @@ static const struct file_operations fops_dfs_stats = {
void ath9k_dfs_init_debug(struct ath_softc *sc)
{
- debugfs_create_file("dfs_stats", S_IRUSR,
+ debugfs_create_file("dfs_stats", 0400,
sc->debug.debugfs_phy, sc, &fops_dfs_stats);
- debugfs_create_file("dfs_simulate_radar", S_IWUSR,
+ debugfs_create_file("dfs_simulate_radar", 0200,
sc->debug.debugfs_phy, sc, &fops_simulate_radar);
}
diff --git a/drivers/net/wireless/ath/ath9k/htc_drv_debug.c b/drivers/net/wireless/ath/ath9k/htc_drv_debug.c
index dc79afd7e151..b3ed65e5c4da 100644
--- a/drivers/net/wireless/ath/ath9k/htc_drv_debug.c
+++ b/drivers/net/wireless/ath/ath9k/htc_drv_debug.c
@@ -496,25 +496,25 @@ int ath9k_htc_init_debug(struct ath_hw *ah)
ath9k_cmn_spectral_init_debug(&priv->spec_priv, priv->debug.debugfs_phy);
- debugfs_create_file("tgt_int_stats", S_IRUSR, priv->debug.debugfs_phy,
+ debugfs_create_file("tgt_int_stats", 0400, priv->debug.debugfs_phy,
priv, &fops_tgt_int_stats);
- debugfs_create_file("tgt_tx_stats", S_IRUSR, priv->debug.debugfs_phy,
+ debugfs_create_file("tgt_tx_stats", 0400, priv->debug.debugfs_phy,
priv, &fops_tgt_tx_stats);
- debugfs_create_file("tgt_rx_stats", S_IRUSR, priv->debug.debugfs_phy,
+ debugfs_create_file("tgt_rx_stats", 0400, priv->debug.debugfs_phy,
priv, &fops_tgt_rx_stats);
- debugfs_create_file("xmit", S_IRUSR, priv->debug.debugfs_phy,
+ debugfs_create_file("xmit", 0400, priv->debug.debugfs_phy,
priv, &fops_xmit);
- debugfs_create_file("skb_rx", S_IRUSR, priv->debug.debugfs_phy,
+ debugfs_create_file("skb_rx", 0400, priv->debug.debugfs_phy,
priv, &fops_skb_rx);
ath9k_cmn_debug_recv(priv->debug.debugfs_phy, &priv->debug.rx_stats);
ath9k_cmn_debug_phy_err(priv->debug.debugfs_phy, &priv->debug.rx_stats);
- debugfs_create_file("slot", S_IRUSR, priv->debug.debugfs_phy,
+ debugfs_create_file("slot", 0400, priv->debug.debugfs_phy,
priv, &fops_slot);
- debugfs_create_file("queue", S_IRUSR, priv->debug.debugfs_phy,
+ debugfs_create_file("queue", 0400, priv->debug.debugfs_phy,
priv, &fops_queue);
- debugfs_create_file("debug", S_IRUSR | S_IWUSR, priv->debug.debugfs_phy,
+ debugfs_create_file("debug", 0600, priv->debug.debugfs_phy,
priv, &fops_debug);
ath9k_cmn_debug_base_eeprom(priv->debug.debugfs_phy, priv->ah);
diff --git a/drivers/net/wireless/ath/ath9k/htc_drv_init.c b/drivers/net/wireless/ath/ath9k/htc_drv_init.c
index f246e9ed4a81..214c68269a69 100644
--- a/drivers/net/wireless/ath/ath9k/htc_drv_init.c
+++ b/drivers/net/wireless/ath/ath9k/htc_drv_init.c
@@ -591,7 +591,7 @@ static void ath9k_init_misc(struct ath9k_htc_priv *priv)
{
struct ath_common *common = ath9k_hw_common(priv->ah);
- memcpy(common->bssidmask, ath_bcast_mac, ETH_ALEN);
+ eth_broadcast_addr(common->bssidmask);
common->last_rssi = ATH_RSSI_DUMMY_MARKER;
priv->ah->opmode = NL80211_IFTYPE_STATION;
diff --git a/drivers/net/wireless/ath/ath9k/hw.c b/drivers/net/wireless/ath/ath9k/hw.c
index cd0f023ccf77..6b37036b2d36 100644
--- a/drivers/net/wireless/ath/ath9k/hw.c
+++ b/drivers/net/wireless/ath/ath9k/hw.c
@@ -184,7 +184,8 @@ u16 ath9k_hw_computetxtime(struct ath_hw *ah,
break;
case WLAN_RC_PHY_OFDM:
if (ah->curchan && IS_CHAN_QUARTER_RATE(ah->curchan)) {
- bitsPerSymbol = (kbps * OFDM_SYMBOL_TIME_QUARTER) / 1000;
+ bitsPerSymbol =
+ ((kbps >> 2) * OFDM_SYMBOL_TIME_QUARTER) / 1000;
numBits = OFDM_PLCP_BITS + (frameLen << 3);
numSymbols = DIV_ROUND_UP(numBits, bitsPerSymbol);
txTime = OFDM_SIFS_TIME_QUARTER
@@ -192,7 +193,8 @@ u16 ath9k_hw_computetxtime(struct ath_hw *ah,
+ (numSymbols * OFDM_SYMBOL_TIME_QUARTER);
} else if (ah->curchan &&
IS_CHAN_HALF_RATE(ah->curchan)) {
- bitsPerSymbol = (kbps * OFDM_SYMBOL_TIME_HALF) / 1000;
+ bitsPerSymbol =
+ ((kbps >> 1) * OFDM_SYMBOL_TIME_HALF) / 1000;
numBits = OFDM_PLCP_BITS + (frameLen << 3);
numSymbols = DIV_ROUND_UP(numBits, bitsPerSymbol);
txTime = OFDM_SIFS_TIME_HALF +
@@ -1036,7 +1038,7 @@ void ath9k_hw_init_global_settings(struct ath_hw *ah)
int acktimeout, ctstimeout, ack_offset = 0;
int slottime;
int sifstime;
- int rx_lat = 0, tx_lat = 0, eifs = 0;
+ int rx_lat = 0, tx_lat = 0, eifs = 0, ack_shift = 0;
u32 reg;
ath_dbg(ath9k_hw_common(ah), RESET, "ah->misc_mode 0x%x\n",
@@ -1068,6 +1070,7 @@ void ath9k_hw_init_global_settings(struct ath_hw *ah)
sifstime = 32;
ack_offset = 16;
+ ack_shift = 3;
slottime = 13;
} else if (IS_CHAN_QUARTER_RATE(chan)) {
eifs = 340;
@@ -1078,6 +1081,7 @@ void ath9k_hw_init_global_settings(struct ath_hw *ah)
sifstime = 64;
ack_offset = 32;
+ ack_shift = 1;
slottime = 21;
} else {
if (AR_SREV_9287(ah) && AR_SREV_9287_13_OR_LATER(ah)) {
@@ -1134,6 +1138,10 @@ void ath9k_hw_init_global_settings(struct ath_hw *ah)
SM(tx_lat, AR_USEC_TX_LAT),
AR_USEC_TX_LAT | AR_USEC_RX_LAT | AR_USEC_USEC);
+ if (IS_CHAN_HALF_RATE(chan) || IS_CHAN_QUARTER_RATE(chan))
+ REG_RMW(ah, AR_TXSIFS,
+ sifstime | SM(ack_shift, AR_TXSIFS_ACK_SHIFT),
+ (AR_TXSIFS_TIME | AR_TXSIFS_ACK_SHIFT));
}
EXPORT_SYMBOL(ath9k_hw_init_global_settings);
diff --git a/drivers/net/wireless/ath/ath9k/init.c b/drivers/net/wireless/ath/ath9k/init.c
index e479fae5aab9..c070a9e51ebf 100644
--- a/drivers/net/wireless/ath/ath9k/init.c
+++ b/drivers/net/wireless/ath/ath9k/init.c
@@ -257,6 +257,11 @@ static void ath9k_reg_notifier(struct wiphy *wiphy,
ath_reg_notifier_apply(wiphy, request, reg);
+ /* synchronize DFS detector if regulatory domain changed */
+ if (sc->dfs_detector != NULL)
+ sc->dfs_detector->set_dfs_domain(sc->dfs_detector,
+ request->dfs_region);
+
/* Set tx power */
if (!ah->curchan)
return;
@@ -267,10 +272,6 @@ static void ath9k_reg_notifier(struct wiphy *wiphy,
ath9k_cmn_update_txpow(ah, sc->cur_chan->cur_txpower,
sc->cur_chan->txpower,
&sc->cur_chan->cur_txpower);
- /* synchronize DFS detector if regulatory domain changed */
- if (sc->dfs_detector != NULL)
- sc->dfs_detector->set_dfs_domain(sc->dfs_detector,
- request->dfs_region);
ath9k_ps_restore(sc);
}
@@ -427,7 +428,7 @@ static void ath9k_init_misc(struct ath_softc *sc)
timer_setup(&common->ani.timer, ath_ani_calibrate, 0);
common->last_rssi = ATH_RSSI_DUMMY_MARKER;
- memcpy(common->bssidmask, ath_bcast_mac, ETH_ALEN);
+ eth_broadcast_addr(common->bssidmask);
sc->beacon.slottime = 9;
for (i = 0; i < ARRAY_SIZE(sc->beacon.bslot); i++)
diff --git a/drivers/net/wireless/ath/ath9k/tx99.c b/drivers/net/wireless/ath/ath9k/tx99.c
index fe3a8263b224..ce50d8f5835e 100644
--- a/drivers/net/wireless/ath/ath9k/tx99.c
+++ b/drivers/net/wireless/ath/ath9k/tx99.c
@@ -278,10 +278,10 @@ void ath9k_tx99_init_debug(struct ath_softc *sc)
if (!AR_SREV_9280_20_OR_LATER(sc->sc_ah))
return;
- debugfs_create_file("tx99", S_IRUSR | S_IWUSR,
+ debugfs_create_file("tx99", 0600,
sc->debug.debugfs_phy, sc,
&fops_tx99);
- debugfs_create_file("tx99_power", S_IRUSR | S_IWUSR,
+ debugfs_create_file("tx99_power", 0600,
sc->debug.debugfs_phy, sc,
&fops_tx99_power);
}
diff --git a/drivers/net/wireless/ath/ath9k/xmit.c b/drivers/net/wireless/ath/ath9k/xmit.c
index 396bf05c6bf6..d8b041f48ca8 100644
--- a/drivers/net/wireless/ath/ath9k/xmit.c
+++ b/drivers/net/wireless/ath/ath9k/xmit.c
@@ -2892,6 +2892,8 @@ void ath_tx_node_cleanup(struct ath_softc *sc, struct ath_node *an)
struct ath_txq *txq;
int tidno;
+ rcu_read_lock();
+
for (tidno = 0; tidno < IEEE80211_NUM_TIDS; tidno++) {
tid = ath_node_to_tid(an, tidno);
txq = tid->txq;
@@ -2909,6 +2911,8 @@ void ath_tx_node_cleanup(struct ath_softc *sc, struct ath_node *an)
if (!an->sta)
break; /* just one multicast ath_atx_tid */
}
+
+ rcu_read_unlock();
}
#ifdef CONFIG_ATH9K_TX99
diff --git a/drivers/net/wireless/ath/carl9170/debug.c b/drivers/net/wireless/ath/carl9170/debug.c
index ec3a64e5d2bb..a9b6dc17e408 100644
--- a/drivers/net/wireless/ath/carl9170/debug.c
+++ b/drivers/net/wireless/ath/carl9170/debug.c
@@ -187,21 +187,21 @@ static const struct carl9170_debugfs_fops carl_debugfs_##name ##_ops = {\
#define DEBUGFS_DECLARE_RO_FILE(name, _read_bufsize) \
DEBUGFS_DECLARE_FILE(name, carl9170_debugfs_##name ##_read, \
- NULL, _read_bufsize, S_IRUSR)
+ NULL, _read_bufsize, 0400)
#define DEBUGFS_DECLARE_WO_FILE(name) \
DEBUGFS_DECLARE_FILE(name, NULL, carl9170_debugfs_##name ##_write,\
- 0, S_IWUSR)
+ 0, 0200)
#define DEBUGFS_DECLARE_RW_FILE(name, _read_bufsize) \
DEBUGFS_DECLARE_FILE(name, carl9170_debugfs_##name ##_read, \
carl9170_debugfs_##name ##_write, \
- _read_bufsize, S_IRUSR | S_IWUSR)
+ _read_bufsize, 0600)
#define __DEBUGFS_DECLARE_RW_FILE(name, _read_bufsize, _dstate) \
__DEBUGFS_DECLARE_FILE(name, carl9170_debugfs_##name ##_read, \
carl9170_debugfs_##name ##_write, \
- _read_bufsize, S_IRUSR | S_IWUSR, _dstate)
+ _read_bufsize, 0600, _dstate)
#define DEBUGFS_READONLY_FILE(name, _read_bufsize, fmt, value...) \
static char *carl9170_debugfs_ ##name ## _read(struct ar9170 *ar, \
diff --git a/drivers/net/wireless/ath/carl9170/main.c b/drivers/net/wireless/ath/carl9170/main.c
index 988c8857d78c..29e93c953d93 100644
--- a/drivers/net/wireless/ath/carl9170/main.c
+++ b/drivers/net/wireless/ath/carl9170/main.c
@@ -48,11 +48,11 @@
#include "cmd.h"
static bool modparam_nohwcrypt;
-module_param_named(nohwcrypt, modparam_nohwcrypt, bool, S_IRUGO);
+module_param_named(nohwcrypt, modparam_nohwcrypt, bool, 0444);
MODULE_PARM_DESC(nohwcrypt, "Disable hardware crypto offload.");
int modparam_noht;
-module_param_named(noht, modparam_noht, int, S_IRUGO);
+module_param_named(noht, modparam_noht, int, 0444);
MODULE_PARM_DESC(noht, "Disable MPDU aggregation.");
#define RATE(_bitrate, _hw_rate, _txpidx, _flags) { \
diff --git a/drivers/net/wireless/ath/dfs_pattern_detector.c b/drivers/net/wireless/ath/dfs_pattern_detector.c
index 4100ffd42a43..448b83eea810 100644
--- a/drivers/net/wireless/ath/dfs_pattern_detector.c
+++ b/drivers/net/wireless/ath/dfs_pattern_detector.c
@@ -115,7 +115,7 @@ static const struct radar_detector_specs jp_radar_ref_types[] = {
JP_PATTERN(4, 0, 5, 150, 230, 1, 23, 50, false),
JP_PATTERN(5, 6, 10, 200, 500, 1, 16, 50, false),
JP_PATTERN(6, 11, 20, 200, 500, 1, 12, 50, false),
- JP_PATTERN(7, 50, 100, 1000, 2000, 1, 3, 50, false),
+ JP_PATTERN(7, 50, 100, 1000, 2000, 1, 3, 50, true),
JP_PATTERN(5, 0, 1, 333, 333, 1, 9, 50, false),
};
diff --git a/drivers/net/wireless/ath/wcn36xx/debug.c b/drivers/net/wireless/ath/wcn36xx/debug.c
index 2a6bb62e785c..389b5e7129a6 100644
--- a/drivers/net/wireless/ath/wcn36xx/debug.c
+++ b/drivers/net/wireless/ath/wcn36xx/debug.c
@@ -161,9 +161,8 @@ void wcn36xx_debugfs_init(struct wcn36xx *wcn)
dfs->rootdir = NULL;
}
- ADD_FILE(bmps_switcher, S_IRUSR | S_IWUSR,
- &fops_wcn36xx_bmps, wcn);
- ADD_FILE(dump, S_IWUSR, &fops_wcn36xx_dump, wcn);
+ ADD_FILE(bmps_switcher, 0600, &fops_wcn36xx_bmps, wcn);
+ ADD_FILE(dump, 0200, &fops_wcn36xx_dump, wcn);
}
void wcn36xx_debugfs_exit(struct wcn36xx *wcn)
diff --git a/drivers/net/wireless/ath/wcn36xx/dxe.c b/drivers/net/wireless/ath/wcn36xx/dxe.c
index a3f1f7d042a4..2c3b899a88fa 100644
--- a/drivers/net/wireless/ath/wcn36xx/dxe.c
+++ b/drivers/net/wireless/ath/wcn36xx/dxe.c
@@ -27,15 +27,6 @@
#include "wcn36xx.h"
#include "txrx.h"
-void *wcn36xx_dxe_get_next_bd(struct wcn36xx *wcn, bool is_low)
-{
- struct wcn36xx_dxe_ch *ch = is_low ?
- &wcn->dxe_tx_l_ch :
- &wcn->dxe_tx_h_ch;
-
- return ch->head_blk_ctl->bd_cpu_addr;
-}
-
static void wcn36xx_ccu_write_register(struct wcn36xx *wcn, int addr, int data)
{
wcn36xx_dbg(WCN36XX_DBG_DXE,
@@ -376,7 +367,7 @@ static void reap_tx_dxes(struct wcn36xx *wcn, struct wcn36xx_dxe_ch *ch)
spin_lock_irqsave(&ch->lock, flags);
ctl = ch->tail_blk_ctl;
do {
- if (ctl->desc->ctrl & WCN36XX_DXE_CTRL_VALID_MASK)
+ if (ctl->desc->ctrl & WCN36xx_DXE_CTRL_VLD)
break;
if (ctl->skb) {
dma_unmap_single(wcn->dev, ctl->desc->src_addr_l,
@@ -397,7 +388,7 @@ static void reap_tx_dxes(struct wcn36xx *wcn, struct wcn36xx_dxe_ch *ch)
}
ctl = ctl->next;
} while (ctl != ch->head_blk_ctl &&
- !(ctl->desc->ctrl & WCN36XX_DXE_CTRL_VALID_MASK));
+ !(ctl->desc->ctrl & WCN36xx_DXE_CTRL_VLD));
ch->tail_blk_ctl = ctl;
spin_unlock_irqrestore(&ch->lock, flags);
@@ -415,14 +406,31 @@ static irqreturn_t wcn36xx_irq_tx_complete(int irq, void *dev)
WCN36XX_DXE_CH_STATUS_REG_ADDR_TX_H,
&int_reason);
- /* TODO: Check int_reason */
-
wcn36xx_dxe_write_register(wcn,
WCN36XX_DXE_0_INT_CLR,
WCN36XX_INT_MASK_CHAN_TX_H);
- wcn36xx_dxe_write_register(wcn, WCN36XX_DXE_0_INT_ED_CLR,
- WCN36XX_INT_MASK_CHAN_TX_H);
+ if (int_reason & WCN36XX_CH_STAT_INT_ERR_MASK ) {
+ wcn36xx_dxe_write_register(wcn,
+ WCN36XX_DXE_0_INT_ERR_CLR,
+ WCN36XX_INT_MASK_CHAN_TX_H);
+
+ wcn36xx_err("DXE IRQ reported error: 0x%x in high TX channel\n",
+ int_src);
+ }
+
+ if (int_reason & WCN36XX_CH_STAT_INT_DONE_MASK) {
+ wcn36xx_dxe_write_register(wcn,
+ WCN36XX_DXE_0_INT_DONE_CLR,
+ WCN36XX_INT_MASK_CHAN_TX_H);
+ }
+
+ if (int_reason & WCN36XX_CH_STAT_INT_ED_MASK) {
+ wcn36xx_dxe_write_register(wcn,
+ WCN36XX_DXE_0_INT_ED_CLR,
+ WCN36XX_INT_MASK_CHAN_TX_H);
+ }
+
wcn36xx_dbg(WCN36XX_DBG_DXE, "dxe tx ready high\n");
reap_tx_dxes(wcn, &wcn->dxe_tx_h_ch);
}
@@ -431,14 +439,33 @@ static irqreturn_t wcn36xx_irq_tx_complete(int irq, void *dev)
wcn36xx_dxe_read_register(wcn,
WCN36XX_DXE_CH_STATUS_REG_ADDR_TX_L,
&int_reason);
- /* TODO: Check int_reason */
wcn36xx_dxe_write_register(wcn,
WCN36XX_DXE_0_INT_CLR,
WCN36XX_INT_MASK_CHAN_TX_L);
- wcn36xx_dxe_write_register(wcn, WCN36XX_DXE_0_INT_ED_CLR,
- WCN36XX_INT_MASK_CHAN_TX_L);
+
+ if (int_reason & WCN36XX_CH_STAT_INT_ERR_MASK ) {
+ wcn36xx_dxe_write_register(wcn,
+ WCN36XX_DXE_0_INT_ERR_CLR,
+ WCN36XX_INT_MASK_CHAN_TX_L);
+
+ wcn36xx_err("DXE IRQ reported error: 0x%x in low TX channel\n",
+ int_src);
+ }
+
+ if (int_reason & WCN36XX_CH_STAT_INT_DONE_MASK) {
+ wcn36xx_dxe_write_register(wcn,
+ WCN36XX_DXE_0_INT_DONE_CLR,
+ WCN36XX_INT_MASK_CHAN_TX_L);
+ }
+
+ if (int_reason & WCN36XX_CH_STAT_INT_ED_MASK) {
+ wcn36xx_dxe_write_register(wcn,
+ WCN36XX_DXE_0_INT_ED_CLR,
+ WCN36XX_INT_MASK_CHAN_TX_L);
+ }
+
wcn36xx_dbg(WCN36XX_DBG_DXE, "dxe tx ready low\n");
reap_tx_dxes(wcn, &wcn->dxe_tx_l_ch);
}
@@ -503,7 +530,7 @@ static int wcn36xx_rx_handle_packets(struct wcn36xx *wcn,
int_mask = WCN36XX_DXE_INT_CH3_MASK;
}
- while (!(dxe->ctrl & WCN36XX_DXE_CTRL_VALID_MASK)) {
+ while (!(dxe->ctrl & WCN36xx_DXE_CTRL_VLD)) {
skb = ctl->skb;
dma_addr = dxe->dst_addr_l;
ret = wcn36xx_dxe_fill_skb(wcn->dev, ctl);
@@ -612,6 +639,7 @@ void wcn36xx_dxe_free_mem_pools(struct wcn36xx *wcn)
int wcn36xx_dxe_tx_frame(struct wcn36xx *wcn,
struct wcn36xx_vif *vif_priv,
+ struct wcn36xx_tx_bd *bd,
struct sk_buff *skb,
bool is_low)
{
@@ -645,6 +673,9 @@ int wcn36xx_dxe_tx_frame(struct wcn36xx *wcn,
ctl->skb = NULL;
desc = ctl->desc;
+ /* write buffer descriptor */
+ memcpy(ctl->bd_cpu_addr, bd, sizeof(*bd));
+
/* Set source address of the BD we send */
desc->src_addr_l = ctl->bd_phy_addr;
diff --git a/drivers/net/wireless/ath/wcn36xx/dxe.h b/drivers/net/wireless/ath/wcn36xx/dxe.h
index c012e807753b..ce580960d109 100644
--- a/drivers/net/wireless/ath/wcn36xx/dxe.h
+++ b/drivers/net/wireless/ath/wcn36xx/dxe.h
@@ -33,15 +33,106 @@ H2H_TEST_RX_TX = DMA2
#define WCN36XX_CCU_DXE_INT_SELECT_RIVA 0x310
#define WCN36XX_CCU_DXE_INT_SELECT_PRONTO 0x10dc
-/* TODO This must calculated properly but not hardcoded */
-#define WCN36XX_DXE_CTRL_TX_L 0x328a44
-#define WCN36XX_DXE_CTRL_TX_H 0x32ce44
-#define WCN36XX_DXE_CTRL_RX_L 0x12ad2f
-#define WCN36XX_DXE_CTRL_RX_H 0x12d12f
-#define WCN36XX_DXE_CTRL_TX_H_BD 0x30ce45
-#define WCN36XX_DXE_CTRL_TX_H_SKB 0x32ce4d
-#define WCN36XX_DXE_CTRL_TX_L_BD 0x308a45
-#define WCN36XX_DXE_CTRL_TX_L_SKB 0x328a4d
+/* Descriptor valid */
+#define WCN36xx_DXE_CTRL_VLD BIT(0)
+/* End of packet */
+#define WCN36xx_DXE_CTRL_EOP BIT(3)
+/* BD handling bit */
+#define WCN36xx_DXE_CTRL_BDH BIT(4)
+/* Source is a queue */
+#define WCN36xx_DXE_CTRL_SIQ BIT(5)
+/* Destination is a queue */
+#define WCN36xx_DXE_CTRL_DIQ BIT(6)
+/* Pointer address is a queue */
+#define WCN36xx_DXE_CTRL_PIQ BIT(7)
+/* Release PDU when done */
+#define WCN36xx_DXE_CTRL_PDU_REL BIT(8)
+/* STOP channel processing */
+#define WCN36xx_DXE_CTRL_STOP BIT(16)
+/* INT on descriptor done */
+#define WCN36xx_DXE_CTRL_INT BIT(17)
+/* Endian byte swap enable */
+#define WCN36xx_DXE_CTRL_SWAP BIT(20)
+/* Master endianness */
+#define WCN36xx_DXE_CTRL_ENDIANNESS BIT(21)
+
+/* Transfer type */
+#define WCN36xx_DXE_CTRL_XTYPE_SHIFT 1
+#define WCN36xx_DXE_CTRL_XTYPE_MASK GENMASK(2, WCN36xx_DXE_CTRL_XTYPE_SHIFT)
+#define WCN36xx_DXE_CTRL_XTYPE_SET(x) ((x) << WCN36xx_DXE_CTRL_XTYPE_SHIFT)
+
+/* BMU Threshold select */
+#define WCN36xx_DXE_CTRL_BTHLD_SEL_SHIFT 9
+#define WCN36xx_DXE_CTRL_BTHLD_SEL_MASK GENMASK(12, WCN36xx_DXE_CTRL_BTHLD_SEL_SHIFT)
+#define WCN36xx_DXE_CTRL_BTHLD_SEL_SET(x) ((x) << WCN36xx_DXE_CTRL_BTHLD_SEL_SHIFT)
+
+/* Priority */
+#define WCN36xx_DXE_CTRL_PRIO_SHIFT 13
+#define WCN36xx_DXE_CTRL_PRIO_MASK GENMASK(15, WCN36xx_DXE_CTRL_PRIO_SHIFT)
+#define WCN36xx_DXE_CTRL_PRIO_SET(x) ((x) << WCN36xx_DXE_CTRL_PRIO_SHIFT)
+
+/* BD Template index */
+#define WCN36xx_DXE_CTRL_BDT_IDX_SHIFT 18
+#define WCN36xx_DXE_CTRL_BDT_IDX_MASK GENMASK(19, WCN36xx_DXE_CTRL_BDT_IDX_SHIFT)
+#define WCN36xx_DXE_CTRL_BDT_IDX_SET(x) ((x) << WCN36xx_DXE_CTRL_BDT_IDX_SHIFT)
+
+/* Transfer types: */
+/* Host to host */
+#define WCN36xx_DXE_XTYPE_H2H (0)
+/* Host to BMU */
+#define WCN36xx_DXE_XTYPE_H2B (2)
+/* BMU to host */
+#define WCN36xx_DXE_XTYPE_B2H (3)
+
+#define WCN36XX_DXE_CTRL_TX_L (WCN36xx_DXE_CTRL_XTYPE_SET(WCN36xx_DXE_XTYPE_H2B) | \
+ WCN36xx_DXE_CTRL_DIQ | WCN36xx_DXE_CTRL_BTHLD_SEL_SET(5) | \
+ WCN36xx_DXE_CTRL_PRIO_SET(4) | WCN36xx_DXE_CTRL_INT | \
+ WCN36xx_DXE_CTRL_SWAP | WCN36xx_DXE_CTRL_ENDIANNESS)
+
+#define WCN36XX_DXE_CTRL_TX_H (WCN36xx_DXE_CTRL_XTYPE_SET(WCN36xx_DXE_XTYPE_H2B) | \
+ WCN36xx_DXE_CTRL_DIQ | WCN36xx_DXE_CTRL_BTHLD_SEL_SET(7) | \
+ WCN36xx_DXE_CTRL_PRIO_SET(6) | WCN36xx_DXE_CTRL_INT | \
+ WCN36xx_DXE_CTRL_SWAP | WCN36xx_DXE_CTRL_ENDIANNESS)
+
+#define WCN36XX_DXE_CTRL_RX_L (WCN36xx_DXE_CTRL_VLD | \
+ WCN36xx_DXE_CTRL_XTYPE_SET(WCN36xx_DXE_XTYPE_B2H) | \
+ WCN36xx_DXE_CTRL_EOP | WCN36xx_DXE_CTRL_SIQ | \
+ WCN36xx_DXE_CTRL_PDU_REL | WCN36xx_DXE_CTRL_BTHLD_SEL_SET(6) | \
+ WCN36xx_DXE_CTRL_PRIO_SET(5) | WCN36xx_DXE_CTRL_INT | \
+ WCN36xx_DXE_CTRL_SWAP)
+
+#define WCN36XX_DXE_CTRL_RX_H (WCN36xx_DXE_CTRL_VLD | \
+ WCN36xx_DXE_CTRL_XTYPE_SET(WCN36xx_DXE_XTYPE_B2H) | \
+ WCN36xx_DXE_CTRL_EOP | WCN36xx_DXE_CTRL_SIQ | \
+ WCN36xx_DXE_CTRL_PDU_REL | WCN36xx_DXE_CTRL_BTHLD_SEL_SET(8) | \
+ WCN36xx_DXE_CTRL_PRIO_SET(6) | WCN36xx_DXE_CTRL_INT | \
+ WCN36xx_DXE_CTRL_SWAP)
+
+#define WCN36XX_DXE_CTRL_TX_H_BD (WCN36xx_DXE_CTRL_VLD | \
+ WCN36xx_DXE_CTRL_XTYPE_SET(WCN36xx_DXE_XTYPE_H2B) | \
+ WCN36xx_DXE_CTRL_DIQ | WCN36xx_DXE_CTRL_BTHLD_SEL_SET(7) | \
+ WCN36xx_DXE_CTRL_PRIO_SET(6) | WCN36xx_DXE_CTRL_SWAP | \
+ WCN36xx_DXE_CTRL_ENDIANNESS)
+
+#define WCN36XX_DXE_CTRL_TX_H_SKB (WCN36xx_DXE_CTRL_VLD | \
+ WCN36xx_DXE_CTRL_XTYPE_SET(WCN36xx_DXE_XTYPE_H2B) | \
+ WCN36xx_DXE_CTRL_EOP | WCN36xx_DXE_CTRL_DIQ | \
+ WCN36xx_DXE_CTRL_BTHLD_SEL_SET(7) | WCN36xx_DXE_CTRL_PRIO_SET(6) | \
+ WCN36xx_DXE_CTRL_INT | WCN36xx_DXE_CTRL_SWAP | \
+ WCN36xx_DXE_CTRL_ENDIANNESS)
+
+#define WCN36XX_DXE_CTRL_TX_L_BD (WCN36xx_DXE_CTRL_VLD | \
+ WCN36xx_DXE_CTRL_XTYPE_SET(WCN36xx_DXE_XTYPE_H2B) | \
+ WCN36xx_DXE_CTRL_DIQ | WCN36xx_DXE_CTRL_BTHLD_SEL_SET(5) | \
+ WCN36xx_DXE_CTRL_PRIO_SET(4) | WCN36xx_DXE_CTRL_SWAP | \
+ WCN36xx_DXE_CTRL_ENDIANNESS)
+
+#define WCN36XX_DXE_CTRL_TX_L_SKB (WCN36xx_DXE_CTRL_VLD | \
+ WCN36xx_DXE_CTRL_XTYPE_SET(WCN36xx_DXE_XTYPE_H2B) | \
+ WCN36xx_DXE_CTRL_EOP | WCN36xx_DXE_CTRL_DIQ | \
+ WCN36xx_DXE_CTRL_BTHLD_SEL_SET(5) | WCN36xx_DXE_CTRL_PRIO_SET(4) | \
+ WCN36xx_DXE_CTRL_INT | WCN36xx_DXE_CTRL_SWAP | \
+ WCN36xx_DXE_CTRL_ENDIANNESS)
/* TODO This must calculated properly but not hardcoded */
#define WCN36XX_DXE_WQ_TX_L 0x17
@@ -49,15 +140,106 @@ H2H_TEST_RX_TX = DMA2
#define WCN36XX_DXE_WQ_RX_L 0xB
#define WCN36XX_DXE_WQ_RX_H 0x4
-/* DXE descriptor control filed */
-#define WCN36XX_DXE_CTRL_VALID_MASK (0x00000001)
+/* Channel enable or restart */
+#define WCN36xx_DXE_CH_CTRL_EN BIT(0)
+/* End of packet bit */
+#define WCN36xx_DXE_CH_CTRL_EOP BIT(3)
+/* BD Handling bit */
+#define WCN36xx_DXE_CH_CTRL_BDH BIT(4)
+/* Source is queue */
+#define WCN36xx_DXE_CH_CTRL_SIQ BIT(5)
+/* Destination is queue */
+#define WCN36xx_DXE_CH_CTRL_DIQ BIT(6)
+/* Pointer descriptor is queue */
+#define WCN36xx_DXE_CH_CTRL_PIQ BIT(7)
+/* Relase PDU when done */
+#define WCN36xx_DXE_CH_CTRL_PDU_REL BIT(8)
+/* Stop channel processing */
+#define WCN36xx_DXE_CH_CTRL_STOP BIT(16)
+/* Enable external descriptor interrupt */
+#define WCN36xx_DXE_CH_CTRL_INE_ED BIT(17)
+/* Enable channel interrupt on errors */
+#define WCN36xx_DXE_CH_CTRL_INE_ERR BIT(18)
+/* Enable Channel interrupt when done */
+#define WCN36xx_DXE_CH_CTRL_INE_DONE BIT(19)
+/* External descriptor enable */
+#define WCN36xx_DXE_CH_CTRL_EDEN BIT(20)
+/* Wait for valid bit */
+#define WCN36xx_DXE_CH_CTRL_EDVEN BIT(21)
+/* Endianness is little endian*/
+#define WCN36xx_DXE_CH_CTRL_ENDIANNESS BIT(26)
+/* Abort transfer */
+#define WCN36xx_DXE_CH_CTRL_ABORT BIT(27)
+/* Long descriptor format */
+#define WCN36xx_DXE_CH_CTRL_DFMT BIT(28)
+/* Endian byte swap enable */
+#define WCN36xx_DXE_CH_CTRL_SWAP BIT(31)
+
+/* Transfer type */
+#define WCN36xx_DXE_CH_CTRL_XTYPE_SHIFT 1
+#define WCN36xx_DXE_CH_CTRL_XTYPE_MASK GENMASK(2, WCN36xx_DXE_CH_CTRL_XTYPE_SHIFT)
+#define WCN36xx_DXE_CH_CTRL_XTYPE_SET(x) ((x) << WCN36xx_DXE_CH_CTRL_XTYPE_SHIFT)
+
+/* Channel BMU Threshold select */
+#define WCN36xx_DXE_CH_CTRL_BTHLD_SEL_SHIFT 9
+#define WCN36xx_DXE_CH_CTRL_BTHLD_SEL_MASK GENMASK(12, WCN36xx_DXE_CH_CTRL_BTHLD_SEL_SHIFT)
+#define WCN36xx_DXE_CH_CTRL_BTHLD_SEL_SET(x) ((x) << WCN36xx_DXE_CH_CTRL_BTHLD_SEL_SHIFT)
+
+/* Channel Priority */
+#define WCN36xx_DXE_CH_CTRL_PRIO_SHIFT 13
+#define WCN36xx_DXE_CH_CTRL_PRIO_MASK GENMASK(15, WCN36xx_DXE_CH_CTRL_PRIO_SHIFT)
+#define WCN36xx_DXE_CH_CTRL_PRIO_SET(x) ((x) << WCN36xx_DXE_CH_CTRL_PRIO_SHIFT)
+
+/* Counter select */
+#define WCN36xx_DXE_CH_CTRL_SEL_SHIFT 22
+#define WCN36xx_DXE_CH_CTRL_SEL_MASK GENMASK(25, WCN36xx_DXE_CH_CTRL_SEL_SHIFT)
+#define WCN36xx_DXE_CH_CTRL_SEL_SET(x) ((x) << WCN36xx_DXE_CH_CTRL_SEL_SHIFT)
+
+/* Channel BD template index */
+#define WCN36xx_DXE_CH_CTRL_BDT_IDX_SHIFT 29
+#define WCN36xx_DXE_CH_CTRL_BDT_IDX_MASK GENMASK(30, WCN36xx_DXE_CH_CTRL_BDT_IDX_SHIFT)
+#define WCN36xx_DXE_CH_CTRL_BDT_IDX_SET(x) ((x) << WCN36xx_DXE_CH_CTRL_BDT_IDX_SHIFT)
-/* TODO This must calculated properly but not hardcoded */
/* DXE default control register values */
-#define WCN36XX_DXE_CH_DEFAULT_CTL_RX_L 0x847EAD2F
-#define WCN36XX_DXE_CH_DEFAULT_CTL_RX_H 0x84FED12F
-#define WCN36XX_DXE_CH_DEFAULT_CTL_TX_H 0x853ECF4D
-#define WCN36XX_DXE_CH_DEFAULT_CTL_TX_L 0x843e8b4d
+#define WCN36XX_DXE_CH_DEFAULT_CTL_RX_L (WCN36xx_DXE_CH_CTRL_EN | \
+ WCN36xx_DXE_CH_CTRL_XTYPE_SET(WCN36xx_DXE_XTYPE_B2H) | \
+ WCN36xx_DXE_CH_CTRL_EOP | WCN36xx_DXE_CH_CTRL_SIQ | \
+ WCN36xx_DXE_CH_CTRL_PDU_REL | WCN36xx_DXE_CH_CTRL_BTHLD_SEL_SET(6) | \
+ WCN36xx_DXE_CH_CTRL_PRIO_SET(5) | WCN36xx_DXE_CH_CTRL_INE_ED | \
+ WCN36xx_DXE_CH_CTRL_INE_ERR | WCN36xx_DXE_CH_CTRL_INE_DONE | \
+ WCN36xx_DXE_CH_CTRL_EDEN | WCN36xx_DXE_CH_CTRL_EDVEN | \
+ WCN36xx_DXE_CH_CTRL_SEL_SET(1) | WCN36xx_DXE_CH_CTRL_ENDIANNESS | \
+ WCN36xx_DXE_CH_CTRL_SWAP)
+
+#define WCN36XX_DXE_CH_DEFAULT_CTL_RX_H (WCN36xx_DXE_CH_CTRL_EN | \
+ WCN36xx_DXE_CH_CTRL_XTYPE_SET(WCN36xx_DXE_XTYPE_B2H) | \
+ WCN36xx_DXE_CH_CTRL_EOP | WCN36xx_DXE_CH_CTRL_SIQ | \
+ WCN36xx_DXE_CH_CTRL_PDU_REL | WCN36xx_DXE_CH_CTRL_BTHLD_SEL_SET(8) | \
+ WCN36xx_DXE_CH_CTRL_PRIO_SET(6) | WCN36xx_DXE_CH_CTRL_INE_ED | \
+ WCN36xx_DXE_CH_CTRL_INE_ERR | WCN36xx_DXE_CH_CTRL_INE_DONE | \
+ WCN36xx_DXE_CH_CTRL_EDEN | WCN36xx_DXE_CH_CTRL_EDVEN | \
+ WCN36xx_DXE_CH_CTRL_SEL_SET(3) | WCN36xx_DXE_CH_CTRL_ENDIANNESS | \
+ WCN36xx_DXE_CH_CTRL_SWAP)
+
+#define WCN36XX_DXE_CH_DEFAULT_CTL_TX_H (WCN36xx_DXE_CH_CTRL_EN | \
+ WCN36xx_DXE_CH_CTRL_XTYPE_SET(WCN36xx_DXE_XTYPE_H2B) | \
+ WCN36xx_DXE_CH_CTRL_EOP | WCN36xx_DXE_CH_CTRL_DIQ | \
+ WCN36xx_DXE_CH_CTRL_PDU_REL | WCN36xx_DXE_CH_CTRL_BTHLD_SEL_SET(7) | \
+ WCN36xx_DXE_CH_CTRL_PRIO_SET(6) | WCN36xx_DXE_CH_CTRL_INE_ED | \
+ WCN36xx_DXE_CH_CTRL_INE_ERR | WCN36xx_DXE_CH_CTRL_INE_DONE | \
+ WCN36xx_DXE_CH_CTRL_EDEN | WCN36xx_DXE_CH_CTRL_EDVEN | \
+ WCN36xx_DXE_CH_CTRL_SEL_SET(4) | WCN36xx_DXE_CH_CTRL_ENDIANNESS | \
+ WCN36xx_DXE_CH_CTRL_SWAP)
+
+#define WCN36XX_DXE_CH_DEFAULT_CTL_TX_L (WCN36xx_DXE_CH_CTRL_EN | \
+ WCN36xx_DXE_CH_CTRL_XTYPE_SET(WCN36xx_DXE_XTYPE_H2B) | \
+ WCN36xx_DXE_CH_CTRL_EOP | WCN36xx_DXE_CH_CTRL_DIQ | \
+ WCN36xx_DXE_CH_CTRL_PDU_REL | WCN36xx_DXE_CH_CTRL_BTHLD_SEL_SET(5) | \
+ WCN36xx_DXE_CH_CTRL_PRIO_SET(4) | WCN36xx_DXE_CH_CTRL_INE_ED | \
+ WCN36xx_DXE_CH_CTRL_INE_ERR | WCN36xx_DXE_CH_CTRL_INE_DONE | \
+ WCN36xx_DXE_CH_CTRL_EDEN | WCN36xx_DXE_CH_CTRL_EDVEN | \
+ WCN36xx_DXE_CH_CTRL_SEL_SET(0) | WCN36xx_DXE_CH_CTRL_ENDIANNESS | \
+ WCN36xx_DXE_CH_CTRL_SWAP)
/* Common DXE registers */
#define WCN36XX_DXE_MEM_CSR (WCN36XX_DXE_MEM_REG + 0x00)
@@ -80,6 +262,10 @@ H2H_TEST_RX_TX = DMA2
#define WCN36XX_DXE_0_INT_DONE_CLR (WCN36XX_DXE_MEM_REG + 0x38)
#define WCN36XX_DXE_0_INT_ERR_CLR (WCN36XX_DXE_MEM_REG + 0x3C)
+#define WCN36XX_CH_STAT_INT_DONE_MASK 0x00008000
+#define WCN36XX_CH_STAT_INT_ERR_MASK 0x00004000
+#define WCN36XX_CH_STAT_INT_ED_MASK 0x00002000
+
#define WCN36XX_DXE_0_CH0_STATUS (WCN36XX_DXE_MEM_REG + 0x404)
#define WCN36XX_DXE_0_CH1_STATUS (WCN36XX_DXE_MEM_REG + 0x444)
#define WCN36XX_DXE_0_CH2_STATUS (WCN36XX_DXE_MEM_REG + 0x484)
@@ -266,6 +452,7 @@ struct wcn36xx_dxe_mem_pool {
dma_addr_t phy_addr;
};
+struct wcn36xx_tx_bd;
struct wcn36xx_vif;
int wcn36xx_dxe_allocate_mem_pools(struct wcn36xx *wcn);
void wcn36xx_dxe_free_mem_pools(struct wcn36xx *wcn);
@@ -277,8 +464,8 @@ void wcn36xx_dxe_deinit(struct wcn36xx *wcn);
int wcn36xx_dxe_init_channels(struct wcn36xx *wcn);
int wcn36xx_dxe_tx_frame(struct wcn36xx *wcn,
struct wcn36xx_vif *vif_priv,
+ struct wcn36xx_tx_bd *bd,
struct sk_buff *skb,
bool is_low);
void wcn36xx_dxe_tx_ack_ind(struct wcn36xx *wcn, u32 status);
-void *wcn36xx_dxe_get_next_bd(struct wcn36xx *wcn, bool is_low);
#endif /* _DXE_H_ */
diff --git a/drivers/net/wireless/ath/wcn36xx/main.c b/drivers/net/wireless/ath/wcn36xx/main.c
index ab5be6d2c691..69d6be59d97f 100644
--- a/drivers/net/wireless/ath/wcn36xx/main.c
+++ b/drivers/net/wireless/ath/wcn36xx/main.c
@@ -261,7 +261,7 @@ static void wcn36xx_feat_caps_info(struct wcn36xx *wcn)
for (i = 0; i < MAX_FEATURE_SUPPORTED; i++) {
if (get_feat_caps(wcn->fw_feat_caps, i))
- wcn36xx_info("FW Cap %s\n", wcn36xx_get_cap_name(i));
+ wcn36xx_dbg(WCN36XX_DBG_MAC, "FW Cap %s\n", wcn36xx_get_cap_name(i));
}
}
@@ -666,16 +666,13 @@ static void wcn36xx_cancel_hw_scan(struct ieee80211_hw *hw,
{
struct wcn36xx *wcn = hw->priv;
- if (!wcn36xx_smd_stop_hw_scan(wcn)) {
- struct cfg80211_scan_info scan_info = { .aborted = true };
-
- ieee80211_scan_completed(wcn->hw, &scan_info);
- }
-
mutex_lock(&wcn->scan_lock);
wcn->scan_aborted = true;
mutex_unlock(&wcn->scan_lock);
+ /* ieee80211_scan_completed will be called on FW scan indication */
+ wcn36xx_smd_stop_hw_scan(wcn);
+
cancel_work_sync(&wcn->scan_work);
}
@@ -1155,8 +1152,6 @@ static int wcn36xx_init_ieee80211(struct wcn36xx *wcn)
wcn->hw->wiphy->cipher_suites = cipher_suites;
wcn->hw->wiphy->n_cipher_suites = ARRAY_SIZE(cipher_suites);
- wcn->hw->wiphy->flags |= WIPHY_FLAG_AP_PROBE_RESP_OFFLOAD;
-
#ifdef CONFIG_PM
wcn->hw->wiphy->wowlan = &wowlan_support;
#endif
@@ -1283,6 +1278,7 @@ static int wcn36xx_probe(struct platform_device *pdev)
wcn = hw->priv;
wcn->hw = hw;
wcn->dev = &pdev->dev;
+ wcn->first_boot = true;
mutex_init(&wcn->conf_mutex);
mutex_init(&wcn->hal_mutex);
mutex_init(&wcn->scan_lock);
diff --git a/drivers/net/wireless/ath/wcn36xx/smd.c b/drivers/net/wireless/ath/wcn36xx/smd.c
index 2a4871ca9c72..8932af5e4d8d 100644
--- a/drivers/net/wireless/ath/wcn36xx/smd.c
+++ b/drivers/net/wireless/ath/wcn36xx/smd.c
@@ -409,15 +409,17 @@ static int wcn36xx_smd_start_rsp(struct wcn36xx *wcn, void *buf, size_t len)
wcn->fw_minor = rsp->start_rsp_params.version.minor;
wcn->fw_major = rsp->start_rsp_params.version.major;
- wcn36xx_info("firmware WLAN version '%s' and CRM version '%s'\n",
- wcn->wlan_version, wcn->crm_version);
-
- wcn36xx_info("firmware API %u.%u.%u.%u, %u stations, %u bssids\n",
- wcn->fw_major, wcn->fw_minor,
- wcn->fw_version, wcn->fw_revision,
- rsp->start_rsp_params.stations,
- rsp->start_rsp_params.bssids);
+ if (wcn->first_boot) {
+ wcn->first_boot = false;
+ wcn36xx_info("firmware WLAN version '%s' and CRM version '%s'\n",
+ wcn->wlan_version, wcn->crm_version);
+ wcn36xx_info("firmware API %u.%u.%u.%u, %u stations, %u bssids\n",
+ wcn->fw_major, wcn->fw_minor,
+ wcn->fw_version, wcn->fw_revision,
+ rsp->start_rsp_params.stations,
+ rsp->start_rsp_params.bssids);
+ }
return 0;
}
@@ -2138,6 +2140,8 @@ static int wcn36xx_smd_hw_scan_ind(struct wcn36xx *wcn, void *buf, size_t len)
case WCN36XX_HAL_SCAN_IND_COMPLETED:
mutex_lock(&wcn->scan_lock);
wcn->scan_req = NULL;
+ if (wcn->scan_aborted)
+ scan_info.aborted = true;
mutex_unlock(&wcn->scan_lock);
ieee80211_scan_completed(wcn->hw, &scan_info);
break;
@@ -2407,54 +2411,63 @@ static void wcn36xx_ind_smd_work(struct work_struct *work)
{
struct wcn36xx *wcn =
container_of(work, struct wcn36xx, hal_ind_work);
- struct wcn36xx_hal_msg_header *msg_header;
- struct wcn36xx_hal_ind_msg *hal_ind_msg;
- unsigned long flags;
- spin_lock_irqsave(&wcn->hal_ind_lock, flags);
+ for (;;) {
+ struct wcn36xx_hal_msg_header *msg_header;
+ struct wcn36xx_hal_ind_msg *hal_ind_msg;
+ unsigned long flags;
- hal_ind_msg = list_first_entry(&wcn->hal_ind_queue,
- struct wcn36xx_hal_ind_msg,
- list);
- list_del(wcn->hal_ind_queue.next);
- spin_unlock_irqrestore(&wcn->hal_ind_lock, flags);
+ spin_lock_irqsave(&wcn->hal_ind_lock, flags);
- msg_header = (struct wcn36xx_hal_msg_header *)hal_ind_msg->msg;
+ if (list_empty(&wcn->hal_ind_queue)) {
+ spin_unlock_irqrestore(&wcn->hal_ind_lock, flags);
+ return;
+ }
- switch (msg_header->msg_type) {
- case WCN36XX_HAL_COEX_IND:
- case WCN36XX_HAL_DEL_BA_IND:
- case WCN36XX_HAL_AVOID_FREQ_RANGE_IND:
- break;
- case WCN36XX_HAL_OTA_TX_COMPL_IND:
- wcn36xx_smd_tx_compl_ind(wcn,
- hal_ind_msg->msg,
- hal_ind_msg->msg_len);
- break;
- case WCN36XX_HAL_MISSED_BEACON_IND:
- wcn36xx_smd_missed_beacon_ind(wcn,
- hal_ind_msg->msg,
- hal_ind_msg->msg_len);
- break;
- case WCN36XX_HAL_DELETE_STA_CONTEXT_IND:
- wcn36xx_smd_delete_sta_context_ind(wcn,
- hal_ind_msg->msg,
- hal_ind_msg->msg_len);
- break;
- case WCN36XX_HAL_PRINT_REG_INFO_IND:
- wcn36xx_smd_print_reg_info_ind(wcn,
- hal_ind_msg->msg,
- hal_ind_msg->msg_len);
- break;
- case WCN36XX_HAL_SCAN_OFFLOAD_IND:
- wcn36xx_smd_hw_scan_ind(wcn, hal_ind_msg->msg,
- hal_ind_msg->msg_len);
- break;
- default:
- wcn36xx_err("SMD_EVENT (%d) not supported\n",
- msg_header->msg_type);
+ hal_ind_msg = list_first_entry(&wcn->hal_ind_queue,
+ struct wcn36xx_hal_ind_msg,
+ list);
+ list_del(&hal_ind_msg->list);
+ spin_unlock_irqrestore(&wcn->hal_ind_lock, flags);
+
+ msg_header = (struct wcn36xx_hal_msg_header *)hal_ind_msg->msg;
+
+ switch (msg_header->msg_type) {
+ case WCN36XX_HAL_COEX_IND:
+ case WCN36XX_HAL_DEL_BA_IND:
+ case WCN36XX_HAL_AVOID_FREQ_RANGE_IND:
+ break;
+ case WCN36XX_HAL_OTA_TX_COMPL_IND:
+ wcn36xx_smd_tx_compl_ind(wcn,
+ hal_ind_msg->msg,
+ hal_ind_msg->msg_len);
+ break;
+ case WCN36XX_HAL_MISSED_BEACON_IND:
+ wcn36xx_smd_missed_beacon_ind(wcn,
+ hal_ind_msg->msg,
+ hal_ind_msg->msg_len);
+ break;
+ case WCN36XX_HAL_DELETE_STA_CONTEXT_IND:
+ wcn36xx_smd_delete_sta_context_ind(wcn,
+ hal_ind_msg->msg,
+ hal_ind_msg->msg_len);
+ break;
+ case WCN36XX_HAL_PRINT_REG_INFO_IND:
+ wcn36xx_smd_print_reg_info_ind(wcn,
+ hal_ind_msg->msg,
+ hal_ind_msg->msg_len);
+ break;
+ case WCN36XX_HAL_SCAN_OFFLOAD_IND:
+ wcn36xx_smd_hw_scan_ind(wcn, hal_ind_msg->msg,
+ hal_ind_msg->msg_len);
+ break;
+ default:
+ wcn36xx_err("SMD_EVENT (%d) not supported\n",
+ msg_header->msg_type);
+ }
+
+ kfree(hal_ind_msg);
}
- kfree(hal_ind_msg);
}
int wcn36xx_smd_open(struct wcn36xx *wcn)
{
diff --git a/drivers/net/wireless/ath/wcn36xx/txrx.c b/drivers/net/wireless/ath/wcn36xx/txrx.c
index 22304edc5948..b1768ed6b0be 100644
--- a/drivers/net/wireless/ath/wcn36xx/txrx.c
+++ b/drivers/net/wireless/ath/wcn36xx/txrx.c
@@ -272,21 +272,9 @@ int wcn36xx_start_tx(struct wcn36xx *wcn,
bool is_low = ieee80211_is_data(hdr->frame_control);
bool bcast = is_broadcast_ether_addr(hdr->addr1) ||
is_multicast_ether_addr(hdr->addr1);
- struct wcn36xx_tx_bd *bd = wcn36xx_dxe_get_next_bd(wcn, is_low);
-
- if (!bd) {
- /*
- * TX DXE are used in pairs. One for the BD and one for the
- * actual frame. The BD DXE's has a preallocated buffer while
- * the skb ones does not. If this isn't true something is really
- * wierd. TODO: Recover from this situation
- */
-
- wcn36xx_err("bd address may not be NULL for BD DXE\n");
- return -EINVAL;
- }
+ struct wcn36xx_tx_bd bd;
- memset(bd, 0, sizeof(*bd));
+ memset(&bd, 0, sizeof(bd));
wcn36xx_dbg(WCN36XX_DBG_TX,
"tx skb %p len %d fc %04x sn %d %s %s\n",
@@ -296,10 +284,10 @@ int wcn36xx_start_tx(struct wcn36xx *wcn,
wcn36xx_dbg_dump(WCN36XX_DBG_TX_DUMP, "", skb->data, skb->len);
- bd->dpu_rf = WCN36XX_BMU_WQ_TX;
+ bd.dpu_rf = WCN36XX_BMU_WQ_TX;
- bd->tx_comp = !!(info->flags & IEEE80211_TX_CTL_REQ_TX_STATUS);
- if (bd->tx_comp) {
+ bd.tx_comp = !!(info->flags & IEEE80211_TX_CTL_REQ_TX_STATUS);
+ if (bd.tx_comp) {
wcn36xx_dbg(WCN36XX_DBG_DXE, "TX_ACK status requested\n");
spin_lock_irqsave(&wcn->dxe_lock, flags);
if (wcn->tx_ack_skb) {
@@ -321,13 +309,13 @@ int wcn36xx_start_tx(struct wcn36xx *wcn,
/* Data frames served first*/
if (is_low)
- wcn36xx_set_tx_data(bd, wcn, &vif_priv, sta_priv, skb, bcast);
+ wcn36xx_set_tx_data(&bd, wcn, &vif_priv, sta_priv, skb, bcast);
else
/* MGMT and CTRL frames are handeld here*/
- wcn36xx_set_tx_mgmt(bd, wcn, &vif_priv, skb, bcast);
+ wcn36xx_set_tx_mgmt(&bd, wcn, &vif_priv, skb, bcast);
- buff_to_be((u32 *)bd, sizeof(*bd)/sizeof(u32));
- bd->tx_bd_sign = 0xbdbdbdbd;
+ buff_to_be((u32 *)&bd, sizeof(bd)/sizeof(u32));
+ bd.tx_bd_sign = 0xbdbdbdbd;
- return wcn36xx_dxe_tx_frame(wcn, vif_priv, skb, is_low);
+ return wcn36xx_dxe_tx_frame(wcn, vif_priv, &bd, skb, is_low);
}
diff --git a/drivers/net/wireless/ath/wcn36xx/wcn36xx.h b/drivers/net/wireless/ath/wcn36xx/wcn36xx.h
index 81017e6703b4..5854adf43f3a 100644
--- a/drivers/net/wireless/ath/wcn36xx/wcn36xx.h
+++ b/drivers/net/wireless/ath/wcn36xx/wcn36xx.h
@@ -192,6 +192,8 @@ struct wcn36xx {
u8 crm_version[WCN36XX_HAL_VERSION_LENGTH + 1];
u8 wlan_version[WCN36XX_HAL_VERSION_LENGTH + 1];
+ bool first_boot;
+
/* IRQs */
int tx_irq;
int rx_irq;
diff --git a/drivers/net/wireless/ath/wil6210/cfg80211.c b/drivers/net/wireless/ath/wil6210/cfg80211.c
index b799a5384abb..cdbb393863f3 100644
--- a/drivers/net/wireless/ath/wil6210/cfg80211.c
+++ b/drivers/net/wireless/ath/wil6210/cfg80211.c
@@ -1,5 +1,6 @@
/*
* Copyright (c) 2012-2017 Qualcomm Atheros, Inc.
+ * Copyright (c) 2018, The Linux Foundation. All rights reserved.
*
* Permission to use, copy, modify, and/or distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
@@ -17,8 +18,10 @@
#include <linux/etherdevice.h>
#include <linux/moduleparam.h>
#include <net/netlink.h>
+#include <net/cfg80211.h>
#include "wil6210.h"
#include "wmi.h"
+#include "fw.h"
#define WIL_MAX_ROC_DURATION_MS 5000
@@ -258,9 +261,10 @@ int wil_iftype_nl2wmi(enum nl80211_iftype type)
return -EOPNOTSUPP;
}
-int wil_cid_fill_sinfo(struct wil6210_priv *wil, int cid,
+int wil_cid_fill_sinfo(struct wil6210_vif *vif, int cid,
struct station_info *sinfo)
{
+ struct wil6210_priv *wil = vif_to_wil(vif);
struct wmi_notify_req_cmd cmd = {
.cid = cid,
.interval_usec = 0,
@@ -272,17 +276,17 @@ int wil_cid_fill_sinfo(struct wil6210_priv *wil, int cid,
struct wil_net_stats *stats = &wil->sta[cid].stats;
int rc;
- rc = wmi_call(wil, WMI_NOTIFY_REQ_CMDID, &cmd, sizeof(cmd),
+ rc = wmi_call(wil, WMI_NOTIFY_REQ_CMDID, vif->mid, &cmd, sizeof(cmd),
WMI_NOTIFY_REQ_DONE_EVENTID, &reply, sizeof(reply), 20);
if (rc)
return rc;
- wil_dbg_wmi(wil, "Link status for CID %d: {\n"
+ wil_dbg_wmi(wil, "Link status for CID %d MID %d: {\n"
" MCS %d TSF 0x%016llx\n"
" BF status 0x%08x RSSI %d SQI %d%%\n"
" Tx Tpt %d goodput %d Rx goodput %d\n"
" Sectors(rx:tx) my %d:%d peer %d:%d\n""}\n",
- cid, le16_to_cpu(reply.evt.bf_mcs),
+ cid, vif->mid, le16_to_cpu(reply.evt.bf_mcs),
le64_to_cpu(reply.evt.tsf), reply.evt.status,
reply.evt.rssi,
reply.evt.sqi,
@@ -315,7 +319,7 @@ int wil_cid_fill_sinfo(struct wil6210_priv *wil, int cid,
sinfo->tx_packets = stats->tx_packets;
sinfo->tx_failed = stats->tx_errors;
- if (test_bit(wil_status_fwconnected, wil->status)) {
+ if (test_bit(wil_vif_fwconnected, vif->status)) {
sinfo->filled |= BIT(NL80211_STA_INFO_SIGNAL);
if (test_bit(WMI_FW_CAPABILITY_RSSI_REPORTING,
wil->fw_capabilities))
@@ -331,30 +335,34 @@ static int wil_cfg80211_get_station(struct wiphy *wiphy,
struct net_device *ndev,
const u8 *mac, struct station_info *sinfo)
{
+ struct wil6210_vif *vif = ndev_to_vif(ndev);
struct wil6210_priv *wil = wiphy_to_wil(wiphy);
int rc;
- int cid = wil_find_cid(wil, mac);
+ int cid = wil_find_cid(wil, vif->mid, mac);
- wil_dbg_misc(wil, "get_station: %pM CID %d\n", mac, cid);
+ wil_dbg_misc(wil, "get_station: %pM CID %d MID %d\n", mac, cid,
+ vif->mid);
if (cid < 0)
return cid;
- rc = wil_cid_fill_sinfo(wil, cid, sinfo);
+ rc = wil_cid_fill_sinfo(vif, cid, sinfo);
return rc;
}
/*
- * Find @idx-th active STA for station dump.
+ * Find @idx-th active STA for specific MID for station dump.
*/
-static int wil_find_cid_by_idx(struct wil6210_priv *wil, int idx)
+static int wil_find_cid_by_idx(struct wil6210_priv *wil, u8 mid, int idx)
{
int i;
for (i = 0; i < ARRAY_SIZE(wil->sta); i++) {
if (wil->sta[i].status == wil_sta_unused)
continue;
+ if (wil->sta[i].mid != mid)
+ continue;
if (idx == 0)
return i;
idx--;
@@ -367,17 +375,19 @@ static int wil_cfg80211_dump_station(struct wiphy *wiphy,
struct net_device *dev, int idx,
u8 *mac, struct station_info *sinfo)
{
+ struct wil6210_vif *vif = ndev_to_vif(dev);
struct wil6210_priv *wil = wiphy_to_wil(wiphy);
int rc;
- int cid = wil_find_cid_by_idx(wil, idx);
+ int cid = wil_find_cid_by_idx(wil, vif->mid, idx);
if (cid < 0)
return -ENOENT;
ether_addr_copy(mac, wil->sta[cid].addr);
- wil_dbg_misc(wil, "dump_station: %pM CID %d\n", mac, cid);
+ wil_dbg_misc(wil, "dump_station: %pM CID %d MID %d\n", mac, cid,
+ vif->mid);
- rc = wil_cid_fill_sinfo(wil, cid, sinfo);
+ rc = wil_cid_fill_sinfo(vif, cid, sinfo);
return rc;
}
@@ -388,7 +398,7 @@ static int wil_cfg80211_start_p2p_device(struct wiphy *wiphy,
struct wil6210_priv *wil = wiphy_to_wil(wiphy);
wil_dbg_misc(wil, "start_p2p_device: entered\n");
- wil->p2p.p2p_dev_started = 1;
+ wil->p2p_dev_started = 1;
return 0;
}
@@ -396,20 +406,66 @@ static void wil_cfg80211_stop_p2p_device(struct wiphy *wiphy,
struct wireless_dev *wdev)
{
struct wil6210_priv *wil = wiphy_to_wil(wiphy);
- struct wil_p2p_info *p2p = &wil->p2p;
- if (!p2p->p2p_dev_started)
+ if (!wil->p2p_dev_started)
return;
wil_dbg_misc(wil, "stop_p2p_device: entered\n");
mutex_lock(&wil->mutex);
- mutex_lock(&wil->p2p_wdev_mutex);
+ mutex_lock(&wil->vif_mutex);
wil_p2p_stop_radio_operations(wil);
- p2p->p2p_dev_started = 0;
- mutex_unlock(&wil->p2p_wdev_mutex);
+ wil->p2p_dev_started = 0;
+ mutex_unlock(&wil->vif_mutex);
mutex_unlock(&wil->mutex);
}
+static int wil_cfg80211_validate_add_iface(struct wil6210_priv *wil,
+ enum nl80211_iftype new_type)
+{
+ int i;
+ struct wireless_dev *wdev;
+ struct iface_combination_params params = {
+ .num_different_channels = 1,
+ };
+
+ for (i = 0; i < wil->max_vifs; i++) {
+ if (wil->vifs[i]) {
+ wdev = vif_to_wdev(wil->vifs[i]);
+ params.iftype_num[wdev->iftype]++;
+ }
+ }
+ params.iftype_num[new_type]++;
+ return cfg80211_check_combinations(wil->wiphy, &params);
+}
+
+static int wil_cfg80211_validate_change_iface(struct wil6210_priv *wil,
+ struct wil6210_vif *vif,
+ enum nl80211_iftype new_type)
+{
+ int i, ret = 0;
+ struct wireless_dev *wdev;
+ struct iface_combination_params params = {
+ .num_different_channels = 1,
+ };
+ bool check_combos = false;
+
+ for (i = 0; i < wil->max_vifs; i++) {
+ struct wil6210_vif *vif_pos = wil->vifs[i];
+
+ if (vif_pos && vif != vif_pos) {
+ wdev = vif_to_wdev(vif_pos);
+ params.iftype_num[wdev->iftype]++;
+ check_combos = true;
+ }
+ }
+
+ if (check_combos) {
+ params.iftype_num[new_type]++;
+ ret = cfg80211_check_combinations(wil->wiphy, &params);
+ }
+ return ret;
+}
+
static struct wireless_dev *
wil_cfg80211_add_iface(struct wiphy *wiphy, const char *name,
unsigned char name_assign_type,
@@ -417,51 +473,137 @@ wil_cfg80211_add_iface(struct wiphy *wiphy, const char *name,
struct vif_params *params)
{
struct wil6210_priv *wil = wiphy_to_wil(wiphy);
- struct net_device *ndev = wil_to_ndev(wil);
- struct wireless_dev *p2p_wdev;
+ struct net_device *ndev_main = wil->main_ndev, *ndev;
+ struct wil6210_vif *vif;
+ struct wireless_dev *p2p_wdev, *wdev;
+ int rc;
- wil_dbg_misc(wil, "add_iface\n");
+ wil_dbg_misc(wil, "add_iface, type %d\n", type);
- if (type != NL80211_IFTYPE_P2P_DEVICE) {
- wil_err(wil, "unsupported iftype %d\n", type);
- return ERR_PTR(-EINVAL);
+ /* P2P device is not a real virtual interface, it is a management-only
+ * interface that shares the main interface.
+ * Skip concurrency checks here.
+ */
+ if (type == NL80211_IFTYPE_P2P_DEVICE) {
+ if (wil->p2p_wdev) {
+ wil_err(wil, "P2P_DEVICE interface already created\n");
+ return ERR_PTR(-EINVAL);
+ }
+
+ p2p_wdev = kzalloc(sizeof(*p2p_wdev), GFP_KERNEL);
+ if (!p2p_wdev)
+ return ERR_PTR(-ENOMEM);
+
+ p2p_wdev->iftype = type;
+ p2p_wdev->wiphy = wiphy;
+ /* use our primary ethernet address */
+ ether_addr_copy(p2p_wdev->address, ndev_main->perm_addr);
+
+ wil->p2p_wdev = p2p_wdev;
+
+ return p2p_wdev;
}
- if (wil->p2p_wdev) {
- wil_err(wil, "P2P_DEVICE interface already created\n");
+ if (!wil->wiphy->n_iface_combinations) {
+ wil_err(wil, "virtual interfaces not supported\n");
return ERR_PTR(-EINVAL);
}
- p2p_wdev = kzalloc(sizeof(*p2p_wdev), GFP_KERNEL);
- if (!p2p_wdev)
- return ERR_PTR(-ENOMEM);
+ rc = wil_cfg80211_validate_add_iface(wil, type);
+ if (rc) {
+ wil_err(wil, "iface validation failed, err=%d\n", rc);
+ return ERR_PTR(rc);
+ }
- p2p_wdev->iftype = type;
- p2p_wdev->wiphy = wiphy;
- /* use our primary ethernet address */
- ether_addr_copy(p2p_wdev->address, ndev->perm_addr);
+ vif = wil_vif_alloc(wil, name, name_assign_type, type);
+ if (IS_ERR(vif))
+ return ERR_CAST(vif);
+
+ ndev = vif_to_ndev(vif);
+ ether_addr_copy(ndev->perm_addr, ndev_main->perm_addr);
+ if (is_valid_ether_addr(params->macaddr)) {
+ ether_addr_copy(ndev->dev_addr, params->macaddr);
+ } else {
+ ether_addr_copy(ndev->dev_addr, ndev_main->perm_addr);
+ ndev->dev_addr[0] = (ndev->dev_addr[0] ^ (1 << vif->mid)) |
+ 0x2; /* locally administered */
+ }
+ wdev = vif_to_wdev(vif);
+ ether_addr_copy(wdev->address, ndev->dev_addr);
- wil->p2p_wdev = p2p_wdev;
+ rc = wil_vif_add(wil, vif);
+ if (rc)
+ goto out;
- return p2p_wdev;
+ wil_info(wil, "added VIF, mid %d iftype %d MAC %pM\n",
+ vif->mid, type, wdev->address);
+ return wdev;
+out:
+ wil_vif_free(vif);
+ return ERR_PTR(rc);
+}
+
+int wil_vif_prepare_stop(struct wil6210_vif *vif)
+{
+ struct wil6210_priv *wil = vif_to_wil(vif);
+ struct wireless_dev *wdev = vif_to_wdev(vif);
+ struct net_device *ndev;
+ int rc;
+
+ if (wdev->iftype != NL80211_IFTYPE_AP)
+ return 0;
+
+ ndev = vif_to_ndev(vif);
+ if (netif_carrier_ok(ndev)) {
+ rc = wmi_pcp_stop(vif);
+ if (rc) {
+ wil_info(wil, "failed to stop AP, status %d\n",
+ rc);
+ /* continue */
+ }
+ wil_bcast_fini(vif);
+ netif_carrier_off(ndev);
+ }
+
+ return 0;
}
static int wil_cfg80211_del_iface(struct wiphy *wiphy,
struct wireless_dev *wdev)
{
struct wil6210_priv *wil = wiphy_to_wil(wiphy);
+ struct wil6210_vif *vif = wdev_to_vif(wil, wdev);
+ int rc;
wil_dbg_misc(wil, "del_iface\n");
- if (wdev != wil->p2p_wdev) {
- wil_err(wil, "delete of incorrect interface 0x%p\n", wdev);
+ if (wdev->iftype == NL80211_IFTYPE_P2P_DEVICE) {
+ if (wdev != wil->p2p_wdev) {
+ wil_err(wil, "delete of incorrect interface 0x%p\n",
+ wdev);
+ return -EINVAL;
+ }
+
+ wil_cfg80211_stop_p2p_device(wiphy, wdev);
+ wil_p2p_wdev_free(wil);
+ return 0;
+ }
+
+ if (vif->mid == 0) {
+ wil_err(wil, "cannot remove the main interface\n");
return -EINVAL;
}
- wil_cfg80211_stop_p2p_device(wiphy, wdev);
- wil_p2p_wdev_free(wil);
+ rc = wil_vif_prepare_stop(vif);
+ if (rc)
+ goto out;
+
+ wil_info(wil, "deleted VIF, mid %d iftype %d MAC %pM\n",
+ vif->mid, wdev->iftype, wdev->address);
- return 0;
+ wil_vif_remove(wil, vif->mid);
+out:
+ return rc;
}
static int wil_cfg80211_change_iface(struct wiphy *wiphy,
@@ -470,12 +612,26 @@ static int wil_cfg80211_change_iface(struct wiphy *wiphy,
struct vif_params *params)
{
struct wil6210_priv *wil = wiphy_to_wil(wiphy);
- struct wireless_dev *wdev = wil_to_wdev(wil);
+ struct wil6210_vif *vif = ndev_to_vif(ndev);
+ struct wireless_dev *wdev = vif_to_wdev(vif);
int rc;
+ bool fw_reset = false;
wil_dbg_misc(wil, "change_iface: type=%d\n", type);
- if (netif_running(wil_to_ndev(wil)) && !wil_is_recovery_blocked(wil)) {
+ if (wiphy->n_iface_combinations) {
+ rc = wil_cfg80211_validate_change_iface(wil, vif, type);
+ if (rc) {
+ wil_err(wil, "iface validation failed, err=%d\n", rc);
+ return rc;
+ }
+ }
+
+ /* do not reset FW when there are active VIFs,
+ * because it can cause significant disruption
+ */
+ if (!wil_has_other_active_ifaces(wil, ndev, true, false) &&
+ netif_running(ndev) && !wil_is_recovery_blocked(wil)) {
wil_dbg_misc(wil, "interface is up. resetting...\n");
mutex_lock(&wil->mutex);
__wil_down(wil);
@@ -484,6 +640,7 @@ static int wil_cfg80211_change_iface(struct wiphy *wiphy,
if (rc)
return rc;
+ fw_reset = true;
}
switch (type) {
@@ -500,8 +657,18 @@ static int wil_cfg80211_change_iface(struct wiphy *wiphy,
return -EOPNOTSUPP;
}
- wdev->iftype = type;
+ if (vif->mid != 0 && wil_has_active_ifaces(wil, true, false)) {
+ if (!fw_reset)
+ wil_vif_prepare_stop(vif);
+ rc = wmi_port_delete(wil, vif->mid);
+ if (rc)
+ return rc;
+ rc = wmi_port_allocate(wil, vif->mid, ndev->dev_addr, type);
+ if (rc)
+ return rc;
+ }
+ wdev->iftype = type;
return 0;
}
@@ -510,6 +677,7 @@ static int wil_cfg80211_scan(struct wiphy *wiphy,
{
struct wil6210_priv *wil = wiphy_to_wil(wiphy);
struct wireless_dev *wdev = request->wdev;
+ struct wil6210_vif *vif = wdev_to_vif(wil, wdev);
struct {
struct wmi_start_scan_cmd cmd;
u16 chnl[4];
@@ -537,35 +705,38 @@ static int wil_cfg80211_scan(struct wiphy *wiphy,
mutex_lock(&wil->mutex);
- mutex_lock(&wil->p2p_wdev_mutex);
- if (wil->scan_request || wil->p2p.discovery_started) {
+ mutex_lock(&wil->vif_mutex);
+ if (vif->scan_request || vif->p2p.discovery_started) {
wil_err(wil, "Already scanning\n");
- mutex_unlock(&wil->p2p_wdev_mutex);
+ mutex_unlock(&wil->vif_mutex);
rc = -EAGAIN;
goto out;
}
- mutex_unlock(&wil->p2p_wdev_mutex);
+ mutex_unlock(&wil->vif_mutex);
if (wdev->iftype == NL80211_IFTYPE_P2P_DEVICE) {
- if (!wil->p2p.p2p_dev_started) {
+ if (!wil->p2p_dev_started) {
wil_err(wil, "P2P search requested on stopped P2P device\n");
rc = -EIO;
goto out;
}
/* social scan on P2P_DEVICE is handled as p2p search */
if (wil_p2p_is_social_scan(request)) {
- wil->scan_request = request;
- wil->radio_wdev = wdev;
- rc = wil_p2p_search(wil, request);
+ vif->scan_request = request;
+ if (vif->mid == 0)
+ wil->radio_wdev = wdev;
+ rc = wil_p2p_search(vif, request);
if (rc) {
- wil->radio_wdev = wil_to_wdev(wil);
- wil->scan_request = NULL;
+ if (vif->mid == 0)
+ wil->radio_wdev =
+ wil->main_ndev->ieee80211_ptr;
+ vif->scan_request = NULL;
}
goto out;
}
}
- (void)wil_p2p_stop_discovery(wil);
+ (void)wil_p2p_stop_discovery(vif);
wil_dbg_misc(wil, "Start scan_request 0x%p\n", request);
wil_dbg_misc(wil, "SSID count: %d", request->n_ssids);
@@ -578,18 +749,18 @@ static int wil_cfg80211_scan(struct wiphy *wiphy,
}
if (request->n_ssids)
- rc = wmi_set_ssid(wil, request->ssids[0].ssid_len,
+ rc = wmi_set_ssid(vif, request->ssids[0].ssid_len,
request->ssids[0].ssid);
else
- rc = wmi_set_ssid(wil, 0, NULL);
+ rc = wmi_set_ssid(vif, 0, NULL);
if (rc) {
wil_err(wil, "set SSID for scan request failed: %d\n", rc);
goto out;
}
- wil->scan_request = request;
- mod_timer(&wil->scan_timer, jiffies + WIL6210_SCAN_TO);
+ vif->scan_request = request;
+ mod_timer(&vif->scan_timer, jiffies + WIL6210_SCAN_TO);
memset(&cmd, 0, sizeof(cmd));
cmd.cmd.scan_type = WMI_ACTIVE_SCAN;
@@ -616,7 +787,8 @@ static int wil_cfg80211_scan(struct wiphy *wiphy,
else
wil_dbg_misc(wil, "Scan has no IE's\n");
- rc = wmi_set_ie(wil, WMI_FRAME_PROBE_REQ, request->ie_len, request->ie);
+ rc = wmi_set_ie(vif, WMI_FRAME_PROBE_REQ,
+ request->ie_len, request->ie);
if (rc)
goto out_restore;
@@ -625,15 +797,18 @@ static int wil_cfg80211_scan(struct wiphy *wiphy,
wil_dbg_misc(wil, "active scan with discovery_mode=1\n");
}
- wil->radio_wdev = wdev;
- rc = wmi_send(wil, WMI_START_SCAN_CMDID, &cmd, sizeof(cmd.cmd) +
- cmd.cmd.num_channels * sizeof(cmd.cmd.channel_list[0]));
+ if (vif->mid == 0)
+ wil->radio_wdev = wdev;
+ rc = wmi_send(wil, WMI_START_SCAN_CMDID, vif->mid,
+ &cmd, sizeof(cmd.cmd) +
+ cmd.cmd.num_channels * sizeof(cmd.cmd.channel_list[0]));
out_restore:
if (rc) {
- del_timer_sync(&wil->scan_timer);
- wil->radio_wdev = wil_to_wdev(wil);
- wil->scan_request = NULL;
+ del_timer_sync(&vif->scan_timer);
+ if (vif->mid == 0)
+ wil->radio_wdev = wil->main_ndev->ieee80211_ptr;
+ vif->scan_request = NULL;
}
out:
mutex_unlock(&wil->mutex);
@@ -644,27 +819,28 @@ static void wil_cfg80211_abort_scan(struct wiphy *wiphy,
struct wireless_dev *wdev)
{
struct wil6210_priv *wil = wiphy_to_wil(wiphy);
+ struct wil6210_vif *vif = wdev_to_vif(wil, wdev);
wil_dbg_misc(wil, "wdev=0x%p iftype=%d\n", wdev, wdev->iftype);
mutex_lock(&wil->mutex);
- mutex_lock(&wil->p2p_wdev_mutex);
+ mutex_lock(&wil->vif_mutex);
- if (!wil->scan_request)
+ if (!vif->scan_request)
goto out;
- if (wdev != wil->scan_request->wdev) {
+ if (wdev != vif->scan_request->wdev) {
wil_dbg_misc(wil, "abort scan was called on the wrong iface\n");
goto out;
}
- if (wil->radio_wdev == wil->p2p_wdev)
+ if (wdev == wil->p2p_wdev && wil->radio_wdev == wil->p2p_wdev)
wil_p2p_stop_radio_operations(wil);
else
- wil_abort_scan(wil, true);
+ wil_abort_scan(vif, true);
out:
- mutex_unlock(&wil->p2p_wdev_mutex);
+ mutex_unlock(&wil->vif_mutex);
mutex_unlock(&wil->mutex);
}
@@ -715,6 +891,7 @@ static int wil_cfg80211_connect(struct wiphy *wiphy,
struct cfg80211_connect_params *sme)
{
struct wil6210_priv *wil = wiphy_to_wil(wiphy);
+ struct wil6210_vif *vif = ndev_to_vif(ndev);
struct cfg80211_bss *bss;
struct wmi_connect_cmd conn;
const u8 *ssid_eid;
@@ -723,11 +900,11 @@ static int wil_cfg80211_connect(struct wiphy *wiphy,
int rc = 0;
enum ieee80211_bss_type bss_type = IEEE80211_BSS_TYPE_ESS;
- wil_dbg_misc(wil, "connect\n");
+ wil_dbg_misc(wil, "connect, mid=%d\n", vif->mid);
wil_print_connect_params(wil, sme);
- if (test_bit(wil_status_fwconnecting, wil->status) ||
- test_bit(wil_status_fwconnected, wil->status))
+ if (test_bit(wil_vif_fwconnecting, vif->status) ||
+ test_bit(wil_vif_fwconnected, vif->status))
return -EALREADY;
if (sme->ie_len > WMI_MAX_IE_LEN) {
@@ -758,18 +935,18 @@ static int wil_cfg80211_connect(struct wiphy *wiphy,
rc = -ENOENT;
goto out;
}
- wil->privacy = sme->privacy;
- wil->pbss = sme->pbss;
+ vif->privacy = sme->privacy;
+ vif->pbss = sme->pbss;
- if (wil->privacy) {
+ if (vif->privacy) {
/* For secure assoc, remove old keys */
- rc = wmi_del_cipher_key(wil, 0, bss->bssid,
+ rc = wmi_del_cipher_key(vif, 0, bss->bssid,
WMI_KEY_USE_PAIRWISE);
if (rc) {
wil_err(wil, "WMI_DELETE_CIPHER_KEY_CMD(PTK) failed\n");
goto out;
}
- rc = wmi_del_cipher_key(wil, 0, bss->bssid,
+ rc = wmi_del_cipher_key(vif, 0, bss->bssid,
WMI_KEY_USE_RX_GROUP);
if (rc) {
wil_err(wil, "WMI_DELETE_CIPHER_KEY_CMD(GTK) failed\n");
@@ -781,7 +958,7 @@ static int wil_cfg80211_connect(struct wiphy *wiphy,
* elements. Send it also in case it's empty, to erase previously set
* ies in FW.
*/
- rc = wmi_set_ie(wil, WMI_FRAME_ASSOC_REQ, sme->ie_len, sme->ie);
+ rc = wmi_set_ie(vif, WMI_FRAME_ASSOC_REQ, sme->ie_len, sme->ie);
if (rc)
goto out;
@@ -799,7 +976,7 @@ static int wil_cfg80211_connect(struct wiphy *wiphy,
bss->capability);
goto out;
}
- if (wil->privacy) {
+ if (vif->privacy) {
if (rsn_eid) { /* regular secure connection */
conn.dot11_auth_mode = WMI_AUTH11_SHARED;
conn.auth_mode = WMI_AUTH_WPA2_PSK;
@@ -831,18 +1008,19 @@ static int wil_cfg80211_connect(struct wiphy *wiphy,
ether_addr_copy(conn.bssid, bss->bssid);
ether_addr_copy(conn.dst_mac, bss->bssid);
- set_bit(wil_status_fwconnecting, wil->status);
+ set_bit(wil_vif_fwconnecting, vif->status);
- rc = wmi_send(wil, WMI_CONNECT_CMDID, &conn, sizeof(conn));
+ rc = wmi_send(wil, WMI_CONNECT_CMDID, vif->mid, &conn, sizeof(conn));
if (rc == 0) {
netif_carrier_on(ndev);
- wil6210_bus_request(wil, WIL_MAX_BUS_REQUEST_KBPS);
- wil->bss = bss;
+ if (!wil_has_other_active_ifaces(wil, ndev, false, true))
+ wil6210_bus_request(wil, WIL_MAX_BUS_REQUEST_KBPS);
+ vif->bss = bss;
/* Connect can take lots of time */
- mod_timer(&wil->connect_timer,
+ mod_timer(&vif->connect_timer,
jiffies + msecs_to_jiffies(5000));
} else {
- clear_bit(wil_status_fwconnecting, wil->status);
+ clear_bit(wil_vif_fwconnecting, vif->status);
}
out:
@@ -857,17 +1035,19 @@ static int wil_cfg80211_disconnect(struct wiphy *wiphy,
{
int rc;
struct wil6210_priv *wil = wiphy_to_wil(wiphy);
+ struct wil6210_vif *vif = ndev_to_vif(ndev);
- wil_dbg_misc(wil, "disconnect: reason=%d\n", reason_code);
+ wil_dbg_misc(wil, "disconnect: reason=%d, mid=%d\n",
+ reason_code, vif->mid);
- if (!(test_bit(wil_status_fwconnecting, wil->status) ||
- test_bit(wil_status_fwconnected, wil->status))) {
+ if (!(test_bit(wil_vif_fwconnecting, vif->status) ||
+ test_bit(wil_vif_fwconnected, vif->status))) {
wil_err(wil, "Disconnect was called while disconnected\n");
return 0;
}
- wil->locally_generated_disc = true;
- rc = wmi_call(wil, WMI_DISCONNECT_CMDID, NULL, 0,
+ vif->locally_generated_disc = true;
+ rc = wmi_call(wil, WMI_DISCONNECT_CMDID, vif->mid, NULL, 0,
WMI_DISCONNECT_EVENTID, NULL, 0,
WIL6210_DISCONNECT_TO_MS);
if (rc)
@@ -903,6 +1083,7 @@ int wil_cfg80211_mgmt_tx(struct wiphy *wiphy, struct wireless_dev *wdev,
const u8 *buf = params->buf;
size_t len = params->len, total;
struct wil6210_priv *wil = wiphy_to_wil(wiphy);
+ struct wil6210_vif *vif = wdev_to_vif(wil, wdev);
int rc;
bool tx_status = false;
struct ieee80211_mgmt *mgmt_frame = (void *)buf;
@@ -919,7 +1100,7 @@ int wil_cfg80211_mgmt_tx(struct wiphy *wiphy, struct wireless_dev *wdev,
* different from currently "listened" channel and fail if it is.
*/
- wil_dbg_misc(wil, "mgmt_tx\n");
+ wil_dbg_misc(wil, "mgmt_tx mid %d\n", vif->mid);
wil_hex_dump_misc("mgmt tx frame ", DUMP_PREFIX_OFFSET, 16, 1, buf,
len, true);
@@ -940,7 +1121,7 @@ int wil_cfg80211_mgmt_tx(struct wiphy *wiphy, struct wireless_dev *wdev,
cmd->len = cpu_to_le16(len);
memcpy(cmd->payload, buf, len);
- rc = wmi_call(wil, WMI_SW_TX_REQ_CMDID, cmd, total,
+ rc = wmi_call(wil, WMI_SW_TX_REQ_CMDID, vif->mid, cmd, total,
WMI_SW_TX_COMPLETE_EVENTID, &evt, sizeof(evt), 2000);
if (rc == 0)
tx_status = !evt.evt.status;
@@ -962,10 +1143,10 @@ static int wil_cfg80211_set_channel(struct wiphy *wiphy,
return 0;
}
-static enum wmi_key_usage wil_detect_key_usage(struct wil6210_priv *wil,
+static enum wmi_key_usage wil_detect_key_usage(struct wireless_dev *wdev,
bool pairwise)
{
- struct wireless_dev *wdev = wil_to_wdev(wil);
+ struct wil6210_priv *wil = wdev_to_wil(wdev);
enum wmi_key_usage rc;
if (pairwise) {
@@ -993,7 +1174,7 @@ static enum wmi_key_usage wil_detect_key_usage(struct wil6210_priv *wil,
}
static struct wil_sta_info *
-wil_find_sta_by_key_usage(struct wil6210_priv *wil,
+wil_find_sta_by_key_usage(struct wil6210_priv *wil, u8 mid,
enum wmi_key_usage key_usage, const u8 *mac_addr)
{
int cid = -EINVAL;
@@ -1003,9 +1184,9 @@ wil_find_sta_by_key_usage(struct wil6210_priv *wil,
/* supplicant provides Rx group key in STA mode with NULL MAC address */
if (mac_addr)
- cid = wil_find_cid(wil, mac_addr);
+ cid = wil_find_cid(wil, mid, mac_addr);
else if (key_usage == WMI_KEY_USE_RX_GROUP)
- cid = wil_find_cid_by_idx(wil, 0);
+ cid = wil_find_cid_by_idx(wil, mid, 0);
if (cid < 0) {
wil_err(wil, "No CID for %pM %s\n", mac_addr,
key_usage_str[key_usage]);
@@ -1082,9 +1263,12 @@ static int wil_cfg80211_add_key(struct wiphy *wiphy,
struct key_params *params)
{
int rc;
+ struct wil6210_vif *vif = ndev_to_vif(ndev);
struct wil6210_priv *wil = wiphy_to_wil(wiphy);
- enum wmi_key_usage key_usage = wil_detect_key_usage(wil, pairwise);
- struct wil_sta_info *cs = wil_find_sta_by_key_usage(wil, key_usage,
+ struct wireless_dev *wdev = vif_to_wdev(vif);
+ enum wmi_key_usage key_usage = wil_detect_key_usage(wdev, pairwise);
+ struct wil_sta_info *cs = wil_find_sta_by_key_usage(wil, vif->mid,
+ key_usage,
mac_addr);
if (!params) {
@@ -1114,7 +1298,7 @@ static int wil_cfg80211_add_key(struct wiphy *wiphy,
return -EINVAL;
}
- rc = wmi_add_cipher_key(wil, key_index, mac_addr, params->key_len,
+ rc = wmi_add_cipher_key(vif, key_index, mac_addr, params->key_len,
params->key, key_usage);
if (!rc)
wil_set_crypto_rx(key_index, key_usage, cs, params);
@@ -1127,9 +1311,12 @@ static int wil_cfg80211_del_key(struct wiphy *wiphy,
u8 key_index, bool pairwise,
const u8 *mac_addr)
{
+ struct wil6210_vif *vif = ndev_to_vif(ndev);
struct wil6210_priv *wil = wiphy_to_wil(wiphy);
- enum wmi_key_usage key_usage = wil_detect_key_usage(wil, pairwise);
- struct wil_sta_info *cs = wil_find_sta_by_key_usage(wil, key_usage,
+ struct wireless_dev *wdev = vif_to_wdev(vif);
+ enum wmi_key_usage key_usage = wil_detect_key_usage(wdev, pairwise);
+ struct wil_sta_info *cs = wil_find_sta_by_key_usage(wil, vif->mid,
+ key_usage,
mac_addr);
wil_dbg_misc(wil, "del_key: %pM %s[%d]\n", mac_addr,
@@ -1142,7 +1329,7 @@ static int wil_cfg80211_del_key(struct wiphy *wiphy,
if (!IS_ERR_OR_NULL(cs))
wil_del_rx_key(key_index, key_usage, cs);
- return wmi_del_cipher_key(wil, key_index, mac_addr, key_usage);
+ return wmi_del_cipher_key(vif, key_index, mac_addr, key_usage);
}
/* Need to be present or wiphy_new() will WARN */
@@ -1179,10 +1366,11 @@ static int wil_cancel_remain_on_channel(struct wiphy *wiphy,
u64 cookie)
{
struct wil6210_priv *wil = wiphy_to_wil(wiphy);
+ struct wil6210_vif *vif = wdev_to_vif(wil, wdev);
wil_dbg_misc(wil, "cancel_remain_on_channel\n");
- return wil_p2p_cancel_listen(wil, cookie);
+ return wil_p2p_cancel_listen(vif, cookie);
}
/**
@@ -1275,11 +1463,10 @@ static void wil_print_bcon_data(struct cfg80211_beacon_data *b)
}
/* internal functions for device reset and starting AP */
-static int _wil_cfg80211_set_ies(struct wiphy *wiphy,
+static int _wil_cfg80211_set_ies(struct wil6210_vif *vif,
struct cfg80211_beacon_data *bcon)
{
int rc;
- struct wil6210_priv *wil = wiphy_to_wil(wiphy);
u16 len = 0, proberesp_len = 0;
u8 *ies = NULL, *proberesp = NULL;
@@ -1300,20 +1487,21 @@ static int _wil_cfg80211_set_ies(struct wiphy *wiphy,
if (rc)
goto out;
- rc = wmi_set_ie(wil, WMI_FRAME_PROBE_RESP, len, ies);
+ rc = wmi_set_ie(vif, WMI_FRAME_PROBE_RESP, len, ies);
if (rc)
goto out;
if (bcon->assocresp_ies)
- rc = wmi_set_ie(wil, WMI_FRAME_ASSOC_RESP,
+ rc = wmi_set_ie(vif, WMI_FRAME_ASSOC_RESP,
bcon->assocresp_ies_len, bcon->assocresp_ies);
else
- rc = wmi_set_ie(wil, WMI_FRAME_ASSOC_RESP, len, ies);
+ rc = wmi_set_ie(vif, WMI_FRAME_ASSOC_RESP, len, ies);
#if 0 /* to use beacon IE's, remove this #if 0 */
if (rc)
goto out;
- rc = wmi_set_ie(wil, WMI_FRAME_BEACON, bcon->tail_len, bcon->tail);
+ rc = wmi_set_ie(vif, WMI_FRAME_BEACON,
+ bcon->tail_len, bcon->tail);
#endif
out:
kfree(ies);
@@ -1328,6 +1516,7 @@ static int _wil_cfg80211_start_ap(struct wiphy *wiphy,
u8 hidden_ssid, u32 pbss)
{
struct wil6210_priv *wil = wiphy_to_wil(wiphy);
+ struct wil6210_vif *vif = ndev_to_vif(ndev);
int rc;
struct wireless_dev *wdev = ndev->ieee80211_ptr;
u8 wmi_nettype = wil_iftype_nl2wmi(wdev->iftype);
@@ -1336,7 +1525,7 @@ static int _wil_cfg80211_start_ap(struct wiphy *wiphy,
if (pbss)
wmi_nettype = WMI_NETTYPE_P2P;
- wil_dbg_misc(wil, "start_ap: is_go=%d\n", is_go);
+ wil_dbg_misc(wil, "start_ap: mid=%d, is_go=%d\n", vif->mid, is_go);
if (is_go && !pbss) {
wil_err(wil, "P2P GO must be in PBSS\n");
return -ENOTSUPP;
@@ -1346,42 +1535,46 @@ static int _wil_cfg80211_start_ap(struct wiphy *wiphy,
mutex_lock(&wil->mutex);
- __wil_down(wil);
- rc = __wil_up(wil);
- if (rc)
- goto out;
+ if (!wil_has_other_active_ifaces(wil, ndev, true, false)) {
+ __wil_down(wil);
+ rc = __wil_up(wil);
+ if (rc)
+ goto out;
+ }
- rc = wmi_set_ssid(wil, ssid_len, ssid);
+ rc = wmi_set_ssid(vif, ssid_len, ssid);
if (rc)
goto out;
- rc = _wil_cfg80211_set_ies(wiphy, bcon);
+ rc = _wil_cfg80211_set_ies(vif, bcon);
if (rc)
goto out;
- wil->privacy = privacy;
- wil->channel = chan;
- wil->hidden_ssid = hidden_ssid;
- wil->pbss = pbss;
+ vif->privacy = privacy;
+ vif->channel = chan;
+ vif->hidden_ssid = hidden_ssid;
+ vif->pbss = pbss;
netif_carrier_on(ndev);
- wil6210_bus_request(wil, WIL_MAX_BUS_REQUEST_KBPS);
+ if (!wil_has_other_active_ifaces(wil, ndev, false, true))
+ wil6210_bus_request(wil, WIL_MAX_BUS_REQUEST_KBPS);
- rc = wmi_pcp_start(wil, bi, wmi_nettype, chan, hidden_ssid, is_go);
+ rc = wmi_pcp_start(vif, bi, wmi_nettype, chan, hidden_ssid, is_go);
if (rc)
goto err_pcp_start;
- rc = wil_bcast_init(wil);
+ rc = wil_bcast_init(vif);
if (rc)
goto err_bcast;
goto out; /* success */
err_bcast:
- wmi_pcp_stop(wil);
+ wmi_pcp_stop(vif);
err_pcp_start:
netif_carrier_off(ndev);
- wil6210_bus_request(wil, WIL_DEFAULT_BUS_REQUEST_KBPS);
+ if (!wil_has_other_active_ifaces(wil, ndev, false, true))
+ wil6210_bus_request(wil, WIL_DEFAULT_BUS_REQUEST_KBPS);
out:
mutex_unlock(&wil->mutex);
return rc;
@@ -1392,10 +1585,11 @@ static int wil_cfg80211_change_beacon(struct wiphy *wiphy,
struct cfg80211_beacon_data *bcon)
{
struct wil6210_priv *wil = wiphy_to_wil(wiphy);
+ struct wil6210_vif *vif = ndev_to_vif(ndev);
int rc;
u32 privacy = 0;
- wil_dbg_misc(wil, "change_beacon\n");
+ wil_dbg_misc(wil, "change_beacon, mid=%d\n", vif->mid);
wil_print_bcon_data(bcon);
if (bcon->tail &&
@@ -1404,20 +1598,20 @@ static int wil_cfg80211_change_beacon(struct wiphy *wiphy,
privacy = 1;
/* in case privacy has changed, need to restart the AP */
- if (wil->privacy != privacy) {
+ if (vif->privacy != privacy) {
struct wireless_dev *wdev = ndev->ieee80211_ptr;
wil_dbg_misc(wil, "privacy changed %d=>%d. Restarting AP\n",
- wil->privacy, privacy);
+ vif->privacy, privacy);
rc = _wil_cfg80211_start_ap(wiphy, ndev, wdev->ssid,
wdev->ssid_len, privacy,
wdev->beacon_interval,
- wil->channel, bcon,
- wil->hidden_ssid,
- wil->pbss);
+ vif->channel, bcon,
+ vif->hidden_ssid,
+ vif->pbss);
} else {
- rc = _wil_cfg80211_set_ies(wiphy, bcon);
+ rc = _wil_cfg80211_set_ies(vif, bcon);
}
return rc;
@@ -1484,20 +1678,27 @@ static int wil_cfg80211_stop_ap(struct wiphy *wiphy,
struct net_device *ndev)
{
struct wil6210_priv *wil = wiphy_to_wil(wiphy);
+ struct wil6210_vif *vif = ndev_to_vif(ndev);
+ bool last;
- wil_dbg_misc(wil, "stop_ap\n");
+ wil_dbg_misc(wil, "stop_ap, mid=%d\n", vif->mid);
netif_carrier_off(ndev);
- wil6210_bus_request(wil, WIL_DEFAULT_BUS_REQUEST_KBPS);
- wil_set_recovery_state(wil, fw_recovery_idle);
-
- set_bit(wil_status_resetting, wil->status);
+ last = !wil_has_other_active_ifaces(wil, ndev, false, true);
+ if (last) {
+ wil6210_bus_request(wil, WIL_DEFAULT_BUS_REQUEST_KBPS);
+ wil_set_recovery_state(wil, fw_recovery_idle);
+ set_bit(wil_status_resetting, wil->status);
+ }
mutex_lock(&wil->mutex);
- wmi_pcp_stop(wil);
+ wmi_pcp_stop(vif);
- __wil_down(wil);
+ if (last)
+ __wil_down(wil);
+ else
+ wil_bcast_fini(vif);
mutex_unlock(&wil->mutex);
@@ -1509,9 +1710,11 @@ static int wil_cfg80211_add_station(struct wiphy *wiphy,
const u8 *mac,
struct station_parameters *params)
{
+ struct wil6210_vif *vif = ndev_to_vif(dev);
struct wil6210_priv *wil = wiphy_to_wil(wiphy);
- wil_dbg_misc(wil, "add station %pM aid %d\n", mac, params->aid);
+ wil_dbg_misc(wil, "add station %pM aid %d mid %d\n",
+ mac, params->aid, vif->mid);
if (!disable_ap_sme) {
wil_err(wil, "not supported with AP SME enabled\n");
@@ -1523,20 +1726,21 @@ static int wil_cfg80211_add_station(struct wiphy *wiphy,
return -EINVAL;
}
- return wmi_new_sta(wil, mac, params->aid);
+ return wmi_new_sta(vif, mac, params->aid);
}
static int wil_cfg80211_del_station(struct wiphy *wiphy,
struct net_device *dev,
struct station_del_parameters *params)
{
+ struct wil6210_vif *vif = ndev_to_vif(dev);
struct wil6210_priv *wil = wiphy_to_wil(wiphy);
- wil_dbg_misc(wil, "del_station: %pM, reason=%d\n", params->mac,
- params->reason_code);
+ wil_dbg_misc(wil, "del_station: %pM, reason=%d mid=%d\n",
+ params->mac, params->reason_code, vif->mid);
mutex_lock(&wil->mutex);
- wil6210_disconnect(wil, params->mac, params->reason_code, false);
+ wil6210_disconnect(vif, params->mac, params->reason_code, false);
mutex_unlock(&wil->mutex);
return 0;
@@ -1547,13 +1751,15 @@ static int wil_cfg80211_change_station(struct wiphy *wiphy,
const u8 *mac,
struct station_parameters *params)
{
+ struct wil6210_vif *vif = ndev_to_vif(dev);
struct wil6210_priv *wil = wiphy_to_wil(wiphy);
int authorize;
int cid, i;
struct vring_tx_data *txdata = NULL;
- wil_dbg_misc(wil, "change station %pM mask 0x%x set 0x%x\n", mac,
- params->sta_flags_mask, params->sta_flags_set);
+ wil_dbg_misc(wil, "change station %pM mask 0x%x set 0x%x mid %d\n",
+ mac, params->sta_flags_mask, params->sta_flags_set,
+ vif->mid);
if (!disable_ap_sme) {
wil_dbg_misc(wil, "not supported with AP SME enabled\n");
@@ -1563,7 +1769,7 @@ static int wil_cfg80211_change_station(struct wiphy *wiphy,
if (!(params->sta_flags_mask & BIT(NL80211_STA_FLAG_AUTHORIZED)))
return 0;
- cid = wil_find_cid(wil, mac);
+ cid = wil_find_cid(wil, vif->mid, mac);
if (cid < 0) {
wil_err(wil, "station not found\n");
return -ENOLINK;
@@ -1590,9 +1796,10 @@ static int wil_cfg80211_change_station(struct wiphy *wiphy,
/* probe_client handling */
static void wil_probe_client_handle(struct wil6210_priv *wil,
+ struct wil6210_vif *vif,
struct wil_probe_client_req *req)
{
- struct net_device *ndev = wil_to_ndev(wil);
+ struct net_device *ndev = vif_to_ndev(vif);
struct wil_sta_info *sta = &wil->sta[req->cid];
/* assume STA is alive if it is still connected,
* else FW will disconnect it
@@ -1603,51 +1810,53 @@ static void wil_probe_client_handle(struct wil6210_priv *wil,
0, false, GFP_KERNEL);
}
-static struct list_head *next_probe_client(struct wil6210_priv *wil)
+static struct list_head *next_probe_client(struct wil6210_vif *vif)
{
struct list_head *ret = NULL;
- mutex_lock(&wil->probe_client_mutex);
+ mutex_lock(&vif->probe_client_mutex);
- if (!list_empty(&wil->probe_client_pending)) {
- ret = wil->probe_client_pending.next;
+ if (!list_empty(&vif->probe_client_pending)) {
+ ret = vif->probe_client_pending.next;
list_del(ret);
}
- mutex_unlock(&wil->probe_client_mutex);
+ mutex_unlock(&vif->probe_client_mutex);
return ret;
}
void wil_probe_client_worker(struct work_struct *work)
{
- struct wil6210_priv *wil = container_of(work, struct wil6210_priv,
- probe_client_worker);
+ struct wil6210_vif *vif = container_of(work, struct wil6210_vif,
+ probe_client_worker);
+ struct wil6210_priv *wil = vif_to_wil(vif);
struct wil_probe_client_req *req;
struct list_head *lh;
- while ((lh = next_probe_client(wil)) != NULL) {
+ while ((lh = next_probe_client(vif)) != NULL) {
req = list_entry(lh, struct wil_probe_client_req, list);
- wil_probe_client_handle(wil, req);
+ wil_probe_client_handle(wil, vif, req);
kfree(req);
}
}
-void wil_probe_client_flush(struct wil6210_priv *wil)
+void wil_probe_client_flush(struct wil6210_vif *vif)
{
struct wil_probe_client_req *req, *t;
+ struct wil6210_priv *wil = vif_to_wil(vif);
wil_dbg_misc(wil, "probe_client_flush\n");
- mutex_lock(&wil->probe_client_mutex);
+ mutex_lock(&vif->probe_client_mutex);
- list_for_each_entry_safe(req, t, &wil->probe_client_pending, list) {
+ list_for_each_entry_safe(req, t, &vif->probe_client_pending, list) {
list_del(&req->list);
kfree(req);
}
- mutex_unlock(&wil->probe_client_mutex);
+ mutex_unlock(&vif->probe_client_mutex);
}
static int wil_cfg80211_probe_client(struct wiphy *wiphy,
@@ -1655,10 +1864,12 @@ static int wil_cfg80211_probe_client(struct wiphy *wiphy,
const u8 *peer, u64 *cookie)
{
struct wil6210_priv *wil = wiphy_to_wil(wiphy);
+ struct wil6210_vif *vif = ndev_to_vif(dev);
struct wil_probe_client_req *req;
- int cid = wil_find_cid(wil, peer);
+ int cid = wil_find_cid(wil, vif->mid, peer);
- wil_dbg_misc(wil, "probe_client: %pM => CID %d\n", peer, cid);
+ wil_dbg_misc(wil, "probe_client: %pM => CID %d MID %d\n",
+ peer, cid, vif->mid);
if (cid < 0)
return -ENOLINK;
@@ -1670,12 +1881,12 @@ static int wil_cfg80211_probe_client(struct wiphy *wiphy,
req->cid = cid;
req->cookie = cid;
- mutex_lock(&wil->probe_client_mutex);
- list_add_tail(&req->list, &wil->probe_client_pending);
- mutex_unlock(&wil->probe_client_mutex);
+ mutex_lock(&vif->probe_client_mutex);
+ list_add_tail(&req->list, &vif->probe_client_pending);
+ mutex_unlock(&vif->probe_client_mutex);
*cookie = req->cookie;
- queue_work(wil->wq_service, &wil->probe_client_worker);
+ queue_work(wil->wq_service, &vif->probe_client_worker);
return 0;
}
@@ -1684,11 +1895,12 @@ static int wil_cfg80211_change_bss(struct wiphy *wiphy,
struct bss_parameters *params)
{
struct wil6210_priv *wil = wiphy_to_wil(wiphy);
+ struct wil6210_vif *vif = ndev_to_vif(dev);
if (params->ap_isolate >= 0) {
- wil_dbg_misc(wil, "change_bss: ap_isolate %d => %d\n",
- wil->ap_isolate, params->ap_isolate);
- wil->ap_isolate = params->ap_isolate;
+ wil_dbg_misc(wil, "change_bss: ap_isolate MID %d, %d => %d\n",
+ vif->mid, vif->ap_isolate, params->ap_isolate);
+ vif->ap_isolate = params->ap_isolate;
}
return 0;
@@ -1732,10 +1944,10 @@ static int wil_cfg80211_suspend(struct wiphy *wiphy,
wil_dbg_pm(wil, "suspending\n");
mutex_lock(&wil->mutex);
- mutex_lock(&wil->p2p_wdev_mutex);
+ mutex_lock(&wil->vif_mutex);
wil_p2p_stop_radio_operations(wil);
- wil_abort_scan(wil, true);
- mutex_unlock(&wil->p2p_wdev_mutex);
+ wil_abort_scan_all_vifs(wil, true);
+ mutex_unlock(&wil->vif_mutex);
mutex_unlock(&wil->mutex);
out:
@@ -1757,8 +1969,12 @@ wil_cfg80211_sched_scan_start(struct wiphy *wiphy,
struct cfg80211_sched_scan_request *request)
{
struct wil6210_priv *wil = wiphy_to_wil(wiphy);
+ struct wil6210_vif *vif = ndev_to_vif(dev);
int i, rc;
+ if (vif->mid != 0)
+ return -EOPNOTSUPP;
+
wil_dbg_misc(wil,
"sched scan start: n_ssids %d, ie_len %zu, flags 0x%x\n",
request->n_ssids, request->ie_len, request->flags);
@@ -1792,7 +2008,8 @@ wil_cfg80211_sched_scan_start(struct wiphy *wiphy,
i, sp->interval, sp->iterations);
}
- rc = wmi_set_ie(wil, WMI_FRAME_PROBE_REQ, request->ie_len, request->ie);
+ rc = wmi_set_ie(vif, WMI_FRAME_PROBE_REQ,
+ request->ie_len, request->ie);
if (rc)
return rc;
return wmi_start_sched_scan(wil, request);
@@ -1803,8 +2020,12 @@ wil_cfg80211_sched_scan_stop(struct wiphy *wiphy, struct net_device *dev,
u64 reqid)
{
struct wil6210_priv *wil = wiphy_to_wil(wiphy);
+ struct wil6210_vif *vif = ndev_to_vif(dev);
int rc;
+ if (vif->mid != 0)
+ return -EOPNOTSUPP;
+
rc = wmi_stop_sched_scan(wil);
/* device would return error if it thinks PNO is already stopped.
* ignore the return code so user space and driver gets back in-sync
@@ -1893,57 +2114,132 @@ static void wil_wiphy_init(struct wiphy *wiphy)
#endif
}
-struct wireless_dev *wil_cfg80211_init(struct device *dev)
+int wil_cfg80211_iface_combinations_from_fw(
+ struct wil6210_priv *wil, const struct wil_fw_record_concurrency *conc)
{
- int rc = 0;
- struct wireless_dev *wdev;
+ struct wiphy *wiphy = wil_to_wiphy(wil);
+ u32 total_limits = 0;
+ u16 n_combos;
+ const struct wil_fw_concurrency_combo *combo;
+ const struct wil_fw_concurrency_limit *limit;
+ struct ieee80211_iface_combination *iface_combinations;
+ struct ieee80211_iface_limit *iface_limit;
+ int i, j;
+
+ if (wiphy->iface_combinations) {
+ wil_dbg_misc(wil, "iface_combinations already set, skipping\n");
+ return 0;
+ }
- dev_dbg(dev, "%s()\n", __func__);
+ combo = conc->combos;
+ n_combos = le16_to_cpu(conc->n_combos);
+ for (i = 0; i < n_combos; i++) {
+ total_limits += combo->n_limits;
+ limit = combo->limits + combo->n_limits;
+ combo = (struct wil_fw_concurrency_combo *)limit;
+ }
- wdev = kzalloc(sizeof(*wdev), GFP_KERNEL);
- if (!wdev)
- return ERR_PTR(-ENOMEM);
+ iface_combinations =
+ kzalloc(n_combos * sizeof(struct ieee80211_iface_combination) +
+ total_limits * sizeof(struct ieee80211_iface_limit),
+ GFP_KERNEL);
+ if (!iface_combinations)
+ return -ENOMEM;
+ iface_limit = (struct ieee80211_iface_limit *)(iface_combinations +
+ n_combos);
+ combo = conc->combos;
+ for (i = 0; i < n_combos; i++) {
+ iface_combinations[i].max_interfaces = combo->max_interfaces;
+ iface_combinations[i].num_different_channels =
+ combo->n_diff_channels;
+ iface_combinations[i].beacon_int_infra_match =
+ combo->same_bi;
+ iface_combinations[i].n_limits = combo->n_limits;
+ wil_dbg_misc(wil,
+ "iface_combination %d: max_if %d, num_ch %d, bi_match %d\n",
+ i, iface_combinations[i].max_interfaces,
+ iface_combinations[i].num_different_channels,
+ iface_combinations[i].beacon_int_infra_match);
+ limit = combo->limits;
+ for (j = 0; j < combo->n_limits; j++) {
+ iface_limit[j].max = le16_to_cpu(limit[j].max);
+ iface_limit[j].types = le16_to_cpu(limit[j].types);
+ wil_dbg_misc(wil,
+ "limit %d: max %d types 0x%x\n", j,
+ iface_limit[j].max, iface_limit[j].types);
+ }
+ iface_combinations[i].limits = iface_limit;
+ iface_limit += combo->n_limits;
+ limit += combo->n_limits;
+ combo = (struct wil_fw_concurrency_combo *)limit;
+ }
- wdev->wiphy = wiphy_new(&wil_cfg80211_ops,
- sizeof(struct wil6210_priv));
- if (!wdev->wiphy) {
- rc = -ENOMEM;
- goto out;
+ wil_dbg_misc(wil, "multiple VIFs supported, n_mids %d\n", conc->n_mids);
+ wil->max_vifs = conc->n_mids + 1; /* including main interface */
+ if (wil->max_vifs > WIL_MAX_VIFS) {
+ wil_info(wil, "limited number of VIFs supported(%d, FW %d)\n",
+ WIL_MAX_VIFS, wil->max_vifs);
+ wil->max_vifs = WIL_MAX_VIFS;
}
+ wiphy->n_iface_combinations = n_combos;
+ wiphy->iface_combinations = iface_combinations;
+ return 0;
+}
- set_wiphy_dev(wdev->wiphy, dev);
- wil_wiphy_init(wdev->wiphy);
+struct wil6210_priv *wil_cfg80211_init(struct device *dev)
+{
+ struct wiphy *wiphy;
+ struct wil6210_priv *wil;
+ struct ieee80211_channel *ch;
- return wdev;
+ dev_dbg(dev, "%s()\n", __func__);
-out:
- kfree(wdev);
+ /* Note: the wireless_dev structure is no longer allocated here.
+ * Instead, it is allocated as part of the net_device structure
+ * for main interface and each VIF.
+ */
+ wiphy = wiphy_new(&wil_cfg80211_ops, sizeof(struct wil6210_priv));
+ if (!wiphy)
+ return ERR_PTR(-ENOMEM);
- return ERR_PTR(rc);
+ set_wiphy_dev(wiphy, dev);
+ wil_wiphy_init(wiphy);
+
+ wil = wiphy_to_wil(wiphy);
+ wil->wiphy = wiphy;
+
+ /* default monitor channel */
+ ch = wiphy->bands[NL80211_BAND_60GHZ]->channels;
+ cfg80211_chandef_create(&wil->monitor_chandef, ch, NL80211_CHAN_NO_HT);
+
+ return wil;
}
-void wil_wdev_free(struct wil6210_priv *wil)
+void wil_cfg80211_deinit(struct wil6210_priv *wil)
{
- struct wireless_dev *wdev = wil_to_wdev(wil);
+ struct wiphy *wiphy = wil_to_wiphy(wil);
dev_dbg(wil_to_dev(wil), "%s()\n", __func__);
- if (!wdev)
+ if (!wiphy)
return;
- wiphy_free(wdev->wiphy);
- kfree(wdev);
+ kfree(wiphy->iface_combinations);
+ wiphy->iface_combinations = NULL;
+
+ wiphy_free(wiphy);
+ /* do not access wil6210_priv after returning from here */
}
void wil_p2p_wdev_free(struct wil6210_priv *wil)
{
struct wireless_dev *p2p_wdev;
- mutex_lock(&wil->p2p_wdev_mutex);
+ mutex_lock(&wil->vif_mutex);
p2p_wdev = wil->p2p_wdev;
wil->p2p_wdev = NULL;
- wil->radio_wdev = wil_to_wdev(wil);
- mutex_unlock(&wil->p2p_wdev_mutex);
+ wil->radio_wdev = wil->main_ndev->ieee80211_ptr;
+ mutex_unlock(&wil->vif_mutex);
if (p2p_wdev) {
cfg80211_unregister_wdev(p2p_wdev);
kfree(p2p_wdev);
@@ -1971,6 +2267,7 @@ static int wil_rf_sector_get_cfg(struct wiphy *wiphy,
const void *data, int data_len)
{
struct wil6210_priv *wil = wdev_to_wil(wdev);
+ struct wil6210_vif *vif = wdev_to_vif(wil, wdev);
int rc;
struct nlattr *tb[QCA_ATTR_DMG_RF_SECTOR_MAX + 1];
u16 sector_index;
@@ -2027,8 +2324,8 @@ static int wil_rf_sector_get_cfg(struct wiphy *wiphy,
cmd.sector_type = sector_type;
cmd.rf_modules_vec = rf_modules_vec & 0xFF;
memset(&reply, 0, sizeof(reply));
- rc = wmi_call(wil, WMI_GET_RF_SECTOR_PARAMS_CMDID, &cmd, sizeof(cmd),
- WMI_GET_RF_SECTOR_PARAMS_DONE_EVENTID,
+ rc = wmi_call(wil, WMI_GET_RF_SECTOR_PARAMS_CMDID, vif->mid,
+ &cmd, sizeof(cmd), WMI_GET_RF_SECTOR_PARAMS_DONE_EVENTID,
&reply, sizeof(reply),
500);
if (rc)
@@ -2090,6 +2387,7 @@ static int wil_rf_sector_set_cfg(struct wiphy *wiphy,
const void *data, int data_len)
{
struct wil6210_priv *wil = wdev_to_wil(wdev);
+ struct wil6210_vif *vif = wdev_to_vif(wil, wdev);
int rc, tmp;
struct nlattr *tb[QCA_ATTR_DMG_RF_SECTOR_MAX + 1];
struct nlattr *tb2[QCA_ATTR_DMG_RF_SECTOR_CFG_MAX + 1];
@@ -2184,8 +2482,8 @@ static int wil_rf_sector_set_cfg(struct wiphy *wiphy,
cmd.rf_modules_vec = rf_modules_vec & 0xFF;
memset(&reply, 0, sizeof(reply));
- rc = wmi_call(wil, WMI_SET_RF_SECTOR_PARAMS_CMDID, &cmd, sizeof(cmd),
- WMI_SET_RF_SECTOR_PARAMS_DONE_EVENTID,
+ rc = wmi_call(wil, WMI_SET_RF_SECTOR_PARAMS_CMDID, vif->mid,
+ &cmd, sizeof(cmd), WMI_SET_RF_SECTOR_PARAMS_DONE_EVENTID,
&reply, sizeof(reply),
500);
if (rc)
@@ -2198,6 +2496,7 @@ static int wil_rf_sector_get_selected(struct wiphy *wiphy,
const void *data, int data_len)
{
struct wil6210_priv *wil = wdev_to_wil(wdev);
+ struct wil6210_vif *vif = wdev_to_vif(wil, wdev);
int rc;
struct nlattr *tb[QCA_ATTR_DMG_RF_SECTOR_MAX + 1];
u8 sector_type, mac_addr[ETH_ALEN];
@@ -2231,13 +2530,13 @@ static int wil_rf_sector_get_selected(struct wiphy *wiphy,
if (tb[QCA_ATTR_MAC_ADDR]) {
ether_addr_copy(mac_addr, nla_data(tb[QCA_ATTR_MAC_ADDR]));
- cid = wil_find_cid(wil, mac_addr);
+ cid = wil_find_cid(wil, vif->mid, mac_addr);
if (cid < 0) {
wil_err(wil, "invalid MAC address %pM\n", mac_addr);
return -ENOENT;
}
} else {
- if (test_bit(wil_status_fwconnected, wil->status)) {
+ if (test_bit(wil_vif_fwconnected, vif->status)) {
wil_err(wil, "must specify MAC address when connected\n");
return -EINVAL;
}
@@ -2247,7 +2546,7 @@ static int wil_rf_sector_get_selected(struct wiphy *wiphy,
cmd.cid = (u8)cid;
cmd.sector_type = sector_type;
memset(&reply, 0, sizeof(reply));
- rc = wmi_call(wil, WMI_GET_SELECTED_RF_SECTOR_INDEX_CMDID,
+ rc = wmi_call(wil, WMI_GET_SELECTED_RF_SECTOR_INDEX_CMDID, vif->mid,
&cmd, sizeof(cmd),
WMI_GET_SELECTED_RF_SECTOR_INDEX_DONE_EVENTID,
&reply, sizeof(reply),
@@ -2280,7 +2579,7 @@ nla_put_failure:
}
static int wil_rf_sector_wmi_set_selected(struct wil6210_priv *wil,
- u16 sector_index,
+ u8 mid, u16 sector_index,
u8 sector_type, u8 cid)
{
struct wmi_set_selected_rf_sector_index_cmd cmd;
@@ -2295,7 +2594,7 @@ static int wil_rf_sector_wmi_set_selected(struct wil6210_priv *wil,
cmd.sector_type = sector_type;
cmd.cid = (u8)cid;
memset(&reply, 0, sizeof(reply));
- rc = wmi_call(wil, WMI_SET_SELECTED_RF_SECTOR_INDEX_CMDID,
+ rc = wmi_call(wil, WMI_SET_SELECTED_RF_SECTOR_INDEX_CMDID, mid,
&cmd, sizeof(cmd),
WMI_SET_SELECTED_RF_SECTOR_INDEX_DONE_EVENTID,
&reply, sizeof(reply),
@@ -2310,6 +2609,7 @@ static int wil_rf_sector_set_selected(struct wiphy *wiphy,
const void *data, int data_len)
{
struct wil6210_priv *wil = wdev_to_wil(wdev);
+ struct wil6210_vif *vif = wdev_to_vif(wil, wdev);
int rc;
struct nlattr *tb[QCA_ATTR_DMG_RF_SECTOR_MAX + 1];
u16 sector_index;
@@ -2349,7 +2649,7 @@ static int wil_rf_sector_set_selected(struct wiphy *wiphy,
if (tb[QCA_ATTR_MAC_ADDR]) {
ether_addr_copy(mac_addr, nla_data(tb[QCA_ATTR_MAC_ADDR]));
if (!is_broadcast_ether_addr(mac_addr)) {
- cid = wil_find_cid(wil, mac_addr);
+ cid = wil_find_cid(wil, vif->mid, mac_addr);
if (cid < 0) {
wil_err(wil, "invalid MAC address %pM\n",
mac_addr);
@@ -2363,7 +2663,7 @@ static int wil_rf_sector_set_selected(struct wiphy *wiphy,
cid = -1;
}
} else {
- if (test_bit(wil_status_fwconnected, wil->status)) {
+ if (test_bit(wil_vif_fwconnected, vif->status)) {
wil_err(wil, "must specify MAC address when connected\n");
return -EINVAL;
}
@@ -2371,17 +2671,20 @@ static int wil_rf_sector_set_selected(struct wiphy *wiphy,
}
if (cid >= 0) {
- rc = wil_rf_sector_wmi_set_selected(wil, sector_index,
+ rc = wil_rf_sector_wmi_set_selected(wil, vif->mid, sector_index,
sector_type, cid);
} else {
/* unlock all cids */
rc = wil_rf_sector_wmi_set_selected(
- wil, WMI_INVALID_RF_SECTOR_INDEX, sector_type,
- WIL_CID_ALL);
+ wil, vif->mid, WMI_INVALID_RF_SECTOR_INDEX,
+ sector_type, WIL_CID_ALL);
if (rc == -EINVAL) {
for (i = 0; i < WIL6210_MAX_CID; i++) {
+ if (wil->sta[i].mid != vif->mid)
+ continue;
rc = wil_rf_sector_wmi_set_selected(
- wil, WMI_INVALID_RF_SECTOR_INDEX,
+ wil, vif->mid,
+ WMI_INVALID_RF_SECTOR_INDEX,
sector_type, i);
/* the FW will silently ignore and return
* success for unused cid, so abort the loop
diff --git a/drivers/net/wireless/ath/wil6210/debug.c b/drivers/net/wireless/ath/wil6210/debug.c
index 217a4591bde4..a9befb971cc4 100644
--- a/drivers/net/wireless/ath/wil6210/debug.c
+++ b/drivers/net/wireless/ath/wil6210/debug.c
@@ -1,5 +1,6 @@
/*
* Copyright (c) 2013,2016 Qualcomm Atheros, Inc.
+ * Copyright (c) 2018, The Linux Foundation. All rights reserved.
*
* Permission to use, copy, modify, and/or distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
@@ -25,7 +26,7 @@ void __wil_err(struct wil6210_priv *wil, const char *fmt, ...)
va_start(args, fmt);
vaf.fmt = fmt;
vaf.va = &args;
- netdev_err(wil_to_ndev(wil), "%pV", &vaf);
+ netdev_err(wil->main_ndev, "%pV", &vaf);
trace_wil6210_log_err(&vaf);
va_end(args);
}
@@ -41,7 +42,7 @@ void __wil_err_ratelimited(struct wil6210_priv *wil, const char *fmt, ...)
va_start(args, fmt);
vaf.fmt = fmt;
vaf.va = &args;
- netdev_err(wil_to_ndev(wil), "%pV", &vaf);
+ netdev_err(wil->main_ndev, "%pV", &vaf);
trace_wil6210_log_err(&vaf);
va_end(args);
}
@@ -57,7 +58,7 @@ void wil_dbg_ratelimited(const struct wil6210_priv *wil, const char *fmt, ...)
va_start(args, fmt);
vaf.fmt = fmt;
vaf.va = &args;
- netdev_dbg(wil_to_ndev(wil), "%pV", &vaf);
+ netdev_dbg(wil->main_ndev, "%pV", &vaf);
trace_wil6210_log_dbg(&vaf);
va_end(args);
}
@@ -70,7 +71,7 @@ void __wil_info(struct wil6210_priv *wil, const char *fmt, ...)
va_start(args, fmt);
vaf.fmt = fmt;
vaf.va = &args;
- netdev_info(wil_to_ndev(wil), "%pV", &vaf);
+ netdev_info(wil->main_ndev, "%pV", &vaf);
trace_wil6210_log_info(&vaf);
va_end(args);
}
diff --git a/drivers/net/wireless/ath/wil6210/debugfs.c b/drivers/net/wireless/ath/wil6210/debugfs.c
index 4a4888246e8c..8c90b3111f0b 100644
--- a/drivers/net/wireless/ath/wil6210/debugfs.c
+++ b/drivers/net/wireless/ath/wil6210/debugfs.c
@@ -1,5 +1,6 @@
/*
* Copyright (c) 2012-2017 Qualcomm Atheros, Inc.
+ * Copyright (c) 2018, The Linux Foundation. All rights reserved.
*
* Permission to use, copy, modify, and/or distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
@@ -621,7 +622,7 @@ static ssize_t wil_write_file_reset(struct file *file, const char __user *buf,
size_t len, loff_t *ppos)
{
struct wil6210_priv *wil = file->private_data;
- struct net_device *ndev = wil_to_ndev(wil);
+ struct net_device *ndev = wil->main_ndev;
/**
* BUG:
@@ -716,27 +717,44 @@ static ssize_t wil_write_back(struct file *file, const char __user *buf,
if (rc < 2)
return -EINVAL;
- if (0 == strcmp(cmd, "add")) {
- if (rc < 3) {
- wil_err(wil, "BACK: add require at least 2 params\n");
+ if ((strcmp(cmd, "add") == 0) ||
+ (strcmp(cmd, "del_tx") == 0)) {
+ struct vring_tx_data *txdata;
+
+ if (p1 < 0 || p1 >= WIL6210_MAX_TX_RINGS) {
+ wil_err(wil, "BACK: invalid ring id %d\n", p1);
return -EINVAL;
}
- if (rc < 4)
- p3 = 0;
- wmi_addba(wil, p1, p2, p3);
- } else if (0 == strcmp(cmd, "del_tx")) {
- if (rc < 3)
- p2 = WLAN_REASON_QSTA_LEAVE_QBSS;
- wmi_delba_tx(wil, p1, p2);
- } else if (0 == strcmp(cmd, "del_rx")) {
+ txdata = &wil->vring_tx_data[p1];
+ if (strcmp(cmd, "add") == 0) {
+ if (rc < 3) {
+ wil_err(wil, "BACK: add require at least 2 params\n");
+ return -EINVAL;
+ }
+ if (rc < 4)
+ p3 = 0;
+ wmi_addba(wil, txdata->mid, p1, p2, p3);
+ } else {
+ if (rc < 3)
+ p2 = WLAN_REASON_QSTA_LEAVE_QBSS;
+ wmi_delba_tx(wil, txdata->mid, p1, p2);
+ }
+ } else if (strcmp(cmd, "del_rx") == 0) {
+ struct wil_sta_info *sta;
+
if (rc < 3) {
wil_err(wil,
"BACK: del_rx require at least 2 params\n");
return -EINVAL;
}
+ if (p1 < 0 || p1 >= WIL6210_MAX_CID) {
+ wil_err(wil, "BACK: invalid CID %d\n", p1);
+ return -EINVAL;
+ }
if (rc < 4)
p3 = WLAN_REASON_QSTA_LEAVE_QBSS;
- wmi_delba_rx(wil, mk_cidxtid(p1, p2), p3);
+ sta = &wil->sta[p1];
+ wmi_delba_rx(wil, sta->mid, mk_cidxtid(p1, p2), p3);
} else {
wil_err(wil, "BACK: Unrecognized command \"%s\"\n", cmd);
return -EINVAL;
@@ -855,7 +873,7 @@ static ssize_t wil_write_file_txmgmt(struct file *file, const char __user *buf,
{
struct wil6210_priv *wil = file->private_data;
struct wiphy *wiphy = wil_to_wiphy(wil);
- struct wireless_dev *wdev = wil_to_wdev(wil);
+ struct wireless_dev *wdev = wil->main_ndev->ieee80211_ptr;
struct cfg80211_mgmt_tx_params params;
int rc;
void *frame;
@@ -890,6 +908,7 @@ static ssize_t wil_write_file_wmi(struct file *file, const char __user *buf,
size_t len, loff_t *ppos)
{
struct wil6210_priv *wil = file->private_data;
+ struct wil6210_vif *vif = ndev_to_vif(wil->main_ndev);
struct wmi_cmd_hdr *wmi;
void *cmd;
int cmdlen = len - sizeof(struct wmi_cmd_hdr);
@@ -912,7 +931,7 @@ static ssize_t wil_write_file_wmi(struct file *file, const char __user *buf,
cmd = (cmdlen > 0) ? &wmi[1] : NULL;
cmdid = le16_to_cpu(wmi->command_id);
- rc1 = wmi_send(wil, cmdid, cmd, cmdlen);
+ rc1 = wmi_send(wil, cmdid, vif->mid, cmd, cmdlen);
kfree(wmi);
wil_info(wil, "0x%04x[%d] -> %d\n", cmdid, cmdlen, rc1);
@@ -1050,6 +1069,7 @@ static int wil_bf_debugfs_show(struct seq_file *s, void *data)
int rc;
int i;
struct wil6210_priv *wil = s->private;
+ struct wil6210_vif *vif = ndev_to_vif(wil->main_ndev);
struct wmi_notify_req_cmd cmd = {
.interval_usec = 0,
};
@@ -1062,7 +1082,8 @@ static int wil_bf_debugfs_show(struct seq_file *s, void *data)
u32 status;
cmd.cid = i;
- rc = wmi_call(wil, WMI_NOTIFY_REQ_CMDID, &cmd, sizeof(cmd),
+ rc = wmi_call(wil, WMI_NOTIFY_REQ_CMDID, vif->mid,
+ &cmd, sizeof(cmd),
WMI_NOTIFY_REQ_DONE_EVENTID, &reply,
sizeof(reply), 20);
/* if reply is all-0, ignore this CID */
@@ -1155,7 +1176,7 @@ static const struct file_operations fops_temp = {
static int wil_freq_debugfs_show(struct seq_file *s, void *data)
{
struct wil6210_priv *wil = s->private;
- struct wireless_dev *wdev = wil_to_wdev(wil);
+ struct wireless_dev *wdev = wil->main_ndev->ieee80211_ptr;
u16 freq = wdev->chandef.chan ? wdev->chandef.chan->center_freq : 0;
seq_printf(s, "Freq = %d\n", freq);
@@ -1185,6 +1206,8 @@ static int wil_link_debugfs_show(struct seq_file *s, void *data)
for (i = 0; i < ARRAY_SIZE(wil->sta); i++) {
struct wil_sta_info *p = &wil->sta[i];
char *status = "unknown";
+ struct wil6210_vif *vif;
+ u8 mid;
switch (p->status) {
case wil_sta_unused:
@@ -1197,16 +1220,24 @@ static int wil_link_debugfs_show(struct seq_file *s, void *data)
status = "connected";
break;
}
- seq_printf(s, "[%d] %pM %s\n", i, p->addr, status);
+ mid = (p->status != wil_sta_unused) ? p->mid : U8_MAX;
+ seq_printf(s, "[%d][MID %d] %pM %s\n",
+ i, mid, p->addr, status);
- if (p->status == wil_sta_connected) {
- rc = wil_cid_fill_sinfo(wil, i, &sinfo);
+ if (p->status != wil_sta_connected)
+ continue;
+
+ vif = (mid < wil->max_vifs) ? wil->vifs[mid] : NULL;
+ if (vif) {
+ rc = wil_cid_fill_sinfo(vif, i, &sinfo);
if (rc)
return rc;
seq_printf(s, " Tx_mcs = %d\n", sinfo.txrate.mcs);
seq_printf(s, " Rx_mcs = %d\n", sinfo.rxrate.mcs);
seq_printf(s, " SQ = %d\n", sinfo.signal);
+ } else {
+ seq_puts(s, " INVALID MID\n");
}
}
@@ -1229,7 +1260,7 @@ static const struct file_operations fops_link = {
static int wil_info_debugfs_show(struct seq_file *s, void *data)
{
struct wil6210_priv *wil = s->private;
- struct net_device *ndev = wil_to_ndev(wil);
+ struct net_device *ndev = wil->main_ndev;
int is_ac = power_supply_is_system_supplied();
int rx = atomic_xchg(&wil->isr_count_rx, 0);
int tx = atomic_xchg(&wil->isr_count_tx, 0);
@@ -1398,6 +1429,7 @@ __acquires(&p->tid_rx_lock) __releases(&p->tid_rx_lock)
struct wil_sta_info *p = &wil->sta[i];
char *status = "unknown";
u8 aid = 0;
+ u8 mid;
switch (p->status) {
case wil_sta_unused:
@@ -1411,7 +1443,9 @@ __acquires(&p->tid_rx_lock) __releases(&p->tid_rx_lock)
aid = p->aid;
break;
}
- seq_printf(s, "[%d] %pM %s AID %d\n", i, p->addr, status, aid);
+ mid = (p->status != wil_sta_unused) ? p->mid : U8_MAX;
+ seq_printf(s, "[%d] %pM %s MID %d AID %d\n", i, p->addr, status,
+ mid, aid);
if (p->status == wil_sta_connected) {
spin_lock_bh(&p->tid_rx_lock);
@@ -1461,6 +1495,42 @@ static const struct file_operations fops_sta = {
.llseek = seq_lseek,
};
+static int wil_mids_debugfs_show(struct seq_file *s, void *data)
+{
+ struct wil6210_priv *wil = s->private;
+ struct wil6210_vif *vif;
+ struct net_device *ndev;
+ int i;
+
+ mutex_lock(&wil->vif_mutex);
+ for (i = 0; i < wil->max_vifs; i++) {
+ vif = wil->vifs[i];
+
+ if (vif) {
+ ndev = vif_to_ndev(vif);
+ seq_printf(s, "[%d] %pM %s\n", i, ndev->dev_addr,
+ ndev->name);
+ } else {
+ seq_printf(s, "[%d] unused\n", i);
+ }
+ }
+ mutex_unlock(&wil->vif_mutex);
+
+ return 0;
+}
+
+static int wil_mids_seq_open(struct inode *inode, struct file *file)
+{
+ return single_open(file, wil_mids_debugfs_show, inode->i_private);
+}
+
+static const struct file_operations fops_mids = {
+ .open = wil_mids_seq_open,
+ .release = single_release,
+ .read = seq_read,
+ .llseek = seq_lseek,
+};
+
static ssize_t wil_read_file_led_cfg(struct file *file, char __user *user_buf,
size_t count, loff_t *ppos)
{
@@ -1715,6 +1785,7 @@ static const struct {
{"mbox", 0444, &fops_mbox},
{"vrings", 0444, &fops_vring},
{"stations", 0444, &fops_sta},
+ {"mids", 0444, &fops_mids},
{"desc", 0444, &fops_txdesc},
{"bf", 0444, &fops_bf},
{"mem_val", 0644, &fops_memread},
@@ -1773,11 +1844,9 @@ static void wil6210_debugfs_init_isr(struct wil6210_priv *wil,
/* fields in struct wil6210_priv */
static const struct dbg_off dbg_wil_off[] = {
- WIL_FIELD(privacy, 0444, doff_u32),
WIL_FIELD(status[0], 0644, doff_ulong),
WIL_FIELD(hw_version, 0444, doff_x32),
WIL_FIELD(recovery_count, 0444, doff_u32),
- WIL_FIELD(ap_isolate, 0444, doff_u32),
WIL_FIELD(discovery_mode, 0644, doff_u8),
WIL_FIELD(chip_revision, 0444, doff_u8),
WIL_FIELD(abft_len, 0644, doff_u8),
diff --git a/drivers/net/wireless/ath/wil6210/ethtool.c b/drivers/net/wireless/ath/wil6210/ethtool.c
index 66200f616a37..e7ff41e623d2 100644
--- a/drivers/net/wireless/ath/wil6210/ethtool.c
+++ b/drivers/net/wireless/ath/wil6210/ethtool.c
@@ -1,5 +1,6 @@
/*
* Copyright (c) 2014,2017 Qualcomm Atheros, Inc.
+ * Copyright (c) 2018, The Linux Foundation. All rights reserved.
*
* Permission to use, copy, modify, and/or distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
@@ -74,12 +75,13 @@ static int wil_ethtoolops_set_coalesce(struct net_device *ndev,
struct ethtool_coalesce *cp)
{
struct wil6210_priv *wil = ndev_to_wil(ndev);
+ struct wireless_dev *wdev = ndev->ieee80211_ptr;
int ret;
wil_dbg_misc(wil, "ethtoolops_set_coalesce: rx %d usec, tx %d usec\n",
cp->rx_coalesce_usecs, cp->tx_coalesce_usecs);
- if (wil->wdev->iftype == NL80211_IFTYPE_MONITOR) {
+ if (wdev->iftype == NL80211_IFTYPE_MONITOR) {
wil_dbg_misc(wil, "No IRQ coalescing in monitor mode\n");
return -EINVAL;
}
diff --git a/drivers/net/wireless/ath/wil6210/fw.h b/drivers/net/wireless/ath/wil6210/fw.h
index 2c7b24f61587..3e7a28045cab 100644
--- a/drivers/net/wireless/ath/wil6210/fw.h
+++ b/drivers/net/wireless/ath/wil6210/fw.h
@@ -14,6 +14,8 @@
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
+#ifndef __WIL_FW_H__
+#define __WIL_FW_H__
#define WIL_FW_SIGNATURE (0x36323130) /* '0126' */
#define WIL_FW_FMT_VERSION (1) /* format version driver supports */
@@ -71,7 +73,39 @@ struct wil_fw_record_capabilities { /* type == wil_fw_type_comment */
struct wil_fw_record_comment_hdr hdr;
/* capabilities (variable size), see enum wmi_fw_capability */
u8 capabilities[0];
-};
+} __packed;
+
+/* FW VIF concurrency encoded inside a comment record
+ * Format is similar to wiphy->iface_combinations
+ */
+#define WIL_FW_CONCURRENCY_MAGIC (0xfedccdef)
+#define WIL_FW_CONCURRENCY_REC_VER 1
+struct wil_fw_concurrency_limit {
+ __le16 max; /* maximum number of interfaces of these types */
+ __le16 types; /* interface types (bit mask of enum nl80211_iftype) */
+} __packed;
+
+struct wil_fw_concurrency_combo {
+ u8 n_limits; /* number of wil_fw_concurrency_limit entries */
+ u8 max_interfaces; /* max number of concurrent interfaces allowed */
+ u8 n_diff_channels; /* total number of different channels allowed */
+ u8 same_bi; /* for APs, 1 if all APs must have same BI */
+ /* keep last - concurrency limits, variable size by n_limits */
+ struct wil_fw_concurrency_limit limits[0];
+} __packed;
+
+struct wil_fw_record_concurrency { /* type == wil_fw_type_comment */
+ /* identifies concurrency record */
+ __le32 magic;
+ /* structure version, currently always 1 */
+ u8 version;
+ /* maximum number of supported MIDs _in addition_ to MID 0 */
+ u8 n_mids;
+ /* number of concurrency combinations that follow */
+ __le16 n_combos;
+ /* keep last - combinations, variable size by n_combos */
+ struct wil_fw_concurrency_combo combos[0];
+} __packed;
/* brd file info encoded inside a comment record */
#define WIL_BRD_FILE_MAGIC (0xabcddcbb)
@@ -175,3 +209,5 @@ struct wil_fw_record_gateway_data4 { /* type == wil_fw_type_gateway_data4 */
__le32 command;
struct wil_fw_data_gw4 data[0]; /* total size [data_size], see above */
} __packed;
+
+#endif /* __WIL_FW_H__ */
diff --git a/drivers/net/wireless/ath/wil6210/fw_inc.c b/drivers/net/wireless/ath/wil6210/fw_inc.c
index 914c0106e94b..718161b829c2 100644
--- a/drivers/net/wireless/ath/wil6210/fw_inc.c
+++ b/drivers/net/wireless/ath/wil6210/fw_inc.c
@@ -136,8 +136,8 @@ fw_handle_capabilities(struct wil6210_priv *wil, const void *data,
size_t capa_size;
if (size < sizeof(*rec)) {
- wil_hex_dump_fw("", DUMP_PREFIX_OFFSET, 16, 1,
- data, size, true);
+ wil_err_fw(wil, "capabilities record too short: %zu\n", size);
+ /* let the FW load anyway */
return 0;
}
@@ -158,8 +158,7 @@ fw_handle_brd_file(struct wil6210_priv *wil, const void *data,
const struct wil_fw_record_brd_file *rec = data;
if (size < sizeof(*rec)) {
- wil_hex_dump_fw("", DUMP_PREFIX_OFFSET, 16, 1,
- data, size, true);
+ wil_err_fw(wil, "brd_file record too short: %zu\n", size);
return 0;
}
@@ -173,6 +172,44 @@ fw_handle_brd_file(struct wil6210_priv *wil, const void *data,
}
static int
+fw_handle_concurrency(struct wil6210_priv *wil, const void *data,
+ size_t size)
+{
+ const struct wil_fw_record_concurrency *rec = data;
+ const struct wil_fw_concurrency_combo *combo;
+ const struct wil_fw_concurrency_limit *limit;
+ size_t remain, lsize;
+ int i, n_combos;
+
+ if (size < sizeof(*rec)) {
+ wil_err_fw(wil, "concurrency record too short: %zu\n", size);
+ /* continue, let the FW load anyway */
+ return 0;
+ }
+
+ n_combos = le16_to_cpu(rec->n_combos);
+ remain = size - offsetof(struct wil_fw_record_concurrency, combos);
+ combo = rec->combos;
+ for (i = 0; i < n_combos; i++) {
+ if (remain < sizeof(*combo))
+ goto out_short;
+ remain -= sizeof(*combo);
+ limit = combo->limits;
+ lsize = combo->n_limits * sizeof(*limit);
+ if (remain < lsize)
+ goto out_short;
+ remain -= lsize;
+ limit += combo->n_limits;
+ combo = (struct wil_fw_concurrency_combo *)limit;
+ }
+
+ return wil_cfg80211_iface_combinations_from_fw(wil, rec);
+out_short:
+ wil_err_fw(wil, "concurrency record truncated\n");
+ return 0;
+}
+
+static int
fw_handle_comment(struct wil6210_priv *wil, const void *data,
size_t size)
{
@@ -194,6 +231,13 @@ fw_handle_comment(struct wil6210_priv *wil, const void *data,
wil_dbg_fw(wil, "magic is WIL_BRD_FILE_MAGIC\n");
rc = fw_handle_brd_file(wil, data, size);
break;
+ case WIL_FW_CONCURRENCY_MAGIC:
+ wil_dbg_fw(wil, "magic is WIL_FW_CONCURRENCY_MAGIC\n");
+ rc = fw_handle_concurrency(wil, data, size);
+ break;
+ default:
+ wil_hex_dump_fw("", DUMP_PREFIX_OFFSET, 16, 1,
+ data, size, true);
}
return rc;
diff --git a/drivers/net/wireless/ath/wil6210/interrupt.c b/drivers/net/wireless/ath/wil6210/interrupt.c
index 1835187ea075..84e9840c1752 100644
--- a/drivers/net/wireless/ath/wil6210/interrupt.c
+++ b/drivers/net/wireless/ath/wil6210/interrupt.c
@@ -127,7 +127,7 @@ void wil6210_unmask_irq_tx(struct wil6210_priv *wil)
void wil6210_unmask_irq_rx(struct wil6210_priv *wil)
{
- bool unmask_rx_htrsh = test_bit(wil_status_fwconnected, wil->status);
+ bool unmask_rx_htrsh = atomic_read(&wil->connected_vifs) > 0;
wil_w(wil, RGF_DMA_EP_RX_ICR + offsetof(struct RGF_ICR, IMC),
unmask_rx_htrsh ? WIL6210_IMC_RX : WIL6210_IMC_RX_NO_RX_HTRSH);
@@ -188,12 +188,14 @@ void wil_unmask_irq(struct wil6210_priv *wil)
void wil_configure_interrupt_moderation(struct wil6210_priv *wil)
{
+ struct wireless_dev *wdev = wil->main_ndev->ieee80211_ptr;
+
wil_dbg_irq(wil, "configure_interrupt_moderation\n");
/* disable interrupt moderation for monitor
* to get better timestamp precision
*/
- if (wil->wdev->iftype == NL80211_IFTYPE_MONITOR)
+ if (wdev->iftype == NL80211_IFTYPE_MONITOR)
return;
/* Disable and clear tx counter before (re)configuration */
@@ -340,7 +342,7 @@ static irqreturn_t wil6210_irq_tx(int irq, void *cookie)
static void wil_notify_fw_error(struct wil6210_priv *wil)
{
- struct device *dev = &wil_to_ndev(wil)->dev;
+ struct device *dev = &wil->main_ndev->dev;
char *envp[3] = {
[0] = "SOURCE=wil6210",
[1] = "EVENT=FW_ERROR",
diff --git a/drivers/net/wireless/ath/wil6210/main.c b/drivers/net/wireless/ath/wil6210/main.c
index 0c61a6c13991..a4b413e8d55a 100644
--- a/drivers/net/wireless/ath/wil6210/main.c
+++ b/drivers/net/wireless/ath/wil6210/main.c
@@ -160,24 +160,34 @@ void wil_memcpy_toio_32(volatile void __iomem *dst, const void *src,
}
}
-static void wil_disconnect_cid(struct wil6210_priv *wil, int cid,
+static void wil_disconnect_cid(struct wil6210_vif *vif, int cid,
u16 reason_code, bool from_event)
__acquires(&sta->tid_rx_lock) __releases(&sta->tid_rx_lock)
{
uint i;
- struct net_device *ndev = wil_to_ndev(wil);
- struct wireless_dev *wdev = wil->wdev;
+ struct wil6210_priv *wil = vif_to_wil(vif);
+ struct net_device *ndev = vif_to_ndev(vif);
+ struct wireless_dev *wdev = vif_to_wdev(vif);
struct wil_sta_info *sta = &wil->sta[cid];
might_sleep();
- wil_dbg_misc(wil, "disconnect_cid: CID %d, status %d\n",
- cid, sta->status);
+ wil_dbg_misc(wil, "disconnect_cid: CID %d, MID %d, status %d\n",
+ cid, sta->mid, sta->status);
/* inform upper/lower layers */
if (sta->status != wil_sta_unused) {
+ if (vif->mid != sta->mid) {
+ wil_err(wil, "STA MID mismatch with VIF MID(%d)\n",
+ vif->mid);
+ /* let FW override sta->mid but be more strict with
+ * user space requests
+ */
+ if (!from_event)
+ return;
+ }
if (!from_event) {
bool del_sta = (wdev->iftype == NL80211_IFTYPE_AP) ?
disable_ap_sme : false;
- wmi_disconnect_sta(wil, sta->addr, reason_code,
+ wmi_disconnect_sta(vif, sta->addr, reason_code,
true, del_sta);
}
@@ -191,6 +201,7 @@ __acquires(&sta->tid_rx_lock) __releases(&sta->tid_rx_lock)
break;
}
sta->status = wil_sta_unused;
+ sta->mid = U8_MAX;
}
/* reorder buffers */
for (i = 0; i < WIL_STA_TID_NUM; i++) {
@@ -216,28 +227,33 @@ __acquires(&sta->tid_rx_lock) __releases(&sta->tid_rx_lock)
memset(&sta->stats, 0, sizeof(sta->stats));
}
-static bool wil_is_connected(struct wil6210_priv *wil)
+static bool wil_vif_is_connected(struct wil6210_priv *wil, u8 mid)
{
int i;
for (i = 0; i < ARRAY_SIZE(wil->sta); i++) {
- if (wil->sta[i].status == wil_sta_connected)
+ if (wil->sta[i].mid == mid &&
+ wil->sta[i].status == wil_sta_connected)
return true;
}
return false;
}
-static void _wil6210_disconnect(struct wil6210_priv *wil, const u8 *bssid,
+static void _wil6210_disconnect(struct wil6210_vif *vif, const u8 *bssid,
u16 reason_code, bool from_event)
{
+ struct wil6210_priv *wil = vif_to_wil(vif);
int cid = -ENOENT;
- struct net_device *ndev = wil_to_ndev(wil);
- struct wireless_dev *wdev = wil->wdev;
+ struct net_device *ndev;
+ struct wireless_dev *wdev;
- if (unlikely(!ndev))
+ if (unlikely(!vif))
return;
+ ndev = vif_to_ndev(vif);
+ wdev = vif_to_wdev(vif);
+
might_sleep();
wil_info(wil, "bssid=%pM, reason=%d, ev%s\n", bssid,
reason_code, from_event ? "+" : "-");
@@ -254,48 +270,51 @@ static void _wil6210_disconnect(struct wil6210_priv *wil, const u8 *bssid,
*/
if (bssid && !is_broadcast_ether_addr(bssid) &&
!ether_addr_equal_unaligned(ndev->dev_addr, bssid)) {
- cid = wil_find_cid(wil, bssid);
+ cid = wil_find_cid(wil, vif->mid, bssid);
wil_dbg_misc(wil, "Disconnect %pM, CID=%d, reason=%d\n",
bssid, cid, reason_code);
if (cid >= 0) /* disconnect 1 peer */
- wil_disconnect_cid(wil, cid, reason_code, from_event);
+ wil_disconnect_cid(vif, cid, reason_code, from_event);
} else { /* all */
wil_dbg_misc(wil, "Disconnect all\n");
for (cid = 0; cid < WIL6210_MAX_CID; cid++)
- wil_disconnect_cid(wil, cid, reason_code, from_event);
+ wil_disconnect_cid(vif, cid, reason_code, from_event);
}
/* link state */
switch (wdev->iftype) {
case NL80211_IFTYPE_STATION:
case NL80211_IFTYPE_P2P_CLIENT:
- wil_bcast_fini(wil);
- wil_update_net_queues_bh(wil, NULL, true);
+ wil_bcast_fini(vif);
+ wil_update_net_queues_bh(wil, vif, NULL, true);
netif_carrier_off(ndev);
- wil6210_bus_request(wil, WIL_DEFAULT_BUS_REQUEST_KBPS);
+ if (!wil_has_other_active_ifaces(wil, ndev, false, true))
+ wil6210_bus_request(wil, WIL_DEFAULT_BUS_REQUEST_KBPS);
- if (test_bit(wil_status_fwconnected, wil->status)) {
- clear_bit(wil_status_fwconnected, wil->status);
+ if (test_and_clear_bit(wil_vif_fwconnected, vif->status)) {
+ atomic_dec(&wil->connected_vifs);
cfg80211_disconnected(ndev, reason_code,
NULL, 0,
- wil->locally_generated_disc,
+ vif->locally_generated_disc,
GFP_KERNEL);
- wil->locally_generated_disc = false;
- } else if (test_bit(wil_status_fwconnecting, wil->status)) {
+ vif->locally_generated_disc = false;
+ } else if (test_bit(wil_vif_fwconnecting, vif->status)) {
cfg80211_connect_result(ndev, bssid, NULL, 0, NULL, 0,
WLAN_STATUS_UNSPECIFIED_FAILURE,
GFP_KERNEL);
- wil->bss = NULL;
+ vif->bss = NULL;
}
- clear_bit(wil_status_fwconnecting, wil->status);
+ clear_bit(wil_vif_fwconnecting, vif->status);
break;
case NL80211_IFTYPE_AP:
case NL80211_IFTYPE_P2P_GO:
- if (!wil_is_connected(wil)) {
- wil_update_net_queues_bh(wil, NULL, true);
- clear_bit(wil_status_fwconnected, wil->status);
+ if (!wil_vif_is_connected(wil, vif->mid)) {
+ wil_update_net_queues_bh(wil, vif, NULL, true);
+ if (test_and_clear_bit(wil_vif_fwconnected,
+ vif->status))
+ atomic_dec(&wil->connected_vifs);
} else {
- wil_update_net_queues_bh(wil, NULL, false);
+ wil_update_net_queues_bh(wil, vif, NULL, false);
}
break;
default:
@@ -303,26 +322,27 @@ static void _wil6210_disconnect(struct wil6210_priv *wil, const u8 *bssid,
}
}
-static void wil_disconnect_worker(struct work_struct *work)
+void wil_disconnect_worker(struct work_struct *work)
{
- struct wil6210_priv *wil = container_of(work,
- struct wil6210_priv, disconnect_worker);
- struct net_device *ndev = wil_to_ndev(wil);
+ struct wil6210_vif *vif = container_of(work,
+ struct wil6210_vif, disconnect_worker);
+ struct wil6210_priv *wil = vif_to_wil(vif);
+ struct net_device *ndev = vif_to_ndev(vif);
int rc;
struct {
struct wmi_cmd_hdr wmi;
struct wmi_disconnect_event evt;
} __packed reply;
- if (test_bit(wil_status_fwconnected, wil->status))
+ if (test_bit(wil_vif_fwconnected, vif->status))
/* connect succeeded after all */
return;
- if (!test_bit(wil_status_fwconnecting, wil->status))
+ if (!test_bit(wil_vif_fwconnecting, vif->status))
/* already disconnected */
return;
- rc = wmi_call(wil, WMI_DISCONNECT_CMDID, NULL, 0,
+ rc = wmi_call(wil, WMI_DISCONNECT_CMDID, vif->mid, NULL, 0,
WMI_DISCONNECT_EVENTID, &reply, sizeof(reply),
WIL6210_DISCONNECT_TO_MS);
if (rc) {
@@ -330,35 +350,11 @@ static void wil_disconnect_worker(struct work_struct *work)
return;
}
- wil_update_net_queues_bh(wil, NULL, true);
+ wil_update_net_queues_bh(wil, vif, NULL, true);
netif_carrier_off(ndev);
cfg80211_connect_result(ndev, NULL, NULL, 0, NULL, 0,
WLAN_STATUS_UNSPECIFIED_FAILURE, GFP_KERNEL);
- clear_bit(wil_status_fwconnecting, wil->status);
-}
-
-static void wil_connect_timer_fn(struct timer_list *t)
-{
- struct wil6210_priv *wil = from_timer(wil, t, connect_timer);
- bool q;
-
- wil_err(wil, "Connect timeout detected, disconnect station\n");
-
- /* reschedule to thread context - disconnect won't
- * run from atomic context.
- * queue on wmi_wq to prevent race with connect event.
- */
- q = queue_work(wil->wmi_wq, &wil->disconnect_worker);
- wil_dbg_wmi(wil, "queue_work of disconnect_worker -> %d\n", q);
-}
-
-static void wil_scan_timer_fn(struct timer_list *t)
-{
- struct wil6210_priv *wil = from_timer(wil, t, scan_timer);
-
- clear_bit(wil_status_fwready, wil->status);
- wil_err(wil, "Scan timeout detected, start fw error recovery\n");
- wil_fw_error_recovery(wil);
+ clear_bit(wil_vif_fwconnecting, vif->status);
}
static int wil_wait_for_recovery(struct wil6210_priv *wil)
@@ -394,12 +390,12 @@ static void wil_fw_error_worker(struct work_struct *work)
{
struct wil6210_priv *wil = container_of(work, struct wil6210_priv,
fw_error_worker);
- struct wireless_dev *wdev = wil->wdev;
- struct net_device *ndev = wil_to_ndev(wil);
+ struct net_device *ndev = wil->main_ndev;
+ struct wireless_dev *wdev = ndev->ieee80211_ptr;
wil_dbg_misc(wil, "fw error worker\n");
- if (!(ndev->flags & IFF_UP)) {
+ if (!ndev || !(ndev->flags & IFF_UP)) {
wil_info(wil, "No recovery - interface is down\n");
return;
}
@@ -429,6 +425,10 @@ static void wil_fw_error_worker(struct work_struct *work)
return;
mutex_lock(&wil->mutex);
+ /* Needs adaptation for multiple VIFs
+ * need to go over all VIFs and consider the appropriate
+ * recovery.
+ */
switch (wdev->iftype) {
case NL80211_IFTYPE_STATION:
case NL80211_IFTYPE_P2P_CLIENT:
@@ -461,8 +461,9 @@ static int wil_find_free_vring(struct wil6210_priv *wil)
return -EINVAL;
}
-int wil_tx_init(struct wil6210_priv *wil, int cid)
+int wil_tx_init(struct wil6210_vif *vif, int cid)
{
+ struct wil6210_priv *wil = vif_to_wil(vif);
int rc = -EINVAL, ringid;
if (cid < 0) {
@@ -475,21 +476,22 @@ int wil_tx_init(struct wil6210_priv *wil, int cid)
goto out;
}
- wil_dbg_wmi(wil, "Configure for connection CID %d vring %d\n",
- cid, ringid);
+ wil_dbg_wmi(wil, "Configure for connection CID %d MID %d vring %d\n",
+ cid, vif->mid, ringid);
- rc = wil_vring_init_tx(wil, ringid, 1 << tx_ring_order, cid, 0);
+ rc = wil_vring_init_tx(vif, ringid, 1 << tx_ring_order, cid, 0);
if (rc)
- wil_err(wil, "wil_vring_init_tx for CID %d vring %d failed\n",
- cid, ringid);
+ wil_err(wil, "init TX for CID %d MID %d vring %d failed\n",
+ cid, vif->mid, ringid);
out:
return rc;
}
-int wil_bcast_init(struct wil6210_priv *wil)
+int wil_bcast_init(struct wil6210_vif *vif)
{
- int ri = wil->bcast_vring, rc;
+ struct wil6210_priv *wil = vif_to_wil(vif);
+ int ri = vif->bcast_vring, rc;
if ((ri >= 0) && wil->vring_tx[ri].va)
return 0;
@@ -498,25 +500,38 @@ int wil_bcast_init(struct wil6210_priv *wil)
if (ri < 0)
return ri;
- wil->bcast_vring = ri;
- rc = wil_vring_init_bcast(wil, ri, 1 << bcast_ring_order);
+ vif->bcast_vring = ri;
+ rc = wil_vring_init_bcast(vif, ri, 1 << bcast_ring_order);
if (rc)
- wil->bcast_vring = -1;
+ vif->bcast_vring = -1;
return rc;
}
-void wil_bcast_fini(struct wil6210_priv *wil)
+void wil_bcast_fini(struct wil6210_vif *vif)
{
- int ri = wil->bcast_vring;
+ struct wil6210_priv *wil = vif_to_wil(vif);
+ int ri = vif->bcast_vring;
if (ri < 0)
return;
- wil->bcast_vring = -1;
+ vif->bcast_vring = -1;
wil_vring_fini_tx(wil, ri);
}
+void wil_bcast_fini_all(struct wil6210_priv *wil)
+{
+ int i;
+ struct wil6210_vif *vif;
+
+ for (i = 0; i < wil->max_vifs; i++) {
+ vif = wil->vifs[i];
+ if (vif)
+ wil_bcast_fini(vif);
+ }
+}
+
int wil_priv_init(struct wil6210_priv *wil)
{
uint i;
@@ -524,38 +539,29 @@ int wil_priv_init(struct wil6210_priv *wil)
wil_dbg_misc(wil, "priv_init\n");
memset(wil->sta, 0, sizeof(wil->sta));
- for (i = 0; i < WIL6210_MAX_CID; i++)
+ for (i = 0; i < WIL6210_MAX_CID; i++) {
spin_lock_init(&wil->sta[i].tid_rx_lock);
+ wil->sta[i].mid = U8_MAX;
+ }
for (i = 0; i < WIL6210_MAX_TX_RINGS; i++)
spin_lock_init(&wil->vring_tx_data[i].lock);
mutex_init(&wil->mutex);
+ mutex_init(&wil->vif_mutex);
mutex_init(&wil->wmi_mutex);
- mutex_init(&wil->probe_client_mutex);
- mutex_init(&wil->p2p_wdev_mutex);
mutex_init(&wil->halp.lock);
init_completion(&wil->wmi_ready);
init_completion(&wil->wmi_call);
init_completion(&wil->halp.comp);
- wil->bcast_vring = -1;
- timer_setup(&wil->connect_timer, wil_connect_timer_fn, 0);
- timer_setup(&wil->scan_timer, wil_scan_timer_fn, 0);
- timer_setup(&wil->p2p.discovery_timer, wil_p2p_discovery_timer_fn, 0);
-
- INIT_WORK(&wil->disconnect_worker, wil_disconnect_worker);
INIT_WORK(&wil->wmi_event_worker, wmi_event_worker);
INIT_WORK(&wil->fw_error_worker, wil_fw_error_worker);
- INIT_WORK(&wil->probe_client_worker, wil_probe_client_worker);
- INIT_WORK(&wil->p2p.delayed_listen_work, wil_p2p_delayed_listen_work);
INIT_LIST_HEAD(&wil->pending_wmi_ev);
- INIT_LIST_HEAD(&wil->probe_client_pending);
spin_lock_init(&wil->wmi_ev_lock);
spin_lock_init(&wil->net_queue_lock);
- wil->net_queue_stopped = 1;
init_waitqueue_head(&wil->wq);
wil->wmi_wq = create_singlethread_workqueue(WIL_NAME "_wmi");
@@ -582,6 +588,9 @@ int wil_priv_init(struct wil6210_priv *wil)
memset(&wil->suspend_stats, 0, sizeof(wil->suspend_stats));
wil->vring_idle_trsh = 16;
+ wil->reply_mid = U8_MAX;
+ wil->max_vifs = 1;
+
return 0;
out_wmi_wq:
@@ -600,7 +609,7 @@ void wil6210_bus_request(struct wil6210_priv *wil, u32 kbps)
/**
* wil6210_disconnect - disconnect one connection
- * @wil: driver context
+ * @vif: virtual interface context
* @bssid: peer to disconnect, NULL to disconnect all
* @reason_code: Reason code for the Disassociation frame
* @from_event: whether is invoked from FW event handler
@@ -608,13 +617,15 @@ void wil6210_bus_request(struct wil6210_priv *wil, u32 kbps)
* Disconnect and release associated resources. If invoked not from the
* FW event handler, issue WMI command(s) to trigger MAC disconnect.
*/
-void wil6210_disconnect(struct wil6210_priv *wil, const u8 *bssid,
+void wil6210_disconnect(struct wil6210_vif *vif, const u8 *bssid,
u16 reason_code, bool from_event)
{
+ struct wil6210_priv *wil = vif_to_wil(vif);
+
wil_dbg_misc(wil, "disconnect\n");
- del_timer_sync(&wil->connect_timer);
- _wil6210_disconnect(wil, bssid, reason_code, from_event);
+ del_timer_sync(&vif->connect_timer);
+ _wil6210_disconnect(vif, bssid, reason_code, from_event);
}
void wil_priv_deinit(struct wil6210_priv *wil)
@@ -622,18 +633,8 @@ void wil_priv_deinit(struct wil6210_priv *wil)
wil_dbg_misc(wil, "priv_deinit\n");
wil_set_recovery_state(wil, fw_recovery_idle);
- del_timer_sync(&wil->scan_timer);
- del_timer_sync(&wil->p2p.discovery_timer);
- cancel_work_sync(&wil->disconnect_worker);
cancel_work_sync(&wil->fw_error_worker);
- cancel_work_sync(&wil->p2p.discovery_expired_work);
- cancel_work_sync(&wil->p2p.delayed_listen_work);
- mutex_lock(&wil->mutex);
- wil6210_disconnect(wil, NULL, WLAN_REASON_DEAUTH_LEAVING, false);
- mutex_unlock(&wil->mutex);
wmi_event_flush(wil);
- wil_probe_client_flush(wil);
- cancel_work_sync(&wil->probe_client_worker);
destroy_workqueue(wil->wq_service);
destroy_workqueue(wil->wmi_wq);
}
@@ -715,7 +716,7 @@ static void wil_bl_prepare_halt(struct wil6210_priv *wil)
offsetof(struct bl_dedicated_registers_v0,
boot_loader_struct_version));
if (!tmp) {
- wil_dbg_misc(wil, "old BL, skipping halt preperation\n");
+ wil_dbg_misc(wil, "old BL, skipping halt preparation\n");
return;
}
@@ -943,7 +944,7 @@ void wil_mbox_ring_le2cpus(struct wil6210_mbox_ring *r)
static int wil_get_bl_info(struct wil6210_priv *wil)
{
- struct net_device *ndev = wil_to_ndev(wil);
+ struct net_device *ndev = wil->main_ndev;
struct wiphy *wiphy = wil_to_wiphy(wil);
union {
struct bl_dedicated_registers_v0 bl0;
@@ -1035,7 +1036,7 @@ static void wil_bl_crash_info(struct wil6210_priv *wil, bool is_err)
static int wil_get_otp_info(struct wil6210_priv *wil)
{
- struct net_device *ndev = wil_to_ndev(wil);
+ struct net_device *ndev = wil->main_ndev;
struct wiphy *wiphy = wil_to_wiphy(wil);
u8 mac[8];
@@ -1069,31 +1070,46 @@ static int wil_wait_for_fw_ready(struct wil6210_priv *wil)
return 0;
}
-void wil_abort_scan(struct wil6210_priv *wil, bool sync)
+void wil_abort_scan(struct wil6210_vif *vif, bool sync)
{
+ struct wil6210_priv *wil = vif_to_wil(vif);
int rc;
struct cfg80211_scan_info info = {
.aborted = true,
};
- lockdep_assert_held(&wil->p2p_wdev_mutex);
+ lockdep_assert_held(&wil->vif_mutex);
- if (!wil->scan_request)
+ if (!vif->scan_request)
return;
- wil_dbg_misc(wil, "Abort scan_request 0x%p\n", wil->scan_request);
- del_timer_sync(&wil->scan_timer);
- mutex_unlock(&wil->p2p_wdev_mutex);
- rc = wmi_abort_scan(wil);
+ wil_dbg_misc(wil, "Abort scan_request 0x%p\n", vif->scan_request);
+ del_timer_sync(&vif->scan_timer);
+ mutex_unlock(&wil->vif_mutex);
+ rc = wmi_abort_scan(vif);
if (!rc && sync)
- wait_event_interruptible_timeout(wil->wq, !wil->scan_request,
+ wait_event_interruptible_timeout(wil->wq, !vif->scan_request,
msecs_to_jiffies(
WAIT_FOR_SCAN_ABORT_MS));
- mutex_lock(&wil->p2p_wdev_mutex);
- if (wil->scan_request) {
- cfg80211_scan_done(wil->scan_request, &info);
- wil->scan_request = NULL;
+ mutex_lock(&wil->vif_mutex);
+ if (vif->scan_request) {
+ cfg80211_scan_done(vif->scan_request, &info);
+ vif->scan_request = NULL;
+ }
+}
+
+void wil_abort_scan_all_vifs(struct wil6210_priv *wil, bool sync)
+{
+ int i;
+
+ lockdep_assert_held(&wil->vif_mutex);
+
+ for (i = 0; i < wil->max_vifs; i++) {
+ struct wil6210_vif *vif = wil->vifs[i];
+
+ if (vif)
+ wil_abort_scan(vif, sync);
}
}
@@ -1138,6 +1154,34 @@ static void wil_pre_fw_config(struct wil6210_priv *wil)
}
}
+static int wil_restore_vifs(struct wil6210_priv *wil)
+{
+ struct wil6210_vif *vif;
+ struct net_device *ndev;
+ struct wireless_dev *wdev;
+ int i, rc;
+
+ for (i = 0; i < wil->max_vifs; i++) {
+ vif = wil->vifs[i];
+ if (!vif)
+ continue;
+ vif->ap_isolate = 0;
+ if (vif->mid) {
+ ndev = vif_to_ndev(vif);
+ wdev = vif_to_wdev(vif);
+ rc = wmi_port_allocate(wil, vif->mid, ndev->dev_addr,
+ wdev->iftype);
+ if (rc) {
+ wil_err(wil, "fail to restore VIF %d type %d, rc %d\n",
+ i, wdev->iftype, rc);
+ return rc;
+ }
+ }
+ }
+
+ return 0;
+}
+
/*
* We reset all the structures, and we reset the UMAC.
* After calling this routine, you're expected to reload
@@ -1145,9 +1189,10 @@ static void wil_pre_fw_config(struct wil6210_priv *wil)
*/
int wil_reset(struct wil6210_priv *wil, bool load_fw)
{
- int rc;
+ int rc, i;
unsigned long status_flags = BIT(wil_status_resetting);
int no_flash;
+ struct wil6210_vif *vif;
wil_dbg_misc(wil, "reset\n");
@@ -1158,7 +1203,7 @@ int wil_reset(struct wil6210_priv *wil, bool load_fw)
static const u8 mac[ETH_ALEN] = {
0x00, 0xde, 0xad, 0x12, 0x34, 0x56,
};
- struct net_device *ndev = wil_to_ndev(wil);
+ struct net_device *ndev = wil->main_ndev;
ether_addr_copy(ndev->perm_addr, mac);
ether_addr_copy(ndev->dev_addr, ndev->perm_addr);
@@ -1196,17 +1241,23 @@ int wil_reset(struct wil6210_priv *wil, bool load_fw)
goto out;
}
- cancel_work_sync(&wil->disconnect_worker);
- wil6210_disconnect(wil, NULL, WLAN_REASON_DEAUTH_LEAVING, false);
- wil_bcast_fini(wil);
+ mutex_lock(&wil->vif_mutex);
+ wil_abort_scan_all_vifs(wil, false);
+ mutex_unlock(&wil->vif_mutex);
+
+ for (i = 0; i < wil->max_vifs; i++) {
+ vif = wil->vifs[i];
+ if (vif) {
+ cancel_work_sync(&vif->disconnect_worker);
+ wil6210_disconnect(vif, NULL,
+ WLAN_REASON_DEAUTH_LEAVING, false);
+ }
+ }
+ wil_bcast_fini_all(wil);
/* Disable device led before reset*/
wmi_led_cfg(wil, false);
- mutex_lock(&wil->p2p_wdev_mutex);
- wil_abort_scan(wil, false);
- mutex_unlock(&wil->p2p_wdev_mutex);
-
/* prevent NAPI from being scheduled and prevent wmi commands */
mutex_lock(&wil->wmi_mutex);
if (test_bit(wil_status_suspending, wil->status))
@@ -1276,7 +1327,6 @@ int wil_reset(struct wil6210_priv *wil, bool load_fw)
}
/* init after reset */
- wil->ap_isolate = 0;
reinit_completion(&wil->wmi_ready);
reinit_completion(&wil->wmi_call);
reinit_completion(&wil->halp.comp);
@@ -1299,6 +1349,12 @@ int wil_reset(struct wil6210_priv *wil, bool load_fw)
return rc;
}
+ rc = wil_restore_vifs(wil);
+ if (rc) {
+ wil_err(wil, "failed to restore vifs, rc %d\n", rc);
+ return rc;
+ }
+
wil_collect_fw_info(wil);
if (wil->ps_profile != WMI_PS_PROFILE_TYPE_DEFAULT)
@@ -1337,8 +1393,8 @@ void wil_fw_error_recovery(struct wil6210_priv *wil)
int __wil_up(struct wil6210_priv *wil)
{
- struct net_device *ndev = wil_to_ndev(wil);
- struct wireless_dev *wdev = wil->wdev;
+ struct net_device *ndev = wil->main_ndev;
+ struct wireless_dev *wdev = ndev->ieee80211_ptr;
int rc;
WARN_ON(!mutex_is_locked(&wil->mutex));
@@ -1420,10 +1476,10 @@ int __wil_down(struct wil6210_priv *wil)
}
wil_enable_irq(wil);
- mutex_lock(&wil->p2p_wdev_mutex);
+ mutex_lock(&wil->vif_mutex);
wil_p2p_stop_radio_operations(wil);
- wil_abort_scan(wil, false);
- mutex_unlock(&wil->p2p_wdev_mutex);
+ wil_abort_scan_all_vifs(wil, false);
+ mutex_unlock(&wil->vif_mutex);
return wil_reset(wil, false);
}
@@ -1442,13 +1498,14 @@ int wil_down(struct wil6210_priv *wil)
return rc;
}
-int wil_find_cid(struct wil6210_priv *wil, const u8 *mac)
+int wil_find_cid(struct wil6210_priv *wil, u8 mid, const u8 *mac)
{
int i;
int rc = -ENOENT;
for (i = 0; i < ARRAY_SIZE(wil->sta); i++) {
- if ((wil->sta[i].status != wil_sta_unused) &&
+ if (wil->sta[i].mid == mid &&
+ wil->sta[i].status != wil_sta_unused &&
ether_addr_equal(wil->sta[i].addr, mac)) {
rc = i;
break;
diff --git a/drivers/net/wireless/ath/wil6210/netdev.c b/drivers/net/wireless/ath/wil6210/netdev.c
index 7ba4e0af8f57..05e9408e7ea3 100644
--- a/drivers/net/wireless/ath/wil6210/netdev.c
+++ b/drivers/net/wireless/ath/wil6210/netdev.c
@@ -1,5 +1,6 @@
/*
* Copyright (c) 2012-2017 Qualcomm Atheros, Inc.
+ * Copyright (c) 2018, The Linux Foundation. All rights reserved.
*
* Permission to use, copy, modify, and/or distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
@@ -15,13 +16,41 @@
*/
#include <linux/etherdevice.h>
+#include <linux/rtnetlink.h>
#include "wil6210.h"
#include "txrx.h"
+bool wil_has_other_active_ifaces(struct wil6210_priv *wil,
+ struct net_device *ndev, bool up, bool ok)
+{
+ int i;
+ struct wil6210_vif *vif;
+ struct net_device *ndev_i;
+
+ for (i = 0; i < wil->max_vifs; i++) {
+ vif = wil->vifs[i];
+ if (vif) {
+ ndev_i = vif_to_ndev(vif);
+ if (ndev_i != ndev)
+ if ((up && (ndev_i->flags & IFF_UP)) ||
+ (ok && netif_carrier_ok(ndev_i)))
+ return true;
+ }
+ }
+
+ return false;
+}
+
+bool wil_has_active_ifaces(struct wil6210_priv *wil, bool up, bool ok)
+{
+ /* use NULL ndev argument to check all interfaces */
+ return wil_has_other_active_ifaces(wil, NULL, up, ok);
+}
+
static int wil_open(struct net_device *ndev)
{
struct wil6210_priv *wil = ndev_to_wil(ndev);
- int rc;
+ int rc = 0;
wil_dbg_misc(wil, "open\n");
@@ -31,13 +60,16 @@ static int wil_open(struct net_device *ndev)
return -EINVAL;
}
- rc = wil_pm_runtime_get(wil);
- if (rc < 0)
- return rc;
+ if (!wil_has_other_active_ifaces(wil, ndev, true, false)) {
+ wil_dbg_misc(wil, "open, first iface\n");
+ rc = wil_pm_runtime_get(wil);
+ if (rc < 0)
+ return rc;
- rc = wil_up(wil);
- if (rc)
- wil_pm_runtime_put(wil);
+ rc = wil_up(wil);
+ if (rc)
+ wil_pm_runtime_put(wil);
+ }
return rc;
}
@@ -45,13 +77,16 @@ static int wil_open(struct net_device *ndev)
static int wil_stop(struct net_device *ndev)
{
struct wil6210_priv *wil = ndev_to_wil(ndev);
- int rc;
+ int rc = 0;
wil_dbg_misc(wil, "stop\n");
- rc = wil_down(wil);
- if (!rc)
- wil_pm_runtime_put(wil);
+ if (!wil_has_other_active_ifaces(wil, ndev, true, false)) {
+ wil_dbg_misc(wil, "stop, last iface\n");
+ rc = wil_down(wil);
+ if (!rc)
+ wil_pm_runtime_put(wil);
+ }
return rc;
}
@@ -96,11 +131,19 @@ static int wil6210_netdev_poll_tx(struct napi_struct *napi, int budget)
for (i = 0; i < WIL6210_MAX_TX_RINGS; i++) {
struct vring *vring = &wil->vring_tx[i];
struct vring_tx_data *txdata = &wil->vring_tx_data[i];
+ struct wil6210_vif *vif;
- if (!vring->va || !txdata->enabled)
+ if (!vring->va || !txdata->enabled ||
+ txdata->mid >= wil->max_vifs)
continue;
- tx_done += wil_tx_complete(wil, i);
+ vif = wil->vifs[txdata->mid];
+ if (unlikely(!vif)) {
+ wil_dbg_txrx(wil, "Invalid MID %d\n", txdata->mid);
+ continue;
+ }
+
+ tx_done += wil_tx_complete(vif, i);
}
if (tx_done < budget) {
@@ -121,44 +164,137 @@ static void wil_dev_setup(struct net_device *dev)
dev->tx_queue_len = WIL_TX_Q_LEN_DEFAULT;
}
-void *wil_if_alloc(struct device *dev)
+static void wil_vif_deinit(struct wil6210_vif *vif)
{
- struct net_device *ndev;
- struct wireless_dev *wdev;
- struct wil6210_priv *wil;
- struct ieee80211_channel *ch;
- int rc = 0;
+ del_timer_sync(&vif->scan_timer);
+ del_timer_sync(&vif->p2p.discovery_timer);
+ cancel_work_sync(&vif->disconnect_worker);
+ cancel_work_sync(&vif->p2p.discovery_expired_work);
+ cancel_work_sync(&vif->p2p.delayed_listen_work);
+ wil_probe_client_flush(vif);
+ cancel_work_sync(&vif->probe_client_worker);
+}
- wdev = wil_cfg80211_init(dev);
- if (IS_ERR(wdev)) {
- dev_err(dev, "wil_cfg80211_init failed\n");
- return wdev;
- }
+void wil_vif_free(struct wil6210_vif *vif)
+{
+ struct net_device *ndev = vif_to_ndev(vif);
- wil = wdev_to_wil(wdev);
- wil->wdev = wdev;
- wil->radio_wdev = wdev;
+ wil_vif_deinit(vif);
+ free_netdev(ndev);
+}
- wil_dbg_misc(wil, "if_alloc\n");
+static void wil_ndev_destructor(struct net_device *ndev)
+{
+ struct wil6210_vif *vif = ndev_to_vif(ndev);
- rc = wil_priv_init(wil);
- if (rc) {
- dev_err(dev, "wil_priv_init failed\n");
- goto out_wdev;
+ wil_vif_deinit(vif);
+}
+
+static void wil_connect_timer_fn(struct timer_list *t)
+{
+ struct wil6210_vif *vif = from_timer(vif, t, connect_timer);
+ struct wil6210_priv *wil = vif_to_wil(vif);
+ bool q;
+
+ wil_err(wil, "Connect timeout detected, disconnect station\n");
+
+ /* reschedule to thread context - disconnect won't
+ * run from atomic context.
+ * queue on wmi_wq to prevent race with connect event.
+ */
+ q = queue_work(wil->wmi_wq, &vif->disconnect_worker);
+ wil_dbg_wmi(wil, "queue_work of disconnect_worker -> %d\n", q);
+}
+
+static void wil_scan_timer_fn(struct timer_list *t)
+{
+ struct wil6210_vif *vif = from_timer(vif, t, scan_timer);
+ struct wil6210_priv *wil = vif_to_wil(vif);
+
+ clear_bit(wil_status_fwready, wil->status);
+ wil_err(wil, "Scan timeout detected, start fw error recovery\n");
+ wil_fw_error_recovery(wil);
+}
+
+static void wil_p2p_discovery_timer_fn(struct timer_list *t)
+{
+ struct wil6210_vif *vif = from_timer(vif, t, p2p.discovery_timer);
+ struct wil6210_priv *wil = vif_to_wil(vif);
+
+ wil_dbg_misc(wil, "p2p_discovery_timer_fn\n");
+
+ schedule_work(&vif->p2p.discovery_expired_work);
+}
+
+static void wil_vif_init(struct wil6210_vif *vif)
+{
+ vif->bcast_vring = -1;
+
+ mutex_init(&vif->probe_client_mutex);
+
+ timer_setup(&vif->connect_timer, wil_connect_timer_fn, 0);
+ timer_setup(&vif->scan_timer, wil_scan_timer_fn, 0);
+ timer_setup(&vif->p2p.discovery_timer, wil_p2p_discovery_timer_fn, 0);
+
+ INIT_WORK(&vif->probe_client_worker, wil_probe_client_worker);
+ INIT_WORK(&vif->disconnect_worker, wil_disconnect_worker);
+ INIT_WORK(&vif->p2p.delayed_listen_work, wil_p2p_delayed_listen_work);
+
+ INIT_LIST_HEAD(&vif->probe_client_pending);
+
+ vif->net_queue_stopped = 1;
+}
+
+static u8 wil_vif_find_free_mid(struct wil6210_priv *wil)
+{
+ u8 i;
+
+ for (i = 0; i < wil->max_vifs; i++) {
+ if (!wil->vifs[i])
+ return i;
}
- wdev->iftype = NL80211_IFTYPE_STATION; /* TODO */
- /* default monitor channel */
- ch = wdev->wiphy->bands[NL80211_BAND_60GHZ]->channels;
- cfg80211_chandef_create(&wil->monitor_chandef, ch, NL80211_CHAN_NO_HT);
+ return U8_MAX;
+}
+
+struct wil6210_vif *
+wil_vif_alloc(struct wil6210_priv *wil, const char *name,
+ unsigned char name_assign_type, enum nl80211_iftype iftype)
+{
+ struct net_device *ndev;
+ struct wireless_dev *wdev;
+ struct wil6210_vif *vif;
+ u8 mid;
+
+ mid = wil_vif_find_free_mid(wil);
+ if (mid == U8_MAX) {
+ wil_err(wil, "no available virtual interface\n");
+ return ERR_PTR(-EINVAL);
+ }
- ndev = alloc_netdev(0, "wlan%d", NET_NAME_UNKNOWN, wil_dev_setup);
+ ndev = alloc_netdev(sizeof(*vif), name, name_assign_type,
+ wil_dev_setup);
if (!ndev) {
- dev_err(dev, "alloc_netdev_mqs failed\n");
- rc = -ENOMEM;
- goto out_priv;
+ dev_err(wil_to_dev(wil), "alloc_netdev failed\n");
+ return ERR_PTR(-ENOMEM);
+ }
+ if (mid == 0) {
+ wil->main_ndev = ndev;
+ } else {
+ ndev->priv_destructor = wil_ndev_destructor;
+ ndev->needs_free_netdev = true;
}
+ vif = ndev_to_vif(ndev);
+ vif->ndev = ndev;
+ vif->wil = wil;
+ vif->mid = mid;
+ wil_vif_init(vif);
+
+ wdev = &vif->wdev;
+ wdev->wiphy = wil->wiphy;
+ wdev->iftype = iftype;
+
ndev->netdev_ops = &wil_netdev_ops;
wil_set_ethtoolops(ndev);
ndev->ieee80211_ptr = wdev;
@@ -170,21 +306,53 @@ void *wil_if_alloc(struct device *dev)
ndev->features |= ndev->hw_features;
SET_NETDEV_DEV(ndev, wiphy_dev(wdev->wiphy));
wdev->netdev = ndev;
+ return vif;
+}
+
+void *wil_if_alloc(struct device *dev)
+{
+ struct wil6210_priv *wil;
+ struct wil6210_vif *vif;
+ int rc = 0;
+
+ wil = wil_cfg80211_init(dev);
+ if (IS_ERR(wil)) {
+ dev_err(dev, "wil_cfg80211_init failed\n");
+ return wil;
+ }
+
+ rc = wil_priv_init(wil);
+ if (rc) {
+ dev_err(dev, "wil_priv_init failed\n");
+ goto out_cfg;
+ }
+
+ wil_dbg_misc(wil, "if_alloc\n");
+
+ vif = wil_vif_alloc(wil, "wlan%d", NET_NAME_UNKNOWN,
+ NL80211_IFTYPE_STATION);
+ if (IS_ERR(vif)) {
+ dev_err(dev, "wil_vif_alloc failed\n");
+ rc = -ENOMEM;
+ goto out_priv;
+ }
+
+ wil->radio_wdev = vif_to_wdev(vif);
return wil;
- out_priv:
+out_priv:
wil_priv_deinit(wil);
- out_wdev:
- wil_wdev_free(wil);
+out_cfg:
+ wil_cfg80211_deinit(wil);
return ERR_PTR(rc);
}
void wil_if_free(struct wil6210_priv *wil)
{
- struct net_device *ndev = wil_to_ndev(wil);
+ struct net_device *ndev = wil->main_ndev;
wil_dbg_misc(wil, "if_free\n");
@@ -193,17 +361,50 @@ void wil_if_free(struct wil6210_priv *wil)
wil_priv_deinit(wil);
- wil_to_ndev(wil) = NULL;
+ wil->main_ndev = NULL;
+ wil_ndev_destructor(ndev);
free_netdev(ndev);
- wil_wdev_free(wil);
+ wil_cfg80211_deinit(wil);
+}
+
+int wil_vif_add(struct wil6210_priv *wil, struct wil6210_vif *vif)
+{
+ struct net_device *ndev = vif_to_ndev(vif);
+ struct wireless_dev *wdev = vif_to_wdev(vif);
+ bool any_active = wil_has_active_ifaces(wil, true, false);
+ int rc;
+
+ ASSERT_RTNL();
+
+ if (wil->vifs[vif->mid]) {
+ dev_err(&ndev->dev, "VIF with mid %d already in use\n",
+ vif->mid);
+ return -EEXIST;
+ }
+ if (any_active && vif->mid != 0) {
+ rc = wmi_port_allocate(wil, vif->mid, ndev->dev_addr,
+ wdev->iftype);
+ if (rc)
+ return rc;
+ }
+ rc = register_netdevice(ndev);
+ if (rc < 0) {
+ dev_err(&ndev->dev, "Failed to register netdev: %d\n", rc);
+ if (any_active && vif->mid != 0)
+ wmi_port_delete(wil, vif->mid);
+ return rc;
+ }
+
+ wil->vifs[vif->mid] = vif;
+ return 0;
}
int wil_if_add(struct wil6210_priv *wil)
{
- struct wireless_dev *wdev = wil_to_wdev(wil);
- struct wiphy *wiphy = wdev->wiphy;
- struct net_device *ndev = wil_to_ndev(wil);
+ struct wiphy *wiphy = wil->wiphy;
+ struct net_device *ndev = wil->main_ndev;
+ struct wil6210_vif *vif = ndev_to_vif(ndev);
int rc;
wil_dbg_misc(wil, "entered");
@@ -216,33 +417,94 @@ int wil_if_add(struct wil6210_priv *wil)
return rc;
}
- netif_napi_add(ndev, &wil->napi_rx, wil6210_netdev_poll_rx,
+ init_dummy_netdev(&wil->napi_ndev);
+ netif_napi_add(&wil->napi_ndev, &wil->napi_rx, wil6210_netdev_poll_rx,
WIL6210_NAPI_BUDGET);
- netif_tx_napi_add(ndev, &wil->napi_tx, wil6210_netdev_poll_tx,
+ netif_tx_napi_add(&wil->napi_ndev,
+ &wil->napi_tx, wil6210_netdev_poll_tx,
WIL6210_NAPI_BUDGET);
- wil_update_net_queues_bh(wil, NULL, true);
+ wil_update_net_queues_bh(wil, vif, NULL, true);
- rc = register_netdev(ndev);
- if (rc < 0) {
- dev_err(&ndev->dev, "Failed to register netdev: %d\n", rc);
+ rtnl_lock();
+ rc = wil_vif_add(wil, vif);
+ rtnl_unlock();
+ if (rc < 0)
goto out_wiphy;
- }
return 0;
out_wiphy:
- wiphy_unregister(wdev->wiphy);
+ wiphy_unregister(wiphy);
return rc;
}
+void wil_vif_remove(struct wil6210_priv *wil, u8 mid)
+{
+ struct wil6210_vif *vif;
+ struct net_device *ndev;
+ bool any_active = wil_has_active_ifaces(wil, true, false);
+
+ ASSERT_RTNL();
+ if (mid >= wil->max_vifs) {
+ wil_err(wil, "invalid MID: %d\n", mid);
+ return;
+ }
+
+ vif = wil->vifs[mid];
+ if (!vif) {
+ wil_err(wil, "MID %d not registered\n", mid);
+ return;
+ }
+
+ ndev = vif_to_ndev(vif);
+ /* during unregister_netdevice cfg80211_leave may perform operations
+ * such as stop AP, disconnect, so we only clear the VIF afterwards
+ */
+ unregister_netdevice(ndev);
+
+ mutex_lock(&wil->mutex);
+ wil6210_disconnect(vif, NULL, WLAN_REASON_DEAUTH_LEAVING, false);
+ mutex_unlock(&wil->mutex);
+
+ if (any_active && vif->mid != 0)
+ wmi_port_delete(wil, vif->mid);
+
+ /* make sure no one is accessing the VIF before removing */
+ mutex_lock(&wil->vif_mutex);
+ wil->vifs[mid] = NULL;
+ /* ensure NAPI code will see the NULL VIF */
+ wmb();
+ if (test_bit(wil_status_napi_en, wil->status)) {
+ napi_synchronize(&wil->napi_rx);
+ napi_synchronize(&wil->napi_tx);
+ }
+ mutex_unlock(&wil->vif_mutex);
+
+ flush_work(&wil->wmi_event_worker);
+ del_timer_sync(&vif->connect_timer);
+ cancel_work_sync(&vif->disconnect_worker);
+ wil_probe_client_flush(vif);
+ cancel_work_sync(&vif->probe_client_worker);
+ /* for VIFs, ndev will be freed by destructor after RTNL is unlocked.
+ * the main interface will be freed in wil_if_free, we need to keep it
+ * a bit longer so logging macros will work.
+ */
+}
+
void wil_if_remove(struct wil6210_priv *wil)
{
- struct net_device *ndev = wil_to_ndev(wil);
- struct wireless_dev *wdev = wil_to_wdev(wil);
+ struct net_device *ndev = wil->main_ndev;
+ struct wireless_dev *wdev = ndev->ieee80211_ptr;
wil_dbg_misc(wil, "if_remove\n");
- unregister_netdev(ndev);
+ rtnl_lock();
+ wil_vif_remove(wil, 0);
+ rtnl_unlock();
+
+ netif_napi_del(&wil->napi_tx);
+ netif_napi_del(&wil->napi_rx);
+
wiphy_unregister(wdev->wiphy);
}
diff --git a/drivers/net/wireless/ath/wil6210/p2p.c b/drivers/net/wireless/ath/wil6210/p2p.c
index 7dbee2c3e482..db087ea58ddf 100644
--- a/drivers/net/wireless/ath/wil6210/p2p.c
+++ b/drivers/net/wireless/ath/wil6210/p2p.c
@@ -1,5 +1,6 @@
/*
* Copyright (c) 2014-2017 Qualcomm Atheros, Inc.
+ * Copyright (c) 2018, The Linux Foundation. All rights reserved.
*
* Permission to use, copy, modify, and/or distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
@@ -22,27 +23,28 @@
#define P2P_SEARCH_DURATION_MS 500
#define P2P_DEFAULT_BI 100
-static int wil_p2p_start_listen(struct wil6210_priv *wil)
+static int wil_p2p_start_listen(struct wil6210_vif *vif)
{
- struct wil_p2p_info *p2p = &wil->p2p;
+ struct wil6210_priv *wil = vif_to_wil(vif);
+ struct wil_p2p_info *p2p = &vif->p2p;
u8 channel = p2p->listen_chan.hw_value;
int rc;
lockdep_assert_held(&wil->mutex);
- rc = wmi_p2p_cfg(wil, channel, P2P_DEFAULT_BI);
+ rc = wmi_p2p_cfg(vif, channel, P2P_DEFAULT_BI);
if (rc) {
wil_err(wil, "wmi_p2p_cfg failed\n");
goto out;
}
- rc = wmi_set_ssid(wil, strlen(P2P_WILDCARD_SSID), P2P_WILDCARD_SSID);
+ rc = wmi_set_ssid(vif, strlen(P2P_WILDCARD_SSID), P2P_WILDCARD_SSID);
if (rc) {
wil_err(wil, "wmi_set_ssid failed\n");
goto out_stop;
}
- rc = wmi_start_listen(wil);
+ rc = wmi_start_listen(vif);
if (rc) {
wil_err(wil, "wmi_start_listen failed\n");
goto out_stop;
@@ -53,7 +55,7 @@ static int wil_p2p_start_listen(struct wil6210_priv *wil)
jiffies + msecs_to_jiffies(p2p->listen_duration));
out_stop:
if (rc)
- wmi_stop_discovery(wil);
+ wmi_stop_discovery(vif);
out:
return rc;
@@ -65,20 +67,12 @@ bool wil_p2p_is_social_scan(struct cfg80211_scan_request *request)
(request->channels[0]->hw_value == P2P_DMG_SOCIAL_CHANNEL);
}
-void wil_p2p_discovery_timer_fn(struct timer_list *t)
-{
- struct wil6210_priv *wil = from_timer(wil, t, p2p.discovery_timer);
-
- wil_dbg_misc(wil, "p2p_discovery_timer_fn\n");
-
- schedule_work(&wil->p2p.discovery_expired_work);
-}
-
-int wil_p2p_search(struct wil6210_priv *wil,
+int wil_p2p_search(struct wil6210_vif *vif,
struct cfg80211_scan_request *request)
{
+ struct wil6210_priv *wil = vif_to_wil(vif);
int rc;
- struct wil_p2p_info *p2p = &wil->p2p;
+ struct wil_p2p_info *p2p = &vif->p2p;
wil_dbg_misc(wil, "p2p_search: channel %d\n", P2P_DMG_SOCIAL_CHANNEL);
@@ -90,20 +84,20 @@ int wil_p2p_search(struct wil6210_priv *wil,
goto out;
}
- rc = wmi_p2p_cfg(wil, P2P_DMG_SOCIAL_CHANNEL, P2P_DEFAULT_BI);
+ rc = wmi_p2p_cfg(vif, P2P_DMG_SOCIAL_CHANNEL, P2P_DEFAULT_BI);
if (rc) {
wil_err(wil, "wmi_p2p_cfg failed\n");
goto out;
}
- rc = wmi_set_ssid(wil, strlen(P2P_WILDCARD_SSID), P2P_WILDCARD_SSID);
+ rc = wmi_set_ssid(vif, strlen(P2P_WILDCARD_SSID), P2P_WILDCARD_SSID);
if (rc) {
wil_err(wil, "wmi_set_ssid failed\n");
goto out_stop;
}
/* Set application IE to probe request and probe response */
- rc = wmi_set_ie(wil, WMI_FRAME_PROBE_REQ,
+ rc = wmi_set_ie(vif, WMI_FRAME_PROBE_REQ,
request->ie_len, request->ie);
if (rc) {
wil_err(wil, "wmi_set_ie(WMI_FRAME_PROBE_REQ) failed\n");
@@ -113,14 +107,14 @@ int wil_p2p_search(struct wil6210_priv *wil,
/* supplicant doesn't provide Probe Response IEs. As a workaround -
* re-use Probe Request IEs
*/
- rc = wmi_set_ie(wil, WMI_FRAME_PROBE_RESP,
+ rc = wmi_set_ie(vif, WMI_FRAME_PROBE_RESP,
request->ie_len, request->ie);
if (rc) {
wil_err(wil, "wmi_set_ie(WMI_FRAME_PROBE_RESP) failed\n");
goto out_stop;
}
- rc = wmi_start_search(wil);
+ rc = wmi_start_search(vif);
if (rc) {
wil_err(wil, "wmi_start_search failed\n");
goto out_stop;
@@ -133,7 +127,7 @@ int wil_p2p_search(struct wil6210_priv *wil,
out_stop:
if (rc)
- wmi_stop_discovery(wil);
+ wmi_stop_discovery(vif);
out:
return rc;
@@ -143,7 +137,8 @@ int wil_p2p_listen(struct wil6210_priv *wil, struct wireless_dev *wdev,
unsigned int duration, struct ieee80211_channel *chan,
u64 *cookie)
{
- struct wil_p2p_info *p2p = &wil->p2p;
+ struct wil6210_vif *vif = wdev_to_vif(wil, wdev);
+ struct wil_p2p_info *p2p = &vif->p2p;
int rc;
if (!chan)
@@ -163,23 +158,24 @@ int wil_p2p_listen(struct wil6210_priv *wil, struct wireless_dev *wdev,
*cookie = ++p2p->cookie;
p2p->listen_duration = duration;
- mutex_lock(&wil->p2p_wdev_mutex);
- if (wil->scan_request) {
+ mutex_lock(&wil->vif_mutex);
+ if (vif->scan_request) {
wil_dbg_misc(wil, "Delaying p2p listen until scan done\n");
p2p->pending_listen_wdev = wdev;
p2p->discovery_started = 1;
rc = 0;
- mutex_unlock(&wil->p2p_wdev_mutex);
+ mutex_unlock(&wil->vif_mutex);
goto out;
}
- mutex_unlock(&wil->p2p_wdev_mutex);
+ mutex_unlock(&wil->vif_mutex);
- rc = wil_p2p_start_listen(wil);
+ rc = wil_p2p_start_listen(vif);
if (rc)
goto out;
p2p->discovery_started = 1;
- wil->radio_wdev = wdev;
+ if (vif->mid == 0)
+ wil->radio_wdev = wdev;
cfg80211_ready_on_channel(wdev, *cookie, chan, duration,
GFP_KERNEL);
@@ -189,9 +185,9 @@ out:
return rc;
}
-u8 wil_p2p_stop_discovery(struct wil6210_priv *wil)
+u8 wil_p2p_stop_discovery(struct wil6210_vif *vif)
{
- struct wil_p2p_info *p2p = &wil->p2p;
+ struct wil_p2p_info *p2p = &vif->p2p;
u8 started = p2p->discovery_started;
if (p2p->discovery_started) {
@@ -200,7 +196,7 @@ u8 wil_p2p_stop_discovery(struct wil6210_priv *wil)
p2p->pending_listen_wdev = NULL;
} else {
del_timer_sync(&p2p->discovery_timer);
- wmi_stop_discovery(wil);
+ wmi_stop_discovery(vif);
}
p2p->discovery_started = 0;
}
@@ -208,9 +204,10 @@ u8 wil_p2p_stop_discovery(struct wil6210_priv *wil)
return started;
}
-int wil_p2p_cancel_listen(struct wil6210_priv *wil, u64 cookie)
+int wil_p2p_cancel_listen(struct wil6210_vif *vif, u64 cookie)
{
- struct wil_p2p_info *p2p = &wil->p2p;
+ struct wil6210_priv *wil = vif_to_wil(vif);
+ struct wil_p2p_info *p2p = &vif->p2p;
u8 started;
mutex_lock(&wil->mutex);
@@ -222,7 +219,7 @@ int wil_p2p_cancel_listen(struct wil6210_priv *wil, u64 cookie)
return -ENOENT;
}
- started = wil_p2p_stop_discovery(wil);
+ started = wil_p2p_stop_discovery(vif);
mutex_unlock(&wil->mutex);
@@ -231,13 +228,14 @@ int wil_p2p_cancel_listen(struct wil6210_priv *wil, u64 cookie)
return -ENOENT;
}
- mutex_lock(&wil->p2p_wdev_mutex);
- cfg80211_remain_on_channel_expired(wil->radio_wdev,
+ mutex_lock(&wil->vif_mutex);
+ cfg80211_remain_on_channel_expired(vif_to_radio_wdev(wil, vif),
p2p->cookie,
&p2p->listen_chan,
GFP_KERNEL);
- wil->radio_wdev = wil->wdev;
- mutex_unlock(&wil->p2p_wdev_mutex);
+ if (vif->mid == 0)
+ wil->radio_wdev = wil->main_ndev->ieee80211_ptr;
+ mutex_unlock(&wil->vif_mutex);
return 0;
}
@@ -245,40 +243,43 @@ void wil_p2p_listen_expired(struct work_struct *work)
{
struct wil_p2p_info *p2p = container_of(work,
struct wil_p2p_info, discovery_expired_work);
- struct wil6210_priv *wil = container_of(p2p,
- struct wil6210_priv, p2p);
+ struct wil6210_vif *vif = container_of(p2p,
+ struct wil6210_vif, p2p);
+ struct wil6210_priv *wil = vif_to_wil(vif);
u8 started;
wil_dbg_misc(wil, "p2p_listen_expired\n");
mutex_lock(&wil->mutex);
- started = wil_p2p_stop_discovery(wil);
+ started = wil_p2p_stop_discovery(vif);
mutex_unlock(&wil->mutex);
- if (started) {
- mutex_lock(&wil->p2p_wdev_mutex);
- cfg80211_remain_on_channel_expired(wil->radio_wdev,
- p2p->cookie,
- &p2p->listen_chan,
- GFP_KERNEL);
- wil->radio_wdev = wil->wdev;
- mutex_unlock(&wil->p2p_wdev_mutex);
- }
+ if (!started)
+ return;
+ mutex_lock(&wil->vif_mutex);
+ cfg80211_remain_on_channel_expired(vif_to_radio_wdev(wil, vif),
+ p2p->cookie,
+ &p2p->listen_chan,
+ GFP_KERNEL);
+ if (vif->mid == 0)
+ wil->radio_wdev = wil->main_ndev->ieee80211_ptr;
+ mutex_unlock(&wil->vif_mutex);
}
void wil_p2p_search_expired(struct work_struct *work)
{
struct wil_p2p_info *p2p = container_of(work,
struct wil_p2p_info, discovery_expired_work);
- struct wil6210_priv *wil = container_of(p2p,
- struct wil6210_priv, p2p);
+ struct wil6210_vif *vif = container_of(p2p,
+ struct wil6210_vif, p2p);
+ struct wil6210_priv *wil = vif_to_wil(vif);
u8 started;
wil_dbg_misc(wil, "p2p_search_expired\n");
mutex_lock(&wil->mutex);
- started = wil_p2p_stop_discovery(wil);
+ started = wil_p2p_stop_discovery(vif);
mutex_unlock(&wil->mutex);
if (started) {
@@ -286,13 +287,15 @@ void wil_p2p_search_expired(struct work_struct *work)
.aborted = false,
};
- mutex_lock(&wil->p2p_wdev_mutex);
- if (wil->scan_request) {
- cfg80211_scan_done(wil->scan_request, &info);
- wil->scan_request = NULL;
- wil->radio_wdev = wil->wdev;
+ mutex_lock(&wil->vif_mutex);
+ if (vif->scan_request) {
+ cfg80211_scan_done(vif->scan_request, &info);
+ vif->scan_request = NULL;
+ if (vif->mid == 0)
+ wil->radio_wdev =
+ wil->main_ndev->ieee80211_ptr;
}
- mutex_unlock(&wil->p2p_wdev_mutex);
+ mutex_unlock(&wil->vif_mutex);
}
}
@@ -300,8 +303,9 @@ void wil_p2p_delayed_listen_work(struct work_struct *work)
{
struct wil_p2p_info *p2p = container_of(work,
struct wil_p2p_info, delayed_listen_work);
- struct wil6210_priv *wil = container_of(p2p,
- struct wil6210_priv, p2p);
+ struct wil6210_vif *vif = container_of(p2p,
+ struct wil6210_vif, p2p);
+ struct wil6210_priv *wil = vif_to_wil(vif);
int rc;
mutex_lock(&wil->mutex);
@@ -310,31 +314,33 @@ void wil_p2p_delayed_listen_work(struct work_struct *work)
if (!p2p->discovery_started || !p2p->pending_listen_wdev)
goto out;
- mutex_lock(&wil->p2p_wdev_mutex);
- if (wil->scan_request) {
+ mutex_lock(&wil->vif_mutex);
+ if (vif->scan_request) {
/* another scan started, wait again... */
- mutex_unlock(&wil->p2p_wdev_mutex);
+ mutex_unlock(&wil->vif_mutex);
goto out;
}
- mutex_unlock(&wil->p2p_wdev_mutex);
+ mutex_unlock(&wil->vif_mutex);
- rc = wil_p2p_start_listen(wil);
+ rc = wil_p2p_start_listen(vif);
- mutex_lock(&wil->p2p_wdev_mutex);
+ mutex_lock(&wil->vif_mutex);
if (rc) {
cfg80211_remain_on_channel_expired(p2p->pending_listen_wdev,
p2p->cookie,
&p2p->listen_chan,
GFP_KERNEL);
- wil->radio_wdev = wil->wdev;
+ if (vif->mid == 0)
+ wil->radio_wdev = wil->main_ndev->ieee80211_ptr;
} else {
cfg80211_ready_on_channel(p2p->pending_listen_wdev, p2p->cookie,
&p2p->listen_chan,
p2p->listen_duration, GFP_KERNEL);
- wil->radio_wdev = p2p->pending_listen_wdev;
+ if (vif->mid == 0)
+ wil->radio_wdev = p2p->pending_listen_wdev;
}
p2p->pending_listen_wdev = NULL;
- mutex_unlock(&wil->p2p_wdev_mutex);
+ mutex_unlock(&wil->vif_mutex);
out:
mutex_unlock(&wil->mutex);
@@ -342,34 +348,35 @@ out:
void wil_p2p_stop_radio_operations(struct wil6210_priv *wil)
{
- struct wil_p2p_info *p2p = &wil->p2p;
+ struct wil6210_vif *vif = ndev_to_vif(wil->main_ndev);
+ struct wil_p2p_info *p2p = &vif->p2p;
struct cfg80211_scan_info info = {
.aborted = true,
};
lockdep_assert_held(&wil->mutex);
- lockdep_assert_held(&wil->p2p_wdev_mutex);
+ lockdep_assert_held(&wil->vif_mutex);
if (wil->radio_wdev != wil->p2p_wdev)
goto out;
if (!p2p->discovery_started) {
/* Regular scan on the p2p device */
- if (wil->scan_request &&
- wil->scan_request->wdev == wil->p2p_wdev)
- wil_abort_scan(wil, true);
+ if (vif->scan_request &&
+ vif->scan_request->wdev == wil->p2p_wdev)
+ wil_abort_scan(vif, true);
goto out;
}
/* Search or listen on p2p device */
- mutex_unlock(&wil->p2p_wdev_mutex);
- wil_p2p_stop_discovery(wil);
- mutex_lock(&wil->p2p_wdev_mutex);
+ mutex_unlock(&wil->vif_mutex);
+ wil_p2p_stop_discovery(vif);
+ mutex_lock(&wil->vif_mutex);
- if (wil->scan_request) {
+ if (vif->scan_request) {
/* search */
- cfg80211_scan_done(wil->scan_request, &info);
- wil->scan_request = NULL;
+ cfg80211_scan_done(vif->scan_request, &info);
+ vif->scan_request = NULL;
} else {
/* listen */
cfg80211_remain_on_channel_expired(wil->radio_wdev,
@@ -379,5 +386,5 @@ void wil_p2p_stop_radio_operations(struct wil6210_priv *wil)
}
out:
- wil->radio_wdev = wil->wdev;
+ wil->radio_wdev = wil->main_ndev->ieee80211_ptr;
}
diff --git a/drivers/net/wireless/ath/wil6210/pcie_bus.c b/drivers/net/wireless/ath/wil6210/pcie_bus.c
index 809092a49192..19cbc6add637 100644
--- a/drivers/net/wireless/ath/wil6210/pcie_bus.c
+++ b/drivers/net/wireless/ath/wil6210/pcie_bus.c
@@ -137,6 +137,20 @@ void wil_enable_irq(struct wil6210_priv *wil)
enable_irq(wil->pdev->irq);
}
+static void wil_remove_all_additional_vifs(struct wil6210_priv *wil)
+{
+ struct wil6210_vif *vif;
+ int i;
+
+ for (i = 1; i < wil->max_vifs; i++) {
+ vif = wil->vifs[i];
+ if (vif) {
+ wil_vif_prepare_stop(vif);
+ wil_vif_remove(wil, vif->mid);
+ }
+ }
+}
+
/* Bus ops */
static int wil_if_pcie_enable(struct wil6210_priv *wil)
{
@@ -148,10 +162,8 @@ static int wil_if_pcie_enable(struct wil6210_priv *wil)
*/
int msi_only = pdev->msi_enabled;
bool _use_msi = use_msi;
- bool wmi_only = test_bit(WMI_FW_CAPABILITY_WMI_ONLY,
- wil->fw_capabilities);
- wil_dbg_misc(wil, "if_pcie_enable, wmi_only %d\n", wmi_only);
+ wil_dbg_misc(wil, "if_pcie_enable\n");
pci_set_master(pdev);
@@ -172,11 +184,9 @@ static int wil_if_pcie_enable(struct wil6210_priv *wil)
if (rc)
goto stop_master;
- /* need reset here to obtain MAC or in case of WMI-only FW, full reset
- * and fw loading takes place
- */
+ /* need reset here to obtain MAC */
mutex_lock(&wil->mutex);
- rc = wil_reset(wil, wmi_only);
+ rc = wil_reset(wil, false);
mutex_unlock(&wil->mutex);
if (rc)
goto release_irq;
@@ -356,6 +366,18 @@ static int wil_pcie_probe(struct pci_dev *pdev, const struct pci_device_id *id)
goto bus_disable;
}
+ /* in case of WMI-only FW, perform full reset and FW loading */
+ if (test_bit(WMI_FW_CAPABILITY_WMI_ONLY, wil->fw_capabilities)) {
+ wil_dbg_misc(wil, "Loading WMI only FW\n");
+ mutex_lock(&wil->mutex);
+ rc = wil_reset(wil, true);
+ mutex_unlock(&wil->mutex);
+ if (rc) {
+ wil_err(wil, "failed to load WMI only FW\n");
+ goto if_remove;
+ }
+ }
+
if (IS_ENABLED(CONFIG_PM))
wil->pm_notify.notifier_call = wil6210_pm_notify;
@@ -372,6 +394,8 @@ static int wil_pcie_probe(struct pci_dev *pdev, const struct pci_device_id *id)
return 0;
+if_remove:
+ wil_if_remove(wil);
bus_disable:
wil_if_pcie_disable(wil);
err_iounmap:
@@ -402,6 +426,7 @@ static void wil_pcie_remove(struct pci_dev *pdev)
wil6210_debugfs_remove(wil);
rtnl_lock();
wil_p2p_wdev_free(wil);
+ wil_remove_all_additional_vifs(wil);
rtnl_unlock();
wil_if_remove(wil);
wil_if_pcie_disable(wil);
@@ -425,12 +450,15 @@ static int wil6210_suspend(struct device *dev, bool is_runtime)
int rc = 0;
struct pci_dev *pdev = to_pci_dev(dev);
struct wil6210_priv *wil = pci_get_drvdata(pdev);
- struct net_device *ndev = wil_to_ndev(wil);
- bool keep_radio_on = ndev->flags & IFF_UP &&
- wil->keep_radio_on_during_sleep;
+ bool keep_radio_on, active_ifaces;
wil_dbg_pm(wil, "suspend: %s\n", is_runtime ? "runtime" : "system");
+ mutex_lock(&wil->vif_mutex);
+ active_ifaces = wil_has_active_ifaces(wil, true, false);
+ mutex_unlock(&wil->vif_mutex);
+ keep_radio_on = active_ifaces && wil->keep_radio_on_during_sleep;
+
rc = wil_can_suspend(wil, is_runtime);
if (rc)
goto out;
@@ -457,12 +485,15 @@ static int wil6210_resume(struct device *dev, bool is_runtime)
int rc = 0;
struct pci_dev *pdev = to_pci_dev(dev);
struct wil6210_priv *wil = pci_get_drvdata(pdev);
- struct net_device *ndev = wil_to_ndev(wil);
- bool keep_radio_on = ndev->flags & IFF_UP &&
- wil->keep_radio_on_during_sleep;
+ bool keep_radio_on, active_ifaces;
wil_dbg_pm(wil, "resume: %s\n", is_runtime ? "runtime" : "system");
+ mutex_lock(&wil->vif_mutex);
+ active_ifaces = wil_has_active_ifaces(wil, true, false);
+ mutex_unlock(&wil->vif_mutex);
+ keep_radio_on = active_ifaces && wil->keep_radio_on_during_sleep;
+
/* In case radio stays on, platform device will control
* PCIe master
*/
diff --git a/drivers/net/wireless/ath/wil6210/pm.c b/drivers/net/wireless/ath/wil6210/pm.c
index 0a96518a566f..ba81fb3ac96f 100644
--- a/drivers/net/wireless/ath/wil6210/pm.c
+++ b/drivers/net/wireless/ath/wil6210/pm.c
@@ -1,5 +1,6 @@
/*
* Copyright (c) 2014,2017 Qualcomm Atheros, Inc.
+ * Copyright (c) 2018, The Linux Foundation. All rights reserved.
*
* Permission to use, copy, modify, and/or distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
@@ -20,13 +21,72 @@
#define WIL6210_AUTOSUSPEND_DELAY_MS (1000)
+static void wil_pm_wake_connected_net_queues(struct wil6210_priv *wil)
+{
+ int i;
+
+ mutex_lock(&wil->vif_mutex);
+ for (i = 0; i < wil->max_vifs; i++) {
+ struct wil6210_vif *vif = wil->vifs[i];
+
+ if (vif && test_bit(wil_vif_fwconnected, vif->status))
+ wil_update_net_queues_bh(wil, vif, NULL, false);
+ }
+ mutex_unlock(&wil->vif_mutex);
+}
+
+static void wil_pm_stop_all_net_queues(struct wil6210_priv *wil)
+{
+ int i;
+
+ mutex_lock(&wil->vif_mutex);
+ for (i = 0; i < wil->max_vifs; i++) {
+ struct wil6210_vif *vif = wil->vifs[i];
+
+ if (vif)
+ wil_update_net_queues_bh(wil, vif, NULL, true);
+ }
+ mutex_unlock(&wil->vif_mutex);
+}
+
+static bool
+wil_can_suspend_vif(struct wil6210_priv *wil, struct wil6210_vif *vif,
+ bool is_runtime)
+{
+ struct wireless_dev *wdev = vif_to_wdev(vif);
+
+ switch (wdev->iftype) {
+ case NL80211_IFTYPE_MONITOR:
+ wil_dbg_pm(wil, "Sniffer\n");
+ return false;
+
+ /* for STA-like interface, don't runtime suspend */
+ case NL80211_IFTYPE_STATION:
+ case NL80211_IFTYPE_P2P_CLIENT:
+ if (test_bit(wil_vif_fwconnecting, vif->status)) {
+ wil_dbg_pm(wil, "Delay suspend when connecting\n");
+ return false;
+ }
+ if (is_runtime) {
+ wil_dbg_pm(wil, "STA-like interface\n");
+ return false;
+ }
+ break;
+ /* AP-like interface - can't suspend */
+ default:
+ wil_dbg_pm(wil, "AP-like interface\n");
+ return false;
+ }
+
+ return true;
+}
+
int wil_can_suspend(struct wil6210_priv *wil, bool is_runtime)
{
- int rc = 0;
- struct wireless_dev *wdev = wil->wdev;
- struct net_device *ndev = wil_to_ndev(wil);
+ int rc = 0, i;
bool wmi_only = test_bit(WMI_FW_CAPABILITY_WMI_ONLY,
wil->fw_capabilities);
+ bool active_ifaces;
wil_dbg_pm(wil, "can_suspend: %s\n", is_runtime ? "runtime" : "system");
@@ -40,7 +100,12 @@ int wil_can_suspend(struct wil6210_priv *wil, bool is_runtime)
rc = -EBUSY;
goto out;
}
- if (!(ndev->flags & IFF_UP)) {
+
+ mutex_lock(&wil->vif_mutex);
+ active_ifaces = wil_has_active_ifaces(wil, true, false);
+ mutex_unlock(&wil->vif_mutex);
+
+ if (!active_ifaces) {
/* can always sleep when down */
wil_dbg_pm(wil, "Interface is down\n");
goto out;
@@ -57,32 +122,19 @@ int wil_can_suspend(struct wil6210_priv *wil, bool is_runtime)
}
/* interface is running */
- switch (wdev->iftype) {
- case NL80211_IFTYPE_MONITOR:
- wil_dbg_pm(wil, "Sniffer\n");
- rc = -EBUSY;
- goto out;
- /* for STA-like interface, don't runtime suspend */
- case NL80211_IFTYPE_STATION:
- case NL80211_IFTYPE_P2P_CLIENT:
- if (test_bit(wil_status_fwconnecting, wil->status)) {
- wil_dbg_pm(wil, "Delay suspend when connecting\n");
- rc = -EBUSY;
- goto out;
- }
- /* Runtime pm not supported in case the interface is up */
- if (is_runtime) {
- wil_dbg_pm(wil, "STA-like interface\n");
+ mutex_lock(&wil->vif_mutex);
+ for (i = 0; i < wil->max_vifs; i++) {
+ struct wil6210_vif *vif = wil->vifs[i];
+
+ if (!vif)
+ continue;
+ if (!wil_can_suspend_vif(wil, vif, is_runtime)) {
rc = -EBUSY;
+ mutex_unlock(&wil->vif_mutex);
goto out;
}
- break;
- /* AP-like interface - can't suspend */
- default:
- wil_dbg_pm(wil, "AP-like interface\n");
- rc = -EBUSY;
- break;
}
+ mutex_unlock(&wil->vif_mutex);
out:
wil_dbg_pm(wil, "can_suspend: %s => %s (%d)\n",
@@ -127,8 +179,7 @@ static int wil_resume_keep_radio_on(struct wil6210_priv *wil)
}
/* Wake all queues */
- if (test_bit(wil_status_fwconnected, wil->status))
- wil_update_net_queues_bh(wil, NULL, false);
+ wil_pm_wake_connected_net_queues(wil);
out:
if (rc)
@@ -152,7 +203,7 @@ static int wil_suspend_keep_radio_on(struct wil6210_priv *wil)
wil->suspend_stats.rejected_by_host++;
return -EBUSY;
}
- wil_update_net_queues_bh(wil, NULL, true);
+ wil_pm_stop_all_net_queues(wil);
if (!wil_is_tx_idle(wil)) {
wil_dbg_pm(wil, "Pending TX data, reject suspend\n");
@@ -243,22 +294,20 @@ resume_after_fail:
/* if resume succeeded, reject the suspend */
if (!rc) {
rc = -EBUSY;
- if (test_bit(wil_status_fwconnected, wil->status))
- wil_update_net_queues_bh(wil, NULL, false);
+ wil_pm_wake_connected_net_queues(wil);
}
return rc;
reject_suspend:
clear_bit(wil_status_suspending, wil->status);
- if (test_bit(wil_status_fwconnected, wil->status))
- wil_update_net_queues_bh(wil, NULL, false);
+ wil_pm_wake_connected_net_queues(wil);
return -EBUSY;
}
static int wil_suspend_radio_off(struct wil6210_priv *wil)
{
int rc = 0;
- struct net_device *ndev = wil_to_ndev(wil);
+ bool active_ifaces;
wil_dbg_pm(wil, "suspend radio off\n");
@@ -272,7 +321,11 @@ static int wil_suspend_radio_off(struct wil6210_priv *wil)
}
/* if netif up, hardware is alive, shut it down */
- if (ndev->flags & IFF_UP) {
+ mutex_lock(&wil->vif_mutex);
+ active_ifaces = wil_has_active_ifaces(wil, true, false);
+ mutex_unlock(&wil->vif_mutex);
+
+ if (active_ifaces) {
rc = wil_down(wil);
if (rc) {
wil_err(wil, "wil_down : %d\n", rc);
@@ -306,16 +359,19 @@ out:
static int wil_resume_radio_off(struct wil6210_priv *wil)
{
int rc = 0;
- struct net_device *ndev = wil_to_ndev(wil);
+ bool active_ifaces;
wil_dbg_pm(wil, "Enabling PCIe IRQ\n");
wil_enable_irq(wil);
- /* if netif up, bring hardware up
+ /* if any netif up, bring hardware up
* During open(), IFF_UP set after actual device method
* invocation. This prevent recursive call to wil_up()
* wil_status_suspended will be cleared in wil_reset
*/
- if (ndev->flags & IFF_UP)
+ mutex_lock(&wil->vif_mutex);
+ active_ifaces = wil_has_active_ifaces(wil, true, false);
+ mutex_unlock(&wil->vif_mutex);
+ if (active_ifaces)
rc = wil_up(wil);
else
clear_bit(wil_status_suspended, wil->status);
diff --git a/drivers/net/wireless/ath/wil6210/pmc.c b/drivers/net/wireless/ath/wil6210/pmc.c
index 4ea27b0bd278..c49f7988369e 100644
--- a/drivers/net/wireless/ath/wil6210/pmc.c
+++ b/drivers/net/wireless/ath/wil6210/pmc.c
@@ -1,5 +1,6 @@
/*
* Copyright (c) 2012-2015,2017 Qualcomm Atheros, Inc.
+ * Copyright (c) 2018, The Linux Foundation. All rights reserved.
*
* Permission to use, copy, modify, and/or distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
@@ -53,6 +54,7 @@ void wil_pmc_alloc(struct wil6210_priv *wil,
u32 i;
struct pmc_ctx *pmc = &wil->pmc;
struct device *dev = wil_to_dev(wil);
+ struct wil6210_vif *vif = ndev_to_vif(wil->main_ndev);
struct wmi_pmc_cmd pmc_cmd = {0};
int last_cmd_err = -ENOMEM;
@@ -186,6 +188,7 @@ void wil_pmc_alloc(struct wil6210_priv *wil,
wil_dbg_misc(wil, "pmc_alloc: send WMI_PMC_CMD with ALLOCATE op\n");
pmc->last_cmd_status = wmi_send(wil,
WMI_PMC_CMDID,
+ vif->mid,
&pmc_cmd,
sizeof(pmc_cmd));
if (pmc->last_cmd_status) {
@@ -236,6 +239,7 @@ void wil_pmc_free(struct wil6210_priv *wil, int send_pmc_cmd)
{
struct pmc_ctx *pmc = &wil->pmc;
struct device *dev = wil_to_dev(wil);
+ struct wil6210_vif *vif = ndev_to_vif(wil->main_ndev);
struct wmi_pmc_cmd pmc_cmd = {0};
mutex_lock(&pmc->lock);
@@ -254,8 +258,8 @@ void wil_pmc_free(struct wil6210_priv *wil, int send_pmc_cmd)
wil_dbg_misc(wil, "send WMI_PMC_CMD with RELEASE op\n");
pmc_cmd.op = WMI_PMC_RELEASE;
pmc->last_cmd_status =
- wmi_send(wil, WMI_PMC_CMDID, &pmc_cmd,
- sizeof(pmc_cmd));
+ wmi_send(wil, WMI_PMC_CMDID, vif->mid,
+ &pmc_cmd, sizeof(pmc_cmd));
if (pmc->last_cmd_status) {
wil_err(wil,
"WMI_PMC_CMD with RELEASE op failed, status %d",
diff --git a/drivers/net/wireless/ath/wil6210/rx_reorder.c b/drivers/net/wireless/ath/wil6210/rx_reorder.c
index a43cffcf1bbf..14dcb0698dee 100644
--- a/drivers/net/wireless/ath/wil6210/rx_reorder.c
+++ b/drivers/net/wireless/ath/wil6210/rx_reorder.c
@@ -1,5 +1,6 @@
/*
* Copyright (c) 2014-2017 Qualcomm Atheros, Inc.
+ * Copyright (c) 2018, The Linux Foundation. All rights reserved.
*
* Permission to use, copy, modify, and/or distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
@@ -40,11 +41,10 @@ static inline int reorder_index(struct wil_tid_ampdu_rx *r, u16 seq)
return seq_sub(seq, r->ssn) % r->buf_size;
}
-static void wil_release_reorder_frame(struct wil6210_priv *wil,
+static void wil_release_reorder_frame(struct net_device *ndev,
struct wil_tid_ampdu_rx *r,
int index)
{
- struct net_device *ndev = wil_to_ndev(wil);
struct sk_buff *skb = r->reorder_buf[index];
if (!skb)
@@ -59,7 +59,7 @@ no_frame:
r->head_seq_num = seq_inc(r->head_seq_num);
}
-static void wil_release_reorder_frames(struct wil6210_priv *wil,
+static void wil_release_reorder_frames(struct net_device *ndev,
struct wil_tid_ampdu_rx *r,
u16 hseq)
{
@@ -73,18 +73,18 @@ static void wil_release_reorder_frames(struct wil6210_priv *wil,
*/
while (seq_less(r->head_seq_num, hseq) && r->stored_mpdu_num) {
index = reorder_index(r, r->head_seq_num);
- wil_release_reorder_frame(wil, r, index);
+ wil_release_reorder_frame(ndev, r, index);
}
r->head_seq_num = hseq;
}
-static void wil_reorder_release(struct wil6210_priv *wil,
+static void wil_reorder_release(struct net_device *ndev,
struct wil_tid_ampdu_rx *r)
{
int index = reorder_index(r, r->head_seq_num);
while (r->reorder_buf[index]) {
- wil_release_reorder_frame(wil, r, index);
+ wil_release_reorder_frame(ndev, r, index);
index = reorder_index(r, r->head_seq_num);
}
}
@@ -93,7 +93,8 @@ static void wil_reorder_release(struct wil6210_priv *wil,
void wil_rx_reorder(struct wil6210_priv *wil, struct sk_buff *skb)
__acquires(&sta->tid_rx_lock) __releases(&sta->tid_rx_lock)
{
- struct net_device *ndev = wil_to_ndev(wil);
+ struct wil6210_vif *vif;
+ struct net_device *ndev;
struct vring_rx_desc *d = wil_skb_rxdesc(skb);
int tid = wil_rxdesc_tid(d);
int cid = wil_rxdesc_cid(d);
@@ -108,6 +109,14 @@ __acquires(&sta->tid_rx_lock) __releases(&sta->tid_rx_lock)
wil_dbg_txrx(wil, "MID %d CID %d TID %d Seq 0x%03x mcast %01x\n",
mid, cid, tid, seq, mcast);
+ vif = wil->vifs[mid];
+ if (unlikely(!vif)) {
+ wil_dbg_txrx(wil, "invalid VIF, mid %d\n", mid);
+ dev_kfree_skb(skb);
+ return;
+ }
+ ndev = vif_to_ndev(vif);
+
if (unlikely(mcast)) {
wil_netif_rx_any(skb, ndev);
return;
@@ -168,7 +177,7 @@ __acquires(&sta->tid_rx_lock) __releases(&sta->tid_rx_lock)
if (!seq_less(seq, r->head_seq_num + r->buf_size)) {
hseq = seq_inc(seq_sub(seq, r->buf_size));
/* release stored frames up to new head to stack */
- wil_release_reorder_frames(wil, r, hseq);
+ wil_release_reorder_frames(ndev, r, hseq);
}
/* Now the new frame is always in the range of the reordering buffer */
@@ -199,16 +208,18 @@ __acquires(&sta->tid_rx_lock) __releases(&sta->tid_rx_lock)
r->reorder_buf[index] = skb;
r->reorder_time[index] = jiffies;
r->stored_mpdu_num++;
- wil_reorder_release(wil, r);
+ wil_reorder_release(ndev, r);
out:
spin_unlock(&sta->tid_rx_lock);
}
/* process BAR frame, called in NAPI context */
-void wil_rx_bar(struct wil6210_priv *wil, u8 cid, u8 tid, u16 seq)
+void wil_rx_bar(struct wil6210_priv *wil, struct wil6210_vif *vif,
+ u8 cid, u8 tid, u16 seq)
{
struct wil_sta_info *sta = &wil->sta[cid];
+ struct net_device *ndev = vif_to_ndev(vif);
struct wil_tid_ampdu_rx *r;
spin_lock(&sta->tid_rx_lock);
@@ -223,9 +234,9 @@ void wil_rx_bar(struct wil6210_priv *wil, u8 cid, u8 tid, u16 seq)
seq, r->head_seq_num);
goto out;
}
- wil_dbg_txrx(wil, "BAR: CID %d TID %d Seq 0x%03x head 0x%03x\n",
- cid, tid, seq, r->head_seq_num);
- wil_release_reorder_frames(wil, r, seq);
+ wil_dbg_txrx(wil, "BAR: CID %d MID %d TID %d Seq 0x%03x head 0x%03x\n",
+ cid, vif->mid, tid, seq, r->head_seq_num);
+ wil_release_reorder_frames(ndev, r, seq);
out:
spin_unlock(&sta->tid_rx_lock);
@@ -292,8 +303,8 @@ static u16 wil_agg_size(struct wil6210_priv *wil, u16 req_agg_wsize)
}
/* Block Ack - Rx side (recipient) */
-int wil_addba_rx_request(struct wil6210_priv *wil, u8 cidxtid,
- u8 dialog_token, __le16 ba_param_set,
+int wil_addba_rx_request(struct wil6210_priv *wil, u8 mid,
+ u8 cidxtid, u8 dialog_token, __le16 ba_param_set,
__le16 ba_timeout, __le16 ba_seq_ctrl)
__acquires(&sta->tid_rx_lock) __releases(&sta->tid_rx_lock)
{
@@ -354,7 +365,7 @@ __acquires(&sta->tid_rx_lock) __releases(&sta->tid_rx_lock)
}
}
- rc = wmi_addba_rx_resp(wil, cid, tid, dialog_token, status,
+ rc = wmi_addba_rx_resp(wil, mid, cid, tid, dialog_token, status,
agg_amsdu, agg_wsize, agg_timeout);
if (rc || (status != WLAN_STATUS_SUCCESS)) {
wil_err(wil, "do not apply ba, rc(%d), status(%d)\n", rc,
@@ -393,7 +404,7 @@ int wil_addba_tx_request(struct wil6210_priv *wil, u8 ringid, u16 wsize)
goto out;
}
txdata->addba_in_progress = true;
- rc = wmi_addba(wil, ringid, agg_wsize, agg_timeout);
+ rc = wmi_addba(wil, txdata->mid, ringid, agg_wsize, agg_timeout);
if (rc) {
wil_err(wil, "wmi_addba failed, rc (%d)", rc);
txdata->addba_in_progress = false;
diff --git a/drivers/net/wireless/ath/wil6210/txrx.c b/drivers/net/wireless/ath/wil6210/txrx.c
index 16b8a4e5201f..b60b9fcaaebd 100644
--- a/drivers/net/wireless/ath/wil6210/txrx.c
+++ b/drivers/net/wireless/ath/wil6210/txrx.c
@@ -1,5 +1,6 @@
/*
* Copyright (c) 2012-2017 Qualcomm Atheros, Inc.
+ * Copyright (c) 2018, The Linux Foundation. All rights reserved.
*
* Permission to use, copy, modify, and/or distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
@@ -474,7 +475,8 @@ static struct sk_buff *wil_vring_reap_rx(struct wil6210_priv *wil,
struct vring *vring)
{
struct device *dev = wil_to_dev(wil);
- struct net_device *ndev = wil_to_ndev(wil);
+ struct wil6210_vif *vif;
+ struct net_device *ndev;
volatile struct vring_rx_desc *_d;
struct vring_rx_desc *d;
struct sk_buff *skb;
@@ -483,7 +485,7 @@ static struct sk_buff *wil_vring_reap_rx(struct wil6210_priv *wil,
unsigned int sz = wil->rx_buf_len + ETH_HLEN + snaplen;
u16 dmalen;
u8 ftype;
- int cid;
+ int cid, mid;
int i;
struct wil_net_stats *stats;
@@ -520,6 +522,16 @@ again:
(const void *)d, sizeof(*d), false);
cid = wil_rxdesc_cid(d);
+ mid = wil_rxdesc_mid(d);
+ vif = wil->vifs[mid];
+
+ if (unlikely(!vif)) {
+ wil_dbg_txrx(wil, "skipped RX descriptor with invalid mid %d",
+ mid);
+ kfree_skb(skb);
+ goto again;
+ }
+ ndev = vif_to_ndev(vif);
stats = &wil->sta[cid].stats;
if (unlikely(dmalen > sz)) {
@@ -553,7 +565,6 @@ again:
ftype = wil_rxdesc_ftype(d) << 2;
if (unlikely(ftype != IEEE80211_FTYPE_DATA)) {
u8 fc1 = wil_rxdesc_fc1(d);
- int mid = wil_rxdesc_mid(d);
int tid = wil_rxdesc_tid(d);
u16 seq = wil_rxdesc_seq(d);
@@ -565,7 +576,7 @@ again:
wil_dbg_txrx(wil,
"BAR: MID %d CID %d TID %d Seq 0x%03x\n",
mid, cid, tid, seq);
- wil_rx_bar(wil, cid, tid, seq);
+ wil_rx_bar(wil, vif, cid, tid, seq);
} else {
/* print again all info. One can enable only this
* without overhead for printing every Rx frame
@@ -621,10 +632,15 @@ again:
/**
* allocate and fill up to @count buffers in rx ring
* buffers posted at @swtail
+ * Note: we have a single RX queue for servicing all VIFs, but we
+ * allocate skbs with headroom according to main interface only. This
+ * means it will not work with monitor interface together with other VIFs.
+ * Currently we only support monitor interface on its own without other VIFs,
+ * and we will need to fix this code once we add support.
*/
static int wil_rx_refill(struct wil6210_priv *wil, int count)
{
- struct net_device *ndev = wil_to_ndev(wil);
+ struct net_device *ndev = wil->main_ndev;
struct vring *v = &wil->vring_rx;
u32 next_tail;
int rc = 0;
@@ -713,8 +729,9 @@ static int wil_rx_crypto_check(struct wil6210_priv *wil, struct sk_buff *skb)
void wil_netif_rx_any(struct sk_buff *skb, struct net_device *ndev)
{
gro_result_t rc = GRO_NORMAL;
+ struct wil6210_vif *vif = ndev_to_vif(ndev);
struct wil6210_priv *wil = ndev_to_wil(ndev);
- struct wireless_dev *wdev = wil_to_wdev(wil);
+ struct wireless_dev *wdev = vif_to_wdev(vif);
unsigned int len = skb->len;
struct vring_rx_desc *d = wil_skb_rxdesc(skb);
int cid = wil_rxdesc_cid(d); /* always 0..7, no need to check */
@@ -751,14 +768,15 @@ void wil_netif_rx_any(struct sk_buff *skb, struct net_device *ndev)
goto stats;
}
- if (wdev->iftype == NL80211_IFTYPE_AP && !wil->ap_isolate) {
+ if (wdev->iftype == NL80211_IFTYPE_AP && !vif->ap_isolate) {
if (mcast) {
/* send multicast frames both to higher layers in
* local net stack and back to the wireless medium
*/
xmit_skb = skb_copy(skb, GFP_ATOMIC);
} else {
- int xmit_cid = wil_find_cid(wil, eth->h_dest);
+ int xmit_cid = wil_find_cid(wil, vif->mid,
+ eth->h_dest);
if (xmit_cid >= 0) {
/* The destination station is associated to
@@ -786,8 +804,8 @@ void wil_netif_rx_any(struct sk_buff *skb, struct net_device *ndev)
}
if (skb) { /* deliver to local stack */
-
skb->protocol = eth_type_trans(skb, ndev);
+ skb->dev = ndev;
rc = napi_gro_receive(&wil->napi_rx, skb);
wil_dbg_txrx(wil, "Rx complete %d bytes => %s\n",
len, gro_res_str[rc]);
@@ -815,7 +833,8 @@ stats:
*/
void wil_rx_handle(struct wil6210_priv *wil, int *quota)
{
- struct net_device *ndev = wil_to_ndev(wil);
+ struct net_device *ndev = wil->main_ndev;
+ struct wireless_dev *wdev = ndev->ieee80211_ptr;
struct vring *v = &wil->vring_rx;
struct sk_buff *skb;
@@ -827,7 +846,8 @@ void wil_rx_handle(struct wil6210_priv *wil, int *quota)
while ((*quota > 0) && (NULL != (skb = wil_vring_reap_rx(wil, v)))) {
(*quota)--;
- if (wil->wdev->iftype == NL80211_IFTYPE_MONITOR) {
+ /* monitor is currently supported on main interface only */
+ if (wdev->iftype == NL80211_IFTYPE_MONITOR) {
skb->dev = ndev;
skb_reset_mac_header(skb);
skb->ip_summed = CHECKSUM_UNNECESSARY;
@@ -911,12 +931,14 @@ static inline void wil_tx_data_init(struct vring_tx_data *txdata)
txdata->agg_timeout = 0;
txdata->agg_amsdu = 0;
txdata->addba_in_progress = false;
+ txdata->mid = U8_MAX;
spin_unlock_bh(&txdata->lock);
}
-int wil_vring_init_tx(struct wil6210_priv *wil, int id, int size,
+int wil_vring_init_tx(struct wil6210_vif *vif, int id, int size,
int cid, int tid)
{
+ struct wil6210_priv *wil = vif_to_wil(vif);
int rc;
struct wmi_vring_cfg_cmd cmd = {
.action = cpu_to_le32(WMI_VRING_CMD_ADD),
@@ -966,9 +988,9 @@ int wil_vring_init_tx(struct wil6210_priv *wil, int id, int size,
cmd.vring_cfg.tx_sw_ring.ring_mem_base = cpu_to_le64(vring->pa);
- if (!wil->privacy)
+ if (!vif->privacy)
txdata->dot1x_open = true;
- rc = wmi_call(wil, WMI_VRING_CFG_CMDID, &cmd, sizeof(cmd),
+ rc = wmi_call(wil, WMI_VRING_CFG_CMDID, vif->mid, &cmd, sizeof(cmd),
WMI_VRING_CFG_DONE_EVENTID, &reply, sizeof(reply), 100);
if (rc)
goto out_free;
@@ -982,6 +1004,7 @@ int wil_vring_init_tx(struct wil6210_priv *wil, int id, int size,
spin_lock_bh(&txdata->lock);
vring->hwtail = le32_to_cpu(reply.cmd.tx_vring_tail_ptr);
+ txdata->mid = vif->mid;
txdata->enabled = 1;
spin_unlock_bh(&txdata->lock);
@@ -1003,8 +1026,9 @@ int wil_vring_init_tx(struct wil6210_priv *wil, int id, int size,
return rc;
}
-int wil_vring_init_bcast(struct wil6210_priv *wil, int id, int size)
+int wil_vring_init_bcast(struct wil6210_vif *vif, int id, int size)
{
+ struct wil6210_priv *wil = vif_to_wil(vif);
int rc;
struct wmi_bcast_vring_cfg_cmd cmd = {
.action = cpu_to_le32(WMI_VRING_CMD_ADD),
@@ -1046,9 +1070,10 @@ int wil_vring_init_bcast(struct wil6210_priv *wil, int id, int size)
cmd.vring_cfg.tx_sw_ring.ring_mem_base = cpu_to_le64(vring->pa);
- if (!wil->privacy)
+ if (!vif->privacy)
txdata->dot1x_open = true;
- rc = wmi_call(wil, WMI_BCAST_VRING_CFG_CMDID, &cmd, sizeof(cmd),
+ rc = wmi_call(wil, WMI_BCAST_VRING_CFG_CMDID, vif->mid,
+ &cmd, sizeof(cmd),
WMI_VRING_CFG_DONE_EVENTID, &reply, sizeof(reply), 100);
if (rc)
goto out_free;
@@ -1062,6 +1087,7 @@ int wil_vring_init_bcast(struct wil6210_priv *wil, int id, int size)
spin_lock_bh(&txdata->lock);
vring->hwtail = le32_to_cpu(reply.cmd.tx_vring_tail_ptr);
+ txdata->mid = vif->mid;
txdata->enabled = 1;
spin_unlock_bh(&txdata->lock);
@@ -1091,6 +1117,7 @@ void wil_vring_fini_tx(struct wil6210_priv *wil, int id)
spin_lock_bh(&txdata->lock);
txdata->dot1x_open = false;
+ txdata->mid = U8_MAX;
txdata->enabled = 0; /* no Tx can be in progress or start anew */
spin_unlock_bh(&txdata->lock);
/* napi_synchronize waits for completion of the current NAPI but will
@@ -1108,11 +1135,12 @@ void wil_vring_fini_tx(struct wil6210_priv *wil, int id)
}
static struct vring *wil_find_tx_ucast(struct wil6210_priv *wil,
+ struct wil6210_vif *vif,
struct sk_buff *skb)
{
int i;
struct ethhdr *eth = (void *)skb->data;
- int cid = wil_find_cid(wil, eth->h_dest);
+ int cid = wil_find_cid(wil, vif->mid, eth->h_dest);
if (cid < 0)
return NULL;
@@ -1142,10 +1170,11 @@ static struct vring *wil_find_tx_ucast(struct wil6210_priv *wil,
return NULL;
}
-static int wil_tx_vring(struct wil6210_priv *wil, struct vring *vring,
- struct sk_buff *skb);
+static int wil_tx_vring(struct wil6210_priv *wil, struct wil6210_vif *vif,
+ struct vring *vring, struct sk_buff *skb);
static struct vring *wil_find_tx_vring_sta(struct wil6210_priv *wil,
+ struct wil6210_vif *vif,
struct sk_buff *skb)
{
struct vring *v;
@@ -1160,7 +1189,7 @@ static struct vring *wil_find_tx_vring_sta(struct wil6210_priv *wil,
for (i = 0; i < WIL6210_MAX_TX_RINGS; i++) {
v = &wil->vring_tx[i];
txdata = &wil->vring_tx_data[i];
- if (!v->va || !txdata->enabled)
+ if (!v->va || !txdata->enabled || txdata->mid != vif->mid)
continue;
cid = wil->vring2cid_tid[i][0];
@@ -1193,11 +1222,12 @@ static struct vring *wil_find_tx_vring_sta(struct wil6210_priv *wil,
* - for PBSS
*/
static struct vring *wil_find_tx_bcast_1(struct wil6210_priv *wil,
+ struct wil6210_vif *vif,
struct sk_buff *skb)
{
struct vring *v;
struct vring_tx_data *txdata;
- int i = wil->bcast_vring;
+ int i = vif->bcast_vring;
if (i < 0)
return NULL;
@@ -1222,6 +1252,7 @@ static void wil_set_da_for_vring(struct wil6210_priv *wil,
}
static struct vring *wil_find_tx_bcast_2(struct wil6210_priv *wil,
+ struct wil6210_vif *vif,
struct sk_buff *skb)
{
struct vring *v, *v2;
@@ -1230,13 +1261,13 @@ static struct vring *wil_find_tx_bcast_2(struct wil6210_priv *wil,
u8 cid;
struct ethhdr *eth = (void *)skb->data;
char *src = eth->h_source;
- struct vring_tx_data *txdata;
+ struct vring_tx_data *txdata, *txdata2;
/* find 1-st vring eligible for data */
for (i = 0; i < WIL6210_MAX_TX_RINGS; i++) {
v = &wil->vring_tx[i];
txdata = &wil->vring_tx_data[i];
- if (!v->va || !txdata->enabled)
+ if (!v->va || !txdata->enabled || txdata->mid != vif->mid)
continue;
cid = wil->vring2cid_tid[i][0];
@@ -1264,7 +1295,8 @@ found:
/* find other active vrings and duplicate skb for each */
for (i++; i < WIL6210_MAX_TX_RINGS; i++) {
v2 = &wil->vring_tx[i];
- if (!v2->va)
+ txdata2 = &wil->vring_tx_data[i];
+ if (!v2->va || txdata2->mid != vif->mid)
continue;
cid = wil->vring2cid_tid[i][0];
if (cid >= WIL6210_MAX_CID) /* skip BCAST */
@@ -1280,7 +1312,7 @@ found:
if (skb2) {
wil_dbg_txrx(wil, "BCAST DUP -> ring %d\n", i);
wil_set_da_for_vring(wil, skb2, i);
- wil_tx_vring(wil, v2, skb2);
+ wil_tx_vring(wil, vif, v2, skb2);
} else {
wil_err(wil, "skb_copy failed\n");
}
@@ -1417,8 +1449,8 @@ static inline void wil_set_tx_desc_last_tso(volatile struct vring_tx_desc *d)
DMA_CFG_DESC_TX_0_SEGMENT_BUF_DETAILS_POS;
}
-static int __wil_tx_vring_tso(struct wil6210_priv *wil, struct vring *vring,
- struct sk_buff *skb)
+static int __wil_tx_vring_tso(struct wil6210_priv *wil, struct wil6210_vif *vif,
+ struct vring *vring, struct sk_buff *skb)
{
struct device *dev = wil_to_dev(wil);
@@ -1710,8 +1742,8 @@ err_exit:
return rc;
}
-static int __wil_tx_vring(struct wil6210_priv *wil, struct vring *vring,
- struct sk_buff *skb)
+static int __wil_tx_vring(struct wil6210_priv *wil, struct wil6210_vif *vif,
+ struct vring *vring, struct sk_buff *skb)
{
struct device *dev = wil_to_dev(wil);
struct vring_tx_desc dd, *d = &dd;
@@ -1725,7 +1757,7 @@ static int __wil_tx_vring(struct wil6210_priv *wil, struct vring *vring,
uint i = swhead;
dma_addr_t pa;
int used;
- bool mcast = (vring_index == wil->bcast_vring);
+ bool mcast = (vring_index == vif->bcast_vring);
uint len = skb_headlen(skb);
wil_dbg_txrx(wil, "tx_vring: %d bytes to vring %d\n", skb->len,
@@ -1860,8 +1892,8 @@ static int __wil_tx_vring(struct wil6210_priv *wil, struct vring *vring,
return -EINVAL;
}
-static int wil_tx_vring(struct wil6210_priv *wil, struct vring *vring,
- struct sk_buff *skb)
+static int wil_tx_vring(struct wil6210_priv *wil, struct wil6210_vif *vif,
+ struct vring *vring, struct sk_buff *skb)
{
int vring_index = vring - wil->vring_tx;
struct vring_tx_data *txdata = &wil->vring_tx_data[vring_index];
@@ -1879,7 +1911,7 @@ static int wil_tx_vring(struct wil6210_priv *wil, struct vring *vring,
}
rc = (skb_is_gso(skb) ? __wil_tx_vring_tso : __wil_tx_vring)
- (wil, vring, skb);
+ (wil, vif, vring, skb);
spin_unlock(&txdata->lock);
@@ -1888,6 +1920,7 @@ static int wil_tx_vring(struct wil6210_priv *wil, struct vring *vring,
/**
* Check status of tx vrings and stop/wake net queues if needed
+ * It will start/stop net queues of a specific VIF net_device.
*
* This function does one of two checks:
* In case check_stop is true, will check if net queues need to be stopped. If
@@ -1903,28 +1936,32 @@ static int wil_tx_vring(struct wil6210_priv *wil, struct vring *vring,
* availability and modified vring has high descriptor availability.
*/
static inline void __wil_update_net_queues(struct wil6210_priv *wil,
+ struct wil6210_vif *vif,
struct vring *vring,
bool check_stop)
{
int i;
+ if (unlikely(!vif))
+ return;
+
if (vring)
- wil_dbg_txrx(wil, "vring %d, check_stop=%d, stopped=%d",
- (int)(vring - wil->vring_tx), check_stop,
- wil->net_queue_stopped);
+ wil_dbg_txrx(wil, "vring %d, mid %d, check_stop=%d, stopped=%d",
+ (int)(vring - wil->vring_tx), vif->mid, check_stop,
+ vif->net_queue_stopped);
else
- wil_dbg_txrx(wil, "check_stop=%d, stopped=%d",
- check_stop, wil->net_queue_stopped);
+ wil_dbg_txrx(wil, "check_stop=%d, mid=%d, stopped=%d",
+ check_stop, vif->mid, vif->net_queue_stopped);
- if (check_stop == wil->net_queue_stopped)
+ if (check_stop == vif->net_queue_stopped)
/* net queues already in desired state */
return;
if (check_stop) {
if (!vring || unlikely(wil_vring_avail_low(vring))) {
/* not enough room in the vring */
- netif_tx_stop_all_queues(wil_to_ndev(wil));
- wil->net_queue_stopped = true;
+ netif_tx_stop_all_queues(vif_to_ndev(vif));
+ vif->net_queue_stopped = true;
wil_dbg_txrx(wil, "netif_tx_stop called\n");
}
return;
@@ -1940,7 +1977,8 @@ static inline void __wil_update_net_queues(struct wil6210_priv *wil,
struct vring *cur_vring = &wil->vring_tx[i];
struct vring_tx_data *txdata = &wil->vring_tx_data[i];
- if (!cur_vring->va || !txdata->enabled || cur_vring == vring)
+ if (txdata->mid != vif->mid || !cur_vring->va ||
+ !txdata->enabled || cur_vring == vring)
continue;
if (wil_vring_avail_low(cur_vring)) {
@@ -1953,30 +1991,31 @@ static inline void __wil_update_net_queues(struct wil6210_priv *wil,
if (!vring || wil_vring_avail_high(vring)) {
/* enough room in the vring */
wil_dbg_txrx(wil, "calling netif_tx_wake\n");
- netif_tx_wake_all_queues(wil_to_ndev(wil));
- wil->net_queue_stopped = false;
+ netif_tx_wake_all_queues(vif_to_ndev(vif));
+ vif->net_queue_stopped = false;
}
}
-void wil_update_net_queues(struct wil6210_priv *wil, struct vring *vring,
- bool check_stop)
+void wil_update_net_queues(struct wil6210_priv *wil, struct wil6210_vif *vif,
+ struct vring *vring, bool check_stop)
{
spin_lock(&wil->net_queue_lock);
- __wil_update_net_queues(wil, vring, check_stop);
+ __wil_update_net_queues(wil, vif, vring, check_stop);
spin_unlock(&wil->net_queue_lock);
}
-void wil_update_net_queues_bh(struct wil6210_priv *wil, struct vring *vring,
- bool check_stop)
+void wil_update_net_queues_bh(struct wil6210_priv *wil, struct wil6210_vif *vif,
+ struct vring *vring, bool check_stop)
{
spin_lock_bh(&wil->net_queue_lock);
- __wil_update_net_queues(wil, vring, check_stop);
+ __wil_update_net_queues(wil, vif, vring, check_stop);
spin_unlock_bh(&wil->net_queue_lock);
}
netdev_tx_t wil_start_xmit(struct sk_buff *skb, struct net_device *ndev)
{
- struct wil6210_priv *wil = ndev_to_wil(ndev);
+ struct wil6210_vif *vif = ndev_to_vif(ndev);
+ struct wil6210_priv *wil = vif_to_wil(vif);
struct ethhdr *eth = (void *)skb->data;
bool bcast = is_multicast_ether_addr(eth->h_dest);
struct vring *vring;
@@ -1991,49 +2030,50 @@ netdev_tx_t wil_start_xmit(struct sk_buff *skb, struct net_device *ndev)
}
goto drop;
}
- if (unlikely(!test_bit(wil_status_fwconnected, wil->status))) {
- wil_dbg_ratelimited(wil, "FW not connected, packet dropped\n");
+ if (unlikely(!test_bit(wil_vif_fwconnected, vif->status))) {
+ wil_dbg_ratelimited(wil,
+ "VIF not connected, packet dropped\n");
goto drop;
}
- if (unlikely(wil->wdev->iftype == NL80211_IFTYPE_MONITOR)) {
+ if (unlikely(vif->wdev.iftype == NL80211_IFTYPE_MONITOR)) {
wil_err(wil, "Xmit in monitor mode not supported\n");
goto drop;
}
pr_once_fw = false;
/* find vring */
- if (wil->wdev->iftype == NL80211_IFTYPE_STATION && !wil->pbss) {
+ if (vif->wdev.iftype == NL80211_IFTYPE_STATION && !vif->pbss) {
/* in STA mode (ESS), all to same VRING (to AP) */
- vring = wil_find_tx_vring_sta(wil, skb);
+ vring = wil_find_tx_vring_sta(wil, vif, skb);
} else if (bcast) {
- if (wil->pbss)
+ if (vif->pbss)
/* in pbss, no bcast VRING - duplicate skb in
* all stations VRINGs
*/
- vring = wil_find_tx_bcast_2(wil, skb);
- else if (wil->wdev->iftype == NL80211_IFTYPE_AP)
+ vring = wil_find_tx_bcast_2(wil, vif, skb);
+ else if (vif->wdev.iftype == NL80211_IFTYPE_AP)
/* AP has a dedicated bcast VRING */
- vring = wil_find_tx_bcast_1(wil, skb);
+ vring = wil_find_tx_bcast_1(wil, vif, skb);
else
/* unexpected combination, fallback to duplicating
* the skb in all stations VRINGs
*/
- vring = wil_find_tx_bcast_2(wil, skb);
+ vring = wil_find_tx_bcast_2(wil, vif, skb);
} else {
/* unicast, find specific VRING by dest. address */
- vring = wil_find_tx_ucast(wil, skb);
+ vring = wil_find_tx_ucast(wil, vif, skb);
}
if (unlikely(!vring)) {
wil_dbg_txrx(wil, "No Tx VRING found for %pM\n", eth->h_dest);
goto drop;
}
/* set up vring entry */
- rc = wil_tx_vring(wil, vring, skb);
+ rc = wil_tx_vring(wil, vif, vring, skb);
switch (rc) {
case 0:
/* shall we stop net queues? */
- wil_update_net_queues_bh(wil, vring, true);
+ wil_update_net_queues_bh(wil, vif, vring, true);
/* statistics will be updated on the tx_complete */
dev_kfree_skb_any(skb);
return NETDEV_TX_OK;
@@ -2072,9 +2112,10 @@ static inline void wil_consume_skb(struct sk_buff *skb, bool acked)
*
* Safe to call from IRQ
*/
-int wil_tx_complete(struct wil6210_priv *wil, int ringid)
+int wil_tx_complete(struct wil6210_vif *vif, int ringid)
{
- struct net_device *ndev = wil_to_ndev(wil);
+ struct wil6210_priv *wil = vif_to_wil(vif);
+ struct net_device *ndev = vif_to_ndev(vif);
struct device *dev = wil_to_dev(wil);
struct vring *vring = &wil->vring_tx[ringid];
struct vring_tx_data *txdata = &wil->vring_tx_data[ringid];
@@ -2184,7 +2225,7 @@ int wil_tx_complete(struct wil6210_priv *wil, int ringid)
/* shall we wake net queues? */
if (done)
- wil_update_net_queues(wil, vring, false);
+ wil_update_net_queues(wil, vif, vring, false);
return done;
}
diff --git a/drivers/net/wireless/ath/wil6210/txrx.h b/drivers/net/wireless/ath/wil6210/txrx.h
index fcdffaa8251b..5f07717acc2c 100644
--- a/drivers/net/wireless/ath/wil6210/txrx.h
+++ b/drivers/net/wireless/ath/wil6210/txrx.h
@@ -1,5 +1,6 @@
/*
* Copyright (c) 2012-2016 Qualcomm Atheros, Inc.
+ * Copyright (c) 2018, The Linux Foundation. All rights reserved.
*
* Permission to use, copy, modify, and/or distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
@@ -63,7 +64,9 @@ static inline void wil_desc_addr_set(struct vring_dma_addr *addr,
* [dword 1]
* bit 0.. 3 : pkt_mode:4
* bit 4 : pkt_mode_en:1
- * bit 5..14 : reserved0:10
+ * bit 5 : mac_id_en:1
+ * bit 6..7 : mac_id:2
+ * bit 8..14 : reserved0:7
* bit 15 : ack_policy_en:1
* bit 16..19 : dst_index:4
* bit 20 : dst_index_en:1
@@ -132,6 +135,14 @@ struct vring_tx_mac {
#define MAC_CFG_DESC_TX_1_PKT_MODE_EN_LEN 1
#define MAC_CFG_DESC_TX_1_PKT_MODE_EN_MSK 0x10
+#define MAC_CFG_DESC_TX_1_MAC_ID_EN_POS 5
+#define MAC_CFG_DESC_TX_1_MAC_ID_EN_LEN 1
+#define MAC_CFG_DESC_TX_1_MAC_ID_EN_MSK 0x20
+
+#define MAC_CFG_DESC_TX_1_MAC_ID_POS 6
+#define MAC_CFG_DESC_TX_1_MAC_ID_LEN 2
+#define MAC_CFG_DESC_TX_1_MAC_ID_MSK 0xc0
+
#define MAC_CFG_DESC_TX_1_ACK_POLICY_EN_POS 15
#define MAC_CFG_DESC_TX_1_ACK_POLICY_EN_LEN 1
#define MAC_CFG_DESC_TX_1_ACK_POLICY_EN_MSK 0x8000
@@ -304,7 +315,7 @@ enum {
* bit 0.. 3 : tid:4 The QoS (b3-0) TID Field
* bit 4.. 6 : cid:3 The Source index that was found during parsing the TA.
* This field is used to define the source of the packet
- * bit 7 : reserved:1
+ * bit 7 : MAC_id_valid:1, 1 if MAC virtual number is valid.
* bit 8.. 9 : mid:2 The MAC virtual number
* bit 10..11 : frame_type:2 : The FC (b3-2) - MPDU Type
* (management, data, control and extension)
@@ -395,6 +406,7 @@ struct vring_rx_mac {
#define RX_DMA_D0_CMD_DMA_EOP BIT(8)
#define RX_DMA_D0_CMD_DMA_RT BIT(9) /* always 1 */
#define RX_DMA_D0_CMD_DMA_IT BIT(10) /* interrupt */
+#define RX_MAC_D0_MAC_ID_VALID BIT(7)
/* Error field */
#define RX_DMA_ERROR_FCS BIT(0)
@@ -451,7 +463,8 @@ static inline int wil_rxdesc_cid(struct vring_rx_desc *d)
static inline int wil_rxdesc_mid(struct vring_rx_desc *d)
{
- return WIL_GET_BITS(d->mac.d0, 8, 9);
+ return (d->mac.d0 & RX_MAC_D0_MAC_ID_VALID) ?
+ WIL_GET_BITS(d->mac.d0, 8, 9) : 0;
}
static inline int wil_rxdesc_ftype(struct vring_rx_desc *d)
@@ -517,7 +530,8 @@ static inline struct vring_rx_desc *wil_skb_rxdesc(struct sk_buff *skb)
void wil_netif_rx_any(struct sk_buff *skb, struct net_device *ndev);
void wil_rx_reorder(struct wil6210_priv *wil, struct sk_buff *skb);
-void wil_rx_bar(struct wil6210_priv *wil, u8 cid, u8 tid, u16 seq);
+void wil_rx_bar(struct wil6210_priv *wil, struct wil6210_vif *vif,
+ u8 cid, u8 tid, u16 seq);
struct wil_tid_ampdu_rx *wil_tid_ampdu_rx_alloc(struct wil6210_priv *wil,
int size, u16 ssn);
void wil_tid_ampdu_rx_free(struct wil6210_priv *wil,
diff --git a/drivers/net/wireless/ath/wil6210/wil6210.h b/drivers/net/wireless/ath/wil6210/wil6210.h
index 0df2aada6659..f9c5155025bc 100644
--- a/drivers/net/wireless/ath/wil6210/wil6210.h
+++ b/drivers/net/wireless/ath/wil6210/wil6210.h
@@ -26,6 +26,7 @@
#include <linux/types.h>
#include "wmi.h"
#include "wil_platform.h"
+#include "fw.h"
extern bool no_fw_recovery;
extern unsigned int mtu_max;
@@ -49,6 +50,11 @@ extern bool disable_ap_sme;
#define WIL_DEFAULT_BUS_REQUEST_KBPS 128000 /* ~1Gbps */
#define WIL_MAX_BUS_REQUEST_KBPS 800000 /* ~6.1Gbps */
+/* maximum number of virtual interfaces the driver supports
+ * (including the main interface)
+ */
+#define WIL_MAX_VIFS 4
+
/**
* extract bits [@b0:@b1] (inclusive) from the value @x
* it should be @b0 <= @b1, or result is incorrect
@@ -463,13 +469,12 @@ struct vring_tx_data {
u16 agg_timeout;
u8 agg_amsdu;
bool addba_in_progress; /* if set, agg_xxx is for request in progress */
+ u8 mid;
spinlock_t lock;
};
enum { /* for wil6210_priv.status */
wil_status_fwready = 0, /* FW operational */
- wil_status_fwconnecting,
- wil_status_fwconnected,
wil_status_dontscan,
wil_status_mbox_ready, /* MBOX structures ready */
wil_status_irqen, /* interrupts enabled - for debug */
@@ -541,7 +546,6 @@ struct wil_tid_crypto_rx {
struct wil_p2p_info {
struct ieee80211_channel listen_chan;
u8 discovery_started;
- u8 p2p_dev_started;
u64 cookie;
struct wireless_dev *pending_listen_wdev;
unsigned int listen_duration;
@@ -584,6 +588,7 @@ struct wil_net_stats {
*/
struct wil_sta_info {
u8 addr[ETH_ALEN];
+ u8 mid;
enum wil_sta_status status;
struct wil_net_stats stats;
/* Rx BACK */
@@ -669,10 +674,44 @@ extern struct blink_on_off_time led_blink_time[WIL_LED_TIME_LAST];
extern u8 led_id;
extern u8 led_polarity;
+enum wil6210_vif_status {
+ wil_vif_fwconnecting,
+ wil_vif_fwconnected,
+ wil_vif_status_last /* keep last */
+};
+
+struct wil6210_vif {
+ struct wireless_dev wdev;
+ struct net_device *ndev;
+ struct wil6210_priv *wil;
+ u8 mid;
+ DECLARE_BITMAP(status, wil_vif_status_last);
+ u32 privacy; /* secure connection? */
+ u16 channel; /* relevant in AP mode */
+ u8 hidden_ssid; /* relevant in AP mode */
+ u32 ap_isolate; /* no intra-BSS communication */
+ bool pbss;
+ int bcast_vring;
+ struct cfg80211_bss *bss; /* connected bss, relevant in STA mode */
+ int locally_generated_disc; /* relevant in STA mode */
+ struct timer_list connect_timer;
+ struct work_struct disconnect_worker;
+ /* scan */
+ struct cfg80211_scan_request *scan_request;
+ struct timer_list scan_timer; /* detect scan timeout */
+ struct wil_p2p_info p2p;
+ /* keep alive */
+ struct list_head probe_client_pending;
+ struct mutex probe_client_mutex; /* protect @probe_client_pending */
+ struct work_struct probe_client_worker;
+ int net_queue_stopped; /* netif_tx_stop_all_queues invoked */
+};
+
struct wil6210_priv {
struct pci_dev *pdev;
u32 bar_size;
- struct wireless_dev *wdev;
+ struct wiphy *wiphy;
+ struct net_device *main_ndev;
void __iomem *csr;
DECLARE_BITMAP(status, wil_status_last);
u8 fw_version[ETHTOOL_FWVERS_LEN];
@@ -686,21 +725,18 @@ struct wil6210_priv {
DECLARE_BITMAP(hw_capa, hw_capa_last);
DECLARE_BITMAP(fw_capabilities, WMI_FW_CAPABILITY_MAX);
DECLARE_BITMAP(platform_capa, WIL_PLATFORM_CAPA_MAX);
- u8 n_mids; /* number of additional MIDs as reported by FW */
u32 recovery_count; /* num of FW recovery attempts in a short time */
u32 recovery_state; /* FW recovery state machine */
unsigned long last_fw_recovery; /* jiffies of last fw recovery */
wait_queue_head_t wq; /* for all wait_event() use */
+ u8 max_vifs; /* maximum number of interfaces, including main */
+ struct wil6210_vif *vifs[WIL_MAX_VIFS];
+ struct mutex vif_mutex; /* protects access to VIF entries */
+ atomic_t connected_vifs;
/* profile */
struct cfg80211_chan_def monitor_chandef;
u32 monitor_flags;
- u32 privacy; /* secure connection? */
- u8 hidden_ssid; /* relevant in AP mode */
- u16 channel; /* relevant in AP mode */
int sinfo_gen;
- u32 ap_isolate; /* no intra-BSS communication */
- struct cfg80211_bss *bss; /* connected bss, relevant in STA mode */
- int locally_generated_disc; /* relevant in STA mode */
/* interrupt moderation */
u32 tx_max_burst_duration;
u32 tx_interframe_timeout;
@@ -715,15 +751,13 @@ struct wil6210_priv {
struct completion wmi_call;
u16 wmi_seq;
u16 reply_id; /**< wait for this WMI event */
+ u8 reply_mid;
void *reply_buf;
u16 reply_size;
struct workqueue_struct *wmi_wq; /* for deferred calls */
struct work_struct wmi_event_worker;
struct workqueue_struct *wq_service;
- struct work_struct disconnect_worker;
struct work_struct fw_error_worker; /* for FW error recovery */
- struct timer_list connect_timer;
- struct timer_list scan_timer; /* detect scan timeout */
struct list_head pending_wmi_ev;
/*
* protect pending_wmi_ev
@@ -732,13 +766,10 @@ struct wil6210_priv {
*/
spinlock_t wmi_ev_lock;
spinlock_t net_queue_lock; /* guarding stop/wake netif queue */
- int net_queue_stopped; /* netif_tx_stop_all_queues invoked */
struct napi_struct napi_rx;
struct napi_struct napi_tx;
- /* keep alive */
- struct list_head probe_client_pending;
- struct mutex probe_client_mutex; /* protect @probe_client_pending */
- struct work_struct probe_client_worker;
+ struct net_device napi_ndev; /* dummy net_device serving all VIFs */
+
/* DMA related */
struct vring vring_rx;
unsigned int rx_buf_len;
@@ -746,11 +777,8 @@ struct wil6210_priv {
struct vring_tx_data vring_tx_data[WIL6210_MAX_TX_RINGS];
u8 vring2cid_tid[WIL6210_MAX_TX_RINGS][2]; /* [0] - CID, [1] - TID */
struct wil_sta_info sta[WIL6210_MAX_CID];
- int bcast_vring;
u32 vring_idle_trsh; /* HW fetches up to 16 descriptors at once */
u32 dma_addr_size; /* indicates dma addr size */
- /* scan */
- struct cfg80211_scan_request *scan_request;
struct mutex mutex; /* for wil6210_priv access in wil_{up|down} */
/* statistics */
@@ -770,13 +798,10 @@ struct wil6210_priv {
struct pmc_ctx pmc;
- bool pbss;
-
- struct wil_p2p_info p2p;
+ u8 p2p_dev_started;
/* P2P_DEVICE vif */
struct wireless_dev *p2p_wdev;
- struct mutex p2p_wdev_mutex; /* protect @p2p_wdev and @scan_request */
struct wireless_dev *radio_wdev;
/* High Access Latency Policy voting */
@@ -798,13 +823,35 @@ struct wil6210_priv {
u32 iccm_base;
};
-#define wil_to_wiphy(i) (i->wdev->wiphy)
+#define wil_to_wiphy(i) (i->wiphy)
#define wil_to_dev(i) (wiphy_dev(wil_to_wiphy(i)))
#define wiphy_to_wil(w) (struct wil6210_priv *)(wiphy_priv(w))
-#define wil_to_wdev(i) (i->wdev)
#define wdev_to_wil(w) (struct wil6210_priv *)(wdev_priv(w))
-#define wil_to_ndev(i) (wil_to_wdev(i)->netdev)
#define ndev_to_wil(n) (wdev_to_wil(n->ieee80211_ptr))
+#define ndev_to_vif(n) (struct wil6210_vif *)(netdev_priv(n))
+#define vif_to_wil(v) (v->wil)
+#define vif_to_ndev(v) (v->ndev)
+#define vif_to_wdev(v) (&v->wdev)
+
+static inline struct wil6210_vif *wdev_to_vif(struct wil6210_priv *wil,
+ struct wireless_dev *wdev)
+{
+ /* main interface is shared with P2P device */
+ if (wdev == wil->p2p_wdev)
+ return ndev_to_vif(wil->main_ndev);
+ else
+ return container_of(wdev, struct wil6210_vif, wdev);
+}
+
+static inline struct wireless_dev *
+vif_to_radio_wdev(struct wil6210_priv *wil, struct wil6210_vif *vif)
+{
+ /* main interface is shared with P2P device */
+ if (vif->mid)
+ return vif_to_wdev(vif);
+ else
+ return wil->radio_wdev;
+}
__printf(2, 3)
void wil_dbg_trace(struct wil6210_priv *wil, const char *fmt, ...);
@@ -817,7 +864,7 @@ void __wil_info(struct wil6210_priv *wil, const char *fmt, ...);
__printf(2, 3)
void wil_dbg_ratelimited(const struct wil6210_priv *wil, const char *fmt, ...);
#define wil_dbg(wil, fmt, arg...) do { \
- netdev_dbg(wil_to_ndev(wil), fmt, ##arg); \
+ netdev_dbg(wil->main_ndev, fmt, ##arg); \
wil_dbg_trace(wil, fmt, ##arg); \
} while (0)
@@ -900,9 +947,18 @@ void wil_memcpy_fromio_32(void *dst, const volatile void __iomem *src,
void wil_memcpy_toio_32(volatile void __iomem *dst, const void *src,
size_t count);
+struct wil6210_vif *
+wil_vif_alloc(struct wil6210_priv *wil, const char *name,
+ unsigned char name_assign_type, enum nl80211_iftype iftype);
+void wil_vif_free(struct wil6210_vif *vif);
void *wil_if_alloc(struct device *dev);
+bool wil_has_other_active_ifaces(struct wil6210_priv *wil,
+ struct net_device *ndev, bool up, bool ok);
+bool wil_has_active_ifaces(struct wil6210_priv *wil, bool up, bool ok);
void wil_if_free(struct wil6210_priv *wil);
+int wil_vif_add(struct wil6210_priv *wil, struct wil6210_vif *vif);
int wil_if_add(struct wil6210_priv *wil);
+void wil_vif_remove(struct wil6210_priv *wil, u8 mid);
void wil_if_remove(struct wil6210_priv *wil);
int wil_priv_init(struct wil6210_priv *wil);
void wil_priv_deinit(struct wil6210_priv *wil);
@@ -918,7 +974,7 @@ int wil_down(struct wil6210_priv *wil);
int __wil_down(struct wil6210_priv *wil);
void wil_refresh_fw_capabilities(struct wil6210_priv *wil);
void wil_mbox_ring_le2cpus(struct wil6210_mbox_ring *r);
-int wil_find_cid(struct wil6210_priv *wil, const u8 *mac);
+int wil_find_cid(struct wil6210_priv *wil, u8 mid, const u8 *mac);
void wil_set_ethtoolops(struct net_device *ndev);
struct fw_map *wil_find_fw_mapping(const char *section);
@@ -927,40 +983,45 @@ void __iomem *wmi_buffer(struct wil6210_priv *wil, __le32 ptr);
void __iomem *wmi_addr(struct wil6210_priv *wil, u32 ptr);
int wmi_read_hdr(struct wil6210_priv *wil, __le32 ptr,
struct wil6210_mbox_hdr *hdr);
-int wmi_send(struct wil6210_priv *wil, u16 cmdid, void *buf, u16 len);
+int wmi_send(struct wil6210_priv *wil, u16 cmdid, u8 mid, void *buf, u16 len);
void wmi_recv_cmd(struct wil6210_priv *wil);
-int wmi_call(struct wil6210_priv *wil, u16 cmdid, void *buf, u16 len,
+int wmi_call(struct wil6210_priv *wil, u16 cmdid, u8 mid, void *buf, u16 len,
u16 reply_id, void *reply, u8 reply_size, int to_msec);
void wmi_event_worker(struct work_struct *work);
void wmi_event_flush(struct wil6210_priv *wil);
-int wmi_set_ssid(struct wil6210_priv *wil, u8 ssid_len, const void *ssid);
-int wmi_get_ssid(struct wil6210_priv *wil, u8 *ssid_len, void *ssid);
+int wmi_set_ssid(struct wil6210_vif *vif, u8 ssid_len, const void *ssid);
+int wmi_get_ssid(struct wil6210_vif *vif, u8 *ssid_len, void *ssid);
int wmi_set_channel(struct wil6210_priv *wil, int channel);
int wmi_get_channel(struct wil6210_priv *wil, int *channel);
-int wmi_del_cipher_key(struct wil6210_priv *wil, u8 key_index,
+int wmi_del_cipher_key(struct wil6210_vif *vif, u8 key_index,
const void *mac_addr, int key_usage);
-int wmi_add_cipher_key(struct wil6210_priv *wil, u8 key_index,
+int wmi_add_cipher_key(struct wil6210_vif *vif, u8 key_index,
const void *mac_addr, int key_len, const void *key,
int key_usage);
int wmi_echo(struct wil6210_priv *wil);
-int wmi_set_ie(struct wil6210_priv *wil, u8 type, u16 ie_len, const void *ie);
+int wmi_set_ie(struct wil6210_vif *vif, u8 type, u16 ie_len, const void *ie);
int wmi_rx_chain_add(struct wil6210_priv *wil, struct vring *vring);
int wmi_rxon(struct wil6210_priv *wil, bool on);
int wmi_get_temperature(struct wil6210_priv *wil, u32 *t_m, u32 *t_r);
-int wmi_disconnect_sta(struct wil6210_priv *wil, const u8 *mac,
+int wmi_disconnect_sta(struct wil6210_vif *vif, const u8 *mac,
u16 reason, bool full_disconnect, bool del_sta);
-int wmi_addba(struct wil6210_priv *wil, u8 ringid, u8 size, u16 timeout);
-int wmi_delba_tx(struct wil6210_priv *wil, u8 ringid, u16 reason);
-int wmi_delba_rx(struct wil6210_priv *wil, u8 cidxtid, u16 reason);
-int wmi_addba_rx_resp(struct wil6210_priv *wil, u8 cid, u8 tid, u8 token,
+int wmi_addba(struct wil6210_priv *wil, u8 mid,
+ u8 ringid, u8 size, u16 timeout);
+int wmi_delba_tx(struct wil6210_priv *wil, u8 mid, u8 ringid, u16 reason);
+int wmi_delba_rx(struct wil6210_priv *wil, u8 mid, u8 cidxtid, u16 reason);
+int wmi_addba_rx_resp(struct wil6210_priv *wil,
+ u8 mid, u8 cid, u8 tid, u8 token,
u16 status, bool amsdu, u16 agg_wsize, u16 timeout);
int wmi_ps_dev_profile_cfg(struct wil6210_priv *wil,
enum wmi_ps_profile_type ps_profile);
int wmi_set_mgmt_retry(struct wil6210_priv *wil, u8 retry_short);
int wmi_get_mgmt_retry(struct wil6210_priv *wil, u8 *retry_short);
-int wmi_new_sta(struct wil6210_priv *wil, const u8 *mac, u8 aid);
-int wil_addba_rx_request(struct wil6210_priv *wil, u8 cidxtid,
- u8 dialog_token, __le16 ba_param_set,
+int wmi_new_sta(struct wil6210_vif *vif, const u8 *mac, u8 aid);
+int wmi_port_allocate(struct wil6210_priv *wil, u8 mid,
+ const u8 *mac, enum nl80211_iftype iftype);
+int wmi_port_delete(struct wil6210_priv *wil, u8 mid);
+int wil_addba_rx_request(struct wil6210_priv *wil, u8 mid,
+ u8 cidxtid, u8 dialog_token, __le16 ba_param_set,
__le16 ba_timeout, __le16 ba_seq_ctrl);
int wil_addba_tx_request(struct wil6210_priv *wil, u8 ringid, u16 wsize);
@@ -976,28 +1037,31 @@ void wil6210_mask_halp(struct wil6210_priv *wil);
/* P2P */
bool wil_p2p_is_social_scan(struct cfg80211_scan_request *request);
-void wil_p2p_discovery_timer_fn(struct timer_list *t);
-int wil_p2p_search(struct wil6210_priv *wil,
+int wil_p2p_search(struct wil6210_vif *vif,
struct cfg80211_scan_request *request);
int wil_p2p_listen(struct wil6210_priv *wil, struct wireless_dev *wdev,
unsigned int duration, struct ieee80211_channel *chan,
u64 *cookie);
-u8 wil_p2p_stop_discovery(struct wil6210_priv *wil);
-int wil_p2p_cancel_listen(struct wil6210_priv *wil, u64 cookie);
+u8 wil_p2p_stop_discovery(struct wil6210_vif *vif);
+int wil_p2p_cancel_listen(struct wil6210_vif *vif, u64 cookie);
void wil_p2p_listen_expired(struct work_struct *work);
void wil_p2p_search_expired(struct work_struct *work);
void wil_p2p_stop_radio_operations(struct wil6210_priv *wil);
void wil_p2p_delayed_listen_work(struct work_struct *work);
/* WMI for P2P */
-int wmi_p2p_cfg(struct wil6210_priv *wil, int channel, int bi);
-int wmi_start_listen(struct wil6210_priv *wil);
-int wmi_start_search(struct wil6210_priv *wil);
-int wmi_stop_discovery(struct wil6210_priv *wil);
+int wmi_p2p_cfg(struct wil6210_vif *vif, int channel, int bi);
+int wmi_start_listen(struct wil6210_vif *vif);
+int wmi_start_search(struct wil6210_vif *vif);
+int wmi_stop_discovery(struct wil6210_vif *vif);
int wil_cfg80211_mgmt_tx(struct wiphy *wiphy, struct wireless_dev *wdev,
struct cfg80211_mgmt_tx_params *params,
u64 *cookie);
+int wil_cfg80211_iface_combinations_from_fw(
+ struct wil6210_priv *wil,
+ const struct wil_fw_record_concurrency *conc);
+int wil_vif_prepare_stop(struct wil6210_vif *vif);
#if defined(CONFIG_WIL6210_DEBUGFS)
int wil6210_debugfs_init(struct wil6210_priv *wil);
@@ -1007,44 +1071,47 @@ static inline int wil6210_debugfs_init(struct wil6210_priv *wil) { return 0; }
static inline void wil6210_debugfs_remove(struct wil6210_priv *wil) {}
#endif
-int wil_cid_fill_sinfo(struct wil6210_priv *wil, int cid,
+int wil_cid_fill_sinfo(struct wil6210_vif *vif, int cid,
struct station_info *sinfo);
-struct wireless_dev *wil_cfg80211_init(struct device *dev);
-void wil_wdev_free(struct wil6210_priv *wil);
+struct wil6210_priv *wil_cfg80211_init(struct device *dev);
+void wil_cfg80211_deinit(struct wil6210_priv *wil);
void wil_p2p_wdev_free(struct wil6210_priv *wil);
int wmi_set_mac_address(struct wil6210_priv *wil, void *addr);
-int wmi_pcp_start(struct wil6210_priv *wil, int bi, u8 wmi_nettype,
- u8 chan, u8 hidden_ssid, u8 is_go);
-int wmi_pcp_stop(struct wil6210_priv *wil);
+int wmi_pcp_start(struct wil6210_vif *vif, int bi, u8 wmi_nettype, u8 chan,
+ u8 hidden_ssid, u8 is_go);
+int wmi_pcp_stop(struct wil6210_vif *vif);
int wmi_led_cfg(struct wil6210_priv *wil, bool enable);
-int wmi_abort_scan(struct wil6210_priv *wil);
-void wil_abort_scan(struct wil6210_priv *wil, bool sync);
+int wmi_abort_scan(struct wil6210_vif *vif);
+void wil_abort_scan(struct wil6210_vif *vif, bool sync);
+void wil_abort_scan_all_vifs(struct wil6210_priv *wil, bool sync);
void wil6210_bus_request(struct wil6210_priv *wil, u32 kbps);
-void wil6210_disconnect(struct wil6210_priv *wil, const u8 *bssid,
+void wil6210_disconnect(struct wil6210_vif *vif, const u8 *bssid,
u16 reason_code, bool from_event);
-void wil_probe_client_flush(struct wil6210_priv *wil);
+void wil_probe_client_flush(struct wil6210_vif *vif);
void wil_probe_client_worker(struct work_struct *work);
+void wil_disconnect_worker(struct work_struct *work);
int wil_rx_init(struct wil6210_priv *wil, u16 size);
void wil_rx_fini(struct wil6210_priv *wil);
/* TX API */
-int wil_vring_init_tx(struct wil6210_priv *wil, int id, int size,
+int wil_vring_init_tx(struct wil6210_vif *vif, int id, int size,
int cid, int tid);
void wil_vring_fini_tx(struct wil6210_priv *wil, int id);
-int wil_tx_init(struct wil6210_priv *wil, int cid);
-int wil_vring_init_bcast(struct wil6210_priv *wil, int id, int size);
-int wil_bcast_init(struct wil6210_priv *wil);
-void wil_bcast_fini(struct wil6210_priv *wil);
-
-void wil_update_net_queues(struct wil6210_priv *wil, struct vring *vring,
- bool should_stop);
-void wil_update_net_queues_bh(struct wil6210_priv *wil, struct vring *vring,
- bool check_stop);
+int wil_tx_init(struct wil6210_vif *vif, int cid);
+int wil_vring_init_bcast(struct wil6210_vif *vif, int id, int size);
+int wil_bcast_init(struct wil6210_vif *vif);
+void wil_bcast_fini(struct wil6210_vif *vif);
+void wil_bcast_fini_all(struct wil6210_priv *wil);
+
+void wil_update_net_queues(struct wil6210_priv *wil, struct wil6210_vif *vif,
+ struct vring *vring, bool should_stop);
+void wil_update_net_queues_bh(struct wil6210_priv *wil, struct wil6210_vif *vif,
+ struct vring *vring, bool check_stop);
netdev_tx_t wil_start_xmit(struct sk_buff *skb, struct net_device *ndev);
-int wil_tx_complete(struct wil6210_priv *wil, int ringid);
+int wil_tx_complete(struct wil6210_vif *vif, int ringid);
void wil6210_unmask_irq_tx(struct wil6210_priv *wil);
/* RX API */
diff --git a/drivers/net/wireless/ath/wil6210/wmi.c b/drivers/net/wireless/ath/wil6210/wmi.c
index b31e2514f8c2..a3dda9a97c1f 100644
--- a/drivers/net/wireless/ath/wil6210/wmi.c
+++ b/drivers/net/wireless/ath/wil6210/wmi.c
@@ -341,6 +341,10 @@ static const char *cmdid2name(u16 cmdid)
return "WMI_GET_PCP_CHANNEL_CMD";
case WMI_P2P_CFG_CMDID:
return "WMI_P2P_CFG_CMD";
+ case WMI_PORT_ALLOCATE_CMDID:
+ return "WMI_PORT_ALLOCATE_CMD";
+ case WMI_PORT_DELETE_CMDID:
+ return "WMI_PORT_DELETE_CMD";
case WMI_START_LISTEN_CMDID:
return "WMI_START_LISTEN_CMD";
case WMI_START_SEARCH_CMDID:
@@ -479,6 +483,10 @@ static const char *eventid2name(u16 eventid)
return "WMI_GET_PCP_CHANNEL_EVENT";
case WMI_P2P_CFG_DONE_EVENTID:
return "WMI_P2P_CFG_DONE_EVENT";
+ case WMI_PORT_ALLOCATED_EVENTID:
+ return "WMI_PORT_ALLOCATED_EVENT";
+ case WMI_PORT_DELETED_EVENTID:
+ return "WMI_PORT_DELETED_EVENT";
case WMI_LISTEN_STARTED_EVENTID:
return "WMI_LISTEN_STARTED_EVENT";
case WMI_SEARCH_STARTED_EVENTID:
@@ -516,7 +524,8 @@ static const char *eventid2name(u16 eventid)
}
}
-static int __wmi_send(struct wil6210_priv *wil, u16 cmdid, void *buf, u16 len)
+static int __wmi_send(struct wil6210_priv *wil, u16 cmdid, u8 mid,
+ void *buf, u16 len)
{
struct {
struct wil6210_mbox_hdr hdr;
@@ -528,7 +537,7 @@ static int __wmi_send(struct wil6210_priv *wil, u16 cmdid, void *buf, u16 len)
.len = cpu_to_le16(sizeof(cmd.wmi) + len),
},
.wmi = {
- .mid = 0,
+ .mid = mid,
.command_id = cpu_to_le16(cmdid),
},
};
@@ -612,8 +621,8 @@ static int __wmi_send(struct wil6210_priv *wil, u16 cmdid, void *buf, u16 len)
}
cmd.hdr.seq = cpu_to_le16(++wil->wmi_seq);
/* set command */
- wil_dbg_wmi(wil, "sending %s (0x%04x) [%d]\n",
- cmdid2name(cmdid), cmdid, len);
+ wil_dbg_wmi(wil, "sending %s (0x%04x) [%d] mid %d\n",
+ cmdid2name(cmdid), cmdid, len, mid);
wil_hex_dump_wmi("Cmd ", DUMP_PREFIX_OFFSET, 16, 1, &cmd,
sizeof(cmd), true);
wil_hex_dump_wmi("cmd ", DUMP_PREFIX_OFFSET, 16, 1, buf,
@@ -637,31 +646,34 @@ out:
return rc;
}
-int wmi_send(struct wil6210_priv *wil, u16 cmdid, void *buf, u16 len)
+int wmi_send(struct wil6210_priv *wil, u16 cmdid, u8 mid, void *buf, u16 len)
{
int rc;
mutex_lock(&wil->wmi_mutex);
- rc = __wmi_send(wil, cmdid, buf, len);
+ rc = __wmi_send(wil, cmdid, mid, buf, len);
mutex_unlock(&wil->wmi_mutex);
return rc;
}
/*=== Event handlers ===*/
-static void wmi_evt_ready(struct wil6210_priv *wil, int id, void *d, int len)
+static void wmi_evt_ready(struct wil6210_vif *vif, int id, void *d, int len)
{
- struct wireless_dev *wdev = wil->wdev;
+ struct wil6210_priv *wil = vif_to_wil(vif);
+ struct wiphy *wiphy = wil_to_wiphy(wil);
struct wmi_ready_event *evt = d;
- wil->n_mids = evt->numof_additional_mids;
-
wil_info(wil, "FW ver. %s(SW %d); MAC %pM; %d MID's\n",
wil->fw_version, le32_to_cpu(evt->sw_version),
- evt->mac, wil->n_mids);
+ evt->mac, evt->numof_additional_mids);
+ if (evt->numof_additional_mids + 1 < wil->max_vifs) {
+ wil_err(wil, "FW does not support enough MIDs (need %d)",
+ wil->max_vifs - 1);
+ return; /* FW load will fail after timeout */
+ }
/* ignore MAC address, we already have it from the boot loader */
- strlcpy(wdev->wiphy->fw_version, wil->fw_version,
- sizeof(wdev->wiphy->fw_version));
+ strlcpy(wiphy->fw_version, wil->fw_version, sizeof(wiphy->fw_version));
if (len > offsetof(struct wmi_ready_event, rfc_read_calib_result)) {
wil_dbg_wmi(wil, "rfc calibration result %d\n",
@@ -674,8 +686,9 @@ static void wmi_evt_ready(struct wil6210_priv *wil, int id, void *d, int len)
complete(&wil->wmi_ready);
}
-static void wmi_evt_rx_mgmt(struct wil6210_priv *wil, int id, void *d, int len)
+static void wmi_evt_rx_mgmt(struct wil6210_vif *vif, int id, void *d, int len)
{
+ struct wil6210_priv *wil = vif_to_wil(vif);
struct wmi_rx_mgmt_packet_event *data = d;
struct wiphy *wiphy = wil_to_wiphy(wil);
struct ieee80211_mgmt *rx_mgmt_frame =
@@ -753,14 +766,14 @@ static void wmi_evt_rx_mgmt(struct wil6210_priv *wil, int id, void *d, int len)
wil_err(wil, "cfg80211_inform_bss_frame() failed\n");
}
} else {
- mutex_lock(&wil->p2p_wdev_mutex);
- cfg80211_rx_mgmt(wil->radio_wdev, freq, signal,
+ mutex_lock(&wil->vif_mutex);
+ cfg80211_rx_mgmt(vif_to_radio_wdev(wil, vif), freq, signal,
(void *)rx_mgmt_frame, d_len, 0);
- mutex_unlock(&wil->p2p_wdev_mutex);
+ mutex_unlock(&wil->vif_mutex);
}
}
-static void wmi_evt_tx_mgmt(struct wil6210_priv *wil, int id, void *d, int len)
+static void wmi_evt_tx_mgmt(struct wil6210_vif *vif, int id, void *d, int len)
{
struct wmi_tx_mgmt_packet_event *data = d;
struct ieee80211_mgmt *mgmt_frame =
@@ -771,11 +784,13 @@ static void wmi_evt_tx_mgmt(struct wil6210_priv *wil, int id, void *d, int len)
flen, true);
}
-static void wmi_evt_scan_complete(struct wil6210_priv *wil, int id,
+static void wmi_evt_scan_complete(struct wil6210_vif *vif, int id,
void *d, int len)
{
- mutex_lock(&wil->p2p_wdev_mutex);
- if (wil->scan_request) {
+ struct wil6210_priv *wil = vif_to_wil(vif);
+
+ mutex_lock(&wil->vif_mutex);
+ if (vif->scan_request) {
struct wmi_scan_complete_event *data = d;
int status = le32_to_cpu(data->status);
struct cfg80211_scan_info info = {
@@ -785,26 +800,28 @@ static void wmi_evt_scan_complete(struct wil6210_priv *wil, int id,
wil_dbg_wmi(wil, "SCAN_COMPLETE(0x%08x)\n", status);
wil_dbg_misc(wil, "Complete scan_request 0x%p aborted %d\n",
- wil->scan_request, info.aborted);
- del_timer_sync(&wil->scan_timer);
- cfg80211_scan_done(wil->scan_request, &info);
- wil->radio_wdev = wil->wdev;
- wil->scan_request = NULL;
+ vif->scan_request, info.aborted);
+ del_timer_sync(&vif->scan_timer);
+ cfg80211_scan_done(vif->scan_request, &info);
+ if (vif->mid == 0)
+ wil->radio_wdev = wil->main_ndev->ieee80211_ptr;
+ vif->scan_request = NULL;
wake_up_interruptible(&wil->wq);
- if (wil->p2p.pending_listen_wdev) {
+ if (vif->p2p.pending_listen_wdev) {
wil_dbg_misc(wil, "Scheduling delayed listen\n");
- schedule_work(&wil->p2p.delayed_listen_work);
+ schedule_work(&vif->p2p.delayed_listen_work);
}
} else {
wil_err(wil, "SCAN_COMPLETE while not scanning\n");
}
- mutex_unlock(&wil->p2p_wdev_mutex);
+ mutex_unlock(&wil->vif_mutex);
}
-static void wmi_evt_connect(struct wil6210_priv *wil, int id, void *d, int len)
+static void wmi_evt_connect(struct wil6210_vif *vif, int id, void *d, int len)
{
- struct net_device *ndev = wil_to_ndev(wil);
- struct wireless_dev *wdev = wil->wdev;
+ struct wil6210_priv *wil = vif_to_wil(vif);
+ struct net_device *ndev = vif_to_ndev(vif);
+ struct wireless_dev *wdev = vif_to_wdev(vif);
struct wmi_connect_event *evt = d;
int ch; /* channel number */
struct station_info sinfo;
@@ -869,12 +886,12 @@ static void wmi_evt_connect(struct wil6210_priv *wil, int id, void *d, int len)
if ((wdev->iftype == NL80211_IFTYPE_STATION) ||
(wdev->iftype == NL80211_IFTYPE_P2P_CLIENT)) {
- if (!test_bit(wil_status_fwconnecting, wil->status)) {
+ if (!test_bit(wil_vif_fwconnecting, vif->status)) {
wil_err(wil, "Not in connecting state\n");
mutex_unlock(&wil->mutex);
return;
}
- del_timer_sync(&wil->connect_timer);
+ del_timer_sync(&vif->connect_timer);
} else if ((wdev->iftype == NL80211_IFTYPE_AP) ||
(wdev->iftype == NL80211_IFTYPE_P2P_GO)) {
if (wil->sta[evt->cid].status != wil_sta_unused) {
@@ -886,13 +903,14 @@ static void wmi_evt_connect(struct wil6210_priv *wil, int id, void *d, int len)
}
ether_addr_copy(wil->sta[evt->cid].addr, evt->bssid);
+ wil->sta[evt->cid].mid = vif->mid;
wil->sta[evt->cid].status = wil_sta_conn_pending;
- rc = wil_tx_init(wil, evt->cid);
+ rc = wil_tx_init(vif, evt->cid);
if (rc) {
wil_err(wil, "config tx vring failed for CID %d, rc (%d)\n",
evt->cid, rc);
- wmi_disconnect_sta(wil, wil->sta[evt->cid].addr,
+ wmi_disconnect_sta(vif, wil->sta[evt->cid].addr,
WLAN_REASON_UNSPECIFIED, false, false);
} else {
wil_info(wil, "successful connection to CID %d\n", evt->cid);
@@ -912,14 +930,14 @@ static void wmi_evt_connect(struct wil6210_priv *wil, int id, void *d, int len)
} else {
struct wiphy *wiphy = wil_to_wiphy(wil);
- cfg80211_ref_bss(wiphy, wil->bss);
- cfg80211_connect_bss(ndev, evt->bssid, wil->bss,
+ cfg80211_ref_bss(wiphy, vif->bss);
+ cfg80211_connect_bss(ndev, evt->bssid, vif->bss,
assoc_req_ie, assoc_req_ielen,
assoc_resp_ie, assoc_resp_ielen,
WLAN_STATUS_SUCCESS, GFP_KERNEL,
NL80211_TIMEOUT_UNSPECIFIED);
}
- wil->bss = NULL;
+ vif->bss = NULL;
} else if ((wdev->iftype == NL80211_IFTYPE_AP) ||
(wdev->iftype == NL80211_IFTYPE_P2P_GO)) {
if (rc) {
@@ -947,19 +965,23 @@ static void wmi_evt_connect(struct wil6210_priv *wil, int id, void *d, int len)
wil->sta[evt->cid].status = wil_sta_connected;
wil->sta[evt->cid].aid = evt->aid;
- set_bit(wil_status_fwconnected, wil->status);
- wil_update_net_queues_bh(wil, NULL, false);
+ if (!test_and_set_bit(wil_vif_fwconnected, vif->status))
+ atomic_inc(&wil->connected_vifs);
+ wil_update_net_queues_bh(wil, vif, NULL, false);
out:
- if (rc)
+ if (rc) {
wil->sta[evt->cid].status = wil_sta_unused;
- clear_bit(wil_status_fwconnecting, wil->status);
+ wil->sta[evt->cid].mid = U8_MAX;
+ }
+ clear_bit(wil_vif_fwconnecting, vif->status);
mutex_unlock(&wil->mutex);
}
-static void wmi_evt_disconnect(struct wil6210_priv *wil, int id,
+static void wmi_evt_disconnect(struct wil6210_vif *vif, int id,
void *d, int len)
{
+ struct wil6210_priv *wil = vif_to_wil(vif);
struct wmi_disconnect_event *evt = d;
u16 reason_code = le16_to_cpu(evt->protocol_reason_status);
@@ -976,7 +998,7 @@ static void wmi_evt_disconnect(struct wil6210_priv *wil, int id,
}
mutex_lock(&wil->mutex);
- wil6210_disconnect(wil, evt->bssid, reason_code, true);
+ wil6210_disconnect(vif, evt->bssid, reason_code, true);
mutex_unlock(&wil->mutex);
}
@@ -984,10 +1006,10 @@ static void wmi_evt_disconnect(struct wil6210_priv *wil, int id,
* Firmware reports EAPOL frame using WME event.
* Reconstruct Ethernet frame and deliver it via normal Rx
*/
-static void wmi_evt_eapol_rx(struct wil6210_priv *wil, int id,
- void *d, int len)
+static void wmi_evt_eapol_rx(struct wil6210_vif *vif, int id, void *d, int len)
{
- struct net_device *ndev = wil_to_ndev(wil);
+ struct wil6210_priv *wil = vif_to_wil(vif);
+ struct net_device *ndev = vif_to_ndev(vif);
struct wmi_eapol_rx_event *evt = d;
u16 eapol_len = le16_to_cpu(evt->eapol_len);
int sz = eapol_len + ETH_HLEN;
@@ -996,10 +1018,10 @@ static void wmi_evt_eapol_rx(struct wil6210_priv *wil, int id,
int cid;
struct wil_net_stats *stats = NULL;
- wil_dbg_wmi(wil, "EAPOL len %d from %pM\n", eapol_len,
- evt->src_mac);
+ wil_dbg_wmi(wil, "EAPOL len %d from %pM MID %d\n", eapol_len,
+ evt->src_mac, vif->mid);
- cid = wil_find_cid(wil, evt->src_mac);
+ cid = wil_find_cid(wil, vif->mid, evt->src_mac);
if (cid >= 0)
stats = &wil->sta[cid].stats;
@@ -1034,13 +1056,14 @@ static void wmi_evt_eapol_rx(struct wil6210_priv *wil, int id,
}
}
-static void wmi_evt_vring_en(struct wil6210_priv *wil, int id, void *d, int len)
+static void wmi_evt_vring_en(struct wil6210_vif *vif, int id, void *d, int len)
{
+ struct wil6210_priv *wil = vif_to_wil(vif);
struct wmi_vring_en_event *evt = d;
u8 vri = evt->vring_index;
- struct wireless_dev *wdev = wil_to_wdev(wil);
+ struct wireless_dev *wdev = vif_to_wdev(vif);
- wil_dbg_wmi(wil, "Enable vring %d\n", vri);
+ wil_dbg_wmi(wil, "Enable vring %d MID %d\n", vri, vif->mid);
if (vri >= ARRAY_SIZE(wil->vring_tx)) {
wil_err(wil, "Enable for invalid vring %d\n", vri);
@@ -1052,15 +1075,16 @@ static void wmi_evt_vring_en(struct wil6210_priv *wil, int id, void *d, int len)
* wil_cfg80211_change_station()
*/
wil->vring_tx_data[vri].dot1x_open = true;
- if (vri == wil->bcast_vring) /* no BA for bcast */
+ if (vri == vif->bcast_vring) /* no BA for bcast */
return;
if (agg_wsize >= 0)
wil_addba_tx_request(wil, vri, agg_wsize);
}
-static void wmi_evt_ba_status(struct wil6210_priv *wil, int id, void *d,
- int len)
+static void wmi_evt_ba_status(struct wil6210_vif *vif, int id,
+ void *d, int len)
{
+ struct wil6210_priv *wil = vif_to_wil(vif);
struct wmi_ba_status_event *evt = d;
struct vring_tx_data *txdata;
@@ -1089,19 +1113,21 @@ static void wmi_evt_ba_status(struct wil6210_priv *wil, int id, void *d,
txdata->addba_in_progress = false;
}
-static void wmi_evt_addba_rx_req(struct wil6210_priv *wil, int id, void *d,
- int len)
+static void wmi_evt_addba_rx_req(struct wil6210_vif *vif, int id,
+ void *d, int len)
{
+ struct wil6210_priv *wil = vif_to_wil(vif);
struct wmi_rcp_addba_req_event *evt = d;
- wil_addba_rx_request(wil, evt->cidxtid, evt->dialog_token,
+ wil_addba_rx_request(wil, vif->mid, evt->cidxtid, evt->dialog_token,
evt->ba_param_set, evt->ba_timeout,
evt->ba_seq_ctrl);
}
-static void wmi_evt_delba(struct wil6210_priv *wil, int id, void *d, int len)
+static void wmi_evt_delba(struct wil6210_vif *vif, int id, void *d, int len)
__acquires(&sta->tid_rx_lock) __releases(&sta->tid_rx_lock)
{
+ struct wil6210_priv *wil = vif_to_wil(vif);
struct wmi_delba_event *evt = d;
u8 cid, tid;
u16 reason = __le16_to_cpu(evt->reason);
@@ -1110,8 +1136,8 @@ __acquires(&sta->tid_rx_lock) __releases(&sta->tid_rx_lock)
might_sleep();
parse_cidxtid(evt->cidxtid, &cid, &tid);
- wil_dbg_wmi(wil, "DELBA CID %d TID %d from %s reason %d\n",
- cid, tid,
+ wil_dbg_wmi(wil, "DELBA MID %d CID %d TID %d from %s reason %d\n",
+ vif->mid, cid, tid,
evt->from_initiator ? "originator" : "recipient",
reason);
if (!evt->from_initiator) {
@@ -1148,8 +1174,9 @@ __acquires(&sta->tid_rx_lock) __releases(&sta->tid_rx_lock)
}
static void
-wmi_evt_sched_scan_result(struct wil6210_priv *wil, int id, void *d, int len)
+wmi_evt_sched_scan_result(struct wil6210_vif *vif, int id, void *d, int len)
{
+ struct wil6210_priv *wil = vif_to_wil(vif);
struct wmi_sched_scan_result_event *data = d;
struct wiphy *wiphy = wil_to_wiphy(wil);
struct ieee80211_mgmt *rx_mgmt_frame =
@@ -1220,15 +1247,17 @@ wmi_evt_sched_scan_result(struct wil6210_priv *wil, int id, void *d, int len)
* Some events are ignored for purpose; and need not be interpreted as
* "unhandled events"
*/
-static void wmi_evt_ignore(struct wil6210_priv *wil, int id, void *d, int len)
+static void wmi_evt_ignore(struct wil6210_vif *vif, int id, void *d, int len)
{
+ struct wil6210_priv *wil = vif_to_wil(vif);
+
wil_dbg_wmi(wil, "Ignore event 0x%04x len %d\n", id, len);
}
static const struct {
int eventid;
- void (*handler)(struct wil6210_priv *wil, int eventid,
- void *data, int data_len);
+ void (*handler)(struct wil6210_vif *vif,
+ int eventid, void *data, int data_len);
} wmi_evt_handlers[] = {
{WMI_READY_EVENTID, wmi_evt_ready},
{WMI_FW_READY_EVENTID, wmi_evt_ignore},
@@ -1325,6 +1354,7 @@ void wmi_recv_cmd(struct wil6210_priv *wil)
(len >= sizeof(struct wmi_cmd_hdr))) {
struct wmi_cmd_hdr *wmi = &evt->event.wmi;
u16 id = le16_to_cpu(wmi->command_id);
+ u8 mid = wmi->mid;
u32 tstamp = le32_to_cpu(wmi->fw_timestamp);
if (test_bit(wil_status_resuming, wil->status)) {
if (id == WMI_TRAFFIC_RESUME_EVENTID)
@@ -1336,7 +1366,8 @@ void wmi_recv_cmd(struct wil6210_priv *wil)
id);
}
spin_lock_irqsave(&wil->wmi_ev_lock, flags);
- if (wil->reply_id && wil->reply_id == id) {
+ if (wil->reply_id && wil->reply_id == id &&
+ wil->reply_mid == mid) {
if (wil->reply_buf) {
memcpy(wil->reply_buf, wmi,
min(len, wil->reply_size));
@@ -1384,7 +1415,7 @@ void wmi_recv_cmd(struct wil6210_priv *wil)
n - num_immed_reply, num_immed_reply);
}
-int wmi_call(struct wil6210_priv *wil, u16 cmdid, void *buf, u16 len,
+int wmi_call(struct wil6210_priv *wil, u16 cmdid, u8 mid, void *buf, u16 len,
u16 reply_id, void *reply, u8 reply_size, int to_msec)
{
int rc;
@@ -1394,12 +1425,13 @@ int wmi_call(struct wil6210_priv *wil, u16 cmdid, void *buf, u16 len,
spin_lock(&wil->wmi_ev_lock);
wil->reply_id = reply_id;
+ wil->reply_mid = mid;
wil->reply_buf = reply;
wil->reply_size = reply_size;
reinit_completion(&wil->wmi_call);
spin_unlock(&wil->wmi_ev_lock);
- rc = __wmi_send(wil, cmdid, buf, len);
+ rc = __wmi_send(wil, cmdid, mid, buf, len);
if (rc)
goto out;
@@ -1419,6 +1451,7 @@ int wmi_call(struct wil6210_priv *wil, u16 cmdid, void *buf, u16 len,
out:
spin_lock(&wil->wmi_ev_lock);
wil->reply_id = 0;
+ wil->reply_mid = U8_MAX;
wil->reply_buf = NULL;
wil->reply_size = 0;
spin_unlock(&wil->wmi_ev_lock);
@@ -1430,27 +1463,31 @@ out:
int wmi_echo(struct wil6210_priv *wil)
{
+ struct wil6210_vif *vif = ndev_to_vif(wil->main_ndev);
struct wmi_echo_cmd cmd = {
.value = cpu_to_le32(0x12345678),
};
- return wmi_call(wil, WMI_ECHO_CMDID, &cmd, sizeof(cmd),
+ return wmi_call(wil, WMI_ECHO_CMDID, vif->mid, &cmd, sizeof(cmd),
WMI_ECHO_RSP_EVENTID, NULL, 0, 50);
}
int wmi_set_mac_address(struct wil6210_priv *wil, void *addr)
{
+ struct wil6210_vif *vif = ndev_to_vif(wil->main_ndev);
struct wmi_set_mac_address_cmd cmd;
ether_addr_copy(cmd.mac, addr);
wil_dbg_wmi(wil, "Set MAC %pM\n", addr);
- return wmi_send(wil, WMI_SET_MAC_ADDRESS_CMDID, &cmd, sizeof(cmd));
+ return wmi_send(wil, WMI_SET_MAC_ADDRESS_CMDID, vif->mid,
+ &cmd, sizeof(cmd));
}
int wmi_led_cfg(struct wil6210_priv *wil, bool enable)
{
+ struct wil6210_vif *vif = ndev_to_vif(wil->main_ndev);
int rc = 0;
struct wmi_led_cfg_cmd cmd = {
.led_mode = enable,
@@ -1487,7 +1524,7 @@ int wmi_led_cfg(struct wil6210_priv *wil, bool enable)
"%s led %d\n",
enable ? "enabling" : "disabling", led_id);
- rc = wmi_call(wil, WMI_LED_CFG_CMDID, &cmd, sizeof(cmd),
+ rc = wmi_call(wil, WMI_LED_CFG_CMDID, vif->mid, &cmd, sizeof(cmd),
WMI_LED_CFG_DONE_EVENTID, &reply, sizeof(reply),
100);
if (rc)
@@ -1503,9 +1540,10 @@ out:
return rc;
}
-int wmi_pcp_start(struct wil6210_priv *wil, int bi, u8 wmi_nettype,
- u8 chan, u8 hidden_ssid, u8 is_go)
+int wmi_pcp_start(struct wil6210_vif *vif,
+ int bi, u8 wmi_nettype, u8 chan, u8 hidden_ssid, u8 is_go)
{
+ struct wil6210_priv *wil = vif_to_wil(vif);
int rc;
struct wmi_pcp_start_cmd cmd = {
@@ -1524,7 +1562,7 @@ int wmi_pcp_start(struct wil6210_priv *wil, int bi, u8 wmi_nettype,
struct wmi_pcp_started_event evt;
} __packed reply;
- if (!wil->privacy)
+ if (!vif->privacy)
cmd.disable_sec = 1;
if ((cmd.pcp_max_assoc_sta > WIL6210_MAX_CID) ||
@@ -1546,7 +1584,7 @@ int wmi_pcp_start(struct wil6210_priv *wil, int bi, u8 wmi_nettype,
* Processing time may be huge, in case of secure AP it takes about
* 3500ms for FW to start AP
*/
- rc = wmi_call(wil, WMI_PCP_START_CMDID, &cmd, sizeof(cmd),
+ rc = wmi_call(wil, WMI_PCP_START_CMDID, vif->mid, &cmd, sizeof(cmd),
WMI_PCP_STARTED_EVENTID, &reply, sizeof(reply), 5000);
if (rc)
return rc;
@@ -1561,20 +1599,22 @@ int wmi_pcp_start(struct wil6210_priv *wil, int bi, u8 wmi_nettype,
return rc;
}
-int wmi_pcp_stop(struct wil6210_priv *wil)
+int wmi_pcp_stop(struct wil6210_vif *vif)
{
+ struct wil6210_priv *wil = vif_to_wil(vif);
int rc;
rc = wmi_led_cfg(wil, false);
if (rc)
return rc;
- return wmi_call(wil, WMI_PCP_STOP_CMDID, NULL, 0,
+ return wmi_call(wil, WMI_PCP_STOP_CMDID, vif->mid, NULL, 0,
WMI_PCP_STOPPED_EVENTID, NULL, 0, 20);
}
-int wmi_set_ssid(struct wil6210_priv *wil, u8 ssid_len, const void *ssid)
+int wmi_set_ssid(struct wil6210_vif *vif, u8 ssid_len, const void *ssid)
{
+ struct wil6210_priv *wil = vif_to_wil(vif);
struct wmi_set_ssid_cmd cmd = {
.ssid_len = cpu_to_le32(ssid_len),
};
@@ -1584,11 +1624,12 @@ int wmi_set_ssid(struct wil6210_priv *wil, u8 ssid_len, const void *ssid)
memcpy(cmd.ssid, ssid, ssid_len);
- return wmi_send(wil, WMI_SET_SSID_CMDID, &cmd, sizeof(cmd));
+ return wmi_send(wil, WMI_SET_SSID_CMDID, vif->mid, &cmd, sizeof(cmd));
}
-int wmi_get_ssid(struct wil6210_priv *wil, u8 *ssid_len, void *ssid)
+int wmi_get_ssid(struct wil6210_vif *vif, u8 *ssid_len, void *ssid)
{
+ struct wil6210_priv *wil = vif_to_wil(vif);
int rc;
struct {
struct wmi_cmd_hdr wmi;
@@ -1596,8 +1637,8 @@ int wmi_get_ssid(struct wil6210_priv *wil, u8 *ssid_len, void *ssid)
} __packed reply;
int len; /* reply.cmd.ssid_len in CPU order */
- rc = wmi_call(wil, WMI_GET_SSID_CMDID, NULL, 0, WMI_GET_SSID_EVENTID,
- &reply, sizeof(reply), 20);
+ rc = wmi_call(wil, WMI_GET_SSID_CMDID, vif->mid, NULL, 0,
+ WMI_GET_SSID_EVENTID, &reply, sizeof(reply), 20);
if (rc)
return rc;
@@ -1613,22 +1654,25 @@ int wmi_get_ssid(struct wil6210_priv *wil, u8 *ssid_len, void *ssid)
int wmi_set_channel(struct wil6210_priv *wil, int channel)
{
+ struct wil6210_vif *vif = ndev_to_vif(wil->main_ndev);
struct wmi_set_pcp_channel_cmd cmd = {
.channel = channel - 1,
};
- return wmi_send(wil, WMI_SET_PCP_CHANNEL_CMDID, &cmd, sizeof(cmd));
+ return wmi_send(wil, WMI_SET_PCP_CHANNEL_CMDID, vif->mid,
+ &cmd, sizeof(cmd));
}
int wmi_get_channel(struct wil6210_priv *wil, int *channel)
{
+ struct wil6210_vif *vif = ndev_to_vif(wil->main_ndev);
int rc;
struct {
struct wmi_cmd_hdr wmi;
struct wmi_set_pcp_channel_cmd cmd;
} __packed reply;
- rc = wmi_call(wil, WMI_GET_PCP_CHANNEL_CMDID, NULL, 0,
+ rc = wmi_call(wil, WMI_GET_PCP_CHANNEL_CMDID, vif->mid, NULL, 0,
WMI_GET_PCP_CHANNEL_EVENTID, &reply, sizeof(reply), 20);
if (rc)
return rc;
@@ -1641,8 +1685,9 @@ int wmi_get_channel(struct wil6210_priv *wil, int *channel)
return 0;
}
-int wmi_p2p_cfg(struct wil6210_priv *wil, int channel, int bi)
+int wmi_p2p_cfg(struct wil6210_vif *vif, int channel, int bi)
{
+ struct wil6210_priv *wil = vif_to_wil(vif);
int rc;
struct wmi_p2p_cfg_cmd cmd = {
.discovery_mode = WMI_DISCOVERY_MODE_PEER2PEER,
@@ -1656,7 +1701,7 @@ int wmi_p2p_cfg(struct wil6210_priv *wil, int channel, int bi)
wil_dbg_wmi(wil, "sending WMI_P2P_CFG_CMDID\n");
- rc = wmi_call(wil, WMI_P2P_CFG_CMDID, &cmd, sizeof(cmd),
+ rc = wmi_call(wil, WMI_P2P_CFG_CMDID, vif->mid, &cmd, sizeof(cmd),
WMI_P2P_CFG_DONE_EVENTID, &reply, sizeof(reply), 300);
if (!rc && reply.evt.status != WMI_FW_STATUS_SUCCESS) {
wil_err(wil, "P2P_CFG failed. status %d\n", reply.evt.status);
@@ -1666,8 +1711,9 @@ int wmi_p2p_cfg(struct wil6210_priv *wil, int channel, int bi)
return rc;
}
-int wmi_start_listen(struct wil6210_priv *wil)
+int wmi_start_listen(struct wil6210_vif *vif)
{
+ struct wil6210_priv *wil = vif_to_wil(vif);
int rc;
struct {
struct wmi_cmd_hdr wmi;
@@ -1676,7 +1722,7 @@ int wmi_start_listen(struct wil6210_priv *wil)
wil_dbg_wmi(wil, "sending WMI_START_LISTEN_CMDID\n");
- rc = wmi_call(wil, WMI_START_LISTEN_CMDID, NULL, 0,
+ rc = wmi_call(wil, WMI_START_LISTEN_CMDID, vif->mid, NULL, 0,
WMI_LISTEN_STARTED_EVENTID, &reply, sizeof(reply), 300);
if (!rc && reply.evt.status != WMI_FW_STATUS_SUCCESS) {
wil_err(wil, "device failed to start listen. status %d\n",
@@ -1687,8 +1733,9 @@ int wmi_start_listen(struct wil6210_priv *wil)
return rc;
}
-int wmi_start_search(struct wil6210_priv *wil)
+int wmi_start_search(struct wil6210_vif *vif)
{
+ struct wil6210_priv *wil = vif_to_wil(vif);
int rc;
struct {
struct wmi_cmd_hdr wmi;
@@ -1697,7 +1744,7 @@ int wmi_start_search(struct wil6210_priv *wil)
wil_dbg_wmi(wil, "sending WMI_START_SEARCH_CMDID\n");
- rc = wmi_call(wil, WMI_START_SEARCH_CMDID, NULL, 0,
+ rc = wmi_call(wil, WMI_START_SEARCH_CMDID, vif->mid, NULL, 0,
WMI_SEARCH_STARTED_EVENTID, &reply, sizeof(reply), 300);
if (!rc && reply.evt.status != WMI_FW_STATUS_SUCCESS) {
wil_err(wil, "device failed to start search. status %d\n",
@@ -1708,13 +1755,14 @@ int wmi_start_search(struct wil6210_priv *wil)
return rc;
}
-int wmi_stop_discovery(struct wil6210_priv *wil)
+int wmi_stop_discovery(struct wil6210_vif *vif)
{
+ struct wil6210_priv *wil = vif_to_wil(vif);
int rc;
wil_dbg_wmi(wil, "sending WMI_DISCOVERY_STOP_CMDID\n");
- rc = wmi_call(wil, WMI_DISCOVERY_STOP_CMDID, NULL, 0,
+ rc = wmi_call(wil, WMI_DISCOVERY_STOP_CMDID, vif->mid, NULL, 0,
WMI_DISCOVERY_STOPPED_EVENTID, NULL, 0, 100);
if (rc)
@@ -1723,9 +1771,10 @@ int wmi_stop_discovery(struct wil6210_priv *wil)
return rc;
}
-int wmi_del_cipher_key(struct wil6210_priv *wil, u8 key_index,
+int wmi_del_cipher_key(struct wil6210_vif *vif, u8 key_index,
const void *mac_addr, int key_usage)
{
+ struct wil6210_priv *wil = vif_to_wil(vif);
struct wmi_delete_cipher_key_cmd cmd = {
.key_index = key_index,
};
@@ -1733,13 +1782,15 @@ int wmi_del_cipher_key(struct wil6210_priv *wil, u8 key_index,
if (mac_addr)
memcpy(cmd.mac, mac_addr, WMI_MAC_LEN);
- return wmi_send(wil, WMI_DELETE_CIPHER_KEY_CMDID, &cmd, sizeof(cmd));
+ return wmi_send(wil, WMI_DELETE_CIPHER_KEY_CMDID, vif->mid,
+ &cmd, sizeof(cmd));
}
-int wmi_add_cipher_key(struct wil6210_priv *wil, u8 key_index,
+int wmi_add_cipher_key(struct wil6210_vif *vif, u8 key_index,
const void *mac_addr, int key_len, const void *key,
int key_usage)
{
+ struct wil6210_priv *wil = vif_to_wil(vif);
struct wmi_add_cipher_key_cmd cmd = {
.key_index = key_index,
.key_usage = key_usage,
@@ -1753,11 +1804,13 @@ int wmi_add_cipher_key(struct wil6210_priv *wil, u8 key_index,
if (mac_addr)
memcpy(cmd.mac, mac_addr, WMI_MAC_LEN);
- return wmi_send(wil, WMI_ADD_CIPHER_KEY_CMDID, &cmd, sizeof(cmd));
+ return wmi_send(wil, WMI_ADD_CIPHER_KEY_CMDID, vif->mid,
+ &cmd, sizeof(cmd));
}
-int wmi_set_ie(struct wil6210_priv *wil, u8 type, u16 ie_len, const void *ie)
+int wmi_set_ie(struct wil6210_vif *vif, u8 type, u16 ie_len, const void *ie)
{
+ struct wil6210_priv *wil = vif_to_wil(vif);
static const char *const names[] = {
[WMI_FRAME_BEACON] = "BEACON",
[WMI_FRAME_PROBE_REQ] = "PROBE_REQ",
@@ -1786,7 +1839,7 @@ int wmi_set_ie(struct wil6210_priv *wil, u8 type, u16 ie_len, const void *ie)
/* BUG: FW API define ieLen as u8. Will fix FW */
cmd->ie_len = cpu_to_le16(ie_len);
memcpy(cmd->ie_info, ie, ie_len);
- rc = wmi_send(wil, WMI_SET_APPIE_CMDID, cmd, len);
+ rc = wmi_send(wil, WMI_SET_APPIE_CMDID, vif->mid, cmd, len);
kfree(cmd);
out:
if (rc) {
@@ -1808,6 +1861,7 @@ out:
*/
int wmi_rxon(struct wil6210_priv *wil, bool on)
{
+ struct wil6210_vif *vif = ndev_to_vif(wil->main_ndev);
int rc;
struct {
struct wmi_cmd_hdr wmi;
@@ -1817,13 +1871,13 @@ int wmi_rxon(struct wil6210_priv *wil, bool on)
wil_info(wil, "(%s)\n", on ? "on" : "off");
if (on) {
- rc = wmi_call(wil, WMI_START_LISTEN_CMDID, NULL, 0,
+ rc = wmi_call(wil, WMI_START_LISTEN_CMDID, vif->mid, NULL, 0,
WMI_LISTEN_STARTED_EVENTID,
&reply, sizeof(reply), 100);
if ((rc == 0) && (reply.evt.status != WMI_FW_STATUS_SUCCESS))
rc = -EINVAL;
} else {
- rc = wmi_call(wil, WMI_DISCOVERY_STOP_CMDID, NULL, 0,
+ rc = wmi_call(wil, WMI_DISCOVERY_STOP_CMDID, vif->mid, NULL, 0,
WMI_DISCOVERY_STOPPED_EVENTID, NULL, 0, 20);
}
@@ -1832,8 +1886,9 @@ int wmi_rxon(struct wil6210_priv *wil, bool on)
int wmi_rx_chain_add(struct wil6210_priv *wil, struct vring *vring)
{
- struct wireless_dev *wdev = wil->wdev;
- struct net_device *ndev = wil_to_ndev(wil);
+ struct net_device *ndev = wil->main_ndev;
+ struct wireless_dev *wdev = ndev->ieee80211_ptr;
+ struct wil6210_vif *vif = ndev_to_vif(ndev);
struct wmi_cfg_rx_chain_cmd cmd = {
.action = WMI_RX_CHAIN_ADD,
.rx_sw_ring = {
@@ -1877,7 +1932,7 @@ int wmi_rx_chain_add(struct wil6210_priv *wil, struct vring *vring)
L2_802_3_OFFLOAD_CTRL_SNAP_KEEP_MSK;
/* typical time for secure PCP is 840ms */
- rc = wmi_call(wil, WMI_CFG_RX_CHAIN_CMDID, &cmd, sizeof(cmd),
+ rc = wmi_call(wil, WMI_CFG_RX_CHAIN_CMDID, vif->mid, &cmd, sizeof(cmd),
WMI_CFG_RX_CHAIN_DONE_EVENTID, &evt, sizeof(evt), 2000);
if (rc)
return rc;
@@ -1895,6 +1950,7 @@ int wmi_rx_chain_add(struct wil6210_priv *wil, struct vring *vring)
int wmi_get_temperature(struct wil6210_priv *wil, u32 *t_bb, u32 *t_rf)
{
+ struct wil6210_vif *vif = ndev_to_vif(wil->main_ndev);
int rc;
struct wmi_temp_sense_cmd cmd = {
.measure_baseband_en = cpu_to_le32(!!t_bb),
@@ -1906,7 +1962,7 @@ int wmi_get_temperature(struct wil6210_priv *wil, u32 *t_bb, u32 *t_rf)
struct wmi_temp_sense_done_event evt;
} __packed reply;
- rc = wmi_call(wil, WMI_TEMP_SENSE_CMDID, &cmd, sizeof(cmd),
+ rc = wmi_call(wil, WMI_TEMP_SENSE_CMDID, vif->mid, &cmd, sizeof(cmd),
WMI_TEMP_SENSE_DONE_EVENTID, &reply, sizeof(reply), 100);
if (rc)
return rc;
@@ -1919,9 +1975,10 @@ int wmi_get_temperature(struct wil6210_priv *wil, u32 *t_bb, u32 *t_rf)
return 0;
}
-int wmi_disconnect_sta(struct wil6210_priv *wil, const u8 *mac,
+int wmi_disconnect_sta(struct wil6210_vif *vif, const u8 *mac,
u16 reason, bool full_disconnect, bool del_sta)
{
+ struct wil6210_priv *wil = vif_to_wil(vif);
int rc;
u16 reason_code;
struct wmi_disconnect_sta_cmd disc_sta_cmd = {
@@ -1937,16 +1994,17 @@ int wmi_disconnect_sta(struct wil6210_priv *wil, const u8 *mac,
wil_dbg_wmi(wil, "disconnect_sta: (%pM, reason %d)\n", mac, reason);
- wil->locally_generated_disc = true;
+ vif->locally_generated_disc = true;
if (del_sta) {
ether_addr_copy(del_sta_cmd.dst_mac, mac);
- rc = wmi_call(wil, WMI_DEL_STA_CMDID, &del_sta_cmd,
+ rc = wmi_call(wil, WMI_DEL_STA_CMDID, vif->mid, &del_sta_cmd,
sizeof(del_sta_cmd), WMI_DISCONNECT_EVENTID,
&reply, sizeof(reply), 1000);
} else {
ether_addr_copy(disc_sta_cmd.dst_mac, mac);
- rc = wmi_call(wil, WMI_DISCONNECT_STA_CMDID, &disc_sta_cmd,
- sizeof(disc_sta_cmd), WMI_DISCONNECT_EVENTID,
+ rc = wmi_call(wil, WMI_DISCONNECT_STA_CMDID, vif->mid,
+ &disc_sta_cmd, sizeof(disc_sta_cmd),
+ WMI_DISCONNECT_EVENTID,
&reply, sizeof(reply), 1000);
}
/* failure to disconnect in reasonable time treated as FW error */
@@ -1967,12 +2025,13 @@ int wmi_disconnect_sta(struct wil6210_priv *wil, const u8 *mac,
reply.evt.disconnect_reason);
wil->sinfo_gen++;
- wil6210_disconnect(wil, reply.evt.bssid, reason_code, true);
+ wil6210_disconnect(vif, reply.evt.bssid, reason_code, true);
}
return 0;
}
-int wmi_addba(struct wil6210_priv *wil, u8 ringid, u8 size, u16 timeout)
+int wmi_addba(struct wil6210_priv *wil, u8 mid,
+ u8 ringid, u8 size, u16 timeout)
{
struct wmi_vring_ba_en_cmd cmd = {
.ringid = ringid,
@@ -1984,10 +2043,10 @@ int wmi_addba(struct wil6210_priv *wil, u8 ringid, u8 size, u16 timeout)
wil_dbg_wmi(wil, "addba: (ring %d size %d timeout %d)\n", ringid, size,
timeout);
- return wmi_send(wil, WMI_VRING_BA_EN_CMDID, &cmd, sizeof(cmd));
+ return wmi_send(wil, WMI_VRING_BA_EN_CMDID, mid, &cmd, sizeof(cmd));
}
-int wmi_delba_tx(struct wil6210_priv *wil, u8 ringid, u16 reason)
+int wmi_delba_tx(struct wil6210_priv *wil, u8 mid, u8 ringid, u16 reason)
{
struct wmi_vring_ba_dis_cmd cmd = {
.ringid = ringid,
@@ -1996,10 +2055,10 @@ int wmi_delba_tx(struct wil6210_priv *wil, u8 ringid, u16 reason)
wil_dbg_wmi(wil, "delba_tx: (ring %d reason %d)\n", ringid, reason);
- return wmi_send(wil, WMI_VRING_BA_DIS_CMDID, &cmd, sizeof(cmd));
+ return wmi_send(wil, WMI_VRING_BA_DIS_CMDID, mid, &cmd, sizeof(cmd));
}
-int wmi_delba_rx(struct wil6210_priv *wil, u8 cidxtid, u16 reason)
+int wmi_delba_rx(struct wil6210_priv *wil, u8 mid, u8 cidxtid, u16 reason)
{
struct wmi_rcp_delba_cmd cmd = {
.cidxtid = cidxtid,
@@ -2009,10 +2068,11 @@ int wmi_delba_rx(struct wil6210_priv *wil, u8 cidxtid, u16 reason)
wil_dbg_wmi(wil, "delba_rx: (CID %d TID %d reason %d)\n", cidxtid & 0xf,
(cidxtid >> 4) & 0xf, reason);
- return wmi_send(wil, WMI_RCP_DELBA_CMDID, &cmd, sizeof(cmd));
+ return wmi_send(wil, WMI_RCP_DELBA_CMDID, mid, &cmd, sizeof(cmd));
}
-int wmi_addba_rx_resp(struct wil6210_priv *wil, u8 cid, u8 tid, u8 token,
+int wmi_addba_rx_resp(struct wil6210_priv *wil,
+ u8 mid, u8 cid, u8 tid, u8 token,
u16 status, bool amsdu, u16 agg_wsize, u16 timeout)
{
int rc;
@@ -2035,10 +2095,11 @@ int wmi_addba_rx_resp(struct wil6210_priv *wil, u8 cid, u8 tid, u8 token,
} __packed reply;
wil_dbg_wmi(wil,
- "ADDBA response for CID %d TID %d size %d timeout %d status %d AMSDU%s\n",
- cid, tid, agg_wsize, timeout, status, amsdu ? "+" : "-");
+ "ADDBA response for MID %d CID %d TID %d size %d timeout %d status %d AMSDU%s\n",
+ mid, cid, tid, agg_wsize,
+ timeout, status, amsdu ? "+" : "-");
- rc = wmi_call(wil, WMI_RCP_ADDBA_RESP_CMDID, &cmd, sizeof(cmd),
+ rc = wmi_call(wil, WMI_RCP_ADDBA_RESP_CMDID, mid, &cmd, sizeof(cmd),
WMI_RCP_ADDBA_RESP_SENT_EVENTID, &reply, sizeof(reply),
100);
if (rc)
@@ -2056,6 +2117,7 @@ int wmi_addba_rx_resp(struct wil6210_priv *wil, u8 cid, u8 tid, u8 token,
int wmi_ps_dev_profile_cfg(struct wil6210_priv *wil,
enum wmi_ps_profile_type ps_profile)
{
+ struct wil6210_vif *vif = ndev_to_vif(wil->main_ndev);
int rc;
struct wmi_ps_dev_profile_cfg_cmd cmd = {
.ps_profile = ps_profile,
@@ -2070,7 +2132,8 @@ int wmi_ps_dev_profile_cfg(struct wil6210_priv *wil,
reply.evt.status = cpu_to_le32(WMI_PS_CFG_CMD_STATUS_ERROR);
- rc = wmi_call(wil, WMI_PS_DEV_PROFILE_CFG_CMDID, &cmd, sizeof(cmd),
+ rc = wmi_call(wil, WMI_PS_DEV_PROFILE_CFG_CMDID, vif->mid,
+ &cmd, sizeof(cmd),
WMI_PS_DEV_PROFILE_CFG_EVENTID, &reply, sizeof(reply),
100);
if (rc)
@@ -2089,6 +2152,7 @@ int wmi_ps_dev_profile_cfg(struct wil6210_priv *wil,
int wmi_set_mgmt_retry(struct wil6210_priv *wil, u8 retry_short)
{
+ struct wil6210_vif *vif = ndev_to_vif(wil->main_ndev);
int rc;
struct wmi_set_mgmt_retry_limit_cmd cmd = {
.mgmt_retry_limit = retry_short,
@@ -2105,7 +2169,8 @@ int wmi_set_mgmt_retry(struct wil6210_priv *wil, u8 retry_short)
reply.evt.status = WMI_FW_STATUS_FAILURE;
- rc = wmi_call(wil, WMI_SET_MGMT_RETRY_LIMIT_CMDID, &cmd, sizeof(cmd),
+ rc = wmi_call(wil, WMI_SET_MGMT_RETRY_LIMIT_CMDID, vif->mid,
+ &cmd, sizeof(cmd),
WMI_SET_MGMT_RETRY_LIMIT_EVENTID, &reply, sizeof(reply),
100);
if (rc)
@@ -2122,6 +2187,7 @@ int wmi_set_mgmt_retry(struct wil6210_priv *wil, u8 retry_short)
int wmi_get_mgmt_retry(struct wil6210_priv *wil, u8 *retry_short)
{
+ struct wil6210_vif *vif = ndev_to_vif(wil->main_ndev);
int rc;
struct {
struct wmi_cmd_hdr wmi;
@@ -2134,7 +2200,7 @@ int wmi_get_mgmt_retry(struct wil6210_priv *wil, u8 *retry_short)
return -ENOTSUPP;
reply.evt.mgmt_retry_limit = 0;
- rc = wmi_call(wil, WMI_GET_MGMT_RETRY_LIMIT_CMDID, NULL, 0,
+ rc = wmi_call(wil, WMI_GET_MGMT_RETRY_LIMIT_CMDID, vif->mid, NULL, 0,
WMI_GET_MGMT_RETRY_LIMIT_EVENTID, &reply, sizeof(reply),
100);
if (rc)
@@ -2146,21 +2212,23 @@ int wmi_get_mgmt_retry(struct wil6210_priv *wil, u8 *retry_short)
return 0;
}
-int wmi_abort_scan(struct wil6210_priv *wil)
+int wmi_abort_scan(struct wil6210_vif *vif)
{
+ struct wil6210_priv *wil = vif_to_wil(vif);
int rc;
wil_dbg_wmi(wil, "sending WMI_ABORT_SCAN_CMDID\n");
- rc = wmi_send(wil, WMI_ABORT_SCAN_CMDID, NULL, 0);
+ rc = wmi_send(wil, WMI_ABORT_SCAN_CMDID, vif->mid, NULL, 0);
if (rc)
wil_err(wil, "Failed to abort scan (%d)\n", rc);
return rc;
}
-int wmi_new_sta(struct wil6210_priv *wil, const u8 *mac, u8 aid)
+int wmi_new_sta(struct wil6210_vif *vif, const u8 *mac, u8 aid)
{
+ struct wil6210_priv *wil = vif_to_wil(vif);
int rc;
struct wmi_new_sta_cmd cmd = {
.aid = aid,
@@ -2170,7 +2238,7 @@ int wmi_new_sta(struct wil6210_priv *wil, const u8 *mac, u8 aid)
ether_addr_copy(cmd.dst_mac, mac);
- rc = wmi_send(wil, WMI_NEW_STA_CMDID, &cmd, sizeof(cmd));
+ rc = wmi_send(wil, WMI_NEW_STA_CMDID, vif->mid, &cmd, sizeof(cmd));
if (rc)
wil_err(wil, "Failed to send new sta (%d)\n", rc);
@@ -2206,6 +2274,7 @@ static const char *suspend_status2name(u8 status)
int wmi_suspend(struct wil6210_priv *wil)
{
+ struct wil6210_vif *vif = ndev_to_vif(wil->main_ndev);
int rc;
struct wmi_traffic_suspend_cmd cmd = {
.wakeup_trigger = wil->wakeup_trigger,
@@ -2221,7 +2290,8 @@ int wmi_suspend(struct wil6210_priv *wil)
reply.evt.status = WMI_TRAFFIC_SUSPEND_REJECTED_LINK_NOT_IDLE;
- rc = wmi_call(wil, WMI_TRAFFIC_SUSPEND_CMDID, &cmd, sizeof(cmd),
+ rc = wmi_call(wil, WMI_TRAFFIC_SUSPEND_CMDID, vif->mid,
+ &cmd, sizeof(cmd),
WMI_TRAFFIC_SUSPEND_EVENTID, &reply, sizeof(reply),
suspend_to);
if (rc) {
@@ -2289,6 +2359,7 @@ static void resume_triggers2string(u32 triggers, char *string, int str_size)
int wmi_resume(struct wil6210_priv *wil)
{
+ struct wil6210_vif *vif = ndev_to_vif(wil->main_ndev);
int rc;
char string[100];
struct {
@@ -2299,7 +2370,7 @@ int wmi_resume(struct wil6210_priv *wil)
reply.evt.status = WMI_TRAFFIC_RESUME_FAILED;
reply.evt.resume_triggers = WMI_RESUME_TRIGGER_UNKNOWN;
- rc = wmi_call(wil, WMI_TRAFFIC_RESUME_CMDID, NULL, 0,
+ rc = wmi_call(wil, WMI_TRAFFIC_RESUME_CMDID, vif->mid, NULL, 0,
WMI_TRAFFIC_RESUME_EVENTID, &reply, sizeof(reply),
WIL_WAIT_FOR_SUSPEND_RESUME_COMP);
if (rc)
@@ -2313,14 +2384,100 @@ int wmi_resume(struct wil6210_priv *wil)
return reply.evt.status;
}
-static bool wmi_evt_call_handler(struct wil6210_priv *wil, int id,
+int wmi_port_allocate(struct wil6210_priv *wil, u8 mid,
+ const u8 *mac, enum nl80211_iftype iftype)
+{
+ int rc;
+ struct wmi_port_allocate_cmd cmd = {
+ .mid = mid,
+ };
+ struct {
+ struct wmi_cmd_hdr wmi;
+ struct wmi_port_allocated_event evt;
+ } __packed reply;
+
+ wil_dbg_misc(wil, "port allocate, mid %d iftype %d, mac %pM\n",
+ mid, iftype, mac);
+
+ ether_addr_copy(cmd.mac, mac);
+ switch (iftype) {
+ case NL80211_IFTYPE_STATION:
+ cmd.port_role = WMI_PORT_STA;
+ break;
+ case NL80211_IFTYPE_AP:
+ cmd.port_role = WMI_PORT_AP;
+ break;
+ case NL80211_IFTYPE_P2P_CLIENT:
+ cmd.port_role = WMI_PORT_P2P_CLIENT;
+ break;
+ case NL80211_IFTYPE_P2P_GO:
+ cmd.port_role = WMI_PORT_P2P_GO;
+ break;
+ /* what about monitor??? */
+ default:
+ wil_err(wil, "unsupported iftype: %d\n", iftype);
+ return -EINVAL;
+ }
+
+ reply.evt.status = WMI_FW_STATUS_FAILURE;
+
+ rc = wmi_call(wil, WMI_PORT_ALLOCATE_CMDID, mid,
+ &cmd, sizeof(cmd),
+ WMI_PORT_ALLOCATED_EVENTID, &reply,
+ sizeof(reply), 300);
+ if (rc) {
+ wil_err(wil, "failed to allocate port, status %d\n", rc);
+ return rc;
+ }
+ if (reply.evt.status != WMI_FW_STATUS_SUCCESS) {
+ wil_err(wil, "WMI_PORT_ALLOCATE returned status %d\n",
+ reply.evt.status);
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+int wmi_port_delete(struct wil6210_priv *wil, u8 mid)
+{
+ int rc;
+ struct wmi_port_delete_cmd cmd = {
+ .mid = mid,
+ };
+ struct {
+ struct wmi_cmd_hdr wmi;
+ struct wmi_port_deleted_event evt;
+ } __packed reply;
+
+ wil_dbg_misc(wil, "port delete, mid %d\n", mid);
+
+ reply.evt.status = WMI_FW_STATUS_FAILURE;
+
+ rc = wmi_call(wil, WMI_PORT_DELETE_CMDID, mid,
+ &cmd, sizeof(cmd),
+ WMI_PORT_DELETED_EVENTID, &reply,
+ sizeof(reply), 2000);
+ if (rc) {
+ wil_err(wil, "failed to delete port, status %d\n", rc);
+ return rc;
+ }
+ if (reply.evt.status != WMI_FW_STATUS_SUCCESS) {
+ wil_err(wil, "WMI_PORT_DELETE returned status %d\n",
+ reply.evt.status);
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static bool wmi_evt_call_handler(struct wil6210_vif *vif, int id,
void *d, int len)
{
uint i;
for (i = 0; i < ARRAY_SIZE(wmi_evt_handlers); i++) {
if (wmi_evt_handlers[i].eventid == id) {
- wmi_evt_handlers[i].handler(wil, id, d, len);
+ wmi_evt_handlers[i].handler(vif, id, d, len);
return true;
}
}
@@ -2332,19 +2489,39 @@ static void wmi_event_handle(struct wil6210_priv *wil,
struct wil6210_mbox_hdr *hdr)
{
u16 len = le16_to_cpu(hdr->len);
+ struct wil6210_vif *vif;
if ((hdr->type == WIL_MBOX_HDR_TYPE_WMI) &&
(len >= sizeof(struct wmi_cmd_hdr))) {
struct wmi_cmd_hdr *wmi = (void *)(&hdr[1]);
void *evt_data = (void *)(&wmi[1]);
u16 id = le16_to_cpu(wmi->command_id);
+ u8 mid = wmi->mid;
+
+ wil_dbg_wmi(wil, "Handle %s (0x%04x) (reply_id 0x%04x,%d)\n",
+ eventid2name(id), id, wil->reply_id,
+ wil->reply_mid);
+
+ if (mid == MID_BROADCAST)
+ mid = 0;
+ if (mid >= wil->max_vifs) {
+ wil_dbg_wmi(wil, "invalid mid %d, event skipped\n",
+ mid);
+ return;
+ }
+ vif = wil->vifs[mid];
+ if (!vif) {
+ wil_dbg_wmi(wil, "event for empty VIF(%d), skipped\n",
+ mid);
+ return;
+ }
- wil_dbg_wmi(wil, "Handle %s (0x%04x) (reply_id 0x%04x)\n",
- eventid2name(id), id, wil->reply_id);
/* check if someone waits for this event */
- if (wil->reply_id && wil->reply_id == id) {
+ if (wil->reply_id && wil->reply_id == id &&
+ wil->reply_mid == mid) {
WARN_ON(wil->reply_buf);
- wmi_evt_call_handler(wil, id, evt_data,
+
+ wmi_evt_call_handler(vif, id, evt_data,
len - sizeof(*wmi));
wil_dbg_wmi(wil, "event_handle: Complete WMI 0x%04x\n",
id);
@@ -2353,7 +2530,7 @@ static void wmi_event_handle(struct wil6210_priv *wil,
}
/* unsolicited event */
/* search for handler */
- if (!wmi_evt_call_handler(wil, id, evt_data,
+ if (!wmi_evt_call_handler(vif, id, evt_data,
len - sizeof(*wmi))) {
wil_info(wil, "Unhandled event 0x%04x\n", id);
}
@@ -2523,6 +2700,7 @@ wmi_sched_scan_set_plans(struct wil6210_priv *wil,
int wmi_start_sched_scan(struct wil6210_priv *wil,
struct cfg80211_sched_scan_request *request)
{
+ struct wil6210_vif *vif = ndev_to_vif(wil->main_ndev);
int rc;
struct wmi_start_sched_scan_cmd cmd = {
.min_rssi_threshold = S8_MIN,
@@ -2549,7 +2727,8 @@ int wmi_start_sched_scan(struct wil6210_priv *wil,
reply.evt.result = WMI_PNO_REJECT;
- rc = wmi_call(wil, WMI_START_SCHED_SCAN_CMDID, &cmd, sizeof(cmd),
+ rc = wmi_call(wil, WMI_START_SCHED_SCAN_CMDID, vif->mid,
+ &cmd, sizeof(cmd),
WMI_START_SCHED_SCAN_EVENTID, &reply, sizeof(reply),
WIL_WMI_CALL_GENERAL_TO_MS);
if (rc)
@@ -2566,6 +2745,7 @@ int wmi_start_sched_scan(struct wil6210_priv *wil,
int wmi_stop_sched_scan(struct wil6210_priv *wil)
{
+ struct wil6210_vif *vif = ndev_to_vif(wil->main_ndev);
int rc;
struct {
struct wmi_cmd_hdr wmi;
@@ -2577,7 +2757,7 @@ int wmi_stop_sched_scan(struct wil6210_priv *wil)
reply.evt.result = WMI_PNO_REJECT;
- rc = wmi_call(wil, WMI_STOP_SCHED_SCAN_CMDID, NULL, 0,
+ rc = wmi_call(wil, WMI_STOP_SCHED_SCAN_CMDID, vif->mid, NULL, 0,
WMI_STOP_SCHED_SCAN_EVENTID, &reply, sizeof(reply),
WIL_WMI_CALL_GENERAL_TO_MS);
if (rc)
diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/bcdc.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/bcdc.c
index 2d3a5dd07a3f..1068a2a4494c 100644
--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/bcdc.c
+++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/bcdc.c
@@ -445,6 +445,11 @@ brcmf_proto_bcdc_init_done(struct brcmf_pub *drvr)
return 0;
}
+static void brcmf_proto_bcdc_debugfs_create(struct brcmf_pub *drvr)
+{
+ brcmf_fws_debugfs_create(drvr);
+}
+
int brcmf_proto_bcdc_attach(struct brcmf_pub *drvr)
{
struct brcmf_bcdc *bcdc;
@@ -472,6 +477,7 @@ int brcmf_proto_bcdc_attach(struct brcmf_pub *drvr)
drvr->proto->del_if = brcmf_proto_bcdc_del_if;
drvr->proto->reset_if = brcmf_proto_bcdc_reset_if;
drvr->proto->init_done = brcmf_proto_bcdc_init_done;
+ drvr->proto->debugfs_create = brcmf_proto_bcdc_debugfs_create;
drvr->proto->pd = bcdc;
drvr->hdrlen += BCDC_HEADER_LEN + BRCMF_PROT_FW_SIGNAL_MAX_TXBYTES;
diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/btcoex.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/btcoex.c
index 03aae6bc1838..372363a6e752 100644
--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/btcoex.c
+++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/btcoex.c
@@ -462,7 +462,7 @@ static void brcmf_btcoex_dhcp_end(struct brcmf_btcoex_info *btci)
int brcmf_btcoex_set_mode(struct brcmf_cfg80211_vif *vif,
enum brcmf_btcoex_mode mode, u16 duration)
{
- struct brcmf_cfg80211_info *cfg = wiphy_priv(vif->wdev.wiphy);
+ struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(vif->wdev.wiphy);
struct brcmf_btcoex_info *btci = cfg->btcoex;
struct brcmf_if *ifp = brcmf_get_ifp(cfg->pub, 0);
diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/bus.h b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/bus.h
index 0b90a63bdeb1..27e693e93f21 100644
--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/bus.h
+++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/bus.h
@@ -88,7 +88,7 @@ struct brcmf_bus_ops {
void (*wowl_config)(struct device *dev, bool enabled);
size_t (*get_ramsize)(struct device *dev);
int (*get_memdump)(struct device *dev, void *data, size_t len);
- int (*get_fwname)(struct device *dev, uint chip, uint chiprev,
+ int (*get_fwname)(struct device *dev, const char *ext,
unsigned char *fw_name);
};
@@ -140,6 +140,7 @@ struct brcmf_bus_stats {
* @always_use_fws_queue: bus wants use queue also when fwsignal is inactive.
* @wowl_supported: is wowl supported by bus driver.
* @chiprev: revision of the dongle chip.
+ * @msgbuf: msgbuf protocol parameters provided by bus layer.
*/
struct brcmf_bus {
union {
@@ -228,10 +229,10 @@ int brcmf_bus_get_memdump(struct brcmf_bus *bus, void *data, size_t len)
}
static inline
-int brcmf_bus_get_fwname(struct brcmf_bus *bus, uint chip, uint chiprev,
+int brcmf_bus_get_fwname(struct brcmf_bus *bus, const char *ext,
unsigned char *fw_name)
{
- return bus->ops->get_fwname(bus->dev, chip, chiprev, fw_name);
+ return bus->ops->get_fwname(bus->dev, ext, fw_name);
}
/*
diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c
index 74a83020c073..89b86251910e 100644
--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c
+++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c
@@ -753,7 +753,7 @@ s32 brcmf_notify_escan_complete(struct brcmf_cfg80211_info *cfg,
static int brcmf_cfg80211_del_ap_iface(struct wiphy *wiphy,
struct wireless_dev *wdev)
{
- struct brcmf_cfg80211_info *cfg = wiphy_priv(wiphy);
+ struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy);
struct net_device *ndev = wdev->netdev;
struct brcmf_if *ifp = netdev_priv(ndev);
int ret;
@@ -786,7 +786,7 @@ err_unarm:
static
int brcmf_cfg80211_del_iface(struct wiphy *wiphy, struct wireless_dev *wdev)
{
- struct brcmf_cfg80211_info *cfg = wiphy_priv(wiphy);
+ struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy);
struct net_device *ndev = wdev->netdev;
if (ndev && ndev == cfg_to_ndev(cfg))
@@ -831,7 +831,7 @@ brcmf_cfg80211_change_iface(struct wiphy *wiphy, struct net_device *ndev,
enum nl80211_iftype type,
struct vif_params *params)
{
- struct brcmf_cfg80211_info *cfg = wiphy_priv(wiphy);
+ struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy);
struct brcmf_if *ifp = netdev_priv(ndev);
struct brcmf_cfg80211_vif *vif = ifp->vif;
s32 infra = 0;
@@ -2127,17 +2127,15 @@ static s32
brcmf_cfg80211_get_tx_power(struct wiphy *wiphy, struct wireless_dev *wdev,
s32 *dbm)
{
- struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy);
- struct net_device *ndev = cfg_to_ndev(cfg);
- struct brcmf_if *ifp = netdev_priv(ndev);
+ struct brcmf_cfg80211_vif *vif = wdev_to_vif(wdev);
s32 qdbm = 0;
s32 err;
brcmf_dbg(TRACE, "Enter\n");
- if (!check_vif_up(ifp->vif))
+ if (!check_vif_up(vif))
return -EIO;
- err = brcmf_fil_iovar_int_get(ifp, "qtxpower", &qdbm);
+ err = brcmf_fil_iovar_int_get(vif->ifp, "qtxpower", &qdbm);
if (err) {
brcmf_err("error (%d)\n", err);
goto done;
@@ -3358,7 +3356,7 @@ brcmf_cfg80211_sched_scan_start(struct wiphy *wiphy,
struct cfg80211_sched_scan_request *req)
{
struct brcmf_if *ifp = netdev_priv(ndev);
- struct brcmf_cfg80211_info *cfg = wiphy_priv(wiphy);
+ struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy);
brcmf_dbg(SCAN, "Enter: n_match_sets=%d n_ssids=%d\n",
req->n_match_sets, req->n_ssids);
@@ -5190,6 +5188,12 @@ static struct cfg80211_ops brcmf_cfg80211_ops = {
.del_pmk = brcmf_cfg80211_del_pmk,
};
+struct cfg80211_ops *brcmf_cfg80211_get_ops(void)
+{
+ return kmemdup(&brcmf_cfg80211_ops, sizeof(brcmf_cfg80211_ops),
+ GFP_KERNEL);
+}
+
struct brcmf_cfg80211_vif *brcmf_alloc_vif(struct brcmf_cfg80211_info *cfg,
enum nl80211_iftype type)
{
@@ -5897,7 +5901,7 @@ static void brcmf_update_bw40_channel_flag(struct ieee80211_channel *channel,
static int brcmf_construct_chaninfo(struct brcmf_cfg80211_info *cfg,
u32 bw_cap[])
{
- struct brcmf_if *ifp = netdev_priv(cfg_to_ndev(cfg));
+ struct brcmf_if *ifp = brcmf_get_ifp(cfg->pub, 0);
struct ieee80211_supported_band *band;
struct ieee80211_channel *channel;
struct wiphy *wiphy;
@@ -6012,7 +6016,7 @@ fail_pbuf:
static int brcmf_enable_bw40_2g(struct brcmf_cfg80211_info *cfg)
{
- struct brcmf_if *ifp = netdev_priv(cfg_to_ndev(cfg));
+ struct brcmf_if *ifp = brcmf_get_ifp(cfg->pub, 0);
struct ieee80211_supported_band *band;
struct brcmf_fil_bwcap_le band_bwcap;
struct brcmf_chanspec_list *list;
@@ -6197,10 +6201,10 @@ static void brcmf_update_vht_cap(struct ieee80211_supported_band *band,
}
}
-static int brcmf_setup_wiphybands(struct wiphy *wiphy)
+static int brcmf_setup_wiphybands(struct brcmf_cfg80211_info *cfg)
{
- struct brcmf_cfg80211_info *cfg = wiphy_priv(wiphy);
- struct brcmf_if *ifp = netdev_priv(cfg_to_ndev(cfg));
+ struct brcmf_if *ifp = brcmf_get_ifp(cfg->pub, 0);
+ struct wiphy *wiphy;
u32 nmode = 0;
u32 vhtmode = 0;
u32 bw_cap[2] = { WLC_BW_20MHZ_BIT, WLC_BW_20MHZ_BIT };
@@ -6794,8 +6798,8 @@ static s32 brcmf_translate_country_code(struct brcmf_pub *drvr, char alpha2[2],
static void brcmf_cfg80211_reg_notifier(struct wiphy *wiphy,
struct regulatory_request *req)
{
- struct brcmf_cfg80211_info *cfg = wiphy_priv(wiphy);
- struct brcmf_if *ifp = netdev_priv(cfg_to_ndev(cfg));
+ struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy);
+ struct brcmf_if *ifp = brcmf_get_ifp(cfg->pub, 0);
struct brcmf_fil_country_le ccreq;
s32 err;
int i;
@@ -6805,7 +6809,7 @@ static void brcmf_cfg80211_reg_notifier(struct wiphy *wiphy,
return;
/* ignore non-ISO3166 country codes */
- for (i = 0; i < sizeof(req->alpha2); i++)
+ for (i = 0; i < 2; i++)
if (req->alpha2[i] < 'A' || req->alpha2[i] > 'Z') {
brcmf_err("not an ISO3166 code (0x%02x 0x%02x)\n",
req->alpha2[0], req->alpha2[1]);
@@ -6830,7 +6834,7 @@ static void brcmf_cfg80211_reg_notifier(struct wiphy *wiphy,
brcmf_err("Firmware rejected country setting\n");
return;
}
- brcmf_setup_wiphybands(wiphy);
+ brcmf_setup_wiphybands(cfg);
}
static void brcmf_free_wiphy(struct wiphy *wiphy)
@@ -6857,17 +6861,15 @@ static void brcmf_free_wiphy(struct wiphy *wiphy)
if (wiphy->wowlan != &brcmf_wowlan_support)
kfree(wiphy->wowlan);
#endif
- wiphy_free(wiphy);
}
struct brcmf_cfg80211_info *brcmf_cfg80211_attach(struct brcmf_pub *drvr,
- struct device *busdev,
+ struct cfg80211_ops *ops,
bool p2pdev_forced)
{
+ struct wiphy *wiphy = drvr->wiphy;
struct net_device *ndev = brcmf_get_ifp(drvr, 0)->ndev;
struct brcmf_cfg80211_info *cfg;
- struct wiphy *wiphy;
- struct cfg80211_ops *ops;
struct brcmf_cfg80211_vif *vif;
struct brcmf_if *ifp;
s32 err = 0;
@@ -6879,26 +6881,13 @@ struct brcmf_cfg80211_info *brcmf_cfg80211_attach(struct brcmf_pub *drvr,
return NULL;
}
- ops = kmemdup(&brcmf_cfg80211_ops, sizeof(*ops), GFP_KERNEL);
- if (!ops)
- return NULL;
-
- ifp = netdev_priv(ndev);
-#ifdef CONFIG_PM
- if (brcmf_feat_is_enabled(ifp, BRCMF_FEAT_WOWL_GTK))
- ops->set_rekey_data = brcmf_cfg80211_set_rekey_data;
-#endif
- wiphy = wiphy_new(ops, sizeof(struct brcmf_cfg80211_info));
- if (!wiphy) {
+ cfg = kzalloc(sizeof(*cfg), GFP_KERNEL);
+ if (!cfg) {
brcmf_err("Could not allocate wiphy device\n");
- goto ops_out;
+ return NULL;
}
- memcpy(wiphy->perm_addr, drvr->mac, ETH_ALEN);
- set_wiphy_dev(wiphy, busdev);
- cfg = wiphy_priv(wiphy);
cfg->wiphy = wiphy;
- cfg->ops = ops;
cfg->pub = drvr;
init_vif_event(&cfg->vif_event);
INIT_LIST_HEAD(&cfg->vif_list);
@@ -6907,6 +6896,7 @@ struct brcmf_cfg80211_info *brcmf_cfg80211_attach(struct brcmf_pub *drvr,
if (IS_ERR(vif))
goto wiphy_out;
+ ifp = netdev_priv(ndev);
vif->ifp = ifp;
vif->wdev.netdev = ndev;
ndev->ieee80211_ptr = &vif->wdev;
@@ -6933,6 +6923,11 @@ struct brcmf_cfg80211_info *brcmf_cfg80211_attach(struct brcmf_pub *drvr,
if (err < 0)
goto priv_out;
+ /* regulatory notifer below needs access to cfg so
+ * assign it now.
+ */
+ drvr->config = cfg;
+
brcmf_dbg(INFO, "Registering custom regulatory\n");
wiphy->reg_notifier = brcmf_cfg80211_reg_notifier;
wiphy->regulatory_flags |= REGULATORY_CUSTOM_REG;
@@ -6946,13 +6941,17 @@ struct brcmf_cfg80211_info *brcmf_cfg80211_attach(struct brcmf_pub *drvr,
cap = &wiphy->bands[NL80211_BAND_2GHZ]->ht_cap.cap;
*cap |= IEEE80211_HT_CAP_SUP_WIDTH_20_40;
}
+#ifdef CONFIG_PM
+ if (brcmf_feat_is_enabled(ifp, BRCMF_FEAT_WOWL_GTK))
+ ops->set_rekey_data = brcmf_cfg80211_set_rekey_data;
+#endif
err = wiphy_register(wiphy);
if (err < 0) {
brcmf_err("Could not register wiphy device (%d)\n", err);
goto priv_out;
}
- err = brcmf_setup_wiphybands(wiphy);
+ err = brcmf_setup_wiphybands(cfg);
if (err) {
brcmf_err("Setting wiphy bands failed (%d)\n", err);
goto wiphy_unreg_out;
@@ -6969,12 +6968,7 @@ struct brcmf_cfg80211_info *brcmf_cfg80211_attach(struct brcmf_pub *drvr,
else
*cap &= ~IEEE80211_HT_CAP_SUP_WIDTH_20_40;
}
- /* p2p might require that "if-events" get processed by fweh. So
- * activate the already registered event handlers now and activate
- * the rest when initialization has completed. drvr->config needs to
- * be assigned before activating events.
- */
- drvr->config = cfg;
+
err = brcmf_fweh_activate_events(ifp);
if (err) {
brcmf_err("FWEH activation failed (%d)\n", err);
@@ -7042,8 +7036,7 @@ priv_out:
ifp->vif = NULL;
wiphy_out:
brcmf_free_wiphy(wiphy);
-ops_out:
- kfree(ops);
+ kfree(cfg);
return NULL;
}
@@ -7058,4 +7051,5 @@ void brcmf_cfg80211_detach(struct brcmf_cfg80211_info *cfg)
kfree(cfg->ops);
wl_deinit_priv(cfg);
brcmf_free_wiphy(cfg->wiphy);
+ kfree(cfg);
}
diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.h b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.h
index b5b5f0f10b63..a4aec0004e4f 100644
--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.h
+++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.h
@@ -355,20 +355,24 @@ static inline struct wiphy *cfg_to_wiphy(struct brcmf_cfg80211_info *cfg)
static inline struct brcmf_cfg80211_info *wiphy_to_cfg(struct wiphy *w)
{
- return (struct brcmf_cfg80211_info *)(wiphy_priv(w));
+ struct brcmf_pub *drvr = wiphy_priv(w);
+ return drvr->config;
}
static inline struct brcmf_cfg80211_info *wdev_to_cfg(struct wireless_dev *wd)
{
- return (struct brcmf_cfg80211_info *)(wdev_priv(wd));
+ return wiphy_to_cfg(wd->wiphy);
+}
+
+static inline struct brcmf_cfg80211_vif *wdev_to_vif(struct wireless_dev *wdev)
+{
+ return container_of(wdev, struct brcmf_cfg80211_vif, wdev);
}
static inline
struct net_device *cfg_to_ndev(struct brcmf_cfg80211_info *cfg)
{
- struct brcmf_cfg80211_vif *vif;
- vif = list_first_entry(&cfg->vif_list, struct brcmf_cfg80211_vif, list);
- return vif->wdev.netdev;
+ return brcmf_get_ifp(cfg->pub, 0)->ndev;
}
static inline struct brcmf_cfg80211_info *ndev_to_cfg(struct net_device *ndev)
@@ -395,11 +399,12 @@ brcmf_cfg80211_connect_info *cfg_to_conn(struct brcmf_cfg80211_info *cfg)
}
struct brcmf_cfg80211_info *brcmf_cfg80211_attach(struct brcmf_pub *drvr,
- struct device *busdev,
+ struct cfg80211_ops *ops,
bool p2pdev_forced);
void brcmf_cfg80211_detach(struct brcmf_cfg80211_info *cfg);
s32 brcmf_cfg80211_up(struct net_device *ndev);
s32 brcmf_cfg80211_down(struct net_device *ndev);
+struct cfg80211_ops *brcmf_cfg80211_get_ops(void);
enum nl80211_iftype brcmf_cfg80211_get_iftype(struct brcmf_if *ifp);
struct brcmf_cfg80211_vif *brcmf_alloc_vif(struct brcmf_cfg80211_info *cfg,
diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/chip.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/chip.c
index f7b30ce2300d..3b829fed8631 100644
--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/chip.c
+++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/chip.c
@@ -464,12 +464,12 @@ static void brcmf_chip_ai_resetcore(struct brcmf_core_priv *core, u32 prereset,
ci->ops->read32(ci->ctx, core->wrapbase + BCMA_IOCTL);
}
-static char *brcmf_chip_name(uint chipid, char *buf, uint len)
+char *brcmf_chip_name(u32 id, u32 rev, char *buf, uint len)
{
const char *fmt;
- fmt = ((chipid > 0xa000) || (chipid < 0x4000)) ? "%d" : "%x";
- snprintf(buf, len, fmt, chipid);
+ fmt = ((id > 0xa000) || (id < 0x4000)) ? "BCM%d/%u" : "BCM%x/%u";
+ snprintf(buf, len, fmt, id, rev);
return buf;
}
@@ -924,10 +924,10 @@ static int brcmf_chip_recognition(struct brcmf_chip_priv *ci)
ci->pub.chiprev = (regdata & CID_REV_MASK) >> CID_REV_SHIFT;
socitype = (regdata & CID_TYPE_MASK) >> CID_TYPE_SHIFT;
- brcmf_chip_name(ci->pub.chip, ci->pub.name, sizeof(ci->pub.name));
- brcmf_dbg(INFO, "found %s chip: BCM%s, rev=%d\n",
- socitype == SOCI_SB ? "SB" : "AXI", ci->pub.name,
- ci->pub.chiprev);
+ brcmf_chip_name(ci->pub.chip, ci->pub.chiprev,
+ ci->pub.name, sizeof(ci->pub.name));
+ brcmf_dbg(INFO, "found %s chip: %s\n",
+ socitype == SOCI_SB ? "SB" : "AXI", ci->pub.name);
if (socitype == SOCI_SB) {
if (ci->pub.chip != BRCM_CC_4329_CHIP_ID) {
diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/chip.h b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/chip.h
index dd0ec3eba6a9..0ae3b33bab62 100644
--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/chip.h
+++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/chip.h
@@ -45,7 +45,7 @@ struct brcmf_chip {
u32 rambase;
u32 ramsize;
u32 srsize;
- char name[8];
+ char name[12];
};
/**
@@ -93,5 +93,6 @@ void brcmf_chip_resetcore(struct brcmf_core *core, u32 prereset, u32 reset,
void brcmf_chip_set_passive(struct brcmf_chip *ci);
bool brcmf_chip_set_active(struct brcmf_chip *ci, u32 rstvec);
bool brcmf_chip_sr_capable(struct brcmf_chip *pub);
+char *brcmf_chip_name(u32 chipid, u32 chiprev, char *buf, uint len);
#endif /* BRCMF_AXIDMP_H */
diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/common.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/common.c
index 70ef9835b647..105b8774fca9 100644
--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/common.c
+++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/common.c
@@ -30,6 +30,7 @@
#include "common.h"
#include "of.h"
#include "firmware.h"
+#include "chip.h"
MODULE_AUTHOR("Broadcom Corporation");
MODULE_DESCRIPTION("Broadcom 802.11 wireless LAN fullmac driver.");
@@ -51,7 +52,7 @@ MODULE_PARM_DESC(txglomsz, "Maximum tx packet chain size [SDIO]");
/* Debug level configuration. See debug.h for bits, sysfs modifiable */
int brcmf_msg_level;
-module_param_named(debug, brcmf_msg_level, int, S_IRUSR | S_IWUSR);
+module_param_named(debug, brcmf_msg_level, int, 0600);
MODULE_PARM_DESC(debug, "Level of debug output");
static int brcmf_p2p_enable;
@@ -64,7 +65,7 @@ MODULE_PARM_DESC(feature_disable, "Disable features");
static char brcmf_firmware_path[BRCMF_FW_ALTPATH_LEN];
module_param_string(alternative_fw_path, brcmf_firmware_path,
- BRCMF_FW_ALTPATH_LEN, S_IRUSR);
+ BRCMF_FW_ALTPATH_LEN, 0400);
MODULE_PARM_DESC(alternative_fw_path, "Alternative firmware path");
static int brcmf_fcmode;
@@ -72,9 +73,13 @@ module_param_named(fcmode, brcmf_fcmode, int, 0);
MODULE_PARM_DESC(fcmode, "Mode of firmware signalled flow control");
static int brcmf_roamoff;
-module_param_named(roamoff, brcmf_roamoff, int, S_IRUSR);
+module_param_named(roamoff, brcmf_roamoff, int, 0400);
MODULE_PARM_DESC(roamoff, "Do not use internal roaming engine");
+static int brcmf_iapp_enable;
+module_param_named(iapp, brcmf_iapp_enable, int, 0);
+MODULE_PARM_DESC(iapp, "Enable partial support for the obsoleted Inter-Access Point Protocol");
+
#ifdef DEBUG
/* always succeed brcmf_bus_started() */
static int brcmf_ignore_probe_fail;
@@ -124,43 +129,9 @@ static int brcmf_c_download(struct brcmf_if *ifp, u16 flag,
return err;
}
-static int brcmf_c_get_clm_name(struct brcmf_if *ifp, u8 *clm_name)
-{
- struct brcmf_bus *bus = ifp->drvr->bus_if;
- struct brcmf_rev_info *ri = &ifp->drvr->revinfo;
- u8 fw_name[BRCMF_FW_NAME_LEN];
- u8 *ptr;
- size_t len;
- s32 err;
-
- memset(fw_name, 0, BRCMF_FW_NAME_LEN);
- err = brcmf_bus_get_fwname(bus, ri->chipnum, ri->chiprev, fw_name);
- if (err) {
- brcmf_err("get firmware name failed (%d)\n", err);
- goto done;
- }
-
- /* generate CLM blob file name */
- ptr = strrchr(fw_name, '.');
- if (!ptr) {
- err = -ENOENT;
- goto done;
- }
-
- len = ptr - fw_name + 1;
- if (len + strlen(".clm_blob") > BRCMF_FW_NAME_LEN) {
- err = -E2BIG;
- } else {
- strlcpy(clm_name, fw_name, len);
- strlcat(clm_name, ".clm_blob", BRCMF_FW_NAME_LEN);
- }
-done:
- return err;
-}
-
static int brcmf_c_process_clm_blob(struct brcmf_if *ifp)
{
- struct device *dev = ifp->drvr->bus_if->dev;
+ struct brcmf_bus *bus = ifp->drvr->bus_if;
struct brcmf_dload_data_le *chunk_buf;
const struct firmware *clm = NULL;
u8 clm_name[BRCMF_FW_NAME_LEN];
@@ -173,16 +144,16 @@ static int brcmf_c_process_clm_blob(struct brcmf_if *ifp)
brcmf_dbg(TRACE, "Enter\n");
- memset(clm_name, 0, BRCMF_FW_NAME_LEN);
- err = brcmf_c_get_clm_name(ifp, clm_name);
+ memset(clm_name, 0, sizeof(clm_name));
+ err = brcmf_bus_get_fwname(bus, ".clm_blob", clm_name);
if (err) {
brcmf_err("get CLM blob file name failed (%d)\n", err);
return err;
}
- err = request_firmware(&clm, clm_name, dev);
+ err = request_firmware(&clm, clm_name, bus->dev);
if (err) {
- brcmf_info("no clm_blob available(err=%d), device may have limited channels available\n",
+ brcmf_info("no clm_blob available (err=%d), device may have limited channels available\n",
err);
return 0;
}
@@ -234,6 +205,7 @@ int brcmf_c_preinit_dcmds(struct brcmf_if *ifp)
{
s8 eventmask[BRCMF_EVENTING_MASK_LEN];
u8 buf[BRCMF_DCMD_SMLEN];
+ struct brcmf_bus *bus;
struct brcmf_rev_info_le revinfo;
struct brcmf_rev_info *ri;
char *clmver;
@@ -247,18 +219,21 @@ int brcmf_c_preinit_dcmds(struct brcmf_if *ifp)
brcmf_err("Retreiving cur_etheraddr failed, %d\n", err);
goto done;
}
+ memcpy(ifp->drvr->wiphy->perm_addr, ifp->drvr->mac, ETH_ALEN);
memcpy(ifp->drvr->mac, ifp->mac_addr, sizeof(ifp->drvr->mac));
+ bus = ifp->drvr->bus_if;
+ ri = &ifp->drvr->revinfo;
+
err = brcmf_fil_cmd_data_get(ifp, BRCMF_C_GET_REVINFO,
&revinfo, sizeof(revinfo));
- ri = &ifp->drvr->revinfo;
if (err < 0) {
brcmf_err("retrieving revision info failed, %d\n", err);
+ strlcpy(ri->chipname, "UNKNOWN", sizeof(ri->chipname));
} else {
ri->vendorid = le32_to_cpu(revinfo.vendorid);
ri->deviceid = le32_to_cpu(revinfo.deviceid);
ri->radiorev = le32_to_cpu(revinfo.radiorev);
- ri->chiprev = le32_to_cpu(revinfo.chiprev);
ri->corerev = le32_to_cpu(revinfo.corerev);
ri->boardid = le32_to_cpu(revinfo.boardid);
ri->boardvendor = le32_to_cpu(revinfo.boardvendor);
@@ -266,15 +241,24 @@ int brcmf_c_preinit_dcmds(struct brcmf_if *ifp)
ri->driverrev = le32_to_cpu(revinfo.driverrev);
ri->ucoderev = le32_to_cpu(revinfo.ucoderev);
ri->bus = le32_to_cpu(revinfo.bus);
- ri->chipnum = le32_to_cpu(revinfo.chipnum);
ri->phytype = le32_to_cpu(revinfo.phytype);
ri->phyrev = le32_to_cpu(revinfo.phyrev);
ri->anarev = le32_to_cpu(revinfo.anarev);
ri->chippkg = le32_to_cpu(revinfo.chippkg);
ri->nvramrev = le32_to_cpu(revinfo.nvramrev);
+
+ /* use revinfo if not known yet */
+ if (!bus->chip) {
+ bus->chip = le32_to_cpu(revinfo.chipnum);
+ bus->chiprev = le32_to_cpu(revinfo.chiprev);
+ }
}
ri->result = err;
+ if (bus->chip)
+ brcmf_chip_name(bus->chip, bus->chiprev,
+ ri->chipname, sizeof(ri->chipname));
+
/* Do any CLM downloading */
err = brcmf_c_process_clm_blob(ifp);
if (err < 0) {
@@ -295,7 +279,7 @@ int brcmf_c_preinit_dcmds(struct brcmf_if *ifp)
strsep(&ptr, "\n");
/* Print fw version info */
- brcmf_info("Firmware version = %s\n", buf);
+ brcmf_info("Firmware: %s %s\n", ri->chipname, buf);
/* locate firmware version number for ethtool */
ptr = strrchr(buf, ' ') + 1;
@@ -438,6 +422,7 @@ struct brcmf_mp_device *brcmf_get_module_param(struct device *dev,
settings->feature_disable = brcmf_feature_disable;
settings->fcmode = brcmf_fcmode;
settings->roamoff = !!brcmf_roamoff;
+ settings->iapp = !!brcmf_iapp_enable;
#ifdef DEBUG
settings->ignore_probe_fail = !!brcmf_ignore_probe_fail;
#endif
@@ -511,9 +496,6 @@ static int __init brcmfmac_module_init(void)
{
int err;
- /* Initialize debug system first */
- brcmf_debugfs_init();
-
/* Get the platform data (if available) for our devices */
err = platform_driver_probe(&brcmf_pd, brcmf_common_pd_probe);
if (err == -ENODEV)
@@ -525,7 +507,6 @@ static int __init brcmfmac_module_init(void)
/* Continue the initialization by registering the different busses */
err = brcmf_core_init();
if (err) {
- brcmf_debugfs_exit();
if (brcmfmac_pdata)
platform_driver_unregister(&brcmf_pd);
}
@@ -538,7 +519,6 @@ static void __exit brcmfmac_module_exit(void)
brcmf_core_exit();
if (brcmfmac_pdata)
platform_driver_unregister(&brcmf_pd);
- brcmf_debugfs_exit();
}
module_init(brcmfmac_module_init);
diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/common.h b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/common.h
index a62f8e70b320..ef914619e8e1 100644
--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/common.h
+++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/common.h
@@ -58,6 +58,7 @@ struct brcmf_mp_device {
unsigned int feature_disable;
int fcmode;
bool roamoff;
+ bool iapp;
bool ignore_probe_fail;
struct brcmfmac_pd_cc *country_codes;
union {
diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/core.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/core.c
index 19048526b4af..8d4511eaa9b9 100644
--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/core.c
+++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/core.c
@@ -230,6 +230,37 @@ static void brcmf_netdev_set_multicast_list(struct net_device *ndev)
schedule_work(&ifp->multicast_work);
}
+/**
+ * brcmf_skb_is_iapp - checks if skb is an IAPP packet
+ *
+ * @skb: skb to check
+ */
+static bool brcmf_skb_is_iapp(struct sk_buff *skb)
+{
+ static const u8 iapp_l2_update_packet[6] __aligned(2) = {
+ 0x00, 0x01, 0xaf, 0x81, 0x01, 0x00,
+ };
+ unsigned char *eth_data;
+#if !defined(CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS)
+ const u16 *a, *b;
+#endif
+
+ if (skb->len - skb->mac_len != 6 ||
+ !is_multicast_ether_addr(eth_hdr(skb)->h_dest))
+ return false;
+
+ eth_data = skb_mac_header(skb) + ETH_HLEN;
+#if defined(CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS)
+ return !(((*(const u32 *)eth_data) ^ (*(const u32 *)iapp_l2_update_packet)) |
+ ((*(const u16 *)(eth_data + 4)) ^ (*(const u16 *)(iapp_l2_update_packet + 4))));
+#else
+ a = (const u16 *)eth_data;
+ b = (const u16 *)iapp_l2_update_packet;
+
+ return !((a[0] ^ b[0]) | (a[1] ^ b[1]) | (a[2] ^ b[2]));
+#endif
+}
+
static netdev_tx_t brcmf_netdev_start_xmit(struct sk_buff *skb,
struct net_device *ndev)
{
@@ -250,6 +281,23 @@ static netdev_tx_t brcmf_netdev_start_xmit(struct sk_buff *skb,
goto done;
}
+ /* Some recent Broadcom's firmwares disassociate STA when they receive
+ * an 802.11f ADD frame. This behavior can lead to a local DoS security
+ * issue. Attacker may trigger disassociation of any STA by sending a
+ * proper Ethernet frame to the wireless interface.
+ *
+ * Moreover this feature may break AP interfaces in some specific
+ * setups. This applies e.g. to the bridge with hairpin mode enabled and
+ * IFLA_BRPORT_MCAST_TO_UCAST set. IAPP packet generated by a firmware
+ * will get passed back to the wireless interface and cause immediate
+ * disassociation of a just-connected STA.
+ */
+ if (!drvr->settings->iapp && brcmf_skb_is_iapp(skb)) {
+ dev_kfree_skb(skb);
+ ret = -EINVAL;
+ goto done;
+ }
+
/* Make sure there's enough writeable headroom */
if (skb_headroom(skb) < drvr->hdrlen || skb_header_cloned(skb)) {
head_delta = max_t(int, drvr->hdrlen - skb_headroom(skb), 0);
@@ -325,6 +373,15 @@ void brcmf_txflowblock_if(struct brcmf_if *ifp,
void brcmf_netif_rx(struct brcmf_if *ifp, struct sk_buff *skb)
{
+ /* Most of Broadcom's firmwares send 802.11f ADD frame every time a new
+ * STA connects to the AP interface. This is an obsoleted standard most
+ * users don't use, so don't pass these frames up unless requested.
+ */
+ if (!ifp->drvr->settings->iapp && brcmf_skb_is_iapp(skb)) {
+ brcmu_pkt_buf_free_skb(skb);
+ return;
+ }
+
if (skb->pkt_type == PACKET_MULTICAST)
ifp->ndev->stats.multicast++;
@@ -924,8 +981,7 @@ static int brcmf_revinfo_read(struct seq_file *s, void *data)
seq_printf(s, "vendorid: 0x%04x\n", ri->vendorid);
seq_printf(s, "deviceid: 0x%04x\n", ri->deviceid);
seq_printf(s, "radiorev: %s\n", brcmu_dotrev_str(ri->radiorev, drev));
- seq_printf(s, "chipnum: %u (%x)\n", ri->chipnum, ri->chipnum);
- seq_printf(s, "chiprev: %u\n", ri->chiprev);
+ seq_printf(s, "chip: %s\n", ri->chipname);
seq_printf(s, "chippkg: %u\n", ri->chippkg);
seq_printf(s, "corerev: %u\n", ri->corerev);
seq_printf(s, "boardid: 0x%04x\n", ri->boardid);
@@ -944,7 +1000,7 @@ static int brcmf_revinfo_read(struct seq_file *s, void *data)
return 0;
}
-static int brcmf_bus_started(struct brcmf_pub *drvr)
+static int brcmf_bus_started(struct brcmf_pub *drvr, struct cfg80211_ops *ops)
{
int ret = -1;
struct brcmf_bus *bus_if = drvr->bus_if;
@@ -973,15 +1029,6 @@ static int brcmf_bus_started(struct brcmf_pub *drvr)
if (ret < 0)
goto fail;
- brcmf_debugfs_add_entry(drvr, "revinfo", brcmf_revinfo_read);
-
- /* assure we have chipid before feature attach */
- if (!bus_if->chip) {
- bus_if->chip = drvr->revinfo.chipnum;
- bus_if->chiprev = drvr->revinfo.chiprev;
- brcmf_dbg(INFO, "firmware revinfo: chip %x (%d) rev %d\n",
- bus_if->chip, bus_if->chip, bus_if->chiprev);
- }
brcmf_feat_attach(drvr);
ret = brcmf_proto_init_done(drvr);
@@ -990,7 +1037,7 @@ static int brcmf_bus_started(struct brcmf_pub *drvr)
brcmf_proto_add_if(drvr, ifp);
- drvr->config = brcmf_cfg80211_attach(drvr, bus_if->dev,
+ drvr->config = brcmf_cfg80211_attach(drvr, ops,
drvr->settings->p2p_enable);
if (drvr->config == NULL) {
ret = -ENOMEM;
@@ -1024,6 +1071,11 @@ static int brcmf_bus_started(struct brcmf_pub *drvr)
#endif
#endif /* CONFIG_INET */
+ /* populate debugfs */
+ brcmf_debugfs_add_entry(drvr, "revinfo", brcmf_revinfo_read);
+ brcmf_feat_debugfs_create(drvr);
+ brcmf_proto_debugfs_create(drvr);
+
return 0;
fail:
@@ -1045,17 +1097,26 @@ fail:
int brcmf_attach(struct device *dev, struct brcmf_mp_device *settings)
{
+ struct wiphy *wiphy;
+ struct cfg80211_ops *ops;
struct brcmf_pub *drvr = NULL;
int ret = 0;
int i;
brcmf_dbg(TRACE, "Enter\n");
- /* Allocate primary brcmf_info */
- drvr = kzalloc(sizeof(*drvr), GFP_ATOMIC);
- if (!drvr)
+ ops = brcmf_cfg80211_get_ops();
+ if (!ops)
+ return -ENOMEM;
+
+ wiphy = wiphy_new(ops, sizeof(*drvr));
+ if (!wiphy)
return -ENOMEM;
+ set_wiphy_dev(wiphy, dev);
+ drvr = wiphy_priv(wiphy);
+ drvr->wiphy = wiphy;
+
for (i = 0; i < ARRAY_SIZE(drvr->if2bss); i++)
drvr->if2bss[i] = BRCMF_BSSIDX_INVALID;
@@ -1067,9 +1128,6 @@ int brcmf_attach(struct device *dev, struct brcmf_mp_device *settings)
drvr->bus_if->drvr = drvr;
drvr->settings = settings;
- /* attach debug facilities */
- brcmf_debug_attach(drvr);
-
/* Attach and link in the protocol */
ret = brcmf_proto_attach(drvr);
if (ret != 0) {
@@ -1084,15 +1142,18 @@ int brcmf_attach(struct device *dev, struct brcmf_mp_device *settings)
/* attach firmware event handler */
brcmf_fweh_attach(drvr);
- ret = brcmf_bus_started(drvr);
+ ret = brcmf_bus_started(drvr, ops);
if (ret != 0) {
brcmf_err("dongle is not responding: err=%d\n", ret);
goto fail;
}
+
+ drvr->config->ops = ops;
return 0;
fail:
brcmf_detach(dev);
+ kfree(ops);
return ret;
}
@@ -1150,14 +1211,14 @@ void brcmf_detach(struct device *dev)
brcmf_remove_interface(drvr->iflist[i], false);
brcmf_cfg80211_detach(drvr->config);
+ drvr->config = NULL;
brcmf_bus_stop(drvr->bus_if);
brcmf_proto_detach(drvr);
- brcmf_debug_detach(drvr);
bus_if->drvr = NULL;
- kfree(drvr);
+ wiphy_free(drvr->wiphy);
}
s32 brcmf_iovar_data_set(struct device *dev, char *name, void *data, u32 len)
diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/core.h b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/core.h
index 232dcbb83311..401f50458686 100644
--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/core.h
+++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/core.h
@@ -87,7 +87,6 @@ struct brcmf_rev_info {
u32 vendorid;
u32 deviceid;
u32 radiorev;
- u32 chiprev;
u32 corerev;
u32 boardid;
u32 boardvendor;
@@ -95,7 +94,7 @@ struct brcmf_rev_info {
u32 driverrev;
u32 ucoderev;
u32 bus;
- u32 chipnum;
+ char chipname[12];
u32 phytype;
u32 phyrev;
u32 anarev;
@@ -108,6 +107,7 @@ struct brcmf_pub {
/* Linkage ponters */
struct brcmf_bus *bus_if;
struct brcmf_proto *proto;
+ struct wiphy *wiphy;
struct brcmf_cfg80211_info *config;
/* Internal brcmf items */
diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/debug.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/debug.c
index 2d3e5e263a32..504832084eca 100644
--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/debug.c
+++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/debug.c
@@ -25,8 +25,6 @@
#include "fweh.h"
#include "debug.h"
-static struct dentry *root_folder;
-
int brcmf_debug_create_memdump(struct brcmf_bus *bus, const void *data,
size_t len)
{
@@ -54,44 +52,9 @@ int brcmf_debug_create_memdump(struct brcmf_bus *bus, const void *data,
return 0;
}
-void brcmf_debugfs_init(void)
-{
- root_folder = debugfs_create_dir(KBUILD_MODNAME, NULL);
- if (IS_ERR(root_folder))
- root_folder = NULL;
-}
-
-void brcmf_debugfs_exit(void)
-{
- if (!root_folder)
- return;
-
- debugfs_remove_recursive(root_folder);
- root_folder = NULL;
-}
-
-int brcmf_debug_attach(struct brcmf_pub *drvr)
-{
- struct device *dev = drvr->bus_if->dev;
-
- if (!root_folder)
- return -ENODEV;
-
- drvr->dbgfs_dir = debugfs_create_dir(dev_name(dev), root_folder);
- return PTR_ERR_OR_ZERO(drvr->dbgfs_dir);
-}
-
-void brcmf_debug_detach(struct brcmf_pub *drvr)
-{
- brcmf_fweh_unregister(drvr, BRCMF_E_PSM_WATCHDOG);
-
- if (!IS_ERR_OR_NULL(drvr->dbgfs_dir))
- debugfs_remove_recursive(drvr->dbgfs_dir);
-}
-
struct dentry *brcmf_debugfs_get_devdir(struct brcmf_pub *drvr)
{
- return drvr->dbgfs_dir;
+ return drvr->wiphy->debugfsdir;
}
int brcmf_debugfs_add_entry(struct brcmf_pub *drvr, const char *fn,
@@ -99,7 +62,8 @@ int brcmf_debugfs_add_entry(struct brcmf_pub *drvr, const char *fn,
{
struct dentry *e;
+ WARN(!drvr->wiphy->debugfsdir, "wiphy not (yet) registered\n");
e = debugfs_create_devm_seqfile(drvr->bus_if->dev, fn,
- drvr->dbgfs_dir, read_fn);
+ drvr->wiphy->debugfsdir, read_fn);
return PTR_ERR_OR_ZERO(e);
}
diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/debug.h b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/debug.h
index 35919d9e8e13..cfed0626bf5a 100644
--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/debug.h
+++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/debug.h
@@ -113,29 +113,12 @@ extern int brcmf_msg_level;
struct brcmf_bus;
struct brcmf_pub;
#ifdef DEBUG
-void brcmf_debugfs_init(void);
-void brcmf_debugfs_exit(void);
-int brcmf_debug_attach(struct brcmf_pub *drvr);
-void brcmf_debug_detach(struct brcmf_pub *drvr);
struct dentry *brcmf_debugfs_get_devdir(struct brcmf_pub *drvr);
int brcmf_debugfs_add_entry(struct brcmf_pub *drvr, const char *fn,
int (*read_fn)(struct seq_file *seq, void *data));
int brcmf_debug_create_memdump(struct brcmf_bus *bus, const void *data,
size_t len);
#else
-static inline void brcmf_debugfs_init(void)
-{
-}
-static inline void brcmf_debugfs_exit(void)
-{
-}
-static inline int brcmf_debug_attach(struct brcmf_pub *drvr)
-{
- return 0;
-}
-static inline void brcmf_debug_detach(struct brcmf_pub *drvr)
-{
-}
static inline
int brcmf_debugfs_add_entry(struct brcmf_pub *drvr, const char *fn,
int (*read_fn)(struct seq_file *seq, void *data))
diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/feature.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/feature.c
index bede7b7fd996..876731c57bf5 100644
--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/feature.c
+++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/feature.c
@@ -228,7 +228,10 @@ void brcmf_feat_attach(struct brcmf_pub *drvr)
/* no quirks */
break;
}
+}
+void brcmf_feat_debugfs_create(struct brcmf_pub *drvr)
+{
brcmf_debugfs_add_entry(drvr, "features", brcmf_feat_debugfs_read);
}
diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/feature.h b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/feature.h
index 1ab4f1617112..d1193825e559 100644
--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/feature.h
+++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/feature.h
@@ -90,6 +90,13 @@ enum brcmf_feat_quirk {
void brcmf_feat_attach(struct brcmf_pub *drvr);
/**
+ * brcmf_feat_debugfs_create() - create debugfs entries.
+ *
+ * @drvr: driver instance.
+ */
+void brcmf_feat_debugfs_create(struct brcmf_pub *drvr);
+
+/**
* brcmf_feat_is_enabled() - query feature.
*
* @ifp: interface instance.
diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/firmware.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/firmware.c
index 091b52979e03..9277f4c2bfeb 100644
--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/firmware.c
+++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/firmware.c
@@ -25,6 +25,7 @@
#include "firmware.h"
#include "core.h"
#include "common.h"
+#include "chip.h"
#define BRCMF_FW_MAX_NVRAM_SIZE 64000
#define BRCMF_FW_NVRAM_DEVPATH_LEN 19 /* devpath0=pcie/1/4/ */
@@ -437,18 +438,31 @@ void brcmf_fw_nvram_free(void *nvram)
struct brcmf_fw {
struct device *dev;
- u16 flags;
- const struct firmware *code;
- const char *nvram_name;
- u16 domain_nr;
- u16 bus_nr;
- void (*done)(struct device *dev, int err, const struct firmware *fw,
- void *nvram_image, u32 nvram_len);
+ struct brcmf_fw_request *req;
+ u32 curpos;
+ void (*done)(struct device *dev, int err, struct brcmf_fw_request *req);
};
+static void brcmf_fw_request_done(const struct firmware *fw, void *ctx);
+
+static void brcmf_fw_free_request(struct brcmf_fw_request *req)
+{
+ struct brcmf_fw_item *item;
+ int i;
+
+ for (i = 0, item = &req->items[0]; i < req->n_items; i++, item++) {
+ if (item->type == BRCMF_FW_TYPE_BINARY)
+ release_firmware(item->binary);
+ else if (item->type == BRCMF_FW_TYPE_NVRAM)
+ brcmf_fw_nvram_free(item->nv_data.data);
+ }
+ kfree(req);
+}
+
static void brcmf_fw_request_nvram_done(const struct firmware *fw, void *ctx)
{
struct brcmf_fw *fwctx = ctx;
+ struct brcmf_fw_item *cur;
u32 nvram_length = 0;
void *nvram = NULL;
u8 *data = NULL;
@@ -456,83 +470,150 @@ static void brcmf_fw_request_nvram_done(const struct firmware *fw, void *ctx)
bool raw_nvram;
brcmf_dbg(TRACE, "enter: dev=%s\n", dev_name(fwctx->dev));
+
+ cur = &fwctx->req->items[fwctx->curpos];
+
if (fw && fw->data) {
data = (u8 *)fw->data;
data_len = fw->size;
raw_nvram = false;
} else {
data = bcm47xx_nvram_get_contents(&data_len);
- if (!data && !(fwctx->flags & BRCMF_FW_REQ_NV_OPTIONAL))
+ if (!data && !(cur->flags & BRCMF_FW_REQF_OPTIONAL))
goto fail;
raw_nvram = true;
}
if (data)
nvram = brcmf_fw_nvram_strip(data, data_len, &nvram_length,
- fwctx->domain_nr, fwctx->bus_nr);
+ fwctx->req->domain_nr,
+ fwctx->req->bus_nr);
if (raw_nvram)
bcm47xx_nvram_release_contents(data);
release_firmware(fw);
- if (!nvram && !(fwctx->flags & BRCMF_FW_REQ_NV_OPTIONAL))
+ if (!nvram && !(cur->flags & BRCMF_FW_REQF_OPTIONAL))
goto fail;
- fwctx->done(fwctx->dev, 0, fwctx->code, nvram, nvram_length);
- kfree(fwctx);
+ brcmf_dbg(TRACE, "nvram %p len %d\n", nvram, nvram_length);
+ cur->nv_data.data = nvram;
+ cur->nv_data.len = nvram_length;
return;
fail:
brcmf_dbg(TRACE, "failed: dev=%s\n", dev_name(fwctx->dev));
- release_firmware(fwctx->code);
- fwctx->done(fwctx->dev, -ENOENT, NULL, NULL, 0);
+ fwctx->done(fwctx->dev, -ENOENT, NULL);
+ brcmf_fw_free_request(fwctx->req);
kfree(fwctx);
}
-static void brcmf_fw_request_code_done(const struct firmware *fw, void *ctx)
+static int brcmf_fw_request_next_item(struct brcmf_fw *fwctx, bool async)
+{
+ struct brcmf_fw_item *cur;
+ const struct firmware *fw = NULL;
+ int ret;
+
+ cur = &fwctx->req->items[fwctx->curpos];
+
+ brcmf_dbg(TRACE, "%srequest for %s\n", async ? "async " : "",
+ cur->path);
+
+ if (async)
+ ret = request_firmware_nowait(THIS_MODULE, true, cur->path,
+ fwctx->dev, GFP_KERNEL, fwctx,
+ brcmf_fw_request_done);
+ else
+ ret = request_firmware(&fw, cur->path, fwctx->dev);
+
+ if (ret < 0) {
+ brcmf_fw_request_done(NULL, fwctx);
+ } else if (!async && fw) {
+ brcmf_dbg(TRACE, "firmware %s %sfound\n", cur->path,
+ fw ? "" : "not ");
+ if (cur->type == BRCMF_FW_TYPE_BINARY)
+ cur->binary = fw;
+ else if (cur->type == BRCMF_FW_TYPE_NVRAM)
+ brcmf_fw_request_nvram_done(fw, fwctx);
+ else
+ release_firmware(fw);
+
+ return -EAGAIN;
+ }
+ return 0;
+}
+
+static void brcmf_fw_request_done(const struct firmware *fw, void *ctx)
{
struct brcmf_fw *fwctx = ctx;
+ struct brcmf_fw_item *cur;
int ret = 0;
- brcmf_dbg(TRACE, "enter: dev=%s\n", dev_name(fwctx->dev));
- if (!fw) {
+ cur = &fwctx->req->items[fwctx->curpos];
+
+ brcmf_dbg(TRACE, "enter: firmware %s %sfound\n", cur->path,
+ fw ? "" : "not ");
+
+ if (fw) {
+ if (cur->type == BRCMF_FW_TYPE_BINARY)
+ cur->binary = fw;
+ else if (cur->type == BRCMF_FW_TYPE_NVRAM)
+ brcmf_fw_request_nvram_done(fw, fwctx);
+ else
+ release_firmware(fw);
+ } else if (cur->type == BRCMF_FW_TYPE_NVRAM) {
+ brcmf_fw_request_nvram_done(NULL, fwctx);
+ } else if (!(cur->flags & BRCMF_FW_REQF_OPTIONAL)) {
ret = -ENOENT;
goto fail;
}
- /* only requested code so done here */
- if (!(fwctx->flags & BRCMF_FW_REQUEST_NVRAM))
- goto done;
- fwctx->code = fw;
- ret = request_firmware_nowait(THIS_MODULE, true, fwctx->nvram_name,
- fwctx->dev, GFP_KERNEL, fwctx,
- brcmf_fw_request_nvram_done);
+ do {
+ if (++fwctx->curpos == fwctx->req->n_items) {
+ ret = 0;
+ goto done;
+ }
+
+ ret = brcmf_fw_request_next_item(fwctx, false);
+ } while (ret == -EAGAIN);
- /* pass NULL to nvram callback for bcm47xx fallback */
- if (ret)
- brcmf_fw_request_nvram_done(NULL, fwctx);
return;
fail:
- brcmf_dbg(TRACE, "failed: dev=%s\n", dev_name(fwctx->dev));
+ brcmf_dbg(TRACE, "failed err=%d: dev=%s, fw=%s\n", ret,
+ dev_name(fwctx->dev), cur->path);
+ brcmf_fw_free_request(fwctx->req);
+ fwctx->req = NULL;
done:
- fwctx->done(fwctx->dev, ret, fw, NULL, 0);
+ fwctx->done(fwctx->dev, ret, fwctx->req);
kfree(fwctx);
}
-int brcmf_fw_get_firmwares_pcie(struct device *dev, u16 flags,
- const char *code, const char *nvram,
- void (*fw_cb)(struct device *dev, int err,
- const struct firmware *fw,
- void *nvram_image, u32 nvram_len),
- u16 domain_nr, u16 bus_nr)
+static bool brcmf_fw_request_is_valid(struct brcmf_fw_request *req)
+{
+ struct brcmf_fw_item *item;
+ int i;
+
+ if (!req->n_items)
+ return false;
+
+ for (i = 0, item = &req->items[0]; i < req->n_items; i++, item++) {
+ if (!item->path)
+ return false;
+ }
+ return true;
+}
+
+int brcmf_fw_get_firmwares(struct device *dev, struct brcmf_fw_request *req,
+ void (*fw_cb)(struct device *dev, int err,
+ struct brcmf_fw_request *req))
{
struct brcmf_fw *fwctx;
brcmf_dbg(TRACE, "enter: dev=%s\n", dev_name(dev));
- if (!fw_cb || !code)
+ if (!fw_cb)
return -EINVAL;
- if ((flags & BRCMF_FW_REQUEST_NVRAM) && !nvram)
+ if (!brcmf_fw_request_is_valid(req))
return -EINVAL;
fwctx = kzalloc(sizeof(*fwctx), GFP_KERNEL);
@@ -540,35 +621,25 @@ int brcmf_fw_get_firmwares_pcie(struct device *dev, u16 flags,
return -ENOMEM;
fwctx->dev = dev;
- fwctx->flags = flags;
+ fwctx->req = req;
fwctx->done = fw_cb;
- if (flags & BRCMF_FW_REQUEST_NVRAM)
- fwctx->nvram_name = nvram;
- fwctx->domain_nr = domain_nr;
- fwctx->bus_nr = bus_nr;
-
- return request_firmware_nowait(THIS_MODULE, true, code, dev,
- GFP_KERNEL, fwctx,
- brcmf_fw_request_code_done);
-}
-int brcmf_fw_get_firmwares(struct device *dev, u16 flags,
- const char *code, const char *nvram,
- void (*fw_cb)(struct device *dev, int err,
- const struct firmware *fw,
- void *nvram_image, u32 nvram_len))
-{
- return brcmf_fw_get_firmwares_pcie(dev, flags, code, nvram, fw_cb, 0,
- 0);
+ brcmf_fw_request_next_item(fwctx, true);
+ return 0;
}
-int brcmf_fw_map_chip_to_name(u32 chip, u32 chiprev,
- struct brcmf_firmware_mapping mapping_table[],
- u32 table_size, char fw_name[BRCMF_FW_NAME_LEN],
- char nvram_name[BRCMF_FW_NAME_LEN])
+struct brcmf_fw_request *
+brcmf_fw_alloc_request(u32 chip, u32 chiprev,
+ struct brcmf_firmware_mapping mapping_table[],
+ u32 table_size, struct brcmf_fw_name *fwnames,
+ u32 n_fwnames)
{
- u32 i;
+ struct brcmf_fw_request *fwreq;
+ char chipname[12];
+ const char *mp_path;
+ u32 i, j;
char end;
+ size_t reqsz;
for (i = 0; i < table_size; i++) {
if (mapping_table[i].chipid == chip &&
@@ -578,32 +649,41 @@ int brcmf_fw_map_chip_to_name(u32 chip, u32 chiprev,
if (i == table_size) {
brcmf_err("Unknown chipid %d [%d]\n", chip, chiprev);
- return -ENODEV;
+ return NULL;
}
- /* check if firmware path is provided by module parameter */
- if (brcmf_mp_global.firmware_path[0] != '\0') {
- strlcpy(fw_name, brcmf_mp_global.firmware_path,
- BRCMF_FW_NAME_LEN);
- if ((nvram_name) && (mapping_table[i].nvram))
- strlcpy(nvram_name, brcmf_mp_global.firmware_path,
+ reqsz = sizeof(*fwreq) + n_fwnames * sizeof(struct brcmf_fw_item);
+ fwreq = kzalloc(reqsz, GFP_KERNEL);
+ if (!fwreq)
+ return NULL;
+
+ brcmf_chip_name(chip, chiprev, chipname, sizeof(chipname));
+
+ brcmf_info("using %s for chip %s\n",
+ mapping_table[i].fw_base, chipname);
+
+ mp_path = brcmf_mp_global.firmware_path;
+ end = mp_path[strlen(mp_path) - 1];
+ fwreq->n_items = n_fwnames;
+
+ for (j = 0; j < n_fwnames; j++) {
+ fwreq->items[j].path = fwnames[j].path;
+ /* check if firmware path is provided by module parameter */
+ if (brcmf_mp_global.firmware_path[0] != '\0') {
+ strlcpy(fwnames[j].path, mp_path,
BRCMF_FW_NAME_LEN);
- end = brcmf_mp_global.firmware_path[
- strlen(brcmf_mp_global.firmware_path) - 1];
- if (end != '/') {
- strlcat(fw_name, "/", BRCMF_FW_NAME_LEN);
- if ((nvram_name) && (mapping_table[i].nvram))
- strlcat(nvram_name, "/", BRCMF_FW_NAME_LEN);
+ if (end != '/') {
+ strlcat(fwnames[j].path, "/",
+ BRCMF_FW_NAME_LEN);
+ }
}
+ strlcat(fwnames[j].path, mapping_table[i].fw_base,
+ BRCMF_FW_NAME_LEN);
+ strlcat(fwnames[j].path, fwnames[j].extension,
+ BRCMF_FW_NAME_LEN);
+ fwreq->items[j].path = fwnames[j].path;
}
- strlcat(fw_name, mapping_table[i].fw, BRCMF_FW_NAME_LEN);
- if ((nvram_name) && (mapping_table[i].nvram))
- strlcat(nvram_name, mapping_table[i].nvram, BRCMF_FW_NAME_LEN);
- brcmf_info("using %s for chip %#08x(%d) rev %#08x\n",
- fw_name, chip, chip, chiprev);
-
- return 0;
+ return fwreq;
}
-
diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/firmware.h b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/firmware.h
index 8fa4b7e1ab3d..79a21095c349 100644
--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/firmware.h
+++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/firmware.h
@@ -16,10 +16,7 @@
#ifndef BRCMFMAC_FIRMWARE_H
#define BRCMFMAC_FIRMWARE_H
-#define BRCMF_FW_REQUEST 0x000F
-#define BRCMF_FW_REQUEST_NVRAM 0x0001
-#define BRCMF_FW_REQ_FLAGS 0x00F0
-#define BRCMF_FW_REQ_NV_OPTIONAL 0x0010
+#define BRCMF_FW_REQF_OPTIONAL 0x0001
#define BRCMF_FW_NAME_LEN 320
@@ -38,49 +35,62 @@
struct brcmf_firmware_mapping {
u32 chipid;
u32 revmask;
- const char *fw;
- const char *nvram;
+ const char *fw_base;
};
-#define BRCMF_FW_NVRAM_DEF(fw_nvram_name, fw, nvram) \
-static const char BRCM_ ## fw_nvram_name ## _FIRMWARE_NAME[] = \
- BRCMF_FW_DEFAULT_PATH fw; \
-static const char BRCM_ ## fw_nvram_name ## _NVRAM_NAME[] = \
- BRCMF_FW_DEFAULT_PATH nvram; \
-MODULE_FIRMWARE(BRCMF_FW_DEFAULT_PATH fw);
-
-#define BRCMF_FW_DEF(fw_name, fw) \
-static const char BRCM_ ## fw_name ## _FIRMWARE_NAME[] = \
- BRCMF_FW_DEFAULT_PATH fw; \
-MODULE_FIRMWARE(BRCMF_FW_DEFAULT_PATH fw) \
-
-#define BRCMF_FW_NVRAM_ENTRY(chipid, mask, name) \
- { chipid, mask, \
- BRCM_ ## name ## _FIRMWARE_NAME, BRCM_ ## name ## _NVRAM_NAME }
+#define BRCMF_FW_DEF(fw_name, fw_base) \
+static const char BRCM_ ## fw_name ## _FIRMWARE_BASENAME[] = \
+ BRCMF_FW_DEFAULT_PATH fw_base; \
+MODULE_FIRMWARE(BRCMF_FW_DEFAULT_PATH fw_base ".bin")
#define BRCMF_FW_ENTRY(chipid, mask, name) \
- { chipid, mask, BRCM_ ## name ## _FIRMWARE_NAME, NULL }
+ { chipid, mask, BRCM_ ## name ## _FIRMWARE_BASENAME }
-int brcmf_fw_map_chip_to_name(u32 chip, u32 chiprev,
- struct brcmf_firmware_mapping mapping_table[],
- u32 table_size, char fw_name[BRCMF_FW_NAME_LEN],
- char nvram_name[BRCMF_FW_NAME_LEN]);
void brcmf_fw_nvram_free(void *nvram);
+
+enum brcmf_fw_type {
+ BRCMF_FW_TYPE_BINARY,
+ BRCMF_FW_TYPE_NVRAM
+};
+
+struct brcmf_fw_item {
+ const char *path;
+ enum brcmf_fw_type type;
+ u16 flags;
+ union {
+ const struct firmware *binary;
+ struct {
+ void *data;
+ u32 len;
+ } nv_data;
+ };
+};
+
+struct brcmf_fw_request {
+ u16 domain_nr;
+ u16 bus_nr;
+ u32 n_items;
+ struct brcmf_fw_item items[0];
+};
+
+struct brcmf_fw_name {
+ const char *extension;
+ char *path;
+};
+
+struct brcmf_fw_request *
+brcmf_fw_alloc_request(u32 chip, u32 chiprev,
+ struct brcmf_firmware_mapping mapping_table[],
+ u32 table_size, struct brcmf_fw_name *fwnames,
+ u32 n_fwnames);
+
/*
* Request firmware(s) asynchronously. When the asynchronous request
* fails it will not use the callback, but call device_release_driver()
* instead which will call the driver .remove() callback.
*/
-int brcmf_fw_get_firmwares_pcie(struct device *dev, u16 flags,
- const char *code, const char *nvram,
- void (*fw_cb)(struct device *dev, int err,
- const struct firmware *fw,
- void *nvram_image, u32 nvram_len),
- u16 domain_nr, u16 bus_nr);
-int brcmf_fw_get_firmwares(struct device *dev, u16 flags,
- const char *code, const char *nvram,
+int brcmf_fw_get_firmwares(struct device *dev, struct brcmf_fw_request *req,
void (*fw_cb)(struct device *dev, int err,
- const struct firmware *fw,
- void *nvram_image, u32 nvram_len));
+ struct brcmf_fw_request *req));
#endif /* BRCMFMAC_FIRMWARE_H */
diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/fwil.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/fwil.c
index fc5751116d99..802d7cb73b80 100644
--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/fwil.c
+++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/fwil.c
@@ -124,8 +124,7 @@ brcmf_fil_cmd_data(struct brcmf_if *ifp, u32 cmd, void *data, u32 len, bool set)
data, len, &fwerr);
if (err) {
- brcmf_dbg(FIL, "Failed: %s (%d)\n",
- brcmf_fil_get_errstr((u32)(-err)), err);
+ brcmf_dbg(FIL, "Failed: error=%d\n", err);
} else if (fwerr < 0) {
brcmf_dbg(FIL, "Firmware error: %s (%d)\n",
brcmf_fil_get_errstr((u32)(-fwerr)), fwerr);
diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/fwsignal.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/fwsignal.c
index f59642b2c935..f3cbf78c8899 100644
--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/fwsignal.c
+++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/fwsignal.c
@@ -2399,10 +2399,6 @@ struct brcmf_fws_info *brcmf_fws_attach(struct brcmf_pub *drvr)
brcmu_pktq_init(&fws->desc.other.psq, BRCMF_FWS_PSQ_PREC_COUNT,
BRCMF_FWS_PSQ_LEN);
- /* create debugfs file for statistics */
- brcmf_debugfs_add_entry(drvr, "fws_stats",
- brcmf_debugfs_fws_stats_read);
-
brcmf_dbg(INFO, "%s bdcv2 tlv signaling [%x]\n",
fws->fw_signals ? "enabled" : "disabled", tlv);
return fws;
@@ -2429,6 +2425,13 @@ void brcmf_fws_detach(struct brcmf_fws_info *fws)
kfree(fws);
}
+void brcmf_fws_debugfs_create(struct brcmf_pub *drvr)
+{
+ /* create debugfs file for statistics */
+ brcmf_debugfs_add_entry(drvr, "fws_stats",
+ brcmf_debugfs_fws_stats_read);
+}
+
bool brcmf_fws_queue_skbs(struct brcmf_fws_info *fws)
{
return !fws->avoid_queueing;
diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/fwsignal.h b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/fwsignal.h
index ba07bd972002..4e6835766d5d 100644
--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/fwsignal.h
+++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/fwsignal.h
@@ -20,6 +20,7 @@
struct brcmf_fws_info *brcmf_fws_attach(struct brcmf_pub *drvr);
void brcmf_fws_detach(struct brcmf_fws_info *fws);
+void brcmf_fws_debugfs_create(struct brcmf_pub *drvr);
bool brcmf_fws_queue_skbs(struct brcmf_fws_info *fws);
bool brcmf_fws_fc_active(struct brcmf_fws_info *fws);
void brcmf_fws_hdrpull(struct brcmf_if *ifp, s16 siglen, struct sk_buff *skb);
diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/msgbuf.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/msgbuf.c
index e212a791a072..49d37ad96958 100644
--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/msgbuf.c
+++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/msgbuf.c
@@ -1418,6 +1418,11 @@ static int brcmf_msgbuf_stats_read(struct seq_file *seq, void *data)
}
#endif
+static void brcmf_msgbuf_debugfs_create(struct brcmf_pub *drvr)
+{
+ brcmf_debugfs_add_entry(drvr, "msgbuf_stats", brcmf_msgbuf_stats_read);
+}
+
int brcmf_proto_msgbuf_attach(struct brcmf_pub *drvr)
{
struct brcmf_bus_msgbuf *if_msgbuf;
@@ -1472,6 +1477,7 @@ int brcmf_proto_msgbuf_attach(struct brcmf_pub *drvr)
drvr->proto->delete_peer = brcmf_msgbuf_delete_peer;
drvr->proto->add_tdls_peer = brcmf_msgbuf_add_tdls_peer;
drvr->proto->rxreorder = brcmf_msgbuf_rxreorder;
+ drvr->proto->debugfs_create = brcmf_msgbuf_debugfs_create;
drvr->proto->pd = msgbuf;
init_waitqueue_head(&msgbuf->ioctl_resp_wait);
@@ -1525,8 +1531,6 @@ int brcmf_proto_msgbuf_attach(struct brcmf_pub *drvr)
spin_lock_init(&msgbuf->flowring_work_lock);
INIT_LIST_HEAD(&msgbuf->work_queue);
- brcmf_debugfs_add_entry(drvr, "msgbuf_stats", brcmf_msgbuf_stats_read);
-
return 0;
fail:
diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/p2p.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/p2p.c
index 82064e909784..bcef208a81a5 100644
--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/p2p.c
+++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/p2p.c
@@ -2227,7 +2227,7 @@ fail:
*/
int brcmf_p2p_del_vif(struct wiphy *wiphy, struct wireless_dev *wdev)
{
- struct brcmf_cfg80211_info *cfg = wiphy_priv(wiphy);
+ struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy);
struct brcmf_p2p_info *p2p = &cfg->p2p;
struct brcmf_cfg80211_vif *vif;
enum nl80211_iftype iftype;
diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/pcie.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/pcie.c
index a7d827ce1684..091c191ce259 100644
--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/pcie.c
+++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/pcie.c
@@ -46,36 +46,36 @@ enum brcmf_pcie_state {
BRCMFMAC_PCIE_STATE_UP
};
-BRCMF_FW_NVRAM_DEF(43602, "brcmfmac43602-pcie.bin", "brcmfmac43602-pcie.txt");
-BRCMF_FW_NVRAM_DEF(4350, "brcmfmac4350-pcie.bin", "brcmfmac4350-pcie.txt");
-BRCMF_FW_NVRAM_DEF(4350C, "brcmfmac4350c2-pcie.bin", "brcmfmac4350c2-pcie.txt");
-BRCMF_FW_NVRAM_DEF(4356, "brcmfmac4356-pcie.bin", "brcmfmac4356-pcie.txt");
-BRCMF_FW_NVRAM_DEF(43570, "brcmfmac43570-pcie.bin", "brcmfmac43570-pcie.txt");
-BRCMF_FW_NVRAM_DEF(4358, "brcmfmac4358-pcie.bin", "brcmfmac4358-pcie.txt");
-BRCMF_FW_NVRAM_DEF(4359, "brcmfmac4359-pcie.bin", "brcmfmac4359-pcie.txt");
-BRCMF_FW_NVRAM_DEF(4365B, "brcmfmac4365b-pcie.bin", "brcmfmac4365b-pcie.txt");
-BRCMF_FW_NVRAM_DEF(4365C, "brcmfmac4365c-pcie.bin", "brcmfmac4365c-pcie.txt");
-BRCMF_FW_NVRAM_DEF(4366B, "brcmfmac4366b-pcie.bin", "brcmfmac4366b-pcie.txt");
-BRCMF_FW_NVRAM_DEF(4366C, "brcmfmac4366c-pcie.bin", "brcmfmac4366c-pcie.txt");
-BRCMF_FW_NVRAM_DEF(4371, "brcmfmac4371-pcie.bin", "brcmfmac4371-pcie.txt");
+BRCMF_FW_DEF(43602, "brcmfmac43602-pcie");
+BRCMF_FW_DEF(4350, "brcmfmac4350-pcie");
+BRCMF_FW_DEF(4350C, "brcmfmac4350c2-pcie");
+BRCMF_FW_DEF(4356, "brcmfmac4356-pcie");
+BRCMF_FW_DEF(43570, "brcmfmac43570-pcie");
+BRCMF_FW_DEF(4358, "brcmfmac4358-pcie");
+BRCMF_FW_DEF(4359, "brcmfmac4359-pcie");
+BRCMF_FW_DEF(4365B, "brcmfmac4365b-pcie");
+BRCMF_FW_DEF(4365C, "brcmfmac4365c-pcie");
+BRCMF_FW_DEF(4366B, "brcmfmac4366b-pcie");
+BRCMF_FW_DEF(4366C, "brcmfmac4366c-pcie");
+BRCMF_FW_DEF(4371, "brcmfmac4371-pcie");
static struct brcmf_firmware_mapping brcmf_pcie_fwnames[] = {
- BRCMF_FW_NVRAM_ENTRY(BRCM_CC_43602_CHIP_ID, 0xFFFFFFFF, 43602),
- BRCMF_FW_NVRAM_ENTRY(BRCM_CC_43465_CHIP_ID, 0xFFFFFFF0, 4366C),
- BRCMF_FW_NVRAM_ENTRY(BRCM_CC_4350_CHIP_ID, 0x000000FF, 4350C),
- BRCMF_FW_NVRAM_ENTRY(BRCM_CC_4350_CHIP_ID, 0xFFFFFF00, 4350),
- BRCMF_FW_NVRAM_ENTRY(BRCM_CC_43525_CHIP_ID, 0xFFFFFFF0, 4365C),
- BRCMF_FW_NVRAM_ENTRY(BRCM_CC_4356_CHIP_ID, 0xFFFFFFFF, 4356),
- BRCMF_FW_NVRAM_ENTRY(BRCM_CC_43567_CHIP_ID, 0xFFFFFFFF, 43570),
- BRCMF_FW_NVRAM_ENTRY(BRCM_CC_43569_CHIP_ID, 0xFFFFFFFF, 43570),
- BRCMF_FW_NVRAM_ENTRY(BRCM_CC_43570_CHIP_ID, 0xFFFFFFFF, 43570),
- BRCMF_FW_NVRAM_ENTRY(BRCM_CC_4358_CHIP_ID, 0xFFFFFFFF, 4358),
- BRCMF_FW_NVRAM_ENTRY(BRCM_CC_4359_CHIP_ID, 0xFFFFFFFF, 4359),
- BRCMF_FW_NVRAM_ENTRY(BRCM_CC_4365_CHIP_ID, 0x0000000F, 4365B),
- BRCMF_FW_NVRAM_ENTRY(BRCM_CC_4365_CHIP_ID, 0xFFFFFFF0, 4365C),
- BRCMF_FW_NVRAM_ENTRY(BRCM_CC_4366_CHIP_ID, 0x0000000F, 4366B),
- BRCMF_FW_NVRAM_ENTRY(BRCM_CC_4366_CHIP_ID, 0xFFFFFFF0, 4366C),
- BRCMF_FW_NVRAM_ENTRY(BRCM_CC_4371_CHIP_ID, 0xFFFFFFFF, 4371),
+ BRCMF_FW_ENTRY(BRCM_CC_43602_CHIP_ID, 0xFFFFFFFF, 43602),
+ BRCMF_FW_ENTRY(BRCM_CC_43465_CHIP_ID, 0xFFFFFFF0, 4366C),
+ BRCMF_FW_ENTRY(BRCM_CC_4350_CHIP_ID, 0x000000FF, 4350C),
+ BRCMF_FW_ENTRY(BRCM_CC_4350_CHIP_ID, 0xFFFFFF00, 4350),
+ BRCMF_FW_ENTRY(BRCM_CC_43525_CHIP_ID, 0xFFFFFFF0, 4365C),
+ BRCMF_FW_ENTRY(BRCM_CC_4356_CHIP_ID, 0xFFFFFFFF, 4356),
+ BRCMF_FW_ENTRY(BRCM_CC_43567_CHIP_ID, 0xFFFFFFFF, 43570),
+ BRCMF_FW_ENTRY(BRCM_CC_43569_CHIP_ID, 0xFFFFFFFF, 43570),
+ BRCMF_FW_ENTRY(BRCM_CC_43570_CHIP_ID, 0xFFFFFFFF, 43570),
+ BRCMF_FW_ENTRY(BRCM_CC_4358_CHIP_ID, 0xFFFFFFFF, 4358),
+ BRCMF_FW_ENTRY(BRCM_CC_4359_CHIP_ID, 0xFFFFFFFF, 4359),
+ BRCMF_FW_ENTRY(BRCM_CC_4365_CHIP_ID, 0x0000000F, 4365B),
+ BRCMF_FW_ENTRY(BRCM_CC_4365_CHIP_ID, 0xFFFFFFF0, 4365C),
+ BRCMF_FW_ENTRY(BRCM_CC_4366_CHIP_ID, 0x0000000F, 4366B),
+ BRCMF_FW_ENTRY(BRCM_CC_4366_CHIP_ID, 0xFFFFFFF0, 4366C),
+ BRCMF_FW_ENTRY(BRCM_CC_4371_CHIP_ID, 0xFFFFFFFF, 4371),
};
#define BRCMF_PCIE_FW_UP_TIMEOUT 2000 /* msec */
@@ -1350,23 +1350,24 @@ static int brcmf_pcie_get_memdump(struct device *dev, void *data, size_t len)
return 0;
}
-static int brcmf_pcie_get_fwname(struct device *dev, u32 chip, u32 chiprev,
- u8 *fw_name)
+static
+int brcmf_pcie_get_fwname(struct device *dev, const char *ext, u8 *fw_name)
{
struct brcmf_bus *bus_if = dev_get_drvdata(dev);
- struct brcmf_pciedev *buspub = bus_if->bus_priv.pcie;
- struct brcmf_pciedev_info *devinfo = buspub->devinfo;
- int ret = 0;
-
- if (devinfo->fw_name[0] != '\0')
- strlcpy(fw_name, devinfo->fw_name, BRCMF_FW_NAME_LEN);
- else
- ret = brcmf_fw_map_chip_to_name(chip, chiprev,
- brcmf_pcie_fwnames,
- ARRAY_SIZE(brcmf_pcie_fwnames),
- fw_name, NULL);
-
- return ret;
+ struct brcmf_fw_request *fwreq;
+ struct brcmf_fw_name fwnames[] = {
+ { ext, fw_name },
+ };
+
+ fwreq = brcmf_fw_alloc_request(bus_if->chip, bus_if->chiprev,
+ brcmf_pcie_fwnames,
+ ARRAY_SIZE(brcmf_pcie_fwnames),
+ fwnames, ARRAY_SIZE(fwnames));
+ if (!fwreq)
+ return -ENOMEM;
+
+ kfree(fwreq);
+ return 0;
}
static const struct brcmf_bus_ops brcmf_pcie_bus_ops = {
@@ -1651,15 +1652,19 @@ static const struct brcmf_buscore_ops brcmf_pcie_buscore_ops = {
.write32 = brcmf_pcie_buscore_write32,
};
+#define BRCMF_PCIE_FW_CODE 0
+#define BRCMF_PCIE_FW_NVRAM 1
+
static void brcmf_pcie_setup(struct device *dev, int ret,
- const struct firmware *fw,
- void *nvram, u32 nvram_len)
+ struct brcmf_fw_request *fwreq)
{
+ const struct firmware *fw;
+ void *nvram;
struct brcmf_bus *bus;
struct brcmf_pciedev *pcie_bus_dev;
struct brcmf_pciedev_info *devinfo;
struct brcmf_commonring **flowrings;
- u32 i;
+ u32 i, nvram_len;
/* check firmware loading result */
if (ret)
@@ -1670,6 +1675,11 @@ static void brcmf_pcie_setup(struct device *dev, int ret,
devinfo = pcie_bus_dev->devinfo;
brcmf_pcie_attach(devinfo);
+ fw = fwreq->items[BRCMF_PCIE_FW_CODE].binary;
+ nvram = fwreq->items[BRCMF_PCIE_FW_NVRAM].nv_data.data;
+ nvram_len = fwreq->items[BRCMF_PCIE_FW_NVRAM].nv_data.len;
+ kfree(fwreq);
+
/* Some of the firmwares have the size of the memory of the device
* defined inside the firmware. This is because part of the memory in
* the device is shared and the devision is determined by FW. Parse
@@ -1726,20 +1736,41 @@ fail:
device_release_driver(dev);
}
+static struct brcmf_fw_request *
+brcmf_pcie_prepare_fw_request(struct brcmf_pciedev_info *devinfo)
+{
+ struct brcmf_fw_request *fwreq;
+ struct brcmf_fw_name fwnames[] = {
+ { ".bin", devinfo->fw_name },
+ { ".txt", devinfo->nvram_name },
+ };
+
+ fwreq = brcmf_fw_alloc_request(devinfo->ci->chip, devinfo->ci->chiprev,
+ brcmf_pcie_fwnames,
+ ARRAY_SIZE(brcmf_pcie_fwnames),
+ fwnames, ARRAY_SIZE(fwnames));
+ if (!fwreq)
+ return NULL;
+
+ fwreq->items[BRCMF_PCIE_FW_CODE].type = BRCMF_FW_TYPE_BINARY;
+ fwreq->items[BRCMF_PCIE_FW_NVRAM].type = BRCMF_FW_TYPE_NVRAM;
+ fwreq->items[BRCMF_PCIE_FW_NVRAM].flags = BRCMF_FW_REQF_OPTIONAL;
+ fwreq->domain_nr = pci_domain_nr(devinfo->pdev->bus);
+ fwreq->bus_nr = devinfo->pdev->bus->number;
+
+ return fwreq;
+}
+
static int
brcmf_pcie_probe(struct pci_dev *pdev, const struct pci_device_id *id)
{
int ret;
+ struct brcmf_fw_request *fwreq;
struct brcmf_pciedev_info *devinfo;
struct brcmf_pciedev *pcie_bus_dev;
struct brcmf_bus *bus;
- u16 domain_nr;
- u16 bus_nr;
- domain_nr = pci_domain_nr(pdev->bus) + 1;
- bus_nr = pdev->bus->number;
- brcmf_dbg(PCIE, "Enter %x:%x (%d/%d)\n", pdev->vendor, pdev->device,
- domain_nr, bus_nr);
+ brcmf_dbg(PCIE, "Enter %x:%x\n", pdev->vendor, pdev->device);
ret = -ENOMEM;
devinfo = kzalloc(sizeof(*devinfo), GFP_KERNEL);
@@ -1793,19 +1824,19 @@ brcmf_pcie_probe(struct pci_dev *pdev, const struct pci_device_id *id)
bus->wowl_supported = pci_pme_capable(pdev, PCI_D3hot);
dev_set_drvdata(&pdev->dev, bus);
- ret = brcmf_fw_map_chip_to_name(devinfo->ci->chip, devinfo->ci->chiprev,
- brcmf_pcie_fwnames,
- ARRAY_SIZE(brcmf_pcie_fwnames),
- devinfo->fw_name, devinfo->nvram_name);
- if (ret)
+ fwreq = brcmf_pcie_prepare_fw_request(devinfo);
+ if (!fwreq) {
+ ret = -ENOMEM;
goto fail_bus;
+ }
+
+ ret = brcmf_fw_get_firmwares(bus->dev, fwreq, brcmf_pcie_setup);
+ if (ret < 0) {
+ kfree(fwreq);
+ goto fail_bus;
+ }
+ return 0;
- ret = brcmf_fw_get_firmwares_pcie(bus->dev, BRCMF_FW_REQUEST_NVRAM |
- BRCMF_FW_REQ_NV_OPTIONAL,
- devinfo->fw_name, devinfo->nvram_name,
- brcmf_pcie_setup, domain_nr, bus_nr);
- if (ret == 0)
- return 0;
fail_bus:
kfree(bus->msgbuf);
kfree(bus);
diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/proto.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/proto.c
index d26ff219ef66..c5ff551ec659 100644
--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/proto.c
+++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/proto.c
@@ -54,7 +54,8 @@ int brcmf_proto_attach(struct brcmf_pub *drvr)
if (!proto->tx_queue_data || (proto->hdrpull == NULL) ||
(proto->query_dcmd == NULL) || (proto->set_dcmd == NULL) ||
(proto->configure_addr_mode == NULL) ||
- (proto->delete_peer == NULL) || (proto->add_tdls_peer == NULL)) {
+ (proto->delete_peer == NULL) || (proto->add_tdls_peer == NULL) ||
+ (proto->debugfs_create == NULL)) {
brcmf_err("Not all proto handlers have been installed\n");
goto fail;
}
diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/proto.h b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/proto.h
index 8a8e08f09ea0..d3c3b9a815ad 100644
--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/proto.h
+++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/proto.h
@@ -48,6 +48,7 @@ struct brcmf_proto {
void (*del_if)(struct brcmf_if *ifp);
void (*reset_if)(struct brcmf_if *ifp);
int (*init_done)(struct brcmf_pub *drvr);
+ void (*debugfs_create)(struct brcmf_pub *drvr);
void *pd;
};
@@ -156,4 +157,10 @@ brcmf_proto_init_done(struct brcmf_pub *drvr)
return drvr->proto->init_done(drvr);
}
+static inline void
+brcmf_proto_debugfs_create(struct brcmf_pub *drvr)
+{
+ drvr->proto->debugfs_create(drvr);
+}
+
#endif /* BRCMFMAC_PROTO_H */
diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/sdio.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/sdio.c
index 4a6459a429ec..1037df7297bb 100644
--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/sdio.c
+++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/sdio.c
@@ -600,47 +600,44 @@ static const struct sdiod_drive_str sdiod_drvstr_tab2_3v3[] = {
{4, 0x1}
};
-BRCMF_FW_NVRAM_DEF(43143, "brcmfmac43143-sdio.bin", "brcmfmac43143-sdio.txt");
-BRCMF_FW_NVRAM_DEF(43241B0, "brcmfmac43241b0-sdio.bin",
- "brcmfmac43241b0-sdio.txt");
-BRCMF_FW_NVRAM_DEF(43241B4, "brcmfmac43241b4-sdio.bin",
- "brcmfmac43241b4-sdio.txt");
-BRCMF_FW_NVRAM_DEF(43241B5, "brcmfmac43241b5-sdio.bin",
- "brcmfmac43241b5-sdio.txt");
-BRCMF_FW_NVRAM_DEF(4329, "brcmfmac4329-sdio.bin", "brcmfmac4329-sdio.txt");
-BRCMF_FW_NVRAM_DEF(4330, "brcmfmac4330-sdio.bin", "brcmfmac4330-sdio.txt");
-BRCMF_FW_NVRAM_DEF(4334, "brcmfmac4334-sdio.bin", "brcmfmac4334-sdio.txt");
-BRCMF_FW_NVRAM_DEF(43340, "brcmfmac43340-sdio.bin", "brcmfmac43340-sdio.txt");
-BRCMF_FW_NVRAM_DEF(4335, "brcmfmac4335-sdio.bin", "brcmfmac4335-sdio.txt");
-BRCMF_FW_NVRAM_DEF(43362, "brcmfmac43362-sdio.bin", "brcmfmac43362-sdio.txt");
-BRCMF_FW_NVRAM_DEF(4339, "brcmfmac4339-sdio.bin", "brcmfmac4339-sdio.txt");
-BRCMF_FW_NVRAM_DEF(43430A0, "brcmfmac43430a0-sdio.bin", "brcmfmac43430a0-sdio.txt");
+BRCMF_FW_DEF(43143, "brcmfmac43143-sdio");
+BRCMF_FW_DEF(43241B0, "brcmfmac43241b0-sdio");
+BRCMF_FW_DEF(43241B4, "brcmfmac43241b4-sdio");
+BRCMF_FW_DEF(43241B5, "brcmfmac43241b5-sdio");
+BRCMF_FW_DEF(4329, "brcmfmac4329-sdio");
+BRCMF_FW_DEF(4330, "brcmfmac4330-sdio");
+BRCMF_FW_DEF(4334, "brcmfmac4334-sdio");
+BRCMF_FW_DEF(43340, "brcmfmac43340-sdio");
+BRCMF_FW_DEF(4335, "brcmfmac4335-sdio");
+BRCMF_FW_DEF(43362, "brcmfmac43362-sdio");
+BRCMF_FW_DEF(4339, "brcmfmac4339-sdio");
+BRCMF_FW_DEF(43430A0, "brcmfmac43430a0-sdio");
/* Note the names are not postfixed with a1 for backward compatibility */
-BRCMF_FW_NVRAM_DEF(43430A1, "brcmfmac43430-sdio.bin", "brcmfmac43430-sdio.txt");
-BRCMF_FW_NVRAM_DEF(43455, "brcmfmac43455-sdio.bin", "brcmfmac43455-sdio.txt");
-BRCMF_FW_NVRAM_DEF(4354, "brcmfmac4354-sdio.bin", "brcmfmac4354-sdio.txt");
-BRCMF_FW_NVRAM_DEF(4356, "brcmfmac4356-sdio.bin", "brcmfmac4356-sdio.txt");
-BRCMF_FW_NVRAM_DEF(4373, "brcmfmac4373-sdio.bin", "brcmfmac4373-sdio.txt");
+BRCMF_FW_DEF(43430A1, "brcmfmac43430-sdio");
+BRCMF_FW_DEF(43455, "brcmfmac43455-sdio");
+BRCMF_FW_DEF(4354, "brcmfmac4354-sdio");
+BRCMF_FW_DEF(4356, "brcmfmac4356-sdio");
+BRCMF_FW_DEF(4373, "brcmfmac4373-sdio");
static struct brcmf_firmware_mapping brcmf_sdio_fwnames[] = {
- BRCMF_FW_NVRAM_ENTRY(BRCM_CC_43143_CHIP_ID, 0xFFFFFFFF, 43143),
- BRCMF_FW_NVRAM_ENTRY(BRCM_CC_43241_CHIP_ID, 0x0000001F, 43241B0),
- BRCMF_FW_NVRAM_ENTRY(BRCM_CC_43241_CHIP_ID, 0x00000020, 43241B4),
- BRCMF_FW_NVRAM_ENTRY(BRCM_CC_43241_CHIP_ID, 0xFFFFFFC0, 43241B5),
- BRCMF_FW_NVRAM_ENTRY(BRCM_CC_4329_CHIP_ID, 0xFFFFFFFF, 4329),
- BRCMF_FW_NVRAM_ENTRY(BRCM_CC_4330_CHIP_ID, 0xFFFFFFFF, 4330),
- BRCMF_FW_NVRAM_ENTRY(BRCM_CC_4334_CHIP_ID, 0xFFFFFFFF, 4334),
- BRCMF_FW_NVRAM_ENTRY(BRCM_CC_43340_CHIP_ID, 0xFFFFFFFF, 43340),
- BRCMF_FW_NVRAM_ENTRY(BRCM_CC_43341_CHIP_ID, 0xFFFFFFFF, 43340),
- BRCMF_FW_NVRAM_ENTRY(BRCM_CC_4335_CHIP_ID, 0xFFFFFFFF, 4335),
- BRCMF_FW_NVRAM_ENTRY(BRCM_CC_43362_CHIP_ID, 0xFFFFFFFE, 43362),
- BRCMF_FW_NVRAM_ENTRY(BRCM_CC_4339_CHIP_ID, 0xFFFFFFFF, 4339),
- BRCMF_FW_NVRAM_ENTRY(BRCM_CC_43430_CHIP_ID, 0x00000001, 43430A0),
- BRCMF_FW_NVRAM_ENTRY(BRCM_CC_43430_CHIP_ID, 0xFFFFFFFE, 43430A1),
- BRCMF_FW_NVRAM_ENTRY(BRCM_CC_4345_CHIP_ID, 0xFFFFFFC0, 43455),
- BRCMF_FW_NVRAM_ENTRY(BRCM_CC_4354_CHIP_ID, 0xFFFFFFFF, 4354),
- BRCMF_FW_NVRAM_ENTRY(BRCM_CC_4356_CHIP_ID, 0xFFFFFFFF, 4356),
- BRCMF_FW_NVRAM_ENTRY(CY_CC_4373_CHIP_ID, 0xFFFFFFFF, 4373)
+ BRCMF_FW_ENTRY(BRCM_CC_43143_CHIP_ID, 0xFFFFFFFF, 43143),
+ BRCMF_FW_ENTRY(BRCM_CC_43241_CHIP_ID, 0x0000001F, 43241B0),
+ BRCMF_FW_ENTRY(BRCM_CC_43241_CHIP_ID, 0x00000020, 43241B4),
+ BRCMF_FW_ENTRY(BRCM_CC_43241_CHIP_ID, 0xFFFFFFC0, 43241B5),
+ BRCMF_FW_ENTRY(BRCM_CC_4329_CHIP_ID, 0xFFFFFFFF, 4329),
+ BRCMF_FW_ENTRY(BRCM_CC_4330_CHIP_ID, 0xFFFFFFFF, 4330),
+ BRCMF_FW_ENTRY(BRCM_CC_4334_CHIP_ID, 0xFFFFFFFF, 4334),
+ BRCMF_FW_ENTRY(BRCM_CC_43340_CHIP_ID, 0xFFFFFFFF, 43340),
+ BRCMF_FW_ENTRY(BRCM_CC_43341_CHIP_ID, 0xFFFFFFFF, 43340),
+ BRCMF_FW_ENTRY(BRCM_CC_4335_CHIP_ID, 0xFFFFFFFF, 4335),
+ BRCMF_FW_ENTRY(BRCM_CC_43362_CHIP_ID, 0xFFFFFFFE, 43362),
+ BRCMF_FW_ENTRY(BRCM_CC_4339_CHIP_ID, 0xFFFFFFFF, 4339),
+ BRCMF_FW_ENTRY(BRCM_CC_43430_CHIP_ID, 0x00000001, 43430A0),
+ BRCMF_FW_ENTRY(BRCM_CC_43430_CHIP_ID, 0xFFFFFFFE, 43430A1),
+ BRCMF_FW_ENTRY(BRCM_CC_4345_CHIP_ID, 0xFFFFFFC0, 43455),
+ BRCMF_FW_ENTRY(BRCM_CC_4354_CHIP_ID, 0xFFFFFFFF, 4354),
+ BRCMF_FW_ENTRY(BRCM_CC_4356_CHIP_ID, 0xFFFFFFFF, 4356),
+ BRCMF_FW_ENTRY(CY_CC_4373_CHIP_ID, 0xFFFFFFFF, 4373)
};
static void pkt_align(struct sk_buff *p, int len, int align)
@@ -4003,22 +4000,24 @@ brcmf_sdio_watchdog(struct timer_list *t)
}
}
-static int brcmf_sdio_get_fwname(struct device *dev, u32 chip, u32 chiprev,
- u8 *fw_name)
+static
+int brcmf_sdio_get_fwname(struct device *dev, const char *ext, u8 *fw_name)
{
struct brcmf_bus *bus_if = dev_get_drvdata(dev);
- struct brcmf_sdio_dev *sdiodev = bus_if->bus_priv.sdio;
- int ret = 0;
-
- if (sdiodev->fw_name[0] != '\0')
- strlcpy(fw_name, sdiodev->fw_name, BRCMF_FW_NAME_LEN);
- else
- ret = brcmf_fw_map_chip_to_name(chip, chiprev,
- brcmf_sdio_fwnames,
- ARRAY_SIZE(brcmf_sdio_fwnames),
- fw_name, NULL);
+ struct brcmf_fw_request *fwreq;
+ struct brcmf_fw_name fwnames[] = {
+ { ext, fw_name },
+ };
+
+ fwreq = brcmf_fw_alloc_request(bus_if->chip, bus_if->chiprev,
+ brcmf_sdio_fwnames,
+ ARRAY_SIZE(brcmf_sdio_fwnames),
+ fwnames, ARRAY_SIZE(fwnames));
+ if (!fwreq)
+ return -ENOMEM;
- return ret;
+ kfree(fwreq);
+ return 0;
}
static const struct brcmf_bus_ops brcmf_sdio_bus_ops = {
@@ -4034,14 +4033,19 @@ static const struct brcmf_bus_ops brcmf_sdio_bus_ops = {
.get_fwname = brcmf_sdio_get_fwname,
};
+#define BRCMF_SDIO_FW_CODE 0
+#define BRCMF_SDIO_FW_NVRAM 1
+
static void brcmf_sdio_firmware_callback(struct device *dev, int err,
- const struct firmware *code,
- void *nvram, u32 nvram_len)
+ struct brcmf_fw_request *fwreq)
{
struct brcmf_bus *bus_if = dev_get_drvdata(dev);
struct brcmf_sdio_dev *sdiod = bus_if->bus_priv.sdio;
struct brcmf_sdio *bus = sdiod->bus;
struct brcmf_core *core = bus->sdio_core;
+ const struct firmware *code;
+ void *nvram;
+ u32 nvram_len;
u8 saveclk;
brcmf_dbg(TRACE, "Enter: dev=%s, err=%d\n", dev_name(dev), err);
@@ -4049,6 +4053,11 @@ static void brcmf_sdio_firmware_callback(struct device *dev, int err,
if (err)
goto fail;
+ code = fwreq->items[BRCMF_SDIO_FW_CODE].binary;
+ nvram = fwreq->items[BRCMF_SDIO_FW_NVRAM].nv_data.data;
+ nvram_len = fwreq->items[BRCMF_SDIO_FW_NVRAM].nv_data.len;
+ kfree(fwreq);
+
/* try to download image and nvram to the dongle */
bus->alp_only = true;
err = brcmf_sdio_download_firmware(bus, code, nvram, nvram_len);
@@ -4148,11 +4157,34 @@ fail:
device_release_driver(dev);
}
+static struct brcmf_fw_request *
+brcmf_sdio_prepare_fw_request(struct brcmf_sdio *bus)
+{
+ struct brcmf_fw_request *fwreq;
+ struct brcmf_fw_name fwnames[] = {
+ { ".bin", bus->sdiodev->fw_name },
+ { ".txt", bus->sdiodev->nvram_name },
+ };
+
+ fwreq = brcmf_fw_alloc_request(bus->ci->chip, bus->ci->chiprev,
+ brcmf_sdio_fwnames,
+ ARRAY_SIZE(brcmf_sdio_fwnames),
+ fwnames, ARRAY_SIZE(fwnames));
+ if (!fwreq)
+ return NULL;
+
+ fwreq->items[BRCMF_SDIO_FW_CODE].type = BRCMF_FW_TYPE_BINARY;
+ fwreq->items[BRCMF_SDIO_FW_NVRAM].type = BRCMF_FW_TYPE_NVRAM;
+
+ return fwreq;
+}
+
struct brcmf_sdio *brcmf_sdio_probe(struct brcmf_sdio_dev *sdiodev)
{
int ret;
struct brcmf_sdio *bus;
struct workqueue_struct *wq;
+ struct brcmf_fw_request *fwreq;
brcmf_dbg(TRACE, "Enter\n");
@@ -4235,18 +4267,17 @@ struct brcmf_sdio *brcmf_sdio_probe(struct brcmf_sdio_dev *sdiodev)
brcmf_dbg(INFO, "completed!!\n");
- ret = brcmf_fw_map_chip_to_name(bus->ci->chip, bus->ci->chiprev,
- brcmf_sdio_fwnames,
- ARRAY_SIZE(brcmf_sdio_fwnames),
- sdiodev->fw_name, sdiodev->nvram_name);
- if (ret)
+ fwreq = brcmf_sdio_prepare_fw_request(bus);
+ if (!fwreq) {
+ ret = -ENOMEM;
goto fail;
+ }
- ret = brcmf_fw_get_firmwares(sdiodev->dev, BRCMF_FW_REQUEST_NVRAM,
- sdiodev->fw_name, sdiodev->nvram_name,
+ ret = brcmf_fw_get_firmwares(sdiodev->dev, fwreq,
brcmf_sdio_firmware_callback);
if (ret != 0) {
brcmf_err("async firmware request failed: %d\n", ret);
+ kfree(fwreq);
goto fail;
}
diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/usb.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/usb.c
index 41642dda40fd..a0873adcc01c 100644
--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/usb.c
+++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/usb.c
@@ -46,11 +46,11 @@
#define BRCMF_USB_CBCTL_READ 1
#define BRCMF_USB_MAX_PKT_SIZE 1600
-BRCMF_FW_DEF(43143, "brcmfmac43143.bin");
-BRCMF_FW_DEF(43236B, "brcmfmac43236b.bin");
-BRCMF_FW_DEF(43242A, "brcmfmac43242a.bin");
-BRCMF_FW_DEF(43569, "brcmfmac43569.bin");
-BRCMF_FW_DEF(4373, "brcmfmac4373.bin");
+BRCMF_FW_DEF(43143, "brcmfmac43143");
+BRCMF_FW_DEF(43236B, "brcmfmac43236b");
+BRCMF_FW_DEF(43242A, "brcmfmac43242a");
+BRCMF_FW_DEF(43569, "brcmfmac43569");
+BRCMF_FW_DEF(4373, "brcmfmac4373");
static struct brcmf_firmware_mapping brcmf_usb_fwnames[] = {
BRCMF_FW_ENTRY(BRCM_CC_43143_CHIP_ID, 0xFFFFFFFF, 43143),
@@ -1128,21 +1128,24 @@ static void brcmf_usb_wowl_config(struct device *dev, bool enabled)
device_set_wakeup_enable(devinfo->dev, false);
}
-static int brcmf_usb_get_fwname(struct device *dev, u32 chip, u32 chiprev,
- u8 *fw_name)
+static
+int brcmf_usb_get_fwname(struct device *dev, const char *ext, u8 *fw_name)
{
- struct brcmf_usbdev_info *devinfo = brcmf_usb_get_businfo(dev);
- int ret = 0;
-
- if (devinfo->fw_name[0] != '\0')
- strlcpy(fw_name, devinfo->fw_name, BRCMF_FW_NAME_LEN);
- else
- ret = brcmf_fw_map_chip_to_name(chip, chiprev,
- brcmf_usb_fwnames,
- ARRAY_SIZE(brcmf_usb_fwnames),
- fw_name, NULL);
+ struct brcmf_bus *bus = dev_get_drvdata(dev);
+ struct brcmf_fw_request *fwreq;
+ struct brcmf_fw_name fwnames[] = {
+ { ext, fw_name },
+ };
+
+ fwreq = brcmf_fw_alloc_request(bus->chip, bus->chiprev,
+ brcmf_usb_fwnames,
+ ARRAY_SIZE(brcmf_usb_fwnames),
+ fwnames, ARRAY_SIZE(fwnames));
+ if (!fwreq)
+ return -ENOMEM;
- return ret;
+ kfree(fwreq);
+ return 0;
}
static const struct brcmf_bus_ops brcmf_usb_bus_ops = {
@@ -1155,18 +1158,23 @@ static const struct brcmf_bus_ops brcmf_usb_bus_ops = {
.get_fwname = brcmf_usb_get_fwname,
};
+#define BRCMF_USB_FW_CODE 0
+
static void brcmf_usb_probe_phase2(struct device *dev, int ret,
- const struct firmware *fw,
- void *nvram, u32 nvlen)
+ struct brcmf_fw_request *fwreq)
{
struct brcmf_bus *bus = dev_get_drvdata(dev);
struct brcmf_usbdev_info *devinfo = bus->bus_priv.usb->devinfo;
+ const struct firmware *fw;
if (ret)
goto error;
brcmf_dbg(USB, "Start fw downloading\n");
+ fw = fwreq->items[BRCMF_USB_FW_CODE].binary;
+ kfree(fwreq);
+
ret = check_file(fw->data);
if (ret < 0) {
brcmf_err("invalid firmware\n");
@@ -1195,11 +1203,33 @@ error:
device_release_driver(dev);
}
+static struct brcmf_fw_request *
+brcmf_usb_prepare_fw_request(struct brcmf_usbdev_info *devinfo)
+{
+ struct brcmf_fw_request *fwreq;
+ struct brcmf_fw_name fwnames[] = {
+ { ".bin", devinfo->fw_name },
+ };
+
+ fwreq = brcmf_fw_alloc_request(devinfo->bus_pub.devid,
+ devinfo->bus_pub.chiprev,
+ brcmf_usb_fwnames,
+ ARRAY_SIZE(brcmf_usb_fwnames),
+ fwnames, ARRAY_SIZE(fwnames));
+ if (!fwreq)
+ return NULL;
+
+ fwreq->items[BRCMF_USB_FW_CODE].type = BRCMF_FW_TYPE_BINARY;
+
+ return fwreq;
+}
+
static int brcmf_usb_probe_cb(struct brcmf_usbdev_info *devinfo)
{
struct brcmf_bus *bus = NULL;
struct brcmf_usbdev *bus_pub = NULL;
struct device *dev = devinfo->dev;
+ struct brcmf_fw_request *fwreq;
int ret;
brcmf_dbg(USB, "Enter\n");
@@ -1243,18 +1273,17 @@ static int brcmf_usb_probe_cb(struct brcmf_usbdev_info *devinfo)
bus->chip = bus_pub->devid;
bus->chiprev = bus_pub->chiprev;
- ret = brcmf_fw_map_chip_to_name(bus_pub->devid, bus_pub->chiprev,
- brcmf_usb_fwnames,
- ARRAY_SIZE(brcmf_usb_fwnames),
- devinfo->fw_name, NULL);
- if (ret)
+ fwreq = brcmf_usb_prepare_fw_request(devinfo);
+ if (!fwreq) {
+ ret = -ENOMEM;
goto fail;
+ }
/* request firmware here */
- ret = brcmf_fw_get_firmwares(dev, 0, devinfo->fw_name, NULL,
- brcmf_usb_probe_phase2);
+ ret = brcmf_fw_get_firmwares(dev, fwreq, brcmf_usb_probe_phase2);
if (ret) {
brcmf_err("firmware request failed: %d\n", ret);
+ kfree(fwreq);
goto fail;
}
@@ -1447,11 +1476,20 @@ static int brcmf_usb_reset_resume(struct usb_interface *intf)
{
struct usb_device *usb = interface_to_usbdev(intf);
struct brcmf_usbdev_info *devinfo = brcmf_usb_get_businfo(&usb->dev);
+ struct brcmf_fw_request *fwreq;
+ int ret;
brcmf_dbg(USB, "Enter\n");
- return brcmf_fw_get_firmwares(&usb->dev, 0, devinfo->fw_name, NULL,
- brcmf_usb_probe_phase2);
+ fwreq = brcmf_usb_prepare_fw_request(devinfo);
+ if (!fwreq)
+ return -ENOMEM;
+
+ ret = brcmf_fw_get_firmwares(&usb->dev, fwreq, brcmf_usb_probe_phase2);
+ if (ret < 0)
+ kfree(fwreq);
+
+ return ret;
}
#define BRCMF_USB_DEVICE(dev_id) \
diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmsmac/debug.c b/drivers/net/wireless/broadcom/brcm80211/brcmsmac/debug.c
index 7a1fbb2e3a71..2fe1f6863278 100644
--- a/drivers/net/wireless/broadcom/brcm80211/brcmsmac/debug.c
+++ b/drivers/net/wireless/broadcom/brcm80211/brcmsmac/debug.c
@@ -214,7 +214,7 @@ brcms_debugfs_add_entry(struct brcms_pub *drvr, const char *fn,
entry->read = read_fn;
entry->drvr = drvr;
- dentry = debugfs_create_file(fn, S_IRUGO, dentry, entry,
+ dentry = debugfs_create_file(fn, 0444, dentry, entry,
&brcms_debugfs_def_ops);
return PTR_ERR_OR_ZERO(dentry);
diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmsmac/mac80211_if.c b/drivers/net/wireless/broadcom/brcm80211/brcmsmac/mac80211_if.c
index ddfdfe177e24..ecc89e718b9c 100644
--- a/drivers/net/wireless/broadcom/brcm80211/brcmsmac/mac80211_if.c
+++ b/drivers/net/wireless/broadcom/brcm80211/brcmsmac/mac80211_if.c
@@ -108,7 +108,7 @@ MODULE_DEVICE_TABLE(bcma, brcms_coreid_table);
* flags are specified by the BRCM_DL_* macros in
* drivers/net/wireless/brcm80211/include/defs.h.
*/
-module_param_named(debug, brcm_msg_level, uint, S_IRUGO | S_IWUSR);
+module_param_named(debug, brcm_msg_level, uint, 0644);
#endif
static struct ieee80211_channel brcms_2ghz_chantable[] = {
@@ -1563,7 +1563,7 @@ void brcms_free_timer(struct brcms_timer *t)
}
/*
- * precondition: perimeter lock has been acquired
+ * precondition: no locking required
*/
int brcms_ucode_init_buf(struct brcms_info *wl, void **pbuf, u32 idx)
{
@@ -1578,7 +1578,7 @@ int brcms_ucode_init_buf(struct brcms_info *wl, void **pbuf, u32 idx)
if (le32_to_cpu(hdr->idx) == idx) {
pdata = wl->fw.fw_bin[i]->data +
le32_to_cpu(hdr->offset);
- *pbuf = kmemdup(pdata, len, GFP_ATOMIC);
+ *pbuf = kmemdup(pdata, len, GFP_KERNEL);
if (*pbuf == NULL)
goto fail;
diff --git a/drivers/net/wireless/cisco/airo.c b/drivers/net/wireless/cisco/airo.c
index 54201c02fdb8..ce0fbf83285f 100644
--- a/drivers/net/wireless/cisco/airo.c
+++ b/drivers/net/wireless/cisco/airo.c
@@ -4519,21 +4519,21 @@ static int setup_proc_entry( struct net_device *dev,
proc_set_user(apriv->proc_entry, proc_kuid, proc_kgid);
/* Setup the StatsDelta */
- entry = proc_create_data("StatsDelta", S_IRUGO & proc_perm,
+ entry = proc_create_data("StatsDelta", 0444 & proc_perm,
apriv->proc_entry, &proc_statsdelta_ops, dev);
if (!entry)
goto fail;
proc_set_user(entry, proc_kuid, proc_kgid);
/* Setup the Stats */
- entry = proc_create_data("Stats", S_IRUGO & proc_perm,
+ entry = proc_create_data("Stats", 0444 & proc_perm,
apriv->proc_entry, &proc_stats_ops, dev);
if (!entry)
goto fail;
proc_set_user(entry, proc_kuid, proc_kgid);
/* Setup the Status */
- entry = proc_create_data("Status", S_IRUGO & proc_perm,
+ entry = proc_create_data("Status", 0444 & proc_perm,
apriv->proc_entry, &proc_status_ops, dev);
if (!entry)
goto fail;
diff --git a/drivers/net/wireless/intel/ipw2x00/ipw2100.c b/drivers/net/wireless/intel/ipw2x00/ipw2100.c
index 19c442cb93e4..236b52423506 100644
--- a/drivers/net/wireless/intel/ipw2x00/ipw2100.c
+++ b/drivers/net/wireless/intel/ipw2x00/ipw2100.c
@@ -3538,7 +3538,7 @@ static ssize_t show_pci(struct device *d, struct device_attribute *attr,
return out - buf;
}
-static DEVICE_ATTR(pci, S_IRUGO, show_pci, NULL);
+static DEVICE_ATTR(pci, 0444, show_pci, NULL);
static ssize_t show_cfg(struct device *d, struct device_attribute *attr,
char *buf)
@@ -3547,7 +3547,7 @@ static ssize_t show_cfg(struct device *d, struct device_attribute *attr,
return sprintf(buf, "0x%08x\n", (int)p->config);
}
-static DEVICE_ATTR(cfg, S_IRUGO, show_cfg, NULL);
+static DEVICE_ATTR(cfg, 0444, show_cfg, NULL);
static ssize_t show_status(struct device *d, struct device_attribute *attr,
char *buf)
@@ -3556,7 +3556,7 @@ static ssize_t show_status(struct device *d, struct device_attribute *attr,
return sprintf(buf, "0x%08x\n", (int)p->status);
}
-static DEVICE_ATTR(status, S_IRUGO, show_status, NULL);
+static DEVICE_ATTR(status, 0444, show_status, NULL);
static ssize_t show_capability(struct device *d, struct device_attribute *attr,
char *buf)
@@ -3565,7 +3565,7 @@ static ssize_t show_capability(struct device *d, struct device_attribute *attr,
return sprintf(buf, "0x%08x\n", (int)p->capability);
}
-static DEVICE_ATTR(capability, S_IRUGO, show_capability, NULL);
+static DEVICE_ATTR(capability, 0444, show_capability, NULL);
#define IPW2100_REG(x) { IPW_ ##x, #x }
static const struct {
@@ -3822,7 +3822,7 @@ static ssize_t show_registers(struct device *d, struct device_attribute *attr,
return out - buf;
}
-static DEVICE_ATTR(registers, S_IRUGO, show_registers, NULL);
+static DEVICE_ATTR(registers, 0444, show_registers, NULL);
static ssize_t show_hardware(struct device *d, struct device_attribute *attr,
char *buf)
@@ -3863,7 +3863,7 @@ static ssize_t show_hardware(struct device *d, struct device_attribute *attr,
return out - buf;
}
-static DEVICE_ATTR(hardware, S_IRUGO, show_hardware, NULL);
+static DEVICE_ATTR(hardware, 0444, show_hardware, NULL);
static ssize_t show_memory(struct device *d, struct device_attribute *attr,
char *buf)
@@ -3957,7 +3957,7 @@ static ssize_t store_memory(struct device *d, struct device_attribute *attr,
return count;
}
-static DEVICE_ATTR(memory, S_IWUSR | S_IRUGO, show_memory, store_memory);
+static DEVICE_ATTR(memory, 0644, show_memory, store_memory);
static ssize_t show_ordinals(struct device *d, struct device_attribute *attr,
char *buf)
@@ -3993,7 +3993,7 @@ static ssize_t show_ordinals(struct device *d, struct device_attribute *attr,
return len;
}
-static DEVICE_ATTR(ordinals, S_IRUGO, show_ordinals, NULL);
+static DEVICE_ATTR(ordinals, 0444, show_ordinals, NULL);
static ssize_t show_stats(struct device *d, struct device_attribute *attr,
char *buf)
@@ -4014,7 +4014,7 @@ static ssize_t show_stats(struct device *d, struct device_attribute *attr,
return out - buf;
}
-static DEVICE_ATTR(stats, S_IRUGO, show_stats, NULL);
+static DEVICE_ATTR(stats, 0444, show_stats, NULL);
static int ipw2100_switch_mode(struct ipw2100_priv *priv, u32 mode)
{
@@ -4112,7 +4112,7 @@ static ssize_t show_internals(struct device *d, struct device_attribute *attr,
return len;
}
-static DEVICE_ATTR(internals, S_IRUGO, show_internals, NULL);
+static DEVICE_ATTR(internals, 0444, show_internals, NULL);
static ssize_t show_bssinfo(struct device *d, struct device_attribute *attr,
char *buf)
@@ -4157,7 +4157,7 @@ static ssize_t show_bssinfo(struct device *d, struct device_attribute *attr,
return out - buf;
}
-static DEVICE_ATTR(bssinfo, S_IRUGO, show_bssinfo, NULL);
+static DEVICE_ATTR(bssinfo, 0444, show_bssinfo, NULL);
#ifdef CONFIG_IPW2100_DEBUG
static ssize_t debug_level_show(struct device_driver *d, char *buf)
@@ -4216,8 +4216,7 @@ static ssize_t store_fatal_error(struct device *d,
return count;
}
-static DEVICE_ATTR(fatal_error, S_IWUSR | S_IRUGO, show_fatal_error,
- store_fatal_error);
+static DEVICE_ATTR(fatal_error, 0644, show_fatal_error, store_fatal_error);
static ssize_t show_scan_age(struct device *d, struct device_attribute *attr,
char *buf)
@@ -4250,7 +4249,7 @@ static ssize_t store_scan_age(struct device *d, struct device_attribute *attr,
return strnlen(buf, count);
}
-static DEVICE_ATTR(scan_age, S_IWUSR | S_IRUGO, show_scan_age, store_scan_age);
+static DEVICE_ATTR(scan_age, 0644, show_scan_age, store_scan_age);
static ssize_t show_rf_kill(struct device *d, struct device_attribute *attr,
char *buf)
@@ -4304,7 +4303,7 @@ static ssize_t store_rf_kill(struct device *d, struct device_attribute *attr,
return count;
}
-static DEVICE_ATTR(rf_kill, S_IWUSR | S_IRUGO, show_rf_kill, store_rf_kill);
+static DEVICE_ATTR(rf_kill, 0644, show_rf_kill, store_rf_kill);
static struct attribute *ipw2100_sysfs_entries[] = {
&dev_attr_hardware.attr,
diff --git a/drivers/net/wireless/intel/ipw2x00/ipw2200.c b/drivers/net/wireless/intel/ipw2x00/ipw2200.c
index 8da87496cb58..87a5e414c2f7 100644
--- a/drivers/net/wireless/intel/ipw2x00/ipw2200.c
+++ b/drivers/net/wireless/intel/ipw2x00/ipw2200.c
@@ -1303,7 +1303,7 @@ static ssize_t show_event_log(struct device *d,
return len;
}
-static DEVICE_ATTR(event_log, S_IRUGO, show_event_log, NULL);
+static DEVICE_ATTR(event_log, 0444, show_event_log, NULL);
static ssize_t show_error(struct device *d,
struct device_attribute *attr, char *buf)
@@ -1351,7 +1351,7 @@ static ssize_t clear_error(struct device *d,
return count;
}
-static DEVICE_ATTR(error, S_IRUGO | S_IWUSR, show_error, clear_error);
+static DEVICE_ATTR(error, 0644, show_error, clear_error);
static ssize_t show_cmd_log(struct device *d,
struct device_attribute *attr, char *buf)
@@ -1378,7 +1378,7 @@ static ssize_t show_cmd_log(struct device *d,
return len;
}
-static DEVICE_ATTR(cmd_log, S_IRUGO, show_cmd_log, NULL);
+static DEVICE_ATTR(cmd_log, 0444, show_cmd_log, NULL);
#ifdef CONFIG_IPW2200_PROMISCUOUS
static void ipw_prom_free(struct ipw_priv *priv);
@@ -1443,8 +1443,7 @@ static ssize_t show_rtap_iface(struct device *d,
}
}
-static DEVICE_ATTR(rtap_iface, S_IWUSR | S_IRUSR, show_rtap_iface,
- store_rtap_iface);
+static DEVICE_ATTR(rtap_iface, 0600, show_rtap_iface, store_rtap_iface);
static ssize_t store_rtap_filter(struct device *d,
struct device_attribute *attr,
@@ -1475,8 +1474,7 @@ static ssize_t show_rtap_filter(struct device *d,
priv->prom_priv ? priv->prom_priv->filter : 0);
}
-static DEVICE_ATTR(rtap_filter, S_IWUSR | S_IRUSR, show_rtap_filter,
- store_rtap_filter);
+static DEVICE_ATTR(rtap_filter, 0600, show_rtap_filter, store_rtap_filter);
#endif
static ssize_t show_scan_age(struct device *d, struct device_attribute *attr,
@@ -1520,7 +1518,7 @@ static ssize_t store_scan_age(struct device *d, struct device_attribute *attr,
return len;
}
-static DEVICE_ATTR(scan_age, S_IWUSR | S_IRUGO, show_scan_age, store_scan_age);
+static DEVICE_ATTR(scan_age, 0644, show_scan_age, store_scan_age);
static ssize_t show_led(struct device *d, struct device_attribute *attr,
char *buf)
@@ -1553,7 +1551,7 @@ static ssize_t store_led(struct device *d, struct device_attribute *attr,
return count;
}
-static DEVICE_ATTR(led, S_IWUSR | S_IRUGO, show_led, store_led);
+static DEVICE_ATTR(led, 0644, show_led, store_led);
static ssize_t show_status(struct device *d,
struct device_attribute *attr, char *buf)
@@ -1562,7 +1560,7 @@ static ssize_t show_status(struct device *d,
return sprintf(buf, "0x%08x\n", (int)p->status);
}
-static DEVICE_ATTR(status, S_IRUGO, show_status, NULL);
+static DEVICE_ATTR(status, 0444, show_status, NULL);
static ssize_t show_cfg(struct device *d, struct device_attribute *attr,
char *buf)
@@ -1571,7 +1569,7 @@ static ssize_t show_cfg(struct device *d, struct device_attribute *attr,
return sprintf(buf, "0x%08x\n", (int)p->config);
}
-static DEVICE_ATTR(cfg, S_IRUGO, show_cfg, NULL);
+static DEVICE_ATTR(cfg, 0444, show_cfg, NULL);
static ssize_t show_nic_type(struct device *d,
struct device_attribute *attr, char *buf)
@@ -1580,7 +1578,7 @@ static ssize_t show_nic_type(struct device *d,
return sprintf(buf, "TYPE: %d\n", priv->nic_type);
}
-static DEVICE_ATTR(nic_type, S_IRUGO, show_nic_type, NULL);
+static DEVICE_ATTR(nic_type, 0444, show_nic_type, NULL);
static ssize_t show_ucode_version(struct device *d,
struct device_attribute *attr, char *buf)
@@ -1594,7 +1592,7 @@ static ssize_t show_ucode_version(struct device *d,
return sprintf(buf, "0x%08x\n", tmp);
}
-static DEVICE_ATTR(ucode_version, S_IWUSR | S_IRUGO, show_ucode_version, NULL);
+static DEVICE_ATTR(ucode_version, 0644, show_ucode_version, NULL);
static ssize_t show_rtc(struct device *d, struct device_attribute *attr,
char *buf)
@@ -1608,7 +1606,7 @@ static ssize_t show_rtc(struct device *d, struct device_attribute *attr,
return sprintf(buf, "0x%08x\n", tmp);
}
-static DEVICE_ATTR(rtc, S_IWUSR | S_IRUGO, show_rtc, NULL);
+static DEVICE_ATTR(rtc, 0644, show_rtc, NULL);
/*
* Add a device attribute to view/control the delay between eeprom
@@ -1630,8 +1628,7 @@ static ssize_t store_eeprom_delay(struct device *d,
return strnlen(buf, count);
}
-static DEVICE_ATTR(eeprom_delay, S_IWUSR | S_IRUGO,
- show_eeprom_delay, store_eeprom_delay);
+static DEVICE_ATTR(eeprom_delay, 0644, show_eeprom_delay, store_eeprom_delay);
static ssize_t show_command_event_reg(struct device *d,
struct device_attribute *attr, char *buf)
@@ -1654,7 +1651,7 @@ static ssize_t store_command_event_reg(struct device *d,
return strnlen(buf, count);
}
-static DEVICE_ATTR(command_event_reg, S_IWUSR | S_IRUGO,
+static DEVICE_ATTR(command_event_reg, 0644,
show_command_event_reg, store_command_event_reg);
static ssize_t show_mem_gpio_reg(struct device *d,
@@ -1678,8 +1675,7 @@ static ssize_t store_mem_gpio_reg(struct device *d,
return strnlen(buf, count);
}
-static DEVICE_ATTR(mem_gpio_reg, S_IWUSR | S_IRUGO,
- show_mem_gpio_reg, store_mem_gpio_reg);
+static DEVICE_ATTR(mem_gpio_reg, 0644, show_mem_gpio_reg, store_mem_gpio_reg);
static ssize_t show_indirect_dword(struct device *d,
struct device_attribute *attr, char *buf)
@@ -1705,7 +1701,7 @@ static ssize_t store_indirect_dword(struct device *d,
return strnlen(buf, count);
}
-static DEVICE_ATTR(indirect_dword, S_IWUSR | S_IRUGO,
+static DEVICE_ATTR(indirect_dword, 0644,
show_indirect_dword, store_indirect_dword);
static ssize_t show_indirect_byte(struct device *d,
@@ -1732,7 +1728,7 @@ static ssize_t store_indirect_byte(struct device *d,
return strnlen(buf, count);
}
-static DEVICE_ATTR(indirect_byte, S_IWUSR | S_IRUGO,
+static DEVICE_ATTR(indirect_byte, 0644,
show_indirect_byte, store_indirect_byte);
static ssize_t show_direct_dword(struct device *d,
@@ -1759,8 +1755,7 @@ static ssize_t store_direct_dword(struct device *d,
return strnlen(buf, count);
}
-static DEVICE_ATTR(direct_dword, S_IWUSR | S_IRUGO,
- show_direct_dword, store_direct_dword);
+static DEVICE_ATTR(direct_dword, 0644, show_direct_dword, store_direct_dword);
static int rf_kill_active(struct ipw_priv *priv)
{
@@ -1831,7 +1826,7 @@ static ssize_t store_rf_kill(struct device *d, struct device_attribute *attr,
return count;
}
-static DEVICE_ATTR(rf_kill, S_IWUSR | S_IRUGO, show_rf_kill, store_rf_kill);
+static DEVICE_ATTR(rf_kill, 0644, show_rf_kill, store_rf_kill);
static ssize_t show_speed_scan(struct device *d, struct device_attribute *attr,
char *buf)
@@ -1884,8 +1879,7 @@ static ssize_t store_speed_scan(struct device *d, struct device_attribute *attr,
return count;
}
-static DEVICE_ATTR(speed_scan, S_IWUSR | S_IRUGO, show_speed_scan,
- store_speed_scan);
+static DEVICE_ATTR(speed_scan, 0644, show_speed_scan, store_speed_scan);
static ssize_t show_net_stats(struct device *d, struct device_attribute *attr,
char *buf)
@@ -1906,8 +1900,7 @@ static ssize_t store_net_stats(struct device *d, struct device_attribute *attr,
return count;
}
-static DEVICE_ATTR(net_stats, S_IWUSR | S_IRUGO,
- show_net_stats, store_net_stats);
+static DEVICE_ATTR(net_stats, 0644, show_net_stats, store_net_stats);
static ssize_t show_channels(struct device *d,
struct device_attribute *attr,
@@ -1953,7 +1946,7 @@ static ssize_t show_channels(struct device *d,
return len;
}
-static DEVICE_ATTR(channels, S_IRUSR, show_channels, NULL);
+static DEVICE_ATTR(channels, 0400, show_channels, NULL);
static void notify_wx_assoc_event(struct ipw_priv *priv)
{
diff --git a/drivers/net/wireless/intel/ipw2x00/libipw_module.c b/drivers/net/wireless/intel/ipw2x00/libipw_module.c
index c58c5b2dcce5..f00d45f54c76 100644
--- a/drivers/net/wireless/intel/ipw2x00/libipw_module.c
+++ b/drivers/net/wireless/intel/ipw2x00/libipw_module.c
@@ -276,7 +276,7 @@ static int __init libipw_init(void)
" proc directory\n");
return -EIO;
}
- e = proc_create("debug_level", S_IRUGO | S_IWUSR, libipw_proc,
+ e = proc_create("debug_level", 0644, libipw_proc,
&debug_level_proc_fops);
if (!e) {
remove_proc_entry(DRV_PROCNAME, init_net.proc_net);
diff --git a/drivers/net/wireless/intel/iwlegacy/3945-mac.c b/drivers/net/wireless/intel/iwlegacy/3945-mac.c
index 4b53ebf00c7f..62a9794f952b 100644
--- a/drivers/net/wireless/intel/iwlegacy/3945-mac.c
+++ b/drivers/net/wireless/intel/iwlegacy/3945-mac.c
@@ -3122,7 +3122,7 @@ il3945_store_debug_level(struct device *d, struct device_attribute *attr,
return strnlen(buf, count);
}
-static DEVICE_ATTR(debug_level, S_IWUSR | S_IRUGO, il3945_show_debug_level,
+static DEVICE_ATTR(debug_level, 0644, il3945_show_debug_level,
il3945_store_debug_level);
#endif /* CONFIG_IWLEGACY_DEBUG */
@@ -3139,7 +3139,7 @@ il3945_show_temperature(struct device *d, struct device_attribute *attr,
return sprintf(buf, "%d\n", il3945_hw_get_temperature(il));
}
-static DEVICE_ATTR(temperature, S_IRUGO, il3945_show_temperature, NULL);
+static DEVICE_ATTR(temperature, 0444, il3945_show_temperature, NULL);
static ssize_t
il3945_show_tx_power(struct device *d, struct device_attribute *attr, char *buf)
@@ -3165,8 +3165,7 @@ il3945_store_tx_power(struct device *d, struct device_attribute *attr,
return count;
}
-static DEVICE_ATTR(tx_power, S_IWUSR | S_IRUGO, il3945_show_tx_power,
- il3945_store_tx_power);
+static DEVICE_ATTR(tx_power, 0644, il3945_show_tx_power, il3945_store_tx_power);
static ssize_t
il3945_show_flags(struct device *d, struct device_attribute *attr, char *buf)
@@ -3199,8 +3198,7 @@ il3945_store_flags(struct device *d, struct device_attribute *attr,
return count;
}
-static DEVICE_ATTR(flags, S_IWUSR | S_IRUGO, il3945_show_flags,
- il3945_store_flags);
+static DEVICE_ATTR(flags, 0644, il3945_show_flags, il3945_store_flags);
static ssize_t
il3945_show_filter_flags(struct device *d, struct device_attribute *attr,
@@ -3235,7 +3233,7 @@ il3945_store_filter_flags(struct device *d, struct device_attribute *attr,
return count;
}
-static DEVICE_ATTR(filter_flags, S_IWUSR | S_IRUGO, il3945_show_filter_flags,
+static DEVICE_ATTR(filter_flags, 0644, il3945_show_filter_flags,
il3945_store_filter_flags);
static ssize_t
@@ -3306,7 +3304,7 @@ il3945_store_measurement(struct device *d, struct device_attribute *attr,
return count;
}
-static DEVICE_ATTR(measurement, S_IRUSR | S_IWUSR, il3945_show_measurement,
+static DEVICE_ATTR(measurement, 0600, il3945_show_measurement,
il3945_store_measurement);
static ssize_t
@@ -3330,7 +3328,7 @@ il3945_show_retry_rate(struct device *d, struct device_attribute *attr,
return sprintf(buf, "%d", il->retry_rate);
}
-static DEVICE_ATTR(retry_rate, S_IWUSR | S_IRUSR, il3945_show_retry_rate,
+static DEVICE_ATTR(retry_rate, 0600, il3945_show_retry_rate,
il3945_store_retry_rate);
static ssize_t
@@ -3340,7 +3338,7 @@ il3945_show_channels(struct device *d, struct device_attribute *attr, char *buf)
return 0;
}
-static DEVICE_ATTR(channels, S_IRUSR, il3945_show_channels, NULL);
+static DEVICE_ATTR(channels, 0400, il3945_show_channels, NULL);
static ssize_t
il3945_show_antenna(struct device *d, struct device_attribute *attr, char *buf)
@@ -3377,8 +3375,7 @@ il3945_store_antenna(struct device *d, struct device_attribute *attr,
return count;
}
-static DEVICE_ATTR(antenna, S_IWUSR | S_IRUGO, il3945_show_antenna,
- il3945_store_antenna);
+static DEVICE_ATTR(antenna, 0644, il3945_show_antenna, il3945_store_antenna);
static ssize_t
il3945_show_status(struct device *d, struct device_attribute *attr, char *buf)
@@ -3389,7 +3386,7 @@ il3945_show_status(struct device *d, struct device_attribute *attr, char *buf)
return sprintf(buf, "0x%08x\n", (int)il->status);
}
-static DEVICE_ATTR(status, S_IRUGO, il3945_show_status, NULL);
+static DEVICE_ATTR(status, 0444, il3945_show_status, NULL);
static ssize_t
il3945_dump_error_log(struct device *d, struct device_attribute *attr,
@@ -3404,7 +3401,7 @@ il3945_dump_error_log(struct device *d, struct device_attribute *attr,
return strnlen(buf, count);
}
-static DEVICE_ATTR(dump_errors, S_IWUSR, NULL, il3945_dump_error_log);
+static DEVICE_ATTR(dump_errors, 0200, NULL, il3945_dump_error_log);
/*****************************************************************************
*
@@ -3943,18 +3940,18 @@ il3945_exit(void)
MODULE_FIRMWARE(IL3945_MODULE_FIRMWARE(IL3945_UCODE_API_MAX));
-module_param_named(antenna, il3945_mod_params.antenna, int, S_IRUGO);
+module_param_named(antenna, il3945_mod_params.antenna, int, 0444);
MODULE_PARM_DESC(antenna, "select antenna (1=Main, 2=Aux, default 0 [both])");
-module_param_named(swcrypto, il3945_mod_params.sw_crypto, int, S_IRUGO);
+module_param_named(swcrypto, il3945_mod_params.sw_crypto, int, 0444);
MODULE_PARM_DESC(swcrypto, "using software crypto (default 1 [software])");
module_param_named(disable_hw_scan, il3945_mod_params.disable_hw_scan, int,
- S_IRUGO);
+ 0444);
MODULE_PARM_DESC(disable_hw_scan, "disable hardware scanning (default 1)");
#ifdef CONFIG_IWLEGACY_DEBUG
-module_param_named(debug, il_debug_level, uint, S_IRUGO | S_IWUSR);
+module_param_named(debug, il_debug_level, uint, 0644);
MODULE_PARM_DESC(debug, "debug output mask");
#endif
-module_param_named(fw_restart, il3945_mod_params.restart_fw, int, S_IRUGO);
+module_param_named(fw_restart, il3945_mod_params.restart_fw, int, 0444);
MODULE_PARM_DESC(fw_restart, "restart firmware in case of error");
module_exit(il3945_exit);
diff --git a/drivers/net/wireless/intel/iwlegacy/4965-mac.c b/drivers/net/wireless/intel/iwlegacy/4965-mac.c
index de63f2518f23..562e94870a9c 100644
--- a/drivers/net/wireless/intel/iwlegacy/4965-mac.c
+++ b/drivers/net/wireless/intel/iwlegacy/4965-mac.c
@@ -4591,7 +4591,7 @@ il4965_store_debug_level(struct device *d, struct device_attribute *attr,
return strnlen(buf, count);
}
-static DEVICE_ATTR(debug_level, S_IWUSR | S_IRUGO, il4965_show_debug_level,
+static DEVICE_ATTR(debug_level, 0644, il4965_show_debug_level,
il4965_store_debug_level);
#endif /* CONFIG_IWLEGACY_DEBUG */
@@ -4608,7 +4608,7 @@ il4965_show_temperature(struct device *d, struct device_attribute *attr,
return sprintf(buf, "%d\n", il->temperature);
}
-static DEVICE_ATTR(temperature, S_IRUGO, il4965_show_temperature, NULL);
+static DEVICE_ATTR(temperature, 0444, il4965_show_temperature, NULL);
static ssize_t
il4965_show_tx_power(struct device *d, struct device_attribute *attr, char *buf)
@@ -4642,7 +4642,7 @@ il4965_store_tx_power(struct device *d, struct device_attribute *attr,
return ret;
}
-static DEVICE_ATTR(tx_power, S_IWUSR | S_IRUGO, il4965_show_tx_power,
+static DEVICE_ATTR(tx_power, 0644, il4965_show_tx_power,
il4965_store_tx_power);
static struct attribute *il_sysfs_entries[] = {
@@ -6859,18 +6859,17 @@ module_exit(il4965_exit);
module_init(il4965_init);
#ifdef CONFIG_IWLEGACY_DEBUG
-module_param_named(debug, il_debug_level, uint, S_IRUGO | S_IWUSR);
+module_param_named(debug, il_debug_level, uint, 0644);
MODULE_PARM_DESC(debug, "debug output mask");
#endif
-module_param_named(swcrypto, il4965_mod_params.sw_crypto, int, S_IRUGO);
+module_param_named(swcrypto, il4965_mod_params.sw_crypto, int, 0444);
MODULE_PARM_DESC(swcrypto, "using crypto in software (default 0 [hardware])");
-module_param_named(queues_num, il4965_mod_params.num_of_queues, int, S_IRUGO);
+module_param_named(queues_num, il4965_mod_params.num_of_queues, int, 0444);
MODULE_PARM_DESC(queues_num, "number of hw queues.");
-module_param_named(11n_disable, il4965_mod_params.disable_11n, int, S_IRUGO);
+module_param_named(11n_disable, il4965_mod_params.disable_11n, int, 0444);
MODULE_PARM_DESC(11n_disable, "disable 11n functionality");
-module_param_named(amsdu_size_8K, il4965_mod_params.amsdu_size_8K, int,
- S_IRUGO);
+module_param_named(amsdu_size_8K, il4965_mod_params.amsdu_size_8K, int, 0444);
MODULE_PARM_DESC(amsdu_size_8K, "enable 8K amsdu size (default 0 [disabled])");
-module_param_named(fw_restart, il4965_mod_params.restart_fw, int, S_IRUGO);
+module_param_named(fw_restart, il4965_mod_params.restart_fw, int, 0444);
MODULE_PARM_DESC(fw_restart, "restart firmware in case of error");
diff --git a/drivers/net/wireless/intel/iwlegacy/4965-rs.c b/drivers/net/wireless/intel/iwlegacy/4965-rs.c
index 365a4187fc37..54ff83829afb 100644
--- a/drivers/net/wireless/intel/iwlegacy/4965-rs.c
+++ b/drivers/net/wireless/intel/iwlegacy/4965-rs.c
@@ -2768,16 +2768,16 @@ il4965_rs_add_debugfs(void *il, void *il_sta, struct dentry *dir)
{
struct il_lq_sta *lq_sta = il_sta;
lq_sta->rs_sta_dbgfs_scale_table_file =
- debugfs_create_file("rate_scale_table", S_IRUSR | S_IWUSR, dir,
+ debugfs_create_file("rate_scale_table", 0600, dir,
lq_sta, &rs_sta_dbgfs_scale_table_ops);
lq_sta->rs_sta_dbgfs_stats_table_file =
- debugfs_create_file("rate_stats_table", S_IRUSR, dir, lq_sta,
+ debugfs_create_file("rate_stats_table", 0400, dir, lq_sta,
&rs_sta_dbgfs_stats_table_ops);
lq_sta->rs_sta_dbgfs_rate_scale_data_file =
- debugfs_create_file("rate_scale_data", S_IRUSR, dir, lq_sta,
+ debugfs_create_file("rate_scale_data", 0400, dir, lq_sta,
&rs_sta_dbgfs_rate_scale_data_ops);
lq_sta->rs_sta_dbgfs_tx_agg_tid_en_file =
- debugfs_create_u8("tx_agg_tid_enable", S_IRUSR | S_IWUSR, dir,
+ debugfs_create_u8("tx_agg_tid_enable", 0600, dir,
&lq_sta->tx_agg_tid_en);
}
diff --git a/drivers/net/wireless/intel/iwlegacy/common.c b/drivers/net/wireless/intel/iwlegacy/common.c
index 558bb16bfd46..063e19ced7c8 100644
--- a/drivers/net/wireless/intel/iwlegacy/common.c
+++ b/drivers/net/wireless/intel/iwlegacy/common.c
@@ -435,7 +435,7 @@ EXPORT_SYMBOL(il_send_cmd_pdu_async);
/* default: IL_LED_BLINK(0) using blinking idx table */
static int led_mode;
-module_param(led_mode, int, S_IRUGO);
+module_param(led_mode, int, 0444);
MODULE_PARM_DESC(led_mode,
"0=system default, " "1=On(RF On)/Off(RF Off), 2=blinking");
@@ -3372,7 +3372,7 @@ MODULE_LICENSE("GPL");
* default: bt_coex_active = true (BT_COEX_ENABLE)
*/
static bool bt_coex_active = true;
-module_param(bt_coex_active, bool, S_IRUGO);
+module_param(bt_coex_active, bool, 0444);
MODULE_PARM_DESC(bt_coex_active, "enable wifi/bluetooth co-exist");
u32 il_debug_level;
diff --git a/drivers/net/wireless/intel/iwlegacy/debug.c b/drivers/net/wireless/intel/iwlegacy/debug.c
index 6fc6b7ff9849..d76073def677 100644
--- a/drivers/net/wireless/intel/iwlegacy/debug.c
+++ b/drivers/net/wireless/intel/iwlegacy/debug.c
@@ -135,16 +135,14 @@ EXPORT_SYMBOL(il_update_stats);
#define DEBUGFS_ADD_BOOL(name, parent, ptr) do { \
struct dentry *__tmp; \
- __tmp = debugfs_create_bool(#name, S_IWUSR | S_IRUSR, \
- parent, ptr); \
+ __tmp = debugfs_create_bool(#name, 0600, parent, ptr); \
if (IS_ERR(__tmp) || !__tmp) \
goto err; \
} while (0)
#define DEBUGFS_ADD_X32(name, parent, ptr) do { \
struct dentry *__tmp; \
- __tmp = debugfs_create_x32(#name, S_IWUSR | S_IRUSR, \
- parent, ptr); \
+ __tmp = debugfs_create_x32(#name, 0600, parent, ptr); \
if (IS_ERR(__tmp) || !__tmp) \
goto err; \
} while (0)
@@ -1365,35 +1363,35 @@ il_dbgfs_register(struct il_priv *il, const char *name)
if (!dir_debug)
goto err;
- DEBUGFS_ADD_FILE(nvm, dir_data, S_IRUSR);
- DEBUGFS_ADD_FILE(sram, dir_data, S_IWUSR | S_IRUSR);
- DEBUGFS_ADD_FILE(stations, dir_data, S_IRUSR);
- DEBUGFS_ADD_FILE(channels, dir_data, S_IRUSR);
- DEBUGFS_ADD_FILE(status, dir_data, S_IRUSR);
- DEBUGFS_ADD_FILE(interrupt, dir_data, S_IWUSR | S_IRUSR);
- DEBUGFS_ADD_FILE(qos, dir_data, S_IRUSR);
- DEBUGFS_ADD_FILE(disable_ht40, dir_data, S_IWUSR | S_IRUSR);
- DEBUGFS_ADD_FILE(rx_stats, dir_debug, S_IRUSR);
- DEBUGFS_ADD_FILE(tx_stats, dir_debug, S_IRUSR);
- DEBUGFS_ADD_FILE(rx_queue, dir_debug, S_IRUSR);
- DEBUGFS_ADD_FILE(tx_queue, dir_debug, S_IRUSR);
- DEBUGFS_ADD_FILE(power_save_status, dir_debug, S_IRUSR);
- DEBUGFS_ADD_FILE(clear_ucode_stats, dir_debug, S_IWUSR);
- DEBUGFS_ADD_FILE(clear_traffic_stats, dir_debug, S_IWUSR);
- DEBUGFS_ADD_FILE(fh_reg, dir_debug, S_IRUSR);
- DEBUGFS_ADD_FILE(missed_beacon, dir_debug, S_IWUSR);
- DEBUGFS_ADD_FILE(force_reset, dir_debug, S_IWUSR | S_IRUSR);
- DEBUGFS_ADD_FILE(ucode_rx_stats, dir_debug, S_IRUSR);
- DEBUGFS_ADD_FILE(ucode_tx_stats, dir_debug, S_IRUSR);
- DEBUGFS_ADD_FILE(ucode_general_stats, dir_debug, S_IRUSR);
+ DEBUGFS_ADD_FILE(nvm, dir_data, 0400);
+ DEBUGFS_ADD_FILE(sram, dir_data, 0600);
+ DEBUGFS_ADD_FILE(stations, dir_data, 0400);
+ DEBUGFS_ADD_FILE(channels, dir_data, 0400);
+ DEBUGFS_ADD_FILE(status, dir_data, 0400);
+ DEBUGFS_ADD_FILE(interrupt, dir_data, 0600);
+ DEBUGFS_ADD_FILE(qos, dir_data, 0400);
+ DEBUGFS_ADD_FILE(disable_ht40, dir_data, 0600);
+ DEBUGFS_ADD_FILE(rx_stats, dir_debug, 0400);
+ DEBUGFS_ADD_FILE(tx_stats, dir_debug, 0400);
+ DEBUGFS_ADD_FILE(rx_queue, dir_debug, 0400);
+ DEBUGFS_ADD_FILE(tx_queue, dir_debug, 0400);
+ DEBUGFS_ADD_FILE(power_save_status, dir_debug, 0400);
+ DEBUGFS_ADD_FILE(clear_ucode_stats, dir_debug, 0200);
+ DEBUGFS_ADD_FILE(clear_traffic_stats, dir_debug, 0200);
+ DEBUGFS_ADD_FILE(fh_reg, dir_debug, 0400);
+ DEBUGFS_ADD_FILE(missed_beacon, dir_debug, 0200);
+ DEBUGFS_ADD_FILE(force_reset, dir_debug, 0600);
+ DEBUGFS_ADD_FILE(ucode_rx_stats, dir_debug, 0400);
+ DEBUGFS_ADD_FILE(ucode_tx_stats, dir_debug, 0400);
+ DEBUGFS_ADD_FILE(ucode_general_stats, dir_debug, 0400);
if (il->cfg->sensitivity_calib_by_driver)
- DEBUGFS_ADD_FILE(sensitivity, dir_debug, S_IRUSR);
+ DEBUGFS_ADD_FILE(sensitivity, dir_debug, 0400);
if (il->cfg->chain_noise_calib_by_driver)
- DEBUGFS_ADD_FILE(chain_noise, dir_debug, S_IRUSR);
- DEBUGFS_ADD_FILE(rxon_flags, dir_debug, S_IWUSR);
- DEBUGFS_ADD_FILE(rxon_filter_flags, dir_debug, S_IWUSR);
- DEBUGFS_ADD_FILE(wd_timeout, dir_debug, S_IWUSR);
+ DEBUGFS_ADD_FILE(chain_noise, dir_debug, 0400);
+ DEBUGFS_ADD_FILE(rxon_flags, dir_debug, 0200);
+ DEBUGFS_ADD_FILE(rxon_filter_flags, dir_debug, 0200);
+ DEBUGFS_ADD_FILE(wd_timeout, dir_debug, 0200);
if (il->cfg->sensitivity_calib_by_driver)
DEBUGFS_ADD_BOOL(disable_sensitivity, dir_rf,
&il->disable_sens_cal);
diff --git a/drivers/net/wireless/intel/iwlwifi/cfg/22000.c b/drivers/net/wireless/intel/iwlwifi/cfg/22000.c
index 48f6f80eb24b..dffd9df782b0 100644
--- a/drivers/net/wireless/intel/iwlwifi/cfg/22000.c
+++ b/drivers/net/wireless/intel/iwlwifi/cfg/22000.c
@@ -6,6 +6,7 @@
* GPL LICENSE SUMMARY
*
* Copyright(c) 2015-2017 Intel Deutschland GmbH
+ * Copyright (C) 2018 Intel Corporation
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of version 2 of the GNU General Public License as
@@ -19,6 +20,7 @@
* BSD LICENSE
*
* Copyright(c) 2015-2017 Intel Deutschland GmbH
+ * Copyright (C) 2018 Intel Corporation
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -55,7 +57,7 @@
#include "iwl-agn-hw.h"
/* Highest firmware API version supported */
-#define IWL_22000_UCODE_API_MAX 36
+#define IWL_22000_UCODE_API_MAX 38
/* Lowest firmware API version supported */
#define IWL_22000_UCODE_API_MIN 24
diff --git a/drivers/net/wireless/intel/iwlwifi/cfg/9000.c b/drivers/net/wireless/intel/iwlwifi/cfg/9000.c
index 90a1d14cf7d2..e1c869a1f8cc 100644
--- a/drivers/net/wireless/intel/iwlwifi/cfg/9000.c
+++ b/drivers/net/wireless/intel/iwlwifi/cfg/9000.c
@@ -6,6 +6,7 @@
* GPL LICENSE SUMMARY
*
* Copyright(c) 2015-2017 Intel Deutschland GmbH
+ * Copyright (C) 2018 Intel Corporation
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of version 2 of the GNU General Public License as
@@ -19,6 +20,7 @@
* BSD LICENSE
*
* Copyright(c) 2015-2017 Intel Deutschland GmbH
+ * Copyright (C) 2018 Intel Corporation
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -53,9 +55,10 @@
#include <linux/stringify.h>
#include "iwl-config.h"
#include "iwl-agn-hw.h"
+#include "fw/file.h"
/* Highest firmware API version supported */
-#define IWL9000_UCODE_API_MAX 36
+#define IWL9000_UCODE_API_MAX 38
/* Lowest firmware API version supported */
#define IWL9000_UCODE_API_MIN 30
@@ -265,6 +268,67 @@ const struct iwl_cfg iwl9560_2ac_cfg_soc = {
.integrated = true,
.soc_latency = 5000,
};
+
+const struct iwl_cfg iwl9460_2ac_cfg_shared_clk = {
+ .name = "Intel(R) Dual Band Wireless AC 9460",
+ .fw_name_pre = IWL9000A_FW_PRE,
+ .fw_name_pre_b_or_c_step = IWL9000B_FW_PRE,
+ .fw_name_pre_rf_next_step = IWL9000RFB_FW_PRE,
+ IWL_DEVICE_9000,
+ .ht_params = &iwl9000_ht_params,
+ .nvm_ver = IWL9000_NVM_VERSION,
+ .nvm_calib_ver = IWL9000_TX_POWER_VERSION,
+ .max_ht_ampdu_exponent = IEEE80211_HT_MAX_AMPDU_64K,
+ .integrated = true,
+ .soc_latency = 5000,
+ .extra_phy_cfg_flags = FW_PHY_CFG_SHARED_CLK
+};
+
+const struct iwl_cfg iwl9461_2ac_cfg_shared_clk = {
+ .name = "Intel(R) Dual Band Wireless AC 9461",
+ .fw_name_pre = IWL9000A_FW_PRE,
+ .fw_name_pre_b_or_c_step = IWL9000B_FW_PRE,
+ .fw_name_pre_rf_next_step = IWL9000RFB_FW_PRE,
+ IWL_DEVICE_9000,
+ .ht_params = &iwl9000_ht_params,
+ .nvm_ver = IWL9000_NVM_VERSION,
+ .nvm_calib_ver = IWL9000_TX_POWER_VERSION,
+ .max_ht_ampdu_exponent = IEEE80211_HT_MAX_AMPDU_64K,
+ .integrated = true,
+ .soc_latency = 5000,
+ .extra_phy_cfg_flags = FW_PHY_CFG_SHARED_CLK
+};
+
+const struct iwl_cfg iwl9462_2ac_cfg_shared_clk = {
+ .name = "Intel(R) Dual Band Wireless AC 9462",
+ .fw_name_pre = IWL9000A_FW_PRE,
+ .fw_name_pre_b_or_c_step = IWL9000B_FW_PRE,
+ .fw_name_pre_rf_next_step = IWL9000RFB_FW_PRE,
+ IWL_DEVICE_9000,
+ .ht_params = &iwl9000_ht_params,
+ .nvm_ver = IWL9000_NVM_VERSION,
+ .nvm_calib_ver = IWL9000_TX_POWER_VERSION,
+ .max_ht_ampdu_exponent = IEEE80211_HT_MAX_AMPDU_64K,
+ .integrated = true,
+ .soc_latency = 5000,
+ .extra_phy_cfg_flags = FW_PHY_CFG_SHARED_CLK
+};
+
+const struct iwl_cfg iwl9560_2ac_cfg_shared_clk = {
+ .name = "Intel(R) Dual Band Wireless AC 9560",
+ .fw_name_pre = IWL9000A_FW_PRE,
+ .fw_name_pre_b_or_c_step = IWL9000B_FW_PRE,
+ .fw_name_pre_rf_next_step = IWL9000RFB_FW_PRE,
+ IWL_DEVICE_9000,
+ .ht_params = &iwl9000_ht_params,
+ .nvm_ver = IWL9000_NVM_VERSION,
+ .nvm_calib_ver = IWL9000_TX_POWER_VERSION,
+ .max_ht_ampdu_exponent = IEEE80211_HT_MAX_AMPDU_64K,
+ .integrated = true,
+ .soc_latency = 5000,
+ .extra_phy_cfg_flags = FW_PHY_CFG_SHARED_CLK
+};
+
MODULE_FIRMWARE(IWL9000A_MODULE_FIRMWARE(IWL9000_UCODE_API_MAX));
MODULE_FIRMWARE(IWL9000B_MODULE_FIRMWARE(IWL9000_UCODE_API_MAX));
MODULE_FIRMWARE(IWL9000RFB_MODULE_FIRMWARE(IWL9000_UCODE_API_MAX));
diff --git a/drivers/net/wireless/intel/iwlwifi/dvm/debugfs.c b/drivers/net/wireless/intel/iwlwifi/dvm/debugfs.c
index 482ac8fdc67b..096a07c5a33f 100644
--- a/drivers/net/wireless/intel/iwlwifi/dvm/debugfs.c
+++ b/drivers/net/wireless/intel/iwlwifi/dvm/debugfs.c
@@ -48,16 +48,14 @@
#define DEBUGFS_ADD_BOOL(name, parent, ptr) do { \
struct dentry *__tmp; \
- __tmp = debugfs_create_bool(#name, S_IWUSR | S_IRUSR, \
- parent, ptr); \
+ __tmp = debugfs_create_bool(#name, 0600, parent, ptr); \
if (IS_ERR(__tmp) || !__tmp) \
goto err; \
} while (0)
#define DEBUGFS_ADD_X32(name, parent, ptr) do { \
struct dentry *__tmp; \
- __tmp = debugfs_create_x32(#name, S_IWUSR | S_IRUSR, \
- parent, ptr); \
+ __tmp = debugfs_create_x32(#name, 0600, parent, ptr); \
if (IS_ERR(__tmp) || !__tmp) \
goto err; \
} while (0)
@@ -2370,48 +2368,48 @@ int iwl_dbgfs_register(struct iwl_priv *priv, struct dentry *dbgfs_dir)
if (!dir_debug)
goto err;
- DEBUGFS_ADD_FILE(nvm, dir_data, S_IRUSR);
- DEBUGFS_ADD_FILE(sram, dir_data, S_IWUSR | S_IRUSR);
- DEBUGFS_ADD_FILE(wowlan_sram, dir_data, S_IRUSR);
- DEBUGFS_ADD_FILE(stations, dir_data, S_IRUSR);
- DEBUGFS_ADD_FILE(channels, dir_data, S_IRUSR);
- DEBUGFS_ADD_FILE(status, dir_data, S_IRUSR);
- DEBUGFS_ADD_FILE(rx_handlers, dir_data, S_IWUSR | S_IRUSR);
- DEBUGFS_ADD_FILE(qos, dir_data, S_IRUSR);
- DEBUGFS_ADD_FILE(sleep_level_override, dir_data, S_IWUSR | S_IRUSR);
- DEBUGFS_ADD_FILE(current_sleep_command, dir_data, S_IRUSR);
- DEBUGFS_ADD_FILE(thermal_throttling, dir_data, S_IRUSR);
- DEBUGFS_ADD_FILE(disable_ht40, dir_data, S_IWUSR | S_IRUSR);
- DEBUGFS_ADD_FILE(temperature, dir_data, S_IRUSR);
-
- DEBUGFS_ADD_FILE(power_save_status, dir_debug, S_IRUSR);
- DEBUGFS_ADD_FILE(clear_ucode_statistics, dir_debug, S_IWUSR);
- DEBUGFS_ADD_FILE(missed_beacon, dir_debug, S_IWUSR);
- DEBUGFS_ADD_FILE(plcp_delta, dir_debug, S_IWUSR | S_IRUSR);
- DEBUGFS_ADD_FILE(rf_reset, dir_debug, S_IWUSR | S_IRUSR);
- DEBUGFS_ADD_FILE(ucode_rx_stats, dir_debug, S_IRUSR);
- DEBUGFS_ADD_FILE(ucode_tx_stats, dir_debug, S_IRUSR);
- DEBUGFS_ADD_FILE(ucode_general_stats, dir_debug, S_IRUSR);
- DEBUGFS_ADD_FILE(txfifo_flush, dir_debug, S_IWUSR);
- DEBUGFS_ADD_FILE(protection_mode, dir_debug, S_IWUSR | S_IRUSR);
- DEBUGFS_ADD_FILE(sensitivity, dir_debug, S_IRUSR);
- DEBUGFS_ADD_FILE(chain_noise, dir_debug, S_IRUSR);
- DEBUGFS_ADD_FILE(ucode_tracing, dir_debug, S_IWUSR | S_IRUSR);
- DEBUGFS_ADD_FILE(ucode_bt_stats, dir_debug, S_IRUSR);
- DEBUGFS_ADD_FILE(reply_tx_error, dir_debug, S_IRUSR);
- DEBUGFS_ADD_FILE(rxon_flags, dir_debug, S_IWUSR);
- DEBUGFS_ADD_FILE(rxon_filter_flags, dir_debug, S_IWUSR);
- DEBUGFS_ADD_FILE(echo_test, dir_debug, S_IWUSR);
- DEBUGFS_ADD_FILE(fw_restart, dir_debug, S_IWUSR);
+ DEBUGFS_ADD_FILE(nvm, dir_data, 0400);
+ DEBUGFS_ADD_FILE(sram, dir_data, 0600);
+ DEBUGFS_ADD_FILE(wowlan_sram, dir_data, 0400);
+ DEBUGFS_ADD_FILE(stations, dir_data, 0400);
+ DEBUGFS_ADD_FILE(channels, dir_data, 0400);
+ DEBUGFS_ADD_FILE(status, dir_data, 0400);
+ DEBUGFS_ADD_FILE(rx_handlers, dir_data, 0600);
+ DEBUGFS_ADD_FILE(qos, dir_data, 0400);
+ DEBUGFS_ADD_FILE(sleep_level_override, dir_data, 0600);
+ DEBUGFS_ADD_FILE(current_sleep_command, dir_data, 0400);
+ DEBUGFS_ADD_FILE(thermal_throttling, dir_data, 0400);
+ DEBUGFS_ADD_FILE(disable_ht40, dir_data, 0600);
+ DEBUGFS_ADD_FILE(temperature, dir_data, 0400);
+
+ DEBUGFS_ADD_FILE(power_save_status, dir_debug, 0400);
+ DEBUGFS_ADD_FILE(clear_ucode_statistics, dir_debug, 0200);
+ DEBUGFS_ADD_FILE(missed_beacon, dir_debug, 0200);
+ DEBUGFS_ADD_FILE(plcp_delta, dir_debug, 0600);
+ DEBUGFS_ADD_FILE(rf_reset, dir_debug, 0600);
+ DEBUGFS_ADD_FILE(ucode_rx_stats, dir_debug, 0400);
+ DEBUGFS_ADD_FILE(ucode_tx_stats, dir_debug, 0400);
+ DEBUGFS_ADD_FILE(ucode_general_stats, dir_debug, 0400);
+ DEBUGFS_ADD_FILE(txfifo_flush, dir_debug, 0200);
+ DEBUGFS_ADD_FILE(protection_mode, dir_debug, 0600);
+ DEBUGFS_ADD_FILE(sensitivity, dir_debug, 0400);
+ DEBUGFS_ADD_FILE(chain_noise, dir_debug, 0400);
+ DEBUGFS_ADD_FILE(ucode_tracing, dir_debug, 0600);
+ DEBUGFS_ADD_FILE(ucode_bt_stats, dir_debug, 0400);
+ DEBUGFS_ADD_FILE(reply_tx_error, dir_debug, 0400);
+ DEBUGFS_ADD_FILE(rxon_flags, dir_debug, 0200);
+ DEBUGFS_ADD_FILE(rxon_filter_flags, dir_debug, 0200);
+ DEBUGFS_ADD_FILE(echo_test, dir_debug, 0200);
+ DEBUGFS_ADD_FILE(fw_restart, dir_debug, 0200);
#ifdef CONFIG_IWLWIFI_DEBUG
- DEBUGFS_ADD_FILE(log_event, dir_debug, S_IWUSR | S_IRUSR);
+ DEBUGFS_ADD_FILE(log_event, dir_debug, 0600);
#endif
if (iwl_advanced_bt_coexist(priv))
- DEBUGFS_ADD_FILE(bt_traffic, dir_debug, S_IRUSR);
+ DEBUGFS_ADD_FILE(bt_traffic, dir_debug, 0400);
/* Calibrations disabled/enabled status*/
- DEBUGFS_ADD_FILE(calib_disabled, dir_rf, S_IWUSR | S_IRUSR);
+ DEBUGFS_ADD_FILE(calib_disabled, dir_rf, 0600);
/*
* Create a symlink with mac80211. This is not very robust, as it does
diff --git a/drivers/net/wireless/intel/iwlwifi/dvm/rs.c b/drivers/net/wireless/intel/iwlwifi/dvm/rs.c
index ddcd8c2d66cd..98050d7be411 100644
--- a/drivers/net/wireless/intel/iwlwifi/dvm/rs.c
+++ b/drivers/net/wireless/intel/iwlwifi/dvm/rs.c
@@ -3276,17 +3276,17 @@ static void rs_add_debugfs(void *priv, void *priv_sta,
{
struct iwl_lq_sta *lq_sta = priv_sta;
lq_sta->rs_sta_dbgfs_scale_table_file =
- debugfs_create_file("rate_scale_table", S_IRUSR | S_IWUSR, dir,
- lq_sta, &rs_sta_dbgfs_scale_table_ops);
+ debugfs_create_file("rate_scale_table", 0600, dir,
+ lq_sta, &rs_sta_dbgfs_scale_table_ops);
lq_sta->rs_sta_dbgfs_stats_table_file =
- debugfs_create_file("rate_stats_table", S_IRUSR, dir,
- lq_sta, &rs_sta_dbgfs_stats_table_ops);
+ debugfs_create_file("rate_stats_table", 0400, dir,
+ lq_sta, &rs_sta_dbgfs_stats_table_ops);
lq_sta->rs_sta_dbgfs_rate_scale_data_file =
- debugfs_create_file("rate_scale_data", S_IRUSR, dir,
- lq_sta, &rs_sta_dbgfs_rate_scale_data_ops);
+ debugfs_create_file("rate_scale_data", 0400, dir,
+ lq_sta, &rs_sta_dbgfs_rate_scale_data_ops);
lq_sta->rs_sta_dbgfs_tx_agg_tid_en_file =
- debugfs_create_u8("tx_agg_tid_enable", S_IRUSR | S_IWUSR, dir,
- &lq_sta->tx_agg_tid_en);
+ debugfs_create_u8("tx_agg_tid_enable", 0600, dir,
+ &lq_sta->tx_agg_tid_en);
}
diff --git a/drivers/net/wireless/intel/iwlwifi/fw/api/nvm-reg.h b/drivers/net/wireless/intel/iwlwifi/fw/api/nvm-reg.h
index 3fd07bc80f54..37c57bcbfb4a 100644
--- a/drivers/net/wireless/intel/iwlwifi/fw/api/nvm-reg.h
+++ b/drivers/net/wireless/intel/iwlwifi/fw/api/nvm-reg.h
@@ -8,6 +8,7 @@
* Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved.
* Copyright(c) 2013 - 2015 Intel Mobile Communications GmbH
* Copyright(c) 2016 - 2017 Intel Deutschland GmbH
+ * Copyright (C) 2018 Intel Corporation
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of version 2 of the GNU General Public License as
@@ -30,6 +31,7 @@
* Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved.
* Copyright(c) 2013 - 2015 Intel Mobile Communications GmbH
* Copyright(c) 2016 - 2017 Intel Deutschland GmbH
+ * Copyright (C) 2018 Intel Corporation
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -311,6 +313,17 @@ struct iwl_mcc_update_resp_v1 {
} __packed; /* LAR_UPDATE_MCC_CMD_RESP_S_VER_1 */
/**
+ * enum iwl_geo_information - geographic information.
+ * @GEO_NO_INFO: no special info for this geo profile.
+ * @GEO_WMM_ETSI_5GHZ_INFO: this geo profile limits the WMM params
+ * for the 5 GHz band.
+ */
+enum iwl_geo_information {
+ GEO_NO_INFO = 0,
+ GEO_WMM_ETSI_5GHZ_INFO = BIT(0),
+};
+
+/**
* struct iwl_mcc_update_resp - response to MCC_UPDATE_CMD.
* Contains the new channel control profile map, if changed, and the new MCC
* (mobile country code).
@@ -320,7 +333,8 @@ struct iwl_mcc_update_resp_v1 {
* @cap: capabilities for all channels which matches the MCC
* @source_id: the MCC source, see iwl_mcc_source
* @time: time elapsed from the MCC test start (in 30 seconds TU)
- * @reserved: reserved.
+ * @geo_info: geographic specific profile information
+ * see &enum iwl_geo_information.
* @n_channels: number of channels in @channels_data (may be 14, 39, 50 or 51
* channels, depending on platform)
* @channels: channel control data map, DWORD for each channel. Only the first
@@ -332,10 +346,10 @@ struct iwl_mcc_update_resp {
u8 cap;
u8 source_id;
__le16 time;
- __le16 reserved;
+ __le16 geo_info;
__le32 n_channels;
__le32 channels[0];
-} __packed; /* LAR_UPDATE_MCC_CMD_RESP_S_VER_2 */
+} __packed; /* LAR_UPDATE_MCC_CMD_RESP_S_VER_3 */
/**
* struct iwl_mcc_chub_notif - chub notifies of mcc change
diff --git a/drivers/net/wireless/intel/iwlwifi/fw/api/scan.h b/drivers/net/wireless/intel/iwlwifi/fw/api/scan.h
index 3bfc657f6b42..7af3a0f51b77 100644
--- a/drivers/net/wireless/intel/iwlwifi/fw/api/scan.h
+++ b/drivers/net/wireless/intel/iwlwifi/fw/api/scan.h
@@ -30,6 +30,7 @@
* Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved.
* Copyright(c) 2013 - 2015 Intel Mobile Communications GmbH
* Copyright(c) 2016 - 2017 Intel Deutschland GmbH
+ * Copyright(c) 2018 Intel Corporation
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -579,8 +580,23 @@ enum iwl_umac_scan_general_flags {
IWL_UMAC_SCAN_GEN_FLAGS_RRM_ENABLED = BIT(8),
IWL_UMAC_SCAN_GEN_FLAGS_MATCH = BIT(9),
IWL_UMAC_SCAN_GEN_FLAGS_EXTENDED_DWELL = BIT(10),
+ /* Extended dwell is obselete when adaptive dwell is used, making this
+ * bit reusable. Hence, probe request defer is used only when adaptive
+ * dwell is supported. */
+ IWL_UMAC_SCAN_GEN_FLAGS_PROB_REQ_DEFER_SUPP = BIT(10),
IWL_UMAC_SCAN_GEN_FLAGS_LMAC2_FRAGMENTED = BIT(11),
IWL_UMAC_SCAN_GEN_FLAGS_ADAPTIVE_DWELL = BIT(13),
+ IWL_UMAC_SCAN_GEN_FLAGS_MAX_CHNL_TIME = BIT(14),
+ IWL_UMAC_SCAN_GEN_FLAGS_PROB_REQ_HIGH_TX_RATE = BIT(15),
+};
+
+/**
+ * enum iwl_umac_scan_general_flags2 - UMAC scan general flags #2
+ * @IWL_UMAC_SCAN_GEN_FLAGS2_NOTIF_PER_CHNL: Whether to send a complete
+ * notification per channel or not.
+ */
+enum iwl_umac_scan_general_flags2 {
+ IWL_UMAC_SCAN_GEN_FLAGS2_NOTIF_PER_CHNL = BIT(0),
};
/**
@@ -629,6 +645,18 @@ struct iwl_scan_req_umac_tail {
} __packed;
/**
+ * struct iwl_scan_umac_chan_param
+ * @flags: channel flags &enum iwl_scan_channel_flags
+ * @count: num of channels in scan request
+ * @reserved: for future use and alignment
+ */
+struct iwl_scan_umac_chan_param {
+ u8 flags;
+ u8 count;
+ __le16 reserved;
+} __packed; /*SCAN_CHANNEL_PARAMS_API_S_VER_1 */
+
+/**
* struct iwl_scan_req_umac
* @flags: &enum iwl_umac_scan_flags
* @uid: scan id, &enum iwl_umac_scan_uid_offsets
@@ -636,23 +664,24 @@ struct iwl_scan_req_umac_tail {
* @general_flags: &enum iwl_umac_scan_general_flags
* @scan_start_mac_id: report the scan start TSF time according to this mac TSF
* @extended_dwell: dwell time for channels 1, 6 and 11
- * @active_dwell: dwell time for active scan
- * @passive_dwell: dwell time for passive scan
+ * @active_dwell: dwell time for active scan per LMAC
+ * @passive_dwell: dwell time for passive scan per LMAC
* @fragmented_dwell: dwell time for fragmented passive scan
* @adwell_default_n_aps: for adaptive dwell the default number of APs
* per channel
* @adwell_default_n_aps_social: for adaptive dwell the default
* number of APs per social (1,6,11) channel
+ * @general_flags2: &enum iwl_umac_scan_general_flags2
* @adwell_max_budget: for adaptive dwell the maximal budget of TU to be added
* to total scan time
* @max_out_time: max out of serving channel time, per LMAC - for CDB there
* are 2 LMACs
* @suspend_time: max suspend time, per LMAC - for CDB there are 2 LMACs
* @scan_priority: scan internal prioritization &enum iwl_scan_priority
- * @channel_flags: &enum iwl_scan_channel_flags
- * @n_channels: num of channels in scan request
+ * @num_of_fragments: Number of fragments needed for full coverage per band.
+ * Relevant only for fragmented scan.
+ * @channel: &struct iwl_scan_umac_chan_param
* @reserved: for future use and alignment
- * @reserved2: for future use and alignment
* @reserved3: for future use and alignment
* @data: &struct iwl_scan_channel_cfg_umac and
* &struct iwl_scan_req_umac_tail
@@ -673,10 +702,7 @@ struct iwl_scan_req_umac {
__le32 max_out_time;
__le32 suspend_time;
__le32 scan_priority;
- /* SCAN_CHANNEL_PARAMS_API_S_VER_1 */
- u8 channel_flags;
- u8 n_channels;
- __le16 reserved2;
+ struct iwl_scan_umac_chan_param channel;
u8 data[];
} v1; /* SCAN_REQUEST_CMD_UMAC_API_S_VER_1 */
struct {
@@ -687,10 +713,7 @@ struct iwl_scan_req_umac {
__le32 max_out_time[SCAN_TWO_LMACS];
__le32 suspend_time[SCAN_TWO_LMACS];
__le32 scan_priority;
- /* SCAN_CHANNEL_PARAMS_API_S_VER_1 */
- u8 channel_flags;
- u8 n_channels;
- __le16 reserved2;
+ struct iwl_scan_umac_chan_param channel;
u8 data[];
} v6; /* SCAN_REQUEST_CMD_UMAC_API_S_VER_6 */
struct {
@@ -704,16 +727,30 @@ struct iwl_scan_req_umac {
__le32 max_out_time[SCAN_TWO_LMACS];
__le32 suspend_time[SCAN_TWO_LMACS];
__le32 scan_priority;
- /* SCAN_CHANNEL_PARAMS_API_S_VER_1 */
- u8 channel_flags;
- u8 n_channels;
- __le16 reserved2;
+ struct iwl_scan_umac_chan_param channel;
u8 data[];
} v7; /* SCAN_REQUEST_CMD_UMAC_API_S_VER_7 */
+ struct {
+ u8 active_dwell[SCAN_TWO_LMACS];
+ u8 reserved2;
+ u8 adwell_default_n_aps;
+ u8 adwell_default_n_aps_social;
+ u8 general_flags2;
+ __le16 adwell_max_budget;
+ __le32 max_out_time[SCAN_TWO_LMACS];
+ __le32 suspend_time[SCAN_TWO_LMACS];
+ __le32 scan_priority;
+ u8 passive_dwell[SCAN_TWO_LMACS];
+ u8 num_of_fragments[SCAN_TWO_LMACS];
+ struct iwl_scan_umac_chan_param channel;
+ u8 data[];
+ } v8; /* SCAN_REQUEST_CMD_UMAC_API_S_VER_8 */
};
} __packed;
-#define IWL_SCAN_REQ_UMAC_SIZE_V7 sizeof(struct iwl_scan_req_umac)
+#define IWL_SCAN_REQ_UMAC_SIZE_V8 sizeof(struct iwl_scan_req_umac)
+#define IWL_SCAN_REQ_UMAC_SIZE_V7 (sizeof(struct iwl_scan_req_umac) - \
+ 4 * sizeof(u8))
#define IWL_SCAN_REQ_UMAC_SIZE_V6 (sizeof(struct iwl_scan_req_umac) - \
2 * sizeof(u8) - sizeof(__le16))
#define IWL_SCAN_REQ_UMAC_SIZE_V1 (sizeof(struct iwl_scan_req_umac) - \
diff --git a/drivers/net/wireless/intel/iwlwifi/fw/dbg.c b/drivers/net/wireless/intel/iwlwifi/fw/dbg.c
index 7bd704a3e640..fa283285fcbe 100644
--- a/drivers/net/wireless/intel/iwlwifi/fw/dbg.c
+++ b/drivers/net/wireless/intel/iwlwifi/fw/dbg.c
@@ -68,6 +68,7 @@
#include "iwl-drv.h"
#include "runtime.h"
#include "dbg.h"
+#include "debugfs.h"
#include "iwl-io.h"
#include "iwl-prph.h"
#include "iwl-csr.h"
@@ -1007,6 +1008,12 @@ int iwl_fw_dbg_collect(struct iwl_fw_runtime *fwrt,
{
struct iwl_fw_dump_desc *desc;
+ if (trigger && trigger->flags & IWL_FW_DBG_FORCE_RESTART) {
+ IWL_WARN(fwrt, "Force restart: trigger %d fired.\n", trig);
+ iwl_force_nmi(fwrt->trans);
+ return 0;
+ }
+
desc = kzalloc(sizeof(*desc) + len, GFP_ATOMIC);
if (!desc)
return -ENOMEM;
@@ -1080,6 +1087,9 @@ int iwl_fw_start_dbg_conf(struct iwl_fw_runtime *fwrt, u8 conf_id)
IWL_WARN(fwrt, "FW already configured (%d) - re-configuring\n",
fwrt->dump.conf);
+ /* start default config marker cmd for syncing logs */
+ iwl_fw_trigger_timestamp(fwrt, 1);
+
/* Send all HCMDs for configuring the FW debug */
ptr = (void *)&fwrt->fw->dbg_conf_tlv[conf_id]->hcmd;
for (i = 0; i < fwrt->fw->dbg_conf_tlv[conf_id]->num_of_hcmds; i++) {
diff --git a/drivers/net/wireless/intel/iwlwifi/fw/debugfs.c b/drivers/net/wireless/intel/iwlwifi/fw/debugfs.c
index e2ded29a145d..8f005cd69559 100644
--- a/drivers/net/wireless/intel/iwlwifi/fw/debugfs.c
+++ b/drivers/net/wireless/intel/iwlwifi/fw/debugfs.c
@@ -157,6 +157,20 @@ static void iwl_fw_timestamp_marker_wk(struct work_struct *work)
ret, jiffies_to_msecs(delay) / 1000);
}
+void iwl_fw_trigger_timestamp(struct iwl_fw_runtime *fwrt, u32 delay)
+{
+ IWL_INFO(fwrt,
+ "starting timestamp_marker trigger with delay: %us\n",
+ delay);
+
+ iwl_fw_cancel_timestamp(fwrt);
+
+ fwrt->timestamp.delay = msecs_to_jiffies(delay * 1000);
+
+ schedule_delayed_work(&fwrt->timestamp.wk,
+ round_jiffies_relative(fwrt->timestamp.delay));
+}
+
static ssize_t iwl_dbgfs_timestamp_marker_write(struct iwl_fw_runtime *fwrt,
char *buf, size_t count,
loff_t *ppos)
@@ -168,16 +182,8 @@ static ssize_t iwl_dbgfs_timestamp_marker_write(struct iwl_fw_runtime *fwrt,
if (ret < 0)
return ret;
- IWL_INFO(fwrt,
- "starting timestamp_marker trigger with delay: %us\n",
- delay);
+ iwl_fw_trigger_timestamp(fwrt, delay);
- iwl_fw_cancel_timestamp(fwrt);
-
- fwrt->timestamp.delay = msecs_to_jiffies(delay * 1000);
-
- schedule_delayed_work(&fwrt->timestamp.wk,
- round_jiffies_relative(fwrt->timestamp.delay));
return count;
}
@@ -187,7 +193,7 @@ int iwl_fwrt_dbgfs_register(struct iwl_fw_runtime *fwrt,
struct dentry *dbgfs_dir)
{
INIT_DELAYED_WORK(&fwrt->timestamp.wk, iwl_fw_timestamp_marker_wk);
- FWRT_DEBUGFS_ADD_FILE(timestamp_marker, dbgfs_dir, S_IWUSR);
+ FWRT_DEBUGFS_ADD_FILE(timestamp_marker, dbgfs_dir, 0200);
return 0;
err:
IWL_ERR(fwrt, "Can't create the fwrt debugfs directory\n");
diff --git a/drivers/net/wireless/intel/iwlwifi/fw/debugfs.h b/drivers/net/wireless/intel/iwlwifi/fw/debugfs.h
index 3da468d2cc92..d93f6a4bb22d 100644
--- a/drivers/net/wireless/intel/iwlwifi/fw/debugfs.h
+++ b/drivers/net/wireless/intel/iwlwifi/fw/debugfs.h
@@ -89,6 +89,8 @@ static inline void iwl_fw_resume_timestamp(struct iwl_fw_runtime *fwrt)
round_jiffies_relative(fwrt->timestamp.delay));
}
+void iwl_fw_trigger_timestamp(struct iwl_fw_runtime *fwrt, u32 delay);
+
#else
static inline int iwl_fwrt_dbgfs_register(struct iwl_fw_runtime *fwrt,
struct dentry *dbgfs_dir)
@@ -102,4 +104,7 @@ static inline void iwl_fw_suspend_timestamp(struct iwl_fw_runtime *fwrt) {}
static inline void iwl_fw_resume_timestamp(struct iwl_fw_runtime *fwrt) {}
+static inline void iwl_fw_trigger_timestamp(struct iwl_fw_runtime *fwrt,
+ u32 delay) {}
+
#endif /* CONFIG_IWLWIFI_DEBUGFS */
diff --git a/drivers/net/wireless/intel/iwlwifi/fw/file.h b/drivers/net/wireless/intel/iwlwifi/fw/file.h
index 1a05d506ac9a..9b2805e1e3b1 100644
--- a/drivers/net/wireless/intel/iwlwifi/fw/file.h
+++ b/drivers/net/wireless/intel/iwlwifi/fw/file.h
@@ -250,6 +250,8 @@ typedef unsigned int __bitwise iwl_ucode_tlv_api_t;
* indicating low latency direction.
* @IWL_UCODE_TLV_API_DEPRECATE_TTAK: RX status flag TTAK ok (bit 7) is
* deprecated.
+ * @IWL_UCODE_TLV_API_ADAPTIVE_DWELL_V2: This ucode supports version 8
+ * of scan request: SCAN_REQUEST_CMD_UMAC_API_S_VER_8
*
* @NUM_IWL_UCODE_TLV_API: number of bits used
*/
@@ -265,10 +267,12 @@ enum iwl_ucode_tlv_api {
IWL_UCODE_TLV_API_NAN2_VER2 = (__force iwl_ucode_tlv_api_t)31,
/* API Set 1 */
IWL_UCODE_TLV_API_ADAPTIVE_DWELL = (__force iwl_ucode_tlv_api_t)32,
+ IWL_UCODE_TLV_API_OCE = (__force iwl_ucode_tlv_api_t)33,
IWL_UCODE_TLV_API_NEW_BEACON_TEMPLATE = (__force iwl_ucode_tlv_api_t)34,
IWL_UCODE_TLV_API_NEW_RX_STATS = (__force iwl_ucode_tlv_api_t)35,
IWL_UCODE_TLV_API_QUOTA_LOW_LATENCY = (__force iwl_ucode_tlv_api_t)38,
IWL_UCODE_TLV_API_DEPRECATE_TTAK = (__force iwl_ucode_tlv_api_t)41,
+ IWL_UCODE_TLV_API_ADAPTIVE_DWELL_V2 = (__force iwl_ucode_tlv_api_t)42,
NUM_IWL_UCODE_TLV_API
#ifdef __CHECKER__
@@ -441,6 +445,7 @@ enum iwl_fw_phy_cfg {
FW_PHY_CFG_TX_CHAIN = 0xf << FW_PHY_CFG_TX_CHAIN_POS,
FW_PHY_CFG_RX_CHAIN_POS = 20,
FW_PHY_CFG_RX_CHAIN = 0xf << FW_PHY_CFG_RX_CHAIN_POS,
+ FW_PHY_CFG_SHARED_CLK = BIT(31),
};
#define IWL_UCODE_MAX_CS 1
@@ -616,6 +621,14 @@ enum iwl_fw_dbg_trigger_mode {
};
/**
+ * enum iwl_fw_dbg_trigger_flags - the flags supported by wrt triggers
+ * @IWL_FW_DBG_FORCE_RESTART: force a firmware restart
+ */
+enum iwl_fw_dbg_trigger_flags {
+ IWL_FW_DBG_FORCE_RESTART = BIT(0),
+};
+
+/**
* enum iwl_fw_dbg_trigger_vif_type - define the VIF type for a trigger
* @IWL_FW_DBG_CONF_VIF_ANY: any vif type
* @IWL_FW_DBG_CONF_VIF_IBSS: IBSS mode
@@ -651,6 +664,7 @@ enum iwl_fw_dbg_trigger_vif_type {
* @occurrences: number of occurrences. 0 means the trigger will never fire.
* @trig_dis_ms: the time, in milliseconds, after an occurrence of this
* trigger in which another occurrence should be ignored.
+ * @flags: &enum iwl_fw_dbg_trigger_flags
*/
struct iwl_fw_dbg_trigger_tlv {
__le32 id;
@@ -661,7 +675,8 @@ struct iwl_fw_dbg_trigger_tlv {
u8 start_conf_id;
__le16 occurrences;
__le16 trig_dis_ms;
- __le16 reserved[3];
+ u8 flags;
+ u8 reserved[5];
u8 data[0];
} __packed;
diff --git a/drivers/net/wireless/intel/iwlwifi/iwl-config.h b/drivers/net/wireless/intel/iwlwifi/iwl-config.h
index 258d439bb0a9..f0f5636dd3ea 100644
--- a/drivers/net/wireless/intel/iwlwifi/iwl-config.h
+++ b/drivers/net/wireless/intel/iwlwifi/iwl-config.h
@@ -398,6 +398,7 @@ struct iwl_cfg {
u8 ucode_api_max;
u8 ucode_api_min;
u32 min_umac_error_event_table;
+ u32 extra_phy_cfg_flags;
};
/*
@@ -477,6 +478,10 @@ extern const struct iwl_cfg iwl9460_2ac_cfg_soc;
extern const struct iwl_cfg iwl9461_2ac_cfg_soc;
extern const struct iwl_cfg iwl9462_2ac_cfg_soc;
extern const struct iwl_cfg iwl9560_2ac_cfg_soc;
+extern const struct iwl_cfg iwl9460_2ac_cfg_shared_clk;
+extern const struct iwl_cfg iwl9461_2ac_cfg_shared_clk;
+extern const struct iwl_cfg iwl9462_2ac_cfg_shared_clk;
+extern const struct iwl_cfg iwl9560_2ac_cfg_shared_clk;
extern const struct iwl_cfg iwl22000_2ac_cfg_hr;
extern const struct iwl_cfg iwl22000_2ac_cfg_hr_cdb;
extern const struct iwl_cfg iwl22000_2ac_cfg_jf;
diff --git a/drivers/net/wireless/intel/iwlwifi/iwl-drv.c b/drivers/net/wireless/intel/iwlwifi/iwl-drv.c
index 9c4a7f648a44..aa2d5c14e202 100644
--- a/drivers/net/wireless/intel/iwlwifi/iwl-drv.c
+++ b/drivers/net/wireless/intel/iwlwifi/iwl-drv.c
@@ -1768,41 +1768,36 @@ static void __exit iwl_drv_exit(void)
module_exit(iwl_drv_exit);
#ifdef CONFIG_IWLWIFI_DEBUG
-module_param_named(debug, iwlwifi_mod_params.debug_level, uint,
- S_IRUGO | S_IWUSR);
+module_param_named(debug, iwlwifi_mod_params.debug_level, uint, 0644);
MODULE_PARM_DESC(debug, "debug output mask");
#endif
-module_param_named(swcrypto, iwlwifi_mod_params.swcrypto, int, S_IRUGO);
+module_param_named(swcrypto, iwlwifi_mod_params.swcrypto, int, 0444);
MODULE_PARM_DESC(swcrypto, "using crypto in software (default 0 [hardware])");
-module_param_named(11n_disable, iwlwifi_mod_params.disable_11n, uint, S_IRUGO);
+module_param_named(11n_disable, iwlwifi_mod_params.disable_11n, uint, 0444);
MODULE_PARM_DESC(11n_disable,
"disable 11n functionality, bitmap: 1: full, 2: disable agg TX, 4: disable agg RX, 8 enable agg TX");
-module_param_named(amsdu_size, iwlwifi_mod_params.amsdu_size,
- int, S_IRUGO);
+module_param_named(amsdu_size, iwlwifi_mod_params.amsdu_size, int, 0444);
MODULE_PARM_DESC(amsdu_size,
"amsdu size 0: 12K for multi Rx queue devices, 4K for other devices 1:4K 2:8K 3:12K (default 0)");
-module_param_named(fw_restart, iwlwifi_mod_params.fw_restart, bool, S_IRUGO);
+module_param_named(fw_restart, iwlwifi_mod_params.fw_restart, bool, 0444);
MODULE_PARM_DESC(fw_restart, "restart firmware in case of error (default true)");
module_param_named(antenna_coupling, iwlwifi_mod_params.antenna_coupling,
- int, S_IRUGO);
+ int, 0444);
MODULE_PARM_DESC(antenna_coupling,
"specify antenna coupling in dB (default: 0 dB)");
-module_param_named(nvm_file, iwlwifi_mod_params.nvm_file, charp, S_IRUGO);
+module_param_named(nvm_file, iwlwifi_mod_params.nvm_file, charp, 0444);
MODULE_PARM_DESC(nvm_file, "NVM file name");
-module_param_named(d0i3_disable, iwlwifi_mod_params.d0i3_disable,
- bool, S_IRUGO);
+module_param_named(d0i3_disable, iwlwifi_mod_params.d0i3_disable, bool, 0444);
MODULE_PARM_DESC(d0i3_disable, "disable d0i3 functionality (default: Y)");
-module_param_named(lar_disable, iwlwifi_mod_params.lar_disable,
- bool, S_IRUGO);
+module_param_named(lar_disable, iwlwifi_mod_params.lar_disable, bool, 0444);
MODULE_PARM_DESC(lar_disable, "disable LAR functionality (default: N)");
-module_param_named(uapsd_disable, iwlwifi_mod_params.uapsd_disable,
- uint, S_IRUGO | S_IWUSR);
+module_param_named(uapsd_disable, iwlwifi_mod_params.uapsd_disable, uint, 0644);
MODULE_PARM_DESC(uapsd_disable,
"disable U-APSD functionality bitmap 1: BSS 2: P2P Client (default: 3)");
@@ -1823,31 +1818,27 @@ MODULE_PARM_DESC(uapsd_disable,
* default: bt_coex_active = true (BT_COEX_ENABLE)
*/
module_param_named(bt_coex_active, iwlwifi_mod_params.bt_coex_active,
- bool, S_IRUGO);
+ bool, 0444);
MODULE_PARM_DESC(bt_coex_active, "enable wifi/bt co-exist (default: enable)");
-module_param_named(led_mode, iwlwifi_mod_params.led_mode, int, S_IRUGO);
+module_param_named(led_mode, iwlwifi_mod_params.led_mode, int, 0444);
MODULE_PARM_DESC(led_mode, "0=system default, "
"1=On(RF On)/Off(RF Off), 2=blinking, 3=Off (default: 0)");
-module_param_named(power_save, iwlwifi_mod_params.power_save,
- bool, S_IRUGO);
+module_param_named(power_save, iwlwifi_mod_params.power_save, bool, 0444);
MODULE_PARM_DESC(power_save,
"enable WiFi power management (default: disable)");
-module_param_named(power_level, iwlwifi_mod_params.power_level,
- int, S_IRUGO);
+module_param_named(power_level, iwlwifi_mod_params.power_level, int, 0444);
MODULE_PARM_DESC(power_level,
"default power save level (range from 1 - 5, default: 1)");
-module_param_named(fw_monitor, iwlwifi_mod_params.fw_monitor, bool, S_IRUGO);
+module_param_named(fw_monitor, iwlwifi_mod_params.fw_monitor, bool, 0444);
MODULE_PARM_DESC(fw_monitor,
"firmware monitor - to debug FW (default: false - needs lots of memory)");
-module_param_named(d0i3_timeout, iwlwifi_mod_params.d0i3_timeout,
- uint, S_IRUGO);
+module_param_named(d0i3_timeout, iwlwifi_mod_params.d0i3_timeout, uint, 0444);
MODULE_PARM_DESC(d0i3_timeout, "Timeout to D0i3 entry when idle (ms)");
-module_param_named(disable_11ac, iwlwifi_mod_params.disable_11ac, bool,
- S_IRUGO);
+module_param_named(disable_11ac, iwlwifi_mod_params.disable_11ac, bool, 0444);
MODULE_PARM_DESC(disable_11ac, "Disable VHT capabilities (default: false)");
diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/constants.h b/drivers/net/wireless/intel/iwlwifi/mvm/constants.h
index 976640fed334..96b52a275ee3 100644
--- a/drivers/net/wireless/intel/iwlwifi/mvm/constants.h
+++ b/drivers/net/wireless/intel/iwlwifi/mvm/constants.h
@@ -110,6 +110,8 @@
#define IWL_MVM_SW_TX_CSUM_OFFLOAD 0
#define IWL_MVM_HW_CSUM_DISABLE 0
#define IWL_MVM_PARSE_NVM 0
+#define IWL_MVM_ADWELL_ENABLE 1
+#define IWL_MVM_ADWELL_MAX_BUDGET 0
#define IWL_MVM_RS_NUM_TRY_BEFORE_ANT_TOGGLE 1
#define IWL_MVM_RS_HT_VHT_RETRIES_PER_RATE 2
#define IWL_MVM_RS_HT_VHT_RETRIES_PER_RATE_TW 1
diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/debugfs-vif.c b/drivers/net/wireless/intel/iwlwifi/mvm/debugfs-vif.c
index 4228fac77f41..f7fcf700196b 100644
--- a/drivers/net/wireless/intel/iwlwifi/mvm/debugfs-vif.c
+++ b/drivers/net/wireless/intel/iwlwifi/mvm/debugfs-vif.c
@@ -1276,7 +1276,6 @@ static ssize_t iwl_dbgfs_low_latency_write(struct ieee80211_vif *vif, char *buf,
{
struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
struct iwl_mvm *mvm = mvmvif->mvm;
- bool prev;
u8 value;
int ret;
@@ -1287,9 +1286,7 @@ static ssize_t iwl_dbgfs_low_latency_write(struct ieee80211_vif *vif, char *buf,
return -EINVAL;
mutex_lock(&mvm->mutex);
- prev = iwl_mvm_vif_low_latency(mvmvif);
- mvmvif->low_latency_dbgfs = value;
- iwl_mvm_update_low_latency(mvm, vif, prev);
+ iwl_mvm_update_low_latency(mvm, vif, value, LOW_LATENCY_DEBUGFS);
mutex_unlock(&mvm->mutex);
return count;
@@ -1306,9 +1303,9 @@ static ssize_t iwl_dbgfs_low_latency_read(struct file *file,
len = scnprintf(buf, sizeof(buf) - 1,
"traffic=%d\ndbgfs=%d\nvcmd=%d\n",
- mvmvif->low_latency_traffic,
- mvmvif->low_latency_dbgfs,
- mvmvif->low_latency_vcmd);
+ !!(mvmvif->low_latency & LOW_LATENCY_TRAFFIC),
+ !!(mvmvif->low_latency & LOW_LATENCY_DEBUGFS),
+ !!(mvmvif->low_latency & LOW_LATENCY_VCMD));
return simple_read_from_buffer(user_buf, count, ppos, buf, len);
}
@@ -1506,44 +1503,36 @@ void iwl_mvm_vif_dbgfs_register(struct iwl_mvm *mvm, struct ieee80211_vif *vif)
if (iwlmvm_mod_params.power_scheme != IWL_POWER_SCHEME_CAM &&
((vif->type == NL80211_IFTYPE_STATION && !vif->p2p) ||
(vif->type == NL80211_IFTYPE_STATION && vif->p2p)))
- MVM_DEBUGFS_ADD_FILE_VIF(pm_params, mvmvif->dbgfs_dir, S_IWUSR |
- S_IRUSR);
-
- MVM_DEBUGFS_ADD_FILE_VIF(tx_pwr_lmt, mvmvif->dbgfs_dir, S_IRUSR);
- MVM_DEBUGFS_ADD_FILE_VIF(mac_params, mvmvif->dbgfs_dir, S_IRUSR);
- MVM_DEBUGFS_ADD_FILE_VIF(low_latency, mvmvif->dbgfs_dir,
- S_IRUSR | S_IWUSR);
- MVM_DEBUGFS_ADD_FILE_VIF(uapsd_misbehaving, mvmvif->dbgfs_dir,
- S_IRUSR | S_IWUSR);
- MVM_DEBUGFS_ADD_FILE_VIF(rx_phyinfo, mvmvif->dbgfs_dir,
- S_IRUSR | S_IWUSR);
- MVM_DEBUGFS_ADD_FILE_VIF(quota_min, mvmvif->dbgfs_dir,
- S_IRUSR | S_IWUSR);
- MVM_DEBUGFS_ADD_FILE_VIF(os_device_timediff,
- mvmvif->dbgfs_dir, S_IRUSR);
+ MVM_DEBUGFS_ADD_FILE_VIF(pm_params, mvmvif->dbgfs_dir, 0600);
+
+ MVM_DEBUGFS_ADD_FILE_VIF(tx_pwr_lmt, mvmvif->dbgfs_dir, 0400);
+ MVM_DEBUGFS_ADD_FILE_VIF(mac_params, mvmvif->dbgfs_dir, 0400);
+ MVM_DEBUGFS_ADD_FILE_VIF(low_latency, mvmvif->dbgfs_dir, 0600);
+ MVM_DEBUGFS_ADD_FILE_VIF(uapsd_misbehaving, mvmvif->dbgfs_dir, 0600);
+ MVM_DEBUGFS_ADD_FILE_VIF(rx_phyinfo, mvmvif->dbgfs_dir, 0600);
+ MVM_DEBUGFS_ADD_FILE_VIF(quota_min, mvmvif->dbgfs_dir, 0600);
+ MVM_DEBUGFS_ADD_FILE_VIF(os_device_timediff, mvmvif->dbgfs_dir, 0400);
if (vif->type == NL80211_IFTYPE_STATION && !vif->p2p &&
mvmvif == mvm->bf_allowed_vif)
- MVM_DEBUGFS_ADD_FILE_VIF(bf_params, mvmvif->dbgfs_dir,
- S_IRUSR | S_IWUSR);
+ MVM_DEBUGFS_ADD_FILE_VIF(bf_params, mvmvif->dbgfs_dir, 0600);
if (fw_has_capa(&mvm->fw->ucode_capa, IWL_UCODE_TLV_CAPA_TOF_SUPPORT) &&
!vif->p2p && (vif->type != NL80211_IFTYPE_P2P_DEVICE)) {
if (IWL_MVM_TOF_IS_RESPONDER && vif->type == NL80211_IFTYPE_AP)
MVM_DEBUGFS_ADD_FILE_VIF(tof_responder_params,
- mvmvif->dbgfs_dir,
- S_IRUSR | S_IWUSR);
+ mvmvif->dbgfs_dir, 0600);
MVM_DEBUGFS_ADD_FILE_VIF(tof_range_request, mvmvif->dbgfs_dir,
- S_IRUSR | S_IWUSR);
+ 0600);
MVM_DEBUGFS_ADD_FILE_VIF(tof_range_req_ext, mvmvif->dbgfs_dir,
- S_IRUSR | S_IWUSR);
+ 0600);
MVM_DEBUGFS_ADD_FILE_VIF(tof_enable, mvmvif->dbgfs_dir,
- S_IRUSR | S_IWUSR);
+ 0600);
MVM_DEBUGFS_ADD_FILE_VIF(tof_range_abort, mvmvif->dbgfs_dir,
- S_IRUSR | S_IWUSR);
+ 0600);
MVM_DEBUGFS_ADD_FILE_VIF(tof_range_response, mvmvif->dbgfs_dir,
- S_IRUSR);
+ 0400);
}
/*
diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/debugfs.c b/drivers/net/wireless/intel/iwlwifi/mvm/debugfs.c
index 9c436d8d001d..0e6401cd7ccc 100644
--- a/drivers/net/wireless/intel/iwlwifi/mvm/debugfs.c
+++ b/drivers/net/wireless/intel/iwlwifi/mvm/debugfs.c
@@ -1914,7 +1914,7 @@ void iwl_mvm_sta_add_debugfs(struct ieee80211_hw *hw,
struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw);
if (iwl_mvm_has_tlc_offload(mvm))
- MVM_DEBUGFS_ADD_STA_FILE(rs_data, dir, S_IRUSR);
+ MVM_DEBUGFS_ADD_STA_FILE(rs_data, dir, 0400);
return;
err:
@@ -1930,48 +1930,45 @@ int iwl_mvm_dbgfs_register(struct iwl_mvm *mvm, struct dentry *dbgfs_dir)
mvm->debugfs_dir = dbgfs_dir;
- MVM_DEBUGFS_ADD_FILE(tx_flush, mvm->debugfs_dir, S_IWUSR);
- MVM_DEBUGFS_ADD_FILE(sta_drain, mvm->debugfs_dir, S_IWUSR);
- MVM_DEBUGFS_ADD_FILE(sram, mvm->debugfs_dir, S_IWUSR | S_IRUSR);
- MVM_DEBUGFS_ADD_FILE(set_nic_temperature, mvm->debugfs_dir,
- S_IWUSR | S_IRUSR);
- MVM_DEBUGFS_ADD_FILE(nic_temp, dbgfs_dir, S_IRUSR);
- MVM_DEBUGFS_ADD_FILE(ctdp_budget, dbgfs_dir, S_IRUSR);
- MVM_DEBUGFS_ADD_FILE(stop_ctdp, dbgfs_dir, S_IWUSR);
- MVM_DEBUGFS_ADD_FILE(force_ctkill, dbgfs_dir, S_IWUSR);
- MVM_DEBUGFS_ADD_FILE(stations, dbgfs_dir, S_IRUSR);
- MVM_DEBUGFS_ADD_FILE(bt_notif, dbgfs_dir, S_IRUSR);
- MVM_DEBUGFS_ADD_FILE(bt_cmd, dbgfs_dir, S_IRUSR);
- MVM_DEBUGFS_ADD_FILE(disable_power_off, mvm->debugfs_dir,
- S_IRUSR | S_IWUSR);
- MVM_DEBUGFS_ADD_FILE(fw_ver, mvm->debugfs_dir, S_IRUSR);
- MVM_DEBUGFS_ADD_FILE(fw_rx_stats, mvm->debugfs_dir, S_IRUSR);
- MVM_DEBUGFS_ADD_FILE(drv_rx_stats, mvm->debugfs_dir, S_IRUSR);
- MVM_DEBUGFS_ADD_FILE(fw_restart, mvm->debugfs_dir, S_IWUSR);
- MVM_DEBUGFS_ADD_FILE(fw_nmi, mvm->debugfs_dir, S_IWUSR);
- MVM_DEBUGFS_ADD_FILE(bt_tx_prio, mvm->debugfs_dir, S_IWUSR);
- MVM_DEBUGFS_ADD_FILE(bt_force_ant, mvm->debugfs_dir, S_IWUSR);
- MVM_DEBUGFS_ADD_FILE(scan_ant_rxchain, mvm->debugfs_dir,
- S_IWUSR | S_IRUSR);
- MVM_DEBUGFS_ADD_FILE(prph_reg, mvm->debugfs_dir, S_IWUSR | S_IRUSR);
- MVM_DEBUGFS_ADD_FILE(d0i3_refs, mvm->debugfs_dir, S_IRUSR | S_IWUSR);
- MVM_DEBUGFS_ADD_FILE(fw_dbg_conf, mvm->debugfs_dir, S_IRUSR | S_IWUSR);
- MVM_DEBUGFS_ADD_FILE(fw_dbg_collect, mvm->debugfs_dir, S_IWUSR);
- MVM_DEBUGFS_ADD_FILE(max_amsdu_len, mvm->debugfs_dir, S_IWUSR);
- MVM_DEBUGFS_ADD_FILE(send_echo_cmd, mvm->debugfs_dir, S_IWUSR);
- MVM_DEBUGFS_ADD_FILE(cont_recording, mvm->debugfs_dir, S_IWUSR);
- MVM_DEBUGFS_ADD_FILE(indirection_tbl, mvm->debugfs_dir, S_IWUSR);
- MVM_DEBUGFS_ADD_FILE(inject_packet, mvm->debugfs_dir, S_IWUSR);
+ MVM_DEBUGFS_ADD_FILE(tx_flush, mvm->debugfs_dir, 0200);
+ MVM_DEBUGFS_ADD_FILE(sta_drain, mvm->debugfs_dir, 0200);
+ MVM_DEBUGFS_ADD_FILE(sram, mvm->debugfs_dir, 0600);
+ MVM_DEBUGFS_ADD_FILE(set_nic_temperature, mvm->debugfs_dir, 0600);
+ MVM_DEBUGFS_ADD_FILE(nic_temp, dbgfs_dir, 0400);
+ MVM_DEBUGFS_ADD_FILE(ctdp_budget, dbgfs_dir, 0400);
+ MVM_DEBUGFS_ADD_FILE(stop_ctdp, dbgfs_dir, 0200);
+ MVM_DEBUGFS_ADD_FILE(force_ctkill, dbgfs_dir, 0200);
+ MVM_DEBUGFS_ADD_FILE(stations, dbgfs_dir, 0400);
+ MVM_DEBUGFS_ADD_FILE(bt_notif, dbgfs_dir, 0400);
+ MVM_DEBUGFS_ADD_FILE(bt_cmd, dbgfs_dir, 0400);
+ MVM_DEBUGFS_ADD_FILE(disable_power_off, mvm->debugfs_dir, 0600);
+ MVM_DEBUGFS_ADD_FILE(fw_ver, mvm->debugfs_dir, 0400);
+ MVM_DEBUGFS_ADD_FILE(fw_rx_stats, mvm->debugfs_dir, 0400);
+ MVM_DEBUGFS_ADD_FILE(drv_rx_stats, mvm->debugfs_dir, 0400);
+ MVM_DEBUGFS_ADD_FILE(fw_restart, mvm->debugfs_dir, 0200);
+ MVM_DEBUGFS_ADD_FILE(fw_nmi, mvm->debugfs_dir, 0200);
+ MVM_DEBUGFS_ADD_FILE(bt_tx_prio, mvm->debugfs_dir, 0200);
+ MVM_DEBUGFS_ADD_FILE(bt_force_ant, mvm->debugfs_dir, 0200);
+ MVM_DEBUGFS_ADD_FILE(scan_ant_rxchain, mvm->debugfs_dir, 0600);
+ MVM_DEBUGFS_ADD_FILE(prph_reg, mvm->debugfs_dir, 0600);
+ MVM_DEBUGFS_ADD_FILE(d0i3_refs, mvm->debugfs_dir, 0600);
+ MVM_DEBUGFS_ADD_FILE(fw_dbg_conf, mvm->debugfs_dir, 0600);
+ MVM_DEBUGFS_ADD_FILE(fw_dbg_collect, mvm->debugfs_dir, 0200);
+ MVM_DEBUGFS_ADD_FILE(max_amsdu_len, mvm->debugfs_dir, 0200);
+ MVM_DEBUGFS_ADD_FILE(send_echo_cmd, mvm->debugfs_dir, 0200);
+ MVM_DEBUGFS_ADD_FILE(cont_recording, mvm->debugfs_dir, 0200);
+ MVM_DEBUGFS_ADD_FILE(indirection_tbl, mvm->debugfs_dir, 0200);
+ MVM_DEBUGFS_ADD_FILE(inject_packet, mvm->debugfs_dir, 0200);
#ifdef CONFIG_ACPI
- MVM_DEBUGFS_ADD_FILE(sar_geo_profile, dbgfs_dir, S_IRUSR);
+ MVM_DEBUGFS_ADD_FILE(sar_geo_profile, dbgfs_dir, 0400);
#endif
if (!debugfs_create_bool("enable_scan_iteration_notif",
- S_IRUSR | S_IWUSR,
+ 0600,
mvm->debugfs_dir,
&mvm->scan_iter_notif_enabled))
goto err;
- if (!debugfs_create_bool("drop_bcn_ap_mode", S_IRUSR | S_IWUSR,
+ if (!debugfs_create_bool("drop_bcn_ap_mode", 0600,
mvm->debugfs_dir, &mvm->drop_bcn_ap_mode))
goto err;
@@ -1982,50 +1979,49 @@ int iwl_mvm_dbgfs_register(struct iwl_mvm *mvm, struct dentry *dbgfs_dir)
if (!bcast_dir)
goto err;
- if (!debugfs_create_bool("override", S_IRUSR | S_IWUSR,
- bcast_dir,
- &mvm->dbgfs_bcast_filtering.override))
+ if (!debugfs_create_bool("override", 0600,
+ bcast_dir,
+ &mvm->dbgfs_bcast_filtering.override))
goto err;
MVM_DEBUGFS_ADD_FILE_ALIAS("filters", bcast_filters,
- bcast_dir, S_IWUSR | S_IRUSR);
+ bcast_dir, 0600);
MVM_DEBUGFS_ADD_FILE_ALIAS("macs", bcast_filters_macs,
- bcast_dir, S_IWUSR | S_IRUSR);
+ bcast_dir, 0600);
}
#endif
#ifdef CONFIG_PM_SLEEP
- MVM_DEBUGFS_ADD_FILE(d3_sram, mvm->debugfs_dir, S_IRUSR | S_IWUSR);
- MVM_DEBUGFS_ADD_FILE(d3_test, mvm->debugfs_dir, S_IRUSR);
- if (!debugfs_create_bool("d3_wake_sysassert", S_IRUSR | S_IWUSR,
+ MVM_DEBUGFS_ADD_FILE(d3_sram, mvm->debugfs_dir, 0600);
+ MVM_DEBUGFS_ADD_FILE(d3_test, mvm->debugfs_dir, 0400);
+ if (!debugfs_create_bool("d3_wake_sysassert", 0600,
mvm->debugfs_dir, &mvm->d3_wake_sysassert))
goto err;
- if (!debugfs_create_u32("last_netdetect_scans", S_IRUSR,
+ if (!debugfs_create_u32("last_netdetect_scans", 0400,
mvm->debugfs_dir, &mvm->last_netdetect_scans))
goto err;
#endif
- if (!debugfs_create_u8("ps_disabled", S_IRUSR,
+ if (!debugfs_create_u8("ps_disabled", 0400,
mvm->debugfs_dir, &mvm->ps_disabled))
goto err;
- if (!debugfs_create_blob("nvm_hw", S_IRUSR,
- mvm->debugfs_dir, &mvm->nvm_hw_blob))
+ if (!debugfs_create_blob("nvm_hw", 0400,
+ mvm->debugfs_dir, &mvm->nvm_hw_blob))
goto err;
- if (!debugfs_create_blob("nvm_sw", S_IRUSR,
- mvm->debugfs_dir, &mvm->nvm_sw_blob))
+ if (!debugfs_create_blob("nvm_sw", 0400,
+ mvm->debugfs_dir, &mvm->nvm_sw_blob))
goto err;
- if (!debugfs_create_blob("nvm_calib", S_IRUSR,
- mvm->debugfs_dir, &mvm->nvm_calib_blob))
+ if (!debugfs_create_blob("nvm_calib", 0400,
+ mvm->debugfs_dir, &mvm->nvm_calib_blob))
goto err;
- if (!debugfs_create_blob("nvm_prod", S_IRUSR,
- mvm->debugfs_dir, &mvm->nvm_prod_blob))
+ if (!debugfs_create_blob("nvm_prod", 0400,
+ mvm->debugfs_dir, &mvm->nvm_prod_blob))
goto err;
- if (!debugfs_create_blob("nvm_phy_sku", S_IRUSR,
+ if (!debugfs_create_blob("nvm_phy_sku", 0400,
mvm->debugfs_dir, &mvm->nvm_phy_sku_blob))
goto err;
- debugfs_create_file("mem", S_IRUSR | S_IWUSR, dbgfs_dir, mvm,
- &iwl_dbgfs_mem_ops);
+ debugfs_create_file("mem", 0600, dbgfs_dir, mvm, &iwl_dbgfs_mem_ops);
/*
* Create a symlink with mac80211. It will be removed when mac80211
diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/fw.c b/drivers/net/wireless/intel/iwlwifi/mvm/fw.c
index 0920be637b57..3c59109bea20 100644
--- a/drivers/net/wireless/intel/iwlwifi/mvm/fw.c
+++ b/drivers/net/wireless/intel/iwlwifi/mvm/fw.c
@@ -433,6 +433,10 @@ static int iwl_send_phy_cfg_cmd(struct iwl_mvm *mvm)
/* Set parameters */
phy_cfg_cmd.phy_cfg = cpu_to_le32(iwl_mvm_get_phy_config(mvm));
+
+ /* set flags extra PHY configuration flags from the device's cfg */
+ phy_cfg_cmd.phy_cfg |= cpu_to_le32(mvm->cfg->extra_phy_cfg_flags);
+
phy_cfg_cmd.calib_control.event_trigger =
mvm->fw->default_calib[ucode_type].event_trigger;
phy_cfg_cmd.calib_control.flow_trigger =
diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c b/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c
index ebf511150f4d..51b30424575b 100644
--- a/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c
+++ b/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c
@@ -421,6 +421,7 @@ int iwl_mvm_mac_setup_register(struct iwl_mvm *mvm)
ieee80211_hw_set(hw, SUPPORTS_CLONED_SKBS);
ieee80211_hw_set(hw, SUPPORTS_AMSDU_IN_AMPDU);
ieee80211_hw_set(hw, NEEDS_UNIQUE_STA_ADDR);
+ ieee80211_hw_set(hw, DEAUTH_NEED_MGD_TX_PREP);
if (iwl_mvm_has_tlc_offload(mvm)) {
ieee80211_hw_set(hw, TX_AMPDU_SETUP_IN_HW);
@@ -661,6 +662,17 @@ int iwl_mvm_mac_setup_register(struct iwl_mvm *mvm)
NL80211_EXT_FEATURE_SET_SCAN_DWELL);
}
+ if (iwl_mvm_is_oce_supported(mvm)) {
+ wiphy_ext_feature_set(hw->wiphy,
+ NL80211_EXT_FEATURE_ACCEPT_BCAST_PROBE_RESP);
+ wiphy_ext_feature_set(hw->wiphy,
+ NL80211_EXT_FEATURE_FILS_MAX_CHANNEL_TIME);
+ wiphy_ext_feature_set(hw->wiphy,
+ NL80211_EXT_FEATURE_OCE_PROBE_REQ_DEFERRAL_SUPPRESSION);
+ wiphy_ext_feature_set(hw->wiphy,
+ NL80211_EXT_FEATURE_OCE_PROBE_REQ_HIGH_TX_RATE);
+ }
+
mvm->rts_threshold = IEEE80211_MAX_RTS_THRESHOLD;
#ifdef CONFIG_PM_SLEEP
@@ -2132,10 +2144,10 @@ static int iwl_mvm_start_ap_ibss(struct ieee80211_hw *hw,
* Send the bcast station. At this stage the TBTT and DTIM time
* events are added and applied to the scheduler
*/
- iwl_mvm_send_add_bcast_sta(mvm, vif);
+ ret = iwl_mvm_send_add_bcast_sta(mvm, vif);
if (ret)
goto out_unbind;
- iwl_mvm_add_mcast_sta(mvm, vif);
+ ret = iwl_mvm_add_mcast_sta(mvm, vif);
if (ret) {
iwl_mvm_send_rm_bcast_sta(mvm, vif);
goto out_unbind;
@@ -2804,9 +2816,6 @@ static void iwl_mvm_mac_mgd_prepare_tx(struct ieee80211_hw *hw,
u32 duration = IWL_MVM_TE_SESSION_PROTECTION_MAX_TIME_MS;
u32 min_duration = IWL_MVM_TE_SESSION_PROTECTION_MIN_TIME_MS;
- if (WARN_ON_ONCE(vif->bss_conf.assoc))
- return;
-
/*
* iwl_mvm_protect_session() reads directly from the device
* (the system time), so make sure it is available.
@@ -3494,6 +3503,7 @@ static int __iwl_mvm_assign_vif_chanctx(struct iwl_mvm *mvm,
ret = 0;
goto out;
case NL80211_IFTYPE_STATION:
+ mvmvif->csa_bcn_pending = false;
break;
case NL80211_IFTYPE_MONITOR:
/* always disable PS when a monitor interface is active */
@@ -3537,7 +3547,7 @@ static int __iwl_mvm_assign_vif_chanctx(struct iwl_mvm *mvm,
}
if (switching_chanctx && vif->type == NL80211_IFTYPE_STATION) {
- u32 duration = 2 * vif->bss_conf.beacon_int;
+ u32 duration = 3 * vif->bss_conf.beacon_int;
/* iwl_mvm_protect_session() reads directly from the
* device (the system time), so make sure it is
@@ -3550,6 +3560,7 @@ static int __iwl_mvm_assign_vif_chanctx(struct iwl_mvm *mvm,
/* Protect the session to make sure we hear the first
* beacon on the new channel.
*/
+ mvmvif->csa_bcn_pending = true;
iwl_mvm_protect_session(mvm, vif, duration, duration,
vif->bss_conf.beacon_int / 2,
true);
@@ -3988,6 +3999,7 @@ static int iwl_mvm_post_channel_switch(struct ieee80211_hw *hw,
if (vif->type == NL80211_IFTYPE_STATION) {
struct iwl_mvm_sta *mvmsta;
+ mvmvif->csa_bcn_pending = false;
mvmsta = iwl_mvm_sta_from_staid_protected(mvm,
mvmvif->ap_sta_id);
diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h b/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h
index 89ff02d7c876..d2cf751db68d 100644
--- a/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h
+++ b/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h
@@ -300,6 +300,18 @@ enum iwl_bt_force_ant_mode {
};
/**
+* struct iwl_mvm_low_latency_cause - low latency set causes
+* @LOW_LATENCY_TRAFFIC: indicates low latency traffic was detected
+* @LOW_LATENCY_DEBUGFS: low latency mode set from debugfs
+* @LOW_LATENCY_VCMD: low latency mode set from vendor command
+*/
+enum iwl_mvm_low_latency_cause {
+ LOW_LATENCY_TRAFFIC = BIT(0),
+ LOW_LATENCY_DEBUGFS = BIT(1),
+ LOW_LATENCY_VCMD = BIT(2),
+};
+
+/**
* struct iwl_mvm_vif_bf_data - beacon filtering related data
* @bf_enabled: indicates if beacon filtering is enabled
* @ba_enabled: indicated if beacon abort is enabled
@@ -335,9 +347,8 @@ struct iwl_mvm_vif_bf_data {
* @pm_enabled - Indicate if MAC power management is allowed
* @monitor_active: indicates that monitor context is configured, and that the
* interface should get quota etc.
- * @low_latency_traffic: indicates low latency traffic was detected
- * @low_latency_dbgfs: low latency mode set from debugfs
- * @low_latency_vcmd: low latency mode set from vendor command
+ * @low_latency: indicates low latency is set, see
+ * enum &iwl_mvm_low_latency_cause for causes.
* @ps_disabled: indicates that this interface requires PS to be disabled
* @queue_params: QoS params for this MAC
* @bcast_sta: station used for broadcast packets. Used by the following
@@ -367,7 +378,7 @@ struct iwl_mvm_vif {
bool ap_ibss_active;
bool pm_enabled;
bool monitor_active;
- bool low_latency_traffic, low_latency_dbgfs, low_latency_vcmd;
+ u8 low_latency;
bool ps_disabled;
struct iwl_mvm_vif_bf_data bf_data;
@@ -438,6 +449,9 @@ struct iwl_mvm_vif {
bool csa_failed;
u16 csa_target_freq;
+ /* Indicates that we are waiting for a beacon on a new channel */
+ bool csa_bcn_pending;
+
/* TCP Checksum Offload */
netdev_features_t features;
};
@@ -1152,6 +1166,18 @@ static inline bool iwl_mvm_is_adaptive_dwell_supported(struct iwl_mvm *mvm)
IWL_UCODE_TLV_API_ADAPTIVE_DWELL);
}
+static inline bool iwl_mvm_is_adaptive_dwell_v2_supported(struct iwl_mvm *mvm)
+{
+ return fw_has_api(&mvm->fw->ucode_capa,
+ IWL_UCODE_TLV_API_ADAPTIVE_DWELL_V2);
+}
+
+static inline bool iwl_mvm_is_oce_supported(struct iwl_mvm *mvm)
+{
+ /* OCE should never be enabled for LMAC scan FWs */
+ return fw_has_api(&mvm->fw->ucode_capa, IWL_UCODE_TLV_API_OCE);
+}
+
static inline bool iwl_mvm_enter_d0i3_on_suspend(struct iwl_mvm *mvm)
{
/* For now we only use this mode to differentiate between
@@ -1741,7 +1767,8 @@ bool iwl_mvm_rx_diversity_allowed(struct iwl_mvm *mvm);
/* Low latency */
int iwl_mvm_update_low_latency(struct iwl_mvm *mvm, struct ieee80211_vif *vif,
- bool value);
+ bool low_latency,
+ enum iwl_mvm_low_latency_cause cause);
/* get SystemLowLatencyMode - only needed for beacon threshold? */
bool iwl_mvm_low_latency(struct iwl_mvm *mvm);
/* get VMACLowLatencyMode */
@@ -1757,9 +1784,17 @@ static inline bool iwl_mvm_vif_low_latency(struct iwl_mvm_vif *mvmvif)
* binding, so this has no real impact. For now, just return
* the current desired low-latency state.
*/
- return mvmvif->low_latency_dbgfs ||
- mvmvif->low_latency_traffic ||
- mvmvif->low_latency_vcmd;
+ return mvmvif->low_latency;
+}
+
+static inline
+void iwl_mvm_vif_set_low_latency(struct iwl_mvm_vif *mvmvif, bool set,
+ enum iwl_mvm_low_latency_cause cause)
+{
+ if (set)
+ mvmvif->low_latency |= cause;
+ else
+ mvmvif->low_latency &= ~cause;
}
/* hw scheduler queue config */
diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/ops.c b/drivers/net/wireless/intel/iwlwifi/mvm/ops.c
index ab7fb5aad984..224bfa1bcf53 100644
--- a/drivers/net/wireless/intel/iwlwifi/mvm/ops.c
+++ b/drivers/net/wireless/intel/iwlwifi/mvm/ops.c
@@ -104,14 +104,14 @@ struct iwl_mvm_mod_params iwlmvm_mod_params = {
/* rest of fields are 0 by default */
};
-module_param_named(init_dbg, iwlmvm_mod_params.init_dbg, bool, S_IRUGO);
+module_param_named(init_dbg, iwlmvm_mod_params.init_dbg, bool, 0444);
MODULE_PARM_DESC(init_dbg,
"set to true to debug an ASSERT in INIT fw (default: false");
-module_param_named(power_scheme, iwlmvm_mod_params.power_scheme, int, S_IRUGO);
+module_param_named(power_scheme, iwlmvm_mod_params.power_scheme, int, 0444);
MODULE_PARM_DESC(power_scheme,
"power management scheme: 1-active, 2-balanced, 3-low power, default: 2");
module_param_named(tfd_q_hang_detect, iwlmvm_mod_params.tfd_q_hang_detect,
- bool, S_IRUGO);
+ bool, 0444);
MODULE_PARM_DESC(tfd_q_hang_detect,
"TFD queues hang detection (default: true");
diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/phy-ctxt.c b/drivers/net/wireless/intel/iwlwifi/mvm/phy-ctxt.c
index 305cd56bf746..7f5434b34d0d 100644
--- a/drivers/net/wireless/intel/iwlwifi/mvm/phy-ctxt.c
+++ b/drivers/net/wireless/intel/iwlwifi/mvm/phy-ctxt.c
@@ -8,6 +8,7 @@
* Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved.
* Copyright(c) 2013 - 2014 Intel Mobile Communications GmbH
* Copyright(c) 2017 Intel Deutschland GmbH
+ * Copyright(c) 2018 Intel Corporation
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of version 2 of the GNU General Public License as
@@ -18,11 +19,6 @@
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110,
- * USA
- *
* The full GNU General Public License is included in this distribution
* in the file called COPYING.
*
@@ -34,6 +30,7 @@
*
* Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved.
* Copyright(c) 2013 - 2014 Intel Mobile Communications GmbH
+ * Copyright(c) 2018 Intel Corporation
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -286,6 +283,20 @@ void iwl_mvm_phy_ctxt_unref(struct iwl_mvm *mvm, struct iwl_mvm_phy_ctxt *ctxt)
return;
ctxt->ref--;
+
+ /*
+ * Move unused phy's to a default channel. When the phy is moved the,
+ * fw will cleanup immediate quiet bit if it was previously set,
+ * otherwise we might not be able to reuse this phy.
+ */
+ if (ctxt->ref == 0) {
+ struct ieee80211_channel *chan;
+ struct cfg80211_chan_def chandef;
+
+ chan = &mvm->hw->wiphy->bands[NL80211_BAND_2GHZ]->channels[0];
+ cfg80211_chandef_create(&chandef, chan, NL80211_CHAN_NO_HT);
+ iwl_mvm_phy_ctxt_changed(mvm, ctxt, &chandef, 1, 1);
+ }
}
static void iwl_mvm_binding_iterator(void *_data, u8 *mac,
diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/rs-fw.c b/drivers/net/wireless/intel/iwlwifi/mvm/rs-fw.c
index 55d1274c6092..fb5745660509 100644
--- a/drivers/net/wireless/intel/iwlwifi/mvm/rs-fw.c
+++ b/drivers/net/wireless/intel/iwlwifi/mvm/rs-fw.c
@@ -234,13 +234,15 @@ void iwl_mvm_tlc_update_notif(struct iwl_mvm *mvm, struct iwl_rx_packet *pkt)
struct iwl_mvm_sta *mvmsta;
struct iwl_lq_sta_rs_fw *lq_sta;
+ rcu_read_lock();
+
notif = (void *)pkt->data;
mvmsta = iwl_mvm_sta_from_staid_rcu(mvm, notif->sta_id);
if (!mvmsta) {
IWL_ERR(mvm, "Invalid sta id (%d) in FW TLC notification\n",
notif->sta_id);
- return;
+ goto out;
}
lq_sta = &mvmsta->lq_sta.rs_fw;
@@ -251,6 +253,8 @@ void iwl_mvm_tlc_update_notif(struct iwl_mvm *mvm, struct iwl_rx_packet *pkt)
IWL_DEBUG_RATE(mvm, "new rate_n_flags: 0x%X\n",
lq_sta->last_rate_n_flags);
}
+out:
+ rcu_read_unlock();
}
void rs_fw_rate_init(struct iwl_mvm *mvm, struct ieee80211_sta *sta,
diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/rs.c b/drivers/net/wireless/intel/iwlwifi/mvm/rs.c
index 47f4c7a1d80d..5d776ec1840f 100644
--- a/drivers/net/wireless/intel/iwlwifi/mvm/rs.c
+++ b/drivers/net/wireless/intel/iwlwifi/mvm/rs.c
@@ -4010,18 +4010,18 @@ static void rs_drv_add_sta_debugfs(void *mvm, void *priv_sta,
if (!mvmsta->vif)
return;
- debugfs_create_file("rate_scale_table", S_IRUSR | S_IWUSR, dir,
+ debugfs_create_file("rate_scale_table", 0600, dir,
lq_sta, &rs_sta_dbgfs_scale_table_ops);
- debugfs_create_file("rate_stats_table", S_IRUSR, dir,
+ debugfs_create_file("rate_stats_table", 0400, dir,
lq_sta, &rs_sta_dbgfs_stats_table_ops);
- debugfs_create_file("drv_tx_stats", S_IRUSR | S_IWUSR, dir,
+ debugfs_create_file("drv_tx_stats", 0600, dir,
lq_sta, &rs_sta_dbgfs_drv_tx_stats_ops);
- debugfs_create_u8("tx_agg_tid_enable", S_IRUSR | S_IWUSR, dir,
+ debugfs_create_u8("tx_agg_tid_enable", 0600, dir,
&lq_sta->tx_agg_tid_en);
- debugfs_create_u8("reduced_tpc", S_IRUSR | S_IWUSR, dir,
+ debugfs_create_u8("reduced_tpc", 0600, dir,
&lq_sta->pers.dbg_fixed_txp_reduction);
- MVM_DEBUGFS_ADD_FILE_RS(ss_force, dir, S_IRUSR | S_IWUSR);
+ MVM_DEBUGFS_ADD_FILE_RS(ss_force, dir, 0600);
return;
err:
IWL_ERR((struct iwl_mvm *)mvm, "Can't create debugfs entity\n");
diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/rxmq.c b/drivers/net/wireless/intel/iwlwifi/mvm/rxmq.c
index 580de5851fc7..4a4ccfd11e5b 100644
--- a/drivers/net/wireless/intel/iwlwifi/mvm/rxmq.c
+++ b/drivers/net/wireless/intel/iwlwifi/mvm/rxmq.c
@@ -831,6 +831,16 @@ out:
rcu_read_unlock();
}
+static void iwl_mvm_flip_address(u8 *addr)
+{
+ int i;
+ u8 mac_addr[ETH_ALEN];
+
+ for (i = 0; i < ETH_ALEN; i++)
+ mac_addr[i] = addr[ETH_ALEN - i - 1];
+ ether_addr_copy(addr, mac_addr);
+}
+
void iwl_mvm_rx_mpdu_mq(struct iwl_mvm *mvm, struct napi_struct *napi,
struct iwl_rx_cmd_buffer *rxb, int queue)
{
@@ -985,21 +995,16 @@ void iwl_mvm_rx_mpdu_mq(struct iwl_mvm *mvm, struct napi_struct *napi,
*/
if ((desc->mac_flags2 & IWL_RX_MPDU_MFLG2_AMSDU) &&
!WARN_ON(!ieee80211_is_data_qos(hdr->frame_control))) {
- int i;
u8 *qc = ieee80211_get_qos_ctl(hdr);
- u8 mac_addr[ETH_ALEN];
*qc &= ~IEEE80211_QOS_CTL_A_MSDU_PRESENT;
- for (i = 0; i < ETH_ALEN; i++)
- mac_addr[i] = hdr->addr3[ETH_ALEN - i - 1];
- ether_addr_copy(hdr->addr3, mac_addr);
+ if (mvm->trans->cfg->device_family ==
+ IWL_DEVICE_FAMILY_9000) {
+ iwl_mvm_flip_address(hdr->addr3);
- if (ieee80211_has_a4(hdr->frame_control)) {
- for (i = 0; i < ETH_ALEN; i++)
- mac_addr[i] =
- hdr->addr4[ETH_ALEN - i - 1];
- ether_addr_copy(hdr->addr4, mac_addr);
+ if (ieee80211_has_a4(hdr->frame_control))
+ iwl_mvm_flip_address(hdr->addr4);
}
}
if (baid != IWL_RX_REORDER_DATA_INVALID_BAID) {
diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/scan.c b/drivers/net/wireless/intel/iwlwifi/mvm/scan.c
index 356b16f40e78..b31f0ffbbbf0 100644
--- a/drivers/net/wireless/intel/iwlwifi/mvm/scan.c
+++ b/drivers/net/wireless/intel/iwlwifi/mvm/scan.c
@@ -35,6 +35,7 @@
* Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved.
* Copyright(c) 2013 - 2015 Intel Mobile Communications GmbH
* Copyright(c) 2016 - 2017 Intel Deutschland GmbH
+ * Copyright(c) 2018 Intel Corporation
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -85,6 +86,17 @@ enum iwl_mvm_traffic_load {
#define IWL_SCAN_DWELL_PASSIVE 110
#define IWL_SCAN_DWELL_FRAGMENTED 44
#define IWL_SCAN_DWELL_EXTENDED 90
+#define IWL_SCAN_NUM_OF_FRAGS 3
+
+
+/* adaptive dwell max budget time [TU] for full scan */
+#define IWL_SCAN_ADWELL_MAX_BUDGET_FULL_SCAN 300
+/* adaptive dwell max budget time [TU] for directed scan */
+#define IWL_SCAN_ADWELL_MAX_BUDGET_DIRECTED_SCAN 100
+/* adaptive dwell default APs number */
+#define IWL_SCAN_ADWELL_DEFAULT_N_APS 2
+/* adaptive dwell default APs number in social channels (1, 6, 11) */
+#define IWL_SCAN_ADWELL_DEFAULT_N_APS_SOCIAL 10
struct iwl_mvm_scan_timing_params {
u32 suspend_time;
@@ -134,6 +146,9 @@ static inline void *iwl_mvm_get_scan_req_umac_data(struct iwl_mvm *mvm)
{
struct iwl_scan_req_umac *cmd = mvm->scan_cmd;
+ if (iwl_mvm_is_adaptive_dwell_v2_supported(mvm))
+ return (void *)&cmd->v8.data;
+
if (iwl_mvm_is_adaptive_dwell_supported(mvm))
return (void *)&cmd->v7.data;
@@ -143,6 +158,23 @@ static inline void *iwl_mvm_get_scan_req_umac_data(struct iwl_mvm *mvm)
return (void *)&cmd->v1.data;
}
+static inline struct iwl_scan_umac_chan_param *
+iwl_mvm_get_scan_req_umac_channel(struct iwl_mvm *mvm)
+{
+ struct iwl_scan_req_umac *cmd = mvm->scan_cmd;
+
+ if (iwl_mvm_is_adaptive_dwell_v2_supported(mvm))
+ return &cmd->v8.channel;
+
+ if (iwl_mvm_is_adaptive_dwell_supported(mvm))
+ return &cmd->v7.channel;
+
+ if (iwl_mvm_has_new_tx_api(mvm))
+ return &cmd->v6.channel;
+
+ return &cmd->v1.channel;
+}
+
static u8 iwl_mvm_scan_rx_ant(struct iwl_mvm *mvm)
{
if (mvm->scan_rx_ant != ANT_NONE)
@@ -1113,66 +1145,92 @@ static void iwl_mvm_scan_umac_dwell(struct iwl_mvm *mvm,
struct iwl_scan_req_umac *cmd,
struct iwl_mvm_scan_params *params)
{
- struct iwl_mvm_scan_timing_params *timing = &scan_timing[params->type];
+ struct iwl_mvm_scan_timing_params *timing, *hb_timing;
+ u8 active_dwell, passive_dwell;
- if (iwl_mvm_is_regular_scan(params))
- cmd->ooc_priority = cpu_to_le32(IWL_SCAN_PRIORITY_EXT_6);
- else
- cmd->ooc_priority = cpu_to_le32(IWL_SCAN_PRIORITY_EXT_2);
+ timing = &scan_timing[params->type];
+ active_dwell = params->measurement_dwell ?
+ params->measurement_dwell : IWL_SCAN_DWELL_ACTIVE;
+ passive_dwell = params->measurement_dwell ?
+ params->measurement_dwell : IWL_SCAN_DWELL_PASSIVE;
if (iwl_mvm_is_adaptive_dwell_supported(mvm)) {
- if (params->measurement_dwell) {
- cmd->v7.active_dwell = params->measurement_dwell;
- cmd->v7.passive_dwell = params->measurement_dwell;
- } else {
- cmd->v7.active_dwell = IWL_SCAN_DWELL_ACTIVE;
- cmd->v7.passive_dwell = IWL_SCAN_DWELL_PASSIVE;
- }
- cmd->v7.fragmented_dwell = IWL_SCAN_DWELL_FRAGMENTED;
+ cmd->v7.adwell_default_n_aps_social =
+ IWL_SCAN_ADWELL_DEFAULT_N_APS_SOCIAL;
+ cmd->v7.adwell_default_n_aps =
+ IWL_SCAN_ADWELL_DEFAULT_N_APS;
+
+ /* if custom max budget was configured with debugfs */
+ if (IWL_MVM_ADWELL_MAX_BUDGET)
+ cmd->v7.adwell_max_budget =
+ cpu_to_le16(IWL_MVM_ADWELL_MAX_BUDGET);
+ else if (params->ssids && params->ssids[0].ssid_len)
+ cmd->v7.adwell_max_budget =
+ cpu_to_le16(IWL_SCAN_ADWELL_MAX_BUDGET_DIRECTED_SCAN);
+ else
+ cmd->v7.adwell_max_budget =
+ cpu_to_le16(IWL_SCAN_ADWELL_MAX_BUDGET_FULL_SCAN);
cmd->v7.scan_priority = cpu_to_le32(IWL_SCAN_PRIORITY_EXT_6);
cmd->v7.max_out_time[SCAN_LB_LMAC_IDX] =
cpu_to_le32(timing->max_out_time);
cmd->v7.suspend_time[SCAN_LB_LMAC_IDX] =
cpu_to_le32(timing->suspend_time);
+
if (iwl_mvm_is_cdb_supported(mvm)) {
+ hb_timing = &scan_timing[params->type];
+
cmd->v7.max_out_time[SCAN_HB_LMAC_IDX] =
- cpu_to_le32(timing->max_out_time);
+ cpu_to_le32(hb_timing->max_out_time);
cmd->v7.suspend_time[SCAN_HB_LMAC_IDX] =
- cpu_to_le32(timing->suspend_time);
+ cpu_to_le32(hb_timing->suspend_time);
}
- return;
- }
-
- if (params->measurement_dwell) {
- cmd->v1.active_dwell = params->measurement_dwell;
- cmd->v1.passive_dwell = params->measurement_dwell;
- cmd->v1.extended_dwell = params->measurement_dwell;
+ if (!iwl_mvm_is_adaptive_dwell_v2_supported(mvm)) {
+ cmd->v7.active_dwell = active_dwell;
+ cmd->v7.passive_dwell = passive_dwell;
+ cmd->v7.fragmented_dwell = IWL_SCAN_DWELL_FRAGMENTED;
+ } else {
+ cmd->v8.active_dwell[SCAN_LB_LMAC_IDX] = active_dwell;
+ cmd->v8.passive_dwell[SCAN_LB_LMAC_IDX] = passive_dwell;
+ if (iwl_mvm_is_cdb_supported(mvm)) {
+ cmd->v8.active_dwell[SCAN_HB_LMAC_IDX] =
+ active_dwell;
+ cmd->v8.passive_dwell[SCAN_HB_LMAC_IDX] =
+ passive_dwell;
+ }
+ }
} else {
- cmd->v1.active_dwell = IWL_SCAN_DWELL_ACTIVE;
- cmd->v1.passive_dwell = IWL_SCAN_DWELL_PASSIVE;
- cmd->v1.extended_dwell = IWL_SCAN_DWELL_EXTENDED;
- }
- cmd->v1.fragmented_dwell = IWL_SCAN_DWELL_FRAGMENTED;
+ cmd->v1.extended_dwell = params->measurement_dwell ?
+ params->measurement_dwell : IWL_SCAN_DWELL_EXTENDED;
+ cmd->v1.active_dwell = active_dwell;
+ cmd->v1.passive_dwell = passive_dwell;
+ cmd->v1.fragmented_dwell = IWL_SCAN_DWELL_FRAGMENTED;
- if (iwl_mvm_has_new_tx_api(mvm)) {
- cmd->v6.scan_priority = cpu_to_le32(IWL_SCAN_PRIORITY_EXT_6);
- cmd->v6.max_out_time[SCAN_LB_LMAC_IDX] =
- cpu_to_le32(timing->max_out_time);
- cmd->v6.suspend_time[SCAN_LB_LMAC_IDX] =
- cpu_to_le32(timing->suspend_time);
if (iwl_mvm_is_cdb_supported(mvm)) {
+ hb_timing = &scan_timing[params->type];
+
cmd->v6.max_out_time[SCAN_HB_LMAC_IDX] =
- cpu_to_le32(timing->max_out_time);
+ cpu_to_le32(hb_timing->max_out_time);
cmd->v6.suspend_time[SCAN_HB_LMAC_IDX] =
+ cpu_to_le32(hb_timing->suspend_time);
+ }
+
+ if (iwl_mvm_has_new_tx_api(mvm)) {
+ cmd->v6.scan_priority =
+ cpu_to_le32(IWL_SCAN_PRIORITY_EXT_6);
+ cmd->v6.max_out_time[SCAN_LB_LMAC_IDX] =
+ cpu_to_le32(timing->max_out_time);
+ cmd->v6.suspend_time[SCAN_LB_LMAC_IDX] =
+ cpu_to_le32(timing->suspend_time);
+ } else {
+ cmd->v1.scan_priority =
+ cpu_to_le32(IWL_SCAN_PRIORITY_EXT_6);
+ cmd->v1.max_out_time =
+ cpu_to_le32(timing->max_out_time);
+ cmd->v1.suspend_time =
cpu_to_le32(timing->suspend_time);
}
- } else {
- cmd->v1.max_out_time = cpu_to_le32(timing->max_out_time);
- cmd->v1.suspend_time = cpu_to_le32(timing->suspend_time);
- cmd->v1.scan_priority =
- cpu_to_le32(IWL_SCAN_PRIORITY_EXT_6);
}
}
@@ -1234,11 +1292,39 @@ static u16 iwl_mvm_scan_umac_flags(struct iwl_mvm *mvm,
if (mvm->sched_scan_pass_all == SCHED_SCAN_PASS_ALL_ENABLED)
flags |= IWL_UMAC_SCAN_GEN_FLAGS_ITER_COMPLETE;
+ if (iwl_mvm_is_adaptive_dwell_supported(mvm) && IWL_MVM_ADWELL_ENABLE &&
+ vif->type != NL80211_IFTYPE_P2P_DEVICE)
+ flags |= IWL_UMAC_SCAN_GEN_FLAGS_ADAPTIVE_DWELL;
+
+ /*
+ * Extended dwell is relevant only for low band to start with, as it is
+ * being used for social channles only (1, 6, 11), so we can check
+ * only scan type on low band also for CDB.
+ */
if (iwl_mvm_is_regular_scan(params) &&
vif->type != NL80211_IFTYPE_P2P_DEVICE &&
- params->type != IWL_SCAN_TYPE_FRAGMENTED)
+ params->type != IWL_SCAN_TYPE_FRAGMENTED &&
+ !iwl_mvm_is_adaptive_dwell_supported(mvm) &&
+ !iwl_mvm_is_oce_supported(mvm))
flags |= IWL_UMAC_SCAN_GEN_FLAGS_EXTENDED_DWELL;
+ if (iwl_mvm_is_oce_supported(mvm)) {
+ if ((params->flags &
+ NL80211_SCAN_FLAG_OCE_PROBE_REQ_HIGH_TX_RATE))
+ flags |= IWL_UMAC_SCAN_GEN_FLAGS_PROB_REQ_HIGH_TX_RATE;
+ /* Since IWL_UMAC_SCAN_GEN_FLAGS_EXTENDED_DWELL and
+ * NL80211_SCAN_FLAG_OCE_PROBE_REQ_DEFERRAL_SUPPRESSION shares
+ * the same bit, we need to make sure that we use this bit here
+ * only when IWL_UMAC_SCAN_GEN_FLAGS_EXTENDED_DWELL cannot be
+ * used. */
+ if ((params->flags &
+ NL80211_SCAN_FLAG_OCE_PROBE_REQ_DEFERRAL_SUPPRESSION) &&
+ !WARN_ON_ONCE(!iwl_mvm_is_adaptive_dwell_supported(mvm)))
+ flags |= IWL_UMAC_SCAN_GEN_FLAGS_PROB_REQ_DEFER_SUPP;
+ if ((params->flags & NL80211_SCAN_FLAG_FILS_MAX_CHANNEL_TIME))
+ flags |= IWL_UMAC_SCAN_GEN_FLAGS_MAX_CHNL_TIME;
+ }
+
return flags;
}
@@ -1247,6 +1333,7 @@ static int iwl_mvm_scan_umac(struct iwl_mvm *mvm, struct ieee80211_vif *vif,
int type)
{
struct iwl_scan_req_umac *cmd = mvm->scan_cmd;
+ struct iwl_scan_umac_chan_param *chan_param;
void *cmd_data = iwl_mvm_get_scan_req_umac_data(mvm);
struct iwl_scan_req_umac_tail *sec_part = cmd_data +
sizeof(struct iwl_scan_channel_cfg_umac) *
@@ -1254,8 +1341,11 @@ static int iwl_mvm_scan_umac(struct iwl_mvm *mvm, struct ieee80211_vif *vif,
int uid, i;
u32 ssid_bitmap = 0;
u8 channel_flags = 0;
+ u16 gen_flags;
struct iwl_mvm_vif *scan_vif = iwl_mvm_vif_from_mac80211(vif);
+ chan_param = iwl_mvm_get_scan_req_umac_channel(mvm);
+
lockdep_assert_held(&mvm->mutex);
if (WARN_ON(params->n_scan_plans > IWL_MAX_SCHED_SCAN_PLANS))
@@ -1272,8 +1362,17 @@ static int iwl_mvm_scan_umac(struct iwl_mvm *mvm, struct ieee80211_vif *vif,
mvm->scan_uid_status[uid] = type;
cmd->uid = cpu_to_le32(uid);
- cmd->general_flags = cpu_to_le16(iwl_mvm_scan_umac_flags(mvm, params,
- vif));
+ gen_flags = iwl_mvm_scan_umac_flags(mvm, params, vif);
+ cmd->general_flags = cpu_to_le16(gen_flags);
+ if (iwl_mvm_is_adaptive_dwell_v2_supported(mvm)) {
+ if (gen_flags & IWL_UMAC_SCAN_GEN_FLAGS_FRAGMENTED)
+ cmd->v8.num_of_fragments[SCAN_LB_LMAC_IDX] =
+ IWL_SCAN_NUM_OF_FRAGS;
+ if (gen_flags & IWL_UMAC_SCAN_GEN_FLAGS_LMAC2_FRAGMENTED)
+ cmd->v8.num_of_fragments[SCAN_HB_LMAC_IDX] =
+ IWL_SCAN_NUM_OF_FRAGS;
+ }
+
cmd->scan_start_mac_id = scan_vif->id;
if (type == IWL_MVM_SCAN_SCHED || type == IWL_MVM_SCAN_NETDETECT)
@@ -1284,16 +1383,8 @@ static int iwl_mvm_scan_umac(struct iwl_mvm *mvm, struct ieee80211_vif *vif,
IWL_SCAN_CHANNEL_FLAG_EBS_ACCURATE |
IWL_SCAN_CHANNEL_FLAG_CACHE_ADD;
- if (iwl_mvm_is_adaptive_dwell_supported(mvm)) {
- cmd->v7.channel_flags = channel_flags;
- cmd->v7.n_channels = params->n_channels;
- } else if (iwl_mvm_has_new_tx_api(mvm)) {
- cmd->v6.channel_flags = channel_flags;
- cmd->v6.n_channels = params->n_channels;
- } else {
- cmd->v1.channel_flags = channel_flags;
- cmd->v1.n_channels = params->n_channels;
- }
+ chan_param->flags = channel_flags;
+ chan_param->count = params->n_channels;
iwl_scan_build_ssids(params, sec_part->direct_scan, &ssid_bitmap);
@@ -1732,7 +1823,9 @@ int iwl_mvm_scan_size(struct iwl_mvm *mvm)
{
int base_size = IWL_SCAN_REQ_UMAC_SIZE_V1;
- if (iwl_mvm_is_adaptive_dwell_supported(mvm))
+ if (iwl_mvm_is_adaptive_dwell_v2_supported(mvm))
+ base_size = IWL_SCAN_REQ_UMAC_SIZE_V8;
+ else if (iwl_mvm_is_adaptive_dwell_supported(mvm))
base_size = IWL_SCAN_REQ_UMAC_SIZE_V7;
else if (iwl_mvm_has_new_tx_api(mvm))
base_size = IWL_SCAN_REQ_UMAC_SIZE_V6;
diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/sta.c b/drivers/net/wireless/intel/iwlwifi/mvm/sta.c
index 630e23cb0ffb..80067eb9ea05 100644
--- a/drivers/net/wireless/intel/iwlwifi/mvm/sta.c
+++ b/drivers/net/wireless/intel/iwlwifi/mvm/sta.c
@@ -1695,7 +1695,8 @@ int iwl_mvm_allocate_int_sta(struct iwl_mvm *mvm,
u32 qmask, enum nl80211_iftype iftype,
enum iwl_sta_type type)
{
- if (!test_bit(IWL_MVM_STATUS_IN_HW_RESTART, &mvm->status)) {
+ if (!test_bit(IWL_MVM_STATUS_IN_HW_RESTART, &mvm->status) ||
+ sta->sta_id == IWL_MVM_INVALID_STA) {
sta->sta_id = iwl_mvm_find_free_sta_id(mvm, iftype);
if (WARN_ON_ONCE(sta->sta_id == IWL_MVM_INVALID_STA))
return -ENOSPC;
@@ -2478,28 +2479,12 @@ int iwl_mvm_sta_tx_agg_start(struct iwl_mvm *mvm, struct ieee80211_vif *vif,
/*
* Note the possible cases:
- * 1. In DQA mode with an enabled TXQ - TXQ needs to become agg'ed
- * 2. Non-DQA mode: the TXQ hasn't yet been enabled, so find a free
- * one and mark it as reserved
- * 3. In DQA mode, but no traffic yet on this TID: same treatment as in
- * non-DQA mode, since the TXQ hasn't yet been allocated
- * Don't support case 3 for new TX path as it is not expected to happen
- * and aggregation will be offloaded soon anyway
+ * 1. An enabled TXQ - TXQ needs to become agg'ed
+ * 2. The TXQ hasn't yet been enabled, so find a free one and mark
+ * it as reserved
*/
txq_id = mvmsta->tid_data[tid].txq_id;
- if (iwl_mvm_has_new_tx_api(mvm)) {
- if (txq_id == IWL_MVM_INVALID_QUEUE) {
- ret = -ENXIO;
- goto release_locks;
- }
- } else if (unlikely(mvm->queue_info[txq_id].status ==
- IWL_MVM_QUEUE_SHARED)) {
- ret = -ENXIO;
- IWL_DEBUG_TX_QUEUES(mvm,
- "Can't start tid %d agg on shared queue!\n",
- tid);
- goto release_locks;
- } else if (mvm->queue_info[txq_id].status != IWL_MVM_QUEUE_READY) {
+ if (txq_id == IWL_MVM_INVALID_QUEUE) {
txq_id = iwl_mvm_find_free_queue(mvm, mvmsta->sta_id,
IWL_MVM_DQA_MIN_DATA_QUEUE,
IWL_MVM_DQA_MAX_DATA_QUEUE);
@@ -2508,16 +2493,16 @@ int iwl_mvm_sta_tx_agg_start(struct iwl_mvm *mvm, struct ieee80211_vif *vif,
IWL_ERR(mvm, "Failed to allocate agg queue\n");
goto release_locks;
}
- /*
- * TXQ shouldn't be in inactive mode for non-DQA, so getting
- * an inactive queue from iwl_mvm_find_free_queue() is
- * certainly a bug
- */
- WARN_ON(mvm->queue_info[txq_id].status ==
- IWL_MVM_QUEUE_INACTIVE);
/* TXQ hasn't yet been enabled, so mark it only as reserved */
mvm->queue_info[txq_id].status = IWL_MVM_QUEUE_RESERVED;
+ } else if (unlikely(mvm->queue_info[txq_id].status ==
+ IWL_MVM_QUEUE_SHARED)) {
+ ret = -ENXIO;
+ IWL_DEBUG_TX_QUEUES(mvm,
+ "Can't start tid %d agg on shared queue!\n",
+ tid);
+ goto release_locks;
}
spin_unlock(&mvm->queue_info_lock);
@@ -2696,8 +2681,10 @@ out:
static void iwl_mvm_unreserve_agg_queue(struct iwl_mvm *mvm,
struct iwl_mvm_sta *mvmsta,
- u16 txq_id)
+ struct iwl_mvm_tid_data *tid_data)
{
+ u16 txq_id = tid_data->txq_id;
+
if (iwl_mvm_has_new_tx_api(mvm))
return;
@@ -2709,8 +2696,10 @@ static void iwl_mvm_unreserve_agg_queue(struct iwl_mvm *mvm,
* allocated through iwl_mvm_enable_txq, so we can just mark it back as
* free.
*/
- if (mvm->queue_info[txq_id].status == IWL_MVM_QUEUE_RESERVED)
+ if (mvm->queue_info[txq_id].status == IWL_MVM_QUEUE_RESERVED) {
mvm->queue_info[txq_id].status = IWL_MVM_QUEUE_FREE;
+ tid_data->txq_id = IWL_MVM_INVALID_QUEUE;
+ }
spin_unlock_bh(&mvm->queue_info_lock);
}
@@ -2741,7 +2730,7 @@ int iwl_mvm_sta_tx_agg_stop(struct iwl_mvm *mvm, struct ieee80211_vif *vif,
mvmsta->agg_tids &= ~BIT(tid);
- iwl_mvm_unreserve_agg_queue(mvm, mvmsta, txq_id);
+ iwl_mvm_unreserve_agg_queue(mvm, mvmsta, tid_data);
switch (tid_data->state) {
case IWL_AGG_ON:
@@ -2808,7 +2797,7 @@ int iwl_mvm_sta_tx_agg_flush(struct iwl_mvm *mvm, struct ieee80211_vif *vif,
mvmsta->agg_tids &= ~BIT(tid);
spin_unlock_bh(&mvmsta->lock);
- iwl_mvm_unreserve_agg_queue(mvm, mvmsta, txq_id);
+ iwl_mvm_unreserve_agg_queue(mvm, mvmsta, tid_data);
if (old_state >= IWL_AGG_ON) {
iwl_mvm_drain_sta(mvm, mvmsta, true);
@@ -3233,17 +3222,9 @@ int iwl_mvm_set_sta_key(struct iwl_mvm *mvm,
}
sta_id = mvm_sta->sta_id;
- if (keyconf->cipher == WLAN_CIPHER_SUITE_AES_CMAC ||
- keyconf->cipher == WLAN_CIPHER_SUITE_BIP_GMAC_128 ||
- keyconf->cipher == WLAN_CIPHER_SUITE_BIP_GMAC_256) {
- ret = iwl_mvm_send_sta_igtk(mvm, keyconf, sta_id,
- false);
- goto end;
- }
-
/*
* It is possible that the 'sta' parameter is NULL, and thus
- * there is a need to retrieve the sta from the local station
+ * there is a need to retrieve the sta from the local station
* table.
*/
if (!sta) {
@@ -3258,6 +3239,17 @@ int iwl_mvm_set_sta_key(struct iwl_mvm *mvm,
if (WARN_ON_ONCE(iwl_mvm_sta_from_mac80211(sta)->vif != vif))
return -EINVAL;
+ } else {
+ struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
+
+ sta_id = mvmvif->mcast_sta.sta_id;
+ }
+
+ if (keyconf->cipher == WLAN_CIPHER_SUITE_AES_CMAC ||
+ keyconf->cipher == WLAN_CIPHER_SUITE_BIP_GMAC_128 ||
+ keyconf->cipher == WLAN_CIPHER_SUITE_BIP_GMAC_256) {
+ ret = iwl_mvm_send_sta_igtk(mvm, keyconf, sta_id, false);
+ goto end;
}
/* If the key_offset is not pre-assigned, we need to find a
diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/time-event.c b/drivers/net/wireless/intel/iwlwifi/mvm/time-event.c
index acb217e666db..cd91bc44259c 100644
--- a/drivers/net/wireless/intel/iwlwifi/mvm/time-event.c
+++ b/drivers/net/wireless/intel/iwlwifi/mvm/time-event.c
@@ -8,6 +8,7 @@
* Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved.
* Copyright(c) 2013 - 2015 Intel Mobile Communications GmbH
* Copyright(c) 2017 Intel Deutschland GmbH
+ * Copyright(c) 2018 Intel Corporation
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of version 2 of the GNU General Public License as
@@ -18,11 +19,6 @@
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110,
- * USA
- *
* The full GNU General Public License is included in this distribution
* in the file called COPYING.
*
@@ -35,6 +31,7 @@
* Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved.
* Copyright(c) 2013 - 2015 Intel Mobile Communications GmbH
* Copyright(c) 2017 Intel Deutschland GmbH
+ * Copyright(c) 2018 Intel Corporation
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -198,9 +195,13 @@ static bool iwl_mvm_te_check_disconnect(struct iwl_mvm *mvm,
struct ieee80211_vif *vif,
const char *errmsg)
{
+ struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
+
if (vif->type != NL80211_IFTYPE_STATION)
return false;
- if (vif->bss_conf.assoc && vif->bss_conf.dtim_period)
+
+ if (!mvmvif->csa_bcn_pending && vif->bss_conf.assoc &&
+ vif->bss_conf.dtim_period)
return false;
if (errmsg)
IWL_ERR(mvm, "%s\n", errmsg);
@@ -344,7 +345,7 @@ static void iwl_mvm_te_handle_notif(struct iwl_mvm *mvm,
* and know the dtim period.
*/
iwl_mvm_te_check_disconnect(mvm, te_data->vif,
- "No association and the time event is over already...");
+ "No beacon heard and the time event is over already...");
break;
default:
break;
diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/tx.c b/drivers/net/wireless/intel/iwlwifi/mvm/tx.c
index af6dfceab6b8..795065974d78 100644
--- a/drivers/net/wireless/intel/iwlwifi/mvm/tx.c
+++ b/drivers/net/wireless/intel/iwlwifi/mvm/tx.c
@@ -687,6 +687,74 @@ int iwl_mvm_tx_skb_non_sta(struct iwl_mvm *mvm, struct sk_buff *skb)
}
#ifdef CONFIG_INET
+
+static int
+iwl_mvm_tx_tso_segment(struct sk_buff *skb, unsigned int num_subframes,
+ netdev_features_t netdev_flags,
+ struct sk_buff_head *mpdus_skb)
+{
+ struct sk_buff *tmp, *next;
+ struct ieee80211_hdr *hdr = (void *)skb->data;
+ char cb[sizeof(skb->cb)];
+ u16 i = 0;
+ unsigned int tcp_payload_len;
+ unsigned int mss = skb_shinfo(skb)->gso_size;
+ bool ipv4 = (skb->protocol == htons(ETH_P_IP));
+ u16 ip_base_id = ipv4 ? ntohs(ip_hdr(skb)->id) : 0;
+
+ skb_shinfo(skb)->gso_size = num_subframes * mss;
+ memcpy(cb, skb->cb, sizeof(cb));
+
+ next = skb_gso_segment(skb, netdev_flags);
+ skb_shinfo(skb)->gso_size = mss;
+ if (WARN_ON_ONCE(IS_ERR(next)))
+ return -EINVAL;
+ else if (next)
+ consume_skb(skb);
+
+ while (next) {
+ tmp = next;
+ next = tmp->next;
+
+ memcpy(tmp->cb, cb, sizeof(tmp->cb));
+ /*
+ * Compute the length of all the data added for the A-MSDU.
+ * This will be used to compute the length to write in the TX
+ * command. We have: SNAP + IP + TCP for n -1 subframes and
+ * ETH header for n subframes.
+ */
+ tcp_payload_len = skb_tail_pointer(tmp) -
+ skb_transport_header(tmp) -
+ tcp_hdrlen(tmp) + tmp->data_len;
+
+ if (ipv4)
+ ip_hdr(tmp)->id = htons(ip_base_id + i * num_subframes);
+
+ if (tcp_payload_len > mss) {
+ skb_shinfo(tmp)->gso_size = mss;
+ } else {
+ if (ieee80211_is_data_qos(hdr->frame_control)) {
+ u8 *qc;
+
+ if (ipv4)
+ ip_send_check(ip_hdr(tmp));
+
+ qc = ieee80211_get_qos_ctl((void *)tmp->data);
+ *qc &= ~IEEE80211_QOS_CTL_A_MSDU_PRESENT;
+ }
+ skb_shinfo(tmp)->gso_size = 0;
+ }
+
+ tmp->prev = NULL;
+ tmp->next = NULL;
+
+ __skb_queue_tail(mpdus_skb, tmp);
+ i++;
+ }
+
+ return 0;
+}
+
static int iwl_mvm_tx_tso(struct iwl_mvm *mvm, struct sk_buff *skb,
struct ieee80211_tx_info *info,
struct ieee80211_sta *sta,
@@ -695,14 +763,10 @@ static int iwl_mvm_tx_tso(struct iwl_mvm *mvm, struct sk_buff *skb,
struct iwl_mvm_sta *mvmsta = iwl_mvm_sta_from_mac80211(sta);
struct ieee80211_hdr *hdr = (void *)skb->data;
unsigned int mss = skb_shinfo(skb)->gso_size;
- struct sk_buff *tmp, *next;
- char cb[sizeof(skb->cb)];
unsigned int num_subframes, tcp_payload_len, subf_len, max_amsdu_len;
- bool ipv4 = (skb->protocol == htons(ETH_P_IP));
- u16 ip_base_id = ipv4 ? ntohs(ip_hdr(skb)->id) : 0;
- u16 snap_ip_tcp, pad, i = 0;
+ u16 snap_ip_tcp, pad;
unsigned int dbg_max_amsdu_len;
- netdev_features_t netdev_features = NETIF_F_CSUM_MASK | NETIF_F_SG;
+ netdev_features_t netdev_flags = NETIF_F_CSUM_MASK | NETIF_F_SG;
u8 *qc, tid, txf;
snap_ip_tcp = 8 + skb_transport_header(skb) - skb_network_header(skb) +
@@ -712,16 +776,8 @@ static int iwl_mvm_tx_tso(struct iwl_mvm *mvm, struct sk_buff *skb,
if (!sta->max_amsdu_len ||
!ieee80211_is_data_qos(hdr->frame_control) ||
- (!mvmsta->tlc_amsdu && !dbg_max_amsdu_len)) {
- num_subframes = 1;
- pad = 0;
- goto segment;
- }
-
- qc = ieee80211_get_qos_ctl(hdr);
- tid = *qc & IEEE80211_QOS_CTL_TID_MASK;
- if (WARN_ON_ONCE(tid >= IWL_MAX_TID_COUNT))
- return -EINVAL;
+ (!mvmsta->tlc_amsdu && !dbg_max_amsdu_len))
+ return iwl_mvm_tx_tso_segment(skb, 1, netdev_flags, mpdus_skb);
/*
* Do not build AMSDU for IPv6 with extension headers.
@@ -730,22 +786,22 @@ static int iwl_mvm_tx_tso(struct iwl_mvm *mvm, struct sk_buff *skb,
if (skb->protocol == htons(ETH_P_IPV6) &&
((struct ipv6hdr *)skb_network_header(skb))->nexthdr !=
IPPROTO_TCP) {
- num_subframes = 1;
- pad = 0;
- netdev_features &= ~NETIF_F_CSUM_MASK;
- goto segment;
+ netdev_flags &= ~NETIF_F_CSUM_MASK;
+ return iwl_mvm_tx_tso_segment(skb, 1, netdev_flags, mpdus_skb);
}
+ qc = ieee80211_get_qos_ctl(hdr);
+ tid = *qc & IEEE80211_QOS_CTL_TID_MASK;
+ if (WARN_ON_ONCE(tid >= IWL_MAX_TID_COUNT))
+ return -EINVAL;
+
/*
* No need to lock amsdu_in_ampdu_allowed since it can't be modified
* during an BA session.
*/
if (info->flags & IEEE80211_TX_CTL_AMPDU &&
- !mvmsta->tid_data[tid].amsdu_in_ampdu_allowed) {
- num_subframes = 1;
- pad = 0;
- goto segment;
- }
+ !mvmsta->tid_data[tid].amsdu_in_ampdu_allowed)
+ return iwl_mvm_tx_tso_segment(skb, 1, netdev_flags, mpdus_skb);
max_amsdu_len = sta->max_amsdu_len;
@@ -811,56 +867,8 @@ static int iwl_mvm_tx_tso(struct iwl_mvm *mvm, struct sk_buff *skb,
* Trick the segmentation function to make it
* create SKBs that can fit into one A-MSDU.
*/
-segment:
- skb_shinfo(skb)->gso_size = num_subframes * mss;
- memcpy(cb, skb->cb, sizeof(cb));
-
- next = skb_gso_segment(skb, netdev_features);
- skb_shinfo(skb)->gso_size = mss;
- if (WARN_ON_ONCE(IS_ERR(next)))
- return -EINVAL;
- else if (next)
- consume_skb(skb);
-
- while (next) {
- tmp = next;
- next = tmp->next;
-
- memcpy(tmp->cb, cb, sizeof(tmp->cb));
- /*
- * Compute the length of all the data added for the A-MSDU.
- * This will be used to compute the length to write in the TX
- * command. We have: SNAP + IP + TCP for n -1 subframes and
- * ETH header for n subframes.
- */
- tcp_payload_len = skb_tail_pointer(tmp) -
- skb_transport_header(tmp) -
- tcp_hdrlen(tmp) + tmp->data_len;
-
- if (ipv4)
- ip_hdr(tmp)->id = htons(ip_base_id + i * num_subframes);
-
- if (tcp_payload_len > mss) {
- skb_shinfo(tmp)->gso_size = mss;
- } else {
- if (ieee80211_is_data_qos(hdr->frame_control)) {
- qc = ieee80211_get_qos_ctl((void *)tmp->data);
-
- if (ipv4)
- ip_send_check(ip_hdr(tmp));
- *qc &= ~IEEE80211_QOS_CTL_A_MSDU_PRESENT;
- }
- skb_shinfo(tmp)->gso_size = 0;
- }
-
- tmp->prev = NULL;
- tmp->next = NULL;
-
- __skb_queue_tail(mpdus_skb, tmp);
- i++;
- }
-
- return 0;
+ return iwl_mvm_tx_tso_segment(skb, num_subframes, netdev_flags,
+ mpdus_skb);
}
#else /* CONFIG_INET */
static int iwl_mvm_tx_tso(struct iwl_mvm *mvm, struct sk_buff *skb,
@@ -1894,14 +1902,12 @@ int iwl_mvm_flush_sta(struct iwl_mvm *mvm, void *sta, bool internal, u32 flags)
struct iwl_mvm_int_sta *int_sta = sta;
struct iwl_mvm_sta *mvm_sta = sta;
- if (iwl_mvm_has_new_tx_api(mvm)) {
- if (internal)
- return iwl_mvm_flush_sta_tids(mvm, int_sta->sta_id,
- BIT(IWL_MGMT_TID), flags);
+ BUILD_BUG_ON(offsetof(struct iwl_mvm_int_sta, sta_id) !=
+ offsetof(struct iwl_mvm_sta, sta_id));
+ if (iwl_mvm_has_new_tx_api(mvm))
return iwl_mvm_flush_sta_tids(mvm, mvm_sta->sta_id,
- 0xFF, flags);
- }
+ 0xff | BIT(IWL_MGMT_TID), flags);
if (internal)
return iwl_mvm_flush_tx_path(mvm, int_sta->tfd_queue_msk,
diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/utils.c b/drivers/net/wireless/intel/iwlwifi/mvm/utils.c
index d65e1db7c097..bebcfb44c8c2 100644
--- a/drivers/net/wireless/intel/iwlwifi/mvm/utils.c
+++ b/drivers/net/wireless/intel/iwlwifi/mvm/utils.c
@@ -800,12 +800,19 @@ int iwl_mvm_disable_txq(struct iwl_mvm *mvm, int queue, int mac80211_queue,
.scd_queue = queue,
.action = SCD_CFG_DISABLE_QUEUE,
};
- bool remove_mac_queue = true;
+ bool remove_mac_queue = mac80211_queue != IEEE80211_INVAL_HW_QUEUE;
int ret;
+ if (WARN_ON(remove_mac_queue && mac80211_queue >= IEEE80211_MAX_QUEUES))
+ return -EINVAL;
+
if (iwl_mvm_has_new_tx_api(mvm)) {
spin_lock_bh(&mvm->queue_info_lock);
- mvm->hw_queue_to_mac80211[queue] &= ~BIT(mac80211_queue);
+
+ if (remove_mac_queue)
+ mvm->hw_queue_to_mac80211[queue] &=
+ ~BIT(mac80211_queue);
+
spin_unlock_bh(&mvm->queue_info_lock);
iwl_trans_txq_free(mvm->trans, queue);
@@ -1027,14 +1034,18 @@ bool iwl_mvm_rx_diversity_allowed(struct iwl_mvm *mvm)
}
int iwl_mvm_update_low_latency(struct iwl_mvm *mvm, struct ieee80211_vif *vif,
- bool prev)
+ bool low_latency,
+ enum iwl_mvm_low_latency_cause cause)
{
struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
int res;
- bool low_latency;
+ bool prev;
lockdep_assert_held(&mvm->mutex);
+ prev = iwl_mvm_vif_low_latency(mvmvif);
+ iwl_mvm_vif_set_low_latency(mvmvif, low_latency, cause);
+
low_latency = iwl_mvm_vif_low_latency(mvmvif);
if (low_latency == prev)
diff --git a/drivers/net/wireless/intel/iwlwifi/pcie/drv.c b/drivers/net/wireless/intel/iwlwifi/pcie/drv.c
index 56fc28750a41..959de2f8bb28 100644
--- a/drivers/net/wireless/intel/iwlwifi/pcie/drv.c
+++ b/drivers/net/wireless/intel/iwlwifi/pcie/drv.c
@@ -8,6 +8,7 @@
* Copyright(c) 2007 - 2014 Intel Corporation. All rights reserved.
* Copyright(c) 2013 - 2015 Intel Mobile Communications GmbH
* Copyright(c) 2016-2017 Intel Deutschland GmbH
+ * Copyright(c) 2018 Intel Corporation
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of version 2 of the GNU General Public License as
@@ -36,6 +37,7 @@
* Copyright(c) 2013 - 2015 Intel Mobile Communications GmbH
* All rights reserved.
* Copyright(c) 2017 Intel Deutschland GmbH
+ * Copyright(c) 2018 Intel Corporation
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
@@ -517,9 +519,9 @@ static const struct pci_device_id iwl_hw_card_ids[] = {
{IWL_PCI_DEVICE(0x24FD, 0x9074, iwl8265_2ac_cfg)},
/* 9000 Series */
- {IWL_PCI_DEVICE(0x2526, 0x0000, iwl9260_2ac_cfg)},
{IWL_PCI_DEVICE(0x2526, 0x0010, iwl9260_2ac_cfg)},
{IWL_PCI_DEVICE(0x2526, 0x0014, iwl9260_2ac_cfg)},
+ {IWL_PCI_DEVICE(0x2526, 0x0018, iwl9260_2ac_cfg)},
{IWL_PCI_DEVICE(0x2526, 0x0030, iwl9560_2ac_cfg)},
{IWL_PCI_DEVICE(0x2526, 0x0034, iwl9560_2ac_cfg)},
{IWL_PCI_DEVICE(0x2526, 0x0038, iwl9560_2ac_cfg)},
@@ -544,11 +546,15 @@ static const struct pci_device_id iwl_hw_card_ids[] = {
{IWL_PCI_DEVICE(0x2526, 0x1410, iwl9270_2ac_cfg)},
{IWL_PCI_DEVICE(0x2526, 0x1420, iwl9460_2ac_cfg_soc)},
{IWL_PCI_DEVICE(0x2526, 0x1610, iwl9270_2ac_cfg)},
+ {IWL_PCI_DEVICE(0x2526, 0x2030, iwl9560_2ac_cfg_soc)},
+ {IWL_PCI_DEVICE(0x2526, 0x2034, iwl9560_2ac_cfg_soc)},
{IWL_PCI_DEVICE(0x2526, 0x4010, iwl9260_2ac_cfg)},
{IWL_PCI_DEVICE(0x2526, 0x4030, iwl9560_2ac_cfg)},
+ {IWL_PCI_DEVICE(0x2526, 0x4034, iwl9560_2ac_cfg_soc)},
{IWL_PCI_DEVICE(0x2526, 0x40A4, iwl9460_2ac_cfg)},
- {IWL_PCI_DEVICE(0x2526, 0xA014, iwl9260_2ac_cfg)},
+ {IWL_PCI_DEVICE(0x2526, 0x4234, iwl9560_2ac_cfg_soc)},
{IWL_PCI_DEVICE(0x2526, 0x42A4, iwl9462_2ac_cfg_soc)},
+ {IWL_PCI_DEVICE(0x2526, 0xA014, iwl9260_2ac_cfg)},
{IWL_PCI_DEVICE(0x271B, 0x0010, iwl9160_2ac_cfg)},
{IWL_PCI_DEVICE(0x271B, 0x0014, iwl9160_2ac_cfg)},
{IWL_PCI_DEVICE(0x271B, 0x0210, iwl9160_2ac_cfg)},
@@ -569,38 +575,146 @@ static const struct pci_device_id iwl_hw_card_ids[] = {
{IWL_PCI_DEVICE(0x2720, 0x0264, iwl9461_2ac_cfg_soc)},
{IWL_PCI_DEVICE(0x2720, 0x02A0, iwl9462_2ac_cfg_soc)},
{IWL_PCI_DEVICE(0x2720, 0x02A4, iwl9462_2ac_cfg_soc)},
+ {IWL_PCI_DEVICE(0x2720, 0x1010, iwl9260_2ac_cfg)},
+ {IWL_PCI_DEVICE(0x2720, 0x1030, iwl9560_2ac_cfg_soc)},
+ {IWL_PCI_DEVICE(0x2720, 0x1210, iwl9260_2ac_cfg)},
+ {IWL_PCI_DEVICE(0x2720, 0x2030, iwl9560_2ac_cfg_soc)},
+ {IWL_PCI_DEVICE(0x2720, 0x2034, iwl9560_2ac_cfg_soc)},
{IWL_PCI_DEVICE(0x2720, 0x4030, iwl9560_2ac_cfg)},
+ {IWL_PCI_DEVICE(0x2720, 0x4034, iwl9560_2ac_cfg_soc)},
{IWL_PCI_DEVICE(0x2720, 0x40A4, iwl9462_2ac_cfg_soc)},
+ {IWL_PCI_DEVICE(0x2720, 0x4234, iwl9560_2ac_cfg_soc)},
+ {IWL_PCI_DEVICE(0x2720, 0x42A4, iwl9462_2ac_cfg_soc)},
+ {IWL_PCI_DEVICE(0x30DC, 0x0030, iwl9560_2ac_cfg_soc)},
+ {IWL_PCI_DEVICE(0x30DC, 0x0034, iwl9560_2ac_cfg_soc)},
+ {IWL_PCI_DEVICE(0x30DC, 0x0038, iwl9560_2ac_cfg_soc)},
+ {IWL_PCI_DEVICE(0x30DC, 0x003C, iwl9560_2ac_cfg_soc)},
{IWL_PCI_DEVICE(0x30DC, 0x0060, iwl9460_2ac_cfg_soc)},
{IWL_PCI_DEVICE(0x30DC, 0x0064, iwl9461_2ac_cfg_soc)},
{IWL_PCI_DEVICE(0x30DC, 0x00A0, iwl9462_2ac_cfg_soc)},
{IWL_PCI_DEVICE(0x30DC, 0x00A4, iwl9462_2ac_cfg_soc)},
+ {IWL_PCI_DEVICE(0x30DC, 0x0230, iwl9560_2ac_cfg_soc)},
+ {IWL_PCI_DEVICE(0x30DC, 0x0234, iwl9560_2ac_cfg_soc)},
+ {IWL_PCI_DEVICE(0x30DC, 0x0238, iwl9560_2ac_cfg_soc)},
+ {IWL_PCI_DEVICE(0x30DC, 0x023C, iwl9560_2ac_cfg_soc)},
{IWL_PCI_DEVICE(0x30DC, 0x0260, iwl9461_2ac_cfg_soc)},
{IWL_PCI_DEVICE(0x30DC, 0x0264, iwl9461_2ac_cfg_soc)},
{IWL_PCI_DEVICE(0x30DC, 0x02A0, iwl9462_2ac_cfg_soc)},
{IWL_PCI_DEVICE(0x30DC, 0x02A4, iwl9462_2ac_cfg_soc)},
- {IWL_PCI_DEVICE(0x31DC, 0x0030, iwl9560_2ac_cfg_soc)},
- {IWL_PCI_DEVICE(0x31DC, 0x0034, iwl9560_2ac_cfg_soc)},
- {IWL_PCI_DEVICE(0x31DC, 0x0038, iwl9560_2ac_cfg_soc)},
- {IWL_PCI_DEVICE(0x31DC, 0x003C, iwl9560_2ac_cfg_soc)},
- {IWL_PCI_DEVICE(0x31DC, 0x0060, iwl9460_2ac_cfg_soc)},
- {IWL_PCI_DEVICE(0x31DC, 0x0064, iwl9461_2ac_cfg_soc)},
- {IWL_PCI_DEVICE(0x31DC, 0x00A0, iwl9462_2ac_cfg_soc)},
- {IWL_PCI_DEVICE(0x31DC, 0x00A4, iwl9462_2ac_cfg_soc)},
- {IWL_PCI_DEVICE(0x31DC, 0x0230, iwl9560_2ac_cfg_soc)},
- {IWL_PCI_DEVICE(0x31DC, 0x0234, iwl9560_2ac_cfg_soc)},
- {IWL_PCI_DEVICE(0x31DC, 0x0238, iwl9560_2ac_cfg_soc)},
- {IWL_PCI_DEVICE(0x31DC, 0x023C, iwl9560_2ac_cfg_soc)},
- {IWL_PCI_DEVICE(0x31DC, 0x0260, iwl9461_2ac_cfg_soc)},
- {IWL_PCI_DEVICE(0x31DC, 0x0264, iwl9461_2ac_cfg_soc)},
- {IWL_PCI_DEVICE(0x31DC, 0x02A0, iwl9462_2ac_cfg_soc)},
- {IWL_PCI_DEVICE(0x31DC, 0x02A4, iwl9462_2ac_cfg_soc)},
- {IWL_PCI_DEVICE(0x31DC, 0x4030, iwl9560_2ac_cfg_soc)},
- {IWL_PCI_DEVICE(0x31DC, 0x4034, iwl9560_2ac_cfg_soc)},
- {IWL_PCI_DEVICE(0x31DC, 0x40A4, iwl9462_2ac_cfg_soc)},
+ {IWL_PCI_DEVICE(0x30DC, 0x1010, iwl9260_2ac_cfg)},
+ {IWL_PCI_DEVICE(0x30DC, 0x1030, iwl9560_2ac_cfg_soc)},
+ {IWL_PCI_DEVICE(0x30DC, 0x1210, iwl9260_2ac_cfg)},
+ {IWL_PCI_DEVICE(0x30DC, 0x2030, iwl9560_2ac_cfg_soc)},
+ {IWL_PCI_DEVICE(0x30DC, 0x2034, iwl9560_2ac_cfg_soc)},
+ {IWL_PCI_DEVICE(0x30DC, 0x4030, iwl9560_2ac_cfg_soc)},
+ {IWL_PCI_DEVICE(0x30DC, 0x4034, iwl9560_2ac_cfg_soc)},
+ {IWL_PCI_DEVICE(0x30DC, 0x40A4, iwl9462_2ac_cfg_soc)},
+ {IWL_PCI_DEVICE(0x30DC, 0x4234, iwl9560_2ac_cfg_soc)},
+ {IWL_PCI_DEVICE(0x30DC, 0x42A4, iwl9462_2ac_cfg_soc)},
+ {IWL_PCI_DEVICE(0x31DC, 0x0030, iwl9560_2ac_cfg_shared_clk)},
+ {IWL_PCI_DEVICE(0x31DC, 0x0034, iwl9560_2ac_cfg_shared_clk)},
+ {IWL_PCI_DEVICE(0x31DC, 0x0038, iwl9560_2ac_cfg_shared_clk)},
+ {IWL_PCI_DEVICE(0x31DC, 0x003C, iwl9560_2ac_cfg_shared_clk)},
+ {IWL_PCI_DEVICE(0x31DC, 0x0060, iwl9460_2ac_cfg_shared_clk)},
+ {IWL_PCI_DEVICE(0x31DC, 0x0064, iwl9461_2ac_cfg_shared_clk)},
+ {IWL_PCI_DEVICE(0x31DC, 0x00A0, iwl9462_2ac_cfg_shared_clk)},
+ {IWL_PCI_DEVICE(0x31DC, 0x00A4, iwl9462_2ac_cfg_shared_clk)},
+ {IWL_PCI_DEVICE(0x31DC, 0x0230, iwl9560_2ac_cfg_shared_clk)},
+ {IWL_PCI_DEVICE(0x31DC, 0x0234, iwl9560_2ac_cfg_shared_clk)},
+ {IWL_PCI_DEVICE(0x31DC, 0x0238, iwl9560_2ac_cfg_shared_clk)},
+ {IWL_PCI_DEVICE(0x31DC, 0x023C, iwl9560_2ac_cfg_shared_clk)},
+ {IWL_PCI_DEVICE(0x31DC, 0x0260, iwl9461_2ac_cfg_shared_clk)},
+ {IWL_PCI_DEVICE(0x31DC, 0x0264, iwl9461_2ac_cfg_shared_clk)},
+ {IWL_PCI_DEVICE(0x31DC, 0x02A0, iwl9462_2ac_cfg_shared_clk)},
+ {IWL_PCI_DEVICE(0x31DC, 0x02A4, iwl9462_2ac_cfg_shared_clk)},
+ {IWL_PCI_DEVICE(0x31DC, 0x1010, iwl9260_2ac_cfg)},
+ {IWL_PCI_DEVICE(0x31DC, 0x1030, iwl9560_2ac_cfg_shared_clk)},
+ {IWL_PCI_DEVICE(0x31DC, 0x1210, iwl9260_2ac_cfg)},
+ {IWL_PCI_DEVICE(0x31DC, 0x2030, iwl9560_2ac_cfg_shared_clk)},
+ {IWL_PCI_DEVICE(0x31DC, 0x2034, iwl9560_2ac_cfg_shared_clk)},
+ {IWL_PCI_DEVICE(0x31DC, 0x4030, iwl9560_2ac_cfg_shared_clk)},
+ {IWL_PCI_DEVICE(0x31DC, 0x4034, iwl9560_2ac_cfg_shared_clk)},
+ {IWL_PCI_DEVICE(0x31DC, 0x40A4, iwl9462_2ac_cfg_shared_clk)},
+ {IWL_PCI_DEVICE(0x31DC, 0x4234, iwl9560_2ac_cfg_shared_clk)},
+ {IWL_PCI_DEVICE(0x31DC, 0x42A4, iwl9462_2ac_cfg_shared_clk)},
{IWL_PCI_DEVICE(0x34F0, 0x0030, iwl9560_2ac_cfg_soc)},
{IWL_PCI_DEVICE(0x34F0, 0x0034, iwl9560_2ac_cfg_soc)},
+ {IWL_PCI_DEVICE(0x34F0, 0x0038, iwl9560_2ac_cfg_soc)},
+ {IWL_PCI_DEVICE(0x34F0, 0x003C, iwl9560_2ac_cfg_soc)},
+ {IWL_PCI_DEVICE(0x34F0, 0x0060, iwl9461_2ac_cfg_soc)},
+ {IWL_PCI_DEVICE(0x34F0, 0x0064, iwl9461_2ac_cfg_soc)},
+ {IWL_PCI_DEVICE(0x34F0, 0x00A0, iwl9462_2ac_cfg_soc)},
+ {IWL_PCI_DEVICE(0x34F0, 0x00A4, iwl9462_2ac_cfg_soc)},
+ {IWL_PCI_DEVICE(0x34F0, 0x0230, iwl9560_2ac_cfg_soc)},
+ {IWL_PCI_DEVICE(0x34F0, 0x0234, iwl9560_2ac_cfg_soc)},
+ {IWL_PCI_DEVICE(0x34F0, 0x0238, iwl9560_2ac_cfg_soc)},
+ {IWL_PCI_DEVICE(0x34F0, 0x023C, iwl9560_2ac_cfg_soc)},
+ {IWL_PCI_DEVICE(0x34F0, 0x0260, iwl9461_2ac_cfg_soc)},
+ {IWL_PCI_DEVICE(0x34F0, 0x0264, iwl9461_2ac_cfg_soc)},
+ {IWL_PCI_DEVICE(0x34F0, 0x02A0, iwl9462_2ac_cfg_soc)},
{IWL_PCI_DEVICE(0x34F0, 0x02A4, iwl9462_2ac_cfg_soc)},
+ {IWL_PCI_DEVICE(0x34F0, 0x1010, iwl9260_2ac_cfg)},
+ {IWL_PCI_DEVICE(0x34F0, 0x1030, iwl9560_2ac_cfg_soc)},
+ {IWL_PCI_DEVICE(0x34F0, 0x1210, iwl9260_2ac_cfg)},
+ {IWL_PCI_DEVICE(0x34F0, 0x2030, iwl9560_2ac_cfg_soc)},
+ {IWL_PCI_DEVICE(0x34F0, 0x2034, iwl9560_2ac_cfg_soc)},
+ {IWL_PCI_DEVICE(0x34F0, 0x4030, iwl9560_2ac_cfg_soc)},
+ {IWL_PCI_DEVICE(0x34F0, 0x4034, iwl9560_2ac_cfg_soc)},
+ {IWL_PCI_DEVICE(0x34F0, 0x40A4, iwl9462_2ac_cfg_soc)},
+ {IWL_PCI_DEVICE(0x34F0, 0x4234, iwl9560_2ac_cfg_soc)},
+ {IWL_PCI_DEVICE(0x34F0, 0x42A4, iwl9462_2ac_cfg_soc)},
+ {IWL_PCI_DEVICE(0x3DF0, 0x0030, iwl9560_2ac_cfg_soc)},
+ {IWL_PCI_DEVICE(0x3DF0, 0x0034, iwl9560_2ac_cfg_soc)},
+ {IWL_PCI_DEVICE(0x3DF0, 0x0038, iwl9560_2ac_cfg_soc)},
+ {IWL_PCI_DEVICE(0x3DF0, 0x003C, iwl9560_2ac_cfg_soc)},
+ {IWL_PCI_DEVICE(0x3DF0, 0x0060, iwl9461_2ac_cfg_soc)},
+ {IWL_PCI_DEVICE(0x3DF0, 0x0064, iwl9461_2ac_cfg_soc)},
+ {IWL_PCI_DEVICE(0x3DF0, 0x00A0, iwl9462_2ac_cfg_soc)},
+ {IWL_PCI_DEVICE(0x3DF0, 0x00A4, iwl9462_2ac_cfg_soc)},
+ {IWL_PCI_DEVICE(0x3DF0, 0x0230, iwl9560_2ac_cfg_soc)},
+ {IWL_PCI_DEVICE(0x3DF0, 0x0234, iwl9560_2ac_cfg_soc)},
+ {IWL_PCI_DEVICE(0x3DF0, 0x0238, iwl9560_2ac_cfg_soc)},
+ {IWL_PCI_DEVICE(0x3DF0, 0x023C, iwl9560_2ac_cfg_soc)},
+ {IWL_PCI_DEVICE(0x3DF0, 0x0260, iwl9461_2ac_cfg_soc)},
+ {IWL_PCI_DEVICE(0x3DF0, 0x0264, iwl9461_2ac_cfg_soc)},
+ {IWL_PCI_DEVICE(0x3DF0, 0x02A0, iwl9462_2ac_cfg_soc)},
+ {IWL_PCI_DEVICE(0x3DF0, 0x02A4, iwl9462_2ac_cfg_soc)},
+ {IWL_PCI_DEVICE(0x3DF0, 0x1010, iwl9260_2ac_cfg)},
+ {IWL_PCI_DEVICE(0x3DF0, 0x1030, iwl9560_2ac_cfg_soc)},
+ {IWL_PCI_DEVICE(0x3DF0, 0x1210, iwl9260_2ac_cfg)},
+ {IWL_PCI_DEVICE(0x3DF0, 0x2030, iwl9560_2ac_cfg_soc)},
+ {IWL_PCI_DEVICE(0x3DF0, 0x2034, iwl9560_2ac_cfg_soc)},
+ {IWL_PCI_DEVICE(0x3DF0, 0x4030, iwl9560_2ac_cfg_soc)},
+ {IWL_PCI_DEVICE(0x3DF0, 0x4034, iwl9560_2ac_cfg_soc)},
+ {IWL_PCI_DEVICE(0x3DF0, 0x40A4, iwl9462_2ac_cfg_soc)},
+ {IWL_PCI_DEVICE(0x3DF0, 0x4234, iwl9560_2ac_cfg_soc)},
+ {IWL_PCI_DEVICE(0x3DF0, 0x42A4, iwl9462_2ac_cfg_soc)},
+ {IWL_PCI_DEVICE(0x43F0, 0x0030, iwl9560_2ac_cfg_soc)},
+ {IWL_PCI_DEVICE(0x43F0, 0x0034, iwl9560_2ac_cfg_soc)},
+ {IWL_PCI_DEVICE(0x43F0, 0x0038, iwl9560_2ac_cfg_soc)},
+ {IWL_PCI_DEVICE(0x43F0, 0x003C, iwl9560_2ac_cfg_soc)},
+ {IWL_PCI_DEVICE(0x43F0, 0x0060, iwl9461_2ac_cfg_soc)},
+ {IWL_PCI_DEVICE(0x43F0, 0x0064, iwl9461_2ac_cfg_soc)},
+ {IWL_PCI_DEVICE(0x43F0, 0x00A0, iwl9462_2ac_cfg_soc)},
+ {IWL_PCI_DEVICE(0x43F0, 0x00A4, iwl9462_2ac_cfg_soc)},
+ {IWL_PCI_DEVICE(0x43F0, 0x0230, iwl9560_2ac_cfg_soc)},
+ {IWL_PCI_DEVICE(0x43F0, 0x0234, iwl9560_2ac_cfg_soc)},
+ {IWL_PCI_DEVICE(0x43F0, 0x0238, iwl9560_2ac_cfg_soc)},
+ {IWL_PCI_DEVICE(0x43F0, 0x023C, iwl9560_2ac_cfg_soc)},
+ {IWL_PCI_DEVICE(0x43F0, 0x0260, iwl9461_2ac_cfg_soc)},
+ {IWL_PCI_DEVICE(0x43F0, 0x0264, iwl9461_2ac_cfg_soc)},
+ {IWL_PCI_DEVICE(0x43F0, 0x02A0, iwl9462_2ac_cfg_soc)},
+ {IWL_PCI_DEVICE(0x43F0, 0x02A4, iwl9462_2ac_cfg_soc)},
+ {IWL_PCI_DEVICE(0x43F0, 0x1010, iwl9260_2ac_cfg)},
+ {IWL_PCI_DEVICE(0x43F0, 0x1030, iwl9560_2ac_cfg_soc)},
+ {IWL_PCI_DEVICE(0x43F0, 0x1210, iwl9260_2ac_cfg)},
+ {IWL_PCI_DEVICE(0x43F0, 0x2030, iwl9560_2ac_cfg_soc)},
+ {IWL_PCI_DEVICE(0x43F0, 0x2034, iwl9560_2ac_cfg_soc)},
+ {IWL_PCI_DEVICE(0x43F0, 0x4030, iwl9560_2ac_cfg_soc)},
+ {IWL_PCI_DEVICE(0x43F0, 0x4034, iwl9560_2ac_cfg_soc)},
+ {IWL_PCI_DEVICE(0x43F0, 0x40A4, iwl9462_2ac_cfg_soc)},
+ {IWL_PCI_DEVICE(0x43F0, 0x4234, iwl9560_2ac_cfg_soc)},
+ {IWL_PCI_DEVICE(0x43F0, 0x42A4, iwl9462_2ac_cfg_soc)},
{IWL_PCI_DEVICE(0x9DF0, 0x0000, iwl9460_2ac_cfg_soc)},
{IWL_PCI_DEVICE(0x9DF0, 0x0010, iwl9460_2ac_cfg_soc)},
{IWL_PCI_DEVICE(0x9DF0, 0x0030, iwl9560_2ac_cfg_soc)},
@@ -626,11 +740,44 @@ static const struct pci_device_id iwl_hw_card_ids[] = {
{IWL_PCI_DEVICE(0x9DF0, 0x0610, iwl9460_2ac_cfg_soc)},
{IWL_PCI_DEVICE(0x9DF0, 0x0710, iwl9460_2ac_cfg_soc)},
{IWL_PCI_DEVICE(0x9DF0, 0x0A10, iwl9460_2ac_cfg_soc)},
+ {IWL_PCI_DEVICE(0x9DF0, 0x1010, iwl9260_2ac_cfg)},
+ {IWL_PCI_DEVICE(0x9DF0, 0x1030, iwl9560_2ac_cfg_soc)},
+ {IWL_PCI_DEVICE(0x9DF0, 0x1210, iwl9260_2ac_cfg)},
{IWL_PCI_DEVICE(0x9DF0, 0x2010, iwl9460_2ac_cfg_soc)},
+ {IWL_PCI_DEVICE(0x9DF0, 0x2030, iwl9560_2ac_cfg_soc)},
+ {IWL_PCI_DEVICE(0x9DF0, 0x2034, iwl9560_2ac_cfg_soc)},
{IWL_PCI_DEVICE(0x9DF0, 0x2A10, iwl9460_2ac_cfg_soc)},
{IWL_PCI_DEVICE(0x9DF0, 0x4030, iwl9560_2ac_cfg_soc)},
{IWL_PCI_DEVICE(0x9DF0, 0x4034, iwl9560_2ac_cfg_soc)},
{IWL_PCI_DEVICE(0x9DF0, 0x40A4, iwl9462_2ac_cfg_soc)},
+ {IWL_PCI_DEVICE(0x9DF0, 0x4234, iwl9560_2ac_cfg_soc)},
+ {IWL_PCI_DEVICE(0x9DF0, 0x42A4, iwl9462_2ac_cfg_soc)},
+ {IWL_PCI_DEVICE(0xA0F0, 0x0030, iwl9560_2ac_cfg_soc)},
+ {IWL_PCI_DEVICE(0xA0F0, 0x0034, iwl9560_2ac_cfg_soc)},
+ {IWL_PCI_DEVICE(0xA0F0, 0x0038, iwl9560_2ac_cfg_soc)},
+ {IWL_PCI_DEVICE(0xA0F0, 0x003C, iwl9560_2ac_cfg_soc)},
+ {IWL_PCI_DEVICE(0xA0F0, 0x0060, iwl9461_2ac_cfg_soc)},
+ {IWL_PCI_DEVICE(0xA0F0, 0x0064, iwl9461_2ac_cfg_soc)},
+ {IWL_PCI_DEVICE(0xA0F0, 0x00A0, iwl9462_2ac_cfg_soc)},
+ {IWL_PCI_DEVICE(0xA0F0, 0x00A4, iwl9462_2ac_cfg_soc)},
+ {IWL_PCI_DEVICE(0xA0F0, 0x0230, iwl9560_2ac_cfg_soc)},
+ {IWL_PCI_DEVICE(0xA0F0, 0x0234, iwl9560_2ac_cfg_soc)},
+ {IWL_PCI_DEVICE(0xA0F0, 0x0238, iwl9560_2ac_cfg_soc)},
+ {IWL_PCI_DEVICE(0xA0F0, 0x023C, iwl9560_2ac_cfg_soc)},
+ {IWL_PCI_DEVICE(0xA0F0, 0x0260, iwl9461_2ac_cfg_soc)},
+ {IWL_PCI_DEVICE(0xA0F0, 0x0264, iwl9461_2ac_cfg_soc)},
+ {IWL_PCI_DEVICE(0xA0F0, 0x02A0, iwl9462_2ac_cfg_soc)},
+ {IWL_PCI_DEVICE(0xA0F0, 0x02A4, iwl9462_2ac_cfg_soc)},
+ {IWL_PCI_DEVICE(0xA0F0, 0x1010, iwl9260_2ac_cfg)},
+ {IWL_PCI_DEVICE(0xA0F0, 0x1030, iwl9560_2ac_cfg_soc)},
+ {IWL_PCI_DEVICE(0xA0F0, 0x1210, iwl9260_2ac_cfg)},
+ {IWL_PCI_DEVICE(0xA0F0, 0x2030, iwl9560_2ac_cfg_soc)},
+ {IWL_PCI_DEVICE(0xA0F0, 0x2034, iwl9560_2ac_cfg_soc)},
+ {IWL_PCI_DEVICE(0xA0F0, 0x4030, iwl9560_2ac_cfg_soc)},
+ {IWL_PCI_DEVICE(0xA0F0, 0x4034, iwl9560_2ac_cfg_soc)},
+ {IWL_PCI_DEVICE(0xA0F0, 0x40A4, iwl9462_2ac_cfg_soc)},
+ {IWL_PCI_DEVICE(0xA0F0, 0x4234, iwl9560_2ac_cfg_soc)},
+ {IWL_PCI_DEVICE(0xA0F0, 0x42A4, iwl9462_2ac_cfg_soc)},
{IWL_PCI_DEVICE(0xA370, 0x0030, iwl9560_2ac_cfg_soc)},
{IWL_PCI_DEVICE(0xA370, 0x0034, iwl9560_2ac_cfg_soc)},
{IWL_PCI_DEVICE(0xA370, 0x0038, iwl9560_2ac_cfg_soc)},
@@ -647,10 +794,16 @@ static const struct pci_device_id iwl_hw_card_ids[] = {
{IWL_PCI_DEVICE(0xA370, 0x0264, iwl9461_2ac_cfg_soc)},
{IWL_PCI_DEVICE(0xA370, 0x02A0, iwl9462_2ac_cfg_soc)},
{IWL_PCI_DEVICE(0xA370, 0x02A4, iwl9462_2ac_cfg_soc)},
+ {IWL_PCI_DEVICE(0xA370, 0x1010, iwl9260_2ac_cfg)},
{IWL_PCI_DEVICE(0xA370, 0x1030, iwl9560_2ac_cfg_soc)},
+ {IWL_PCI_DEVICE(0xA370, 0x1210, iwl9260_2ac_cfg)},
+ {IWL_PCI_DEVICE(0xA370, 0x2030, iwl9560_2ac_cfg_soc)},
+ {IWL_PCI_DEVICE(0xA370, 0x2034, iwl9560_2ac_cfg_soc)},
{IWL_PCI_DEVICE(0xA370, 0x4030, iwl9560_2ac_cfg_soc)},
{IWL_PCI_DEVICE(0xA370, 0x4034, iwl9560_2ac_cfg_soc)},
{IWL_PCI_DEVICE(0xA370, 0x40A4, iwl9462_2ac_cfg_soc)},
+ {IWL_PCI_DEVICE(0xA370, 0x4234, iwl9560_2ac_cfg_soc)},
+ {IWL_PCI_DEVICE(0xA370, 0x42A4, iwl9462_2ac_cfg_soc)},
/* 22000 Series */
{IWL_PCI_DEVICE(0x2720, 0x0A10, iwl22000_2ac_cfg_hr_cdb)},
diff --git a/drivers/net/wireless/intel/iwlwifi/pcie/trans.c b/drivers/net/wireless/intel/iwlwifi/pcie/trans.c
index b406b536c850..f8a0234d332c 100644
--- a/drivers/net/wireless/intel/iwlwifi/pcie/trans.c
+++ b/drivers/net/wireless/intel/iwlwifi/pcie/trans.c
@@ -2616,12 +2616,12 @@ int iwl_trans_pcie_dbgfs_register(struct iwl_trans *trans)
{
struct dentry *dir = trans->dbgfs_dir;
- DEBUGFS_ADD_FILE(rx_queue, dir, S_IRUSR);
- DEBUGFS_ADD_FILE(tx_queue, dir, S_IRUSR);
- DEBUGFS_ADD_FILE(interrupt, dir, S_IWUSR | S_IRUSR);
- DEBUGFS_ADD_FILE(csr, dir, S_IWUSR);
- DEBUGFS_ADD_FILE(fh_reg, dir, S_IRUSR);
- DEBUGFS_ADD_FILE(rfkill, dir, S_IWUSR | S_IRUSR);
+ DEBUGFS_ADD_FILE(rx_queue, dir, 0400);
+ DEBUGFS_ADD_FILE(tx_queue, dir, 0400);
+ DEBUGFS_ADD_FILE(interrupt, dir, 0600);
+ DEBUGFS_ADD_FILE(csr, dir, 0200);
+ DEBUGFS_ADD_FILE(fh_reg, dir, 0400);
+ DEBUGFS_ADD_FILE(rfkill, dir, 0600);
return 0;
err:
diff --git a/drivers/net/wireless/intersil/p54/main.c b/drivers/net/wireless/intersil/p54/main.c
index ab6d39e12069..1c6d428515a4 100644
--- a/drivers/net/wireless/intersil/p54/main.c
+++ b/drivers/net/wireless/intersil/p54/main.c
@@ -27,7 +27,7 @@
#include "lmac.h"
static bool modparam_nohwcrypt;
-module_param_named(nohwcrypt, modparam_nohwcrypt, bool, S_IRUGO);
+module_param_named(nohwcrypt, modparam_nohwcrypt, bool, 0444);
MODULE_PARM_DESC(nohwcrypt, "Disable hardware encryption.");
MODULE_AUTHOR("Michael Wu <flamingice@sourmilk.net>");
MODULE_DESCRIPTION("Softmac Prism54 common code");
diff --git a/drivers/net/wireless/marvell/mwifiex/11n.c b/drivers/net/wireless/marvell/mwifiex/11n.c
index feebfdcf025a..5d75c971004b 100644
--- a/drivers/net/wireless/marvell/mwifiex/11n.c
+++ b/drivers/net/wireless/marvell/mwifiex/11n.c
@@ -356,17 +356,19 @@ mwifiex_cmd_append_11n_tlv(struct mwifiex_private *priv,
case IEEE80211_HT_PARAM_CHA_SEC_ABOVE:
if (chan->flags & IEEE80211_CHAN_NO_HT40PLUS) {
ht_cap->ht_cap.cap_info &=
- ~IEEE80211_HT_CAP_SUP_WIDTH_20_40;
+ cpu_to_le16
+ (~IEEE80211_HT_CAP_SUP_WIDTH_20_40);
ht_cap->ht_cap.cap_info &=
- ~IEEE80211_HT_CAP_SGI_40;
+ cpu_to_le16(~IEEE80211_HT_CAP_SGI_40);
}
break;
case IEEE80211_HT_PARAM_CHA_SEC_BELOW:
if (chan->flags & IEEE80211_CHAN_NO_HT40MINUS) {
ht_cap->ht_cap.cap_info &=
- ~IEEE80211_HT_CAP_SUP_WIDTH_20_40;
+ cpu_to_le16
+ (~IEEE80211_HT_CAP_SUP_WIDTH_20_40);
ht_cap->ht_cap.cap_info &=
- ~IEEE80211_HT_CAP_SGI_40;
+ cpu_to_le16(~IEEE80211_HT_CAP_SGI_40);
}
break;
}
diff --git a/drivers/net/wireless/mediatek/mt76/debugfs.c b/drivers/net/wireless/mediatek/mt76/debugfs.c
index c121b502a462..a38d05dea599 100644
--- a/drivers/net/wireless/mediatek/mt76/debugfs.c
+++ b/drivers/net/wireless/mediatek/mt76/debugfs.c
@@ -64,13 +64,13 @@ struct dentry *mt76_register_debugfs(struct mt76_dev *dev)
if (!dir)
return NULL;
- debugfs_create_u8("led_pin", S_IRUSR | S_IWUSR, dir, &dev->led_pin);
- debugfs_create_u32("regidx", S_IRUSR | S_IWUSR, dir, &dev->debugfs_reg);
- debugfs_create_file_unsafe("regval", S_IRUSR | S_IWUSR, dir, dev,
+ debugfs_create_u8("led_pin", 0600, dir, &dev->led_pin);
+ debugfs_create_u32("regidx", 0600, dir, &dev->debugfs_reg);
+ debugfs_create_file_unsafe("regval", 0600, dir, dev,
&fops_regval);
- debugfs_create_blob("eeprom", S_IRUSR, dir, &dev->eeprom);
+ debugfs_create_blob("eeprom", 0400, dir, &dev->eeprom);
if (dev->otp.data)
- debugfs_create_blob("otp", S_IRUSR, dir, &dev->otp);
+ debugfs_create_blob("otp", 0400, dir, &dev->otp);
debugfs_create_devm_seqfile(dev->dev, "queues", dir, mt76_queues_read);
return dir;
diff --git a/drivers/net/wireless/mediatek/mt76/mt76x2_debugfs.c b/drivers/net/wireless/mediatek/mt76/mt76x2_debugfs.c
index 612feb593d7d..955ea3e692dd 100644
--- a/drivers/net/wireless/mediatek/mt76/mt76x2_debugfs.c
+++ b/drivers/net/wireless/mediatek/mt76/mt76x2_debugfs.c
@@ -123,11 +123,11 @@ void mt76x2_init_debugfs(struct mt76x2_dev *dev)
if (!dir)
return;
- debugfs_create_u8("temperature", S_IRUSR, dir, &dev->cal.temp);
- debugfs_create_bool("tpc", S_IRUSR | S_IWUSR, dir, &dev->enable_tpc);
+ debugfs_create_u8("temperature", 0400, dir, &dev->cal.temp);
+ debugfs_create_bool("tpc", 0600, dir, &dev->enable_tpc);
- debugfs_create_file("ampdu_stat", S_IRUSR, dir, dev, &fops_ampdu_stat);
- debugfs_create_file("dfs_stats", S_IRUSR, dir, dev, &fops_dfs_stat);
+ debugfs_create_file("ampdu_stat", 0400, dir, dev, &fops_ampdu_stat);
+ debugfs_create_file("dfs_stats", 0400, dir, dev, &fops_dfs_stat);
debugfs_create_devm_seqfile(dev->mt76.dev, "txpower", dir,
read_txpower);
}
diff --git a/drivers/net/wireless/mediatek/mt76/mt76x2_main.c b/drivers/net/wireless/mediatek/mt76/mt76x2_main.c
index 25f4cebef26d..73c127f92613 100644
--- a/drivers/net/wireless/mediatek/mt76/mt76x2_main.c
+++ b/drivers/net/wireless/mediatek/mt76/mt76x2_main.c
@@ -336,6 +336,17 @@ mt76x2_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd,
int idx = key->keyidx;
int ret;
+ /* fall back to sw encryption for unsupported ciphers */
+ switch (key->cipher) {
+ case WLAN_CIPHER_SUITE_WEP40:
+ case WLAN_CIPHER_SUITE_WEP104:
+ case WLAN_CIPHER_SUITE_TKIP:
+ case WLAN_CIPHER_SUITE_CCMP:
+ break;
+ default:
+ return -EOPNOTSUPP;
+ }
+
/*
* The hardware does not support per-STA RX GTK, fall back
* to software mode for these.
diff --git a/drivers/net/wireless/mediatek/mt76/mt76x2_mcu.c b/drivers/net/wireless/mediatek/mt76/mt76x2_mcu.c
index 15820b11f9db..dfd36d736b06 100644
--- a/drivers/net/wireless/mediatek/mt76/mt76x2_mcu.c
+++ b/drivers/net/wireless/mediatek/mt76/mt76x2_mcu.c
@@ -187,7 +187,7 @@ mt76pci_load_firmware(struct mt76x2_dev *dev)
{
const struct firmware *fw;
const struct mt76x2_fw_header *hdr;
- int i, len, ret;
+ int len, ret;
__le32 *cur;
u32 offset, val;
@@ -240,16 +240,7 @@ mt76pci_load_firmware(struct mt76x2_dev *dev)
/* trigger firmware */
mt76_wr(dev, MT_MCU_INT_LEVEL, 2);
- for (i = 200; i > 0; i--) {
- val = mt76_rr(dev, MT_MCU_COM_REG0);
-
- if (val & 1)
- break;
-
- msleep(10);
- }
-
- if (!i) {
+ if (!mt76_poll_msec(dev, MT_MCU_COM_REG0, 1, 1, 200)) {
dev_err(dev->mt76.dev, "Firmware failed to start\n");
release_firmware(fw);
return -ETIMEDOUT;
diff --git a/drivers/net/wireless/mediatek/mt76/mt76x2_tx.c b/drivers/net/wireless/mediatek/mt76/mt76x2_tx.c
index 534e4bf9a34c..e46eafc4c436 100644
--- a/drivers/net/wireless/mediatek/mt76/mt76x2_tx.c
+++ b/drivers/net/wireless/mediatek/mt76/mt76x2_tx.c
@@ -36,9 +36,12 @@ void mt76x2_tx(struct ieee80211_hw *hw, struct ieee80211_tx_control *control,
msta = (struct mt76x2_sta *) control->sta->drv_priv;
wcid = &msta->wcid;
+ /* sw encrypted frames */
+ if (!info->control.hw_key && wcid->hw_key_idx != -1)
+ control->sta = NULL;
}
- if (vif || (!info->control.hw_key && wcid->hw_key_idx != -1)) {
+ if (vif && !control->sta) {
struct mt76x2_vif *mvif;
mvif = (struct mt76x2_vif *) vif->drv_priv;
diff --git a/drivers/net/wireless/mediatek/mt7601u/debugfs.c b/drivers/net/wireless/mediatek/mt7601u/debugfs.c
index fc008475a03b..991a6a729b1e 100644
--- a/drivers/net/wireless/mediatek/mt7601u/debugfs.c
+++ b/drivers/net/wireless/mediatek/mt7601u/debugfs.c
@@ -160,13 +160,11 @@ void mt7601u_init_debugfs(struct mt7601u_dev *dev)
if (!dir)
return;
- debugfs_create_u8("temperature", S_IRUSR, dir, &dev->raw_temp);
- debugfs_create_u32("temp_mode", S_IRUSR, dir, &dev->temp_mode);
-
- debugfs_create_u32("regidx", S_IRUSR | S_IWUSR, dir, &dev->debugfs_reg);
- debugfs_create_file("regval", S_IRUSR | S_IWUSR, dir, dev,
- &fops_regval);
- debugfs_create_file("ampdu_stat", S_IRUSR, dir, dev, &fops_ampdu_stat);
- debugfs_create_file("eeprom_param", S_IRUSR, dir, dev,
- &fops_eeprom_param);
+ debugfs_create_u8("temperature", 0400, dir, &dev->raw_temp);
+ debugfs_create_u32("temp_mode", 0400, dir, &dev->temp_mode);
+
+ debugfs_create_u32("regidx", 0600, dir, &dev->debugfs_reg);
+ debugfs_create_file("regval", 0600, dir, dev, &fops_regval);
+ debugfs_create_file("ampdu_stat", 0400, dir, dev, &fops_ampdu_stat);
+ debugfs_create_file("eeprom_param", 0400, dir, dev, &fops_eeprom_param);
}
diff --git a/drivers/net/wireless/ralink/rt2x00/rt2500usb.c b/drivers/net/wireless/ralink/rt2x00/rt2500usb.c
index f4b48b77c491..3df8c4b895e7 100644
--- a/drivers/net/wireless/ralink/rt2x00/rt2500usb.c
+++ b/drivers/net/wireless/ralink/rt2x00/rt2500usb.c
@@ -37,7 +37,7 @@
* Allow hardware encryption to be disabled.
*/
static bool modparam_nohwcrypt;
-module_param_named(nohwcrypt, modparam_nohwcrypt, bool, S_IRUGO);
+module_param_named(nohwcrypt, modparam_nohwcrypt, bool, 0444);
MODULE_PARM_DESC(nohwcrypt, "Disable hardware encryption.");
/*
diff --git a/drivers/net/wireless/ralink/rt2x00/rt2800pci.c b/drivers/net/wireless/ralink/rt2x00/rt2800pci.c
index 5cf655ff1430..1172eefd1c1a 100644
--- a/drivers/net/wireless/ralink/rt2x00/rt2800pci.c
+++ b/drivers/net/wireless/ralink/rt2x00/rt2800pci.c
@@ -49,7 +49,7 @@
* Allow hardware encryption to be disabled.
*/
static bool modparam_nohwcrypt = false;
-module_param_named(nohwcrypt, modparam_nohwcrypt, bool, S_IRUGO);
+module_param_named(nohwcrypt, modparam_nohwcrypt, bool, 0444);
MODULE_PARM_DESC(nohwcrypt, "Disable hardware encryption.");
static bool rt2800pci_hwcrypt_disabled(struct rt2x00_dev *rt2x00dev)
diff --git a/drivers/net/wireless/ralink/rt2x00/rt2800soc.c b/drivers/net/wireless/ralink/rt2x00/rt2800soc.c
index a985a5a7945e..6848ebc83534 100644
--- a/drivers/net/wireless/ralink/rt2x00/rt2800soc.c
+++ b/drivers/net/wireless/ralink/rt2x00/rt2800soc.c
@@ -41,7 +41,7 @@
/* Allow hardware encryption to be disabled. */
static bool modparam_nohwcrypt;
-module_param_named(nohwcrypt, modparam_nohwcrypt, bool, S_IRUGO);
+module_param_named(nohwcrypt, modparam_nohwcrypt, bool, 0444);
MODULE_PARM_DESC(nohwcrypt, "Disable hardware encryption.");
static bool rt2800soc_hwcrypt_disabled(struct rt2x00_dev *rt2x00dev)
diff --git a/drivers/net/wireless/ralink/rt2x00/rt2800usb.c b/drivers/net/wireless/ralink/rt2x00/rt2800usb.c
index 24fc6d2045ef..d901a41d36e4 100644
--- a/drivers/net/wireless/ralink/rt2x00/rt2800usb.c
+++ b/drivers/net/wireless/ralink/rt2x00/rt2800usb.c
@@ -43,7 +43,7 @@
* Allow hardware encryption to be disabled.
*/
static bool modparam_nohwcrypt;
-module_param_named(nohwcrypt, modparam_nohwcrypt, bool, S_IRUGO);
+module_param_named(nohwcrypt, modparam_nohwcrypt, bool, 0444);
MODULE_PARM_DESC(nohwcrypt, "Disable hardware encryption.");
static bool rt2800usb_hwcrypt_disabled(struct rt2x00_dev *rt2x00dev)
diff --git a/drivers/net/wireless/ralink/rt2x00/rt2x00debug.c b/drivers/net/wireless/ralink/rt2x00/rt2x00debug.c
index ac2572943ed0..0eee479583b8 100644
--- a/drivers/net/wireless/ralink/rt2x00/rt2x00debug.c
+++ b/drivers/net/wireless/ralink/rt2x00/rt2x00debug.c
@@ -606,7 +606,7 @@ static struct dentry *rt2x00debug_create_file_driver(const char *name,
data += sprintf(data, "version:\t%s\n", DRV_VERSION);
blob->size = strlen(blob->data);
- return debugfs_create_blob(name, S_IRUSR, intf->driver_folder, blob);
+ return debugfs_create_blob(name, 0400, intf->driver_folder, blob);
}
static struct dentry *rt2x00debug_create_file_chipset(const char *name,
@@ -647,7 +647,7 @@ static struct dentry *rt2x00debug_create_file_chipset(const char *name,
blob->size = strlen(blob->data);
- return debugfs_create_blob(name, S_IRUSR, intf->driver_folder, blob);
+ return debugfs_create_blob(name, 0400, intf->driver_folder, blob);
}
void rt2x00debug_register(struct rt2x00_dev *rt2x00dev)
@@ -682,13 +682,13 @@ void rt2x00debug_register(struct rt2x00_dev *rt2x00dev)
if (IS_ERR(intf->chipset_entry) || !intf->chipset_entry)
goto exit;
- intf->dev_flags = debugfs_create_file("dev_flags", S_IRUSR,
+ intf->dev_flags = debugfs_create_file("dev_flags", 0400,
intf->driver_folder, intf,
&rt2x00debug_fop_dev_flags);
if (IS_ERR(intf->dev_flags) || !intf->dev_flags)
goto exit;
- intf->cap_flags = debugfs_create_file("cap_flags", S_IRUSR,
+ intf->cap_flags = debugfs_create_file("cap_flags", 0400,
intf->driver_folder, intf,
&rt2x00debug_fop_cap_flags);
if (IS_ERR(intf->cap_flags) || !intf->cap_flags)
@@ -699,27 +699,28 @@ void rt2x00debug_register(struct rt2x00_dev *rt2x00dev)
if (IS_ERR(intf->register_folder) || !intf->register_folder)
goto exit;
-#define RT2X00DEBUGFS_CREATE_REGISTER_ENTRY(__intf, __name) \
-({ \
- if (debug->__name.read) { \
- (__intf)->__name##_off_entry = \
- debugfs_create_u32(__stringify(__name) "_offset", \
- S_IRUSR | S_IWUSR, \
- (__intf)->register_folder, \
- &(__intf)->offset_##__name); \
- if (IS_ERR((__intf)->__name##_off_entry) \
- || !(__intf)->__name##_off_entry) \
- goto exit; \
- \
- (__intf)->__name##_val_entry = \
- debugfs_create_file(__stringify(__name) "_value", \
- S_IRUSR | S_IWUSR, \
- (__intf)->register_folder, \
- (__intf), &rt2x00debug_fop_##__name); \
- if (IS_ERR((__intf)->__name##_val_entry) \
- || !(__intf)->__name##_val_entry) \
- goto exit; \
- } \
+#define RT2X00DEBUGFS_CREATE_REGISTER_ENTRY(__intf, __name) \
+({ \
+ if (debug->__name.read) { \
+ (__intf)->__name##_off_entry = \
+ debugfs_create_u32(__stringify(__name) "_offset", \
+ 0600, \
+ (__intf)->register_folder, \
+ &(__intf)->offset_##__name); \
+ if (IS_ERR((__intf)->__name##_off_entry) || \
+ !(__intf)->__name##_off_entry) \
+ goto exit; \
+ \
+ (__intf)->__name##_val_entry = \
+ debugfs_create_file(__stringify(__name) "_value", \
+ 0600, \
+ (__intf)->register_folder, \
+ (__intf), \
+ &rt2x00debug_fop_##__name); \
+ if (IS_ERR((__intf)->__name##_val_entry) || \
+ !(__intf)->__name##_val_entry) \
+ goto exit; \
+ } \
})
RT2X00DEBUGFS_CREATE_REGISTER_ENTRY(intf, csr);
@@ -736,8 +737,8 @@ void rt2x00debug_register(struct rt2x00_dev *rt2x00dev)
goto exit;
intf->queue_frame_dump_entry =
- debugfs_create_file("dump", S_IRUSR, intf->queue_folder,
- intf, &rt2x00debug_fop_queue_dump);
+ debugfs_create_file("dump", 0400, intf->queue_folder,
+ intf, &rt2x00debug_fop_queue_dump);
if (IS_ERR(intf->queue_frame_dump_entry)
|| !intf->queue_frame_dump_entry)
goto exit;
@@ -746,14 +747,15 @@ void rt2x00debug_register(struct rt2x00_dev *rt2x00dev)
init_waitqueue_head(&intf->frame_dump_waitqueue);
intf->queue_stats_entry =
- debugfs_create_file("queue", S_IRUSR, intf->queue_folder,
- intf, &rt2x00debug_fop_queue_stats);
+ debugfs_create_file("queue", 0400, intf->queue_folder,
+ intf, &rt2x00debug_fop_queue_stats);
#ifdef CONFIG_RT2X00_LIB_CRYPTO
if (rt2x00_has_cap_hw_crypto(rt2x00dev))
intf->crypto_stats_entry =
- debugfs_create_file("crypto", S_IRUGO, intf->queue_folder,
- intf, &rt2x00debug_fop_crypto_stats);
+ debugfs_create_file("crypto", 0444, intf->queue_folder,
+ intf,
+ &rt2x00debug_fop_crypto_stats);
#endif
return;
diff --git a/drivers/net/wireless/ralink/rt2x00/rt61pci.c b/drivers/net/wireless/ralink/rt2x00/rt61pci.c
index 234310200759..cb0e1196f2c2 100644
--- a/drivers/net/wireless/ralink/rt2x00/rt61pci.c
+++ b/drivers/net/wireless/ralink/rt2x00/rt61pci.c
@@ -40,7 +40,7 @@
* Allow hardware encryption to be disabled.
*/
static bool modparam_nohwcrypt = false;
-module_param_named(nohwcrypt, modparam_nohwcrypt, bool, S_IRUGO);
+module_param_named(nohwcrypt, modparam_nohwcrypt, bool, 0444);
MODULE_PARM_DESC(nohwcrypt, "Disable hardware encryption.");
/*
diff --git a/drivers/net/wireless/ralink/rt2x00/rt73usb.c b/drivers/net/wireless/ralink/rt2x00/rt73usb.c
index 9a212823f42c..319ec4f2d9d2 100644
--- a/drivers/net/wireless/ralink/rt2x00/rt73usb.c
+++ b/drivers/net/wireless/ralink/rt2x00/rt73usb.c
@@ -38,7 +38,7 @@
* Allow hardware encryption to be disabled.
*/
static bool modparam_nohwcrypt;
-module_param_named(nohwcrypt, modparam_nohwcrypt, bool, S_IRUGO);
+module_param_named(nohwcrypt, modparam_nohwcrypt, bool, 0444);
MODULE_PARM_DESC(nohwcrypt, "Disable hardware encryption.");
/*
diff --git a/drivers/net/wireless/ray_cs.c b/drivers/net/wireless/ray_cs.c
index 0133fcd4601b..7f9b16b97ea3 100644
--- a/drivers/net/wireless/ray_cs.c
+++ b/drivers/net/wireless/ray_cs.c
@@ -2815,9 +2815,11 @@ static int __init init_ray_cs(void)
proc_mkdir("driver/ray_cs", NULL);
proc_create("driver/ray_cs/ray_cs", 0, NULL, &ray_cs_proc_fops);
- proc_create("driver/ray_cs/essid", S_IWUSR, NULL, &ray_cs_essid_proc_fops);
- proc_create_data("driver/ray_cs/net_type", S_IWUSR, NULL, &int_proc_fops, &net_type);
- proc_create_data("driver/ray_cs/translate", S_IWUSR, NULL, &int_proc_fops, &translate);
+ proc_create("driver/ray_cs/essid", 0200, NULL, &ray_cs_essid_proc_fops);
+ proc_create_data("driver/ray_cs/net_type", 0200, NULL, &int_proc_fops,
+ &net_type);
+ proc_create_data("driver/ray_cs/translate", 0200, NULL, &int_proc_fops,
+ &translate);
#endif
if (translate != 0)
translate = 1;
diff --git a/drivers/net/wireless/realtek/rtlwifi/base.c b/drivers/net/wireless/realtek/rtlwifi/base.c
index 6db3389e2ced..762a29cdf7ad 100644
--- a/drivers/net/wireless/realtek/rtlwifi/base.c
+++ b/drivers/net/wireless/realtek/rtlwifi/base.c
@@ -1549,7 +1549,6 @@ u8 rtl_is_special_data(struct ieee80211_hw *hw, struct sk_buff *skb, u8 is_tx,
/* EAPOL is seens as in-4way */
rtlpriv->btcoexist.btc_info.in_4way = true;
rtlpriv->btcoexist.btc_info.in_4way_ts = jiffies;
- rtlpriv->btcoexist.btc_info.in_4way_ts = jiffies;
RT_TRACE(rtlpriv, (COMP_SEND | COMP_RECV), DBG_DMESG,
"802.1X %s EAPOL pkt!!\n", (is_tx) ? "Tx" : "Rx");
diff --git a/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtc8723b1ant.c b/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtc8723b1ant.c
index 05beb16f0a0a..59553db020ef 100644
--- a/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtc8723b1ant.c
+++ b/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtc8723b1ant.c
@@ -1436,6 +1436,7 @@ static void halbtc8723b1ant_ps_tdma(struct btc_coexist *btcoexist,
coex_dm->pre_ps_tdma = coex_dm->cur_ps_tdma;
}
+static
void btc8723b1ant_tdma_dur_adj_for_acl(struct btc_coexist *btcoexist,
u8 wifi_status)
{
diff --git a/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtc8723b2ant.c b/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtc8723b2ant.c
index 4907c2ffadfe..73ec31972944 100644
--- a/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtc8723b2ant.c
+++ b/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtc8723b2ant.c
@@ -833,9 +833,9 @@ static void btc8723b2ant_set_sw_fulltime_dac_swing(struct btc_coexist *btcoex,
btc8723b2ant_set_dac_swing_reg(btcoex, 0x18);
}
-void btc8723b2ant_dac_swing(struct btc_coexist *btcoexist,
- bool force_exec, bool dac_swing_on,
- u32 dac_swing_lvl)
+static void btc8723b2ant_dac_swing(struct btc_coexist *btcoexist,
+ bool force_exec, bool dac_swing_on,
+ u32 dac_swing_lvl)
{
struct rtl_priv *rtlpriv = btcoexist->adapter;
diff --git a/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtc8821a1ant.c b/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtc8821a1ant.c
index 0b26419881c0..202597cf8915 100644
--- a/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtc8821a1ant.c
+++ b/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtc8821a1ant.c
@@ -426,39 +426,6 @@ static void btc8821a1ant_query_bt_info(struct btc_coexist *btcoexist)
btcoexist->btc_fill_h2c(btcoexist, 0x61, 1, h2c_parameter);
}
-bool btc8821a1ant_is_wifi_status_changed(struct btc_coexist *btcoexist)
-{
- static bool pre_wifi_busy = true;
- static bool pre_under_4way = true;
- static bool pre_bt_hs_on = true;
- bool wifi_busy = false, under_4way = false, bt_hs_on = false;
- bool wifi_connected = false;
-
- btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_CONNECTED,
- &wifi_connected);
- btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_BUSY, &wifi_busy);
- btcoexist->btc_get(btcoexist, BTC_GET_BL_HS_OPERATION, &bt_hs_on);
- btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_4_WAY_PROGRESS,
- &under_4way);
-
- if (wifi_connected) {
- if (wifi_busy != pre_wifi_busy) {
- pre_wifi_busy = wifi_busy;
- return true;
- }
- if (under_4way != pre_under_4way) {
- pre_under_4way = under_4way;
- return true;
- }
- if (bt_hs_on != pre_bt_hs_on) {
- pre_bt_hs_on = bt_hs_on;
- return true;
- }
- }
-
- return false;
-}
-
static void btc8821a1ant_update_bt_link_info(struct btc_coexist *btcoexist)
{
struct btc_bt_link_info *bt_link_info = &btcoexist->bt_link_info;
diff --git a/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtc8821a2ant.c b/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtc8821a2ant.c
index d5f282cb9d24..2202d5e18977 100644
--- a/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtc8821a2ant.c
+++ b/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtc8821a2ant.c
@@ -359,7 +359,7 @@ static void btc8821a2ant_query_bt_info(struct btc_coexist *btcoexist)
btcoexist->btc_fill_h2c(btcoexist, 0x61, 1, h2c_parameter);
}
-bool btc8821a2ant_is_wifi_status_changed(struct btc_coexist *btcoexist)
+static bool btc8821a2ant_is_wifi_status_changed(struct btc_coexist *btcoexist)
{
static bool pre_wifi_busy = true;
static bool pre_under_4way = true;
@@ -1517,7 +1517,7 @@ static void btc8821a2ant_action_bt_inquiry(struct btc_coexist *btcoexist)
btc8821a2ant_sw_mechanism2(btcoexist, false, false, false, 0x18);
}
-void btc8821a2ant_action_wifi_link_process(struct btc_coexist *btcoexist)
+static void btc8821a2ant_action_wifi_link_process(struct btc_coexist *btcoexist)
{
struct rtl_priv *rtlpriv = btcoexist->adapter;
u8 u8tmpa, u8tmpb;
diff --git a/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtcoutsrc.c b/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtcoutsrc.c
index 823694cb4fdb..8b6b07a936f5 100644
--- a/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtcoutsrc.c
+++ b/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtcoutsrc.c
@@ -363,6 +363,22 @@ static void halbtc_normal_lps(struct btc_coexist *btcoexist)
}
}
+static void halbtc_pre_normal_lps(struct btc_coexist *btcoexist)
+{
+ struct rtl_priv *rtlpriv = btcoexist->adapter;
+
+ if (btcoexist->bt_info.bt_ctrl_lps) {
+ btcoexist->bt_info.bt_lps_on = false;
+ rtl_lps_leave(rtlpriv->mac80211.hw);
+ }
+}
+
+static void halbtc_post_normal_lps(struct btc_coexist *btcoexist)
+{
+ if (btcoexist->bt_info.bt_ctrl_lps)
+ btcoexist->bt_info.bt_ctrl_lps = false;
+}
+
static void halbtc_leave_low_power(struct btc_coexist *btcoexist)
{
}
@@ -577,6 +593,9 @@ static bool halbtc_get(void *void_btcoexist, u8 get_type, void *out_buf)
tmp = true;
*bool_tmp = tmp;
break;
+ case BTC_GET_BL_WIFI_DUAL_BAND_CONNECTED:
+ *u8_tmp = BTC_MULTIPORT_SCC;
+ break;
case BTC_GET_BL_WIFI_BUSY:
if (halbtc_is_wifi_busy(rtlpriv))
*bool_tmp = true;
@@ -637,6 +656,9 @@ static bool halbtc_get(void *void_btcoexist, u8 get_type, void *out_buf)
case BTC_GET_BL_IS_ASUS_8723B:
*bool_tmp = false;
break;
+ case BTC_GET_BL_RF4CE_CONNECTED:
+ *bool_tmp = false;
+ break;
case BTC_GET_S4_WIFI_RSSI:
*s32_tmp = halbtc_get_wifi_rssi(rtlpriv);
break;
@@ -677,6 +699,21 @@ static bool halbtc_get(void *void_btcoexist, u8 get_type, void *out_buf)
case BTC_GET_U4_BT_FORBIDDEN_SLOT_VAL:
*u32_tmp = halbtc_get_bt_forbidden_slot_val(btcoexist);
break;
+ case BTC_GET_U4_WIFI_IQK_TOTAL:
+ *u32_tmp =
+ btcoexist->btc_phydm_query_phy_counter(btcoexist,
+ DM_INFO_IQK_ALL);
+ break;
+ case BTC_GET_U4_WIFI_IQK_OK:
+ *u32_tmp =
+ btcoexist->btc_phydm_query_phy_counter(btcoexist,
+ DM_INFO_IQK_OK);
+ break;
+ case BTC_GET_U4_WIFI_IQK_FAIL:
+ *u32_tmp =
+ btcoexist->btc_phydm_query_phy_counter(btcoexist,
+ DM_INFO_IQK_NG);
+ break;
case BTC_GET_U1_WIFI_DOT11_CHNL:
*u8_tmp = rtlphy->current_channel;
break;
@@ -788,6 +825,12 @@ static bool halbtc_set(void *void_btcoexist, u8 set_type, void *in_buf)
case BTC_SET_ACT_NORMAL_LPS:
halbtc_normal_lps(btcoexist);
break;
+ case BTC_SET_ACT_PRE_NORMAL_LPS:
+ halbtc_pre_normal_lps(btcoexist);
+ break;
+ case BTC_SET_ACT_POST_NORMAL_LPS:
+ halbtc_post_normal_lps(btcoexist);
+ break;
case BTC_SET_ACT_DISABLE_LOW_POWER:
halbtc_disable_low_power(btcoexist, *bool_tmp);
break;
@@ -1101,6 +1144,11 @@ static void halbtc_display_dbg_msg(void *bt_context, u8 disp_type,
}
}
+static u32 halbtc_get_bt_reg(void *btc_context, u8 reg_type, u32 offset)
+{
+ return 0;
+}
+
static bool halbtc_under_ips(struct btc_coexist *btcoexist)
{
struct rtl_priv *rtlpriv = btcoexist->adapter;
@@ -1119,6 +1167,25 @@ static bool halbtc_under_ips(struct btc_coexist *btcoexist)
return false;
}
+static
+u32 halbtc_get_phydm_version(void *btc_context)
+{
+ return 0;
+}
+
+static
+void halbtc_phydm_modify_ra_pcr_threshold(void *btc_context,
+ u8 ra_offset_direction,
+ u8 ra_threshold_offset)
+{
+}
+
+static
+u32 halbtc_phydm_query_phy_counter(void *btc_context, enum dm_info_query dm_id)
+{
+ return 0;
+}
+
static u8 halbtc_get_ant_det_val_from_bt(void *btc_context)
{
struct btc_coexist *btcoexist = (struct btc_coexist *)btc_context;
@@ -1232,6 +1299,7 @@ bool exhalbtc_initlize_variables(struct rtl_priv *rtlpriv)
btcoexist->btc_get = halbtc_get;
btcoexist->btc_set = halbtc_set;
btcoexist->btc_set_bt_reg = halbtc_set_bt_reg;
+ btcoexist->btc_get_bt_reg = halbtc_get_bt_reg;
btcoexist->bt_info.bt_ctrl_buf_size = false;
btcoexist->bt_info.agg_buf_size = 5;
@@ -1242,6 +1310,10 @@ bool exhalbtc_initlize_variables(struct rtl_priv *rtlpriv)
halbtc_get_bt_coex_supported_feature;
btcoexist->btc_get_bt_coex_supported_version =
halbtc_get_bt_coex_supported_version;
+ btcoexist->btc_get_bt_phydm_version = halbtc_get_phydm_version;
+ btcoexist->btc_phydm_modify_ra_pcr_threshold =
+ halbtc_phydm_modify_ra_pcr_threshold;
+ btcoexist->btc_phydm_query_phy_counter = halbtc_phydm_query_phy_counter;
btcoexist->btc_get_ant_det_val_from_bt = halbtc_get_ant_det_val_from_bt;
btcoexist->btc_get_ble_scan_type_from_bt =
halbtc_get_ble_scan_type_from_bt;
@@ -1547,7 +1619,8 @@ void exhalbtc_scan_notify_wifi_only(struct wifi_only_cfg *wifionly_cfg,
void exhalbtc_connect_notify(struct btc_coexist *btcoexist, u8 action)
{
- u8 asso_type;
+ u8 asso_type, asso_type_v2;
+ bool wifi_under_5g;
if (!halbtc_is_bt_coexist_available(btcoexist))
return;
@@ -1555,10 +1628,17 @@ void exhalbtc_connect_notify(struct btc_coexist *btcoexist, u8 action)
if (btcoexist->manual_control)
return;
- if (action)
+ btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_UNDER_5G, &wifi_under_5g);
+
+ if (action) {
asso_type = BTC_ASSOCIATE_START;
- else
+ asso_type_v2 = wifi_under_5g ? BTC_ASSOCIATE_5G_START :
+ BTC_ASSOCIATE_START;
+ } else {
asso_type = BTC_ASSOCIATE_FINISH;
+ asso_type_v2 = wifi_under_5g ? BTC_ASSOCIATE_5G_FINISH :
+ BTC_ASSOCIATE_FINISH;
+ }
halbtc_leave_low_power(btcoexist);
diff --git a/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtcoutsrc.h b/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtcoutsrc.h
index f5d8159a88eb..9eae87d19120 100644
--- a/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtcoutsrc.h
+++ b/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtcoutsrc.h
@@ -62,6 +62,8 @@
#define BTC_ANT_PATH_WIFI 0
#define BTC_ANT_PATH_BT 1
#define BTC_ANT_PATH_PTA 2
+#define BTC_ANT_PATH_WIFI5G 3
+#define BTC_ANT_PATH_AUTO 4
/* dual Antenna definition */
#define BTC_ANT_WIFI_AT_MAIN 0
#define BTC_ANT_WIFI_AT_AUX 1
@@ -154,6 +156,7 @@ struct btc_board_info {
u8 rfe_type;
u8 ant_div_cfg;
+ u8 customer_id;
};
enum btc_dbg_opcode {
@@ -204,6 +207,7 @@ enum btc_wifi_traffic_dir {
enum btc_wifi_pnp {
BTC_WIFI_PNP_WAKE_UP = 0x0,
BTC_WIFI_PNP_SLEEP = 0x1,
+ BTC_WIFI_PNP_SLEEP_KEEP_ANT = 0x2,
BTC_WIFI_PNP_MAX
};
@@ -250,6 +254,7 @@ enum btc_get_type {
BTC_GET_BL_HS_OPERATION,
BTC_GET_BL_HS_CONNECTING,
BTC_GET_BL_WIFI_CONNECTED,
+ BTC_GET_BL_WIFI_DUAL_BAND_CONNECTED,
BTC_GET_BL_WIFI_BUSY,
BTC_GET_BL_WIFI_SCAN,
BTC_GET_BL_WIFI_LINK,
@@ -333,6 +338,7 @@ enum btc_set_type {
BTC_SET_ACT_GET_BT_RSSI,
BTC_SET_ACT_AGGREGATE_CTRL,
BTC_SET_ACT_ANTPOSREGRISTRY_CTRL,
+ BTC_SET_MIMO_PS_MODE,
/********* for 1Ant **********/
/* type bool */
@@ -347,8 +353,11 @@ enum btc_set_type {
BTC_SET_ACT_LEAVE_LPS,
BTC_SET_ACT_ENTER_LPS,
BTC_SET_ACT_NORMAL_LPS,
+ BTC_SET_ACT_PRE_NORMAL_LPS,
+ BTC_SET_ACT_POST_NORMAL_LPS,
BTC_SET_ACT_INC_FORCE_EXEC_PWR_CMD_CNT,
BTC_SET_ACT_DISABLE_LOW_POWER,
+ BTC_SET_BL_BT_LNA_CONSTRAIN_LEVEL,
BTC_SET_ACT_UPDATE_RAMASK,
BTC_SET_ACT_SEND_MIMO_PS,
/* BT Coex related */
@@ -383,6 +392,7 @@ enum btc_notify_type_lps {
enum btc_notify_type_scan {
BTC_SCAN_FINISH = 0x0,
BTC_SCAN_START = 0x1,
+ BTC_SCAN_START_2G = 0x2,
BTC_SCAN_MAX
};
@@ -397,6 +407,8 @@ enum btc_notify_type_switchband {
enum btc_notify_type_associate {
BTC_ASSOCIATE_FINISH = 0x0,
BTC_ASSOCIATE_START = 0x1,
+ BTC_ASSOCIATE_5G_FINISH = 0x2,
+ BTC_ASSOCIATE_5G_START = 0x3,
BTC_ASSOCIATE_MAX
};
@@ -435,6 +447,107 @@ enum btc_notify_type_stack_operation {
BTC_STACK_OP_MAX
};
+enum {
+ BTC_CCK_1,
+ BTC_CCK_2,
+ BTC_CCK_5_5,
+ BTC_CCK_11,
+ BTC_OFDM_6,
+ BTC_OFDM_9,
+ BTC_OFDM_12,
+ BTC_OFDM_18,
+ BTC_OFDM_24,
+ BTC_OFDM_36,
+ BTC_OFDM_48,
+ BTC_OFDM_54,
+ BTC_MCS_0,
+ BTC_MCS_1,
+ BTC_MCS_2,
+ BTC_MCS_3,
+ BTC_MCS_4,
+ BTC_MCS_5,
+ BTC_MCS_6,
+ BTC_MCS_7,
+ BTC_MCS_8,
+ BTC_MCS_9,
+ BTC_MCS_10,
+ BTC_MCS_11,
+ BTC_MCS_12,
+ BTC_MCS_13,
+ BTC_MCS_14,
+ BTC_MCS_15,
+ BTC_MCS_16,
+ BTC_MCS_17,
+ BTC_MCS_18,
+ BTC_MCS_19,
+ BTC_MCS_20,
+ BTC_MCS_21,
+ BTC_MCS_22,
+ BTC_MCS_23,
+ BTC_MCS_24,
+ BTC_MCS_25,
+ BTC_MCS_26,
+ BTC_MCS_27,
+ BTC_MCS_28,
+ BTC_MCS_29,
+ BTC_MCS_30,
+ BTC_MCS_31,
+ BTC_VHT_1SS_MCS_0,
+ BTC_VHT_1SS_MCS_1,
+ BTC_VHT_1SS_MCS_2,
+ BTC_VHT_1SS_MCS_3,
+ BTC_VHT_1SS_MCS_4,
+ BTC_VHT_1SS_MCS_5,
+ BTC_VHT_1SS_MCS_6,
+ BTC_VHT_1SS_MCS_7,
+ BTC_VHT_1SS_MCS_8,
+ BTC_VHT_1SS_MCS_9,
+ BTC_VHT_2SS_MCS_0,
+ BTC_VHT_2SS_MCS_1,
+ BTC_VHT_2SS_MCS_2,
+ BTC_VHT_2SS_MCS_3,
+ BTC_VHT_2SS_MCS_4,
+ BTC_VHT_2SS_MCS_5,
+ BTC_VHT_2SS_MCS_6,
+ BTC_VHT_2SS_MCS_7,
+ BTC_VHT_2SS_MCS_8,
+ BTC_VHT_2SS_MCS_9,
+ BTC_VHT_3SS_MCS_0,
+ BTC_VHT_3SS_MCS_1,
+ BTC_VHT_3SS_MCS_2,
+ BTC_VHT_3SS_MCS_3,
+ BTC_VHT_3SS_MCS_4,
+ BTC_VHT_3SS_MCS_5,
+ BTC_VHT_3SS_MCS_6,
+ BTC_VHT_3SS_MCS_7,
+ BTC_VHT_3SS_MCS_8,
+ BTC_VHT_3SS_MCS_9,
+ BTC_VHT_4SS_MCS_0,
+ BTC_VHT_4SS_MCS_1,
+ BTC_VHT_4SS_MCS_2,
+ BTC_VHT_4SS_MCS_3,
+ BTC_VHT_4SS_MCS_4,
+ BTC_VHT_4SS_MCS_5,
+ BTC_VHT_4SS_MCS_6,
+ BTC_VHT_4SS_MCS_7,
+ BTC_VHT_4SS_MCS_8,
+ BTC_VHT_4SS_MCS_9,
+ BTC_MCS_32,
+ BTC_UNKNOWN,
+ BTC_PKT_MGNT,
+ BTC_PKT_CTRL,
+ BTC_PKT_UNKNOWN,
+ BTC_PKT_NOT_FOR_ME,
+ BTC_RATE_MAX
+};
+
+enum {
+ BTC_MULTIPORT_SCC,
+ BTC_MULTIPORT_MCC_2CHANNEL,
+ BTC_MULTIPORT_MCC_2BAND,
+ BTC_MULTIPORT_MAX
+};
+
struct btc_bt_info {
bool bt_disabled;
u8 rssi_adjust_for_agc_table_on;
@@ -454,6 +567,7 @@ struct btc_bt_info {
u16 bt_hci_ver;
u16 bt_real_fw_ver;
u8 bt_fw_ver;
+ u32 bt_get_fw_ver;
bool bt_disable_low_pwr;
@@ -525,6 +639,7 @@ struct btc_bt_link_info {
bool pan_exist;
bool pan_only;
bool slave_role;
+ bool acl_busy;
};
enum btc_antenna_pos {
@@ -625,8 +740,15 @@ struct btc_coexist {
void (*btc_set_bt_reg)(void *btc_context, u8 reg_type, u32 offset,
u32 value);
+ u32 (*btc_get_bt_reg)(void *btc_context, u8 reg_type, u32 offset);
u32 (*btc_get_bt_coex_supported_feature)(void *btcoexist);
u32 (*btc_get_bt_coex_supported_version)(void *btcoexist);
+ u32 (*btc_get_bt_phydm_version)(void *btcoexist);
+ void (*btc_phydm_modify_ra_pcr_threshold)(void *btcoexist,
+ u8 ra_offset_direction,
+ u8 ra_threshold_offset);
+ u32 (*btc_phydm_query_phy_counter)(void *btcoexist,
+ enum dm_info_query dm_id);
u8 (*btc_get_ant_det_val_from_bt)(void *btcoexist);
u8 (*btc_get_ble_scan_type_from_bt)(void *btcoexist);
u32 (*btc_get_ble_scan_para_from_bt)(void *btcoexist, u8 scan_type);
diff --git a/drivers/net/wireless/realtek/rtlwifi/rtl8188ee/pwrseq.h b/drivers/net/wireless/realtek/rtlwifi/rtl8188ee/pwrseq.h
index f2d9c6116e5c..8379a3e5198c 100644
--- a/drivers/net/wireless/realtek/rtlwifi/rtl8188ee/pwrseq.h
+++ b/drivers/net/wireless/realtek/rtlwifi/rtl8188ee/pwrseq.h
@@ -142,7 +142,7 @@
/*wait power state to suspend*/}, \
{0x0005, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK, \
PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT(3) | BIT(4), 0 \
- /*0x04[12:11] = 2b'01enable WL suspend*/},
+ /*0x04[12:11] = 2b'00 disable WL suspend*/},
#define RTL8188EE_TRANS_CARDEMU_TO_CARDDIS \
{0x0026, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK, \
@@ -179,7 +179,7 @@
/*wait power state to suspend*/}, \
{0x0005, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK, \
PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT(3)|BIT(4), 0 \
- /*0x04[12:11] = 2b'01enable WL suspend*/},
+ /*0x04[12:11] = 2b'00 disable WL suspend*/},
#define RTL8188EE_TRANS_CARDEMU_TO_PDN \
{0x0006, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK, \
diff --git a/drivers/net/wireless/realtek/rtlwifi/rtl8192ee/pwrseq.h b/drivers/net/wireless/realtek/rtlwifi/rtl8192ee/pwrseq.h
index 781eeaa6af49..c570801508cc 100644
--- a/drivers/net/wireless/realtek/rtlwifi/rtl8192ee/pwrseq.h
+++ b/drivers/net/wireless/realtek/rtlwifi/rtl8192ee/pwrseq.h
@@ -134,7 +134,7 @@
/*wait power state to suspend*/ \
{0x0086, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_SDIO_MSK, \
PWR_BASEADDR_SDIO , PWR_CMD_POLLING, BIT(1), BIT(1)}, \
- /*0x04[12:11] = 2b'01enable WL suspend*/ \
+ /*0x04[12:11] = 2b'00 disable WL suspend*/ \
{0x0005, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK, \
PWR_BASEADDR_MAC , PWR_CMD_WRITE, BIT(3) | BIT(4), 0},
@@ -181,7 +181,7 @@
/*Lock small LDO Register*/ \
{0x00CC, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_SDIO_MSK, \
PWR_BASEADDR_MAC , PWR_CMD_WRITE, BIT(2), 0}, \
- /*0x04[12:11] = 2b'01enable WL suspend*/ \
+ /*0x04[12:11] = 2b'00 disable WL suspend*/ \
{0x0005, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK, \
PWR_BASEADDR_MAC , PWR_CMD_WRITE, BIT(3) | BIT(4), 0},
diff --git a/drivers/net/wireless/realtek/rtlwifi/rtl8723ae/pwrseq.h b/drivers/net/wireless/realtek/rtlwifi/rtl8723ae/pwrseq.h
index 4ac7db526f15..e6c3aac3e9fd 100644
--- a/drivers/net/wireless/realtek/rtlwifi/rtl8723ae/pwrseq.h
+++ b/drivers/net/wireless/realtek/rtlwifi/rtl8723ae/pwrseq.h
@@ -135,7 +135,7 @@
/*wait power state to suspend*/ \
{0x0086, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_SDIO_MSK,\
PWR_BASEADDR_SDIO, PWR_CMD_POLLING, BIT(1), BIT(1)},\
- /*0x04[12:11] = 2b'01enable WL suspend*/ \
+ /*0x04[12:11] = 2b'00 disable WL suspend*/ \
{0x0005, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK,\
PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT(3)|BIT(4), 0},
@@ -172,7 +172,7 @@
{0x0086, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, \
PWR_INTF_SDIO_MSK, PWR_BASEADDR_SDIO,\
PWR_CMD_POLLING, BIT(1), BIT(1)},\
- /*0x04[12:11] = 2b'00enable WL suspend*/ \
+ /*0x04[12:11] = 2b'00 disable WL suspend*/ \
{0x0005, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, \
PWR_INTF_ALL_MSK, PWR_BASEADDR_MAC,\
PWR_CMD_WRITE, BIT(3)|BIT(4), 0},\
diff --git a/drivers/net/wireless/realtek/rtlwifi/rtl8723be/pwrseq.h b/drivers/net/wireless/realtek/rtlwifi/rtl8723be/pwrseq.h
index 0fee5e0e55c2..3367cfbc9502 100644
--- a/drivers/net/wireless/realtek/rtlwifi/rtl8723be/pwrseq.h
+++ b/drivers/net/wireless/realtek/rtlwifi/rtl8723be/pwrseq.h
@@ -204,7 +204,7 @@
/*0x23[4] = 1b'0 12H LDO enter normal mode*/ \
{0x0023, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_SDIO_MSK, \
PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT(4), 0}, \
- /*0x04[12:11] = 2b'01enable WL suspend*/ \
+ /*0x04[12:11] = 2b'00 disable WL suspend*/ \
{0x0005, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK, \
PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT(3)|BIT(4), 0},
@@ -251,7 +251,7 @@
/*0x48[16] = 0 to disable GPIO9 as EXT WAKEUP*/ \
{0x004A, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_USB_MSK, \
PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT(0), 0}, \
- /*0x04[12:11] = 2b'01enable WL suspend*/ \
+ /*0x04[12:11] = 2b'00 disable WL suspend*/ \
{0x0005, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK, \
PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT(3)|BIT(4), 0}, \
/*0x23[4] = 1b'0 12H LDO enter normal mode*/ \
diff --git a/drivers/net/wireless/realtek/rtlwifi/rtl8821ae/dm.c b/drivers/net/wireless/realtek/rtlwifi/rtl8821ae/dm.c
index b11365a5ee1f..9111ba7ff0a1 100644
--- a/drivers/net/wireless/realtek/rtlwifi/rtl8821ae/dm.c
+++ b/drivers/net/wireless/realtek/rtlwifi/rtl8821ae/dm.c
@@ -1475,7 +1475,7 @@ void rtl8812ae_dm_txpwr_track_set_pwr(struct ieee80211_hw *hw,
}
} else if (method == MIX_MODE) {
RT_TRACE(rtlpriv, COMP_POWER_TRACKING, DBG_LOUD,
- "pDM_Odm->DefaultOfdmIndex=%d, pDM_Odm->Aboslute_OFDMSwingIdx[RFPath]=%d, RF_Path = %d\n",
+ "pDM_Odm->DefaultOfdmIndex=%d, pDM_Odm->Absolute_OFDMSwingIdx[RFPath]=%d, RF_Path = %d\n",
rtldm->default_ofdm_index,
rtldm->absolute_ofdm_swing_idx[rf_path],
rf_path);
@@ -1750,7 +1750,7 @@ void rtl8812ae_dm_txpower_tracking_callback_thermalmeter(
/*Record delta swing for mix mode power tracking*/
RT_TRACE(rtlpriv, COMP_POWER_TRACKING, DBG_LOUD,
- "******Temp is higher and pDM_Odm->Aboslute_OFDMSwingIdx[ODM_RF_PATH_A] = %d\n",
+ "******Temp is higher and pDM_Odm->Absolute_OFDMSwingIdx[ODM_RF_PATH_A] = %d\n",
rtldm->absolute_ofdm_swing_idx[RF90_PATH_A]);
RT_TRACE(rtlpriv, COMP_POWER_TRACKING, DBG_LOUD,
@@ -1766,7 +1766,7 @@ void rtl8812ae_dm_txpower_tracking_callback_thermalmeter(
/*Record delta swing for mix mode power tracking*/
RT_TRACE(rtlpriv, COMP_POWER_TRACKING, DBG_LOUD,
- "******Temp is higher and pDM_Odm->Aboslute_OFDMSwingIdx[ODM_RF_PATH_B] = %d\n",
+ "******Temp is higher and pDM_Odm->Absolute_OFDMSwingIdx[ODM_RF_PATH_B] = %d\n",
rtldm->absolute_ofdm_swing_idx[RF90_PATH_B]);
} else {
RT_TRACE(rtlpriv, COMP_POWER_TRACKING, DBG_LOUD,
@@ -1782,7 +1782,7 @@ void rtl8812ae_dm_txpower_tracking_callback_thermalmeter(
-1 * delta_swing_table_idx_tdown_a[delta];
/* Record delta swing for mix mode power tracking*/
RT_TRACE(rtlpriv, COMP_POWER_TRACKING, DBG_LOUD,
- "******Temp is lower and pDM_Odm->Aboslute_OFDMSwingIdx[ODM_RF_PATH_A] = %d\n",
+ "******Temp is lower and pDM_Odm->Absolute_OFDMSwingIdx[ODM_RF_PATH_A] = %d\n",
rtldm->absolute_ofdm_swing_idx[RF90_PATH_A]);
RT_TRACE(rtlpriv, COMP_POWER_TRACKING, DBG_LOUD,
@@ -1799,7 +1799,7 @@ void rtl8812ae_dm_txpower_tracking_callback_thermalmeter(
/*Record delta swing for mix mode power tracking*/
RT_TRACE(rtlpriv, COMP_POWER_TRACKING, DBG_LOUD,
- "******Temp is lower and pDM_Odm->Aboslute_OFDMSwingIdx[ODM_RF_PATH_B] = %d\n",
+ "******Temp is lower and pDM_Odm->Absolute_OFDMSwingIdx[ODM_RF_PATH_B] = %d\n",
rtldm->absolute_ofdm_swing_idx[RF90_PATH_B]);
}
@@ -2115,7 +2115,7 @@ void rtl8821ae_dm_txpwr_track_set_pwr(struct ieee80211_hw *hw,
}
} else if (method == MIX_MODE) {
RT_TRACE(rtlpriv, COMP_POWER_TRACKING, DBG_LOUD,
- "pDM_Odm->DefaultOfdmIndex=%d,pDM_Odm->Aboslute_OFDMSwingIdx[RFPath]=%d, RF_Path = %d\n",
+ "pDM_Odm->DefaultOfdmIndex=%d,pDM_Odm->Absolute_OFDMSwingIdx[RFPath]=%d, RF_Path = %d\n",
rtldm->default_ofdm_index,
rtldm->absolute_ofdm_swing_idx[rf_path],
rf_path);
@@ -2329,7 +2329,7 @@ void rtl8821ae_dm_txpower_tracking_callback_thermalmeter(
/*Record delta swing for mix mode power tracking*/
RT_TRACE(rtlpriv, COMP_POWER_TRACKING, DBG_LOUD,
- "******Temp is higher and pDM_Odm->Aboslute_OFDMSwingIdx[ODM_RF_PATH_A] = %d\n",
+ "******Temp is higher and pDM_Odm->Absolute_OFDMSwingIdx[ODM_RF_PATH_A] = %d\n",
rtldm->absolute_ofdm_swing_idx[RF90_PATH_A]);
} else {
RT_TRACE(rtlpriv, COMP_POWER_TRACKING, DBG_LOUD,
@@ -2345,7 +2345,7 @@ void rtl8821ae_dm_txpower_tracking_callback_thermalmeter(
-1 * delta_swing_table_idx_tdown_a[delta];
/* Record delta swing for mix mode power tracking*/
RT_TRACE(rtlpriv, COMP_POWER_TRACKING, DBG_LOUD,
- "******Temp is lower and pDM_Odm->Aboslute_OFDMSwingIdx[ODM_RF_PATH_A] = %d\n",
+ "******Temp is lower and pDM_Odm->Absolute_OFDMSwingIdx[ODM_RF_PATH_A] = %d\n",
rtldm->absolute_ofdm_swing_idx[RF90_PATH_A]);
}
diff --git a/drivers/net/wireless/realtek/rtlwifi/rtl8821ae/pwrseq.h b/drivers/net/wireless/realtek/rtlwifi/rtl8821ae/pwrseq.h
index 36b3e91d996e..6dd575435c63 100644
--- a/drivers/net/wireless/realtek/rtlwifi/rtl8821ae/pwrseq.h
+++ b/drivers/net/wireless/realtek/rtlwifi/rtl8821ae/pwrseq.h
@@ -531,7 +531,7 @@ extern struct wlan_pwr_cfg rtl8812_leave_lps_flow
/*0x23[4] = 1b'0 12H LDO enter normal mode*/}, \
{0x0005, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK,\
PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT3|BIT4, 0 \
- /*0x04[12:11] = 2b'01enable WL suspend*/},
+ /*0x04[12:11] = 2b'00 disable WL suspend*/},
#define RTL8821A_TRANS_CARDEMU_TO_CARDDIS \
{0x0007, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_SDIO_MSK,\
@@ -572,7 +572,7 @@ extern struct wlan_pwr_cfg rtl8812_leave_lps_flow
/*0x48[16] = 0 to disable GPIO9 as EXT WAKEUP*/}, \
{0x0005, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK,\
PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT3|BIT4, 0 \
- /*0x04[12:11] = 2b'01enable WL suspend*/},\
+ /*0x04[12:11] = 2b'00 disable WL suspend*/},\
{0x0023, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_SDIO_MSK,\
PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT4, 0 \
/*0x23[4] = 1b'0 12H LDO enter normal mode*/}, \
diff --git a/drivers/net/wireless/realtek/rtlwifi/wifi.h b/drivers/net/wireless/realtek/rtlwifi/wifi.h
index 4f48b934ec01..d27e33960e77 100644
--- a/drivers/net/wireless/realtek/rtlwifi/wifi.h
+++ b/drivers/net/wireless/realtek/rtlwifi/wifi.h
@@ -556,6 +556,7 @@ enum rt_oem_id {
RT_CID_NETGEAR = 36,
RT_CID_PLANEX = 37,
RT_CID_CC_C = 38,
+ RT_CID_LENOVO_CHINA = 40,
};
enum hw_descs {
@@ -977,6 +978,38 @@ enum rtl_spec_ver {
RTL_SPEC_EXT_C2H = BIT(2), /* extend FW C2H (e.g. TX REPORT) */
};
+enum dm_info_query {
+ DM_INFO_FA_OFDM,
+ DM_INFO_FA_CCK,
+ DM_INFO_FA_TOTAL,
+ DM_INFO_CCA_OFDM,
+ DM_INFO_CCA_CCK,
+ DM_INFO_CCA_ALL,
+ DM_INFO_CRC32_OK_VHT,
+ DM_INFO_CRC32_OK_HT,
+ DM_INFO_CRC32_OK_LEGACY,
+ DM_INFO_CRC32_OK_CCK,
+ DM_INFO_CRC32_ERROR_VHT,
+ DM_INFO_CRC32_ERROR_HT,
+ DM_INFO_CRC32_ERROR_LEGACY,
+ DM_INFO_CRC32_ERROR_CCK,
+ DM_INFO_EDCCA_FLAG,
+ DM_INFO_OFDM_ENABLE,
+ DM_INFO_CCK_ENABLE,
+ DM_INFO_CRC32_OK_HT_AGG,
+ DM_INFO_CRC32_ERROR_HT_AGG,
+ DM_INFO_DBG_PORT_0,
+ DM_INFO_CURR_IGI,
+ DM_INFO_RSSI_MIN,
+ DM_INFO_RSSI_MAX,
+ DM_INFO_CLM_RATIO,
+ DM_INFO_NHM_RATIO,
+ DM_INFO_IQK_ALL,
+ DM_INFO_IQK_OK,
+ DM_INFO_IQK_NG,
+ DM_INFO_SIZE,
+};
+
struct octet_string {
u8 *octet;
u16 length;
diff --git a/drivers/net/wireless/rsi/Kconfig b/drivers/net/wireless/rsi/Kconfig
index f004be33fcfa..976c21866230 100644
--- a/drivers/net/wireless/rsi/Kconfig
+++ b/drivers/net/wireless/rsi/Kconfig
@@ -13,6 +13,7 @@ if WLAN_VENDOR_RSI
config RSI_91X
tristate "Redpine Signals Inc 91x WLAN driver support"
+ select BT_HCIRSI if RSI_COEX
depends on MAC80211
---help---
This option enabes support for RSI 1x1 devices.
@@ -44,7 +45,8 @@ config RSI_USB
config RSI_COEX
bool "Redpine Signals WLAN BT Coexistence support"
- depends on BT_HCIRSI && RSI_91X
+ depends on BT && RSI_91X
+ depends on !(BT=m && RSI_91X=y)
default y
---help---
This option enables the WLAN BT coex support in rsi drivers.
diff --git a/drivers/net/wireless/rsi/rsi_91x_sdio.c b/drivers/net/wireless/rsi/rsi_91x_sdio.c
index 98c7d1dae18e..d76e69c0beaa 100644
--- a/drivers/net/wireless/rsi/rsi_91x_sdio.c
+++ b/drivers/net/wireless/rsi/rsi_91x_sdio.c
@@ -576,7 +576,7 @@ static int rsi_sdio_load_data_master_write(struct rsi_hw *adapter,
{
u32 num_blocks, offset, i;
u16 msb_address, lsb_address;
- u8 temp_buf[block_size];
+ u8 *temp_buf;
int status;
num_blocks = instructions_sz / block_size;
@@ -585,11 +585,15 @@ static int rsi_sdio_load_data_master_write(struct rsi_hw *adapter,
rsi_dbg(INFO_ZONE, "ins_size: %d, num_blocks: %d\n",
instructions_sz, num_blocks);
+ temp_buf = kmalloc(block_size, GFP_KERNEL);
+ if (!temp_buf)
+ return -ENOMEM;
+
/* Loading DM ms word in the sdio slave */
status = rsi_sdio_master_access_msword(adapter, msb_address);
if (status < 0) {
rsi_dbg(ERR_ZONE, "%s: Unable to set ms word reg\n", __func__);
- return status;
+ goto out_free;
}
for (offset = 0, i = 0; i < num_blocks; i++, offset += block_size) {
@@ -601,7 +605,7 @@ static int rsi_sdio_load_data_master_write(struct rsi_hw *adapter,
temp_buf, block_size);
if (status < 0) {
rsi_dbg(ERR_ZONE, "%s: failed to write\n", __func__);
- return status;
+ goto out_free;
}
rsi_dbg(INFO_ZONE, "%s: loading block: %d\n", __func__, i);
base_address += block_size;
@@ -616,7 +620,7 @@ static int rsi_sdio_load_data_master_write(struct rsi_hw *adapter,
rsi_dbg(ERR_ZONE,
"%s: Unable to set ms word reg\n",
__func__);
- return status;
+ goto out_free;
}
}
}
@@ -632,12 +636,16 @@ static int rsi_sdio_load_data_master_write(struct rsi_hw *adapter,
temp_buf,
instructions_sz % block_size);
if (status < 0)
- return status;
+ goto out_free;
rsi_dbg(INFO_ZONE,
"Written Last Block in Address 0x%x Successfully\n",
offset | RSI_SD_REQUEST_MASTER);
}
- return 0;
+
+ status = 0;
+out_free:
+ kfree(temp_buf);
+ return status;
}
#define FLASH_SIZE_ADDR 0x04000016
@@ -645,11 +653,14 @@ static int rsi_sdio_master_reg_read(struct rsi_hw *adapter, u32 addr,
u32 *read_buf, u16 size)
{
u32 addr_on_bus, *data;
- u32 align[2] = {};
u16 ms_addr;
int status;
- data = PTR_ALIGN(&align[0], 8);
+ data = kzalloc(RSI_MASTER_REG_BUF_SIZE, GFP_KERNEL);
+ if (!data)
+ return -ENOMEM;
+
+ data = PTR_ALIGN(data, 8);
ms_addr = (addr >> 16);
status = rsi_sdio_master_access_msword(adapter, ms_addr);
@@ -657,7 +668,7 @@ static int rsi_sdio_master_reg_read(struct rsi_hw *adapter, u32 addr,
rsi_dbg(ERR_ZONE,
"%s: Unable to set ms word to common reg\n",
__func__);
- return status;
+ goto err;
}
addr &= 0xFFFF;
@@ -675,7 +686,7 @@ static int rsi_sdio_master_reg_read(struct rsi_hw *adapter, u32 addr,
(u8 *)data, 4);
if (status < 0) {
rsi_dbg(ERR_ZONE, "%s: AHB register read failed\n", __func__);
- return status;
+ goto err;
}
if (size == 2) {
if ((addr & 0x3) == 0)
@@ -697,17 +708,23 @@ static int rsi_sdio_master_reg_read(struct rsi_hw *adapter, u32 addr,
*read_buf = *data;
}
- return 0;
+err:
+ kfree(data);
+ return status;
}
static int rsi_sdio_master_reg_write(struct rsi_hw *adapter,
unsigned long addr,
unsigned long data, u16 size)
{
- unsigned long data1[2], *data_aligned;
+ unsigned long *data_aligned;
int status;
- data_aligned = PTR_ALIGN(&data1[0], 8);
+ data_aligned = kzalloc(RSI_MASTER_REG_BUF_SIZE, GFP_KERNEL);
+ if (!data_aligned)
+ return -ENOMEM;
+
+ data_aligned = PTR_ALIGN(data_aligned, 8);
if (size == 2) {
*data_aligned = ((data << 16) | (data & 0xFFFF));
@@ -726,6 +743,7 @@ static int rsi_sdio_master_reg_write(struct rsi_hw *adapter,
rsi_dbg(ERR_ZONE,
"%s: Unable to set ms word to common reg\n",
__func__);
+ kfree(data_aligned);
return -EIO;
}
addr = addr & 0xFFFF;
@@ -735,12 +753,12 @@ static int rsi_sdio_master_reg_write(struct rsi_hw *adapter,
(adapter,
(addr | RSI_SD_REQUEST_MASTER),
(u8 *)data_aligned, size);
- if (status < 0) {
+ if (status < 0)
rsi_dbg(ERR_ZONE,
"%s: Unable to do AHB reg write\n", __func__);
- return status;
- }
- return 0;
+
+ kfree(data_aligned);
+ return status;
}
/**
@@ -959,7 +977,7 @@ static int rsi_probe(struct sdio_func *pfunction,
rsi_sdio_rx_thread, "SDIO-RX-Thread");
if (status) {
rsi_dbg(ERR_ZONE, "%s: Unable to init rx thrd\n", __func__);
- goto fail_free_adapter;
+ goto fail_kill_thread;
}
skb_queue_head_init(&sdev->rx_q.head);
sdev->rx_q.num_rx_pkts = 0;
@@ -969,7 +987,7 @@ static int rsi_probe(struct sdio_func *pfunction,
rsi_dbg(ERR_ZONE, "%s: Failed to request IRQ\n", __func__);
sdio_release_host(pfunction);
status = -EIO;
- goto fail_kill_thread;
+ goto fail_claim_irq;
}
sdio_release_host(pfunction);
rsi_dbg(INIT_ZONE, "%s: Registered Interrupt handler\n", __func__);
@@ -977,7 +995,7 @@ static int rsi_probe(struct sdio_func *pfunction,
if (rsi_hal_device_init(adapter)) {
rsi_dbg(ERR_ZONE, "%s: Failed in device init\n", __func__);
status = -EINVAL;
- goto fail_kill_thread;
+ goto fail_dev_init;
}
rsi_dbg(INFO_ZONE, "===> RSI Device Init Done <===\n");
@@ -994,10 +1012,13 @@ static int rsi_probe(struct sdio_func *pfunction,
fail_dev_init:
sdio_claim_host(pfunction);
sdio_release_irq(pfunction);
- sdio_disable_func(pfunction);
sdio_release_host(pfunction);
-fail_kill_thread:
+fail_claim_irq:
rsi_kill_thread(&sdev->rx_thread);
+fail_kill_thread:
+ sdio_claim_host(pfunction);
+ sdio_disable_func(pfunction);
+ sdio_release_host(pfunction);
fail_free_adapter:
rsi_91x_deinit(adapter);
rsi_dbg(ERR_ZONE, "%s: Failed in probe...Exiting\n", __func__);
diff --git a/drivers/net/wireless/rsi/rsi_91x_usb.c b/drivers/net/wireless/rsi/rsi_91x_usb.c
index be8236f404b5..7b8bae313aa9 100644
--- a/drivers/net/wireless/rsi/rsi_91x_usb.c
+++ b/drivers/net/wireless/rsi/rsi_91x_usb.c
@@ -140,7 +140,6 @@ static int rsi_find_bulk_in_and_out_endpoints(struct usb_interface *interface,
buffer_size = endpoint->wMaxPacketSize;
dev->bulkout_endpoint_addr[bout_found] =
endpoint->bEndpointAddress;
- buffer_size = endpoint->wMaxPacketSize;
dev->bulkout_size[bout_found] = buffer_size;
bout_found++;
}
diff --git a/drivers/net/wireless/rsi/rsi_sdio.h b/drivers/net/wireless/rsi/rsi_sdio.h
index ba649be284af..ead8e7c4df3a 100644
--- a/drivers/net/wireless/rsi/rsi_sdio.h
+++ b/drivers/net/wireless/rsi/rsi_sdio.h
@@ -46,6 +46,8 @@ enum sdio_interrupt_type {
#define PKT_BUFF_AVAILABLE 1
#define FW_ASSERT_IND 2
+#define RSI_MASTER_REG_BUF_SIZE 12
+
#define RSI_DEVICE_BUFFER_STATUS_REGISTER 0xf3
#define RSI_FN1_INT_REGISTER 0xf9
#define RSI_INT_ENABLE_REGISTER 0x04
diff --git a/drivers/net/wireless/st/cw1200/debug.c b/drivers/net/wireless/st/cw1200/debug.c
index 34f97c31eecf..295cb1a29f25 100644
--- a/drivers/net/wireless/st/cw1200/debug.c
+++ b/drivers/net/wireless/st/cw1200/debug.c
@@ -398,15 +398,15 @@ int cw1200_debug_init(struct cw1200_common *priv)
if (!d->debugfs_phy)
goto err;
- if (!debugfs_create_file("status", S_IRUSR, d->debugfs_phy,
+ if (!debugfs_create_file("status", 0400, d->debugfs_phy,
priv, &fops_status))
goto err;
- if (!debugfs_create_file("counters", S_IRUSR, d->debugfs_phy,
+ if (!debugfs_create_file("counters", 0400, d->debugfs_phy,
priv, &fops_counters))
goto err;
- if (!debugfs_create_file("wsm_dumps", S_IWUSR, d->debugfs_phy,
+ if (!debugfs_create_file("wsm_dumps", 0200, d->debugfs_phy,
priv, &fops_wsm_dumps))
goto err;
diff --git a/drivers/net/wireless/st/cw1200/main.c b/drivers/net/wireless/st/cw1200/main.c
index a186d1df1f29..90dc979f260b 100644
--- a/drivers/net/wireless/st/cw1200/main.c
+++ b/drivers/net/wireless/st/cw1200/main.c
@@ -46,7 +46,7 @@ MODULE_ALIAS("cw1200_core");
/* Accept MAC address of the form macaddr=0x00,0x80,0xE1,0x30,0x40,0x50 */
static u8 cw1200_mac_template[ETH_ALEN] = {0x02, 0x80, 0xe1, 0x00, 0x00, 0x00};
-module_param_array_named(macaddr, cw1200_mac_template, byte, NULL, S_IRUGO);
+module_param_array_named(macaddr, cw1200_mac_template, byte, NULL, 0444);
MODULE_PARM_DESC(macaddr, "Override platform_data MAC address");
static char *cw1200_sdd_path;
diff --git a/drivers/net/wireless/ti/wl18xx/main.c b/drivers/net/wireless/ti/wl18xx/main.c
index 0cf3b4013dd6..ca0f936fc119 100644
--- a/drivers/net/wireless/ti/wl18xx/main.c
+++ b/drivers/net/wireless/ti/wl18xx/main.c
@@ -2092,54 +2092,51 @@ static struct platform_driver wl18xx_driver = {
};
module_platform_driver(wl18xx_driver);
-module_param_named(ht_mode, ht_mode_param, charp, S_IRUSR);
+module_param_named(ht_mode, ht_mode_param, charp, 0400);
MODULE_PARM_DESC(ht_mode, "Force HT mode: wide or siso20");
-module_param_named(board_type, board_type_param, charp, S_IRUSR);
+module_param_named(board_type, board_type_param, charp, 0400);
MODULE_PARM_DESC(board_type, "Board type: fpga, hdk (default), evb, com8 or "
"dvp");
-module_param_named(checksum, checksum_param, bool, S_IRUSR);
+module_param_named(checksum, checksum_param, bool, 0400);
MODULE_PARM_DESC(checksum, "Enable TCP checksum: boolean (defaults to false)");
-module_param_named(dc2dc, dc2dc_param, int, S_IRUSR);
+module_param_named(dc2dc, dc2dc_param, int, 0400);
MODULE_PARM_DESC(dc2dc, "External DC2DC: u8 (defaults to 0)");
-module_param_named(n_antennas_2, n_antennas_2_param, int, S_IRUSR);
+module_param_named(n_antennas_2, n_antennas_2_param, int, 0400);
MODULE_PARM_DESC(n_antennas_2,
"Number of installed 2.4GHz antennas: 1 (default) or 2");
-module_param_named(n_antennas_5, n_antennas_5_param, int, S_IRUSR);
+module_param_named(n_antennas_5, n_antennas_5_param, int, 0400);
MODULE_PARM_DESC(n_antennas_5,
"Number of installed 5GHz antennas: 1 (default) or 2");
-module_param_named(low_band_component, low_band_component_param, int,
- S_IRUSR);
+module_param_named(low_band_component, low_band_component_param, int, 0400);
MODULE_PARM_DESC(low_band_component, "Low band component: u8 "
"(default is 0x01)");
module_param_named(low_band_component_type, low_band_component_type_param,
- int, S_IRUSR);
+ int, 0400);
MODULE_PARM_DESC(low_band_component_type, "Low band component type: u8 "
"(default is 0x05 or 0x06 depending on the board_type)");
-module_param_named(high_band_component, high_band_component_param, int,
- S_IRUSR);
+module_param_named(high_band_component, high_band_component_param, int, 0400);
MODULE_PARM_DESC(high_band_component, "High band component: u8, "
"(default is 0x01)");
module_param_named(high_band_component_type, high_band_component_type_param,
- int, S_IRUSR);
+ int, 0400);
MODULE_PARM_DESC(high_band_component_type, "High band component type: u8 "
"(default is 0x09)");
module_param_named(pwr_limit_reference_11_abg,
- pwr_limit_reference_11_abg_param, int, S_IRUSR);
+ pwr_limit_reference_11_abg_param, int, 0400);
MODULE_PARM_DESC(pwr_limit_reference_11_abg, "Power limit reference: u8 "
"(default is 0xc8)");
-module_param_named(num_rx_desc,
- num_rx_desc_param, int, S_IRUSR);
+module_param_named(num_rx_desc, num_rx_desc_param, int, 0400);
MODULE_PARM_DESC(num_rx_desc_param,
"Number of Rx descriptors: u8 (default is 32)");
diff --git a/drivers/net/wireless/ti/wlcore/main.c b/drivers/net/wireless/ti/wlcore/main.c
index 09714034dbf1..3a51ab116e79 100644
--- a/drivers/net/wireless/ti/wlcore/main.c
+++ b/drivers/net/wireless/ti/wlcore/main.c
@@ -6630,20 +6630,20 @@ EXPORT_SYMBOL_GPL(wlcore_remove);
u32 wl12xx_debug_level = DEBUG_NONE;
EXPORT_SYMBOL_GPL(wl12xx_debug_level);
-module_param_named(debug_level, wl12xx_debug_level, uint, S_IRUSR | S_IWUSR);
+module_param_named(debug_level, wl12xx_debug_level, uint, 0600);
MODULE_PARM_DESC(debug_level, "wl12xx debugging level");
module_param_named(fwlog, fwlog_param, charp, 0);
MODULE_PARM_DESC(fwlog,
"FW logger options: continuous, dbgpins or disable");
-module_param(fwlog_mem_blocks, int, S_IRUSR | S_IWUSR);
+module_param(fwlog_mem_blocks, int, 0600);
MODULE_PARM_DESC(fwlog_mem_blocks, "fwlog mem_blocks");
-module_param(bug_on_recovery, int, S_IRUSR | S_IWUSR);
+module_param(bug_on_recovery, int, 0600);
MODULE_PARM_DESC(bug_on_recovery, "BUG() on fw recovery");
-module_param(no_recovery, int, S_IRUSR | S_IWUSR);
+module_param(no_recovery, int, 0600);
MODULE_PARM_DESC(no_recovery, "Prevent HW recovery. FW will remain stuck.");
MODULE_LICENSE("GPL");
diff --git a/drivers/net/wireless/ti/wlcore/sdio.c b/drivers/net/wireless/ti/wlcore/sdio.c
index f8a1fea64e25..1f727babbea0 100644
--- a/drivers/net/wireless/ti/wlcore/sdio.c
+++ b/drivers/net/wireless/ti/wlcore/sdio.c
@@ -469,7 +469,7 @@ static void __exit wl1271_exit(void)
module_init(wl1271_init);
module_exit(wl1271_exit);
-module_param(dump, bool, S_IRUSR | S_IWUSR);
+module_param(dump, bool, 0600);
MODULE_PARM_DESC(dump, "Enable sdio read/write dumps.");
MODULE_LICENSE("GPL");
diff --git a/drivers/net/wireless/ti/wlcore/sysfs.c b/drivers/net/wireless/ti/wlcore/sysfs.c
index b72e2101488b..d31eb775e023 100644
--- a/drivers/net/wireless/ti/wlcore/sysfs.c
+++ b/drivers/net/wireless/ti/wlcore/sysfs.c
@@ -80,7 +80,7 @@ static ssize_t wl1271_sysfs_store_bt_coex_state(struct device *dev,
return count;
}
-static DEVICE_ATTR(bt_coex_state, S_IRUGO | S_IWUSR,
+static DEVICE_ATTR(bt_coex_state, 0644,
wl1271_sysfs_show_bt_coex_state,
wl1271_sysfs_store_bt_coex_state);
@@ -103,8 +103,7 @@ static ssize_t wl1271_sysfs_show_hw_pg_ver(struct device *dev,
return len;
}
-static DEVICE_ATTR(hw_pg_ver, S_IRUGO,
- wl1271_sysfs_show_hw_pg_ver, NULL);
+static DEVICE_ATTR(hw_pg_ver, 0444, wl1271_sysfs_show_hw_pg_ver, NULL);
static ssize_t wl1271_sysfs_read_fwlog(struct file *filp, struct kobject *kobj,
struct bin_attribute *bin_attr,
@@ -139,7 +138,7 @@ static ssize_t wl1271_sysfs_read_fwlog(struct file *filp, struct kobject *kobj,
}
static const struct bin_attribute fwlog_attr = {
- .attr = {.name = "fwlog", .mode = S_IRUSR},
+ .attr = { .name = "fwlog", .mode = 0400 },
.read = wl1271_sysfs_read_fwlog,
};