summaryrefslogtreecommitdiff
path: root/drivers/net/wireless/ath
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2016-01-13 05:57:02 +0300
committerLinus Torvalds <torvalds@linux-foundation.org>2016-01-13 05:57:02 +0300
commitaee3bfa3307cd0da2126bdc0ea359dabea5ee8f7 (patch)
tree3d35c69e8fa835098bb90f77f30abed120681651 /drivers/net/wireless/ath
parentc597b6bcd5c624534afc3df65cdc42bb05173bca (diff)
parent415b6f19e87e350b13585591859d4fdf50772229 (diff)
downloadlinux-aee3bfa3307cd0da2126bdc0ea359dabea5ee8f7.tar.xz
Merge git://git.kernel.org/pub/scm/linux/kernel/git/davem/net-next
Pull networking updates from Davic Miller: 1) Support busy polling generically, for all NAPI drivers. From Eric Dumazet. 2) Add byte/packet counter support to nft_ct, from Floriani Westphal. 3) Add RSS/XPS support to mvneta driver, from Gregory Clement. 4) Implement IPV6_HDRINCL socket option for raw sockets, from Hannes Frederic Sowa. 5) Add support for T6 adapter to cxgb4 driver, from Hariprasad Shenai. 6) Add support for VLAN device bridging to mlxsw switch driver, from Ido Schimmel. 7) Add driver for Netronome NFP4000/NFP6000, from Jakub Kicinski. 8) Provide hwmon interface to mlxsw switch driver, from Jiri Pirko. 9) Reorganize wireless drivers into per-vendor directories just like we do for ethernet drivers. From Kalle Valo. 10) Provide a way for administrators "destroy" connected sockets via the SOCK_DESTROY socket netlink diag operation. From Lorenzo Colitti. 11) Add support to add/remove multicast routes via netlink, from Nikolay Aleksandrov. 12) Make TCP keepalive settings per-namespace, from Nikolay Borisov. 13) Add forwarding and packet duplication facilities to nf_tables, from Pablo Neira Ayuso. 14) Dead route support in MPLS, from Roopa Prabhu. 15) TSO support for thunderx chips, from Sunil Goutham. 16) Add driver for IBM's System i/p VNIC protocol, from Thomas Falcon. 17) Rationalize, consolidate, and more completely document the checksum offloading facilities in the networking stack. From Tom Herbert. 18) Support aborting an ongoing scan in mac80211/cfg80211, from Vidyullatha Kanchanapally. 19) Use per-bucket spinlock for bpf hash facility, from Tom Leiming. * git://git.kernel.org/pub/scm/linux/kernel/git/davem/net-next: (1375 commits) net: bnxt: always return values from _bnxt_get_max_rings net: bpf: reject invalid shifts phonet: properly unshare skbs in phonet_rcv() dwc_eth_qos: Fix dma address for multi-fragment skbs phy: remove an unneeded condition mdio: remove an unneed condition mdio_bus: NULL dereference on allocation error net: Fix typo in netdev_intersect_features net: freescale: mac-fec: Fix build error from phy_device API change net: freescale: ucc_geth: Fix build error from phy_device API change bonding: Prevent IPv6 link local address on enslaved devices IB/mlx5: Add flow steering support net/mlx5_core: Export flow steering API net/mlx5_core: Make ipv4/ipv6 location more clear net/mlx5_core: Enable flow steering support for the IB driver net/mlx5_core: Initialize namespaces only when supported by device net/mlx5_core: Set priority attributes net/mlx5_core: Connect flow tables net/mlx5_core: Introduce modify flow table command net/mlx5_core: Managing root flow table ...
Diffstat (limited to 'drivers/net/wireless/ath')
-rw-r--r--drivers/net/wireless/ath/Kconfig17
-rw-r--r--drivers/net/wireless/ath/ath10k/Kconfig1
-rw-r--r--drivers/net/wireless/ath/ath10k/core.c16
-rw-r--r--drivers/net/wireless/ath/ath10k/core.h38
-rw-r--r--drivers/net/wireless/ath/ath10k/debug.c199
-rw-r--r--drivers/net/wireless/ath/ath10k/debug.h4
-rw-r--r--drivers/net/wireless/ath/ath10k/htt.h15
-rw-r--r--drivers/net/wireless/ath/ath10k/htt_rx.c33
-rw-r--r--drivers/net/wireless/ath/ath10k/htt_tx.c130
-rw-r--r--drivers/net/wireless/ath/ath10k/hw.h15
-rw-r--r--drivers/net/wireless/ath/ath10k/mac.c210
-rw-r--r--drivers/net/wireless/ath/ath10k/mac.h3
-rw-r--r--drivers/net/wireless/ath/ath10k/pci.c49
-rw-r--r--drivers/net/wireless/ath/ath10k/thermal.c2
-rw-r--r--drivers/net/wireless/ath/ath10k/txrx.c15
-rw-r--r--drivers/net/wireless/ath/ath10k/wmi-tlv.c19
-rw-r--r--drivers/net/wireless/ath/ath10k/wmi-tlv.h18
-rw-r--r--drivers/net/wireless/ath/ath10k/wmi.c208
-rw-r--r--drivers/net/wireless/ath/ath10k/wmi.h130
-rw-r--r--drivers/net/wireless/ath/ath5k/base.c2
-rw-r--r--drivers/net/wireless/ath/ath6kl/cfg80211.c4
-rw-r--r--drivers/net/wireless/ath/ath6kl/htc_mbox.c5
-rw-r--r--drivers/net/wireless/ath/ath6kl/init.c16
-rw-r--r--drivers/net/wireless/ath/ath9k/Kconfig11
-rw-r--r--drivers/net/wireless/ath/ath9k/Makefile1
-rw-r--r--drivers/net/wireless/ath/ath9k/ath9k.h23
-rw-r--r--drivers/net/wireless/ath/ath9k/beacon.c3
-rw-r--r--drivers/net/wireless/ath/ath9k/channel.c56
-rw-r--r--drivers/net/wireless/ath/ath9k/common-beacon.c22
-rw-r--r--drivers/net/wireless/ath/ath9k/eeprom.c74
-rw-r--r--drivers/net/wireless/ath/ath9k/eeprom.h3
-rw-r--r--drivers/net/wireless/ath/ath9k/eeprom_4k.c76
-rw-r--r--drivers/net/wireless/ath/ath9k/eeprom_9287.c68
-rw-r--r--drivers/net/wireless/ath/ath9k/eeprom_def.c61
-rw-r--r--drivers/net/wireless/ath/ath9k/htc_drv_main.c2
-rw-r--r--drivers/net/wireless/ath/ath9k/htc_hst.c2
-rw-r--r--drivers/net/wireless/ath/ath9k/hw.c11
-rw-r--r--drivers/net/wireless/ath/ath9k/init.c1
-rw-r--r--drivers/net/wireless/ath/ath9k/main.c4
-rw-r--r--drivers/net/wireless/ath/ath9k/recv.c3
-rw-r--r--drivers/net/wireless/ath/ath9k/rng.c107
-rw-r--r--drivers/net/wireless/ath/ath9k/xmit.c23
-rw-r--r--drivers/net/wireless/ath/wcn36xx/dxe.c43
-rw-r--r--drivers/net/wireless/ath/wcn36xx/hal.h2
-rw-r--r--drivers/net/wireless/ath/wcn36xx/smd.c27
-rw-r--r--drivers/net/wireless/ath/wcn36xx/smd.h9
-rw-r--r--drivers/net/wireless/ath/wil6210/interrupt.c8
-rw-r--r--drivers/net/wireless/ath/wil6210/main.c24
-rw-r--r--drivers/net/wireless/ath/wil6210/netdev.c2
-rw-r--r--drivers/net/wireless/ath/wil6210/pcie_bus.c30
-rw-r--r--drivers/net/wireless/ath/wil6210/rx_reorder.c12
-rw-r--r--drivers/net/wireless/ath/wil6210/txrx.c5
-rw-r--r--drivers/net/wireless/ath/wil6210/wil6210.h1
-rw-r--r--drivers/net/wireless/ath/wil6210/wil_crash_dump.c3
-rw-r--r--drivers/net/wireless/ath/wil6210/wil_platform.c3
-rw-r--r--drivers/net/wireless/ath/wil6210/wil_platform.h38
-rw-r--r--drivers/net/wireless/ath/wil6210/wmi.c4
57 files changed, 1380 insertions, 531 deletions
diff --git a/drivers/net/wireless/ath/Kconfig b/drivers/net/wireless/ath/Kconfig
index ce7826009eeb..44b2470af81d 100644
--- a/drivers/net/wireless/ath/Kconfig
+++ b/drivers/net/wireless/ath/Kconfig
@@ -1,13 +1,16 @@
config ATH_COMMON
tristate
-menuconfig ATH_CARDS
- tristate "Atheros Wireless Cards"
- depends on CFG80211 && (!UML || BROKEN)
+config WLAN_VENDOR_ATH
+ bool "Atheros/Qualcomm devices"
+ default y
---help---
- This will enable the support for the Atheros wireless drivers.
- ath5k, ath9k, ath9k_htc and ar9170 drivers share some common code, this option
- enables the common ath.ko module which shares common helpers.
+ If you have a wireless card belonging to this class, say Y.
+
+ Note that the answer to this question doesn't directly affect the
+ kernel: saying N will just cause the configurator to skip all
+ the questions about cards. If you say Y, you will be asked for
+ your specific card in the following questions.
For more information and documentation on this module you can visit:
@@ -17,7 +20,7 @@ menuconfig ATH_CARDS
http://wireless.kernel.org/en/users/Drivers/Atheros
-if ATH_CARDS
+if WLAN_VENDOR_ATH
config ATH_DEBUG
bool "Atheros wireless debugging"
diff --git a/drivers/net/wireless/ath/ath10k/Kconfig b/drivers/net/wireless/ath/ath10k/Kconfig
index 72acb822bb11..03aa35f999a1 100644
--- a/drivers/net/wireless/ath/ath10k/Kconfig
+++ b/drivers/net/wireless/ath/ath10k/Kconfig
@@ -2,6 +2,7 @@ config ATH10K
tristate "Atheros 802.11ac wireless cards support"
depends on MAC80211 && HAS_DMA
select ATH_COMMON
+ select CRC32
---help---
This module adds support for wireless adapters based on
Atheros IEEE 802.11ac family of chipsets.
diff --git a/drivers/net/wireless/ath/ath10k/core.c b/drivers/net/wireless/ath/ath10k/core.c
index 0947cc271e69..b41eb3f4ee56 100644
--- a/drivers/net/wireless/ath/ath10k/core.c
+++ b/drivers/net/wireless/ath/ath10k/core.c
@@ -59,6 +59,7 @@ static const struct ath10k_hw_params ath10k_hw_params_list[] = {
.otp_exe_param = 0,
.channel_counters_freq_hz = 88000,
.max_probe_resp_desc_thres = 0,
+ .hw_4addr_pad = ATH10K_HW_4ADDR_PAD_AFTER,
.fw = {
.dir = QCA988X_HW_2_0_FW_DIR,
.fw = QCA988X_HW_2_0_FW_FILE,
@@ -95,6 +96,7 @@ static const struct ath10k_hw_params ath10k_hw_params_list[] = {
.otp_exe_param = 0,
.channel_counters_freq_hz = 88000,
.max_probe_resp_desc_thres = 0,
+ .hw_4addr_pad = ATH10K_HW_4ADDR_PAD_AFTER,
.fw = {
.dir = QCA6174_HW_2_1_FW_DIR,
.fw = QCA6174_HW_2_1_FW_FILE,
@@ -113,6 +115,7 @@ static const struct ath10k_hw_params ath10k_hw_params_list[] = {
.otp_exe_param = 0,
.channel_counters_freq_hz = 88000,
.max_probe_resp_desc_thres = 0,
+ .hw_4addr_pad = ATH10K_HW_4ADDR_PAD_AFTER,
.fw = {
.dir = QCA6174_HW_3_0_FW_DIR,
.fw = QCA6174_HW_3_0_FW_FILE,
@@ -131,6 +134,7 @@ static const struct ath10k_hw_params ath10k_hw_params_list[] = {
.otp_exe_param = 0,
.channel_counters_freq_hz = 88000,
.max_probe_resp_desc_thres = 0,
+ .hw_4addr_pad = ATH10K_HW_4ADDR_PAD_AFTER,
.fw = {
/* uses same binaries as hw3.0 */
.dir = QCA6174_HW_3_0_FW_DIR,
@@ -151,6 +155,7 @@ static const struct ath10k_hw_params ath10k_hw_params_list[] = {
.continuous_frag_desc = true,
.channel_counters_freq_hz = 150000,
.max_probe_resp_desc_thres = 24,
+ .hw_4addr_pad = ATH10K_HW_4ADDR_PAD_BEFORE,
.fw = {
.dir = QCA99X0_HW_2_0_FW_DIR,
.fw = QCA99X0_HW_2_0_FW_FILE,
@@ -211,6 +216,7 @@ static const char *const ath10k_core_fw_feature_str[] = {
[ATH10K_FW_FEATURE_SUPPORTS_SKIP_CLOCK_INIT] = "skip-clock-init",
[ATH10K_FW_FEATURE_RAW_MODE_SUPPORT] = "raw-mode",
[ATH10K_FW_FEATURE_SUPPORTS_ADAPTIVE_CCA] = "adaptive-cca",
+ [ATH10K_FW_FEATURE_MFP_SUPPORT] = "mfp",
};
static unsigned int ath10k_core_get_fw_feature_str(char *buf,
@@ -887,7 +893,7 @@ out:
if (!ar->board_data || !ar->board_len) {
ath10k_err(ar,
"failed to fetch board data for %s from %s/%s\n",
- ar->hw_params.fw.dir, boardname, filename);
+ boardname, ar->hw_params.fw.dir, filename);
ret = -ENODATA;
goto err;
}
@@ -1790,9 +1796,11 @@ static int ath10k_core_probe_fw(struct ath10k *ar)
goto err_power_down;
}
+ ath10k_debug_print_hwfw_info(ar);
+
ret = ath10k_core_get_board_id_from_otp(ar);
if (ret && ret != -EOPNOTSUPP) {
- ath10k_err(ar, "failed to get board id from otp for qca99x0: %d\n",
+ ath10k_err(ar, "failed to get board id from otp: %d\n",
ret);
return ret;
}
@@ -1803,6 +1811,8 @@ static int ath10k_core_probe_fw(struct ath10k *ar)
goto err_free_firmware_files;
}
+ ath10k_debug_print_board_info(ar);
+
ret = ath10k_core_init_firmware_features(ar);
if (ret) {
ath10k_err(ar, "fatal problem with firmware features: %d\n",
@@ -1825,7 +1835,7 @@ static int ath10k_core_probe_fw(struct ath10k *ar)
goto err_unlock;
}
- ath10k_print_driver_info(ar);
+ ath10k_debug_print_boot_info(ar);
ath10k_core_stop(ar);
mutex_unlock(&ar->conf_mutex);
diff --git a/drivers/net/wireless/ath/ath10k/core.h b/drivers/net/wireless/ath/ath10k/core.h
index 858d75f49a9f..7840cf3ef7a6 100644
--- a/drivers/net/wireless/ath/ath10k/core.h
+++ b/drivers/net/wireless/ath/ath10k/core.h
@@ -81,26 +81,20 @@ static inline const char *ath10k_bus_str(enum ath10k_bus bus)
return "unknown";
}
+enum ath10k_skb_flags {
+ ATH10K_SKB_F_NO_HWCRYPT = BIT(0),
+ ATH10K_SKB_F_DTIM_ZERO = BIT(1),
+ ATH10K_SKB_F_DELIVER_CAB = BIT(2),
+ ATH10K_SKB_F_MGMT = BIT(3),
+ ATH10K_SKB_F_QOS = BIT(4),
+};
+
struct ath10k_skb_cb {
dma_addr_t paddr;
+ u8 flags;
u8 eid;
- u8 vdev_id;
- enum ath10k_hw_txrx_mode txmode;
- bool is_protected;
-
- struct {
- u8 tid;
- u16 freq;
- bool is_offchan;
- bool nohwcrypt;
- struct ath10k_htt_txbuf *txbuf;
- u32 txbuf_paddr;
- } __packed htt;
-
- struct {
- bool dtim_zero;
- bool deliver_cab;
- } bcn;
+ u16 msdu_id;
+ struct ieee80211_vif *vif;
} __packed;
struct ath10k_skb_rxcb {
@@ -151,6 +145,7 @@ struct ath10k_wmi {
struct wmi_vdev_param_map *vdev_param;
struct wmi_pdev_param_map *pdev_param;
const struct wmi_ops *ops;
+ const struct wmi_peer_flags_map *peer_flags;
u32 num_mem_chunks;
u32 rx_decap_mode;
@@ -512,6 +507,9 @@ enum ath10k_fw_features {
/* Firmware Supports Adaptive CCA*/
ATH10K_FW_FEATURE_SUPPORTS_ADAPTIVE_CCA = 11,
+ /* Firmware supports management frame protection */
+ ATH10K_FW_FEATURE_MFP_SUPPORT = 12,
+
/* keep last */
ATH10K_FW_FEATURE_COUNT,
};
@@ -534,6 +532,9 @@ enum ath10k_dev_flags {
/* Disable HW crypto engine */
ATH10K_FLAG_HW_CRYPTO_DISABLED,
+
+ /* Bluetooth coexistance enabled */
+ ATH10K_FLAG_BTCOEX,
};
enum ath10k_cal_mode {
@@ -662,6 +663,9 @@ struct ath10k {
*/
u32 max_probe_resp_desc_thres;
+ /* The padding bytes's location is different on various chips */
+ enum ath10k_hw_4addr_pad hw_4addr_pad;
+
struct ath10k_hw_params_fw {
const char *dir;
const char *fw;
diff --git a/drivers/net/wireless/ath/ath10k/debug.c b/drivers/net/wireless/ath/ath10k/debug.c
index 6cc1aa3449c8..2bdf5408b0d9 100644
--- a/drivers/net/wireless/ath/ath10k/debug.c
+++ b/drivers/net/wireless/ath/ath10k/debug.c
@@ -19,6 +19,8 @@
#include <linux/debugfs.h>
#include <linux/vmalloc.h>
#include <linux/utsname.h>
+#include <linux/crc32.h>
+#include <linux/firmware.h>
#include "core.h"
#include "debug.h"
@@ -122,28 +124,51 @@ void ath10k_info(struct ath10k *ar, const char *fmt, ...)
}
EXPORT_SYMBOL(ath10k_info);
-void ath10k_print_driver_info(struct ath10k *ar)
+void ath10k_debug_print_hwfw_info(struct ath10k *ar)
{
char fw_features[128] = {};
- char boardinfo[100];
ath10k_core_get_fw_features_str(ar, fw_features, sizeof(fw_features));
- if (ar->id.bmi_ids_valid)
- scnprintf(boardinfo, sizeof(boardinfo), "bmi %d:%d",
- ar->id.bmi_chip_id, ar->id.bmi_board_id);
- else
- scnprintf(boardinfo, sizeof(boardinfo), "sub %04x:%04x",
- ar->id.subsystem_vendor, ar->id.subsystem_device);
-
- ath10k_info(ar, "%s (0x%08x, 0x%08x %s) fw %s fwapi %d bdapi %d htt-ver %d.%d wmi-op %d htt-op %d cal %s max-sta %d raw %d hwcrypto %d features %s\n",
+ ath10k_info(ar, "%s target 0x%08x chip_id 0x%08x sub %04x:%04x",
ar->hw_params.name,
ar->target_version,
ar->chip_id,
- boardinfo,
+ ar->id.subsystem_vendor, ar->id.subsystem_device);
+
+ ath10k_info(ar, "kconfig debug %d debugfs %d tracing %d dfs %d testmode %d\n",
+ config_enabled(CONFIG_ATH10K_DEBUG),
+ config_enabled(CONFIG_ATH10K_DEBUGFS),
+ config_enabled(CONFIG_ATH10K_TRACING),
+ config_enabled(CONFIG_ATH10K_DFS_CERTIFIED),
+ config_enabled(CONFIG_NL80211_TESTMODE));
+
+ ath10k_info(ar, "firmware ver %s api %d features %s crc32 %08x\n",
ar->hw->wiphy->fw_version,
ar->fw_api,
+ fw_features,
+ crc32_le(0, ar->firmware->data, ar->firmware->size));
+}
+
+void ath10k_debug_print_board_info(struct ath10k *ar)
+{
+ char boardinfo[100];
+
+ if (ar->id.bmi_ids_valid)
+ scnprintf(boardinfo, sizeof(boardinfo), "%d:%d",
+ ar->id.bmi_chip_id, ar->id.bmi_board_id);
+ else
+ scnprintf(boardinfo, sizeof(boardinfo), "N/A");
+
+ ath10k_info(ar, "board_file api %d bmi_id %s crc32 %08x",
ar->bd_api,
+ boardinfo,
+ crc32_le(0, ar->board->data, ar->board->size));
+}
+
+void ath10k_debug_print_boot_info(struct ath10k *ar)
+{
+ ath10k_info(ar, "htt-ver %d.%d wmi-op %d htt-op %d cal %s max-sta %d raw %d hwcrypto %d\n",
ar->htt.target_version_major,
ar->htt.target_version_minor,
ar->wmi.op_version,
@@ -151,14 +176,14 @@ void ath10k_print_driver_info(struct ath10k *ar)
ath10k_cal_mode_str(ar->cal_mode),
ar->max_num_stations,
test_bit(ATH10K_FLAG_RAW_MODE, &ar->dev_flags),
- !test_bit(ATH10K_FLAG_HW_CRYPTO_DISABLED, &ar->dev_flags),
- fw_features);
- ath10k_info(ar, "debug %d debugfs %d tracing %d dfs %d testmode %d\n",
- config_enabled(CONFIG_ATH10K_DEBUG),
- config_enabled(CONFIG_ATH10K_DEBUGFS),
- config_enabled(CONFIG_ATH10K_TRACING),
- config_enabled(CONFIG_ATH10K_DFS_CERTIFIED),
- config_enabled(CONFIG_NL80211_TESTMODE));
+ !test_bit(ATH10K_FLAG_HW_CRYPTO_DISABLED, &ar->dev_flags));
+}
+
+void ath10k_print_driver_info(struct ath10k *ar)
+{
+ ath10k_debug_print_hwfw_info(ar);
+ ath10k_debug_print_board_info(ar);
+ ath10k_debug_print_boot_info(ar);
}
EXPORT_SYMBOL(ath10k_print_driver_info);
@@ -1114,7 +1139,7 @@ static ssize_t ath10k_read_htt_max_amsdu_ampdu(struct file *file,
{
struct ath10k *ar = file->private_data;
char buf[64];
- u8 amsdu = 3, ampdu = 64;
+ u8 amsdu, ampdu;
unsigned int len;
mutex_lock(&ar->conf_mutex);
@@ -2074,6 +2099,121 @@ static const struct file_operations fops_quiet_period = {
.open = simple_open
};
+static ssize_t ath10k_write_btcoex(struct file *file,
+ const char __user *ubuf,
+ size_t count, loff_t *ppos)
+{
+ struct ath10k *ar = file->private_data;
+ char buf[32];
+ size_t buf_size;
+ bool val;
+
+ buf_size = min(count, (sizeof(buf) - 1));
+ if (copy_from_user(buf, ubuf, buf_size))
+ return -EFAULT;
+
+ buf[buf_size] = '\0';
+
+ if (strtobool(buf, &val) != 0)
+ return -EINVAL;
+
+ mutex_lock(&ar->conf_mutex);
+
+ if (!(test_bit(ATH10K_FLAG_BTCOEX, &ar->dev_flags) ^ val))
+ goto exit;
+
+ if (val)
+ set_bit(ATH10K_FLAG_BTCOEX, &ar->dev_flags);
+ else
+ clear_bit(ATH10K_FLAG_BTCOEX, &ar->dev_flags);
+
+ if (ar->state != ATH10K_STATE_ON)
+ goto exit;
+
+ ath10k_info(ar, "restarting firmware due to btcoex change");
+
+ queue_work(ar->workqueue, &ar->restart_work);
+
+exit:
+ mutex_unlock(&ar->conf_mutex);
+
+ return count;
+}
+
+static ssize_t ath10k_read_btcoex(struct file *file, char __user *ubuf,
+ size_t count, loff_t *ppos)
+{
+ char buf[32];
+ struct ath10k *ar = file->private_data;
+ int len = 0;
+
+ mutex_lock(&ar->conf_mutex);
+ len = scnprintf(buf, sizeof(buf) - len, "%d\n",
+ test_bit(ATH10K_FLAG_BTCOEX, &ar->dev_flags));
+ mutex_unlock(&ar->conf_mutex);
+
+ return simple_read_from_buffer(ubuf, count, ppos, buf, len);
+}
+
+static const struct file_operations fops_btcoex = {
+ .read = ath10k_read_btcoex,
+ .write = ath10k_write_btcoex,
+ .open = simple_open
+};
+
+static ssize_t ath10k_debug_fw_checksums_read(struct file *file,
+ char __user *user_buf,
+ size_t count, loff_t *ppos)
+{
+ struct ath10k *ar = file->private_data;
+ unsigned int len = 0, buf_len = 4096;
+ ssize_t ret_cnt;
+ char *buf;
+
+ buf = kzalloc(buf_len, GFP_KERNEL);
+ if (!buf)
+ return -ENOMEM;
+
+ mutex_lock(&ar->conf_mutex);
+
+ if (len > buf_len)
+ len = buf_len;
+
+ len += scnprintf(buf + len, buf_len - len,
+ "firmware-N.bin\t\t%08x\n",
+ crc32_le(0, ar->firmware->data, ar->firmware->size));
+ len += scnprintf(buf + len, buf_len - len,
+ "athwlan\t\t\t%08x\n",
+ crc32_le(0, ar->firmware_data, ar->firmware_len));
+ len += scnprintf(buf + len, buf_len - len,
+ "otp\t\t\t%08x\n",
+ crc32_le(0, ar->otp_data, ar->otp_len));
+ len += scnprintf(buf + len, buf_len - len,
+ "codeswap\t\t%08x\n",
+ crc32_le(0, ar->swap.firmware_codeswap_data,
+ ar->swap.firmware_codeswap_len));
+ len += scnprintf(buf + len, buf_len - len,
+ "board-N.bin\t\t%08x\n",
+ crc32_le(0, ar->board->data, ar->board->size));
+ len += scnprintf(buf + len, buf_len - len,
+ "board\t\t\t%08x\n",
+ crc32_le(0, ar->board_data, ar->board_len));
+
+ ret_cnt = simple_read_from_buffer(user_buf, count, ppos, buf, len);
+
+ mutex_unlock(&ar->conf_mutex);
+
+ kfree(buf);
+ return ret_cnt;
+}
+
+static const struct file_operations fops_fw_checksums = {
+ .read = ath10k_debug_fw_checksums_read,
+ .open = simple_open,
+ .owner = THIS_MODULE,
+ .llseek = default_llseek,
+};
+
int ath10k_debug_create(struct ath10k *ar)
{
ar->debug.fw_crash_data = vzalloc(sizeof(*ar->debug.fw_crash_data));
@@ -2123,8 +2263,8 @@ int ath10k_debug_register(struct ath10k *ar)
debugfs_create_file("wmi_services", S_IRUSR, ar->debug.debugfs_phy, ar,
&fops_wmi_services);
- debugfs_create_file("simulate_fw_crash", S_IRUSR, ar->debug.debugfs_phy,
- ar, &fops_simulate_fw_crash);
+ debugfs_create_file("simulate_fw_crash", S_IRUSR | S_IWUSR,
+ ar->debug.debugfs_phy, ar, &fops_simulate_fw_crash);
debugfs_create_file("fw_crash_dump", S_IRUSR, ar->debug.debugfs_phy,
ar, &fops_fw_crash_dump);
@@ -2141,15 +2281,15 @@ int ath10k_debug_register(struct ath10k *ar)
debugfs_create_file("chip_id", S_IRUSR, ar->debug.debugfs_phy,
ar, &fops_chip_id);
- debugfs_create_file("htt_stats_mask", S_IRUSR, ar->debug.debugfs_phy,
- ar, &fops_htt_stats_mask);
+ debugfs_create_file("htt_stats_mask", S_IRUSR | S_IWUSR,
+ ar->debug.debugfs_phy, ar, &fops_htt_stats_mask);
debugfs_create_file("htt_max_amsdu_ampdu", S_IRUSR | S_IWUSR,
ar->debug.debugfs_phy, ar,
&fops_htt_max_amsdu_ampdu);
- debugfs_create_file("fw_dbglog", S_IRUSR, ar->debug.debugfs_phy,
- ar, &fops_fw_dbglog);
+ debugfs_create_file("fw_dbglog", S_IRUSR | S_IWUSR,
+ ar->debug.debugfs_phy, ar, &fops_fw_dbglog);
debugfs_create_file("cal_data", S_IRUSR, ar->debug.debugfs_phy,
ar, &fops_cal_data);
@@ -2183,6 +2323,13 @@ int ath10k_debug_register(struct ath10k *ar)
debugfs_create_file("tpc_stats", S_IRUSR,
ar->debug.debugfs_phy, ar, &fops_tpc_stats);
+ if (test_bit(WMI_SERVICE_COEX_GPIO, ar->wmi.svc_map))
+ debugfs_create_file("btcoex", S_IRUGO | S_IWUSR,
+ ar->debug.debugfs_phy, ar, &fops_btcoex);
+
+ debugfs_create_file("fw_checksums", S_IRUSR,
+ ar->debug.debugfs_phy, ar, &fops_fw_checksums);
+
return 0;
}
diff --git a/drivers/net/wireless/ath/ath10k/debug.h b/drivers/net/wireless/ath/ath10k/debug.h
index 7de780c4ec8d..814719cf4f22 100644
--- a/drivers/net/wireless/ath/ath10k/debug.h
+++ b/drivers/net/wireless/ath/ath10k/debug.h
@@ -63,6 +63,10 @@ extern unsigned int ath10k_debug_mask;
__printf(2, 3) void ath10k_info(struct ath10k *ar, const char *fmt, ...);
__printf(2, 3) void ath10k_err(struct ath10k *ar, const char *fmt, ...);
__printf(2, 3) void ath10k_warn(struct ath10k *ar, const char *fmt, ...);
+
+void ath10k_debug_print_hwfw_info(struct ath10k *ar);
+void ath10k_debug_print_board_info(struct ath10k *ar);
+void ath10k_debug_print_boot_info(struct ath10k *ar);
void ath10k_print_driver_info(struct ath10k *ar);
#ifdef CONFIG_ATH10K_DEBUGFS
diff --git a/drivers/net/wireless/ath/ath10k/htt.h b/drivers/net/wireless/ath/ath10k/htt.h
index 2bad50e520b5..47ca048feaf0 100644
--- a/drivers/net/wireless/ath/ath10k/htt.h
+++ b/drivers/net/wireless/ath/ath10k/htt.h
@@ -166,8 +166,13 @@ struct htt_data_tx_desc {
__le16 len;
__le16 id;
__le32 frags_paddr;
- __le16 peerid;
- __le16 freq;
+ union {
+ __le32 peerid;
+ struct {
+ __le16 peerid;
+ __le16 freq;
+ } __packed offchan_tx;
+ } __packed;
u8 prefetch[0]; /* start of frame, for FW classification engine */
} __packed;
@@ -1597,6 +1602,10 @@ void __ath10k_htt_tx_dec_pending(struct ath10k_htt *htt, bool limit_mgmt_desc);
int ath10k_htt_tx_alloc_msdu_id(struct ath10k_htt *htt, struct sk_buff *skb);
void ath10k_htt_tx_free_msdu_id(struct ath10k_htt *htt, u16 msdu_id);
int ath10k_htt_mgmt_tx(struct ath10k_htt *htt, struct sk_buff *);
-int ath10k_htt_tx(struct ath10k_htt *htt, struct sk_buff *);
+int ath10k_htt_tx(struct ath10k_htt *htt,
+ enum ath10k_hw_txrx_mode txmode,
+ struct sk_buff *msdu);
+void ath10k_htt_rx_pktlog_completion_handler(struct ath10k *ar,
+ struct sk_buff *skb);
#endif
diff --git a/drivers/net/wireless/ath/ath10k/htt_rx.c b/drivers/net/wireless/ath/ath10k/htt_rx.c
index 6060dda4e910..91afa3ae414c 100644
--- a/drivers/net/wireless/ath/ath10k/htt_rx.c
+++ b/drivers/net/wireless/ath/ath10k/htt_rx.c
@@ -536,7 +536,7 @@ int ath10k_htt_rx_alloc(struct ath10k_htt *htt)
size = htt->rx_ring.size * sizeof(htt->rx_ring.paddrs_ring);
- vaddr = dma_alloc_coherent(htt->ar->dev, size, &paddr, GFP_DMA);
+ vaddr = dma_alloc_coherent(htt->ar->dev, size, &paddr, GFP_KERNEL);
if (!vaddr)
goto err_dma_ring;
@@ -545,7 +545,7 @@ int ath10k_htt_rx_alloc(struct ath10k_htt *htt)
vaddr = dma_alloc_coherent(htt->ar->dev,
sizeof(*htt->rx_ring.alloc_idx.vaddr),
- &paddr, GFP_DMA);
+ &paddr, GFP_KERNEL);
if (!vaddr)
goto err_dma_idx;
@@ -674,7 +674,7 @@ static void ath10k_htt_rx_h_rates(struct ath10k *ar,
rate &= ~RX_PPDU_START_RATE_FLAG;
sband = &ar->mac.sbands[status->band];
- status->rate_idx = ath10k_mac_hw_rate_to_idx(sband, rate);
+ status->rate_idx = ath10k_mac_hw_rate_to_idx(sband, rate, cck);
break;
case HTT_RX_HT:
case HTT_RX_HT_WITH_TXBF:
@@ -1114,7 +1114,20 @@ static void ath10k_htt_rx_h_undecap_nwifi(struct ath10k *ar,
*/
/* pull decapped header and copy SA & DA */
- hdr = (struct ieee80211_hdr *)msdu->data;
+ if ((ar->hw_params.hw_4addr_pad == ATH10K_HW_4ADDR_PAD_BEFORE) &&
+ ieee80211_has_a4(((struct ieee80211_hdr *)first_hdr)->frame_control)) {
+ /* The QCA99X0 4 address mode pad 2 bytes at the
+ * beginning of MSDU
+ */
+ hdr = (struct ieee80211_hdr *)(msdu->data + 2);
+ /* The skb length need be extended 2 as the 2 bytes at the tail
+ * be excluded due to the padding
+ */
+ skb_put(msdu, 2);
+ } else {
+ hdr = (struct ieee80211_hdr *)(msdu->data);
+ }
+
hdr_len = ath10k_htt_rx_nwifi_hdrlen(ar, hdr);
ether_addr_copy(da, ieee80211_get_DA(hdr));
ether_addr_copy(sa, ieee80211_get_SA(hdr));
@@ -2127,6 +2140,18 @@ void ath10k_htt_t2h_msg_handler(struct ath10k *ar, struct sk_buff *skb)
}
EXPORT_SYMBOL(ath10k_htt_t2h_msg_handler);
+void ath10k_htt_rx_pktlog_completion_handler(struct ath10k *ar,
+ struct sk_buff *skb)
+{
+ struct ath10k_pktlog_10_4_hdr *hdr =
+ (struct ath10k_pktlog_10_4_hdr *)skb->data;
+
+ trace_ath10k_htt_pktlog(ar, hdr->payload,
+ sizeof(*hdr) + __le16_to_cpu(hdr->size));
+ dev_kfree_skb_any(skb);
+}
+EXPORT_SYMBOL(ath10k_htt_rx_pktlog_completion_handler);
+
static void ath10k_htt_txrx_compl_task(unsigned long ptr)
{
struct ath10k_htt *htt = (struct ath10k_htt *)ptr;
diff --git a/drivers/net/wireless/ath/ath10k/htt_tx.c b/drivers/net/wireless/ath/ath10k/htt_tx.c
index 16823970dbfd..b3adadb5f824 100644
--- a/drivers/net/wireless/ath/ath10k/htt_tx.c
+++ b/drivers/net/wireless/ath/ath10k/htt_tx.c
@@ -111,7 +111,7 @@ int ath10k_htt_tx_alloc(struct ath10k_htt *htt)
size = htt->max_num_pending_tx * sizeof(struct ath10k_htt_txbuf);
htt->txbuf.vaddr = dma_alloc_coherent(ar->dev, size,
&htt->txbuf.paddr,
- GFP_DMA);
+ GFP_KERNEL);
if (!htt->txbuf.vaddr) {
ath10k_err(ar, "failed to alloc tx buffer\n");
ret = -ENOMEM;
@@ -124,7 +124,7 @@ int ath10k_htt_tx_alloc(struct ath10k_htt *htt)
size = htt->max_num_pending_tx * sizeof(struct htt_msdu_ext_desc);
htt->frag_desc.vaddr = dma_alloc_coherent(ar->dev, size,
&htt->frag_desc.paddr,
- GFP_DMA);
+ GFP_KERNEL);
if (!htt->frag_desc.vaddr) {
ath10k_warn(ar, "failed to alloc fragment desc memory\n");
ret = -ENOMEM;
@@ -439,6 +439,35 @@ int ath10k_htt_h2t_aggr_cfg_msg(struct ath10k_htt *htt,
return 0;
}
+static u8 ath10k_htt_tx_get_vdev_id(struct ath10k *ar, struct sk_buff *skb)
+{
+ struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
+ struct ath10k_skb_cb *cb = ATH10K_SKB_CB(skb);
+ struct ath10k_vif *arvif = (void *)cb->vif->drv_priv;
+
+ if (info->flags & IEEE80211_TX_CTL_TX_OFFCHAN)
+ return ar->scan.vdev_id;
+ else if (cb->vif)
+ return arvif->vdev_id;
+ else if (ar->monitor_started)
+ return ar->monitor_vdev_id;
+ else
+ return 0;
+}
+
+static u8 ath10k_htt_tx_get_tid(struct sk_buff *skb, bool is_eth)
+{
+ struct ieee80211_hdr *hdr = (void *)skb->data;
+ struct ath10k_skb_cb *cb = ATH10K_SKB_CB(skb);
+
+ if (!is_eth && ieee80211_is_mgmt(hdr->frame_control))
+ return HTT_DATA_TX_EXT_TID_MGMT;
+ else if (cb->flags & ATH10K_SKB_F_QOS)
+ return skb->priority % IEEE80211_QOS_CTL_TID_MASK;
+ else
+ return HTT_DATA_TX_EXT_TID_NON_QOS_MCAST_BCAST;
+}
+
int ath10k_htt_mgmt_tx(struct ath10k_htt *htt, struct sk_buff *msdu)
{
struct ath10k *ar = htt->ar;
@@ -446,7 +475,7 @@ int ath10k_htt_mgmt_tx(struct ath10k_htt *htt, struct sk_buff *msdu)
struct sk_buff *txdesc = NULL;
struct htt_cmd *cmd;
struct ath10k_skb_cb *skb_cb = ATH10K_SKB_CB(msdu);
- u8 vdev_id = skb_cb->vdev_id;
+ u8 vdev_id = ath10k_htt_tx_get_vdev_id(ar, msdu);
int len = 0;
int msdu_id = -1;
int res;
@@ -477,6 +506,13 @@ int ath10k_htt_mgmt_tx(struct ath10k_htt *htt, struct sk_buff *msdu)
msdu_id = res;
+ if ((ieee80211_is_action(hdr->frame_control) ||
+ ieee80211_is_deauth(hdr->frame_control) ||
+ ieee80211_is_disassoc(hdr->frame_control)) &&
+ ieee80211_has_protected(hdr->frame_control)) {
+ skb_put(msdu, IEEE80211_CCMP_MIC_LEN);
+ }
+
txdesc = ath10k_htc_alloc_skb(ar, len);
if (!txdesc) {
res = -ENOMEM;
@@ -503,8 +539,6 @@ int ath10k_htt_mgmt_tx(struct ath10k_htt *htt, struct sk_buff *msdu)
memcpy(cmd->mgmt_tx.hdr, msdu->data,
min_t(int, msdu->len, HTT_MGMT_FRM_HDR_DOWNLOAD_LEN));
- skb_cb->htt.txbuf = NULL;
-
res = ath10k_htc_send(&htt->ar->htc, htt->eid, txdesc);
if (res)
goto err_unmap_msdu;
@@ -525,21 +559,27 @@ err:
return res;
}
-int ath10k_htt_tx(struct ath10k_htt *htt, struct sk_buff *msdu)
+int ath10k_htt_tx(struct ath10k_htt *htt, enum ath10k_hw_txrx_mode txmode,
+ struct sk_buff *msdu)
{
struct ath10k *ar = htt->ar;
struct device *dev = ar->dev;
struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)msdu->data;
+ struct ieee80211_tx_info *info = IEEE80211_SKB_CB(msdu);
struct ath10k_skb_cb *skb_cb = ATH10K_SKB_CB(msdu);
struct ath10k_hif_sg_item sg_items[2];
+ struct ath10k_htt_txbuf *txbuf;
struct htt_data_tx_desc_frag *frags;
- u8 vdev_id = skb_cb->vdev_id;
- u8 tid = skb_cb->htt.tid;
+ bool is_eth = (txmode == ATH10K_HW_TXRX_ETHERNET);
+ u8 vdev_id = ath10k_htt_tx_get_vdev_id(ar, msdu);
+ u8 tid = ath10k_htt_tx_get_tid(msdu, is_eth);
int prefetch_len;
int res;
u8 flags0 = 0;
u16 msdu_id, flags1 = 0;
+ u16 freq = 0;
u32 frags_paddr = 0;
+ u32 txbuf_paddr;
struct htt_msdu_ext_desc *ext_desc = NULL;
bool limit_mgmt_desc = false;
bool is_probe_resp = false;
@@ -567,17 +607,17 @@ int ath10k_htt_tx(struct ath10k_htt *htt, struct sk_buff *msdu)
prefetch_len = min(htt->prefetch_len, msdu->len);
prefetch_len = roundup(prefetch_len, 4);
- skb_cb->htt.txbuf = &htt->txbuf.vaddr[msdu_id];
- skb_cb->htt.txbuf_paddr = htt->txbuf.paddr +
- (sizeof(struct ath10k_htt_txbuf) * msdu_id);
+ txbuf = &htt->txbuf.vaddr[msdu_id];
+ txbuf_paddr = htt->txbuf.paddr +
+ (sizeof(struct ath10k_htt_txbuf) * msdu_id);
if ((ieee80211_is_action(hdr->frame_control) ||
ieee80211_is_deauth(hdr->frame_control) ||
ieee80211_is_disassoc(hdr->frame_control)) &&
ieee80211_has_protected(hdr->frame_control)) {
skb_put(msdu, IEEE80211_CCMP_MIC_LEN);
- } else if (!skb_cb->htt.nohwcrypt &&
- skb_cb->txmode == ATH10K_HW_TXRX_RAW &&
+ } else if (!(skb_cb->flags & ATH10K_SKB_F_NO_HWCRYPT) &&
+ txmode == ATH10K_HW_TXRX_RAW &&
ieee80211_has_protected(hdr->frame_control)) {
skb_put(msdu, IEEE80211_CCMP_MIC_LEN);
}
@@ -590,7 +630,10 @@ int ath10k_htt_tx(struct ath10k_htt *htt, struct sk_buff *msdu)
goto err_free_msdu_id;
}
- switch (skb_cb->txmode) {
+ if (unlikely(info->flags & IEEE80211_TX_CTL_TX_OFFCHAN))
+ freq = ar->scan.roc_freq;
+
+ switch (txmode) {
case ATH10K_HW_TXRX_RAW:
case ATH10K_HW_TXRX_NATIVE_WIFI:
flags0 |= HTT_DATA_TX_DESC_FLAGS0_MAC_HDR_PRESENT;
@@ -610,16 +653,16 @@ int ath10k_htt_tx(struct ath10k_htt *htt, struct sk_buff *msdu)
frags_paddr = htt->frag_desc.paddr +
(sizeof(struct htt_msdu_ext_desc) * msdu_id);
} else {
- frags = skb_cb->htt.txbuf->frags;
+ frags = txbuf->frags;
frags[0].dword_addr.paddr =
__cpu_to_le32(skb_cb->paddr);
frags[0].dword_addr.len = __cpu_to_le32(msdu->len);
frags[1].dword_addr.paddr = 0;
frags[1].dword_addr.len = 0;
- frags_paddr = skb_cb->htt.txbuf_paddr;
+ frags_paddr = txbuf_paddr;
}
- flags0 |= SM(skb_cb->txmode, HTT_DATA_TX_DESC_FLAGS0_PKT_TYPE);
+ flags0 |= SM(txmode, HTT_DATA_TX_DESC_FLAGS0_PKT_TYPE);
break;
case ATH10K_HW_TXRX_MGMT:
flags0 |= SM(ATH10K_HW_TXRX_MGMT,
@@ -646,17 +689,13 @@ int ath10k_htt_tx(struct ath10k_htt *htt, struct sk_buff *msdu)
* avoid extra memory allocations, compress data structures and thus
* improve performance. */
- skb_cb->htt.txbuf->htc_hdr.eid = htt->eid;
- skb_cb->htt.txbuf->htc_hdr.len = __cpu_to_le16(
- sizeof(skb_cb->htt.txbuf->cmd_hdr) +
- sizeof(skb_cb->htt.txbuf->cmd_tx) +
- prefetch_len);
- skb_cb->htt.txbuf->htc_hdr.flags = 0;
-
- if (skb_cb->htt.nohwcrypt)
- flags0 |= HTT_DATA_TX_DESC_FLAGS0_NO_ENCRYPT;
+ txbuf->htc_hdr.eid = htt->eid;
+ txbuf->htc_hdr.len = __cpu_to_le16(sizeof(txbuf->cmd_hdr) +
+ sizeof(txbuf->cmd_tx) +
+ prefetch_len);
+ txbuf->htc_hdr.flags = 0;
- if (!skb_cb->is_protected)
+ if (skb_cb->flags & ATH10K_SKB_F_NO_HWCRYPT)
flags0 |= HTT_DATA_TX_DESC_FLAGS0_NO_ENCRYPT;
flags1 |= SM((u16)vdev_id, HTT_DATA_TX_DESC_FLAGS1_VDEV_ID);
@@ -675,20 +714,27 @@ int ath10k_htt_tx(struct ath10k_htt *htt, struct sk_buff *msdu)
*/
flags1 |= HTT_DATA_TX_DESC_FLAGS1_POSTPONED;
- skb_cb->htt.txbuf->cmd_hdr.msg_type = HTT_H2T_MSG_TYPE_TX_FRM;
- skb_cb->htt.txbuf->cmd_tx.flags0 = flags0;
- skb_cb->htt.txbuf->cmd_tx.flags1 = __cpu_to_le16(flags1);
- skb_cb->htt.txbuf->cmd_tx.len = __cpu_to_le16(msdu->len);
- skb_cb->htt.txbuf->cmd_tx.id = __cpu_to_le16(msdu_id);
- skb_cb->htt.txbuf->cmd_tx.frags_paddr = __cpu_to_le32(frags_paddr);
- skb_cb->htt.txbuf->cmd_tx.peerid = __cpu_to_le16(HTT_INVALID_PEERID);
- skb_cb->htt.txbuf->cmd_tx.freq = __cpu_to_le16(skb_cb->htt.freq);
+ txbuf->cmd_hdr.msg_type = HTT_H2T_MSG_TYPE_TX_FRM;
+ txbuf->cmd_tx.flags0 = flags0;
+ txbuf->cmd_tx.flags1 = __cpu_to_le16(flags1);
+ txbuf->cmd_tx.len = __cpu_to_le16(msdu->len);
+ txbuf->cmd_tx.id = __cpu_to_le16(msdu_id);
+ txbuf->cmd_tx.frags_paddr = __cpu_to_le32(frags_paddr);
+ if (ath10k_mac_tx_frm_has_freq(ar)) {
+ txbuf->cmd_tx.offchan_tx.peerid =
+ __cpu_to_le16(HTT_INVALID_PEERID);
+ txbuf->cmd_tx.offchan_tx.freq =
+ __cpu_to_le16(freq);
+ } else {
+ txbuf->cmd_tx.peerid =
+ __cpu_to_le32(HTT_INVALID_PEERID);
+ }
trace_ath10k_htt_tx(ar, msdu_id, msdu->len, vdev_id, tid);
ath10k_dbg(ar, ATH10K_DBG_HTT,
"htt tx flags0 %hhu flags1 %hu len %d id %hu frags_paddr %08x, msdu_paddr %08x vdev %hhu tid %hhu freq %hu\n",
flags0, flags1, msdu->len, msdu_id, frags_paddr,
- (u32)skb_cb->paddr, vdev_id, tid, skb_cb->htt.freq);
+ (u32)skb_cb->paddr, vdev_id, tid, freq);
ath10k_dbg_dump(ar, ATH10K_DBG_HTT_DUMP, NULL, "htt tx msdu: ",
msdu->data, msdu->len);
trace_ath10k_tx_hdr(ar, msdu->data, msdu->len);
@@ -696,12 +742,12 @@ int ath10k_htt_tx(struct ath10k_htt *htt, struct sk_buff *msdu)
sg_items[0].transfer_id = 0;
sg_items[0].transfer_context = NULL;
- sg_items[0].vaddr = &skb_cb->htt.txbuf->htc_hdr;
- sg_items[0].paddr = skb_cb->htt.txbuf_paddr +
- sizeof(skb_cb->htt.txbuf->frags);
- sg_items[0].len = sizeof(skb_cb->htt.txbuf->htc_hdr) +
- sizeof(skb_cb->htt.txbuf->cmd_hdr) +
- sizeof(skb_cb->htt.txbuf->cmd_tx);
+ sg_items[0].vaddr = &txbuf->htc_hdr;
+ sg_items[0].paddr = txbuf_paddr +
+ sizeof(txbuf->frags);
+ sg_items[0].len = sizeof(txbuf->htc_hdr) +
+ sizeof(txbuf->cmd_hdr) +
+ sizeof(txbuf->cmd_tx);
sg_items[1].transfer_id = 0;
sg_items[1].transfer_context = NULL;
diff --git a/drivers/net/wireless/ath/ath10k/hw.h b/drivers/net/wireless/ath/ath10k/hw.h
index 713c2bcea178..0678831e8671 100644
--- a/drivers/net/wireless/ath/ath10k/hw.h
+++ b/drivers/net/wireless/ath/ath10k/hw.h
@@ -286,6 +286,16 @@ struct ath10k_pktlog_hdr {
u8 payload[0];
} __packed;
+struct ath10k_pktlog_10_4_hdr {
+ __le16 flags;
+ __le16 missed_cnt;
+ __le16 log_type;
+ __le16 size;
+ __le32 timestamp;
+ __le32 type_specific_data;
+ u8 payload[0];
+} __packed;
+
enum ath10k_hw_rate_ofdm {
ATH10K_HW_RATE_OFDM_48M = 0,
ATH10K_HW_RATE_OFDM_24M,
@@ -307,6 +317,11 @@ enum ath10k_hw_rate_cck {
ATH10K_HW_RATE_CCK_SP_2M,
};
+enum ath10k_hw_4addr_pad {
+ ATH10K_HW_4ADDR_PAD_AFTER,
+ ATH10K_HW_4ADDR_PAD_BEFORE,
+};
+
/* Target specific defines for MAIN firmware */
#define TARGET_NUM_VDEVS 8
#define TARGET_NUM_PEER_AST 2
diff --git a/drivers/net/wireless/ath/ath10k/mac.c b/drivers/net/wireless/ath/ath10k/mac.c
index 95a55405ebf0..6146a293601a 100644
--- a/drivers/net/wireless/ath/ath10k/mac.c
+++ b/drivers/net/wireless/ath/ath10k/mac.c
@@ -90,7 +90,7 @@ static u8 ath10k_mac_bitrate_to_rate(int bitrate)
}
u8 ath10k_mac_hw_rate_to_idx(const struct ieee80211_supported_band *sband,
- u8 hw_rate)
+ u8 hw_rate, bool cck)
{
const struct ieee80211_rate *rate;
int i;
@@ -98,6 +98,9 @@ u8 ath10k_mac_hw_rate_to_idx(const struct ieee80211_supported_band *sband,
for (i = 0; i < sband->n_bitrates; i++) {
rate = &sband->bitrates[i];
+ if (ath10k_mac_bitrate_is_cck(rate->bitrate) != cck)
+ continue;
+
if (rate->hw_value == hw_rate)
return i;
else if (rate->flags & IEEE80211_RATE_SHORT_PREAMBLE &&
@@ -247,7 +250,8 @@ static int ath10k_install_peer_wep_keys(struct ath10k_vif *arvif,
lockdep_assert_held(&ar->conf_mutex);
if (WARN_ON(arvif->vif->type != NL80211_IFTYPE_AP &&
- arvif->vif->type != NL80211_IFTYPE_ADHOC))
+ arvif->vif->type != NL80211_IFTYPE_ADHOC &&
+ arvif->vif->type != NL80211_IFTYPE_MESH_POINT))
return -EINVAL;
spin_lock_bh(&ar->data_lock);
@@ -1960,7 +1964,7 @@ static void ath10k_peer_assoc_h_basic(struct ath10k *ar,
ether_addr_copy(arg->addr, sta->addr);
arg->vdev_id = arvif->vdev_id;
arg->peer_aid = aid;
- arg->peer_flags |= WMI_PEER_AUTH;
+ arg->peer_flags |= arvif->ar->wmi.peer_flags->auth;
arg->peer_listen_intval = ath10k_peer_assoc_h_listen_intval(ar, vif);
arg->peer_num_spatial_streams = 1;
arg->peer_caps = vif->bss_conf.assoc_capability;
@@ -1968,6 +1972,7 @@ static void ath10k_peer_assoc_h_basic(struct ath10k *ar,
static void ath10k_peer_assoc_h_crypto(struct ath10k *ar,
struct ieee80211_vif *vif,
+ struct ieee80211_sta *sta,
struct wmi_peer_assoc_complete_arg *arg)
{
struct ieee80211_bss_conf *info = &vif->bss_conf;
@@ -2002,12 +2007,17 @@ static void ath10k_peer_assoc_h_crypto(struct ath10k *ar,
/* FIXME: base on RSN IE/WPA IE is a correct idea? */
if (rsnie || wpaie) {
ath10k_dbg(ar, ATH10K_DBG_WMI, "%s: rsn ie found\n", __func__);
- arg->peer_flags |= WMI_PEER_NEED_PTK_4_WAY;
+ arg->peer_flags |= ar->wmi.peer_flags->need_ptk_4_way;
}
if (wpaie) {
ath10k_dbg(ar, ATH10K_DBG_WMI, "%s: wpa ie found\n", __func__);
- arg->peer_flags |= WMI_PEER_NEED_GTK_2_WAY;
+ arg->peer_flags |= ar->wmi.peer_flags->need_gtk_2_way;
+ }
+
+ if (sta->mfp &&
+ test_bit(ATH10K_FW_FEATURE_MFP_SUPPORT, ar->fw_features)) {
+ arg->peer_flags |= ar->wmi.peer_flags->pmf;
}
}
@@ -2104,7 +2114,7 @@ static void ath10k_peer_assoc_h_ht(struct ath10k *ar,
ath10k_peer_assoc_h_vht_masked(vht_mcs_mask))
return;
- arg->peer_flags |= WMI_PEER_HT;
+ arg->peer_flags |= ar->wmi.peer_flags->ht;
arg->peer_max_mpdu = (1 << (IEEE80211_HT_MAX_AMPDU_FACTOR +
ht_cap->ampdu_factor)) - 1;
@@ -2115,10 +2125,10 @@ static void ath10k_peer_assoc_h_ht(struct ath10k *ar,
arg->peer_rate_caps |= WMI_RC_HT_FLAG;
if (ht_cap->cap & IEEE80211_HT_CAP_LDPC_CODING)
- arg->peer_flags |= WMI_PEER_LDPC;
+ arg->peer_flags |= ar->wmi.peer_flags->ldbc;
if (sta->bandwidth >= IEEE80211_STA_RX_BW_40) {
- arg->peer_flags |= WMI_PEER_40MHZ;
+ arg->peer_flags |= ar->wmi.peer_flags->bw40;
arg->peer_rate_caps |= WMI_RC_CW40_FLAG;
}
@@ -2132,7 +2142,7 @@ static void ath10k_peer_assoc_h_ht(struct ath10k *ar,
if (ht_cap->cap & IEEE80211_HT_CAP_TX_STBC) {
arg->peer_rate_caps |= WMI_RC_TX_STBC_FLAG;
- arg->peer_flags |= WMI_PEER_STBC;
+ arg->peer_flags |= ar->wmi.peer_flags->stbc;
}
if (ht_cap->cap & IEEE80211_HT_CAP_RX_STBC) {
@@ -2140,7 +2150,7 @@ static void ath10k_peer_assoc_h_ht(struct ath10k *ar,
stbc = stbc >> IEEE80211_HT_CAP_RX_STBC_SHIFT;
stbc = stbc << WMI_RC_RX_STBC_FLAG_S;
arg->peer_rate_caps |= stbc;
- arg->peer_flags |= WMI_PEER_STBC;
+ arg->peer_flags |= ar->wmi.peer_flags->stbc;
}
if (ht_cap->mcs.rx_mask[1] && ht_cap->mcs.rx_mask[2])
@@ -2321,10 +2331,10 @@ static void ath10k_peer_assoc_h_vht(struct ath10k *ar,
if (ath10k_peer_assoc_h_vht_masked(vht_mcs_mask))
return;
- arg->peer_flags |= WMI_PEER_VHT;
+ arg->peer_flags |= ar->wmi.peer_flags->vht;
if (def.chan->band == IEEE80211_BAND_2GHZ)
- arg->peer_flags |= WMI_PEER_VHT_2G;
+ arg->peer_flags |= ar->wmi.peer_flags->vht_2g;
arg->peer_vht_caps = vht_cap->cap;
@@ -2341,7 +2351,7 @@ static void ath10k_peer_assoc_h_vht(struct ath10k *ar,
ampdu_factor)) - 1);
if (sta->bandwidth == IEEE80211_STA_RX_BW_80)
- arg->peer_flags |= WMI_PEER_80MHZ;
+ arg->peer_flags |= ar->wmi.peer_flags->bw80;
arg->peer_vht_rates.rx_max_rate =
__le16_to_cpu(vht_cap->vht_mcs.rx_highest);
@@ -2366,27 +2376,28 @@ static void ath10k_peer_assoc_h_qos(struct ath10k *ar,
switch (arvif->vdev_type) {
case WMI_VDEV_TYPE_AP:
if (sta->wme)
- arg->peer_flags |= WMI_PEER_QOS;
+ arg->peer_flags |= arvif->ar->wmi.peer_flags->qos;
if (sta->wme && sta->uapsd_queues) {
- arg->peer_flags |= WMI_PEER_APSD;
+ arg->peer_flags |= arvif->ar->wmi.peer_flags->apsd;
arg->peer_rate_caps |= WMI_RC_UAPSD_FLAG;
}
break;
case WMI_VDEV_TYPE_STA:
if (vif->bss_conf.qos)
- arg->peer_flags |= WMI_PEER_QOS;
+ arg->peer_flags |= arvif->ar->wmi.peer_flags->qos;
break;
case WMI_VDEV_TYPE_IBSS:
if (sta->wme)
- arg->peer_flags |= WMI_PEER_QOS;
+ arg->peer_flags |= arvif->ar->wmi.peer_flags->qos;
break;
default:
break;
}
ath10k_dbg(ar, ATH10K_DBG_MAC, "mac peer %pM qos %d\n",
- sta->addr, !!(arg->peer_flags & WMI_PEER_QOS));
+ sta->addr, !!(arg->peer_flags &
+ arvif->ar->wmi.peer_flags->qos));
}
static bool ath10k_mac_sta_has_ofdm_only(struct ieee80211_sta *sta)
@@ -2479,7 +2490,7 @@ static int ath10k_peer_assoc_prepare(struct ath10k *ar,
memset(arg, 0, sizeof(*arg));
ath10k_peer_assoc_h_basic(ar, vif, sta, arg);
- ath10k_peer_assoc_h_crypto(ar, vif, arg);
+ ath10k_peer_assoc_h_crypto(ar, vif, sta, arg);
ath10k_peer_assoc_h_rates(ar, vif, sta, arg);
ath10k_peer_assoc_h_ht(ar, vif, sta, arg);
ath10k_peer_assoc_h_vht(ar, vif, sta, arg);
@@ -3112,35 +3123,11 @@ void ath10k_mac_handle_tx_pause_vdev(struct ath10k *ar, u32 vdev_id,
spin_unlock_bh(&ar->htt.tx_lock);
}
-static u8 ath10k_tx_h_get_tid(struct ieee80211_hdr *hdr)
-{
- if (ieee80211_is_mgmt(hdr->frame_control))
- return HTT_DATA_TX_EXT_TID_MGMT;
-
- if (!ieee80211_is_data_qos(hdr->frame_control))
- return HTT_DATA_TX_EXT_TID_NON_QOS_MCAST_BCAST;
-
- if (!is_unicast_ether_addr(ieee80211_get_DA(hdr)))
- return HTT_DATA_TX_EXT_TID_NON_QOS_MCAST_BCAST;
-
- return ieee80211_get_qos_ctl(hdr)[0] & IEEE80211_QOS_CTL_TID_MASK;
-}
-
-static u8 ath10k_tx_h_get_vdev_id(struct ath10k *ar, struct ieee80211_vif *vif)
-{
- if (vif)
- return ath10k_vif_to_arvif(vif)->vdev_id;
-
- if (ar->monitor_started)
- return ar->monitor_vdev_id;
-
- ath10k_warn(ar, "failed to resolve vdev id\n");
- return 0;
-}
-
static enum ath10k_hw_txrx_mode
-ath10k_tx_h_get_txmode(struct ath10k *ar, struct ieee80211_vif *vif,
- struct ieee80211_sta *sta, struct sk_buff *skb)
+ath10k_mac_tx_h_get_txmode(struct ath10k *ar,
+ struct ieee80211_vif *vif,
+ struct ieee80211_sta *sta,
+ struct sk_buff *skb)
{
const struct ieee80211_hdr *hdr = (void *)skb->data;
__le16 fc = hdr->frame_control;
@@ -3190,14 +3177,22 @@ ath10k_tx_h_get_txmode(struct ath10k *ar, struct ieee80211_vif *vif,
}
static bool ath10k_tx_h_use_hwcrypto(struct ieee80211_vif *vif,
- struct sk_buff *skb) {
- struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
+ struct sk_buff *skb)
+{
+ const struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
+ const struct ieee80211_hdr *hdr = (void *)skb->data;
const u32 mask = IEEE80211_TX_INTFL_DONT_ENCRYPT |
IEEE80211_TX_CTL_INJECTED;
+
+ if (!ieee80211_has_protected(hdr->frame_control))
+ return false;
+
if ((info->flags & mask) == mask)
return false;
+
if (vif)
return !ath10k_vif_to_arvif(vif)->nohwcrypt;
+
return true;
}
@@ -3224,7 +3219,7 @@ static void ath10k_tx_h_nwifi(struct ieee80211_hw *hw, struct sk_buff *skb)
*/
hdr = (void *)skb->data;
if (ieee80211_is_qos_nullfunc(hdr->frame_control))
- cb->htt.tid = HTT_DATA_TX_EXT_TID_NON_QOS_MCAST_BCAST;
+ cb->flags &= ~ATH10K_SKB_F_QOS;
hdr->frame_control &= ~__cpu_to_le16(IEEE80211_STYPE_QOS_DATA);
}
@@ -3280,7 +3275,7 @@ static void ath10k_tx_h_add_p2p_noa_ie(struct ath10k *ar,
}
}
-static bool ath10k_mac_need_offchan_tx_work(struct ath10k *ar)
+bool ath10k_mac_tx_frm_has_freq(struct ath10k *ar)
{
/* FIXME: Not really sure since when the behaviour changed. At some
* point new firmware stopped requiring creation of peer entries for
@@ -3288,8 +3283,9 @@ static bool ath10k_mac_need_offchan_tx_work(struct ath10k *ar)
* tx credit replenishment and reliability). Assuming it's at least 3.4
* because that's when the `freq` was introduced to TX_FRM HTT command.
*/
- return !(ar->htt.target_version_major >= 3 &&
- ar->htt.target_version_minor >= 4);
+ return (ar->htt.target_version_major >= 3 &&
+ ar->htt.target_version_minor >= 4 &&
+ ar->htt.op_version == ATH10K_FW_HTT_OP_VERSION_TLV);
}
static int ath10k_mac_tx_wmi_mgmt(struct ath10k *ar, struct sk_buff *skb)
@@ -3314,24 +3310,24 @@ unlock:
return ret;
}
-static void ath10k_mac_tx(struct ath10k *ar, struct sk_buff *skb)
+static void ath10k_mac_tx(struct ath10k *ar, enum ath10k_hw_txrx_mode txmode,
+ struct sk_buff *skb)
{
- struct ath10k_skb_cb *cb = ATH10K_SKB_CB(skb);
struct ath10k_htt *htt = &ar->htt;
int ret = 0;
- switch (cb->txmode) {
+ switch (txmode) {
case ATH10K_HW_TXRX_RAW:
case ATH10K_HW_TXRX_NATIVE_WIFI:
case ATH10K_HW_TXRX_ETHERNET:
- ret = ath10k_htt_tx(htt, skb);
+ ret = ath10k_htt_tx(htt, txmode, skb);
break;
case ATH10K_HW_TXRX_MGMT:
if (test_bit(ATH10K_FW_FEATURE_HAS_WMI_MGMT_TX,
ar->fw_features))
ret = ath10k_mac_tx_wmi_mgmt(ar, skb);
else if (ar->htt.target_version_major >= 3)
- ret = ath10k_htt_tx(htt, skb);
+ ret = ath10k_htt_tx(htt, txmode, skb);
else
ret = ath10k_htt_mgmt_tx(htt, skb);
break;
@@ -3361,9 +3357,13 @@ void ath10k_offchan_tx_work(struct work_struct *work)
{
struct ath10k *ar = container_of(work, struct ath10k, offchan_tx_work);
struct ath10k_peer *peer;
+ struct ath10k_vif *arvif;
struct ieee80211_hdr *hdr;
+ struct ieee80211_vif *vif;
+ struct ieee80211_sta *sta;
struct sk_buff *skb;
const u8 *peer_addr;
+ enum ath10k_hw_txrx_mode txmode;
int vdev_id;
int ret;
unsigned long time_left;
@@ -3388,9 +3388,9 @@ void ath10k_offchan_tx_work(struct work_struct *work)
hdr = (struct ieee80211_hdr *)skb->data;
peer_addr = ieee80211_get_DA(hdr);
- vdev_id = ATH10K_SKB_CB(skb)->vdev_id;
spin_lock_bh(&ar->data_lock);
+ vdev_id = ar->scan.vdev_id;
peer = ath10k_peer_find(ar, vdev_id, peer_addr);
spin_unlock_bh(&ar->data_lock);
@@ -3413,7 +3413,22 @@ void ath10k_offchan_tx_work(struct work_struct *work)
ar->offchan_tx_skb = skb;
spin_unlock_bh(&ar->data_lock);
- ath10k_mac_tx(ar, skb);
+ /* It's safe to access vif and sta - conf_mutex guarantees that
+ * sta_state() and remove_interface() are locked exclusively
+ * out wrt to this offchannel worker.
+ */
+ arvif = ath10k_get_arvif(ar, vdev_id);
+ if (arvif) {
+ vif = arvif->vif;
+ sta = ieee80211_find_sta(vif, peer_addr);
+ } else {
+ vif = NULL;
+ sta = NULL;
+ }
+
+ txmode = ath10k_mac_tx_h_get_txmode(ar, vif, sta, skb);
+
+ ath10k_mac_tx(ar, txmode, skb);
time_left =
wait_for_completion_timeout(&ar->offchan_tx_completed, 3 * HZ);
@@ -3488,6 +3503,7 @@ void __ath10k_scan_finish(struct ath10k *ar)
case ATH10K_SCAN_STARTING:
ar->scan.state = ATH10K_SCAN_IDLE;
ar->scan_channel = NULL;
+ ar->scan.roc_freq = 0;
ath10k_offchan_tx_purge(ar);
cancel_delayed_work(&ar->scan.timeout);
complete_all(&ar->scan.completed);
@@ -3631,25 +3647,32 @@ static void ath10k_tx(struct ieee80211_hw *hw,
struct sk_buff *skb)
{
struct ath10k *ar = hw->priv;
+ struct ath10k_skb_cb *skb_cb = ATH10K_SKB_CB(skb);
struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
struct ieee80211_vif *vif = info->control.vif;
struct ieee80211_sta *sta = control->sta;
struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data;
- __le16 fc = hdr->frame_control;
+ enum ath10k_hw_txrx_mode txmode;
/* We should disable CCK RATE due to P2P */
if (info->flags & IEEE80211_TX_CTL_NO_CCK_RATE)
ath10k_dbg(ar, ATH10K_DBG_MAC, "IEEE80211_TX_CTL_NO_CCK_RATE\n");
- ATH10K_SKB_CB(skb)->htt.is_offchan = false;
- ATH10K_SKB_CB(skb)->htt.freq = 0;
- ATH10K_SKB_CB(skb)->htt.tid = ath10k_tx_h_get_tid(hdr);
- ATH10K_SKB_CB(skb)->htt.nohwcrypt = !ath10k_tx_h_use_hwcrypto(vif, skb);
- ATH10K_SKB_CB(skb)->vdev_id = ath10k_tx_h_get_vdev_id(ar, vif);
- ATH10K_SKB_CB(skb)->txmode = ath10k_tx_h_get_txmode(ar, vif, sta, skb);
- ATH10K_SKB_CB(skb)->is_protected = ieee80211_has_protected(fc);
+ txmode = ath10k_mac_tx_h_get_txmode(ar, vif, sta, skb);
+
+ skb_cb->flags = 0;
+ if (!ath10k_tx_h_use_hwcrypto(vif, skb))
+ skb_cb->flags |= ATH10K_SKB_F_NO_HWCRYPT;
+
+ if (ieee80211_is_mgmt(hdr->frame_control))
+ skb_cb->flags |= ATH10K_SKB_F_MGMT;
- switch (ATH10K_SKB_CB(skb)->txmode) {
+ if (ieee80211_is_data_qos(hdr->frame_control))
+ skb_cb->flags |= ATH10K_SKB_F_QOS;
+
+ skb_cb->vif = vif;
+
+ switch (txmode) {
case ATH10K_HW_TXRX_MGMT:
case ATH10K_HW_TXRX_NATIVE_WIFI:
ath10k_tx_h_nwifi(hw, skb);
@@ -3668,15 +3691,7 @@ static void ath10k_tx(struct ieee80211_hw *hw,
}
if (info->flags & IEEE80211_TX_CTL_TX_OFFCHAN) {
- spin_lock_bh(&ar->data_lock);
- ATH10K_SKB_CB(skb)->htt.freq = ar->scan.roc_freq;
- ATH10K_SKB_CB(skb)->vdev_id = ar->scan.vdev_id;
- spin_unlock_bh(&ar->data_lock);
-
- if (ath10k_mac_need_offchan_tx_work(ar)) {
- ATH10K_SKB_CB(skb)->htt.freq = 0;
- ATH10K_SKB_CB(skb)->htt.is_offchan = true;
-
+ if (!ath10k_mac_tx_frm_has_freq(ar)) {
ath10k_dbg(ar, ATH10K_DBG_MAC, "queued offchannel skb %p\n",
skb);
@@ -3686,7 +3701,7 @@ static void ath10k_tx(struct ieee80211_hw *hw,
}
}
- ath10k_mac_tx(ar, skb);
+ ath10k_mac_tx(ar, txmode, skb);
}
/* Must not be called with conf_mutex held as workers can use that also. */
@@ -3845,7 +3860,8 @@ static struct ieee80211_sta_ht_cap ath10k_get_ht_cap(struct ath10k *ar)
ht_cap.ampdu_density = IEEE80211_HT_MPDU_DENSITY_8;
ht_cap.cap |= IEEE80211_HT_CAP_SUP_WIDTH_20_40;
ht_cap.cap |= IEEE80211_HT_CAP_DSSSCCK40;
- ht_cap.cap |= WLAN_HT_CAP_SM_PS_STATIC << IEEE80211_HT_CAP_SM_PS_SHIFT;
+ ht_cap.cap |=
+ WLAN_HT_CAP_SM_PS_DISABLED << IEEE80211_HT_CAP_SM_PS_SHIFT;
if (ar->ht_cap_info & WMI_HT_CAP_HT20_SGI)
ht_cap.cap |= IEEE80211_HT_CAP_SGI_20;
@@ -4350,7 +4366,9 @@ static int ath10k_add_interface(struct ieee80211_hw *hw,
arvif->vdev_type = WMI_VDEV_TYPE_IBSS;
break;
case NL80211_IFTYPE_MESH_POINT:
- if (!test_bit(ATH10K_FLAG_RAW_MODE, &ar->dev_flags)) {
+ if (test_bit(WMI_SERVICE_MESH, ar->wmi.svc_map)) {
+ arvif->vdev_subtype = WMI_VDEV_SUBTYPE_MESH;
+ } else if (!test_bit(ATH10K_FLAG_RAW_MODE, &ar->dev_flags)) {
ret = -EINVAL;
ath10k_warn(ar, "must load driver with rawmode=1 to add mesh interfaces\n");
goto err;
@@ -6907,35 +6925,39 @@ void ath10k_mac_destroy(struct ath10k *ar)
static const struct ieee80211_iface_limit ath10k_if_limits[] = {
{
- .max = 8,
- .types = BIT(NL80211_IFTYPE_STATION)
- | BIT(NL80211_IFTYPE_P2P_CLIENT)
+ .max = 8,
+ .types = BIT(NL80211_IFTYPE_STATION)
+ | BIT(NL80211_IFTYPE_P2P_CLIENT)
},
{
- .max = 3,
- .types = BIT(NL80211_IFTYPE_P2P_GO)
+ .max = 3,
+ .types = BIT(NL80211_IFTYPE_P2P_GO)
},
{
- .max = 1,
- .types = BIT(NL80211_IFTYPE_P2P_DEVICE)
+ .max = 1,
+ .types = BIT(NL80211_IFTYPE_P2P_DEVICE)
},
{
- .max = 7,
- .types = BIT(NL80211_IFTYPE_AP)
+ .max = 7,
+ .types = BIT(NL80211_IFTYPE_AP)
#ifdef CONFIG_MAC80211_MESH
- | BIT(NL80211_IFTYPE_MESH_POINT)
+ | BIT(NL80211_IFTYPE_MESH_POINT)
#endif
},
};
static const struct ieee80211_iface_limit ath10k_10x_if_limits[] = {
{
- .max = 8,
- .types = BIT(NL80211_IFTYPE_AP)
+ .max = 8,
+ .types = BIT(NL80211_IFTYPE_AP)
#ifdef CONFIG_MAC80211_MESH
- | BIT(NL80211_IFTYPE_MESH_POINT)
+ | BIT(NL80211_IFTYPE_MESH_POINT)
#endif
},
+ {
+ .max = 1,
+ .types = BIT(NL80211_IFTYPE_STATION)
+ },
};
static const struct ieee80211_iface_combination ath10k_if_comb[] = {
diff --git a/drivers/net/wireless/ath/ath10k/mac.h b/drivers/net/wireless/ath/ath10k/mac.h
index e3cefe4c7cfd..53091588090d 100644
--- a/drivers/net/wireless/ath/ath10k/mac.h
+++ b/drivers/net/wireless/ath/ath10k/mac.h
@@ -66,7 +66,7 @@ void ath10k_mac_handle_tx_pause_vdev(struct ath10k *ar, u32 vdev_id,
enum wmi_tlv_tx_pause_action action);
u8 ath10k_mac_hw_rate_to_idx(const struct ieee80211_supported_band *sband,
- u8 hw_rate);
+ u8 hw_rate, bool cck);
u8 ath10k_mac_bitrate_to_idx(const struct ieee80211_supported_band *sband,
u32 bitrate);
@@ -74,6 +74,7 @@ void ath10k_mac_tx_lock(struct ath10k *ar, int reason);
void ath10k_mac_tx_unlock(struct ath10k *ar, int reason);
void ath10k_mac_vif_tx_lock(struct ath10k_vif *arvif, int reason);
void ath10k_mac_vif_tx_unlock(struct ath10k_vif *arvif, int reason);
+bool ath10k_mac_tx_frm_has_freq(struct ath10k *ar);
static inline struct ath10k_vif *ath10k_vif_to_arvif(struct ieee80211_vif *vif)
{
diff --git a/drivers/net/wireless/ath/ath10k/pci.c b/drivers/net/wireless/ath/ath10k/pci.c
index 930785a724e1..ee925c618535 100644
--- a/drivers/net/wireless/ath/ath10k/pci.c
+++ b/drivers/net/wireless/ath/ath10k/pci.c
@@ -108,6 +108,7 @@ static void ath10k_pci_htc_rx_cb(struct ath10k_ce_pipe *ce_state);
static void ath10k_pci_htt_tx_cb(struct ath10k_ce_pipe *ce_state);
static void ath10k_pci_htt_rx_cb(struct ath10k_ce_pipe *ce_state);
static void ath10k_pci_htt_htc_rx_cb(struct ath10k_ce_pipe *ce_state);
+static void ath10k_pci_pktlog_rx_cb(struct ath10k_ce_pipe *ce_state);
static struct ce_attr host_ce_config_wlan[] = {
/* CE0: host->target HTC control and raw streams */
@@ -186,6 +187,7 @@ static struct ce_attr host_ce_config_wlan[] = {
.src_nentries = 0,
.src_sz_max = 2048,
.dest_nentries = 128,
+ .recv_cb = ath10k_pci_pktlog_rx_cb,
},
/* CE9 target autonomous qcache memcpy */
@@ -485,6 +487,9 @@ static int ath10k_pci_force_wake(struct ath10k *ar)
unsigned long flags;
int ret = 0;
+ if (ar_pci->pci_ps)
+ return ret;
+
spin_lock_irqsave(&ar_pci->ps_lock, flags);
if (!ar_pci->ps_awake) {
@@ -1215,6 +1220,15 @@ static void ath10k_pci_htt_htc_rx_cb(struct ath10k_ce_pipe *ce_state)
ath10k_pci_process_rx_cb(ce_state, ath10k_htc_rx_completion_handler);
}
+/* Called by lower (CE) layer when data is received from the Target.
+ * Only 10.4 firmware uses separate CE to transfer pktlog data.
+ */
+static void ath10k_pci_pktlog_rx_cb(struct ath10k_ce_pipe *ce_state)
+{
+ ath10k_pci_process_rx_cb(ce_state,
+ ath10k_htt_rx_pktlog_completion_handler);
+}
+
/* Called by lower (CE) layer when a send to HTT Target completes. */
static void ath10k_pci_htt_tx_cb(struct ath10k_ce_pipe *ce_state)
{
@@ -2469,12 +2483,10 @@ static int ath10k_pci_hif_resume(struct ath10k *ar)
u32 val;
int ret = 0;
- if (ar_pci->pci_ps == 0) {
- ret = ath10k_pci_force_wake(ar);
- if (ret) {
- ath10k_err(ar, "failed to wake up target: %d\n", ret);
- return ret;
- }
+ ret = ath10k_pci_force_wake(ar);
+ if (ret) {
+ ath10k_err(ar, "failed to wake up target: %d\n", ret);
+ return ret;
}
/* Suspend/Resume resets the PCI configuration space, so we have to
@@ -2581,13 +2593,10 @@ static irqreturn_t ath10k_pci_interrupt_handler(int irq, void *arg)
struct ath10k_pci *ar_pci = ath10k_pci_priv(ar);
int ret;
- if (ar_pci->pci_ps == 0) {
- ret = ath10k_pci_force_wake(ar);
- if (ret) {
- ath10k_warn(ar, "failed to wake device up on irq: %d\n",
- ret);
- return IRQ_NONE;
- }
+ ret = ath10k_pci_force_wake(ar);
+ if (ret) {
+ ath10k_warn(ar, "failed to wake device up on irq: %d\n", ret);
+ return IRQ_NONE;
}
if (ar_pci->num_msi_intrs == 0) {
@@ -3060,17 +3069,15 @@ static int ath10k_pci_probe(struct pci_dev *pdev,
goto err_sleep;
}
+ ret = ath10k_pci_force_wake(ar);
+ if (ret) {
+ ath10k_warn(ar, "failed to wake up device : %d\n", ret);
+ goto err_free_pipes;
+ }
+
ath10k_pci_ce_deinit(ar);
ath10k_pci_irq_disable(ar);
- if (ar_pci->pci_ps == 0) {
- ret = ath10k_pci_force_wake(ar);
- if (ret) {
- ath10k_warn(ar, "failed to wake up device : %d\n", ret);
- goto err_free_pipes;
- }
- }
-
ret = ath10k_pci_init_irq(ar);
if (ret) {
ath10k_err(ar, "failed to init irqs: %d\n", ret);
diff --git a/drivers/net/wireless/ath/ath10k/thermal.c b/drivers/net/wireless/ath/ath10k/thermal.c
index 60fe562e3041..444b52c7e4f3 100644
--- a/drivers/net/wireless/ath/ath10k/thermal.c
+++ b/drivers/net/wireless/ath/ath10k/thermal.c
@@ -187,7 +187,7 @@ int ath10k_thermal_register(struct ath10k *ar)
/* Do not register hwmon device when temperature reading is not
* supported by firmware
*/
- if (ar->wmi.op_version != ATH10K_FW_WMI_OP_VERSION_10_2_4)
+ if (!(ar->wmi.ops->gen_pdev_get_temperature))
return 0;
/* Avoid linking error on devm_hwmon_device_register_with_groups, I
diff --git a/drivers/net/wireless/ath/ath10k/txrx.c b/drivers/net/wireless/ath/ath10k/txrx.c
index 6d1105ab4592..fbfb608e48ab 100644
--- a/drivers/net/wireless/ath/ath10k/txrx.c
+++ b/drivers/net/wireless/ath/ath10k/txrx.c
@@ -23,7 +23,12 @@
static void ath10k_report_offchan_tx(struct ath10k *ar, struct sk_buff *skb)
{
- if (!ATH10K_SKB_CB(skb)->htt.is_offchan)
+ struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
+
+ if (likely(!(info->flags & IEEE80211_TX_CTL_TX_OFFCHAN)))
+ return;
+
+ if (ath10k_mac_tx_frm_has_freq(ar))
return;
/* If the original wait_for_completion() timed out before
@@ -52,8 +57,6 @@ void ath10k_txrx_tx_unref(struct ath10k_htt *htt,
struct ieee80211_tx_info *info;
struct ath10k_skb_cb *skb_cb;
struct sk_buff *msdu;
- struct ieee80211_hdr *hdr;
- __le16 fc;
bool limit_mgmt_desc = false;
ath10k_dbg(ar, ATH10K_DBG_HTT,
@@ -76,10 +79,9 @@ void ath10k_txrx_tx_unref(struct ath10k_htt *htt,
return;
}
- hdr = (struct ieee80211_hdr *)msdu->data;
- fc = hdr->frame_control;
+ skb_cb = ATH10K_SKB_CB(msdu);
- if (unlikely(ieee80211_is_mgmt(fc)) &&
+ if (unlikely(skb_cb->flags & ATH10K_SKB_F_MGMT) &&
ar->hw_params.max_probe_resp_desc_thres)
limit_mgmt_desc = true;
@@ -89,7 +91,6 @@ void ath10k_txrx_tx_unref(struct ath10k_htt *htt,
wake_up(&htt->empty_tx_wq);
spin_unlock_bh(&htt->tx_lock);
- skb_cb = ATH10K_SKB_CB(msdu);
dma_unmap_single(dev, skb_cb->paddr, msdu->len, DMA_TO_DEVICE);
ath10k_report_offchan_tx(htt->ar, msdu);
diff --git a/drivers/net/wireless/ath/ath10k/wmi-tlv.c b/drivers/net/wireless/ath/ath10k/wmi-tlv.c
index 6fbd17b69469..3b3a27b859f3 100644
--- a/drivers/net/wireless/ath/ath10k/wmi-tlv.c
+++ b/drivers/net/wireless/ath/ath10k/wmi-tlv.c
@@ -3485,6 +3485,24 @@ static const struct wmi_ops wmi_tlv_ops = {
.fw_stats_fill = ath10k_wmi_main_op_fw_stats_fill,
};
+static const struct wmi_peer_flags_map wmi_tlv_peer_flags_map = {
+ .auth = WMI_TLV_PEER_AUTH,
+ .qos = WMI_TLV_PEER_QOS,
+ .need_ptk_4_way = WMI_TLV_PEER_NEED_PTK_4_WAY,
+ .need_gtk_2_way = WMI_TLV_PEER_NEED_GTK_2_WAY,
+ .apsd = WMI_TLV_PEER_APSD,
+ .ht = WMI_TLV_PEER_HT,
+ .bw40 = WMI_TLV_PEER_40MHZ,
+ .stbc = WMI_TLV_PEER_STBC,
+ .ldbc = WMI_TLV_PEER_LDPC,
+ .dyn_mimops = WMI_TLV_PEER_DYN_MIMOPS,
+ .static_mimops = WMI_TLV_PEER_STATIC_MIMOPS,
+ .spatial_mux = WMI_TLV_PEER_SPATIAL_MUX,
+ .vht = WMI_TLV_PEER_VHT,
+ .bw80 = WMI_TLV_PEER_80MHZ,
+ .pmf = WMI_TLV_PEER_PMF,
+};
+
/************/
/* TLV init */
/************/
@@ -3495,4 +3513,5 @@ void ath10k_wmi_tlv_attach(struct ath10k *ar)
ar->wmi.vdev_param = &wmi_tlv_vdev_param_map;
ar->wmi.pdev_param = &wmi_tlv_pdev_param_map;
ar->wmi.ops = &wmi_tlv_ops;
+ ar->wmi.peer_flags = &wmi_tlv_peer_flags_map;
}
diff --git a/drivers/net/wireless/ath/ath10k/wmi-tlv.h b/drivers/net/wireless/ath/ath10k/wmi-tlv.h
index ad655c44afdb..dd678590531a 100644
--- a/drivers/net/wireless/ath/ath10k/wmi-tlv.h
+++ b/drivers/net/wireless/ath/ath10k/wmi-tlv.h
@@ -527,6 +527,24 @@ enum wmi_tlv_vdev_param {
WMI_TLV_VDEV_PARAM_IBSS_PS_1RX_CHAIN_IN_ATIM_WINDOW_ENABLE,
};
+enum wmi_tlv_peer_flags {
+ WMI_TLV_PEER_AUTH = 0x00000001,
+ WMI_TLV_PEER_QOS = 0x00000002,
+ WMI_TLV_PEER_NEED_PTK_4_WAY = 0x00000004,
+ WMI_TLV_PEER_NEED_GTK_2_WAY = 0x00000010,
+ WMI_TLV_PEER_APSD = 0x00000800,
+ WMI_TLV_PEER_HT = 0x00001000,
+ WMI_TLV_PEER_40MHZ = 0x00002000,
+ WMI_TLV_PEER_STBC = 0x00008000,
+ WMI_TLV_PEER_LDPC = 0x00010000,
+ WMI_TLV_PEER_DYN_MIMOPS = 0x00020000,
+ WMI_TLV_PEER_STATIC_MIMOPS = 0x00040000,
+ WMI_TLV_PEER_SPATIAL_MUX = 0x00200000,
+ WMI_TLV_PEER_VHT = 0x02000000,
+ WMI_TLV_PEER_80MHZ = 0x04000000,
+ WMI_TLV_PEER_PMF = 0x08000000,
+};
+
enum wmi_tlv_tag {
WMI_TLV_TAG_LAST_RESERVED = 15,
diff --git a/drivers/net/wireless/ath/ath10k/wmi.c b/drivers/net/wireless/ath/ath10k/wmi.c
index 7569db0f69b5..a7c3d299639b 100644
--- a/drivers/net/wireless/ath/ath10k/wmi.c
+++ b/drivers/net/wireless/ath/ath10k/wmi.c
@@ -1546,6 +1546,61 @@ static struct wmi_pdev_param_map wmi_10_4_pdev_param_map = {
.arp_dstaddr = WMI_10_4_PDEV_PARAM_ARP_DSTADDR,
};
+static const struct wmi_peer_flags_map wmi_peer_flags_map = {
+ .auth = WMI_PEER_AUTH,
+ .qos = WMI_PEER_QOS,
+ .need_ptk_4_way = WMI_PEER_NEED_PTK_4_WAY,
+ .need_gtk_2_way = WMI_PEER_NEED_GTK_2_WAY,
+ .apsd = WMI_PEER_APSD,
+ .ht = WMI_PEER_HT,
+ .bw40 = WMI_PEER_40MHZ,
+ .stbc = WMI_PEER_STBC,
+ .ldbc = WMI_PEER_LDPC,
+ .dyn_mimops = WMI_PEER_DYN_MIMOPS,
+ .static_mimops = WMI_PEER_STATIC_MIMOPS,
+ .spatial_mux = WMI_PEER_SPATIAL_MUX,
+ .vht = WMI_PEER_VHT,
+ .bw80 = WMI_PEER_80MHZ,
+ .vht_2g = WMI_PEER_VHT_2G,
+ .pmf = WMI_PEER_PMF,
+};
+
+static const struct wmi_peer_flags_map wmi_10x_peer_flags_map = {
+ .auth = WMI_10X_PEER_AUTH,
+ .qos = WMI_10X_PEER_QOS,
+ .need_ptk_4_way = WMI_10X_PEER_NEED_PTK_4_WAY,
+ .need_gtk_2_way = WMI_10X_PEER_NEED_GTK_2_WAY,
+ .apsd = WMI_10X_PEER_APSD,
+ .ht = WMI_10X_PEER_HT,
+ .bw40 = WMI_10X_PEER_40MHZ,
+ .stbc = WMI_10X_PEER_STBC,
+ .ldbc = WMI_10X_PEER_LDPC,
+ .dyn_mimops = WMI_10X_PEER_DYN_MIMOPS,
+ .static_mimops = WMI_10X_PEER_STATIC_MIMOPS,
+ .spatial_mux = WMI_10X_PEER_SPATIAL_MUX,
+ .vht = WMI_10X_PEER_VHT,
+ .bw80 = WMI_10X_PEER_80MHZ,
+};
+
+static const struct wmi_peer_flags_map wmi_10_2_peer_flags_map = {
+ .auth = WMI_10_2_PEER_AUTH,
+ .qos = WMI_10_2_PEER_QOS,
+ .need_ptk_4_way = WMI_10_2_PEER_NEED_PTK_4_WAY,
+ .need_gtk_2_way = WMI_10_2_PEER_NEED_GTK_2_WAY,
+ .apsd = WMI_10_2_PEER_APSD,
+ .ht = WMI_10_2_PEER_HT,
+ .bw40 = WMI_10_2_PEER_40MHZ,
+ .stbc = WMI_10_2_PEER_STBC,
+ .ldbc = WMI_10_2_PEER_LDPC,
+ .dyn_mimops = WMI_10_2_PEER_DYN_MIMOPS,
+ .static_mimops = WMI_10_2_PEER_STATIC_MIMOPS,
+ .spatial_mux = WMI_10_2_PEER_SPATIAL_MUX,
+ .vht = WMI_10_2_PEER_VHT,
+ .bw80 = WMI_10_2_PEER_80MHZ,
+ .vht_2g = WMI_10_2_PEER_VHT_2G,
+ .pmf = WMI_10_2_PEER_PMF,
+};
+
void ath10k_wmi_put_wmi_channel(struct wmi_channel *ch,
const struct wmi_channel_arg *arg)
{
@@ -1660,6 +1715,8 @@ static void ath10k_wmi_tx_beacon_nowait(struct ath10k_vif *arvif)
struct ath10k *ar = arvif->ar;
struct ath10k_skb_cb *cb;
struct sk_buff *bcn;
+ bool dtim_zero;
+ bool deliver_cab;
int ret;
spin_lock_bh(&ar->data_lock);
@@ -1679,12 +1736,14 @@ static void ath10k_wmi_tx_beacon_nowait(struct ath10k_vif *arvif)
arvif->beacon_state = ATH10K_BEACON_SENDING;
spin_unlock_bh(&ar->data_lock);
+ dtim_zero = !!(cb->flags & ATH10K_SKB_F_DTIM_ZERO);
+ deliver_cab = !!(cb->flags & ATH10K_SKB_F_DELIVER_CAB);
ret = ath10k_wmi_beacon_send_ref_nowait(arvif->ar,
arvif->vdev_id,
bcn->data, bcn->len,
cb->paddr,
- cb->bcn.dtim_zero,
- cb->bcn.deliver_cab);
+ dtim_zero,
+ deliver_cab);
spin_lock_bh(&ar->data_lock);
@@ -1755,16 +1814,24 @@ int ath10k_wmi_cmd_send(struct ath10k *ar, struct sk_buff *skb, u32 cmd_id)
static struct sk_buff *
ath10k_wmi_op_gen_mgmt_tx(struct ath10k *ar, struct sk_buff *msdu)
{
+ struct ath10k_skb_cb *cb = ATH10K_SKB_CB(msdu);
+ struct ath10k_vif *arvif = (void *)cb->vif->drv_priv;
struct wmi_mgmt_tx_cmd *cmd;
struct ieee80211_hdr *hdr;
struct sk_buff *skb;
int len;
+ u32 vdev_id;
u32 buf_len = msdu->len;
u16 fc;
hdr = (struct ieee80211_hdr *)msdu->data;
fc = le16_to_cpu(hdr->frame_control);
+ if (cb->vif)
+ vdev_id = arvif->vdev_id;
+ else
+ vdev_id = 0;
+
if (WARN_ON_ONCE(!ieee80211_is_mgmt(hdr->frame_control)))
return ERR_PTR(-EINVAL);
@@ -1786,7 +1853,7 @@ ath10k_wmi_op_gen_mgmt_tx(struct ath10k *ar, struct sk_buff *msdu)
cmd = (struct wmi_mgmt_tx_cmd *)skb->data;
- cmd->hdr.vdev_id = __cpu_to_le32(ATH10K_SKB_CB(msdu)->vdev_id);
+ cmd->hdr.vdev_id = __cpu_to_le32(vdev_id);
cmd->hdr.tx_rate = 0;
cmd->hdr.tx_power = 0;
cmd->hdr.buf_len = __cpu_to_le32(buf_len);
@@ -2204,22 +2271,9 @@ int ath10k_wmi_event_mgmt_rx(struct ath10k *ar, struct sk_buff *skb)
ath10k_dbg(ar, ATH10K_DBG_MGMT,
"event mgmt rx status %08x\n", rx_status);
- if (test_bit(ATH10K_CAC_RUNNING, &ar->dev_flags)) {
- dev_kfree_skb(skb);
- return 0;
- }
-
- if (rx_status & WMI_RX_STATUS_ERR_DECRYPT) {
- dev_kfree_skb(skb);
- return 0;
- }
-
- if (rx_status & WMI_RX_STATUS_ERR_KEY_CACHE_MISS) {
- dev_kfree_skb(skb);
- return 0;
- }
-
- if (rx_status & WMI_RX_STATUS_ERR_CRC) {
+ if ((test_bit(ATH10K_CAC_RUNNING, &ar->dev_flags)) ||
+ (rx_status & (WMI_RX_STATUS_ERR_DECRYPT |
+ WMI_RX_STATUS_ERR_KEY_CACHE_MISS | WMI_RX_STATUS_ERR_CRC))) {
dev_kfree_skb(skb);
return 0;
}
@@ -3115,10 +3169,10 @@ static void ath10k_wmi_update_tim(struct ath10k *ar,
memcpy(tim->virtual_map, arvif->u.ap.tim_bitmap, pvm_len);
if (tim->dtim_count == 0) {
- ATH10K_SKB_CB(bcn)->bcn.dtim_zero = true;
+ ATH10K_SKB_CB(bcn)->flags |= ATH10K_SKB_F_DTIM_ZERO;
if (__le32_to_cpu(tim_info->tim_mcast) == 1)
- ATH10K_SKB_CB(bcn)->bcn.deliver_cab = true;
+ ATH10K_SKB_CB(bcn)->flags |= ATH10K_SKB_F_DELIVER_CAB;
}
ath10k_dbg(ar, ATH10K_DBG_MGMT, "dtim %d/%d mcast %d pvmlen %d\n",
@@ -4258,34 +4312,58 @@ void ath10k_wmi_event_vdev_resume_req(struct ath10k *ar, struct sk_buff *skb)
ath10k_dbg(ar, ATH10K_DBG_WMI, "WMI_VDEV_RESUME_REQ_EVENTID\n");
}
-static int ath10k_wmi_alloc_host_mem(struct ath10k *ar, u32 req_id,
- u32 num_units, u32 unit_len)
+static int ath10k_wmi_alloc_chunk(struct ath10k *ar, u32 req_id,
+ u32 num_units, u32 unit_len)
{
dma_addr_t paddr;
- u32 pool_size;
+ u32 pool_size = 0;
int idx = ar->wmi.num_mem_chunks;
+ void *vaddr = NULL;
- pool_size = num_units * round_up(unit_len, 4);
+ if (ar->wmi.num_mem_chunks == ARRAY_SIZE(ar->wmi.mem_chunks))
+ return -ENOMEM;
- if (!pool_size)
- return -EINVAL;
+ while (!vaddr && num_units) {
+ pool_size = num_units * round_up(unit_len, 4);
+ if (!pool_size)
+ return -EINVAL;
- ar->wmi.mem_chunks[idx].vaddr = dma_alloc_coherent(ar->dev,
- pool_size,
- &paddr,
- GFP_KERNEL);
- if (!ar->wmi.mem_chunks[idx].vaddr) {
- ath10k_warn(ar, "failed to allocate memory chunk\n");
- return -ENOMEM;
+ vaddr = kzalloc(pool_size, GFP_KERNEL | __GFP_NOWARN);
+ if (!vaddr)
+ num_units /= 2;
}
- memset(ar->wmi.mem_chunks[idx].vaddr, 0, pool_size);
+ if (!num_units)
+ return -ENOMEM;
+ paddr = dma_map_single(ar->dev, vaddr, pool_size, DMA_TO_DEVICE);
+ if (dma_mapping_error(ar->dev, paddr)) {
+ kfree(vaddr);
+ return -ENOMEM;
+ }
+
+ ar->wmi.mem_chunks[idx].vaddr = vaddr;
ar->wmi.mem_chunks[idx].paddr = paddr;
ar->wmi.mem_chunks[idx].len = pool_size;
ar->wmi.mem_chunks[idx].req_id = req_id;
ar->wmi.num_mem_chunks++;
+ return num_units;
+}
+
+static int ath10k_wmi_alloc_host_mem(struct ath10k *ar, u32 req_id,
+ u32 num_units, u32 unit_len)
+{
+ int ret;
+
+ while (num_units) {
+ ret = ath10k_wmi_alloc_chunk(ar, req_id, num_units, unit_len);
+ if (ret < 0)
+ return ret;
+
+ num_units -= ret;
+ }
+
return 0;
}
@@ -5061,6 +5139,9 @@ static void ath10k_wmi_10_4_op_rx(struct ath10k *ar, struct sk_buff *skb)
case WMI_10_4_UPDATE_STATS_EVENTID:
ath10k_wmi_event_update_stats(ar, skb);
break;
+ case WMI_10_4_PDEV_TEMPERATURE_EVENTID:
+ ath10k_wmi_event_temperature(ar, skb);
+ break;
default:
ath10k_warn(ar, "Unknown eventid: %d\n", id);
break;
@@ -5431,8 +5512,11 @@ static struct sk_buff *ath10k_wmi_10_2_op_gen_init(struct ath10k *ar)
cmd = (struct wmi_init_cmd_10_2 *)buf->data;
features = WMI_10_2_RX_BATCH_MODE;
- if (test_bit(WMI_SERVICE_COEX_GPIO, ar->wmi.svc_map))
+
+ if (test_bit(ATH10K_FLAG_BTCOEX, &ar->dev_flags) &&
+ test_bit(WMI_SERVICE_COEX_GPIO, ar->wmi.svc_map))
features |= WMI_10_2_COEX_GPIO;
+
cmd->resource_config.feature_mask = __cpu_to_le32(features);
memcpy(&cmd->resource_config.common, &config, sizeof(config));
@@ -6328,6 +6412,16 @@ ath10k_wmi_peer_assoc_fill_10_2(struct ath10k *ar, void *buf,
cmd->info0 = __cpu_to_le32(info0);
}
+static void
+ath10k_wmi_peer_assoc_fill_10_4(struct ath10k *ar, void *buf,
+ const struct wmi_peer_assoc_complete_arg *arg)
+{
+ struct wmi_10_4_peer_assoc_complete_cmd *cmd = buf;
+
+ ath10k_wmi_peer_assoc_fill_10_2(ar, buf, arg);
+ cmd->peer_bw_rxnss_override = 0;
+}
+
static int
ath10k_wmi_peer_assoc_check_arg(const struct wmi_peer_assoc_complete_arg *arg)
{
@@ -6417,6 +6511,31 @@ ath10k_wmi_10_2_op_gen_peer_assoc(struct ath10k *ar,
}
static struct sk_buff *
+ath10k_wmi_10_4_op_gen_peer_assoc(struct ath10k *ar,
+ const struct wmi_peer_assoc_complete_arg *arg)
+{
+ size_t len = sizeof(struct wmi_10_4_peer_assoc_complete_cmd);
+ struct sk_buff *skb;
+ int ret;
+
+ ret = ath10k_wmi_peer_assoc_check_arg(arg);
+ if (ret)
+ return ERR_PTR(ret);
+
+ skb = ath10k_wmi_alloc_skb(ar, len);
+ if (!skb)
+ return ERR_PTR(-ENOMEM);
+
+ ath10k_wmi_peer_assoc_fill_10_4(ar, skb->data, arg);
+
+ ath10k_dbg(ar, ATH10K_DBG_WMI,
+ "wmi peer assoc vdev %d addr %pM (%s)\n",
+ arg->vdev_id, arg->addr,
+ arg->peer_reassoc ? "reassociate" : "new");
+ return skb;
+}
+
+static struct sk_buff *
ath10k_wmi_10_2_op_gen_pdev_get_temperature(struct ath10k *ar)
{
struct sk_buff *skb;
@@ -7536,6 +7655,7 @@ static const struct wmi_ops wmi_10_4_ops = {
.gen_peer_delete = ath10k_wmi_op_gen_peer_delete,
.gen_peer_flush = ath10k_wmi_op_gen_peer_flush,
.gen_peer_set_param = ath10k_wmi_op_gen_peer_set_param,
+ .gen_peer_assoc = ath10k_wmi_10_4_op_gen_peer_assoc,
.gen_set_psmode = ath10k_wmi_op_gen_set_psmode,
.gen_set_sta_ps = ath10k_wmi_op_gen_set_sta_ps,
.gen_set_ap_ps = ath10k_wmi_op_gen_set_ap_ps,
@@ -7555,8 +7675,8 @@ static const struct wmi_ops wmi_10_4_ops = {
.fw_stats_fill = ath10k_wmi_10_4_op_fw_stats_fill,
/* shared with 10.2 */
- .gen_peer_assoc = ath10k_wmi_10_2_op_gen_peer_assoc,
.gen_request_stats = ath10k_wmi_op_gen_request_stats,
+ .gen_pdev_get_temperature = ath10k_wmi_10_2_op_gen_pdev_get_temperature,
};
int ath10k_wmi_attach(struct ath10k *ar)
@@ -7567,30 +7687,35 @@ int ath10k_wmi_attach(struct ath10k *ar)
ar->wmi.cmd = &wmi_10_4_cmd_map;
ar->wmi.vdev_param = &wmi_10_4_vdev_param_map;
ar->wmi.pdev_param = &wmi_10_4_pdev_param_map;
+ ar->wmi.peer_flags = &wmi_10_2_peer_flags_map;
break;
case ATH10K_FW_WMI_OP_VERSION_10_2_4:
ar->wmi.cmd = &wmi_10_2_4_cmd_map;
ar->wmi.ops = &wmi_10_2_4_ops;
ar->wmi.vdev_param = &wmi_10_2_4_vdev_param_map;
ar->wmi.pdev_param = &wmi_10_2_4_pdev_param_map;
+ ar->wmi.peer_flags = &wmi_10_2_peer_flags_map;
break;
case ATH10K_FW_WMI_OP_VERSION_10_2:
ar->wmi.cmd = &wmi_10_2_cmd_map;
ar->wmi.ops = &wmi_10_2_ops;
ar->wmi.vdev_param = &wmi_10x_vdev_param_map;
ar->wmi.pdev_param = &wmi_10x_pdev_param_map;
+ ar->wmi.peer_flags = &wmi_10_2_peer_flags_map;
break;
case ATH10K_FW_WMI_OP_VERSION_10_1:
ar->wmi.cmd = &wmi_10x_cmd_map;
ar->wmi.ops = &wmi_10_1_ops;
ar->wmi.vdev_param = &wmi_10x_vdev_param_map;
ar->wmi.pdev_param = &wmi_10x_pdev_param_map;
+ ar->wmi.peer_flags = &wmi_10x_peer_flags_map;
break;
case ATH10K_FW_WMI_OP_VERSION_MAIN:
ar->wmi.cmd = &wmi_cmd_map;
ar->wmi.ops = &wmi_ops;
ar->wmi.vdev_param = &wmi_vdev_param_map;
ar->wmi.pdev_param = &wmi_pdev_param_map;
+ ar->wmi.peer_flags = &wmi_peer_flags_map;
break;
case ATH10K_FW_WMI_OP_VERSION_TLV:
ath10k_wmi_tlv_attach(ar);
@@ -7616,10 +7741,11 @@ void ath10k_wmi_free_host_mem(struct ath10k *ar)
/* free the host memory chunks requested by firmware */
for (i = 0; i < ar->wmi.num_mem_chunks; i++) {
- dma_free_coherent(ar->dev,
- ar->wmi.mem_chunks[i].len,
- ar->wmi.mem_chunks[i].vaddr,
- ar->wmi.mem_chunks[i].paddr);
+ dma_unmap_single(ar->dev,
+ ar->wmi.mem_chunks[i].paddr,
+ ar->wmi.mem_chunks[i].len,
+ DMA_TO_DEVICE);
+ kfree(ar->wmi.mem_chunks[i].vaddr);
}
ar->wmi.num_mem_chunks = 0;
diff --git a/drivers/net/wireless/ath/ath10k/wmi.h b/drivers/net/wireless/ath/ath10k/wmi.h
index 72a4ef709577..d85ad7855d20 100644
--- a/drivers/net/wireless/ath/ath10k/wmi.h
+++ b/drivers/net/wireless/ath/ath10k/wmi.h
@@ -175,6 +175,8 @@ enum wmi_service {
WMI_SERVICE_AUX_SPECTRAL_INTF,
WMI_SERVICE_AUX_CHAN_LOAD_INTF,
WMI_SERVICE_BSS_CHANNEL_INFO_64,
+ WMI_SERVICE_EXT_RES_CFG_SUPPORT,
+ WMI_SERVICE_MESH,
/* keep last */
WMI_SERVICE_MAX,
@@ -206,6 +208,11 @@ enum wmi_10x_service {
WMI_10X_SERVICE_SMART_ANTENNA_HW_SUPPORT,
WMI_10X_SERVICE_ATF,
WMI_10X_SERVICE_COEX_GPIO,
+ WMI_10X_SERVICE_AUX_SPECTRAL_INTF,
+ WMI_10X_SERVICE_AUX_CHAN_LOAD_INTF,
+ WMI_10X_SERVICE_BSS_CHANNEL_INFO_64,
+ WMI_10X_SERVICE_MESH,
+ WMI_10X_SERVICE_EXT_RES_CFG_SUPPORT,
};
enum wmi_main_service {
@@ -286,6 +293,8 @@ enum wmi_10_4_service {
WMI_10_4_SERVICE_AUX_SPECTRAL_INTF,
WMI_10_4_SERVICE_AUX_CHAN_LOAD_INTF,
WMI_10_4_SERVICE_BSS_CHANNEL_INFO_64,
+ WMI_10_4_SERVICE_EXT_RES_CFG_SUPPORT,
+ WMI_10_4_SERVICE_MESH,
};
static inline char *wmi_service_name(int service_id)
@@ -375,6 +384,8 @@ static inline char *wmi_service_name(int service_id)
SVCSTR(WMI_SERVICE_AUX_SPECTRAL_INTF);
SVCSTR(WMI_SERVICE_AUX_CHAN_LOAD_INTF);
SVCSTR(WMI_SERVICE_BSS_CHANNEL_INFO_64);
+ SVCSTR(WMI_SERVICE_EXT_RES_CFG_SUPPORT);
+ SVCSTR(WMI_SERVICE_MESH);
default:
return NULL;
}
@@ -442,6 +453,16 @@ static inline void wmi_10x_svc_map(const __le32 *in, unsigned long *out,
WMI_SERVICE_ATF, len);
SVCMAP(WMI_10X_SERVICE_COEX_GPIO,
WMI_SERVICE_COEX_GPIO, len);
+ SVCMAP(WMI_10X_SERVICE_AUX_SPECTRAL_INTF,
+ WMI_SERVICE_AUX_SPECTRAL_INTF, len);
+ SVCMAP(WMI_10X_SERVICE_AUX_CHAN_LOAD_INTF,
+ WMI_SERVICE_AUX_CHAN_LOAD_INTF, len);
+ SVCMAP(WMI_10X_SERVICE_BSS_CHANNEL_INFO_64,
+ WMI_SERVICE_BSS_CHANNEL_INFO_64, len);
+ SVCMAP(WMI_10X_SERVICE_MESH,
+ WMI_SERVICE_MESH, len);
+ SVCMAP(WMI_10X_SERVICE_EXT_RES_CFG_SUPPORT,
+ WMI_SERVICE_EXT_RES_CFG_SUPPORT, len);
}
static inline void wmi_main_svc_map(const __le32 *in, unsigned long *out,
@@ -600,6 +621,10 @@ static inline void wmi_10_4_svc_map(const __le32 *in, unsigned long *out,
WMI_SERVICE_AUX_CHAN_LOAD_INTF, len);
SVCMAP(WMI_10_4_SERVICE_BSS_CHANNEL_INFO_64,
WMI_SERVICE_BSS_CHANNEL_INFO_64, len);
+ SVCMAP(WMI_10_4_SERVICE_EXT_RES_CFG_SUPPORT,
+ WMI_SERVICE_EXT_RES_CFG_SUPPORT, len);
+ SVCMAP(WMI_10_4_SERVICE_MESH,
+ WMI_SERVICE_MESH, len);
}
#undef SVCMAP
@@ -1576,6 +1601,9 @@ enum wmi_10_4_cmd_id {
WMI_10_4_MU_CAL_START_CMDID,
WMI_10_4_SET_CCA_PARAMS_CMDID,
WMI_10_4_PDEV_BSS_CHAN_INFO_REQUEST_CMDID,
+ WMI_10_4_EXT_RESOURCE_CFG_CMDID,
+ WMI_10_4_VDEV_SET_IE_CMDID,
+ WMI_10_4_SET_LTEU_CONFIG_CMDID,
WMI_10_4_PDEV_UTF_CMDID = WMI_10_4_END_CMDID - 1,
};
@@ -1638,6 +1666,7 @@ enum wmi_10_4_event_id {
WMI_10_4_PDEV_TEMPERATURE_EVENTID,
WMI_10_4_PDEV_NFCAL_POWER_ALL_CHANNELS_EVENTID,
WMI_10_4_PDEV_BSS_CHAN_INFO_EVENTID,
+ WMI_10_4_MU_REPORT_EVENTID,
WMI_10_4_PDEV_UTF_EVENTID = WMI_10_4_END_EVENTID - 1,
};
@@ -3650,6 +3679,12 @@ enum wmi_10_4_pdev_param {
WMI_10_4_PDEV_PARAM_WAPI_MBSSID_OFFSET,
WMI_10_4_PDEV_PARAM_ARP_SRCADDR,
WMI_10_4_PDEV_PARAM_ARP_DSTADDR,
+ WMI_10_4_PDEV_PARAM_TXPOWER_DECR_DB,
+ WMI_10_4_PDEV_PARAM_RX_BATCHMODE,
+ WMI_10_4_PDEV_PARAM_PACKET_AGGR_DELAY,
+ WMI_10_4_PDEV_PARAM_ATF_OBSS_NOISE_SCH,
+ WMI_10_4_PDEV_PARAM_ATF_OBSS_NOISE_SCALING_FACTOR,
+ WMI_10_4_PDEV_PARAM_CUST_TXPOWER_SCALE,
};
struct wmi_pdev_set_param_cmd {
@@ -4239,6 +4274,8 @@ enum wmi_vdev_subtype {
WMI_VDEV_SUBTYPE_P2P_DEVICE = 1,
WMI_VDEV_SUBTYPE_P2P_CLIENT = 2,
WMI_VDEV_SUBTYPE_P2P_GO = 3,
+ WMI_VDEV_SUBTYPE_PROXY_STA = 4,
+ WMI_VDEV_SUBTYPE_MESH = 5,
};
/* values for vdev_subtype */
@@ -5641,21 +5678,79 @@ struct wmi_peer_set_q_empty_callback_cmd {
__le32 callback_enable;
} __packed;
-#define WMI_PEER_AUTH 0x00000001
-#define WMI_PEER_QOS 0x00000002
-#define WMI_PEER_NEED_PTK_4_WAY 0x00000004
-#define WMI_PEER_NEED_GTK_2_WAY 0x00000010
-#define WMI_PEER_APSD 0x00000800
-#define WMI_PEER_HT 0x00001000
-#define WMI_PEER_40MHZ 0x00002000
-#define WMI_PEER_STBC 0x00008000
-#define WMI_PEER_LDPC 0x00010000
-#define WMI_PEER_DYN_MIMOPS 0x00020000
-#define WMI_PEER_STATIC_MIMOPS 0x00040000
-#define WMI_PEER_SPATIAL_MUX 0x00200000
-#define WMI_PEER_VHT 0x02000000
-#define WMI_PEER_80MHZ 0x04000000
-#define WMI_PEER_VHT_2G 0x08000000
+struct wmi_peer_flags_map {
+ u32 auth;
+ u32 qos;
+ u32 need_ptk_4_way;
+ u32 need_gtk_2_way;
+ u32 apsd;
+ u32 ht;
+ u32 bw40;
+ u32 stbc;
+ u32 ldbc;
+ u32 dyn_mimops;
+ u32 static_mimops;
+ u32 spatial_mux;
+ u32 vht;
+ u32 bw80;
+ u32 vht_2g;
+ u32 pmf;
+};
+
+enum wmi_peer_flags {
+ WMI_PEER_AUTH = 0x00000001,
+ WMI_PEER_QOS = 0x00000002,
+ WMI_PEER_NEED_PTK_4_WAY = 0x00000004,
+ WMI_PEER_NEED_GTK_2_WAY = 0x00000010,
+ WMI_PEER_APSD = 0x00000800,
+ WMI_PEER_HT = 0x00001000,
+ WMI_PEER_40MHZ = 0x00002000,
+ WMI_PEER_STBC = 0x00008000,
+ WMI_PEER_LDPC = 0x00010000,
+ WMI_PEER_DYN_MIMOPS = 0x00020000,
+ WMI_PEER_STATIC_MIMOPS = 0x00040000,
+ WMI_PEER_SPATIAL_MUX = 0x00200000,
+ WMI_PEER_VHT = 0x02000000,
+ WMI_PEER_80MHZ = 0x04000000,
+ WMI_PEER_VHT_2G = 0x08000000,
+ WMI_PEER_PMF = 0x10000000,
+};
+
+enum wmi_10x_peer_flags {
+ WMI_10X_PEER_AUTH = 0x00000001,
+ WMI_10X_PEER_QOS = 0x00000002,
+ WMI_10X_PEER_NEED_PTK_4_WAY = 0x00000004,
+ WMI_10X_PEER_NEED_GTK_2_WAY = 0x00000010,
+ WMI_10X_PEER_APSD = 0x00000800,
+ WMI_10X_PEER_HT = 0x00001000,
+ WMI_10X_PEER_40MHZ = 0x00002000,
+ WMI_10X_PEER_STBC = 0x00008000,
+ WMI_10X_PEER_LDPC = 0x00010000,
+ WMI_10X_PEER_DYN_MIMOPS = 0x00020000,
+ WMI_10X_PEER_STATIC_MIMOPS = 0x00040000,
+ WMI_10X_PEER_SPATIAL_MUX = 0x00200000,
+ WMI_10X_PEER_VHT = 0x02000000,
+ WMI_10X_PEER_80MHZ = 0x04000000,
+};
+
+enum wmi_10_2_peer_flags {
+ WMI_10_2_PEER_AUTH = 0x00000001,
+ WMI_10_2_PEER_QOS = 0x00000002,
+ WMI_10_2_PEER_NEED_PTK_4_WAY = 0x00000004,
+ WMI_10_2_PEER_NEED_GTK_2_WAY = 0x00000010,
+ WMI_10_2_PEER_APSD = 0x00000800,
+ WMI_10_2_PEER_HT = 0x00001000,
+ WMI_10_2_PEER_40MHZ = 0x00002000,
+ WMI_10_2_PEER_STBC = 0x00008000,
+ WMI_10_2_PEER_LDPC = 0x00010000,
+ WMI_10_2_PEER_DYN_MIMOPS = 0x00020000,
+ WMI_10_2_PEER_STATIC_MIMOPS = 0x00040000,
+ WMI_10_2_PEER_SPATIAL_MUX = 0x00200000,
+ WMI_10_2_PEER_VHT = 0x02000000,
+ WMI_10_2_PEER_80MHZ = 0x04000000,
+ WMI_10_2_PEER_VHT_2G = 0x08000000,
+ WMI_10_2_PEER_PMF = 0x10000000,
+};
/*
* Peer rate capabilities.
@@ -5721,6 +5816,11 @@ struct wmi_10_2_peer_assoc_complete_cmd {
__le32 info0; /* WMI_PEER_ASSOC_INFO0_ */
} __packed;
+struct wmi_10_4_peer_assoc_complete_cmd {
+ struct wmi_10_2_peer_assoc_complete_cmd cmd;
+ __le32 peer_bw_rxnss_override;
+} __packed;
+
struct wmi_peer_assoc_complete_arg {
u8 addr[ETH_ALEN];
u32 vdev_id;
diff --git a/drivers/net/wireless/ath/ath5k/base.c b/drivers/net/wireless/ath/ath5k/base.c
index 342563a3706f..3d946d8b2db2 100644
--- a/drivers/net/wireless/ath/ath5k/base.c
+++ b/drivers/net/wireless/ath/ath5k/base.c
@@ -767,7 +767,7 @@ ath5k_txbuf_setup(struct ath5k_hw *ah, struct ath5k_buf *bf,
if (info->flags & IEEE80211_TX_CTL_NO_ACK)
flags |= AR5K_TXDESC_NOACK;
- rc_flags = info->control.rates[0].flags;
+ rc_flags = bf->rates[0].flags;
hw_rate = ath5k_get_rate_hw_value(ah->hw, info, bf, 0);
diff --git a/drivers/net/wireless/ath/ath6kl/cfg80211.c b/drivers/net/wireless/ath/ath6kl/cfg80211.c
index 81ac8c59f0ec..7f3f94fbf157 100644
--- a/drivers/net/wireless/ath/ath6kl/cfg80211.c
+++ b/drivers/net/wireless/ath/ath6kl/cfg80211.c
@@ -3930,8 +3930,8 @@ int ath6kl_cfg80211_init(struct ath6kl *ar)
ath6kl_band_5ghz.ht_cap.mcs.rx_mask[0] = 0xff;
ath6kl_band_2ghz.ht_cap.mcs.rx_mask[1] = 0xff;
ath6kl_band_5ghz.ht_cap.mcs.rx_mask[1] = 0xff;
- ar->hw.tx_ant = 2;
- ar->hw.rx_ant = 2;
+ ar->hw.tx_ant = 0x3; /* mask, 2 antenna */
+ ar->hw.rx_ant = 0x3;
} else {
ath6kl_band_2ghz.ht_cap.mcs.rx_mask[0] = 0xff;
ath6kl_band_5ghz.ht_cap.mcs.rx_mask[0] = 0xff;
diff --git a/drivers/net/wireless/ath/ath6kl/htc_mbox.c b/drivers/net/wireless/ath/ath6kl/htc_mbox.c
index fffb65b3e652..65c31da43c47 100644
--- a/drivers/net/wireless/ath/ath6kl/htc_mbox.c
+++ b/drivers/net/wireless/ath/ath6kl/htc_mbox.c
@@ -2222,8 +2222,9 @@ int ath6kl_htc_rxmsg_pending_handler(struct htc_target *target,
}
if (status) {
- ath6kl_err("failed to get pending recv messages: %d\n",
- status);
+ if (status != -ECANCELED)
+ ath6kl_err("failed to get pending recv messages: %d\n",
+ status);
/* cleanup any packets in sync completion queue */
list_for_each_entry_safe(packets, tmp_pkt, &comp_pktq, list) {
diff --git a/drivers/net/wireless/ath/ath6kl/init.c b/drivers/net/wireless/ath/ath6kl/init.c
index 6ae0734f86e0..da557dc742e6 100644
--- a/drivers/net/wireless/ath/ath6kl/init.c
+++ b/drivers/net/wireless/ath/ath6kl/init.c
@@ -954,8 +954,10 @@ static int ath6kl_fetch_fw_apin(struct ath6kl *ar, const char *name)
snprintf(filename, sizeof(filename), "%s/%s", ar->hw.fw.dir, name);
ret = request_firmware(&fw, filename, ar->dev);
- if (ret)
+ if (ret) {
+ ath6kl_err("Failed request firmware, rv: %d\n", ret);
return ret;
+ }
data = fw->data;
len = fw->size;
@@ -964,11 +966,15 @@ static int ath6kl_fetch_fw_apin(struct ath6kl *ar, const char *name)
magic_len = strlen(ATH6KL_FIRMWARE_MAGIC) + 1;
if (len < magic_len) {
+ ath6kl_err("Magic length is invalid, len: %zd magic_len: %zd\n",
+ len, magic_len);
ret = -EINVAL;
goto out;
}
if (memcmp(data, ATH6KL_FIRMWARE_MAGIC, magic_len) != 0) {
+ ath6kl_err("Magic is invalid, magic_len: %zd\n",
+ magic_len);
ret = -EINVAL;
goto out;
}
@@ -987,7 +993,12 @@ static int ath6kl_fetch_fw_apin(struct ath6kl *ar, const char *name)
len -= sizeof(*hdr);
data += sizeof(*hdr);
+ ath6kl_dbg(ATH6KL_DBG_BOOT, "ie-id: %d len: %zd (0x%zx)\n",
+ ie_id, ie_len, ie_len);
+
if (len < ie_len) {
+ ath6kl_err("IE len is invalid, len: %zd ie_len: %zd ie-id: %d\n",
+ len, ie_len, ie_id);
ret = -EINVAL;
goto out;
}
@@ -1008,6 +1019,7 @@ static int ath6kl_fetch_fw_apin(struct ath6kl *ar, const char *name)
ar->fw_otp = kmemdup(data, ie_len, GFP_KERNEL);
if (ar->fw_otp == NULL) {
+ ath6kl_err("fw_otp cannot be allocated\n");
ret = -ENOMEM;
goto out;
}
@@ -1025,6 +1037,7 @@ static int ath6kl_fetch_fw_apin(struct ath6kl *ar, const char *name)
ar->fw = vmalloc(ie_len);
if (ar->fw == NULL) {
+ ath6kl_err("fw storage cannot be allocated, len: %zd\n", ie_len);
ret = -ENOMEM;
goto out;
}
@@ -1039,6 +1052,7 @@ static int ath6kl_fetch_fw_apin(struct ath6kl *ar, const char *name)
ar->fw_patch = kmemdup(data, ie_len, GFP_KERNEL);
if (ar->fw_patch == NULL) {
+ ath6kl_err("fw_patch storage cannot be allocated, len: %zd\n", ie_len);
ret = -ENOMEM;
goto out;
}
diff --git a/drivers/net/wireless/ath/ath9k/Kconfig b/drivers/net/wireless/ath/ath9k/Kconfig
index fee0cadb0f5e..40fa915d6f35 100644
--- a/drivers/net/wireless/ath/ath9k/Kconfig
+++ b/drivers/net/wireless/ath/ath9k/Kconfig
@@ -176,3 +176,14 @@ config ATH9K_HTC_DEBUGFS
depends on ATH9K_HTC && DEBUG_FS
---help---
Say Y, if you need access to ath9k_htc's statistics.
+
+config ATH9K_HWRNG
+ bool "Random number generator support"
+ depends on ATH9K && (HW_RANDOM = y || HW_RANDOM = ATH9K)
+ default y
+ ---help---
+ This option incorporates the ADC register output as a source of
+ randomness into Linux entropy pool (/dev/urandom and /dev/random)
+
+ Say Y, feeds the entropy directly from the WiFi driver to the input
+ pool.
diff --git a/drivers/net/wireless/ath/ath9k/Makefile b/drivers/net/wireless/ath/ath9k/Makefile
index ecda613c2d54..76f9dc37500b 100644
--- a/drivers/net/wireless/ath/ath9k/Makefile
+++ b/drivers/net/wireless/ath/ath9k/Makefile
@@ -15,6 +15,7 @@ ath9k-$(CONFIG_ATH9K_DFS_DEBUGFS) += dfs_debug.o
ath9k-$(CONFIG_ATH9K_DFS_CERTIFIED) += dfs.o
ath9k-$(CONFIG_ATH9K_TX99) += tx99.o
ath9k-$(CONFIG_ATH9K_WOW) += wow.o
+ath9k-$(CONFIG_ATH9K_HWRNG) += rng.o
ath9k-$(CONFIG_ATH9K_DEBUGFS) += debug.o
diff --git a/drivers/net/wireless/ath/ath9k/ath9k.h b/drivers/net/wireless/ath/ath9k/ath9k.h
index b42f4a963ef4..5294595da5a7 100644
--- a/drivers/net/wireless/ath/ath9k/ath9k.h
+++ b/drivers/net/wireless/ath/ath9k/ath9k.h
@@ -23,6 +23,7 @@
#include <linux/leds.h>
#include <linux/completion.h>
#include <linux/time.h>
+#include <linux/hw_random.h>
#include "common.h"
#include "debug.h"
@@ -981,6 +982,7 @@ struct ath_softc {
struct ath_offchannel offchannel;
struct ath_chanctx *next_chan;
struct completion go_beacon;
+ struct timespec last_event_time;
#endif
unsigned long driver_data;
@@ -1040,6 +1042,11 @@ struct ath_softc {
u32 wow_intr_before_sleep;
bool force_wow;
#endif
+
+#ifdef CONFIG_ATH9K_HWRNG
+ u32 rng_last;
+ struct task_struct *rng_task;
+#endif
};
/********/
@@ -1062,6 +1069,22 @@ static inline int ath9k_tx99_send(struct ath_softc *sc,
}
#endif /* CONFIG_ATH9K_TX99 */
+/***************************/
+/* Random Number Generator */
+/***************************/
+#ifdef CONFIG_ATH9K_HWRNG
+void ath9k_rng_start(struct ath_softc *sc);
+void ath9k_rng_stop(struct ath_softc *sc);
+#else
+static inline void ath9k_rng_start(struct ath_softc *sc)
+{
+}
+
+static inline void ath9k_rng_stop(struct ath_softc *sc)
+{
+}
+#endif
+
static inline void ath_read_cachesize(struct ath_common *common, int *csz)
{
common->bus_ops->read_cachesize(common, csz);
diff --git a/drivers/net/wireless/ath/ath9k/beacon.c b/drivers/net/wireless/ath/ath9k/beacon.c
index f50a6bc5d06e..5cf0cd7cb2d1 100644
--- a/drivers/net/wireless/ath/ath9k/beacon.c
+++ b/drivers/net/wireless/ath/ath9k/beacon.c
@@ -148,7 +148,8 @@ static struct ath_buf *ath9k_beacon_generate(struct ieee80211_hw *hw,
ath_assign_seq(common, skb);
- if (vif->p2p)
+ /* Always assign NOA attr when MCC enabled */
+ if (ath9k_is_chanctx_enabled())
ath9k_beacon_add_noa(sc, avp, skb);
bf->bf_buf_addr = dma_map_single(sc->dev, skb->data,
diff --git a/drivers/net/wireless/ath/ath9k/channel.c b/drivers/net/wireless/ath/ath9k/channel.c
index 90f5773a1a61..50e614b915f1 100644
--- a/drivers/net/wireless/ath/ath9k/channel.c
+++ b/drivers/net/wireless/ath/ath9k/channel.c
@@ -226,6 +226,20 @@ static const char *chanctx_state_string(enum ath_chanctx_state state)
}
}
+static const u32 chanctx_event_delta(struct ath_softc *sc)
+{
+ u64 ms;
+ struct timespec ts, *old;
+
+ getrawmonotonic(&ts);
+ old = &sc->last_event_time;
+ ms = ts.tv_sec * 1000 + ts.tv_nsec / 1000000;
+ ms -= old->tv_sec * 1000 + old->tv_nsec / 1000000;
+ sc->last_event_time = ts;
+
+ return (u32)ms;
+}
+
void ath_chanctx_check_active(struct ath_softc *sc, struct ath_chanctx *ctx)
{
struct ath_common *common = ath9k_hw_common(sc->sc_ah);
@@ -356,14 +370,16 @@ static void ath_chanctx_setup_timer(struct ath_softc *sc, u32 tsf_time)
{
struct ath_common *common = ath9k_hw_common(sc->sc_ah);
struct ath_hw *ah = sc->sc_ah;
+ unsigned long timeout;
ath9k_hw_gen_timer_start(ah, sc->p2p_ps_timer, tsf_time, 1000000);
tsf_time -= ath9k_hw_gettsf32(ah);
- tsf_time = msecs_to_jiffies(tsf_time / 1000) + 1;
- mod_timer(&sc->sched.timer, jiffies + tsf_time);
+ timeout = msecs_to_jiffies(tsf_time / 1000) + 1;
+ mod_timer(&sc->sched.timer, jiffies + timeout);
ath_dbg(common, CHAN_CTX,
- "Setup chanctx timer with timeout: %d ms\n", jiffies_to_msecs(tsf_time));
+ "Setup chanctx timer with timeout: %d (%d) ms\n",
+ tsf_time / 1000, jiffies_to_msecs(timeout));
}
static void ath_chanctx_handle_bmiss(struct ath_softc *sc,
@@ -403,7 +419,7 @@ static void ath_chanctx_offchannel_noa(struct ath_softc *sc,
avp->offchannel_duration = sc->sched.offchannel_duration;
ath_dbg(common, CHAN_CTX,
- "offchannel noa_duration: %d, noa_start: %d, noa_index: %d\n",
+ "offchannel noa_duration: %d, noa_start: %u, noa_index: %d\n",
avp->offchannel_duration,
avp->offchannel_start,
avp->noa_index);
@@ -443,7 +459,7 @@ static void ath_chanctx_set_periodic_noa(struct ath_softc *sc,
avp->periodic_noa = true;
ath_dbg(common, CHAN_CTX,
- "noa_duration: %d, noa_start: %d, noa_index: %d, periodic: %d\n",
+ "noa_duration: %d, noa_start: %u, noa_index: %d, periodic: %d\n",
avp->noa_duration,
avp->noa_start,
avp->noa_index,
@@ -464,7 +480,7 @@ static void ath_chanctx_set_oneshot_noa(struct ath_softc *sc,
avp->noa_duration = duration + sc->sched.channel_switch_time;
ath_dbg(common, CHAN_CTX,
- "oneshot noa_duration: %d, noa_start: %d, noa_index: %d, periodic: %d\n",
+ "oneshot noa_duration: %d, noa_start: %u, noa_index: %d, periodic: %d\n",
avp->noa_duration,
avp->noa_start,
avp->noa_index,
@@ -487,10 +503,11 @@ void ath_chanctx_event(struct ath_softc *sc, struct ieee80211_vif *vif,
spin_lock_bh(&sc->chan_lock);
- ath_dbg(common, CHAN_CTX, "cur_chan: %d MHz, event: %s, state: %s\n",
+ ath_dbg(common, CHAN_CTX, "cur_chan: %d MHz, event: %s, state: %s, delta: %u ms\n",
sc->cur_chan->chandef.center_freq1,
chanctx_event_string(ev),
- chanctx_state_string(sc->sched.state));
+ chanctx_state_string(sc->sched.state),
+ chanctx_event_delta(sc));
switch (ev) {
case ATH_CHANCTX_EVENT_BEACON_PREPARE:
@@ -1099,6 +1116,7 @@ ath_chanctx_send_vif_ps_frame(struct ath_softc *sc, struct ath_vif *avp,
nullfunc->frame_control |=
cpu_to_le16(IEEE80211_FCTL_PM);
+ skb->priority = 7;
skb_set_queue_mapping(skb, IEEE80211_AC_VO);
if (!ieee80211_tx_prepare_skb(sc->hw, vif, skb, band, &sta)) {
dev_kfree_skb_any(skb);
@@ -1401,8 +1419,9 @@ void ath9k_chanctx_wake_queues(struct ath_softc *sc, struct ath_chanctx *ctx)
static void ath9k_update_p2p_ps_timer(struct ath_softc *sc, struct ath_vif *avp)
{
+ struct ath_common *common = ath9k_hw_common(sc->sc_ah);
struct ath_hw *ah = sc->sc_ah;
- s32 tsf, target_tsf;
+ u32 tsf, target_tsf;
if (!avp || !avp->noa.has_next_tsf)
return;
@@ -1414,11 +1433,17 @@ static void ath9k_update_p2p_ps_timer(struct ath_softc *sc, struct ath_vif *avp)
target_tsf = avp->noa.next_tsf;
if (!avp->noa.absent)
target_tsf -= ATH_P2P_PS_STOP_TIME;
+ else
+ target_tsf += ATH_P2P_PS_STOP_TIME;
if (target_tsf - tsf < ATH_P2P_PS_STOP_TIME)
target_tsf = tsf + ATH_P2P_PS_STOP_TIME;
- ath9k_hw_gen_timer_start(ah, sc->p2p_ps_timer, (u32) target_tsf, 1000000);
+ ath_dbg(common, CHAN_CTX, "%s absent %d tsf 0x%08X next_tsf 0x%08X (%dms)\n",
+ __func__, avp->noa.absent, tsf, target_tsf,
+ (target_tsf - tsf) / 1000);
+
+ ath9k_hw_gen_timer_start(ah, sc->p2p_ps_timer, target_tsf, 1000000);
}
static void ath9k_update_p2p_ps(struct ath_softc *sc, struct ieee80211_vif *vif)
@@ -1433,6 +1458,10 @@ static void ath9k_update_p2p_ps(struct ath_softc *sc, struct ieee80211_vif *vif)
return;
sc->p2p_ps_vif = avp;
+
+ if (sc->ps_flags & PS_BEACON_SYNC)
+ return;
+
tsf = ath9k_hw_gettsf32(sc->sc_ah);
ieee80211_parse_p2p_noa(&vif->bss_conf.p2p_noa_attr, &avp->noa, tsf);
ath9k_update_p2p_ps_timer(sc, avp);
@@ -1495,6 +1524,8 @@ void ath9k_beacon_add_noa(struct ath_softc *sc, struct ath_vif *avp,
noa->index = avp->noa_index;
noa->oppps_ctwindow = ath9k_get_ctwin(sc, avp);
+ if (noa->oppps_ctwindow)
+ noa->oppps_ctwindow |= BIT(7);
if (avp->noa_duration) {
if (avp->periodic_noa) {
@@ -1536,6 +1567,8 @@ void ath9k_p2p_ps_timer(void *priv)
tsf = ath9k_hw_gettsf32(sc->sc_ah);
if (!avp->noa.absent)
tsf += ATH_P2P_PS_STOP_TIME;
+ else
+ tsf -= ATH_P2P_PS_STOP_TIME;
if (!avp->noa.has_next_tsf ||
avp->noa.next_tsf - tsf > BIT(31))
@@ -1571,8 +1604,7 @@ void ath9k_p2p_bss_info_changed(struct ath_softc *sc,
spin_lock_bh(&sc->sc_pcu_lock);
spin_lock_irqsave(&sc->sc_pm_lock, flags);
- if (!(sc->ps_flags & PS_BEACON_SYNC))
- ath9k_update_p2p_ps(sc, vif);
+ ath9k_update_p2p_ps(sc, vif);
spin_unlock_irqrestore(&sc->sc_pm_lock, flags);
spin_unlock_bh(&sc->sc_pcu_lock);
}
diff --git a/drivers/net/wireless/ath/ath9k/common-beacon.c b/drivers/net/wireless/ath/ath9k/common-beacon.c
index 6ad44470d0f2..01d6d3205a65 100644
--- a/drivers/net/wireless/ath/ath9k/common-beacon.c
+++ b/drivers/net/wireless/ath/ath9k/common-beacon.c
@@ -18,30 +18,16 @@
#define FUDGE 2
-/* Calculate the modulo of a 64 bit TSF snapshot with a TU divisor */
-static u32 ath9k_mod_tsf64_tu(u64 tsf, u32 div_tu)
-{
- u32 tsf_mod, tsf_hi, tsf_lo, mod_hi, mod_lo;
-
- tsf_mod = tsf & (BIT(10) - 1);
- tsf_hi = tsf >> 32;
- tsf_lo = ((u32) tsf) >> 10;
-
- mod_hi = tsf_hi % div_tu;
- mod_lo = ((mod_hi << 22) + tsf_lo) % div_tu;
-
- return (mod_lo << 10) | tsf_mod;
-}
-
static u32 ath9k_get_next_tbtt(struct ath_hw *ah, u64 tsf,
unsigned int interval)
{
- unsigned int offset;
+ unsigned int offset, divisor;
tsf += TU_TO_USEC(FUDGE + ah->config.sw_beacon_response_time);
- offset = ath9k_mod_tsf64_tu(tsf, interval);
+ divisor = TU_TO_USEC(interval);
+ div_u64_rem(tsf, divisor, &offset);
- return (u32) tsf + TU_TO_USEC(interval) - offset;
+ return (u32) tsf + divisor - offset;
}
/*
diff --git a/drivers/net/wireless/ath/ath9k/eeprom.c b/drivers/net/wireless/ath/ath9k/eeprom.c
index cc81482c934d..a7afdeee698c 100644
--- a/drivers/net/wireless/ath/ath9k/eeprom.c
+++ b/drivers/net/wireless/ath/ath9k/eeprom.c
@@ -138,6 +138,80 @@ bool ath9k_hw_nvram_read(struct ath_hw *ah, u32 off, u16 *data)
return ret;
}
+int ath9k_hw_nvram_swap_data(struct ath_hw *ah, bool *swap_needed, int size)
+{
+ u16 magic;
+ u16 *eepdata;
+ int i;
+ struct ath_common *common = ath9k_hw_common(ah);
+
+ if (!ath9k_hw_nvram_read(ah, AR5416_EEPROM_MAGIC_OFFSET, &magic)) {
+ ath_err(common, "Reading Magic # failed\n");
+ return -EIO;
+ }
+
+ if (magic == AR5416_EEPROM_MAGIC) {
+ *swap_needed = false;
+ } else if (swab16(magic) == AR5416_EEPROM_MAGIC) {
+ if (ah->ah_flags & AH_NO_EEP_SWAP) {
+ ath_info(common,
+ "Ignoring endianness difference in EEPROM magic bytes.\n");
+
+ *swap_needed = false;
+ } else {
+ *swap_needed = true;
+ }
+ } else {
+ ath_err(common,
+ "Invalid EEPROM Magic (0x%04x).\n", magic);
+ return -EINVAL;
+ }
+
+ eepdata = (u16 *)(&ah->eeprom);
+
+ if (*swap_needed) {
+ ath_dbg(common, EEPROM,
+ "EEPROM Endianness is not native.. Changing.\n");
+
+ for (i = 0; i < size; i++)
+ eepdata[i] = swab16(eepdata[i]);
+ }
+
+ return 0;
+}
+
+bool ath9k_hw_nvram_validate_checksum(struct ath_hw *ah, int size)
+{
+ u32 i, sum = 0;
+ u16 *eepdata = (u16 *)(&ah->eeprom);
+ struct ath_common *common = ath9k_hw_common(ah);
+
+ for (i = 0; i < size; i++)
+ sum ^= eepdata[i];
+
+ if (sum != 0xffff) {
+ ath_err(common, "Bad EEPROM checksum 0x%x\n", sum);
+ return false;
+ }
+
+ return true;
+}
+
+bool ath9k_hw_nvram_check_version(struct ath_hw *ah, int version, int minrev)
+{
+ struct ath_common *common = ath9k_hw_common(ah);
+
+ if (ah->eep_ops->get_eeprom_ver(ah) != version ||
+ ah->eep_ops->get_eeprom_rev(ah) < minrev) {
+ ath_err(common, "Bad EEPROM VER 0x%04x or REV 0x%04x\n",
+ ah->eep_ops->get_eeprom_ver(ah),
+ ah->eep_ops->get_eeprom_rev(ah));
+ return false;
+ }
+
+ return true;
+}
+
void ath9k_hw_fill_vpd_table(u8 pwrMin, u8 pwrMax, u8 *pPwrList,
u8 *pVpdList, u16 numIntercepts,
u8 *pRetVpdList)
diff --git a/drivers/net/wireless/ath/ath9k/eeprom.h b/drivers/net/wireless/ath/ath9k/eeprom.h
index 40d4f62d0f16..4465c6566f20 100644
--- a/drivers/net/wireless/ath/ath9k/eeprom.h
+++ b/drivers/net/wireless/ath/ath9k/eeprom.h
@@ -664,6 +664,9 @@ int16_t ath9k_hw_interpolate(u16 target, u16 srcLeft, u16 srcRight,
bool ath9k_hw_get_lower_upper_index(u8 target, u8 *pList, u16 listSize,
u16 *indexL, u16 *indexR);
bool ath9k_hw_nvram_read(struct ath_hw *ah, u32 off, u16 *data);
+int ath9k_hw_nvram_swap_data(struct ath_hw *ah, bool *swap_needed, int size);
+bool ath9k_hw_nvram_validate_checksum(struct ath_hw *ah, int size);
+bool ath9k_hw_nvram_check_version(struct ath_hw *ah, int version, int minrev);
void ath9k_hw_usb_gen_fill_eeprom(struct ath_hw *ah, u16 *eep_data,
int eep_start_loc, int size);
void ath9k_hw_fill_vpd_table(u8 pwrMin, u8 pwrMax, u8 *pPwrList,
diff --git a/drivers/net/wireless/ath/ath9k/eeprom_4k.c b/drivers/net/wireless/ath/ath9k/eeprom_4k.c
index 4773da6dc6f2..5da0826bf1be 100644
--- a/drivers/net/wireless/ath/ath9k/eeprom_4k.c
+++ b/drivers/net/wireless/ath/ath9k/eeprom_4k.c
@@ -177,74 +177,30 @@ static u32 ath9k_hw_4k_dump_eeprom(struct ath_hw *ah, bool dump_base_hdr,
}
#endif
-
-#undef SIZE_EEPROM_4K
-
static int ath9k_hw_4k_check_eeprom(struct ath_hw *ah)
{
-#define EEPROM_4K_SIZE (sizeof(struct ar5416_eeprom_4k) / sizeof(u16))
- struct ath_common *common = ath9k_hw_common(ah);
struct ar5416_eeprom_4k *eep = &ah->eeprom.map4k;
- u16 *eepdata, temp, magic, magic2;
- u32 sum = 0, el;
- bool need_swap = false;
- int i, addr;
+ u32 el;
+ bool need_swap;
+ int i, err;
-
- if (!ath9k_hw_use_flash(ah)) {
- if (!ath9k_hw_nvram_read(ah, AR5416_EEPROM_MAGIC_OFFSET,
- &magic)) {
- ath_err(common, "Reading Magic # failed\n");
- return false;
- }
-
- ath_dbg(common, EEPROM, "Read Magic = 0x%04X\n", magic);
-
- if (magic != AR5416_EEPROM_MAGIC) {
- magic2 = swab16(magic);
-
- if (magic2 == AR5416_EEPROM_MAGIC) {
- need_swap = true;
- eepdata = (u16 *) (&ah->eeprom);
-
- for (addr = 0; addr < EEPROM_4K_SIZE; addr++) {
- temp = swab16(*eepdata);
- *eepdata = temp;
- eepdata++;
- }
- } else {
- ath_err(common,
- "Invalid EEPROM Magic. Endianness mismatch.\n");
- return -EINVAL;
- }
- }
- }
-
- ath_dbg(common, EEPROM, "need_swap = %s\n",
- need_swap ? "True" : "False");
+ err = ath9k_hw_nvram_swap_data(ah, &need_swap, SIZE_EEPROM_4K);
+ if (err)
+ return err;
if (need_swap)
- el = swab16(ah->eeprom.map4k.baseEepHeader.length);
- else
- el = ah->eeprom.map4k.baseEepHeader.length;
-
- if (el > sizeof(struct ar5416_eeprom_4k))
- el = sizeof(struct ar5416_eeprom_4k) / sizeof(u16);
+ el = swab16(eep->baseEepHeader.length);
else
- el = el / sizeof(u16);
+ el = eep->baseEepHeader.length;
- eepdata = (u16 *)(&ah->eeprom);
-
- for (i = 0; i < el; i++)
- sum ^= *eepdata++;
+ el = min(el / sizeof(u16), SIZE_EEPROM_4K);
+ if (!ath9k_hw_nvram_validate_checksum(ah, el))
+ return -EINVAL;
if (need_swap) {
u32 integer;
u16 word;
- ath_dbg(common, EEPROM,
- "EEPROM Endianness is not native.. Changing\n");
-
word = swab16(eep->baseEepHeader.length);
eep->baseEepHeader.length = word;
@@ -283,17 +239,15 @@ static int ath9k_hw_4k_check_eeprom(struct ath_hw *ah)
}
}
- if (sum != 0xffff || ah->eep_ops->get_eeprom_ver(ah) != AR5416_EEP_VER ||
- ah->eep_ops->get_eeprom_rev(ah) < AR5416_EEP_NO_BACK_VER) {
- ath_err(common, "Bad EEPROM checksum 0x%x or revision 0x%04x\n",
- sum, ah->eep_ops->get_eeprom_ver(ah));
+ if (!ath9k_hw_nvram_check_version(ah, AR5416_EEP_VER,
+ AR5416_EEP_NO_BACK_VER))
return -EINVAL;
- }
return 0;
-#undef EEPROM_4K_SIZE
}
+#undef SIZE_EEPROM_4K
+
static u32 ath9k_hw_4k_get_eeprom(struct ath_hw *ah,
enum eeprom_param param)
{
diff --git a/drivers/net/wireless/ath/ath9k/eeprom_9287.c b/drivers/net/wireless/ath/ath9k/eeprom_9287.c
index 6ca33dfde1fd..1a019a39eda1 100644
--- a/drivers/net/wireless/ath/ath9k/eeprom_9287.c
+++ b/drivers/net/wireless/ath/ath9k/eeprom_9287.c
@@ -177,59 +177,24 @@ static u32 ath9k_hw_ar9287_dump_eeprom(struct ath_hw *ah, bool dump_base_hdr,
static int ath9k_hw_ar9287_check_eeprom(struct ath_hw *ah)
{
- u32 sum = 0, el, integer;
- u16 temp, word, magic, magic2, *eepdata;
- int i, addr;
- bool need_swap = false;
+ u32 el, integer;
+ u16 word;
+ int i, err;
+ bool need_swap;
struct ar9287_eeprom *eep = &ah->eeprom.map9287;
- struct ath_common *common = ath9k_hw_common(ah);
-
- if (!ath9k_hw_use_flash(ah)) {
- if (!ath9k_hw_nvram_read(ah, AR5416_EEPROM_MAGIC_OFFSET,
- &magic)) {
- ath_err(common, "Reading Magic # failed\n");
- return false;
- }
-
- ath_dbg(common, EEPROM, "Read Magic = 0x%04X\n", magic);
-
- if (magic != AR5416_EEPROM_MAGIC) {
- magic2 = swab16(magic);
-
- if (magic2 == AR5416_EEPROM_MAGIC) {
- need_swap = true;
- eepdata = (u16 *)(&ah->eeprom);
-
- for (addr = 0; addr < SIZE_EEPROM_AR9287; addr++) {
- temp = swab16(*eepdata);
- *eepdata = temp;
- eepdata++;
- }
- } else {
- ath_err(common,
- "Invalid EEPROM Magic. Endianness mismatch.\n");
- return -EINVAL;
- }
- }
- }
- ath_dbg(common, EEPROM, "need_swap = %s\n",
- need_swap ? "True" : "False");
+ err = ath9k_hw_nvram_swap_data(ah, &need_swap, SIZE_EEPROM_AR9287);
+ if (err)
+ return err;
if (need_swap)
- el = swab16(ah->eeprom.map9287.baseEepHeader.length);
- else
- el = ah->eeprom.map9287.baseEepHeader.length;
-
- if (el > sizeof(struct ar9287_eeprom))
- el = sizeof(struct ar9287_eeprom) / sizeof(u16);
+ el = swab16(eep->baseEepHeader.length);
else
- el = el / sizeof(u16);
-
- eepdata = (u16 *)(&ah->eeprom);
+ el = eep->baseEepHeader.length;
- for (i = 0; i < el; i++)
- sum ^= *eepdata++;
+ el = min(el / sizeof(u16), SIZE_EEPROM_AR9287);
+ if (!ath9k_hw_nvram_validate_checksum(ah, el))
+ return -EINVAL;
if (need_swap) {
word = swab16(eep->baseEepHeader.length);
@@ -270,16 +235,15 @@ static int ath9k_hw_ar9287_check_eeprom(struct ath_hw *ah)
}
}
- if (sum != 0xffff || ah->eep_ops->get_eeprom_ver(ah) != AR9287_EEP_VER
- || ah->eep_ops->get_eeprom_rev(ah) < AR5416_EEP_NO_BACK_VER) {
- ath_err(common, "Bad EEPROM checksum 0x%x or revision 0x%04x\n",
- sum, ah->eep_ops->get_eeprom_ver(ah));
+ if (!ath9k_hw_nvram_check_version(ah, AR9287_EEP_VER,
+ AR5416_EEP_NO_BACK_VER))
return -EINVAL;
- }
return 0;
}
+#undef SIZE_EEPROM_AR9287
+
static u32 ath9k_hw_ar9287_get_eeprom(struct ath_hw *ah,
enum eeprom_param param)
{
diff --git a/drivers/net/wireless/ath/ath9k/eeprom_def.c b/drivers/net/wireless/ath/ath9k/eeprom_def.c
index 056f516bf017..959682f7909c 100644
--- a/drivers/net/wireless/ath/ath9k/eeprom_def.c
+++ b/drivers/net/wireless/ath/ath9k/eeprom_def.c
@@ -126,8 +126,6 @@ static bool ath9k_hw_def_fill_eeprom(struct ath_hw *ah)
return __ath9k_hw_def_fill_eeprom(ah);
}
-#undef SIZE_EEPROM_DEF
-
#if defined(CONFIG_ATH9K_DEBUGFS) || defined(CONFIG_ATH9K_HTC_DEBUGFS)
static u32 ath9k_def_dump_modal_eeprom(char *buf, u32 len, u32 size,
struct modal_eep_header *modal_hdr)
@@ -257,59 +255,31 @@ static u32 ath9k_hw_def_dump_eeprom(struct ath_hw *ah, bool dump_base_hdr,
}
#endif
-
static int ath9k_hw_def_check_eeprom(struct ath_hw *ah)
{
struct ar5416_eeprom_def *eep = &ah->eeprom.def;
struct ath_common *common = ath9k_hw_common(ah);
- u16 *eepdata, temp, magic;
- u32 sum = 0, el;
- bool need_swap = false;
- int i, addr, size;
-
- if (!ath9k_hw_nvram_read(ah, AR5416_EEPROM_MAGIC_OFFSET, &magic)) {
- ath_err(common, "Reading Magic # failed\n");
- return false;
- }
-
- if (swab16(magic) == AR5416_EEPROM_MAGIC &&
- !(ah->ah_flags & AH_NO_EEP_SWAP)) {
- size = sizeof(struct ar5416_eeprom_def);
- need_swap = true;
- eepdata = (u16 *) (&ah->eeprom);
-
- for (addr = 0; addr < size / sizeof(u16); addr++) {
- temp = swab16(*eepdata);
- *eepdata = temp;
- eepdata++;
- }
- }
+ u32 el;
+ bool need_swap;
+ int i, err;
- ath_dbg(common, EEPROM, "need_swap = %s\n",
- need_swap ? "True" : "False");
+ err = ath9k_hw_nvram_swap_data(ah, &need_swap, SIZE_EEPROM_DEF);
+ if (err)
+ return err;
if (need_swap)
- el = swab16(ah->eeprom.def.baseEepHeader.length);
+ el = swab16(eep->baseEepHeader.length);
else
- el = ah->eeprom.def.baseEepHeader.length;
+ el = eep->baseEepHeader.length;
- if (el > sizeof(struct ar5416_eeprom_def))
- el = sizeof(struct ar5416_eeprom_def) / sizeof(u16);
- else
- el = el / sizeof(u16);
-
- eepdata = (u16 *)(&ah->eeprom);
-
- for (i = 0; i < el; i++)
- sum ^= *eepdata++;
+ el = min(el / sizeof(u16), SIZE_EEPROM_DEF);
+ if (!ath9k_hw_nvram_validate_checksum(ah, el))
+ return -EINVAL;
if (need_swap) {
u32 integer, j;
u16 word;
- ath_dbg(common, EEPROM,
- "EEPROM Endianness is not native.. Changing.\n");
-
word = swab16(eep->baseEepHeader.length);
eep->baseEepHeader.length = word;
@@ -356,12 +326,9 @@ static int ath9k_hw_def_check_eeprom(struct ath_hw *ah)
}
}
- if (sum != 0xffff || ah->eep_ops->get_eeprom_ver(ah) != AR5416_EEP_VER ||
- ah->eep_ops->get_eeprom_rev(ah) < AR5416_EEP_NO_BACK_VER) {
- ath_err(common, "Bad EEPROM checksum 0x%x or revision 0x%04x\n",
- sum, ah->eep_ops->get_eeprom_ver(ah));
+ if (!ath9k_hw_nvram_check_version(ah, AR5416_EEP_VER,
+ AR5416_EEP_NO_BACK_VER))
return -EINVAL;
- }
/* Enable fixup for AR_AN_TOP2 if necessary */
if ((ah->hw_version.devid == AR9280_DEVID_PCI) &&
@@ -376,6 +343,8 @@ static int ath9k_hw_def_check_eeprom(struct ath_hw *ah)
return 0;
}
+#undef SIZE_EEPROM_DEF
+
static u32 ath9k_hw_def_get_eeprom(struct ath_hw *ah,
enum eeprom_param param)
{
diff --git a/drivers/net/wireless/ath/ath9k/htc_drv_main.c b/drivers/net/wireless/ath/ath9k/htc_drv_main.c
index a680a970b7f7..fe1fd1a5ae15 100644
--- a/drivers/net/wireless/ath/ath9k/htc_drv_main.c
+++ b/drivers/net/wireless/ath/ath9k/htc_drv_main.c
@@ -834,7 +834,7 @@ void ath9k_htc_ani_work(struct work_struct *work)
if (longcal || shortcal)
common->ani.caldone =
ath9k_hw_calibrate(ah, ah->curchan,
- ah->rxchainmask, longcal);
+ ah->rxchainmask, longcal) > 0;
ath9k_htc_ps_restore(priv);
}
diff --git a/drivers/net/wireless/ath/ath9k/htc_hst.c b/drivers/net/wireless/ath/ath9k/htc_hst.c
index 2294709ee8b0..fd85f996c554 100644
--- a/drivers/net/wireless/ath/ath9k/htc_hst.c
+++ b/drivers/net/wireless/ath/ath9k/htc_hst.c
@@ -414,7 +414,7 @@ void ath9k_htc_rx_msg(struct htc_target *htc_handle,
return;
}
- if (epid >= ENDPOINT_MAX) {
+ if (epid < 0 || epid >= ENDPOINT_MAX) {
if (pipe_id != USB_REG_IN_PIPE)
dev_kfree_skb_any(skb);
else
diff --git a/drivers/net/wireless/ath/ath9k/hw.c b/drivers/net/wireless/ath/ath9k/hw.c
index 41382f89abe1..257f46ed4a04 100644
--- a/drivers/net/wireless/ath/ath9k/hw.c
+++ b/drivers/net/wireless/ath/ath9k/hw.c
@@ -2299,10 +2299,10 @@ void ath9k_hw_set_sta_beacon_timers(struct ath_hw *ah,
else
nextTbtt = bs->bs_nexttbtt;
- ath_dbg(common, BEACON, "next DTIM %d\n", bs->bs_nextdtim);
- ath_dbg(common, BEACON, "next beacon %d\n", nextTbtt);
- ath_dbg(common, BEACON, "beacon period %d\n", beaconintval);
- ath_dbg(common, BEACON, "DTIM period %d\n", dtimperiod);
+ ath_dbg(common, BEACON, "next DTIM %u\n", bs->bs_nextdtim);
+ ath_dbg(common, BEACON, "next beacon %u\n", nextTbtt);
+ ath_dbg(common, BEACON, "beacon period %u\n", beaconintval);
+ ath_dbg(common, BEACON, "DTIM period %u\n", dtimperiod);
ENABLE_REGWRITE_BUFFER(ah);
@@ -2761,9 +2761,6 @@ void ath9k_hw_setrxfilter(struct ath_hw *ah, u32 bits)
ENABLE_REGWRITE_BUFFER(ah);
- if (AR_SREV_9462(ah) || AR_SREV_9565(ah))
- bits |= ATH9K_RX_FILTER_CONTROL_WRAPPER;
-
REG_WRITE(ah, AR_RX_FILTER, bits);
phybits = 0;
diff --git a/drivers/net/wireless/ath/ath9k/init.c b/drivers/net/wireless/ath/ath9k/init.c
index 2e2b92ba96b8..ab7a1ac37849 100644
--- a/drivers/net/wireless/ath/ath9k/init.c
+++ b/drivers/net/wireless/ath/ath9k/init.c
@@ -828,6 +828,7 @@ static void ath9k_set_hw_capab(struct ath_softc *sc, struct ieee80211_hw *hw)
ieee80211_hw_set(hw, RX_INCLUDES_FCS);
ieee80211_hw_set(hw, HOST_BROADCAST_PS_BUFFERING);
ieee80211_hw_set(hw, SUPPORT_FAST_XMIT);
+ ieee80211_hw_set(hw, SUPPORTS_CLONED_SKBS);
if (ath9k_ps_enable)
ieee80211_hw_set(hw, SUPPORTS_PS);
diff --git a/drivers/net/wireless/ath/ath9k/main.c b/drivers/net/wireless/ath/ath9k/main.c
index d184e682e636..c1b33fdcca08 100644
--- a/drivers/net/wireless/ath/ath9k/main.c
+++ b/drivers/net/wireless/ath/ath9k/main.c
@@ -739,6 +739,8 @@ static int ath9k_start(struct ieee80211_hw *hw)
ath9k_ps_restore(sc);
+ ath9k_rng_start(sc);
+
return 0;
}
@@ -828,6 +830,8 @@ static void ath9k_stop(struct ieee80211_hw *hw)
ath9k_deinit_channel_context(sc);
+ ath9k_rng_stop(sc);
+
mutex_lock(&sc->mutex);
ath_cancel_work(sc);
diff --git a/drivers/net/wireless/ath/ath9k/recv.c b/drivers/net/wireless/ath/ath9k/recv.c
index 994daf6c6297..32160fca876a 100644
--- a/drivers/net/wireless/ath/ath9k/recv.c
+++ b/drivers/net/wireless/ath/ath9k/recv.c
@@ -424,6 +424,9 @@ u32 ath_calcrxfilter(struct ath_softc *sc)
AR_SREV_9561(sc->sc_ah))
rfilt |= ATH9K_RX_FILTER_4ADDRESS;
+ if (AR_SREV_9462(sc->sc_ah) || AR_SREV_9565(sc->sc_ah))
+ rfilt |= ATH9K_RX_FILTER_CONTROL_WRAPPER;
+
if (ath9k_is_chanctx_enabled() &&
test_bit(ATH_OP_SCANNING, &common->op_flags))
rfilt |= ATH9K_RX_FILTER_BEACON;
diff --git a/drivers/net/wireless/ath/ath9k/rng.c b/drivers/net/wireless/ath/ath9k/rng.c
new file mode 100644
index 000000000000..c9cb2aad7b6f
--- /dev/null
+++ b/drivers/net/wireless/ath/ath9k/rng.c
@@ -0,0 +1,107 @@
+/*
+ * Copyright (c) 2015 Qualcomm Atheros, Inc.
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <linux/hw_random.h>
+#include <linux/kthread.h>
+
+#include "ath9k.h"
+#include "hw.h"
+#include "ar9003_phy.h"
+
+#define ATH9K_RNG_BUF_SIZE 320
+#define ATH9K_RNG_ENTROPY(x) (((x) * 8 * 320) >> 10) /* quality: 320/1024 */
+
+static int ath9k_rng_data_read(struct ath_softc *sc, u32 *buf, u32 buf_size)
+{
+ int i, j;
+ u32 v1, v2, rng_last = sc->rng_last;
+ struct ath_hw *ah = sc->sc_ah;
+
+ ath9k_ps_wakeup(sc);
+
+ REG_RMW_FIELD(ah, AR_PHY_TEST, AR_PHY_TEST_BBB_OBS_SEL, 1);
+ REG_CLR_BIT(ah, AR_PHY_TEST, AR_PHY_TEST_RX_OBS_SEL_BIT5);
+ REG_RMW_FIELD(ah, AR_PHY_TEST_CTL_STATUS, AR_PHY_TEST_CTL_RX_OBS_SEL, 0);
+
+ for (i = 0, j = 0; i < buf_size; i++) {
+ v1 = REG_READ(ah, AR_PHY_TST_ADC) & 0xffff;
+ v2 = REG_READ(ah, AR_PHY_TST_ADC) & 0xffff;
+
+ /* wait for data ready */
+ if (v1 && v2 && rng_last != v1 && v1 != v2 && v1 != 0xffff &&
+ v2 != 0xffff)
+ buf[j++] = (v1 << 16) | v2;
+
+ rng_last = v2;
+ }
+
+ ath9k_ps_restore(sc);
+
+ sc->rng_last = rng_last;
+
+ return j << 2;
+}
+
+static int ath9k_rng_kthread(void *data)
+{
+ int bytes_read;
+ struct ath_softc *sc = data;
+ u32 *rng_buf;
+
+ rng_buf = kmalloc_array(ATH9K_RNG_BUF_SIZE, sizeof(u32), GFP_KERNEL);
+ if (!rng_buf)
+ goto out;
+
+ while (!kthread_should_stop()) {
+ bytes_read = ath9k_rng_data_read(sc, rng_buf,
+ ATH9K_RNG_BUF_SIZE);
+ if (unlikely(!bytes_read)) {
+ msleep_interruptible(10);
+ continue;
+ }
+
+ /* sleep until entropy bits under write_wakeup_threshold */
+ add_hwgenerator_randomness((void *)rng_buf, bytes_read,
+ ATH9K_RNG_ENTROPY(bytes_read));
+ }
+
+ kfree(rng_buf);
+out:
+ sc->rng_task = NULL;
+
+ return 0;
+}
+
+void ath9k_rng_start(struct ath_softc *sc)
+{
+ struct ath_hw *ah = sc->sc_ah;
+
+ if (sc->rng_task)
+ return;
+
+ if (!AR_SREV_9300_20_OR_LATER(ah))
+ return;
+
+ sc->rng_task = kthread_run(ath9k_rng_kthread, sc, "ath9k-hwrng");
+ if (IS_ERR(sc->rng_task))
+ sc->rng_task = NULL;
+}
+
+void ath9k_rng_stop(struct ath_softc *sc)
+{
+ if (sc->rng_task)
+ kthread_stop(sc->rng_task);
+}
diff --git a/drivers/net/wireless/ath/ath9k/xmit.c b/drivers/net/wireless/ath/ath9k/xmit.c
index 3e3dac3d7060..fe795fc5288c 100644
--- a/drivers/net/wireless/ath/ath9k/xmit.c
+++ b/drivers/net/wireless/ath/ath9k/xmit.c
@@ -1473,11 +1473,14 @@ static bool ath_tx_sched_aggr(struct ath_softc *sc, struct ath_txq *txq,
int ath_tx_aggr_start(struct ath_softc *sc, struct ieee80211_sta *sta,
u16 tid, u16 *ssn)
{
+ struct ath_common *common = ath9k_hw_common(sc->sc_ah);
struct ath_atx_tid *txtid;
struct ath_txq *txq;
struct ath_node *an;
u8 density;
+ ath_dbg(common, XMIT, "%s called\n", __func__);
+
an = (struct ath_node *)sta->drv_priv;
txtid = ATH_AN_2_TID(an, tid);
txq = txtid->txq;
@@ -1512,10 +1515,13 @@ int ath_tx_aggr_start(struct ath_softc *sc, struct ieee80211_sta *sta,
void ath_tx_aggr_stop(struct ath_softc *sc, struct ieee80211_sta *sta, u16 tid)
{
+ struct ath_common *common = ath9k_hw_common(sc->sc_ah);
struct ath_node *an = (struct ath_node *)sta->drv_priv;
struct ath_atx_tid *txtid = ATH_AN_2_TID(an, tid);
struct ath_txq *txq = txtid->txq;
+ ath_dbg(common, XMIT, "%s called\n", __func__);
+
ath_txq_lock(sc, txq);
txtid->active = false;
ath_tx_flush_tid(sc, txtid);
@@ -1526,11 +1532,14 @@ void ath_tx_aggr_stop(struct ath_softc *sc, struct ieee80211_sta *sta, u16 tid)
void ath_tx_aggr_sleep(struct ieee80211_sta *sta, struct ath_softc *sc,
struct ath_node *an)
{
+ struct ath_common *common = ath9k_hw_common(sc->sc_ah);
struct ath_atx_tid *tid;
struct ath_txq *txq;
bool buffered;
int tidno;
+ ath_dbg(common, XMIT, "%s called\n", __func__);
+
for (tidno = 0, tid = &an->tid[tidno];
tidno < IEEE80211_NUM_TIDS; tidno++, tid++) {
@@ -1555,10 +1564,13 @@ void ath_tx_aggr_sleep(struct ieee80211_sta *sta, struct ath_softc *sc,
void ath_tx_aggr_wakeup(struct ath_softc *sc, struct ath_node *an)
{
+ struct ath_common *common = ath9k_hw_common(sc->sc_ah);
struct ath_atx_tid *tid;
struct ath_txq *txq;
int tidno;
+ ath_dbg(common, XMIT, "%s called\n", __func__);
+
for (tidno = 0, tid = &an->tid[tidno];
tidno < IEEE80211_NUM_TIDS; tidno++, tid++) {
@@ -1579,10 +1591,13 @@ void ath_tx_aggr_wakeup(struct ath_softc *sc, struct ath_node *an)
void ath_tx_aggr_resume(struct ath_softc *sc, struct ieee80211_sta *sta,
u16 tidno)
{
+ struct ath_common *common = ath9k_hw_common(sc->sc_ah);
struct ath_atx_tid *tid;
struct ath_node *an;
struct ath_txq *txq;
+ ath_dbg(common, XMIT, "%s called\n", __func__);
+
an = (struct ath_node *)sta->drv_priv;
tid = ATH_AN_2_TID(an, tidno);
txq = tid->txq;
@@ -2316,6 +2331,12 @@ int ath_tx_start(struct ieee80211_hw *hw, struct sk_buff *skb,
queue = ieee80211_is_data_present(hdr->frame_control);
+ /* If chanctx, queue all null frames while NOA could be there */
+ if (ath9k_is_chanctx_enabled() &&
+ ieee80211_is_nullfunc(hdr->frame_control) &&
+ !txctl->force_channel)
+ queue = true;
+
/* Force queueing of all frames that belong to a virtual interface on
* a different channel context, to ensure that they are sent on the
* correct channel.
@@ -2894,7 +2915,7 @@ int ath9k_tx99_send(struct ath_softc *sc, struct sk_buff *skb,
if (skb_headroom(skb) < padsize) {
ath_dbg(common, XMIT,
"tx99 padding failed\n");
- return -EINVAL;
+ return -EINVAL;
}
skb_push(skb, padsize);
diff --git a/drivers/net/wireless/ath/wcn36xx/dxe.c b/drivers/net/wireless/ath/wcn36xx/dxe.c
index f8dfa05b290a..8643801f31b6 100644
--- a/drivers/net/wireless/ath/wcn36xx/dxe.c
+++ b/drivers/net/wireless/ath/wcn36xx/dxe.c
@@ -474,36 +474,37 @@ static int wcn36xx_rx_handle_packets(struct wcn36xx *wcn,
struct wcn36xx_dxe_desc *dxe = ctl->desc;
dma_addr_t dma_addr;
struct sk_buff *skb;
+ int ret = 0, int_mask;
+ u32 value;
+
+ if (ch->ch_type == WCN36XX_DXE_CH_RX_L) {
+ value = WCN36XX_DXE_CTRL_RX_L;
+ int_mask = WCN36XX_DXE_INT_CH1_MASK;
+ } else {
+ value = WCN36XX_DXE_CTRL_RX_H;
+ int_mask = WCN36XX_DXE_INT_CH3_MASK;
+ }
while (!(dxe->ctrl & WCN36XX_DXE_CTRL_VALID_MASK)) {
skb = ctl->skb;
dma_addr = dxe->dst_addr_l;
- wcn36xx_dxe_fill_skb(wcn->dev, ctl);
-
- switch (ch->ch_type) {
- case WCN36XX_DXE_CH_RX_L:
- dxe->ctrl = WCN36XX_DXE_CTRL_RX_L;
- wcn36xx_dxe_write_register(wcn, WCN36XX_DXE_ENCH_ADDR,
- WCN36XX_DXE_INT_CH1_MASK);
- break;
- case WCN36XX_DXE_CH_RX_H:
- dxe->ctrl = WCN36XX_DXE_CTRL_RX_H;
- wcn36xx_dxe_write_register(wcn, WCN36XX_DXE_ENCH_ADDR,
- WCN36XX_DXE_INT_CH3_MASK);
- break;
- default:
- wcn36xx_warn("Unknown channel\n");
- }
-
- dma_unmap_single(wcn->dev, dma_addr, WCN36XX_PKT_SIZE,
- DMA_FROM_DEVICE);
- wcn36xx_rx_skb(wcn, skb);
+ ret = wcn36xx_dxe_fill_skb(wcn->dev, ctl);
+ if (0 == ret) {
+ /* new skb allocation ok. Use the new one and queue
+ * the old one to network system.
+ */
+ dma_unmap_single(wcn->dev, dma_addr, WCN36XX_PKT_SIZE,
+ DMA_FROM_DEVICE);
+ wcn36xx_rx_skb(wcn, skb);
+ } /* else keep old skb not submitted and use it for rx DMA */
+
+ dxe->ctrl = value;
ctl = ctl->next;
dxe = ctl->desc;
}
+ wcn36xx_dxe_write_register(wcn, WCN36XX_DXE_ENCH_ADDR, int_mask);
ch->head_blk_ctl = ctl;
-
return 0;
}
diff --git a/drivers/net/wireless/ath/wcn36xx/hal.h b/drivers/net/wireless/ath/wcn36xx/hal.h
index a1f1127d7808..b947de0fb2e5 100644
--- a/drivers/net/wireless/ath/wcn36xx/hal.h
+++ b/drivers/net/wireless/ath/wcn36xx/hal.h
@@ -345,6 +345,8 @@ enum wcn36xx_hal_host_msg_type {
WCN36XX_HAL_DHCP_START_IND = 189,
WCN36XX_HAL_DHCP_STOP_IND = 190,
+ WCN36XX_HAL_AVOID_FREQ_RANGE_IND = 233,
+
WCN36XX_HAL_MSG_MAX = WCN36XX_HAL_MSG_TYPE_MAX_ENUM_SIZE
};
diff --git a/drivers/net/wireless/ath/wcn36xx/smd.c b/drivers/net/wireless/ath/wcn36xx/smd.c
index c9263e1c75d4..74f56a81ad9a 100644
--- a/drivers/net/wireless/ath/wcn36xx/smd.c
+++ b/drivers/net/wireless/ath/wcn36xx/smd.c
@@ -302,6 +302,22 @@ static int wcn36xx_smd_rsp_status_check(void *buf, size_t len)
return 0;
}
+static int wcn36xx_smd_rsp_status_check_v2(struct wcn36xx *wcn, void *buf,
+ size_t len)
+{
+ struct wcn36xx_fw_msg_status_rsp_v2 *rsp;
+
+ if (len < sizeof(struct wcn36xx_hal_msg_header) + sizeof(*rsp))
+ return wcn36xx_smd_rsp_status_check(buf, len);
+
+ rsp = buf + sizeof(struct wcn36xx_hal_msg_header);
+
+ if (WCN36XX_FW_MSG_RESULT_SUCCESS != rsp->status)
+ return rsp->status;
+
+ return 0;
+}
+
int wcn36xx_smd_load_nv(struct wcn36xx *wcn)
{
struct nv_data *nv_d;
@@ -1582,7 +1598,8 @@ int wcn36xx_smd_remove_bsskey(struct wcn36xx *wcn,
wcn36xx_err("Sending hal_remove_bsskey failed\n");
goto out;
}
- ret = wcn36xx_smd_rsp_status_check(wcn->hal_buf, wcn->hal_rsp_len);
+ ret = wcn36xx_smd_rsp_status_check_v2(wcn, wcn->hal_buf,
+ wcn->hal_rsp_len);
if (ret) {
wcn36xx_err("hal_remove_bsskey response failed err=%d\n", ret);
goto out;
@@ -1951,7 +1968,8 @@ int wcn36xx_smd_trigger_ba(struct wcn36xx *wcn, u8 sta_index)
wcn36xx_err("Sending hal_trigger_ba failed\n");
goto out;
}
- ret = wcn36xx_smd_rsp_status_check(wcn->hal_buf, wcn->hal_rsp_len);
+ ret = wcn36xx_smd_rsp_status_check_v2(wcn, wcn->hal_buf,
+ wcn->hal_rsp_len);
if (ret) {
wcn36xx_err("hal_trigger_ba response failed err=%d\n", ret);
goto out;
@@ -2128,6 +2146,8 @@ static void wcn36xx_smd_rsp_process(struct wcn36xx *wcn, void *buf, size_t len)
complete(&wcn->hal_rsp_compl);
break;
+ case WCN36XX_HAL_COEX_IND:
+ case WCN36XX_HAL_AVOID_FREQ_RANGE_IND:
case WCN36XX_HAL_OTA_TX_COMPL_IND:
case WCN36XX_HAL_MISSED_BEACON_IND:
case WCN36XX_HAL_DELETE_STA_CONTEXT_IND:
@@ -2174,6 +2194,9 @@ static void wcn36xx_ind_smd_work(struct work_struct *work)
msg_header = (struct wcn36xx_hal_msg_header *)hal_ind_msg->msg;
switch (msg_header->msg_type) {
+ case WCN36XX_HAL_COEX_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,
diff --git a/drivers/net/wireless/ath/wcn36xx/smd.h b/drivers/net/wireless/ath/wcn36xx/smd.h
index 008d03423dbf..8361f9e3995b 100644
--- a/drivers/net/wireless/ath/wcn36xx/smd.h
+++ b/drivers/net/wireless/ath/wcn36xx/smd.h
@@ -44,6 +44,15 @@ struct wcn36xx_fw_msg_status_rsp {
u32 status;
} __packed;
+/* wcn3620 returns this for tigger_ba */
+
+struct wcn36xx_fw_msg_status_rsp_v2 {
+ u8 bss_id[6];
+ u32 status __packed;
+ u16 count_following_candidates __packed;
+ /* candidate list follows */
+};
+
struct wcn36xx_hal_ind_msg {
struct list_head list;
u8 *msg;
diff --git a/drivers/net/wireless/ath/wil6210/interrupt.c b/drivers/net/wireless/ath/wil6210/interrupt.c
index 50c136e843c4..4f2ffa5c6e17 100644
--- a/drivers/net/wireless/ath/wil6210/interrupt.c
+++ b/drivers/net/wireless/ath/wil6210/interrupt.c
@@ -394,9 +394,13 @@ static irqreturn_t wil6210_irq_misc_thread(int irq, void *cookie)
wil_fw_core_dump(wil);
wil_notify_fw_error(wil);
isr &= ~ISR_MISC_FW_ERROR;
- wil_fw_error_recovery(wil);
+ if (wil->platform_ops.notify_crash) {
+ wil_err(wil, "notify platform driver about FW crash");
+ wil->platform_ops.notify_crash(wil->platform_handle);
+ } else {
+ wil_fw_error_recovery(wil);
+ }
}
-
if (isr & ISR_MISC_MBOX_EVT) {
wil_dbg_irq(wil, "MBOX event\n");
wmi_recv_cmd(wil);
diff --git a/drivers/net/wireless/ath/wil6210/main.c b/drivers/net/wireless/ath/wil6210/main.c
index bb69a5949aea..b39f0bfc591e 100644
--- a/drivers/net/wireless/ath/wil6210/main.c
+++ b/drivers/net/wireless/ath/wil6210/main.c
@@ -401,20 +401,26 @@ void wil_bcast_fini(struct wil6210_priv *wil)
static void wil_connect_worker(struct work_struct *work)
{
- int rc;
+ int rc, cid, ringid;
struct wil6210_priv *wil = container_of(work, struct wil6210_priv,
connect_worker);
struct net_device *ndev = wil_to_ndev(wil);
- int cid = wil->pending_connect_cid;
- int ringid = wil_find_free_vring(wil);
+ mutex_lock(&wil->mutex);
+ cid = wil->pending_connect_cid;
if (cid < 0) {
wil_err(wil, "No connection pending\n");
- return;
+ goto out;
+ }
+ ringid = wil_find_free_vring(wil);
+ if (ringid < 0) {
+ wil_err(wil, "No free vring found\n");
+ goto out;
}
- wil_dbg_wmi(wil, "Configure for connection CID %d\n", cid);
+ wil_dbg_wmi(wil, "Configure for connection CID %d vring %d\n",
+ cid, ringid);
rc = wil_vring_init_tx(wil, ringid, 1 << tx_ring_order, cid, 0);
wil->pending_connect_cid = -1;
@@ -424,6 +430,8 @@ static void wil_connect_worker(struct work_struct *work)
} else {
wil_disconnect_cid(wil, cid, WLAN_REASON_UNSPECIFIED, true);
}
+out:
+ mutex_unlock(&wil->mutex);
}
int wil_priv_init(struct wil6210_priv *wil)
@@ -773,8 +781,10 @@ int wil_reset(struct wil6210_priv *wil, bool load_fw)
wil6210_disconnect(wil, NULL, WLAN_REASON_DEAUTH_LEAVING, false);
wil_bcast_fini(wil);
- /* prevent NAPI from being scheduled */
+ /* prevent NAPI from being scheduled and prevent wmi commands */
+ mutex_lock(&wil->wmi_mutex);
bitmap_zero(wil->status, wil_status_last);
+ mutex_unlock(&wil->wmi_mutex);
if (wil->scan_request) {
wil_dbg_misc(wil, "Abort scan_request 0x%p\n",
@@ -977,7 +987,7 @@ int __wil_down(struct wil6210_priv *wil)
}
mutex_lock(&wil->mutex);
- if (!iter)
+ if (iter < 0)
wil_err(wil, "timeout waiting for idle FW/HW\n");
wil_reset(wil, false);
diff --git a/drivers/net/wireless/ath/wil6210/netdev.c b/drivers/net/wireless/ath/wil6210/netdev.c
index e3b3c8fb4605..56aaa2d4fb0e 100644
--- a/drivers/net/wireless/ath/wil6210/netdev.c
+++ b/drivers/net/wireless/ath/wil6210/netdev.c
@@ -183,7 +183,7 @@ void *wil_if_alloc(struct device *dev)
netif_napi_add(ndev, &wil->napi_rx, wil6210_netdev_poll_rx,
WIL6210_NAPI_BUDGET);
- netif_napi_add(ndev, &wil->napi_tx, wil6210_netdev_poll_tx,
+ netif_tx_napi_add(ndev, &wil->napi_tx, wil6210_netdev_poll_tx,
WIL6210_NAPI_BUDGET);
netif_tx_stop_all_queues(ndev);
diff --git a/drivers/net/wireless/ath/wil6210/pcie_bus.c b/drivers/net/wireless/ath/wil6210/pcie_bus.c
index 1a3142c332e1..e36f2a0c8cb6 100644
--- a/drivers/net/wireless/ath/wil6210/pcie_bus.c
+++ b/drivers/net/wireless/ath/wil6210/pcie_bus.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2012-2014 Qualcomm Atheros, Inc.
+ * Copyright (c) 2012-2015 Qualcomm Atheros, Inc.
*
* Permission to use, copy, modify, and/or distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
@@ -125,11 +125,37 @@ static int wil_if_pcie_disable(struct wil6210_priv *wil)
return 0;
}
+static int wil_platform_rop_ramdump(void *wil_handle, void *buf, uint32_t size)
+{
+ struct wil6210_priv *wil = wil_handle;
+
+ if (!wil)
+ return -EINVAL;
+
+ return wil_fw_copy_crash_dump(wil, buf, size);
+}
+
+static int wil_platform_rop_fw_recovery(void *wil_handle)
+{
+ struct wil6210_priv *wil = wil_handle;
+
+ if (!wil)
+ return -EINVAL;
+
+ wil_fw_error_recovery(wil);
+
+ return 0;
+}
+
static int wil_pcie_probe(struct pci_dev *pdev, const struct pci_device_id *id)
{
struct wil6210_priv *wil;
struct device *dev = &pdev->dev;
int rc;
+ const struct wil_platform_rops rops = {
+ .ramdump = wil_platform_rop_ramdump,
+ .fw_recovery = wil_platform_rop_fw_recovery,
+ };
/* check HW */
dev_info(&pdev->dev, WIL_NAME
@@ -154,7 +180,7 @@ static int wil_pcie_probe(struct pci_dev *pdev, const struct pci_device_id *id)
/* rollback to if_free */
wil->platform_handle =
- wil_platform_init(&pdev->dev, &wil->platform_ops);
+ wil_platform_init(&pdev->dev, &wil->platform_ops, &rops, wil);
if (!wil->platform_handle) {
rc = -ENODEV;
wil_err(wil, "wil_platform_init failed\n");
diff --git a/drivers/net/wireless/ath/wil6210/rx_reorder.c b/drivers/net/wireless/ath/wil6210/rx_reorder.c
index e3d1be82f314..32031e7a11d5 100644
--- a/drivers/net/wireless/ath/wil6210/rx_reorder.c
+++ b/drivers/net/wireless/ath/wil6210/rx_reorder.c
@@ -261,9 +261,19 @@ struct wil_tid_ampdu_rx *wil_tid_ampdu_rx_alloc(struct wil6210_priv *wil,
void wil_tid_ampdu_rx_free(struct wil6210_priv *wil,
struct wil_tid_ampdu_rx *r)
{
+ int i;
+
if (!r)
return;
- wil_release_reorder_frames(wil, r, r->head_seq_num + r->buf_size);
+
+ /* Do not pass remaining frames to the network stack - it may be
+ * not expecting to get any more Rx. Rx from here may lead to
+ * kernel OOPS since some per-socket accounting info was already
+ * released.
+ */
+ for (i = 0; i < r->buf_size; i++)
+ kfree_skb(r->reorder_buf[i]);
+
kfree(r->reorder_buf);
kfree(r->reorder_time);
kfree(r);
diff --git a/drivers/net/wireless/ath/wil6210/txrx.c b/drivers/net/wireless/ath/wil6210/txrx.c
index 3bc9bc0efbac..7887e6cfd817 100644
--- a/drivers/net/wireless/ath/wil6210/txrx.c
+++ b/drivers/net/wireless/ath/wil6210/txrx.c
@@ -160,6 +160,7 @@ static void wil_vring_free(struct wil6210_priv *wil, struct vring *vring,
struct device *dev = wil_to_dev(wil);
size_t sz = vring->size * sizeof(vring->va[0]);
+ lockdep_assert_held(&wil->mutex);
if (tx) {
int vring_index = vring - wil->vring_tx;
@@ -749,6 +750,7 @@ int wil_vring_init_tx(struct wil6210_priv *wil, int id, int size,
wil_dbg_misc(wil, "%s() max_mpdu_size %d\n", __func__,
cmd.vring_cfg.tx_sw_ring.max_mpdu_size);
+ lockdep_assert_held(&wil->mutex);
if (vring->va) {
wil_err(wil, "Tx ring [%d] already allocated\n", id);
@@ -821,6 +823,7 @@ int wil_vring_init_bcast(struct wil6210_priv *wil, int id, int size)
wil_dbg_misc(wil, "%s() max_mpdu_size %d\n", __func__,
cmd.vring_cfg.tx_sw_ring.max_mpdu_size);
+ lockdep_assert_held(&wil->mutex);
if (vring->va) {
wil_err(wil, "Tx ring [%d] already allocated\n", id);
@@ -872,7 +875,7 @@ void wil_vring_fini_tx(struct wil6210_priv *wil, int id)
struct vring *vring = &wil->vring_tx[id];
struct vring_tx_data *txdata = &wil->vring_tx_data[id];
- WARN_ON(!mutex_is_locked(&wil->mutex));
+ lockdep_assert_held(&wil->mutex);
if (!vring->va)
return;
diff --git a/drivers/net/wireless/ath/wil6210/wil6210.h b/drivers/net/wireless/ath/wil6210/wil6210.h
index ade5f3b8274b..235e205ce2bc 100644
--- a/drivers/net/wireless/ath/wil6210/wil6210.h
+++ b/drivers/net/wireless/ath/wil6210/wil6210.h
@@ -828,6 +828,7 @@ int wil_can_suspend(struct wil6210_priv *wil, bool is_runtime);
int wil_suspend(struct wil6210_priv *wil, bool is_runtime);
int wil_resume(struct wil6210_priv *wil, bool is_runtime);
+int wil_fw_copy_crash_dump(struct wil6210_priv *wil, void *dest, u32 size);
void wil_fw_core_dump(struct wil6210_priv *wil);
#endif /* __WIL6210_H__ */
diff --git a/drivers/net/wireless/ath/wil6210/wil_crash_dump.c b/drivers/net/wireless/ath/wil6210/wil_crash_dump.c
index 7e70934990ae..b57d280946e0 100644
--- a/drivers/net/wireless/ath/wil6210/wil_crash_dump.c
+++ b/drivers/net/wireless/ath/wil6210/wil_crash_dump.c
@@ -51,8 +51,7 @@ static int wil_fw_get_crash_dump_bounds(struct wil6210_priv *wil,
return 0;
}
-static int wil_fw_copy_crash_dump(struct wil6210_priv *wil, void *dest,
- u32 size)
+int wil_fw_copy_crash_dump(struct wil6210_priv *wil, void *dest, u32 size)
{
int i;
const struct fw_map *map;
diff --git a/drivers/net/wireless/ath/wil6210/wil_platform.c b/drivers/net/wireless/ath/wil6210/wil_platform.c
index 2e831bf20117..4eed05bddb60 100644
--- a/drivers/net/wireless/ath/wil6210/wil_platform.c
+++ b/drivers/net/wireless/ath/wil6210/wil_platform.c
@@ -33,7 +33,8 @@ void wil_platform_modexit(void)
* It returns a handle which is used with the rest of the API
*
*/
-void *wil_platform_init(struct device *dev, struct wil_platform_ops *ops)
+void *wil_platform_init(struct device *dev, struct wil_platform_ops *ops,
+ const struct wil_platform_rops *rops, void *wil_handle)
{
void *handle = ops; /* to return some non-NULL for 'void' impl. */
diff --git a/drivers/net/wireless/ath/wil6210/wil_platform.h b/drivers/net/wireless/ath/wil6210/wil_platform.h
index d7fa19b7886d..9a949d910343 100644
--- a/drivers/net/wireless/ath/wil6210/wil_platform.h
+++ b/drivers/net/wireless/ath/wil6210/wil_platform.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2014 Qualcomm Atheros, Inc.
+ * Copyright (c) 2014-2015 Qualcomm Atheros, Inc.
*
* Permission to use, copy, modify, and/or distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
@@ -20,16 +20,48 @@
struct device;
/**
- * struct wil_platform_ops - wil platform module callbacks
+ * struct wil_platform_ops - wil platform module calls from this
+ * driver to platform driver
*/
struct wil_platform_ops {
int (*bus_request)(void *handle, uint32_t kbps /* KBytes/Sec */);
int (*suspend)(void *handle);
int (*resume)(void *handle);
void (*uninit)(void *handle);
+ int (*notify_crash)(void *handle);
};
-void *wil_platform_init(struct device *dev, struct wil_platform_ops *ops);
+/**
+ * struct wil_platform_rops - wil platform module callbacks from
+ * platform driver to this driver
+ * @ramdump: store a ramdump from the wil firmware. The platform
+ * driver may add additional data to the ramdump to
+ * generate the final crash dump.
+ * @fw_recovery: start a firmware recovery process. Called as
+ * part of a crash recovery process which may include other
+ * related platform subsystems.
+ */
+struct wil_platform_rops {
+ int (*ramdump)(void *wil_handle, void *buf, uint32_t size);
+ int (*fw_recovery)(void *wil_handle);
+};
+
+/**
+ * wil_platform_init - initialize the platform driver
+ *
+ * @dev - pointer to the wil6210 device
+ * @ops - structure with platform driver operations. Platform
+ * driver will fill this structure with function pointers.
+ * @rops - structure with callbacks from platform driver to
+ * this driver. The platform driver copies the structure to
+ * its own storage. Can be NULL if this driver does not
+ * support crash recovery.
+ * @wil_handle - context for this driver that will be passed
+ * when platform driver invokes one of the callbacks in
+ * rops. May be NULL if rops is NULL.
+ */
+void *wil_platform_init(struct device *dev, struct wil_platform_ops *ops,
+ const struct wil_platform_rops *rops, void *wil_handle);
int __init wil_platform_modinit(void);
void wil_platform_modexit(void);
diff --git a/drivers/net/wireless/ath/wil6210/wmi.c b/drivers/net/wireless/ath/wil6210/wmi.c
index 6ed26baca0e5..e3ea74cdd4aa 100644
--- a/drivers/net/wireless/ath/wil6210/wmi.c
+++ b/drivers/net/wireless/ath/wil6210/wmi.c
@@ -228,6 +228,10 @@ static int __wmi_send(struct wil6210_priv *wil, u16 cmdid, void *buf, u16 len)
wil_dbg_wmi(wil, "Head 0x%08x -> 0x%08x\n", r->head, next_head);
/* wait till FW finish with previous command */
for (retry = 5; retry > 0; retry--) {
+ if (!test_bit(wil_status_fwready, wil->status)) {
+ wil_err(wil, "WMI: cannot send command while FW not ready\n");
+ return -EAGAIN;
+ }
r->tail = wil_r(wil, RGF_MBOX +
offsetof(struct wil6210_mbox_ctl, tx.tail));
if (next_head != r->tail)