Commit f1b4b511 authored by Kalle Valo's avatar Kalle Valo

Merge ath-next from ath.git

Major changes:

ath10k

* support Manegement Frame Protection (MFP)
* add thermal throttling support for 10.4 firmware
* add support for pktlog in QCA99X0
* add debugfs file to enable Bluetooth coexistence feature
* use firmware's native mesh interface type instead of raw mode
parents b31fa550 9e100c4d
...@@ -2,6 +2,7 @@ config ATH10K ...@@ -2,6 +2,7 @@ config ATH10K
tristate "Atheros 802.11ac wireless cards support" tristate "Atheros 802.11ac wireless cards support"
depends on MAC80211 && HAS_DMA depends on MAC80211 && HAS_DMA
select ATH_COMMON select ATH_COMMON
select CRC32
---help--- ---help---
This module adds support for wireless adapters based on This module adds support for wireless adapters based on
Atheros IEEE 802.11ac family of chipsets. Atheros IEEE 802.11ac family of chipsets.
......
...@@ -58,6 +58,7 @@ static const struct ath10k_hw_params ath10k_hw_params_list[] = { ...@@ -58,6 +58,7 @@ static const struct ath10k_hw_params ath10k_hw_params_list[] = {
.otp_exe_param = 0, .otp_exe_param = 0,
.channel_counters_freq_hz = 88000, .channel_counters_freq_hz = 88000,
.max_probe_resp_desc_thres = 0, .max_probe_resp_desc_thres = 0,
.hw_4addr_pad = ATH10K_HW_4ADDR_PAD_AFTER,
.fw = { .fw = {
.dir = QCA988X_HW_2_0_FW_DIR, .dir = QCA988X_HW_2_0_FW_DIR,
.fw = QCA988X_HW_2_0_FW_FILE, .fw = QCA988X_HW_2_0_FW_FILE,
...@@ -75,6 +76,7 @@ static const struct ath10k_hw_params ath10k_hw_params_list[] = { ...@@ -75,6 +76,7 @@ static const struct ath10k_hw_params ath10k_hw_params_list[] = {
.otp_exe_param = 0, .otp_exe_param = 0,
.channel_counters_freq_hz = 88000, .channel_counters_freq_hz = 88000,
.max_probe_resp_desc_thres = 0, .max_probe_resp_desc_thres = 0,
.hw_4addr_pad = ATH10K_HW_4ADDR_PAD_AFTER,
.fw = { .fw = {
.dir = QCA6174_HW_2_1_FW_DIR, .dir = QCA6174_HW_2_1_FW_DIR,
.fw = QCA6174_HW_2_1_FW_FILE, .fw = QCA6174_HW_2_1_FW_FILE,
...@@ -92,6 +94,7 @@ static const struct ath10k_hw_params ath10k_hw_params_list[] = { ...@@ -92,6 +94,7 @@ static const struct ath10k_hw_params ath10k_hw_params_list[] = {
.otp_exe_param = 0, .otp_exe_param = 0,
.channel_counters_freq_hz = 88000, .channel_counters_freq_hz = 88000,
.max_probe_resp_desc_thres = 0, .max_probe_resp_desc_thres = 0,
.hw_4addr_pad = ATH10K_HW_4ADDR_PAD_AFTER,
.fw = { .fw = {
.dir = QCA6174_HW_3_0_FW_DIR, .dir = QCA6174_HW_3_0_FW_DIR,
.fw = QCA6174_HW_3_0_FW_FILE, .fw = QCA6174_HW_3_0_FW_FILE,
...@@ -109,6 +112,7 @@ static const struct ath10k_hw_params ath10k_hw_params_list[] = { ...@@ -109,6 +112,7 @@ static const struct ath10k_hw_params ath10k_hw_params_list[] = {
.otp_exe_param = 0, .otp_exe_param = 0,
.channel_counters_freq_hz = 88000, .channel_counters_freq_hz = 88000,
.max_probe_resp_desc_thres = 0, .max_probe_resp_desc_thres = 0,
.hw_4addr_pad = ATH10K_HW_4ADDR_PAD_AFTER,
.fw = { .fw = {
/* uses same binaries as hw3.0 */ /* uses same binaries as hw3.0 */
.dir = QCA6174_HW_3_0_FW_DIR, .dir = QCA6174_HW_3_0_FW_DIR,
...@@ -128,6 +132,7 @@ static const struct ath10k_hw_params ath10k_hw_params_list[] = { ...@@ -128,6 +132,7 @@ static const struct ath10k_hw_params ath10k_hw_params_list[] = {
.continuous_frag_desc = true, .continuous_frag_desc = true,
.channel_counters_freq_hz = 150000, .channel_counters_freq_hz = 150000,
.max_probe_resp_desc_thres = 24, .max_probe_resp_desc_thres = 24,
.hw_4addr_pad = ATH10K_HW_4ADDR_PAD_BEFORE,
.fw = { .fw = {
.dir = QCA99X0_HW_2_0_FW_DIR, .dir = QCA99X0_HW_2_0_FW_DIR,
.fw = QCA99X0_HW_2_0_FW_FILE, .fw = QCA99X0_HW_2_0_FW_FILE,
...@@ -167,6 +172,7 @@ static const char *const ath10k_core_fw_feature_str[] = { ...@@ -167,6 +172,7 @@ static const char *const ath10k_core_fw_feature_str[] = {
[ATH10K_FW_FEATURE_SUPPORTS_SKIP_CLOCK_INIT] = "skip-clock-init", [ATH10K_FW_FEATURE_SUPPORTS_SKIP_CLOCK_INIT] = "skip-clock-init",
[ATH10K_FW_FEATURE_RAW_MODE_SUPPORT] = "raw-mode", [ATH10K_FW_FEATURE_RAW_MODE_SUPPORT] = "raw-mode",
[ATH10K_FW_FEATURE_SUPPORTS_ADAPTIVE_CCA] = "adaptive-cca", [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, static unsigned int ath10k_core_get_fw_feature_str(char *buf,
...@@ -843,7 +849,7 @@ static int ath10k_core_fetch_board_data_api_n(struct ath10k *ar, ...@@ -843,7 +849,7 @@ static int ath10k_core_fetch_board_data_api_n(struct ath10k *ar,
if (!ar->board_data || !ar->board_len) { if (!ar->board_data || !ar->board_len) {
ath10k_err(ar, ath10k_err(ar,
"failed to fetch board data for %s from %s/%s\n", "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; ret = -ENODATA;
goto err; goto err;
} }
...@@ -1745,9 +1751,11 @@ static int ath10k_core_probe_fw(struct ath10k *ar) ...@@ -1745,9 +1751,11 @@ static int ath10k_core_probe_fw(struct ath10k *ar)
goto err_power_down; goto err_power_down;
} }
ath10k_debug_print_hwfw_info(ar);
ret = ath10k_core_get_board_id_from_otp(ar); ret = ath10k_core_get_board_id_from_otp(ar);
if (ret && ret != -EOPNOTSUPP) { 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); ret);
return ret; return ret;
} }
...@@ -1758,6 +1766,8 @@ static int ath10k_core_probe_fw(struct ath10k *ar) ...@@ -1758,6 +1766,8 @@ static int ath10k_core_probe_fw(struct ath10k *ar)
goto err_free_firmware_files; goto err_free_firmware_files;
} }
ath10k_debug_print_board_info(ar);
ret = ath10k_core_init_firmware_features(ar); ret = ath10k_core_init_firmware_features(ar);
if (ret) { if (ret) {
ath10k_err(ar, "fatal problem with firmware features: %d\n", ath10k_err(ar, "fatal problem with firmware features: %d\n",
...@@ -1780,7 +1790,7 @@ static int ath10k_core_probe_fw(struct ath10k *ar) ...@@ -1780,7 +1790,7 @@ static int ath10k_core_probe_fw(struct ath10k *ar)
goto err_unlock; goto err_unlock;
} }
ath10k_print_driver_info(ar); ath10k_debug_print_boot_info(ar);
ath10k_core_stop(ar); ath10k_core_stop(ar);
mutex_unlock(&ar->conf_mutex); mutex_unlock(&ar->conf_mutex);
......
...@@ -81,26 +81,20 @@ static inline const char *ath10k_bus_str(enum ath10k_bus bus) ...@@ -81,26 +81,20 @@ static inline const char *ath10k_bus_str(enum ath10k_bus bus)
return "unknown"; 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 { struct ath10k_skb_cb {
dma_addr_t paddr; dma_addr_t paddr;
u8 flags;
u8 eid; u8 eid;
u8 vdev_id; u16 msdu_id;
enum ath10k_hw_txrx_mode txmode; struct ieee80211_vif *vif;
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;
} __packed; } __packed;
struct ath10k_skb_rxcb { struct ath10k_skb_rxcb {
...@@ -151,6 +145,7 @@ struct ath10k_wmi { ...@@ -151,6 +145,7 @@ struct ath10k_wmi {
struct wmi_vdev_param_map *vdev_param; struct wmi_vdev_param_map *vdev_param;
struct wmi_pdev_param_map *pdev_param; struct wmi_pdev_param_map *pdev_param;
const struct wmi_ops *ops; const struct wmi_ops *ops;
const struct wmi_peer_flags_map *peer_flags;
u32 num_mem_chunks; u32 num_mem_chunks;
u32 rx_decap_mode; u32 rx_decap_mode;
...@@ -512,6 +507,9 @@ enum ath10k_fw_features { ...@@ -512,6 +507,9 @@ enum ath10k_fw_features {
/* Firmware Supports Adaptive CCA*/ /* Firmware Supports Adaptive CCA*/
ATH10K_FW_FEATURE_SUPPORTS_ADAPTIVE_CCA = 11, ATH10K_FW_FEATURE_SUPPORTS_ADAPTIVE_CCA = 11,
/* Firmware supports management frame protection */
ATH10K_FW_FEATURE_MFP_SUPPORT = 12,
/* keep last */ /* keep last */
ATH10K_FW_FEATURE_COUNT, ATH10K_FW_FEATURE_COUNT,
}; };
...@@ -534,6 +532,9 @@ enum ath10k_dev_flags { ...@@ -534,6 +532,9 @@ enum ath10k_dev_flags {
/* Disable HW crypto engine */ /* Disable HW crypto engine */
ATH10K_FLAG_HW_CRYPTO_DISABLED, ATH10K_FLAG_HW_CRYPTO_DISABLED,
/* Bluetooth coexistance enabled */
ATH10K_FLAG_BTCOEX,
}; };
enum ath10k_cal_mode { enum ath10k_cal_mode {
...@@ -661,6 +662,9 @@ struct ath10k { ...@@ -661,6 +662,9 @@ struct ath10k {
*/ */
u32 max_probe_resp_desc_thres; 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 { struct ath10k_hw_params_fw {
const char *dir; const char *dir;
const char *fw; const char *fw;
......
...@@ -19,6 +19,8 @@ ...@@ -19,6 +19,8 @@
#include <linux/debugfs.h> #include <linux/debugfs.h>
#include <linux/vmalloc.h> #include <linux/vmalloc.h>
#include <linux/utsname.h> #include <linux/utsname.h>
#include <linux/crc32.h>
#include <linux/firmware.h>
#include "core.h" #include "core.h"
#include "debug.h" #include "debug.h"
...@@ -122,28 +124,51 @@ void ath10k_info(struct ath10k *ar, const char *fmt, ...) ...@@ -122,28 +124,51 @@ void ath10k_info(struct ath10k *ar, const char *fmt, ...)
} }
EXPORT_SYMBOL(ath10k_info); 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 fw_features[128] = {};
char boardinfo[100];
ath10k_core_get_fw_features_str(ar, fw_features, sizeof(fw_features)); ath10k_core_get_fw_features_str(ar, fw_features, sizeof(fw_features));
if (ar->id.bmi_ids_valid) ath10k_info(ar, "%s target 0x%08x chip_id 0x%08x sub %04x:%04x",
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",
ar->hw_params.name, ar->hw_params.name,
ar->target_version, ar->target_version,
ar->chip_id, 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->hw->wiphy->fw_version,
ar->fw_api, 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, 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_major,
ar->htt.target_version_minor, ar->htt.target_version_minor,
ar->wmi.op_version, ar->wmi.op_version,
...@@ -151,14 +176,14 @@ void ath10k_print_driver_info(struct ath10k *ar) ...@@ -151,14 +176,14 @@ void ath10k_print_driver_info(struct ath10k *ar)
ath10k_cal_mode_str(ar->cal_mode), ath10k_cal_mode_str(ar->cal_mode),
ar->max_num_stations, ar->max_num_stations,
test_bit(ATH10K_FLAG_RAW_MODE, &ar->dev_flags), test_bit(ATH10K_FLAG_RAW_MODE, &ar->dev_flags),
!test_bit(ATH10K_FLAG_HW_CRYPTO_DISABLED, &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), void ath10k_print_driver_info(struct ath10k *ar)
config_enabled(CONFIG_ATH10K_DEBUGFS), {
config_enabled(CONFIG_ATH10K_TRACING), ath10k_debug_print_hwfw_info(ar);
config_enabled(CONFIG_ATH10K_DFS_CERTIFIED), ath10k_debug_print_board_info(ar);
config_enabled(CONFIG_NL80211_TESTMODE)); ath10k_debug_print_boot_info(ar);
} }
EXPORT_SYMBOL(ath10k_print_driver_info); EXPORT_SYMBOL(ath10k_print_driver_info);
...@@ -2074,6 +2099,121 @@ static const struct file_operations fops_quiet_period = { ...@@ -2074,6 +2099,121 @@ static const struct file_operations fops_quiet_period = {
.open = simple_open .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) int ath10k_debug_create(struct ath10k *ar)
{ {
ar->debug.fw_crash_data = vzalloc(sizeof(*ar->debug.fw_crash_data)); ar->debug.fw_crash_data = vzalloc(sizeof(*ar->debug.fw_crash_data));
...@@ -2123,8 +2263,8 @@ int ath10k_debug_register(struct ath10k *ar) ...@@ -2123,8 +2263,8 @@ int ath10k_debug_register(struct ath10k *ar)
debugfs_create_file("wmi_services", S_IRUSR, ar->debug.debugfs_phy, ar, debugfs_create_file("wmi_services", S_IRUSR, ar->debug.debugfs_phy, ar,
&fops_wmi_services); &fops_wmi_services);
debugfs_create_file("simulate_fw_crash", S_IRUSR, ar->debug.debugfs_phy, debugfs_create_file("simulate_fw_crash", S_IRUSR | S_IWUSR,
ar, &fops_simulate_fw_crash); ar->debug.debugfs_phy, ar, &fops_simulate_fw_crash);
debugfs_create_file("fw_crash_dump", S_IRUSR, ar->debug.debugfs_phy, debugfs_create_file("fw_crash_dump", S_IRUSR, ar->debug.debugfs_phy,
ar, &fops_fw_crash_dump); ar, &fops_fw_crash_dump);
...@@ -2141,15 +2281,15 @@ int ath10k_debug_register(struct ath10k *ar) ...@@ -2141,15 +2281,15 @@ int ath10k_debug_register(struct ath10k *ar)
debugfs_create_file("chip_id", S_IRUSR, ar->debug.debugfs_phy, debugfs_create_file("chip_id", S_IRUSR, ar->debug.debugfs_phy,
ar, &fops_chip_id); ar, &fops_chip_id);
debugfs_create_file("htt_stats_mask", S_IRUSR, ar->debug.debugfs_phy, debugfs_create_file("htt_stats_mask", S_IRUSR | S_IWUSR,
ar, &fops_htt_stats_mask); ar->debug.debugfs_phy, ar, &fops_htt_stats_mask);
debugfs_create_file("htt_max_amsdu_ampdu", S_IRUSR | S_IWUSR, debugfs_create_file("htt_max_amsdu_ampdu", S_IRUSR | S_IWUSR,
ar->debug.debugfs_phy, ar, ar->debug.debugfs_phy, ar,
&fops_htt_max_amsdu_ampdu); &fops_htt_max_amsdu_ampdu);
debugfs_create_file("fw_dbglog", S_IRUSR, ar->debug.debugfs_phy, debugfs_create_file("fw_dbglog", S_IRUSR | S_IWUSR,
ar, &fops_fw_dbglog); ar->debug.debugfs_phy, ar, &fops_fw_dbglog);
debugfs_create_file("cal_data", S_IRUSR, ar->debug.debugfs_phy, debugfs_create_file("cal_data", S_IRUSR, ar->debug.debugfs_phy,
ar, &fops_cal_data); ar, &fops_cal_data);
...@@ -2183,6 +2323,13 @@ int ath10k_debug_register(struct ath10k *ar) ...@@ -2183,6 +2323,13 @@ int ath10k_debug_register(struct ath10k *ar)
debugfs_create_file("tpc_stats", S_IRUSR, debugfs_create_file("tpc_stats", S_IRUSR,
ar->debug.debugfs_phy, ar, &fops_tpc_stats); 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; return 0;
} }
......
...@@ -63,6 +63,10 @@ extern unsigned int ath10k_debug_mask; ...@@ -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_info(struct ath10k *ar, const char *fmt, ...);
__printf(2, 3) void ath10k_err(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, ...); __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); void ath10k_print_driver_info(struct ath10k *ar);
#ifdef CONFIG_ATH10K_DEBUGFS #ifdef CONFIG_ATH10K_DEBUGFS
......
...@@ -166,8 +166,13 @@ struct htt_data_tx_desc { ...@@ -166,8 +166,13 @@ struct htt_data_tx_desc {
__le16 len; __le16 len;
__le16 id; __le16 id;
__le32 frags_paddr; __le32 frags_paddr;
union {
__le32 peerid;
struct {
__le16 peerid; __le16 peerid;
__le16 freq; __le16 freq;
} __packed offchan_tx;
} __packed;
u8 prefetch[0]; /* start of frame, for FW classification engine */ u8 prefetch[0]; /* start of frame, for FW classification engine */
} __packed; } __packed;
...@@ -1597,6 +1602,10 @@ void __ath10k_htt_tx_dec_pending(struct ath10k_htt *htt, bool limit_mgmt_desc); ...@@ -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); 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); 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_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 #endif
...@@ -536,7 +536,7 @@ int ath10k_htt_rx_alloc(struct ath10k_htt *htt) ...@@ -536,7 +536,7 @@ int ath10k_htt_rx_alloc(struct ath10k_htt *htt)
size = htt->rx_ring.size * sizeof(htt->rx_ring.paddrs_ring); 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) if (!vaddr)
goto err_dma_ring; goto err_dma_ring;
...@@ -545,7 +545,7 @@ int ath10k_htt_rx_alloc(struct ath10k_htt *htt) ...@@ -545,7 +545,7 @@ int ath10k_htt_rx_alloc(struct ath10k_htt *htt)
vaddr = dma_alloc_coherent(htt->ar->dev, vaddr = dma_alloc_coherent(htt->ar->dev,
sizeof(*htt->rx_ring.alloc_idx.vaddr), sizeof(*htt->rx_ring.alloc_idx.vaddr),
&paddr, GFP_DMA); &paddr, GFP_KERNEL);
if (!vaddr) if (!vaddr)
goto err_dma_idx; goto err_dma_idx;
...@@ -674,7 +674,7 @@ static void ath10k_htt_rx_h_rates(struct ath10k *ar, ...@@ -674,7 +674,7 @@ static void ath10k_htt_rx_h_rates(struct ath10k *ar,
rate &= ~RX_PPDU_START_RATE_FLAG; rate &= ~RX_PPDU_START_RATE_FLAG;
sband = &ar->mac.sbands[status->band]; 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; break;
case HTT_RX_HT: case HTT_RX_HT:
case HTT_RX_HT_WITH_TXBF: case HTT_RX_HT_WITH_TXBF:
...@@ -1114,7 +1114,20 @@ static void ath10k_htt_rx_h_undecap_nwifi(struct ath10k *ar, ...@@ -1114,7 +1114,20 @@ static void ath10k_htt_rx_h_undecap_nwifi(struct ath10k *ar,
*/ */
/* pull decapped header and copy SA & DA */ /* 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); hdr_len = ath10k_htt_rx_nwifi_hdrlen(ar, hdr);
ether_addr_copy(da, ieee80211_get_DA(hdr)); ether_addr_copy(da, ieee80211_get_DA(hdr));
ether_addr_copy(sa, ieee80211_get_SA(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) ...@@ -2127,6 +2140,18 @@ void ath10k_htt_t2h_msg_handler(struct ath10k *ar, struct sk_buff *skb)
} }
EXPORT_SYMBOL(ath10k_htt_t2h_msg_handler); 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) static void ath10k_htt_txrx_compl_task(unsigned long ptr)
{ {
struct ath10k_htt *htt = (struct ath10k_htt *)ptr; struct ath10k_htt *htt = (struct ath10k_htt *)ptr;
......
...@@ -111,7 +111,7 @@ int ath10k_htt_tx_alloc(struct ath10k_htt *htt) ...@@ -111,7 +111,7 @@ int ath10k_htt_tx_alloc(struct ath10k_htt *htt)
size = htt->max_num_pending_tx * sizeof(struct ath10k_htt_txbuf); size = htt->max_num_pending_tx * sizeof(struct ath10k_htt_txbuf);
htt->txbuf.vaddr = dma_alloc_coherent(ar->dev, size, htt->txbuf.vaddr = dma_alloc_coherent(ar->dev, size,
&htt->txbuf.paddr, &htt->txbuf.paddr,
GFP_DMA); GFP_KERNEL);
if (!htt->txbuf.vaddr) { if (!htt->txbuf.vaddr) {
ath10k_err(ar, "failed to alloc tx buffer\n"); ath10k_err(ar, "failed to alloc tx buffer\n");
ret = -ENOMEM; ret = -ENOMEM;
...@@ -124,7 +124,7 @@ int ath10k_htt_tx_alloc(struct ath10k_htt *htt) ...@@ -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); 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.vaddr = dma_alloc_coherent(ar->dev, size,
&htt->frag_desc.paddr, &htt->frag_desc.paddr,
GFP_DMA); GFP_KERNEL);
if (!htt->frag_desc.vaddr) { if (!htt->frag_desc.vaddr) {
ath10k_warn(ar, "failed to alloc fragment desc memory\n"); ath10k_warn(ar, "failed to alloc fragment desc memory\n");
ret = -ENOMEM; ret = -ENOMEM;
...@@ -439,6 +439,35 @@ int ath10k_htt_h2t_aggr_cfg_msg(struct ath10k_htt *htt, ...@@ -439,6 +439,35 @@ int ath10k_htt_h2t_aggr_cfg_msg(struct ath10k_htt *htt,
return 0; 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) int ath10k_htt_mgmt_tx(struct ath10k_htt *htt, struct sk_buff *msdu)
{ {
struct ath10k *ar = htt->ar; struct ath10k *ar = htt->ar;
...@@ -446,7 +475,7 @@ int ath10k_htt_mgmt_tx(struct ath10k_htt *htt, struct sk_buff *msdu) ...@@ -446,7 +475,7 @@ int ath10k_htt_mgmt_tx(struct ath10k_htt *htt, struct sk_buff *msdu)
struct sk_buff *txdesc = NULL; struct sk_buff *txdesc = NULL;
struct htt_cmd *cmd; struct htt_cmd *cmd;
struct ath10k_skb_cb *skb_cb = ATH10K_SKB_CB(msdu); 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 len = 0;
int msdu_id = -1; int msdu_id = -1;
int res; int res;
...@@ -477,6 +506,13 @@ int ath10k_htt_mgmt_tx(struct ath10k_htt *htt, struct sk_buff *msdu) ...@@ -477,6 +506,13 @@ int ath10k_htt_mgmt_tx(struct ath10k_htt *htt, struct sk_buff *msdu)
msdu_id = res; 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); txdesc = ath10k_htc_alloc_skb(ar, len);
if (!txdesc) { if (!txdesc) {
res = -ENOMEM; res = -ENOMEM;
...@@ -503,8 +539,6 @@ int ath10k_htt_mgmt_tx(struct ath10k_htt *htt, struct sk_buff *msdu) ...@@ -503,8 +539,6 @@ int ath10k_htt_mgmt_tx(struct ath10k_htt *htt, struct sk_buff *msdu)
memcpy(cmd->mgmt_tx.hdr, msdu->data, memcpy(cmd->mgmt_tx.hdr, msdu->data,
min_t(int, msdu->len, HTT_MGMT_FRM_HDR_DOWNLOAD_LEN)); 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); res = ath10k_htc_send(&htt->ar->htc, htt->eid, txdesc);
if (res) if (res)
goto err_unmap_msdu; goto err_unmap_msdu;
...@@ -525,21 +559,27 @@ int ath10k_htt_mgmt_tx(struct ath10k_htt *htt, struct sk_buff *msdu) ...@@ -525,21 +559,27 @@ int ath10k_htt_mgmt_tx(struct ath10k_htt *htt, struct sk_buff *msdu)
return res; 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 ath10k *ar = htt->ar;
struct device *dev = ar->dev; struct device *dev = ar->dev;
struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)msdu->data; 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_skb_cb *skb_cb = ATH10K_SKB_CB(msdu);
struct ath10k_hif_sg_item sg_items[2]; struct ath10k_hif_sg_item sg_items[2];
struct ath10k_htt_txbuf *txbuf;
struct htt_data_tx_desc_frag *frags; struct htt_data_tx_desc_frag *frags;
u8 vdev_id = skb_cb->vdev_id; bool is_eth = (txmode == ATH10K_HW_TXRX_ETHERNET);
u8 tid = skb_cb->htt.tid; 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 prefetch_len;
int res; int res;
u8 flags0 = 0; u8 flags0 = 0;
u16 msdu_id, flags1 = 0; u16 msdu_id, flags1 = 0;
u16 freq = 0;
u32 frags_paddr = 0; u32 frags_paddr = 0;
u32 txbuf_paddr;
struct htt_msdu_ext_desc *ext_desc = NULL; struct htt_msdu_ext_desc *ext_desc = NULL;
bool limit_mgmt_desc = false; bool limit_mgmt_desc = false;
bool is_probe_resp = false; bool is_probe_resp = false;
...@@ -567,8 +607,8 @@ int ath10k_htt_tx(struct ath10k_htt *htt, struct sk_buff *msdu) ...@@ -567,8 +607,8 @@ int ath10k_htt_tx(struct ath10k_htt *htt, struct sk_buff *msdu)
prefetch_len = min(htt->prefetch_len, msdu->len); prefetch_len = min(htt->prefetch_len, msdu->len);
prefetch_len = roundup(prefetch_len, 4); prefetch_len = roundup(prefetch_len, 4);
skb_cb->htt.txbuf = &htt->txbuf.vaddr[msdu_id]; txbuf = &htt->txbuf.vaddr[msdu_id];
skb_cb->htt.txbuf_paddr = htt->txbuf.paddr + txbuf_paddr = htt->txbuf.paddr +
(sizeof(struct ath10k_htt_txbuf) * msdu_id); (sizeof(struct ath10k_htt_txbuf) * msdu_id);
if ((ieee80211_is_action(hdr->frame_control) || if ((ieee80211_is_action(hdr->frame_control) ||
...@@ -576,8 +616,8 @@ int ath10k_htt_tx(struct ath10k_htt *htt, struct sk_buff *msdu) ...@@ -576,8 +616,8 @@ int ath10k_htt_tx(struct ath10k_htt *htt, struct sk_buff *msdu)
ieee80211_is_disassoc(hdr->frame_control)) && ieee80211_is_disassoc(hdr->frame_control)) &&
ieee80211_has_protected(hdr->frame_control)) { ieee80211_has_protected(hdr->frame_control)) {
skb_put(msdu, IEEE80211_CCMP_MIC_LEN); skb_put(msdu, IEEE80211_CCMP_MIC_LEN);
} else if (!skb_cb->htt.nohwcrypt && } else if (!(skb_cb->flags & ATH10K_SKB_F_NO_HWCRYPT) &&
skb_cb->txmode == ATH10K_HW_TXRX_RAW && txmode == ATH10K_HW_TXRX_RAW &&
ieee80211_has_protected(hdr->frame_control)) { ieee80211_has_protected(hdr->frame_control)) {
skb_put(msdu, IEEE80211_CCMP_MIC_LEN); skb_put(msdu, IEEE80211_CCMP_MIC_LEN);
} }
...@@ -590,7 +630,10 @@ int ath10k_htt_tx(struct ath10k_htt *htt, struct sk_buff *msdu) ...@@ -590,7 +630,10 @@ int ath10k_htt_tx(struct ath10k_htt *htt, struct sk_buff *msdu)
goto err_free_msdu_id; 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_RAW:
case ATH10K_HW_TXRX_NATIVE_WIFI: case ATH10K_HW_TXRX_NATIVE_WIFI:
flags0 |= HTT_DATA_TX_DESC_FLAGS0_MAC_HDR_PRESENT; 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) ...@@ -610,16 +653,16 @@ int ath10k_htt_tx(struct ath10k_htt *htt, struct sk_buff *msdu)
frags_paddr = htt->frag_desc.paddr + frags_paddr = htt->frag_desc.paddr +
(sizeof(struct htt_msdu_ext_desc) * msdu_id); (sizeof(struct htt_msdu_ext_desc) * msdu_id);
} else { } else {
frags = skb_cb->htt.txbuf->frags; frags = txbuf->frags;
frags[0].dword_addr.paddr = frags[0].dword_addr.paddr =
__cpu_to_le32(skb_cb->paddr); __cpu_to_le32(skb_cb->paddr);
frags[0].dword_addr.len = __cpu_to_le32(msdu->len); frags[0].dword_addr.len = __cpu_to_le32(msdu->len);
frags[1].dword_addr.paddr = 0; frags[1].dword_addr.paddr = 0;
frags[1].dword_addr.len = 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; break;
case ATH10K_HW_TXRX_MGMT: case ATH10K_HW_TXRX_MGMT:
flags0 |= SM(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) ...@@ -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 * avoid extra memory allocations, compress data structures and thus
* improve performance. */ * improve performance. */
skb_cb->htt.txbuf->htc_hdr.eid = htt->eid; txbuf->htc_hdr.eid = htt->eid;
skb_cb->htt.txbuf->htc_hdr.len = __cpu_to_le16( txbuf->htc_hdr.len = __cpu_to_le16(sizeof(txbuf->cmd_hdr) +
sizeof(skb_cb->htt.txbuf->cmd_hdr) + sizeof(txbuf->cmd_tx) +
sizeof(skb_cb->htt.txbuf->cmd_tx) +
prefetch_len); prefetch_len);
skb_cb->htt.txbuf->htc_hdr.flags = 0; txbuf->htc_hdr.flags = 0;
if (skb_cb->htt.nohwcrypt)
flags0 |= HTT_DATA_TX_DESC_FLAGS0_NO_ENCRYPT;
if (!skb_cb->is_protected) if (skb_cb->flags & ATH10K_SKB_F_NO_HWCRYPT)
flags0 |= HTT_DATA_TX_DESC_FLAGS0_NO_ENCRYPT; flags0 |= HTT_DATA_TX_DESC_FLAGS0_NO_ENCRYPT;
flags1 |= SM((u16)vdev_id, HTT_DATA_TX_DESC_FLAGS1_VDEV_ID); 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) ...@@ -675,20 +714,27 @@ int ath10k_htt_tx(struct ath10k_htt *htt, struct sk_buff *msdu)
*/ */
flags1 |= HTT_DATA_TX_DESC_FLAGS1_POSTPONED; flags1 |= HTT_DATA_TX_DESC_FLAGS1_POSTPONED;
skb_cb->htt.txbuf->cmd_hdr.msg_type = HTT_H2T_MSG_TYPE_TX_FRM; txbuf->cmd_hdr.msg_type = HTT_H2T_MSG_TYPE_TX_FRM;
skb_cb->htt.txbuf->cmd_tx.flags0 = flags0; txbuf->cmd_tx.flags0 = flags0;
skb_cb->htt.txbuf->cmd_tx.flags1 = __cpu_to_le16(flags1); txbuf->cmd_tx.flags1 = __cpu_to_le16(flags1);
skb_cb->htt.txbuf->cmd_tx.len = __cpu_to_le16(msdu->len); txbuf->cmd_tx.len = __cpu_to_le16(msdu->len);
skb_cb->htt.txbuf->cmd_tx.id = __cpu_to_le16(msdu_id); txbuf->cmd_tx.id = __cpu_to_le16(msdu_id);
skb_cb->htt.txbuf->cmd_tx.frags_paddr = __cpu_to_le32(frags_paddr); txbuf->cmd_tx.frags_paddr = __cpu_to_le32(frags_paddr);
skb_cb->htt.txbuf->cmd_tx.peerid = __cpu_to_le16(HTT_INVALID_PEERID); if (ath10k_mac_tx_frm_has_freq(ar)) {
skb_cb->htt.txbuf->cmd_tx.freq = __cpu_to_le16(skb_cb->htt.freq); 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); trace_ath10k_htt_tx(ar, msdu_id, msdu->len, vdev_id, tid);
ath10k_dbg(ar, ATH10K_DBG_HTT, 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", "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, 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: ", ath10k_dbg_dump(ar, ATH10K_DBG_HTT_DUMP, NULL, "htt tx msdu: ",
msdu->data, msdu->len); msdu->data, msdu->len);
trace_ath10k_tx_hdr(ar, 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) ...@@ -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_id = 0;
sg_items[0].transfer_context = NULL; sg_items[0].transfer_context = NULL;
sg_items[0].vaddr = &skb_cb->htt.txbuf->htc_hdr; sg_items[0].vaddr = &txbuf->htc_hdr;
sg_items[0].paddr = skb_cb->htt.txbuf_paddr + sg_items[0].paddr = txbuf_paddr +
sizeof(skb_cb->htt.txbuf->frags); sizeof(txbuf->frags);
sg_items[0].len = sizeof(skb_cb->htt.txbuf->htc_hdr) + sg_items[0].len = sizeof(txbuf->htc_hdr) +
sizeof(skb_cb->htt.txbuf->cmd_hdr) + sizeof(txbuf->cmd_hdr) +
sizeof(skb_cb->htt.txbuf->cmd_tx); sizeof(txbuf->cmd_tx);
sg_items[1].transfer_id = 0; sg_items[1].transfer_id = 0;
sg_items[1].transfer_context = NULL; sg_items[1].transfer_context = NULL;
......
...@@ -273,6 +273,16 @@ struct ath10k_pktlog_hdr { ...@@ -273,6 +273,16 @@ struct ath10k_pktlog_hdr {
u8 payload[0]; u8 payload[0];
} __packed; } __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 { enum ath10k_hw_rate_ofdm {
ATH10K_HW_RATE_OFDM_48M = 0, ATH10K_HW_RATE_OFDM_48M = 0,
ATH10K_HW_RATE_OFDM_24M, ATH10K_HW_RATE_OFDM_24M,
...@@ -294,6 +304,11 @@ enum ath10k_hw_rate_cck { ...@@ -294,6 +304,11 @@ enum ath10k_hw_rate_cck {
ATH10K_HW_RATE_CCK_SP_2M, 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 */ /* Target specific defines for MAIN firmware */
#define TARGET_NUM_VDEVS 8 #define TARGET_NUM_VDEVS 8
#define TARGET_NUM_PEER_AST 2 #define TARGET_NUM_PEER_AST 2
......
...@@ -90,7 +90,7 @@ static u8 ath10k_mac_bitrate_to_rate(int bitrate) ...@@ -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 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; const struct ieee80211_rate *rate;
int i; int i;
...@@ -98,6 +98,9 @@ u8 ath10k_mac_hw_rate_to_idx(const struct ieee80211_supported_band *sband, ...@@ -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++) { for (i = 0; i < sband->n_bitrates; i++) {
rate = &sband->bitrates[i]; rate = &sband->bitrates[i];
if (ath10k_mac_bitrate_is_cck(rate->bitrate) != cck)
continue;
if (rate->hw_value == hw_rate) if (rate->hw_value == hw_rate)
return i; return i;
else if (rate->flags & IEEE80211_RATE_SHORT_PREAMBLE && else if (rate->flags & IEEE80211_RATE_SHORT_PREAMBLE &&
...@@ -1960,7 +1963,7 @@ static void ath10k_peer_assoc_h_basic(struct ath10k *ar, ...@@ -1960,7 +1963,7 @@ static void ath10k_peer_assoc_h_basic(struct ath10k *ar,
ether_addr_copy(arg->addr, sta->addr); ether_addr_copy(arg->addr, sta->addr);
arg->vdev_id = arvif->vdev_id; arg->vdev_id = arvif->vdev_id;
arg->peer_aid = aid; 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_listen_intval = ath10k_peer_assoc_h_listen_intval(ar, vif);
arg->peer_num_spatial_streams = 1; arg->peer_num_spatial_streams = 1;
arg->peer_caps = vif->bss_conf.assoc_capability; arg->peer_caps = vif->bss_conf.assoc_capability;
...@@ -1968,6 +1971,7 @@ static void ath10k_peer_assoc_h_basic(struct ath10k *ar, ...@@ -1968,6 +1971,7 @@ static void ath10k_peer_assoc_h_basic(struct ath10k *ar,
static void ath10k_peer_assoc_h_crypto(struct ath10k *ar, static void ath10k_peer_assoc_h_crypto(struct ath10k *ar,
struct ieee80211_vif *vif, struct ieee80211_vif *vif,
struct ieee80211_sta *sta,
struct wmi_peer_assoc_complete_arg *arg) struct wmi_peer_assoc_complete_arg *arg)
{ {
struct ieee80211_bss_conf *info = &vif->bss_conf; struct ieee80211_bss_conf *info = &vif->bss_conf;
...@@ -2002,12 +2006,17 @@ static void ath10k_peer_assoc_h_crypto(struct ath10k *ar, ...@@ -2002,12 +2006,17 @@ static void ath10k_peer_assoc_h_crypto(struct ath10k *ar,
/* FIXME: base on RSN IE/WPA IE is a correct idea? */ /* FIXME: base on RSN IE/WPA IE is a correct idea? */
if (rsnie || wpaie) { if (rsnie || wpaie) {
ath10k_dbg(ar, ATH10K_DBG_WMI, "%s: rsn ie found\n", __func__); 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) { if (wpaie) {
ath10k_dbg(ar, ATH10K_DBG_WMI, "%s: wpa ie found\n", __func__); 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 +2113,7 @@ static void ath10k_peer_assoc_h_ht(struct ath10k *ar, ...@@ -2104,7 +2113,7 @@ static void ath10k_peer_assoc_h_ht(struct ath10k *ar,
ath10k_peer_assoc_h_vht_masked(vht_mcs_mask)) ath10k_peer_assoc_h_vht_masked(vht_mcs_mask))
return; 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 + arg->peer_max_mpdu = (1 << (IEEE80211_HT_MAX_AMPDU_FACTOR +
ht_cap->ampdu_factor)) - 1; ht_cap->ampdu_factor)) - 1;
...@@ -2115,10 +2124,10 @@ static void ath10k_peer_assoc_h_ht(struct ath10k *ar, ...@@ -2115,10 +2124,10 @@ static void ath10k_peer_assoc_h_ht(struct ath10k *ar,
arg->peer_rate_caps |= WMI_RC_HT_FLAG; arg->peer_rate_caps |= WMI_RC_HT_FLAG;
if (ht_cap->cap & IEEE80211_HT_CAP_LDPC_CODING) 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) { 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; arg->peer_rate_caps |= WMI_RC_CW40_FLAG;
} }
...@@ -2132,7 +2141,7 @@ static void ath10k_peer_assoc_h_ht(struct ath10k *ar, ...@@ -2132,7 +2141,7 @@ static void ath10k_peer_assoc_h_ht(struct ath10k *ar,
if (ht_cap->cap & IEEE80211_HT_CAP_TX_STBC) { if (ht_cap->cap & IEEE80211_HT_CAP_TX_STBC) {
arg->peer_rate_caps |= WMI_RC_TX_STBC_FLAG; 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) { if (ht_cap->cap & IEEE80211_HT_CAP_RX_STBC) {
...@@ -2140,7 +2149,7 @@ static void ath10k_peer_assoc_h_ht(struct ath10k *ar, ...@@ -2140,7 +2149,7 @@ static void ath10k_peer_assoc_h_ht(struct ath10k *ar,
stbc = stbc >> IEEE80211_HT_CAP_RX_STBC_SHIFT; stbc = stbc >> IEEE80211_HT_CAP_RX_STBC_SHIFT;
stbc = stbc << WMI_RC_RX_STBC_FLAG_S; stbc = stbc << WMI_RC_RX_STBC_FLAG_S;
arg->peer_rate_caps |= stbc; 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]) if (ht_cap->mcs.rx_mask[1] && ht_cap->mcs.rx_mask[2])
...@@ -2321,10 +2330,10 @@ static void ath10k_peer_assoc_h_vht(struct ath10k *ar, ...@@ -2321,10 +2330,10 @@ static void ath10k_peer_assoc_h_vht(struct ath10k *ar,
if (ath10k_peer_assoc_h_vht_masked(vht_mcs_mask)) if (ath10k_peer_assoc_h_vht_masked(vht_mcs_mask))
return; return;
arg->peer_flags |= WMI_PEER_VHT; arg->peer_flags |= ar->wmi.peer_flags->vht;
if (def.chan->band == IEEE80211_BAND_2GHZ) 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; arg->peer_vht_caps = vht_cap->cap;
...@@ -2341,7 +2350,7 @@ static void ath10k_peer_assoc_h_vht(struct ath10k *ar, ...@@ -2341,7 +2350,7 @@ static void ath10k_peer_assoc_h_vht(struct ath10k *ar,
ampdu_factor)) - 1); ampdu_factor)) - 1);
if (sta->bandwidth == IEEE80211_STA_RX_BW_80) 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 = arg->peer_vht_rates.rx_max_rate =
__le16_to_cpu(vht_cap->vht_mcs.rx_highest); __le16_to_cpu(vht_cap->vht_mcs.rx_highest);
...@@ -2366,27 +2375,28 @@ static void ath10k_peer_assoc_h_qos(struct ath10k *ar, ...@@ -2366,27 +2375,28 @@ static void ath10k_peer_assoc_h_qos(struct ath10k *ar,
switch (arvif->vdev_type) { switch (arvif->vdev_type) {
case WMI_VDEV_TYPE_AP: case WMI_VDEV_TYPE_AP:
if (sta->wme) if (sta->wme)
arg->peer_flags |= WMI_PEER_QOS; arg->peer_flags |= arvif->ar->wmi.peer_flags->qos;
if (sta->wme && sta->uapsd_queues) { 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; arg->peer_rate_caps |= WMI_RC_UAPSD_FLAG;
} }
break; break;
case WMI_VDEV_TYPE_STA: case WMI_VDEV_TYPE_STA:
if (vif->bss_conf.qos) if (vif->bss_conf.qos)
arg->peer_flags |= WMI_PEER_QOS; arg->peer_flags |= arvif->ar->wmi.peer_flags->qos;
break; break;
case WMI_VDEV_TYPE_IBSS: case WMI_VDEV_TYPE_IBSS:
if (sta->wme) if (sta->wme)
arg->peer_flags |= WMI_PEER_QOS; arg->peer_flags |= arvif->ar->wmi.peer_flags->qos;
break; break;
default: default:
break; break;
} }
ath10k_dbg(ar, ATH10K_DBG_MAC, "mac peer %pM qos %d\n", 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) static bool ath10k_mac_sta_has_ofdm_only(struct ieee80211_sta *sta)
...@@ -2479,7 +2489,7 @@ static int ath10k_peer_assoc_prepare(struct ath10k *ar, ...@@ -2479,7 +2489,7 @@ static int ath10k_peer_assoc_prepare(struct ath10k *ar,
memset(arg, 0, sizeof(*arg)); memset(arg, 0, sizeof(*arg));
ath10k_peer_assoc_h_basic(ar, vif, sta, 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_rates(ar, vif, sta, arg);
ath10k_peer_assoc_h_ht(ar, vif, sta, arg); ath10k_peer_assoc_h_ht(ar, vif, sta, arg);
ath10k_peer_assoc_h_vht(ar, vif, sta, arg); ath10k_peer_assoc_h_vht(ar, vif, sta, arg);
...@@ -3112,35 +3122,11 @@ void ath10k_mac_handle_tx_pause_vdev(struct ath10k *ar, u32 vdev_id, ...@@ -3112,35 +3122,11 @@ void ath10k_mac_handle_tx_pause_vdev(struct ath10k *ar, u32 vdev_id,
spin_unlock_bh(&ar->htt.tx_lock); 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 static enum ath10k_hw_txrx_mode
ath10k_tx_h_get_txmode(struct ath10k *ar, struct ieee80211_vif *vif, ath10k_mac_tx_h_get_txmode(struct ath10k *ar,
struct ieee80211_sta *sta, struct sk_buff *skb) struct ieee80211_vif *vif,
struct ieee80211_sta *sta,
struct sk_buff *skb)
{ {
const struct ieee80211_hdr *hdr = (void *)skb->data; const struct ieee80211_hdr *hdr = (void *)skb->data;
__le16 fc = hdr->frame_control; __le16 fc = hdr->frame_control;
...@@ -3190,14 +3176,22 @@ ath10k_tx_h_get_txmode(struct ath10k *ar, struct ieee80211_vif *vif, ...@@ -3190,14 +3176,22 @@ ath10k_tx_h_get_txmode(struct ath10k *ar, struct ieee80211_vif *vif,
} }
static bool ath10k_tx_h_use_hwcrypto(struct ieee80211_vif *vif, static bool ath10k_tx_h_use_hwcrypto(struct ieee80211_vif *vif,
struct sk_buff *skb) { struct sk_buff *skb)
struct ieee80211_tx_info *info = IEEE80211_SKB_CB(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 | const u32 mask = IEEE80211_TX_INTFL_DONT_ENCRYPT |
IEEE80211_TX_CTL_INJECTED; IEEE80211_TX_CTL_INJECTED;
if (!ieee80211_has_protected(hdr->frame_control))
return false;
if ((info->flags & mask) == mask) if ((info->flags & mask) == mask)
return false; return false;
if (vif) if (vif)
return !ath10k_vif_to_arvif(vif)->nohwcrypt; return !ath10k_vif_to_arvif(vif)->nohwcrypt;
return true; return true;
} }
...@@ -3224,7 +3218,7 @@ static void ath10k_tx_h_nwifi(struct ieee80211_hw *hw, struct sk_buff *skb) ...@@ -3224,7 +3218,7 @@ static void ath10k_tx_h_nwifi(struct ieee80211_hw *hw, struct sk_buff *skb)
*/ */
hdr = (void *)skb->data; hdr = (void *)skb->data;
if (ieee80211_is_qos_nullfunc(hdr->frame_control)) 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); hdr->frame_control &= ~__cpu_to_le16(IEEE80211_STYPE_QOS_DATA);
} }
...@@ -3280,7 +3274,7 @@ static void ath10k_tx_h_add_p2p_noa_ie(struct ath10k *ar, ...@@ -3280,7 +3274,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 /* FIXME: Not really sure since when the behaviour changed. At some
* point new firmware stopped requiring creation of peer entries for * point new firmware stopped requiring creation of peer entries for
...@@ -3288,8 +3282,9 @@ static bool ath10k_mac_need_offchan_tx_work(struct ath10k *ar) ...@@ -3288,8 +3282,9 @@ static bool ath10k_mac_need_offchan_tx_work(struct ath10k *ar)
* tx credit replenishment and reliability). Assuming it's at least 3.4 * 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. * because that's when the `freq` was introduced to TX_FRM HTT command.
*/ */
return !(ar->htt.target_version_major >= 3 && return (ar->htt.target_version_major >= 3 &&
ar->htt.target_version_minor >= 4); 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) static int ath10k_mac_tx_wmi_mgmt(struct ath10k *ar, struct sk_buff *skb)
...@@ -3314,24 +3309,24 @@ static int ath10k_mac_tx_wmi_mgmt(struct ath10k *ar, struct sk_buff *skb) ...@@ -3314,24 +3309,24 @@ static int ath10k_mac_tx_wmi_mgmt(struct ath10k *ar, struct sk_buff *skb)
return ret; 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; struct ath10k_htt *htt = &ar->htt;
int ret = 0; int ret = 0;
switch (cb->txmode) { switch (txmode) {
case ATH10K_HW_TXRX_RAW: case ATH10K_HW_TXRX_RAW:
case ATH10K_HW_TXRX_NATIVE_WIFI: case ATH10K_HW_TXRX_NATIVE_WIFI:
case ATH10K_HW_TXRX_ETHERNET: case ATH10K_HW_TXRX_ETHERNET:
ret = ath10k_htt_tx(htt, skb); ret = ath10k_htt_tx(htt, txmode, skb);
break; break;
case ATH10K_HW_TXRX_MGMT: case ATH10K_HW_TXRX_MGMT:
if (test_bit(ATH10K_FW_FEATURE_HAS_WMI_MGMT_TX, if (test_bit(ATH10K_FW_FEATURE_HAS_WMI_MGMT_TX,
ar->fw_features)) ar->fw_features))
ret = ath10k_mac_tx_wmi_mgmt(ar, skb); ret = ath10k_mac_tx_wmi_mgmt(ar, skb);
else if (ar->htt.target_version_major >= 3) else if (ar->htt.target_version_major >= 3)
ret = ath10k_htt_tx(htt, skb); ret = ath10k_htt_tx(htt, txmode, skb);
else else
ret = ath10k_htt_mgmt_tx(htt, skb); ret = ath10k_htt_mgmt_tx(htt, skb);
break; break;
...@@ -3361,9 +3356,13 @@ void ath10k_offchan_tx_work(struct work_struct *work) ...@@ -3361,9 +3356,13 @@ void ath10k_offchan_tx_work(struct work_struct *work)
{ {
struct ath10k *ar = container_of(work, struct ath10k, offchan_tx_work); struct ath10k *ar = container_of(work, struct ath10k, offchan_tx_work);
struct ath10k_peer *peer; struct ath10k_peer *peer;
struct ath10k_vif *arvif;
struct ieee80211_hdr *hdr; struct ieee80211_hdr *hdr;
struct ieee80211_vif *vif;
struct ieee80211_sta *sta;
struct sk_buff *skb; struct sk_buff *skb;
const u8 *peer_addr; const u8 *peer_addr;
enum ath10k_hw_txrx_mode txmode;
int vdev_id; int vdev_id;
int ret; int ret;
unsigned long time_left; unsigned long time_left;
...@@ -3388,9 +3387,9 @@ void ath10k_offchan_tx_work(struct work_struct *work) ...@@ -3388,9 +3387,9 @@ void ath10k_offchan_tx_work(struct work_struct *work)
hdr = (struct ieee80211_hdr *)skb->data; hdr = (struct ieee80211_hdr *)skb->data;
peer_addr = ieee80211_get_DA(hdr); peer_addr = ieee80211_get_DA(hdr);
vdev_id = ATH10K_SKB_CB(skb)->vdev_id;
spin_lock_bh(&ar->data_lock); spin_lock_bh(&ar->data_lock);
vdev_id = ar->scan.vdev_id;
peer = ath10k_peer_find(ar, vdev_id, peer_addr); peer = ath10k_peer_find(ar, vdev_id, peer_addr);
spin_unlock_bh(&ar->data_lock); spin_unlock_bh(&ar->data_lock);
...@@ -3413,7 +3412,22 @@ void ath10k_offchan_tx_work(struct work_struct *work) ...@@ -3413,7 +3412,22 @@ void ath10k_offchan_tx_work(struct work_struct *work)
ar->offchan_tx_skb = skb; ar->offchan_tx_skb = skb;
spin_unlock_bh(&ar->data_lock); 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 = time_left =
wait_for_completion_timeout(&ar->offchan_tx_completed, 3 * HZ); wait_for_completion_timeout(&ar->offchan_tx_completed, 3 * HZ);
...@@ -3488,6 +3502,7 @@ void __ath10k_scan_finish(struct ath10k *ar) ...@@ -3488,6 +3502,7 @@ void __ath10k_scan_finish(struct ath10k *ar)
case ATH10K_SCAN_STARTING: case ATH10K_SCAN_STARTING:
ar->scan.state = ATH10K_SCAN_IDLE; ar->scan.state = ATH10K_SCAN_IDLE;
ar->scan_channel = NULL; ar->scan_channel = NULL;
ar->scan.roc_freq = 0;
ath10k_offchan_tx_purge(ar); ath10k_offchan_tx_purge(ar);
cancel_delayed_work(&ar->scan.timeout); cancel_delayed_work(&ar->scan.timeout);
complete_all(&ar->scan.completed); complete_all(&ar->scan.completed);
...@@ -3631,25 +3646,32 @@ static void ath10k_tx(struct ieee80211_hw *hw, ...@@ -3631,25 +3646,32 @@ static void ath10k_tx(struct ieee80211_hw *hw,
struct sk_buff *skb) struct sk_buff *skb)
{ {
struct ath10k *ar = hw->priv; 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_tx_info *info = IEEE80211_SKB_CB(skb);
struct ieee80211_vif *vif = info->control.vif; struct ieee80211_vif *vif = info->control.vif;
struct ieee80211_sta *sta = control->sta; struct ieee80211_sta *sta = control->sta;
struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data; 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 */ /* We should disable CCK RATE due to P2P */
if (info->flags & IEEE80211_TX_CTL_NO_CCK_RATE) if (info->flags & IEEE80211_TX_CTL_NO_CCK_RATE)
ath10k_dbg(ar, ATH10K_DBG_MAC, "IEEE80211_TX_CTL_NO_CCK_RATE\n"); ath10k_dbg(ar, ATH10K_DBG_MAC, "IEEE80211_TX_CTL_NO_CCK_RATE\n");
ATH10K_SKB_CB(skb)->htt.is_offchan = false; txmode = ath10k_mac_tx_h_get_txmode(ar, vif, sta, skb);
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);
switch (ATH10K_SKB_CB(skb)->txmode) { 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;
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_MGMT:
case ATH10K_HW_TXRX_NATIVE_WIFI: case ATH10K_HW_TXRX_NATIVE_WIFI:
ath10k_tx_h_nwifi(hw, skb); ath10k_tx_h_nwifi(hw, skb);
...@@ -3668,15 +3690,7 @@ static void ath10k_tx(struct ieee80211_hw *hw, ...@@ -3668,15 +3690,7 @@ static void ath10k_tx(struct ieee80211_hw *hw,
} }
if (info->flags & IEEE80211_TX_CTL_TX_OFFCHAN) { if (info->flags & IEEE80211_TX_CTL_TX_OFFCHAN) {
spin_lock_bh(&ar->data_lock); if (!ath10k_mac_tx_frm_has_freq(ar)) {
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;
ath10k_dbg(ar, ATH10K_DBG_MAC, "queued offchannel skb %p\n", ath10k_dbg(ar, ATH10K_DBG_MAC, "queued offchannel skb %p\n",
skb); skb);
...@@ -3686,7 +3700,7 @@ static void ath10k_tx(struct ieee80211_hw *hw, ...@@ -3686,7 +3700,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. */ /* Must not be called with conf_mutex held as workers can use that also. */
...@@ -4350,7 +4364,9 @@ static int ath10k_add_interface(struct ieee80211_hw *hw, ...@@ -4350,7 +4364,9 @@ static int ath10k_add_interface(struct ieee80211_hw *hw,
arvif->vdev_type = WMI_VDEV_TYPE_IBSS; arvif->vdev_type = WMI_VDEV_TYPE_IBSS;
break; break;
case NL80211_IFTYPE_MESH_POINT: 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; ret = -EINVAL;
ath10k_warn(ar, "must load driver with rawmode=1 to add mesh interfaces\n"); ath10k_warn(ar, "must load driver with rawmode=1 to add mesh interfaces\n");
goto err; goto err;
...@@ -6936,6 +6952,10 @@ static const struct ieee80211_iface_limit ath10k_10x_if_limits[] = { ...@@ -6936,6 +6952,10 @@ static const struct ieee80211_iface_limit ath10k_10x_if_limits[] = {
| BIT(NL80211_IFTYPE_MESH_POINT) | BIT(NL80211_IFTYPE_MESH_POINT)
#endif #endif
}, },
{
.max = 1,
.types = BIT(NL80211_IFTYPE_STATION)
},
}; };
static const struct ieee80211_iface_combination ath10k_if_comb[] = { static const struct ieee80211_iface_combination ath10k_if_comb[] = {
......
...@@ -66,7 +66,7 @@ void ath10k_mac_handle_tx_pause_vdev(struct ath10k *ar, u32 vdev_id, ...@@ -66,7 +66,7 @@ void ath10k_mac_handle_tx_pause_vdev(struct ath10k *ar, u32 vdev_id,
enum wmi_tlv_tx_pause_action action); enum wmi_tlv_tx_pause_action action);
u8 ath10k_mac_hw_rate_to_idx(const struct ieee80211_supported_band *sband, 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, u8 ath10k_mac_bitrate_to_idx(const struct ieee80211_supported_band *sband,
u32 bitrate); u32 bitrate);
...@@ -74,6 +74,7 @@ void ath10k_mac_tx_lock(struct ath10k *ar, int reason); ...@@ -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_tx_unlock(struct ath10k *ar, int reason);
void ath10k_mac_vif_tx_lock(struct ath10k_vif *arvif, 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); 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) static inline struct ath10k_vif *ath10k_vif_to_arvif(struct ieee80211_vif *vif)
{ {
......
...@@ -111,6 +111,7 @@ static void ath10k_pci_htc_tx_cb(struct ath10k_ce_pipe *ce_state); ...@@ -111,6 +111,7 @@ static void ath10k_pci_htc_tx_cb(struct ath10k_ce_pipe *ce_state);
static void ath10k_pci_htc_rx_cb(struct ath10k_ce_pipe *ce_state); 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_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_rx_cb(struct ath10k_ce_pipe *ce_state);
static void ath10k_pci_pktlog_rx_cb(struct ath10k_ce_pipe *ce_state);
static const struct ce_attr host_ce_config_wlan[] = { static const struct ce_attr host_ce_config_wlan[] = {
/* CE0: host->target HTC control and raw streams */ /* CE0: host->target HTC control and raw streams */
...@@ -189,6 +190,7 @@ static const struct ce_attr host_ce_config_wlan[] = { ...@@ -189,6 +190,7 @@ static const struct ce_attr host_ce_config_wlan[] = {
.src_nentries = 0, .src_nentries = 0,
.src_sz_max = 2048, .src_sz_max = 2048,
.dest_nentries = 128, .dest_nentries = 128,
.recv_cb = ath10k_pci_pktlog_rx_cb,
}, },
/* CE9 target autonomous qcache memcpy */ /* CE9 target autonomous qcache memcpy */
...@@ -1208,6 +1210,15 @@ static void ath10k_pci_htc_rx_cb(struct ath10k_ce_pipe *ce_state) ...@@ -1208,6 +1210,15 @@ static void ath10k_pci_htc_rx_cb(struct ath10k_ce_pipe *ce_state)
ath10k_pci_process_rx_cb(ce_state, ath10k_htc_rx_completion_handler); 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. */ /* 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) static void ath10k_pci_htt_tx_cb(struct ath10k_ce_pipe *ce_state)
{ {
......
...@@ -187,7 +187,7 @@ int ath10k_thermal_register(struct ath10k *ar) ...@@ -187,7 +187,7 @@ int ath10k_thermal_register(struct ath10k *ar)
/* Do not register hwmon device when temperature reading is not /* Do not register hwmon device when temperature reading is not
* supported by firmware * 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; return 0;
/* Avoid linking error on devm_hwmon_device_register_with_groups, I /* Avoid linking error on devm_hwmon_device_register_with_groups, I
......
...@@ -23,7 +23,12 @@ ...@@ -23,7 +23,12 @@
static void ath10k_report_offchan_tx(struct ath10k *ar, struct sk_buff *skb) 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; return;
/* If the original wait_for_completion() timed out before /* If the original wait_for_completion() timed out before
...@@ -52,8 +57,6 @@ void ath10k_txrx_tx_unref(struct ath10k_htt *htt, ...@@ -52,8 +57,6 @@ void ath10k_txrx_tx_unref(struct ath10k_htt *htt,
struct ieee80211_tx_info *info; struct ieee80211_tx_info *info;
struct ath10k_skb_cb *skb_cb; struct ath10k_skb_cb *skb_cb;
struct sk_buff *msdu; struct sk_buff *msdu;
struct ieee80211_hdr *hdr;
__le16 fc;
bool limit_mgmt_desc = false; bool limit_mgmt_desc = false;
ath10k_dbg(ar, ATH10K_DBG_HTT, ath10k_dbg(ar, ATH10K_DBG_HTT,
...@@ -76,10 +79,9 @@ void ath10k_txrx_tx_unref(struct ath10k_htt *htt, ...@@ -76,10 +79,9 @@ void ath10k_txrx_tx_unref(struct ath10k_htt *htt,
return; return;
} }
hdr = (struct ieee80211_hdr *)msdu->data; skb_cb = ATH10K_SKB_CB(msdu);
fc = hdr->frame_control;
if (unlikely(ieee80211_is_mgmt(fc)) && if (unlikely(skb_cb->flags & ATH10K_SKB_F_MGMT) &&
ar->hw_params.max_probe_resp_desc_thres) ar->hw_params.max_probe_resp_desc_thres)
limit_mgmt_desc = true; limit_mgmt_desc = true;
...@@ -89,7 +91,6 @@ void ath10k_txrx_tx_unref(struct ath10k_htt *htt, ...@@ -89,7 +91,6 @@ void ath10k_txrx_tx_unref(struct ath10k_htt *htt,
wake_up(&htt->empty_tx_wq); wake_up(&htt->empty_tx_wq);
spin_unlock_bh(&htt->tx_lock); spin_unlock_bh(&htt->tx_lock);
skb_cb = ATH10K_SKB_CB(msdu);
dma_unmap_single(dev, skb_cb->paddr, msdu->len, DMA_TO_DEVICE); dma_unmap_single(dev, skb_cb->paddr, msdu->len, DMA_TO_DEVICE);
ath10k_report_offchan_tx(htt->ar, msdu); ath10k_report_offchan_tx(htt->ar, msdu);
......
...@@ -3485,6 +3485,24 @@ static const struct wmi_ops wmi_tlv_ops = { ...@@ -3485,6 +3485,24 @@ static const struct wmi_ops wmi_tlv_ops = {
.fw_stats_fill = ath10k_wmi_main_op_fw_stats_fill, .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 */ /* TLV init */
/************/ /************/
...@@ -3495,4 +3513,5 @@ void ath10k_wmi_tlv_attach(struct ath10k *ar) ...@@ -3495,4 +3513,5 @@ void ath10k_wmi_tlv_attach(struct ath10k *ar)
ar->wmi.vdev_param = &wmi_tlv_vdev_param_map; ar->wmi.vdev_param = &wmi_tlv_vdev_param_map;
ar->wmi.pdev_param = &wmi_tlv_pdev_param_map; ar->wmi.pdev_param = &wmi_tlv_pdev_param_map;
ar->wmi.ops = &wmi_tlv_ops; ar->wmi.ops = &wmi_tlv_ops;
ar->wmi.peer_flags = &wmi_tlv_peer_flags_map;
} }
...@@ -527,6 +527,24 @@ enum wmi_tlv_vdev_param { ...@@ -527,6 +527,24 @@ enum wmi_tlv_vdev_param {
WMI_TLV_VDEV_PARAM_IBSS_PS_1RX_CHAIN_IN_ATIM_WINDOW_ENABLE, 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 { enum wmi_tlv_tag {
WMI_TLV_TAG_LAST_RESERVED = 15, WMI_TLV_TAG_LAST_RESERVED = 15,
......
...@@ -1546,6 +1546,61 @@ static struct wmi_pdev_param_map wmi_10_4_pdev_param_map = { ...@@ -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, .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, void ath10k_wmi_put_wmi_channel(struct wmi_channel *ch,
const struct wmi_channel_arg *arg) const struct wmi_channel_arg *arg)
{ {
...@@ -1660,6 +1715,8 @@ static void ath10k_wmi_tx_beacon_nowait(struct ath10k_vif *arvif) ...@@ -1660,6 +1715,8 @@ static void ath10k_wmi_tx_beacon_nowait(struct ath10k_vif *arvif)
struct ath10k *ar = arvif->ar; struct ath10k *ar = arvif->ar;
struct ath10k_skb_cb *cb; struct ath10k_skb_cb *cb;
struct sk_buff *bcn; struct sk_buff *bcn;
bool dtim_zero;
bool deliver_cab;
int ret; int ret;
spin_lock_bh(&ar->data_lock); spin_lock_bh(&ar->data_lock);
...@@ -1679,12 +1736,14 @@ static void ath10k_wmi_tx_beacon_nowait(struct ath10k_vif *arvif) ...@@ -1679,12 +1736,14 @@ static void ath10k_wmi_tx_beacon_nowait(struct ath10k_vif *arvif)
arvif->beacon_state = ATH10K_BEACON_SENDING; arvif->beacon_state = ATH10K_BEACON_SENDING;
spin_unlock_bh(&ar->data_lock); 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, ret = ath10k_wmi_beacon_send_ref_nowait(arvif->ar,
arvif->vdev_id, arvif->vdev_id,
bcn->data, bcn->len, bcn->data, bcn->len,
cb->paddr, cb->paddr,
cb->bcn.dtim_zero, dtim_zero,
cb->bcn.deliver_cab); deliver_cab);
spin_lock_bh(&ar->data_lock); 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) ...@@ -1755,16 +1814,24 @@ int ath10k_wmi_cmd_send(struct ath10k *ar, struct sk_buff *skb, u32 cmd_id)
static struct sk_buff * static struct sk_buff *
ath10k_wmi_op_gen_mgmt_tx(struct ath10k *ar, struct sk_buff *msdu) 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 wmi_mgmt_tx_cmd *cmd;
struct ieee80211_hdr *hdr; struct ieee80211_hdr *hdr;
struct sk_buff *skb; struct sk_buff *skb;
int len; int len;
u32 vdev_id;
u32 buf_len = msdu->len; u32 buf_len = msdu->len;
u16 fc; u16 fc;
hdr = (struct ieee80211_hdr *)msdu->data; hdr = (struct ieee80211_hdr *)msdu->data;
fc = le16_to_cpu(hdr->frame_control); 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))) if (WARN_ON_ONCE(!ieee80211_is_mgmt(hdr->frame_control)))
return ERR_PTR(-EINVAL); return ERR_PTR(-EINVAL);
...@@ -1786,7 +1853,7 @@ ath10k_wmi_op_gen_mgmt_tx(struct ath10k *ar, struct sk_buff *msdu) ...@@ -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 = (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_rate = 0;
cmd->hdr.tx_power = 0; cmd->hdr.tx_power = 0;
cmd->hdr.buf_len = __cpu_to_le32(buf_len); 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) ...@@ -2204,22 +2271,9 @@ int ath10k_wmi_event_mgmt_rx(struct ath10k *ar, struct sk_buff *skb)
ath10k_dbg(ar, ATH10K_DBG_MGMT, ath10k_dbg(ar, ATH10K_DBG_MGMT,
"event mgmt rx status %08x\n", rx_status); "event mgmt rx status %08x\n", rx_status);
if (test_bit(ATH10K_CAC_RUNNING, &ar->dev_flags)) { if ((test_bit(ATH10K_CAC_RUNNING, &ar->dev_flags)) ||
dev_kfree_skb(skb); (rx_status & (WMI_RX_STATUS_ERR_DECRYPT |
return 0; WMI_RX_STATUS_ERR_KEY_CACHE_MISS | WMI_RX_STATUS_ERR_CRC))) {
}
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) {
dev_kfree_skb(skb); dev_kfree_skb(skb);
return 0; return 0;
} }
...@@ -3115,10 +3169,10 @@ static void ath10k_wmi_update_tim(struct ath10k *ar, ...@@ -3115,10 +3169,10 @@ static void ath10k_wmi_update_tim(struct ath10k *ar,
memcpy(tim->virtual_map, arvif->u.ap.tim_bitmap, pvm_len); memcpy(tim->virtual_map, arvif->u.ap.tim_bitmap, pvm_len);
if (tim->dtim_count == 0) { 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) 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", ath10k_dbg(ar, ATH10K_DBG_MGMT, "dtim %d/%d mcast %d pvmlen %d\n",
...@@ -5061,6 +5115,9 @@ static void ath10k_wmi_10_4_op_rx(struct ath10k *ar, struct sk_buff *skb) ...@@ -5061,6 +5115,9 @@ static void ath10k_wmi_10_4_op_rx(struct ath10k *ar, struct sk_buff *skb)
case WMI_10_4_UPDATE_STATS_EVENTID: case WMI_10_4_UPDATE_STATS_EVENTID:
ath10k_wmi_event_update_stats(ar, skb); ath10k_wmi_event_update_stats(ar, skb);
break; break;
case WMI_10_4_PDEV_TEMPERATURE_EVENTID:
ath10k_wmi_event_temperature(ar, skb);
break;
default: default:
ath10k_warn(ar, "Unknown eventid: %d\n", id); ath10k_warn(ar, "Unknown eventid: %d\n", id);
break; break;
...@@ -5431,8 +5488,11 @@ static struct sk_buff *ath10k_wmi_10_2_op_gen_init(struct ath10k *ar) ...@@ -5431,8 +5488,11 @@ static struct sk_buff *ath10k_wmi_10_2_op_gen_init(struct ath10k *ar)
cmd = (struct wmi_init_cmd_10_2 *)buf->data; cmd = (struct wmi_init_cmd_10_2 *)buf->data;
features = WMI_10_2_RX_BATCH_MODE; 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; features |= WMI_10_2_COEX_GPIO;
cmd->resource_config.feature_mask = __cpu_to_le32(features); cmd->resource_config.feature_mask = __cpu_to_le32(features);
memcpy(&cmd->resource_config.common, &config, sizeof(config)); memcpy(&cmd->resource_config.common, &config, sizeof(config));
...@@ -6328,6 +6388,16 @@ ath10k_wmi_peer_assoc_fill_10_2(struct ath10k *ar, void *buf, ...@@ -6328,6 +6388,16 @@ ath10k_wmi_peer_assoc_fill_10_2(struct ath10k *ar, void *buf,
cmd->info0 = __cpu_to_le32(info0); 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 static int
ath10k_wmi_peer_assoc_check_arg(const struct wmi_peer_assoc_complete_arg *arg) ath10k_wmi_peer_assoc_check_arg(const struct wmi_peer_assoc_complete_arg *arg)
{ {
...@@ -6416,6 +6486,31 @@ ath10k_wmi_10_2_op_gen_peer_assoc(struct ath10k *ar, ...@@ -6416,6 +6486,31 @@ ath10k_wmi_10_2_op_gen_peer_assoc(struct ath10k *ar,
return skb; return skb;
} }
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 * static struct sk_buff *
ath10k_wmi_10_2_op_gen_pdev_get_temperature(struct ath10k *ar) ath10k_wmi_10_2_op_gen_pdev_get_temperature(struct ath10k *ar)
{ {
...@@ -7536,6 +7631,7 @@ static const struct wmi_ops wmi_10_4_ops = { ...@@ -7536,6 +7631,7 @@ static const struct wmi_ops wmi_10_4_ops = {
.gen_peer_delete = ath10k_wmi_op_gen_peer_delete, .gen_peer_delete = ath10k_wmi_op_gen_peer_delete,
.gen_peer_flush = ath10k_wmi_op_gen_peer_flush, .gen_peer_flush = ath10k_wmi_op_gen_peer_flush,
.gen_peer_set_param = ath10k_wmi_op_gen_peer_set_param, .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_psmode = ath10k_wmi_op_gen_set_psmode,
.gen_set_sta_ps = ath10k_wmi_op_gen_set_sta_ps, .gen_set_sta_ps = ath10k_wmi_op_gen_set_sta_ps,
.gen_set_ap_ps = ath10k_wmi_op_gen_set_ap_ps, .gen_set_ap_ps = ath10k_wmi_op_gen_set_ap_ps,
...@@ -7555,8 +7651,8 @@ static const struct wmi_ops wmi_10_4_ops = { ...@@ -7555,8 +7651,8 @@ static const struct wmi_ops wmi_10_4_ops = {
.fw_stats_fill = ath10k_wmi_10_4_op_fw_stats_fill, .fw_stats_fill = ath10k_wmi_10_4_op_fw_stats_fill,
/* shared with 10.2 */ /* 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_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) int ath10k_wmi_attach(struct ath10k *ar)
...@@ -7567,30 +7663,35 @@ int ath10k_wmi_attach(struct ath10k *ar) ...@@ -7567,30 +7663,35 @@ int ath10k_wmi_attach(struct ath10k *ar)
ar->wmi.cmd = &wmi_10_4_cmd_map; ar->wmi.cmd = &wmi_10_4_cmd_map;
ar->wmi.vdev_param = &wmi_10_4_vdev_param_map; ar->wmi.vdev_param = &wmi_10_4_vdev_param_map;
ar->wmi.pdev_param = &wmi_10_4_pdev_param_map; ar->wmi.pdev_param = &wmi_10_4_pdev_param_map;
ar->wmi.peer_flags = &wmi_10_2_peer_flags_map;
break; break;
case ATH10K_FW_WMI_OP_VERSION_10_2_4: case ATH10K_FW_WMI_OP_VERSION_10_2_4:
ar->wmi.cmd = &wmi_10_2_4_cmd_map; ar->wmi.cmd = &wmi_10_2_4_cmd_map;
ar->wmi.ops = &wmi_10_2_4_ops; ar->wmi.ops = &wmi_10_2_4_ops;
ar->wmi.vdev_param = &wmi_10_2_4_vdev_param_map; ar->wmi.vdev_param = &wmi_10_2_4_vdev_param_map;
ar->wmi.pdev_param = &wmi_10_2_4_pdev_param_map; ar->wmi.pdev_param = &wmi_10_2_4_pdev_param_map;
ar->wmi.peer_flags = &wmi_10_2_peer_flags_map;
break; break;
case ATH10K_FW_WMI_OP_VERSION_10_2: case ATH10K_FW_WMI_OP_VERSION_10_2:
ar->wmi.cmd = &wmi_10_2_cmd_map; ar->wmi.cmd = &wmi_10_2_cmd_map;
ar->wmi.ops = &wmi_10_2_ops; ar->wmi.ops = &wmi_10_2_ops;
ar->wmi.vdev_param = &wmi_10x_vdev_param_map; ar->wmi.vdev_param = &wmi_10x_vdev_param_map;
ar->wmi.pdev_param = &wmi_10x_pdev_param_map; ar->wmi.pdev_param = &wmi_10x_pdev_param_map;
ar->wmi.peer_flags = &wmi_10_2_peer_flags_map;
break; break;
case ATH10K_FW_WMI_OP_VERSION_10_1: case ATH10K_FW_WMI_OP_VERSION_10_1:
ar->wmi.cmd = &wmi_10x_cmd_map; ar->wmi.cmd = &wmi_10x_cmd_map;
ar->wmi.ops = &wmi_10_1_ops; ar->wmi.ops = &wmi_10_1_ops;
ar->wmi.vdev_param = &wmi_10x_vdev_param_map; ar->wmi.vdev_param = &wmi_10x_vdev_param_map;
ar->wmi.pdev_param = &wmi_10x_pdev_param_map; ar->wmi.pdev_param = &wmi_10x_pdev_param_map;
ar->wmi.peer_flags = &wmi_10x_peer_flags_map;
break; break;
case ATH10K_FW_WMI_OP_VERSION_MAIN: case ATH10K_FW_WMI_OP_VERSION_MAIN:
ar->wmi.cmd = &wmi_cmd_map; ar->wmi.cmd = &wmi_cmd_map;
ar->wmi.ops = &wmi_ops; ar->wmi.ops = &wmi_ops;
ar->wmi.vdev_param = &wmi_vdev_param_map; ar->wmi.vdev_param = &wmi_vdev_param_map;
ar->wmi.pdev_param = &wmi_pdev_param_map; ar->wmi.pdev_param = &wmi_pdev_param_map;
ar->wmi.peer_flags = &wmi_peer_flags_map;
break; break;
case ATH10K_FW_WMI_OP_VERSION_TLV: case ATH10K_FW_WMI_OP_VERSION_TLV:
ath10k_wmi_tlv_attach(ar); ath10k_wmi_tlv_attach(ar);
......
...@@ -175,6 +175,8 @@ enum wmi_service { ...@@ -175,6 +175,8 @@ enum wmi_service {
WMI_SERVICE_AUX_SPECTRAL_INTF, WMI_SERVICE_AUX_SPECTRAL_INTF,
WMI_SERVICE_AUX_CHAN_LOAD_INTF, WMI_SERVICE_AUX_CHAN_LOAD_INTF,
WMI_SERVICE_BSS_CHANNEL_INFO_64, WMI_SERVICE_BSS_CHANNEL_INFO_64,
WMI_SERVICE_EXT_RES_CFG_SUPPORT,
WMI_SERVICE_MESH,
/* keep last */ /* keep last */
WMI_SERVICE_MAX, WMI_SERVICE_MAX,
...@@ -206,6 +208,11 @@ enum wmi_10x_service { ...@@ -206,6 +208,11 @@ enum wmi_10x_service {
WMI_10X_SERVICE_SMART_ANTENNA_HW_SUPPORT, WMI_10X_SERVICE_SMART_ANTENNA_HW_SUPPORT,
WMI_10X_SERVICE_ATF, WMI_10X_SERVICE_ATF,
WMI_10X_SERVICE_COEX_GPIO, 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 { enum wmi_main_service {
...@@ -286,6 +293,8 @@ enum wmi_10_4_service { ...@@ -286,6 +293,8 @@ enum wmi_10_4_service {
WMI_10_4_SERVICE_AUX_SPECTRAL_INTF, WMI_10_4_SERVICE_AUX_SPECTRAL_INTF,
WMI_10_4_SERVICE_AUX_CHAN_LOAD_INTF, WMI_10_4_SERVICE_AUX_CHAN_LOAD_INTF,
WMI_10_4_SERVICE_BSS_CHANNEL_INFO_64, 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) static inline char *wmi_service_name(int service_id)
...@@ -375,6 +384,8 @@ 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_SPECTRAL_INTF);
SVCSTR(WMI_SERVICE_AUX_CHAN_LOAD_INTF); SVCSTR(WMI_SERVICE_AUX_CHAN_LOAD_INTF);
SVCSTR(WMI_SERVICE_BSS_CHANNEL_INFO_64); SVCSTR(WMI_SERVICE_BSS_CHANNEL_INFO_64);
SVCSTR(WMI_SERVICE_EXT_RES_CFG_SUPPORT);
SVCSTR(WMI_SERVICE_MESH);
default: default:
return NULL; return NULL;
} }
...@@ -442,6 +453,16 @@ static inline void wmi_10x_svc_map(const __le32 *in, unsigned long *out, ...@@ -442,6 +453,16 @@ static inline void wmi_10x_svc_map(const __le32 *in, unsigned long *out,
WMI_SERVICE_ATF, len); WMI_SERVICE_ATF, len);
SVCMAP(WMI_10X_SERVICE_COEX_GPIO, SVCMAP(WMI_10X_SERVICE_COEX_GPIO,
WMI_SERVICE_COEX_GPIO, len); 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, 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, ...@@ -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); WMI_SERVICE_AUX_CHAN_LOAD_INTF, len);
SVCMAP(WMI_10_4_SERVICE_BSS_CHANNEL_INFO_64, SVCMAP(WMI_10_4_SERVICE_BSS_CHANNEL_INFO_64,
WMI_SERVICE_BSS_CHANNEL_INFO_64, len); 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 #undef SVCMAP
...@@ -1576,6 +1601,9 @@ enum wmi_10_4_cmd_id { ...@@ -1576,6 +1601,9 @@ enum wmi_10_4_cmd_id {
WMI_10_4_MU_CAL_START_CMDID, WMI_10_4_MU_CAL_START_CMDID,
WMI_10_4_SET_CCA_PARAMS_CMDID, WMI_10_4_SET_CCA_PARAMS_CMDID,
WMI_10_4_PDEV_BSS_CHAN_INFO_REQUEST_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, WMI_10_4_PDEV_UTF_CMDID = WMI_10_4_END_CMDID - 1,
}; };
...@@ -1638,6 +1666,7 @@ enum wmi_10_4_event_id { ...@@ -1638,6 +1666,7 @@ enum wmi_10_4_event_id {
WMI_10_4_PDEV_TEMPERATURE_EVENTID, WMI_10_4_PDEV_TEMPERATURE_EVENTID,
WMI_10_4_PDEV_NFCAL_POWER_ALL_CHANNELS_EVENTID, WMI_10_4_PDEV_NFCAL_POWER_ALL_CHANNELS_EVENTID,
WMI_10_4_PDEV_BSS_CHAN_INFO_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, WMI_10_4_PDEV_UTF_EVENTID = WMI_10_4_END_EVENTID - 1,
}; };
...@@ -3650,6 +3679,12 @@ enum wmi_10_4_pdev_param { ...@@ -3650,6 +3679,12 @@ enum wmi_10_4_pdev_param {
WMI_10_4_PDEV_PARAM_WAPI_MBSSID_OFFSET, WMI_10_4_PDEV_PARAM_WAPI_MBSSID_OFFSET,
WMI_10_4_PDEV_PARAM_ARP_SRCADDR, WMI_10_4_PDEV_PARAM_ARP_SRCADDR,
WMI_10_4_PDEV_PARAM_ARP_DSTADDR, 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 { struct wmi_pdev_set_param_cmd {
...@@ -4239,6 +4274,8 @@ enum wmi_vdev_subtype { ...@@ -4239,6 +4274,8 @@ enum wmi_vdev_subtype {
WMI_VDEV_SUBTYPE_P2P_DEVICE = 1, WMI_VDEV_SUBTYPE_P2P_DEVICE = 1,
WMI_VDEV_SUBTYPE_P2P_CLIENT = 2, WMI_VDEV_SUBTYPE_P2P_CLIENT = 2,
WMI_VDEV_SUBTYPE_P2P_GO = 3, WMI_VDEV_SUBTYPE_P2P_GO = 3,
WMI_VDEV_SUBTYPE_PROXY_STA = 4,
WMI_VDEV_SUBTYPE_MESH = 5,
}; };
/* values for vdev_subtype */ /* values for vdev_subtype */
...@@ -5641,21 +5678,79 @@ struct wmi_peer_set_q_empty_callback_cmd { ...@@ -5641,21 +5678,79 @@ struct wmi_peer_set_q_empty_callback_cmd {
__le32 callback_enable; __le32 callback_enable;
} __packed; } __packed;
#define WMI_PEER_AUTH 0x00000001 struct wmi_peer_flags_map {
#define WMI_PEER_QOS 0x00000002 u32 auth;
#define WMI_PEER_NEED_PTK_4_WAY 0x00000004 u32 qos;
#define WMI_PEER_NEED_GTK_2_WAY 0x00000010 u32 need_ptk_4_way;
#define WMI_PEER_APSD 0x00000800 u32 need_gtk_2_way;
#define WMI_PEER_HT 0x00001000 u32 apsd;
#define WMI_PEER_40MHZ 0x00002000 u32 ht;
#define WMI_PEER_STBC 0x00008000 u32 bw40;
#define WMI_PEER_LDPC 0x00010000 u32 stbc;
#define WMI_PEER_DYN_MIMOPS 0x00020000 u32 ldbc;
#define WMI_PEER_STATIC_MIMOPS 0x00040000 u32 dyn_mimops;
#define WMI_PEER_SPATIAL_MUX 0x00200000 u32 static_mimops;
#define WMI_PEER_VHT 0x02000000 u32 spatial_mux;
#define WMI_PEER_80MHZ 0x04000000 u32 vht;
#define WMI_PEER_VHT_2G 0x08000000 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. * Peer rate capabilities.
...@@ -5721,6 +5816,11 @@ struct wmi_10_2_peer_assoc_complete_cmd { ...@@ -5721,6 +5816,11 @@ struct wmi_10_2_peer_assoc_complete_cmd {
__le32 info0; /* WMI_PEER_ASSOC_INFO0_ */ __le32 info0; /* WMI_PEER_ASSOC_INFO0_ */
} __packed; } __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 { struct wmi_peer_assoc_complete_arg {
u8 addr[ETH_ALEN]; u8 addr[ETH_ALEN];
u32 vdev_id; u32 vdev_id;
......
...@@ -401,20 +401,26 @@ void wil_bcast_fini(struct wil6210_priv *wil) ...@@ -401,20 +401,26 @@ void wil_bcast_fini(struct wil6210_priv *wil)
static void wil_connect_worker(struct work_struct *work) 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, struct wil6210_priv *wil = container_of(work, struct wil6210_priv,
connect_worker); connect_worker);
struct net_device *ndev = wil_to_ndev(wil); struct net_device *ndev = wil_to_ndev(wil);
int cid = wil->pending_connect_cid; mutex_lock(&wil->mutex);
int ringid = wil_find_free_vring(wil);
cid = wil->pending_connect_cid;
if (cid < 0) { if (cid < 0) {
wil_err(wil, "No connection pending\n"); 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); rc = wil_vring_init_tx(wil, ringid, 1 << tx_ring_order, cid, 0);
wil->pending_connect_cid = -1; wil->pending_connect_cid = -1;
...@@ -424,6 +430,8 @@ static void wil_connect_worker(struct work_struct *work) ...@@ -424,6 +430,8 @@ static void wil_connect_worker(struct work_struct *work)
} else { } else {
wil_disconnect_cid(wil, cid, WLAN_REASON_UNSPECIFIED, true); wil_disconnect_cid(wil, cid, WLAN_REASON_UNSPECIFIED, true);
} }
out:
mutex_unlock(&wil->mutex);
} }
int wil_priv_init(struct wil6210_priv *wil) int wil_priv_init(struct wil6210_priv *wil)
......
...@@ -160,6 +160,7 @@ static void wil_vring_free(struct wil6210_priv *wil, struct vring *vring, ...@@ -160,6 +160,7 @@ static void wil_vring_free(struct wil6210_priv *wil, struct vring *vring,
struct device *dev = wil_to_dev(wil); struct device *dev = wil_to_dev(wil);
size_t sz = vring->size * sizeof(vring->va[0]); size_t sz = vring->size * sizeof(vring->va[0]);
lockdep_assert_held(&wil->mutex);
if (tx) { if (tx) {
int vring_index = vring - wil->vring_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, ...@@ -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__, wil_dbg_misc(wil, "%s() max_mpdu_size %d\n", __func__,
cmd.vring_cfg.tx_sw_ring.max_mpdu_size); cmd.vring_cfg.tx_sw_ring.max_mpdu_size);
lockdep_assert_held(&wil->mutex);
if (vring->va) { if (vring->va) {
wil_err(wil, "Tx ring [%d] already allocated\n", id); 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) ...@@ -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__, wil_dbg_misc(wil, "%s() max_mpdu_size %d\n", __func__,
cmd.vring_cfg.tx_sw_ring.max_mpdu_size); cmd.vring_cfg.tx_sw_ring.max_mpdu_size);
lockdep_assert_held(&wil->mutex);
if (vring->va) { if (vring->va) {
wil_err(wil, "Tx ring [%d] already allocated\n", id); 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) ...@@ -872,7 +875,7 @@ void wil_vring_fini_tx(struct wil6210_priv *wil, int id)
struct vring *vring = &wil->vring_tx[id]; struct vring *vring = &wil->vring_tx[id];
struct vring_tx_data *txdata = &wil->vring_tx_data[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) if (!vring->va)
return; return;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment