diff options
author | John W. Linville <linville@tuxdriver.com> | 2014-12-01 15:51:31 -0500 |
---|---|---|
committer | John W. Linville <linville@tuxdriver.com> | 2014-12-01 15:51:31 -0500 |
commit | cbe1bc2383ad69a35e4b030c00642785b8b135e8 (patch) | |
tree | fd73d9b59dc6d0a5b419cd6d5f6554dbb026ee25 /drivers/net/wireless | |
parent | 992066c8d3f24d3b5779b1309f8a67634fac1c24 (diff) | |
parent | fe2407a889f7b6530b7e231e7c866f5c5d223657 (diff) |
Merge branch 'for-linville' of git://github.com/kvalo/ath
Diffstat (limited to 'drivers/net/wireless')
-rw-r--r-- | drivers/net/wireless/ath/ath10k/core.c | 13 | ||||
-rw-r--r-- | drivers/net/wireless/ath/ath10k/core.h | 13 | ||||
-rw-r--r-- | drivers/net/wireless/ath/ath10k/debug.c | 262 | ||||
-rw-r--r-- | drivers/net/wireless/ath/ath10k/debug.h | 10 | ||||
-rw-r--r-- | drivers/net/wireless/ath/ath10k/hif.h | 43 | ||||
-rw-r--r-- | drivers/net/wireless/ath/ath10k/htc.c | 13 | ||||
-rw-r--r-- | drivers/net/wireless/ath/ath10k/htt.h | 7 | ||||
-rw-r--r-- | drivers/net/wireless/ath/ath10k/htt_rx.c | 1169 | ||||
-rw-r--r-- | drivers/net/wireless/ath/ath10k/htt_tx.c | 7 | ||||
-rw-r--r-- | drivers/net/wireless/ath/ath10k/hw.h | 15 | ||||
-rw-r--r-- | drivers/net/wireless/ath/ath10k/mac.c | 202 | ||||
-rw-r--r-- | drivers/net/wireless/ath/ath10k/mac.h | 4 | ||||
-rw-r--r-- | drivers/net/wireless/ath/ath10k/pci.c | 28 | ||||
-rw-r--r-- | drivers/net/wireless/ath/ath10k/trace.h | 31 | ||||
-rw-r--r-- | drivers/net/wireless/ath/ath10k/wmi.c | 61 | ||||
-rw-r--r-- | drivers/net/wireless/ath/ath10k/wmi.h | 128 |
16 files changed, 1257 insertions, 749 deletions
diff --git a/drivers/net/wireless/ath/ath10k/core.c b/drivers/net/wireless/ath/ath10k/core.c index f660553c6c4..7762061a194 100644 --- a/drivers/net/wireless/ath/ath10k/core.c +++ b/drivers/net/wireless/ath/ath10k/core.c @@ -799,6 +799,17 @@ static void ath10k_core_restart(struct work_struct *work) mutex_unlock(&ar->conf_mutex); } +static void ath10k_core_init_max_sta_count(struct ath10k *ar) +{ + if (test_bit(ATH10K_FW_FEATURE_WMI_10X, ar->fw_features)) { + ar->max_num_peers = TARGET_10X_NUM_PEERS; + ar->max_num_stations = TARGET_10X_NUM_STATIONS; + } else { + ar->max_num_peers = TARGET_NUM_PEERS; + ar->max_num_stations = TARGET_NUM_STATIONS; + } +} + int ath10k_core_start(struct ath10k *ar, enum ath10k_firmware_mode mode) { int status; @@ -1035,6 +1046,8 @@ static int ath10k_core_probe_fw(struct ath10k *ar) return ret; } + ath10k_core_init_max_sta_count(ar); + mutex_lock(&ar->conf_mutex); ret = ath10k_core_start(ar, ATH10K_FIRMWARE_MODE_NORMAL); diff --git a/drivers/net/wireless/ath/ath10k/core.h b/drivers/net/wireless/ath/ath10k/core.h index 8f86bd34e82..514c219263a 100644 --- a/drivers/net/wireless/ath/ath10k/core.h +++ b/drivers/net/wireless/ath/ath10k/core.h @@ -79,10 +79,12 @@ static inline const char *ath10k_bus_str(enum ath10k_bus bus) struct ath10k_skb_cb { dma_addr_t paddr; + u8 eid; u8 vdev_id; struct { u8 tid; + u16 freq; bool is_offchan; struct ath10k_htt_txbuf *txbuf; u32 txbuf_paddr; @@ -122,6 +124,7 @@ struct ath10k_wmi { struct completion service_ready; struct completion unified_ready; wait_queue_head_t tx_credits_wq; + DECLARE_BITMAP(svc_map, WMI_SERVICE_MAX); struct wmi_cmd_map *cmd; struct wmi_vdev_param_map *vdev_param; struct wmi_pdev_param_map *pdev_param; @@ -218,6 +221,8 @@ struct ath10k_peer { int vdev_id; u8 addr[ETH_ALEN]; DECLARE_BITMAP(peer_ids, ATH10K_MAX_NUM_PEER_IDS); + + /* protected by ar->data_lock */ struct ieee80211_key_conf *keys[WMI_MAX_KEY_INDEX + 1]; }; @@ -310,7 +315,6 @@ struct ath10k_debug { struct ath10k_fw_stats fw_stats; struct completion fw_stats_complete; bool fw_stats_done; - DECLARE_BITMAP(wmi_service_bitmap, WMI_SERVICE_MAX); unsigned long htt_stats_mask; struct delayed_work htt_stats_dwork; @@ -320,6 +324,7 @@ struct ath10k_debug { /* protected by conf_mutex */ u32 fw_dbglog_mask; u32 pktlog_filter; + u32 reg_addr; u8 htt_max_amsdu; u8 htt_max_ampdu; @@ -560,8 +565,12 @@ struct ath10k { struct list_head peers; wait_queue_head_t peer_mapping_wq; - /* number of created peers; protected by data_lock */ + /* protected by conf_mutex */ int num_peers; + int num_stations; + + int max_num_peers; + int max_num_stations; struct work_struct offchan_tx_work; struct sk_buff_head offchan_tx_queue; diff --git a/drivers/net/wireless/ath/ath10k/debug.c b/drivers/net/wireless/ath/ath10k/debug.c index a8f5a72ba25..a716758f14b 100644 --- a/drivers/net/wireless/ath/ath10k/debug.c +++ b/drivers/net/wireless/ath/ath10k/debug.c @@ -17,9 +17,8 @@ #include <linux/module.h> #include <linux/debugfs.h> -#include <linux/version.h> -#include <linux/vermagic.h> #include <linux/vmalloc.h> +#include <linux/utsname.h> #include "core.h" #include "debug.h" @@ -124,7 +123,7 @@ EXPORT_SYMBOL(ath10k_info); void ath10k_print_driver_info(struct ath10k *ar) { - ath10k_info(ar, "%s (0x%08x, 0x%08x) fw %s api %d htt %d.%d wmi %d.%d.%d.%d cal %s\n", + ath10k_info(ar, "%s (0x%08x, 0x%08x) fw %s api %d htt %d.%d wmi %d.%d.%d.%d cal %s max_sta %d\n", ar->hw_params.name, ar->target_version, ar->chip_id, @@ -136,7 +135,8 @@ void ath10k_print_driver_info(struct ath10k *ar) ar->fw_version_minor, ar->fw_version_release, ar->fw_version_build, - ath10k_cal_mode_str(ar->cal_mode)); + ath10k_cal_mode_str(ar->cal_mode), + ar->max_num_stations); ath10k_info(ar, "debug %d debugfs %d tracing %d dfs %d testmode %d\n", config_enabled(CONFIG_ATH10K_DEBUG), config_enabled(CONFIG_ATH10K_DEBUGFS), @@ -179,13 +179,6 @@ EXPORT_SYMBOL(ath10k_warn); #ifdef CONFIG_ATH10K_DEBUGFS -void ath10k_debug_read_service_map(struct ath10k *ar, - const void *service_map, - size_t map_size) -{ - memcpy(ar->debug.wmi_service_bitmap, service_map, map_size); -} - static ssize_t ath10k_read_wmi_services(struct file *file, char __user *user_buf, size_t count, loff_t *ppos) @@ -207,8 +200,9 @@ static ssize_t ath10k_read_wmi_services(struct file *file, if (len > buf_len) len = buf_len; + spin_lock_bh(&ar->data_lock); for (i = 0; i < WMI_SERVICE_MAX; i++) { - enabled = test_bit(i, ar->debug.wmi_service_bitmap); + enabled = test_bit(i, ar->wmi.svc_map); name = wmi_service_name(i); if (!name) { @@ -224,6 +218,7 @@ static ssize_t ath10k_read_wmi_services(struct file *file, "%-40s %s\n", name, enabled ? "enabled" : "-"); } + spin_unlock_bh(&ar->data_lock); ret_cnt = simple_read_from_buffer(user_buf, count, ppos, buf, len); @@ -866,8 +861,8 @@ static struct ath10k_dump_file_data *ath10k_build_dump_file(struct ath10k *ar) strlcpy(dump_data->fw_ver, ar->hw->wiphy->fw_version, sizeof(dump_data->fw_ver)); - dump_data->kernel_ver_code = cpu_to_le32(LINUX_VERSION_CODE); - strlcpy(dump_data->kernel_ver, VERMAGIC_STRING, + dump_data->kernel_ver_code = 0; + strlcpy(dump_data->kernel_ver, init_utsname()->release, sizeof(dump_data->kernel_ver)); dump_data->tv_sec = cpu_to_le64(crash_data->timestamp.tv_sec); @@ -929,6 +924,236 @@ static const struct file_operations fops_fw_crash_dump = { .llseek = default_llseek, }; +static ssize_t ath10k_reg_addr_read(struct file *file, + char __user *user_buf, + size_t count, loff_t *ppos) +{ + struct ath10k *ar = file->private_data; + u8 buf[32]; + unsigned int len = 0; + u32 reg_addr; + + mutex_lock(&ar->conf_mutex); + reg_addr = ar->debug.reg_addr; + mutex_unlock(&ar->conf_mutex); + + len += scnprintf(buf + len, sizeof(buf) - len, "0x%x\n", reg_addr); + + return simple_read_from_buffer(user_buf, count, ppos, buf, len); +} + +static ssize_t ath10k_reg_addr_write(struct file *file, + const char __user *user_buf, + size_t count, loff_t *ppos) +{ + struct ath10k *ar = file->private_data; + u32 reg_addr; + int ret; + + ret = kstrtou32_from_user(user_buf, count, 0, ®_addr); + if (ret) + return ret; + + if (!IS_ALIGNED(reg_addr, 4)) + return -EFAULT; + + mutex_lock(&ar->conf_mutex); + ar->debug.reg_addr = reg_addr; + mutex_unlock(&ar->conf_mutex); + + return count; +} + +static const struct file_operations fops_reg_addr = { + .read = ath10k_reg_addr_read, + .write = ath10k_reg_addr_write, + .open = simple_open, + .owner = THIS_MODULE, + .llseek = default_llseek, +}; + +static ssize_t ath10k_reg_value_read(struct file *file, + char __user *user_buf, + size_t count, loff_t *ppos) +{ + struct ath10k *ar = file->private_data; + u8 buf[48]; + unsigned int len; + u32 reg_addr, reg_val; + int ret; + + mutex_lock(&ar->conf_mutex); + + if (ar->state != ATH10K_STATE_ON && + ar->state != ATH10K_STATE_UTF) { + ret = -ENETDOWN; + goto exit; + } + + reg_addr = ar->debug.reg_addr; + + reg_val = ath10k_hif_read32(ar, reg_addr); + len = scnprintf(buf, sizeof(buf), "0x%08x:0x%08x\n", reg_addr, reg_val); + + ret = simple_read_from_buffer(user_buf, count, ppos, buf, len); + +exit: + mutex_unlock(&ar->conf_mutex); + + return ret; +} + +static ssize_t ath10k_reg_value_write(struct file *file, + const char __user *user_buf, + size_t count, loff_t *ppos) +{ + struct ath10k *ar = file->private_data; + u32 reg_addr, reg_val; + int ret; + + mutex_lock(&ar->conf_mutex); + + if (ar->state != ATH10K_STATE_ON && + ar->state != ATH10K_STATE_UTF) { + ret = -ENETDOWN; + goto exit; + } + + reg_addr = ar->debug.reg_addr; + + ret = kstrtou32_from_user(user_buf, count, 0, ®_val); + if (ret) + goto exit; + + ath10k_hif_write32(ar, reg_addr, reg_val); + + ret = count; + +exit: + mutex_unlock(&ar->conf_mutex); + + return ret; +} + +static const struct file_operations fops_reg_value = { + .read = ath10k_reg_value_read, + .write = ath10k_reg_value_write, + .open = simple_open, + .owner = THIS_MODULE, + .llseek = default_llseek, +}; + +static ssize_t ath10k_mem_value_read(struct file *file, + char __user *user_buf, + size_t count, loff_t *ppos) +{ + struct ath10k *ar = file->private_data; + u8 *buf; + int ret; + + if (*ppos < 0) + return -EINVAL; + + if (!count) + return 0; + + mutex_lock(&ar->conf_mutex); + + buf = vmalloc(count); + if (!buf) { + ret = -ENOMEM; + goto exit; + } + + if (ar->state != ATH10K_STATE_ON && + ar->state != ATH10K_STATE_UTF) { + ret = -ENETDOWN; + goto exit; + } + + ret = ath10k_hif_diag_read(ar, *ppos, buf, count); + if (ret) { + ath10k_warn(ar, "failed to read address 0x%08x via diagnose window fnrom debugfs: %d\n", + (u32)(*ppos), ret); + goto exit; + } + + ret = copy_to_user(user_buf, buf, count); + if (ret) { + ret = -EFAULT; + goto exit; + } + + count -= ret; + *ppos += count; + ret = count; + +exit: + vfree(buf); + mutex_unlock(&ar->conf_mutex); + + return ret; +} + +static ssize_t ath10k_mem_value_write(struct file *file, + const char __user *user_buf, + size_t count, loff_t *ppos) +{ + struct ath10k *ar = file->private_data; + u8 *buf; + int ret; + + if (*ppos < 0) + return -EINVAL; + + if (!count) + return 0; + + mutex_lock(&ar->conf_mutex); + + buf = vmalloc(count); + if (!buf) { + ret = -ENOMEM; + goto exit; + } + + if (ar->state != ATH10K_STATE_ON && + ar->state != ATH10K_STATE_UTF) { + ret = -ENETDOWN; + goto exit; + } + + ret = copy_from_user(buf, user_buf, count); + if (ret) { + ret = -EFAULT; + goto exit; + } + + ret = ath10k_hif_diag_write(ar, *ppos, buf, count); + if (ret) { + ath10k_warn(ar, "failed to write address 0x%08x via diagnose window from debugfs: %d\n", + (u32)(*ppos), ret); + goto exit; + } + + *ppos += count; + ret = count; + +exit: + vfree(buf); + mutex_unlock(&ar->conf_mutex); + + return ret; +} + +static const struct file_operations fops_mem_value = { + .read = ath10k_mem_value_read, + .write = ath10k_mem_value_write, + .open = simple_open, + .owner = THIS_MODULE, + .llseek = default_llseek, +}; + static int ath10k_debug_htt_stats_req(struct ath10k *ar) { u64 cookie; @@ -1630,6 +1855,15 @@ int ath10k_debug_register(struct ath10k *ar) debugfs_create_file("fw_crash_dump", S_IRUSR, ar->debug.debugfs_phy, ar, &fops_fw_crash_dump); + debugfs_create_file("reg_addr", S_IRUSR | S_IWUSR, + ar->debug.debugfs_phy, ar, &fops_reg_addr); + + debugfs_create_file("reg_value", S_IRUSR | S_IWUSR, + ar->debug.debugfs_phy, ar, &fops_reg_value); + + debugfs_create_file("mem_value", S_IRUSR | S_IWUSR, + ar->debug.debugfs_phy, ar, &fops_mem_value); + debugfs_create_file("chip_id", S_IRUSR, ar->debug.debugfs_phy, ar, &fops_chip_id); diff --git a/drivers/net/wireless/ath/ath10k/debug.h b/drivers/net/wireless/ath/ath10k/debug.h index 0c934a8378d..1b87a5dbec5 100644 --- a/drivers/net/wireless/ath/ath10k/debug.h +++ b/drivers/net/wireless/ath/ath10k/debug.h @@ -35,6 +35,7 @@ enum ath10k_debug_mask { ATH10K_DBG_BMI = 0x00000400, ATH10K_DBG_REGULATORY = 0x00000800, ATH10K_DBG_TESTMODE = 0x00001000, + ATH10K_DBG_WMI_PRINT = 0x00002000, ATH10K_DBG_ANY = 0xffffffff, }; @@ -61,9 +62,6 @@ int ath10k_debug_create(struct ath10k *ar); void ath10k_debug_destroy(struct ath10k *ar); int ath10k_debug_register(struct ath10k *ar); void ath10k_debug_unregister(struct ath10k *ar); -void ath10k_debug_read_service_map(struct ath10k *ar, - const void *service_map, - size_t map_size); void ath10k_debug_fw_stats_process(struct ath10k *ar, struct sk_buff *skb); struct ath10k_fw_crash_data * ath10k_debug_get_new_fw_crash_data(struct ath10k *ar); @@ -108,12 +106,6 @@ static inline void ath10k_debug_unregister(struct ath10k *ar) { } -static inline void ath10k_debug_read_service_map(struct ath10k *ar, - const void *service_map, - size_t map_size) -{ -} - static inline void ath10k_debug_fw_stats_process(struct ath10k *ar, struct sk_buff *skb) { diff --git a/drivers/net/wireless/ath/ath10k/hif.h b/drivers/net/wireless/ath/ath10k/hif.h index 30301f5b605..0c92e0251e8 100644 --- a/drivers/net/wireless/ath/ath10k/hif.h +++ b/drivers/net/wireless/ath/ath10k/hif.h @@ -20,6 +20,7 @@ #include <linux/kernel.h> #include "core.h" +#include "debug.h" struct ath10k_hif_sg_item { u16 transfer_id; @@ -31,11 +32,9 @@ struct ath10k_hif_sg_item { struct ath10k_hif_cb { int (*tx_completion)(struct ath10k *ar, - struct sk_buff *wbuf, - unsigned transfer_id); + struct sk_buff *wbuf); int (*rx_completion)(struct ath10k *ar, - struct sk_buff *wbuf, - u8 pipe_id); + struct sk_buff *wbuf); }; struct ath10k_hif_ops { @@ -47,6 +46,8 @@ struct ath10k_hif_ops { int (*diag_read)(struct ath10k *ar, u32 address, void *buf, size_t buf_len); + int (*diag_write)(struct ath10k *ar, u32 address, const void *data, + int nbytes); /* * API to handle HIF-specific BMI message exchanges, this API is * synchronous and only allowed to be called from a context that @@ -84,6 +85,10 @@ struct ath10k_hif_ops { u16 (*get_free_queue_number)(struct ath10k *ar, u8 pipe_id); + u32 (*read32)(struct ath10k *ar, u32 address); + + void (*write32)(struct ath10k *ar, u32 address, u32 value); + /* Power up the device and enter BMI transfer mode for FW download */ int (*power_up)(struct ath10k *ar); @@ -108,6 +113,15 @@ static inline int ath10k_hif_diag_read(struct ath10k *ar, u32 address, void *buf return ar->hif.ops->diag_read(ar, address, buf, buf_len); } +static inline int ath10k_hif_diag_write(struct ath10k *ar, u32 address, + const void *data, int nbytes) +{ + if (!ar->hif.ops->diag_write) + return -EOPNOTSUPP; + + return ar->hif.ops->diag_write(ar, address, data, nbytes); +} + static inline int ath10k_hif_exchange_bmi_msg(struct ath10k *ar, void *request, u32 request_len, void *response, u32 *response_len) @@ -187,4 +201,25 @@ static inline int ath10k_hif_resume(struct ath10k *ar) return ar->hif.ops->resume(ar); } +static inline u32 ath10k_hif_read32(struct ath10k *ar, u32 address) +{ + if (!ar->hif.ops->read32) { + ath10k_warn(ar, "hif read32 not supported\n"); + return 0xdeaddead; + } + + return ar->hif.ops->read32(ar, address); +} + +static inline void ath10k_hif_write32(struct ath10k *ar, + u32 address, u32 data) +{ + if (!ar->hif.ops->write32) { + ath10k_warn(ar, "hif write32 not supported\n"); + return; + } + + ar->hif.ops->write32(ar, address, data); +} + #endif /* _HIF_H_ */ diff --git a/drivers/net/wireless/ath/ath10k/htc.c b/drivers/net/wireless/ath/ath10k/htc.c index 676bd4ed969..f1946a6be44 100644 --- a/drivers/net/wireless/ath/ath10k/htc.c +++ b/drivers/net/wireless/ath/ath10k/htc.c @@ -160,6 +160,7 @@ int ath10k_htc_send(struct ath10k_htc *htc, ath10k_htc_prepare_tx_skb(ep, skb); + skb_cb->eid = eid; skb_cb->paddr = dma_map_single(dev, skb->data, skb->len, DMA_TO_DEVICE); ret = dma_mapping_error(dev, skb_cb->paddr); if (ret) @@ -197,15 +198,18 @@ err_pull: } static int ath10k_htc_tx_completion_handler(struct ath10k *ar, - struct sk_buff *skb, - unsigned int eid) + struct sk_buff *skb) { struct ath10k_htc *htc = &ar->htc; - struct ath10k_htc_ep *ep = &htc->endpoint[eid]; + struct ath10k_skb_cb *skb_cb; + struct ath10k_htc_ep *ep; if (WARN_ON_ONCE(!skb)) return 0; + skb_cb = ATH10K_SKB_CB(skb); + ep = &htc->endpoint[skb_cb->eid]; + ath10k_htc_notify_tx_completion(ep, skb); /* the skb now belongs to the completion handler */ @@ -317,8 +321,7 @@ static int ath10k_htc_process_trailer(struct ath10k_htc *htc, } static int ath10k_htc_rx_completion_handler(struct ath10k *ar, - struct sk_buff *skb, - u8 pipe_id) + struct sk_buff *skb) { int status = 0; struct ath10k_htc *htc = &ar->htc; diff --git a/drivers/net/wireless/ath/ath10k/htt.h b/drivers/net/wireless/ath/ath10k/htt.h index 15c58e884b6..1bd5545af90 100644 --- a/drivers/net/wireless/ath/ath10k/htt.h +++ b/drivers/net/wireless/ath/ath10k/htt.h @@ -126,6 +126,7 @@ enum htt_data_tx_ext_tid { * (HL hosts manage queues on the host ) * more_in_batch: only for HL hosts. indicates if more packets are * pending. this allows target to wait and aggregate + * freq: 0 means home channel of given vdev. intended for offchannel */ struct htt_data_tx_desc { u8 flags0; /* %HTT_DATA_TX_DESC_FLAGS0_ */ @@ -133,7 +134,8 @@ struct htt_data_tx_desc { __le16 len; __le16 id; __le32 frags_paddr; - __le32 peerid; + __le16 peerid; + __le16 freq; u8 prefetch[0]; /* start of frame, for FW classification engine */ } __packed; @@ -156,6 +158,9 @@ enum htt_rx_ring_flags { HTT_RX_RING_FLAGS_PHY_DATA_RX = 1 << 15 }; +#define HTT_RX_RING_SIZE_MIN 128 +#define HTT_RX_RING_SIZE_MAX 2048 + struct htt_rx_ring_setup_ring { __le32 fw_idx_shadow_reg_paddr; __le32 rx_ring_base_paddr; diff --git a/drivers/net/wireless/ath/ath10k/htt_rx.c b/drivers/net/wireless/ath/ath10k/htt_rx.c index 52c63067271..9c782a42665 100644 --- a/drivers/net/wireless/ath/ath10k/htt_rx.c +++ b/drivers/net/wireless/ath/ath10k/htt_rx.c @@ -25,19 +25,8 @@ #include <linux/log2.h> -/* slightly larger than one large A-MPDU */ -#define HTT_RX_RING_SIZE_MIN 128 - -/* roughly 20 ms @ 1 Gbps of 1500B MSDUs */ -#define HTT_RX_RING_SIZE_MAX 2048 - -#define HTT_RX_AVG_FRM_BYTES 1000 - -/* ms, very conservative */ -#define HTT_RX_HOST_LATENCY_MAX_MS 20 - -/* ms, conservative */ -#define HTT_RX_HOST_LATENCY_WORST_LIKELY_MS 10 +#define HTT_RX_RING_SIZE 1024 +#define HTT_RX_RING_FILL_LEVEL 1000 /* when under memory pressure rx ring refill may fail and needs a retry */ #define HTT_RX_RING_REFILL_RETRY_MS 50 @@ -45,68 +34,6 @@ static int ath10k_htt_rx_get_csum_state(struct sk_buff *skb); static void ath10k_htt_txrx_compl_task(unsigned long ptr); -static int ath10k_htt_rx_ring_size(struct ath10k_htt *htt) -{ - int size; - - /* - * It is expected that the host CPU will typically be able to - * service the rx indication from one A-MPDU before the rx - * indication from the subsequent A-MPDU happens, roughly 1-2 ms - * later. However, the rx ring should be sized very conservatively, - * to accomodate the worst reasonable delay before the host CPU - * services a rx indication interrupt. - * - * The rx ring need not be kept full of empty buffers. In theory, - * the htt host SW can dynamically track the low-water mark in the - * rx ring, and dynamically adjust the level to which the rx ring - * is filled with empty buffers, to dynamically meet the desired - * low-water mark. - * - * In contrast, it's difficult to resize the rx ring itself, once - * it's in use. Thus, the ring itself should be sized very - * conservatively, while the degree to which the ring is filled - * with empty buffers should be sized moderately conservatively. - */ - - /* 1e6 bps/mbps / 1e3 ms per sec = 1000 */ - size = - htt->max_throughput_mbps + - 1000 / - (8 * HTT_RX_AVG_FRM_BYTES) * HTT_RX_HOST_LATENCY_MAX_MS; - - if (size < HTT_RX_RING_SIZE_MIN) - size = HTT_RX_RING_SIZE_MIN; - - if (size > HTT_RX_RING_SIZE_MAX) - size = HTT_RX_RING_SIZE_MAX; - - size = roundup_pow_of_two(size); - - return size; -} - -static int ath10k_htt_rx_ring_fill_level(struct ath10k_htt *htt) -{ - int size; - - /* 1e6 bps/mbps / 1e3 ms per sec = 1000 */ - size = - htt->max_throughput_mbps * - 1000 / - (8 * HTT_RX_AVG_FRM_BYTES) * HTT_RX_HOST_LATENCY_WORST_LIKELY_MS; - - /* - * Make sure the fill level is at least 1 less than the ring size. - * Leaving 1 element empty allows the SW to easily distinguish - * between a full ring vs. an empty ring. - */ - if (size >= htt->rx_ring.size) - size = htt->rx_ring.size - 1; - - return size; -} - static void ath10k_htt_rx_ring_free(struct ath10k_htt *htt) { struct sk_buff *skb; @@ -301,40 +228,29 @@ static inline struct sk_buff *ath10k_htt_rx_netbuf_pop(struct ath10k_htt *htt) return msdu; } -static void ath10k_htt_rx_free_msdu_chain(struct sk_buff *skb) -{ - struct sk_buff *next; - - while (skb) { - next = skb->next; - dev_kfree_skb_any(skb); - skb = next; - } -} - /* return: < 0 fatal error, 0 - non chained msdu, 1 chained msdu */ static int ath10k_htt_rx_amsdu_pop(struct ath10k_htt *htt, u8 **fw_desc, int *fw_desc_len, - struct sk_buff **head_msdu, - struct sk_buff **tail_msdu, - u32 *attention) + struct sk_buff_head *amsdu) { struct ath10k *ar = htt->ar; int msdu_len, msdu_chaining = 0; - struct sk_buff *msdu, *next; + struct sk_buff *msdu; struct htt_rx_desc *rx_desc; lockdep_assert_held(&htt->rx_ring.lock); - if (htt->rx_confused) { - ath10k_warn(ar, "htt is confused. refusing rx\n"); - return -1; - } - - msdu = *head_msdu = ath10k_htt_rx_netbuf_pop(htt); - while (msdu) { + for (;;) { int last_msdu, msdu_len_invalid, msdu_chained; + msdu = ath10k_htt_rx_netbuf_pop(htt); + if (!msdu) { + __skb_queue_purge(amsdu); + return -ENOENT; + } + + __skb_queue_tail(amsdu, msdu); + rx_desc = (struct htt_rx_desc *)msdu->data; /* FIXME: we must report msdu payload since this is what caller @@ -352,19 +268,10 @@ static int ath10k_htt_rx_amsdu_pop(struct ath10k_htt *htt, */ if (!(__le32_to_cpu(rx_desc->attention.flags) & RX_ATTENTION_FLAGS_MSDU_DONE)) { - ath10k_htt_rx_free_msdu_chain(*head_msdu); - *head_msdu = NULL; - msdu = NULL; - ath10k_err(ar, "htt rx stopped. cannot recover\n"); - htt->rx_confused = true; - break; + __skb_queue_purge(amsdu); + return -EIO; } - *attention |= __le32_to_cpu(rx_desc->attention.flags) & - (RX_ATTENTION_FLAGS_TKIP_MIC_ERR | - RX_ATTENTION_FLAGS_DECRYPT_ERR | - RX_ATTENTION_FLAGS_FCS_ERR | - RX_ATTENTION_FLAGS_MGMT_TYPE); /* * Copy the FW rx descriptor for this MSDU from the rx * indication message into the MSDU's netbuf. HL uses the @@ -421,25 +328,18 @@ static int ath10k_htt_rx_amsdu_pop(struct ath10k_htt *htt, skb_put(msdu, min(msdu_len, HTT_RX_MSDU_SIZE)); msdu_len -= msdu->len; - /* FIXME: Do chained buffers include htt_rx_desc or not? */ + /* Note: Chained buffers do not contain rx descriptor */ while (msdu_chained--) { - struct sk_buff *next = ath10k_htt_rx_netbuf_pop(htt); - - if (!next) { - ath10k_warn(ar, "failed to pop chained msdu\n"); - ath10k_htt_rx_free_msdu_chain(*head_msdu); - *head_msdu = NULL; - msdu = NULL; - htt->rx_confused = true; - break; + msdu = ath10k_htt_rx_netbuf_pop(htt); + if (!msdu) { + __skb_queue_purge(amsdu); + return -ENOENT; } - skb_trim(next, 0); - skb_put(next, min(msdu_len, HTT_RX_BUF_SIZE)); - msdu_len -= next->len; - - msdu->next = next; - msdu = next; + __skb_queue_tail(amsdu, msdu); + skb_trim(msdu, 0); + skb_put(msdu, min(msdu_len, HTT_RX_BUF_SIZE)); + msdu_len -= msdu->len; msdu_chaining = 1; } @@ -448,18 +348,12 @@ static int ath10k_htt_rx_amsdu_pop(struct ath10k_htt *htt, trace_ath10k_htt_rx_desc(ar, &rx_desc->attention, sizeof(*rx_desc) - sizeof(u32)); - if (last_msdu) { - msdu->next = NULL; - break; - } - next = ath10k_htt_rx_netbuf_pop(htt); - msdu->next = next; - msdu = next; + if (last_msdu) + break; } - *tail_msdu = msdu; - if (*head_msdu == NULL) + if (skb_queue_empty(amsdu)) msdu_chaining = -1; /* @@ -495,25 +389,18 @@ int ath10k_htt_rx_alloc(struct ath10k_htt *htt) htt->rx_confused = false; - htt->rx_ring.size = ath10k_htt_rx_ring_size(htt); + /* XXX: The fill level could be changed during runtime in response to + * the host processing latency. Is this really worth it? + */ + htt->rx_ring.size = HTT_RX_RING_SIZE; + htt->rx_ring.size_mask = htt->rx_ring.size - 1; + htt->rx_ring.fill_level = HTT_RX_RING_FILL_LEVEL; + if (!is_power_of_2(htt->rx_ring.size)) { ath10k_warn(ar, "htt rx ring size is not power of 2\n"); return -EINVAL; } - htt->rx_ring.size_mask = htt->rx_ring.size - 1; - - /* - * Set the initial value for the level to which the rx ring - * should be filled, based on the max throughput and the - * worst likely latency for the host to fill the rx ring - * with new buffers. In theory, this fill level can be - * dynamically adjusted from the initial value set here, to - * reflect the actual host latency rather than a - * conservative assumption about the host latency. - */ - htt->rx_ring.fill_level = ath10k_htt_rx_ring_fill_level(htt); - htt->rx_ring.netbufs_ring = kzalloc(htt->rx_ring.size * sizeof(struct sk_buff *), GFP_KERNEL); @@ -628,35 +515,6 @@ static int ath10k_htt_rx_crypto_tail_len(struct ath10k *ar, return 0; } -/* Applies for first msdu in chain, before altering it. */ -static struct ieee80211_hdr *ath10k_htt_rx_skb_get_hdr(struct sk_buff *skb) -{ - struct htt_rx_desc *rxd; - enum rx_msdu_decap_format fmt; - - rxd = (void *)skb->data - sizeof(*rxd); - fmt = MS(__le32_to_cpu(rxd->msdu_start.info1), - RX_MSDU_START_INFO1_DECAP_FORMAT); - - if (fmt == RX_MSDU_DECAP_RAW) - return (void *)skb->data; - - return (void *)skb->data - RX_HTT_HDR_STATUS_LEN; -} - -/* This function only applies for first msdu in an msdu chain */ -static bool ath10k_htt_rx_hdr_is_amsdu(struct ieee80211_hdr *hdr) -{ - u8 *qc; - - if (ieee80211_is_data_qos(hdr->frame_control)) { - qc = ieee80211_get_qos_ctl(hdr); - if (qc[0] & 0x80) - return true; - } - return false; -} - struct rfc1042_hdr { u8 llc_dsap; u8 llc_ssap; @@ -691,23 +549,34 @@ static const u8 rx_legacy_rate_idx[] = { }; static void ath10k_htt_rx_h_rates(struct ath10k *ar, - enum ieee80211_band band, - u8 info0, u32 info1, u32 info2, - struct ieee80211_rx_status *status) + struct ieee80211_rx_status *status, + struct htt_rx_desc *rxd) { + enum ieee80211_band band; u8 cck, rate, rate_idx, bw, sgi, mcs, nss; u8 preamble = 0; + u32 info1, info2, info3; - /* Check if valid fields */ - if (!(info0 & HTT_RX_INDICATION_INFO0_START_VALID)) + /* Band value can't be set as undefined but freq can be 0 - use that to + * determine whether band is provided. + * + * FIXME: Perhaps this can go away if CCK rate reporting is a little + * reworked? + */ + if (!status->freq) return; - preamble = MS(info1, HTT_RX_INDICATION_INFO1_PREAMBLE_TYPE); + band = status->band; + info1 = __le32_to_cpu(rxd->ppdu_start.info1); + info2 = __le32_to_cpu(rxd->ppdu_start.info2); + info3 = __le32_to_cpu(rxd->ppdu_start.info3); + + preamble = MS(info1, RX_PPDU_START_INFO1_PREAMBLE_TYPE); switch (preamble) { case HTT_RX_LEGACY: - cck = info0 & HTT_RX_INDICATION_INFO0_LEGACY_RATE_CCK; - rate = MS(info0, HTT_RX_INDICATION_INFO0_LEGACY_RATE); + cck = info1 & RX_PPDU_START_INFO1_L_SIG_RATE_SELECT; + rate = MS(info1, RX_PPDU_START_INFO1_L_SIG_RATE); rate_idx = 0; if (rate < 0x08 || rate > 0x0F) @@ -734,11 +603,11 @@ static void ath10k_htt_rx_h_rates(struct ath10k *ar, break; case HTT_RX_HT: case HTT_RX_HT_WITH_TXBF: - /* HT-SIG - Table 20-11 in info1 and info2 */ - mcs = info1 & 0x1F; + /* HT-SIG - Table 20-11 in info2 and info3 */ + mcs = info2 & 0x1F; nss = mcs >> 3; - bw = (info1 >> 7) & 1; - sgi = (info2 >> 7) & 1; + bw = (info2 >> 7) & 1; + sgi = (info3 >> 7) & 1; status->rate_idx = mcs; status->flag |= RX_FLAG_HT; @@ -749,12 +618,12 @@ static void ath10k_htt_rx_h_rates(struct ath10k *ar, break; case HTT_RX_VHT: case HTT_RX_VHT_WITH_TXBF: - /* VHT-SIG-A1 in info 1, VHT-SIG-A2 in info2 + /* VHT-SIG-A1 in info2, VHT-SIG-A2 in info3 TODO check this */ - mcs = (info2 >> 4) & 0x0F; - nss = ((info1 >> 10) & 0x07) + 1; - bw = info1 & 3; - sgi = info2 & 1; + mcs = (info3 >> 4) & 0x0F; + nss = ((info2 >> 10) & 0x07) + 1; + bw = info2 & 3; + sgi = info3 & 1; status->rate_idx = mcs; status->vht_nss = nss; @@ -782,41 +651,6 @@ static void ath10k_htt_rx_h_rates(struct ath10k *ar, } } -static void ath10k_htt_rx_h_protected(struct ath10k_htt *htt, - struct ieee80211_rx_status *rx_status, - struct sk_buff *skb, - enum htt_rx_mpdu_encrypt_type enctype, - enum rx_msdu_decap_format fmt, - bool dot11frag) -{ - struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data; - - rx_status->flag &= ~(RX_FLAG_DECRYPTED | - RX_FLAG_IV_STRIPPED | - RX_FLAG_MMIC_STRIPPED); - - if (enctype == HTT_RX_MPDU_ENCRYPT_NONE) - return; - - /* - * There's no explicit rx descriptor flag to indicate whether a given - * frame has been decrypted or not. We're forced to use the decap - * format as an implicit indication. However fragmentation rx is always - * raw and it probably never reports undecrypted raws. - * - * This makes sure sniffed frames are reported as-is without stripping - * the protected flag. - */ - if (fmt == RX_MSDU_DECAP_RAW && !dot11frag) - return; - - rx_status->flag |= RX_FLAG_DECRYPTED | - RX_FLAG_IV_STRIPPED | - RX_FLAG_MMIC_STRIPPED; - hdr->frame_control = __cpu_to_le16(__le16_to_cpu(hdr->frame_control) & - ~IEEE80211_FCTL_PROTECTED); -} - static bool ath10k_htt_rx_h_channel(struct ath10k *ar, struct ieee80211_rx_status *status) { @@ -837,6 +671,72 @@ static bool ath10k_htt_rx_h_channel(struct ath10k *ar, return true; } +static void ath10k_htt_rx_h_signal(struct ath10k *ar, + struct ieee80211_rx_status *status, + struct htt_rx_desc *rxd) +{ + /* FIXME: Get real NF */ + status->signal = ATH10K_DEFAULT_NOISE_FLOOR + + rxd->ppdu_start.rssi_comb; + status->flag &= ~RX_FLAG_NO_SIGNAL_VAL; +} + +static void ath10k_htt_rx_h_mactime(struct ath10k *ar, + struct ieee80211_rx_status *status, + struct htt_rx_desc *rxd) +{ + /* FIXME: TSF is known only at the end of PPDU, in the last MPDU. This + * means all prior MSDUs in a PPDU are reported to mac80211 without the + * TSF. Is it worth holding frames until end of PPDU is known? + * + * FIXME: Can we get/compute 64bit TSF? + */ + status->mactime = __le32_to_cpu(rxd->ppdu_end.tsf_timestamp); + status->flag |= RX_FLAG_MACTIME_END; +} + +static void ath10k_htt_rx_h_ppdu(struct ath10k *ar, + struct sk_buff_head *amsdu, + struct ieee80211_rx_status *status) +{ + struct sk_buff *first; + struct htt_rx_desc *rxd; + bool is_first_ppdu; + bool is_last_ppdu; + + if (skb_queue_empty(amsdu)) + return; + + first = skb_peek(amsdu); + rxd = (void *)first->data - sizeof(*rxd); + + is_first_ppdu = !!(rxd->attention.flags & + __cpu_to_le32(RX_ATTENTION_FLAGS_FIRST_MPDU)); + is_last_ppdu = !!(rxd->attention.flags & + __cpu_to_le32(RX_ATTENTION_FLAGS_LAST_MPDU)); + + if (is_first_ppdu) { + /* New PPDU starts so clear out the old per-PPDU status. */ + status->freq = 0; + status->rate_idx = 0; + status->vht_nss = 0; + status->vht_flag &= ~RX_VHT_FLAG_80MHZ; + status->flag &= ~(RX_FLAG_HT | + RX_FLAG_VHT | + RX_FLAG_SHORT_GI | + RX_FLAG_40MHZ | + RX_FLAG_MACTIME_END); + status->flag |= RX_FLAG_NO_SIGNAL_VAL; + + ath10k_htt_rx_h_signal(ar, status, rxd); + ath10k_htt_rx_h_channel(ar, status); + ath10k_htt_rx_h_rates(ar, status, rxd); + } + + if (is_last_ppdu) + ath10k_htt_rx_h_mactime(ar, status, rxd); +} + static const char * const tid_to_ac[] = { "BE", "BK", @@ -913,187 +813,263 @@ static int ath10k_htt_rx_nwifi_hdrlen(struct ieee80211_hdr *hdr) return round_up(ieee80211_hdrlen(hdr->frame_control), 4); } -static void ath10k_htt_rx_amsdu(struct ath10k_htt *htt, - struct ieee80211_rx_status *rx_status, - struct sk_buff *skb_in) +static void ath10k_htt_rx_h_undecap_raw(struct ath10k *ar, + struct sk_buff *msdu, + struct ieee80211_rx_status *status, + enum htt_rx_mpdu_encrypt_type enctype, + bool is_decrypted) { - struct ath10k *ar = htt->ar; + struct ieee80211_hdr *hdr; struct htt_rx_desc *rxd; - struct sk_buff *skb = skb_in; - struct sk_buff *first; - enum rx_msdu_decap_format fmt; - enum htt_rx_mpdu_encrypt_type enctype; + size_t hdr_len; + size_t crypto_len; + bool is_first; + bool is_last; + + rxd = (void *)msdu->data - sizeof(*rxd); + is_first = !!(rxd->msdu_end.info0 & + __cpu_to_le32(RX_MSDU_END_INFO0_FIRST_MSDU)); + is_last = !!(rxd->msdu_end.info0 & + __cpu_to_le32(RX_MSDU_END_INFO0_LAST_MSDU)); + + /* Delivered decapped frame: + * [802.11 header] + * [crypto param] <-- can be trimmed if !fcs_err && + * !decrypt_err && !peer_idx_invalid + * [amsdu header] <-- only if A-MSDU + * [rfc1042/llc] + * [payload] + * [FCS] <-- at end, needs to be trimmed + */ + + /* This probably shouldn't happen but warn just in case */ + if (unlikely(WARN_ON_ONCE(!is_first))) + return; + + /* This probably shouldn't happen but warn just in case */ + if (unlikely(WARN_ON_ONCE(!(is_first && is_last)))) + return; + + skb_trim(msdu, msdu->len - FCS_LEN); + + /* In most cases this will be true for sniffed frames. It makes sense + * to deliver them as-is without stripping the crypto param. This would + * also make sense for software based decryption (which is not + * implemented in ath10k). + * + * If there's no error then the frame is decrypted. At least that is + * the case for frames that come in via fragmented rx indication. + */ + if (!is_decrypted) + return; + + /* The payload is decrypted so strip crypto params. Start from tail + * since hdr is used to compute some stuff. + */ + + hdr = (void *)msdu->data; + + /* Tail */ + skb_trim(msdu, msdu->len - ath10k_htt_rx_crypto_tail_len(ar, enctype)); + + /* MMIC */ + if (!ieee80211_has_morefrags(hdr->frame_control) && + enctype == HTT_RX_MPDU_ENCRYPT_TKIP_WPA) + skb_trim(msdu, msdu->len - 8); + + /* Head */ + hdr_len = ieee80211_hdrlen(hdr->frame_control); + crypto_len = ath10k_htt_rx_crypto_param_len(ar, enctype); + + memmove((void *)msdu->data + crypto_len, + (void *)msdu->data, hdr_len); + skb_pull(msdu, crypto_len); +} + +static void ath10k_htt_rx_h_undecap_nwifi(struct ath10k *ar, + struct sk_buff *msdu, + struct ieee80211_rx_status *status, + const u8 first_hdr[64]) +{ struct ieee80211_hdr *hdr; - u8 hdr_buf[64], da[ETH_ALEN], sa[ETH_ALEN], *qos; - unsigned int hdr_len; + size_t hdr_len; + u8 da[ETH_ALEN]; + u8 sa[ETH_ALEN]; - rxd = (void *)skb->data - sizeof(*rxd); - enctype = MS(__le32_to_cpu(rxd->mpdu_start.info0), - RX_MPDU_START_INFO0_ENCRYPT_TYPE); + /* Delivered decapped frame: + * [nwifi 802.11 header] <-- replaced with 802.11 hdr + * [rfc1042/llc] + * + * Note: The nwifi header doesn't have QoS Control and is + * (always?) a 3addr frame. + * + * Note2: There's no A-MSDU subframe header. Even if it's part + * of an A-MSDU. + */ - hdr = (struct ieee80211_hdr *)rxd->rx_hdr_status; + /* pull decapped header and copy SA & DA */ + hdr = (struct ieee80211_hdr *)msdu->data; + hdr_len = ath10k_htt_rx_nwifi_hdrlen(hdr); + ether_addr_copy(da, ieee80211_get_DA(hdr)); + ether_addr_copy(sa, ieee80211_get_SA(hdr)); + skb_pull(msdu, hdr_len); + + /* push original 802.11 header */ + hdr = (struct ieee80211_hdr *)first_hdr; hdr_len = ieee80211_hdrlen(hdr->frame_control); - memcpy(hdr_buf, hdr, hdr_len); - hdr = (struct ieee80211_hdr *)hdr_buf; - - first = skb; - while (skb) { - void *decap_hdr; - int len; - - rxd = (void *)skb->data - sizeof(*rxd); - fmt = MS(__le32_to_cpu(rxd->msdu_start.info1), - RX_MSDU_START_INFO1_DECAP_FORMAT); - decap_hdr = (void *)rxd->rx_hdr_status; - - skb->ip_summed = ath10k_htt_rx_get_csum_state(skb); - - /* First frame in an A-MSDU chain has more decapped data. */ - if (skb == first) { - len = round_up(ieee80211_hdrlen(hdr->frame_control), 4); - len += round_up(ath10k_htt_rx_crypto_param_len(ar, - enctype), 4); - decap_hdr += len; - } + memcpy(skb_push(msdu, hdr_len), hdr, hdr_len); - switch (fmt) { - case RX_MSDU_DECAP_RAW: - /* remove trailing FCS */ - skb_trim(skb, skb->len - FCS_LEN); - break; - case RX_MSDU_DECAP_NATIVE_WIFI: - /* pull decapped header and copy SA & DA */ - hdr = (struct ieee80211_hdr *)skb->data; - hdr_len = ath10k_htt_rx_nwifi_hdrlen(hdr); - ether_addr_copy(da, ieee80211_get_DA(hdr)); - ether_addr_copy(sa, ieee80211_get_SA(hdr)); - skb_pull(skb, hdr_len); - - /* push original 802.11 header */ - hdr = (struct ieee80211_hdr *)hdr_buf; - hdr_len = ieee80211_hdrlen(hdr->frame_control); - memcpy(skb_push(skb, hdr_len), hdr, hdr_len); - - /* original A-MSDU header has the bit set but we're - * not including A-MSDU subframe header */ - hdr = (struct ieee80211_hdr *)skb->data; - qos = ieee80211_get_qos_ctl(hdr); - qos[0] &= ~IEEE80211_QOS_CTL_A_MSDU_PRESENT; - - /* original 802.11 header has a different DA and in - * case of 4addr it may also have different SA - */ - ether_addr_copy(ieee80211_get_DA(hdr), da); - ether_addr_copy(ieee80211_get_SA(hdr), sa); - break; - case RX_MSDU_DECAP_ETHERNET2_DIX: - /* strip ethernet header and insert decapped 802.11 - * header, amsdu subframe header and rfc1042 header */ + /* original 802.11 header has a different DA and in + * case of 4addr it may also have different SA + */ + hdr = (struct ieee80211_hdr *)msdu->data; + ether_addr_copy(ieee80211_get_DA(hdr), da); + ether_addr_copy(ieee80211_get_SA(hdr), sa); +} - len = 0; - len += sizeof(struct rfc1042_hdr); - len += sizeof(struct amsdu_subframe_hdr); +static void *ath10k_htt_rx_h_find_rfc1042(struct ath10k *ar, + struct sk_buff *msdu, + enum htt_rx_mpdu_encrypt_type enctype) +{ + struct ieee80211_hdr *hdr; + struct htt_rx_desc *rxd; + size_t hdr_len, crypto_len; + void *rfc1042; + bool is_first, is_last, is_amsdu; - skb_pull(skb, sizeof(struct ethhdr)); - memcpy(skb_push(skb, len), decap_hdr, len); - memcpy(skb_push(skb, hdr_len), hdr, hdr_len); - break; - case RX_MSDU_DECAP_8023_SNAP_LLC: - /* insert decapped 802.11 header making a singly - * A-MSDU */ - memcpy(skb_push(skb, hdr_len), hdr, hdr_len); - break; - } + rxd = (void *)msdu->data - sizeof(*rxd); + hdr = (void *)rxd->rx_hdr_status; - skb_in = skb; - ath10k_htt_rx_h_protected(htt, rx_status, skb_in, enctype, fmt, - false); - skb = skb->next; - skb_in->next = NULL; + is_first = !!(rxd->msdu_end.info0 & + __cpu_to_le32(RX_MSDU_END_INFO0_FIRST_MSDU)); + is_last = !!(rxd->msdu_end.info0 & + __cpu_to_le32(RX_MSDU_END_INFO0_LAST_MSDU)); + is_amsdu = !(is_first && is_last); - if (skb) - rx_status->flag |= RX_FLAG_AMSDU_MORE; - else - rx_status->flag &= ~RX_FLAG_AMSDU_MORE; + rfc1042 = hdr; + + if (is_first) { + hdr_len = ieee80211_hdrlen(hdr->frame_control); + crypto_len = ath10k_htt_rx_crypto_param_len(ar, enctype); - ath10k_process_rx(htt->ar, rx_status, skb_in); + rfc1042 += round_up(hdr_len, 4) + + round_up(crypto_len, 4); } - /* FIXME: It might be nice to re-assemble the A-MSDU when there's a - * monitor interface active for sniffing purposes. */ + if (is_amsdu) + rfc1042 += sizeof(struct amsdu_subframe_hdr); + + return rfc1042; } -static void ath10k_htt_rx_msdu(struct ath10k_htt *htt, - struct ieee80211_rx_status *rx_status, - struct sk_buff *skb) +static void ath10k_htt_rx_h_undecap_eth(struct ath10k *ar, + struct sk_buff *msdu, + struct ieee80211_rx_status *status, + const u8 first_hdr[64], + enum htt_rx_mpdu_encrypt_type enctype) { - struct ath10k *ar = htt->ar; - struct htt_rx_desc *rxd; struct ieee80211_hdr *hdr; - enum rx_msdu_decap_format fmt; - enum htt_rx_mpdu_encrypt_type enctype; - int hdr_len; + struct ethhdr *eth; + size_t hdr_len; void *rfc1042; + u8 da[ETH_ALEN]; + u8 sa[ETH_ALEN]; - /* This shouldn't happen. If it does than it may be a FW bug. */ - if (skb->next) { - ath10k_warn(ar, "htt rx received chained non A-MSDU frame\n"); - ath10k_htt_rx_free_msdu_chain(skb->next); - skb->next = NULL; - } + /* Delivered decapped frame: + * [eth header] <-- replaced with 802.11 hdr & rfc1042/llc + * [payload] + */ - rxd = (void *)skb->data - sizeof(*rxd); - fmt = MS(__le32_to_cpu(rxd->msdu_start.info1), - RX_MSDU_START_INFO1_DECAP_FORMAT); - enctype = MS(__le32_to_cpu(rxd->mpdu_start.info0), - RX_MPDU_START_INFO0_ENCRYPT_TYPE); - hdr = (struct ieee80211_hdr *)rxd->rx_hdr_status; + rfc1042 = ath10k_htt_rx_h_find_rfc1042(ar, msdu, enctype); + if (WARN_ON_ONCE(!rfc1042)) + return; + + /* pull decapped header and copy SA & DA */ + eth = (struct ethhdr *)msdu->data; + ether_addr_copy(da, eth->h_dest); + ether_addr_copy(sa, eth->h_source); + skb_pull(msdu, sizeof(struct ethhdr)); + + /* push rfc1042/llc/snap */ + memcpy(skb_push(msdu, sizeof(struct rfc1042_hdr)), rfc1042, + sizeof(struct rfc1042_hdr)); + + /* push original 802.11 header */ + hdr = (struct ieee80211_hdr *)first_hdr; hdr_len = ieee80211_hdrlen(hdr->frame_control); + memcpy(skb_push(msdu, hdr_len), hdr, hdr_len); + + /* original 802.11 header has a different DA and in + * case of 4addr it may also have different SA + */ + hdr = (struct ieee80211_hdr *)msdu->data; + ether_addr_copy(ieee80211_get_DA(hdr), da); + ether_addr_copy(ieee80211_get_SA(hdr), sa); +} + +static void ath10k_htt_rx_h_undecap_snap(struct ath10k *ar, + struct sk_buff *msdu, + struct ieee80211_rx_status *status, + const u8 first_hdr[64]) +{ + struct ieee80211_hdr *hdr; + size_t hdr_len; - skb->ip_summed = ath10k_htt_rx_get_csum_state(skb); + /* Delivered decapped frame: + * [amsdu header] <-- replaced with 802.11 hdr + * [rfc1042/llc] + * [payload] + */ + + skb_pull(msdu, sizeof(struct amsdu_subframe_hdr)); + + hdr = (struct ieee80211_hdr *)first_hdr; + hdr_len = ieee80211_hdrlen(hdr->frame_control); + memcpy(skb_push(msdu, hdr_len), hdr, hdr_len); +} - switch (fmt) { +static void ath10k_htt_rx_h_undecap(struct ath10k *ar, + struct sk_buff *msdu, + struct ieee80211_rx_status *status, + u8 first_hdr[64], + enum htt_rx_mpdu_encrypt_type enctype, + bool is_decrypted) +{ + struct htt_rx_desc *rxd; + enum rx_msdu_decap_format decap; + struct ieee80211_hdr *hdr; + + /* First msdu's decapped header: + * [802.11 header] <-- padded to 4 bytes long + * [crypto param] <-- padded to 4 bytes long + * [amsdu header] <-- only if A-MSDU + * [rfc1042/llc] + * + * Other (2nd, 3rd, ..) msdu's decapped header: + * [amsdu header] <-- only if A-MSDU + * [rfc1042/llc] + */ + + rxd = (void *)msdu->data - sizeof(*rxd); + hdr = (void *)rxd->rx_hdr_status; + decap = MS(__le32_to_cpu(rxd->msdu_start.info1), + RX_MSDU_START_INFO1_DECAP_FORMAT); + + switch (decap) { case RX_MSDU_DECAP_RAW: - /* remove trailing FCS */ - skb_trim(skb, skb->len - FCS_LEN); + ath10k_htt_rx_h_undecap_raw(ar, msdu, status, enctype, + is_decrypted); break; case RX_MSDU_DECAP_NATIVE_WIFI: - /* Pull decapped header */ - hdr = (struct ieee80211_hdr *)skb->data; - hdr_len = ath10k_htt_rx_nwifi_hdrlen(hdr); - skb_pull(skb, hdr_len); - - /* Push original header */ - hdr = (struct ieee80211_hdr *)rxd->rx_hdr_status; - hdr_len = ieee80211_hdrlen(hdr->frame_control); - memcpy(skb_push(skb, hdr_len), hdr, hdr_len); + ath10k_htt_rx_h_undecap_nwifi(ar, msdu, status, first_hdr); break; case RX_MSDU_DECAP_ETHERNET2_DIX: - /* strip ethernet header and insert decapped 802.11 header and - * rfc1042 header */ - - rfc1042 = hdr; - rfc1042 += roundup(hdr_len, 4); - rfc1042 += roundup(ath10k_htt_rx_crypto_param_len(ar, - enctype), 4); - - skb_pull(skb, sizeof(struct ethhdr)); - memcpy(skb_push(skb, sizeof(struct rfc1042_hdr)), - rfc1042, sizeof(struct rfc1042_hdr)); - memcpy(skb_push(skb, hdr_len), hdr, hdr_len); + ath10k_htt_rx_h_undecap_eth(ar, msdu, status, first_hdr, enctype); break; case RX_MSDU_DECAP_8023_SNAP_LLC: - /* remove A-MSDU subframe header and insert - * decapped 802.11 header. rfc1042 header is already there */ - - skb_pull(skb, sizeof(struct amsdu_subframe_hdr)); - memcpy(skb_push(skb, hdr_len), hdr, hdr_len); + ath10k_htt_rx_h_undecap_snap(ar, msdu, status, first_hdr); break; } - - ath10k_htt_rx_h_protected(htt, rx_status, skb, enctype, fmt, false); - - ath10k_process_rx(htt->ar, rx_status, skb); } static int ath10k_htt_rx_get_csum_state(struct sk_buff *skb) @@ -1127,10 +1103,128 @@ static int ath10k_htt_rx_get_csum_state(struct sk_buff *skb) return CHECKSUM_UNNECESSARY; } -static int ath10k_unchain_msdu(struct sk_buff *msdu_head) +static void ath10k_htt_rx_h_csum_offload(struct sk_buff *msdu) { - struct sk_buff *next = msdu_head->next; - struct sk_buff *to_free = next; + msdu->ip_summed = ath10k_htt_rx_get_csum_state(msdu); +} + +static void ath10k_htt_rx_h_mpdu(struct ath10k *ar, + struct sk_buff_head *amsdu, + struct ieee80211_rx_status *status) +{ + struct sk_buff *first; + struct sk_buff *last; + struct sk_buff *msdu; + struct htt_rx_desc *rxd; + struct ieee80211_hdr *hdr; + enum htt_rx_mpdu_encrypt_type enctype; + u8 first_hdr[64]; + u8 *qos; + size_t hdr_len; + bool has_fcs_err; + bool has_crypto_err; + bool has_tkip_err; + bool has_peer_idx_invalid; + bool is_decrypted; + u32 attention; + + if (skb_queue_empty(amsdu)) + return; + + first = skb_peek(amsdu); + rxd = (void *)first->data - sizeof(*rxd); + + enctype = MS(__le32_to_cpu(rxd->mpdu_start.info0), + RX_MPDU_START_INFO0_ENCRYPT_TYPE); + + /* First MSDU's Rx descriptor in an A-MSDU contains full 802.11 + * decapped header. It'll be used for undecapping of each MSDU. + */ + hdr = (void *)rxd->rx_hdr_status; + hdr_len = ieee80211_hdrlen(hdr->frame_control); + memcpy(first_hdr, hdr, hdr_len); + + /* Each A-MSDU subframe will use the original header as the base and be + * reported as a separate MSDU so strip the A-MSDU bit from QoS Ctl. + */ + hdr = (void *)first_hdr; + qos = ieee80211_get_qos_ctl(hdr); + qos[0] &= ~IEEE80211_QOS_CTL_A_MSDU_PRESENT; + + /* Some attention flags are valid only in the last MSDU. */ + last = skb_peek_tail(amsdu); + rxd = (void *)last->data - sizeof(*rxd); + attention = __le32_to_cpu(rxd->attention.flags); + + has_fcs_err = !!(attention & RX_ATTENTION_FLAGS_FCS_ERR); + has_crypto_err = !!(attention & RX_ATTENTION_FLAGS_DECRYPT_ERR); + has_tkip_err = !!(attention & RX_ATTENTION_FLAGS_TKIP_MIC_ERR); + has_peer_idx_invalid = !!(attention & RX_ATTENTION_FLAGS_PEER_IDX_INVALID); + + /* Note: If hardware captures an encrypted frame that it can't decrypt, + * e.g. due to fcs error, missing peer or invalid key data it will + * report the frame as raw. + */ + is_decrypted = (enctype != HTT_RX_MPDU_ENCRYPT_NONE && + !has_fcs_err && + !has_crypto_err && + !has_peer_idx_invalid); + + /* Clear per-MPDU flags while leaving per-PPDU flags intact. */ + status->flag &= ~(RX_FLAG_FAILED_FCS_CRC | + RX_FLAG_MMIC_ERROR | + RX_FLAG_DECRYPTED | + RX_FLAG_IV_STRIPPED | + RX_FLAG_MMIC_STRIPPED); + + if (has_fcs_err) + status->flag |= RX_FLAG_FAILED_FCS_CRC; + + if (has_tkip_err) + status->flag |= RX_FLAG_MMIC_ERROR; + + if (is_decrypted) + status->flag |= RX_FLAG_DECRYPTED | + RX_FLAG_IV_STRIPPED | + RX_FLAG_MMIC_STRIPPED; + + skb_queue_walk(amsdu, msdu) { + ath10k_htt_rx_h_csum_offload(msdu); + ath10k_htt_rx_h_undecap(ar, msdu, status, first_hdr, enctype, + is_decrypted); + + /* Undecapping involves copying the original 802.11 header back + * to sk_buff. If frame is protected and hardware has decrypted + * it then remove the protected bit. + */ + if (!is_decrypted) + continue; + + hdr = (void *)msdu->data; + hdr->frame_control &= ~__cpu_to_le16(IEEE80211_FCTL_PROTECTED); + } +} + +static void ath10k_htt_rx_h_deliver(struct ath10k *ar, + struct sk_buff_head *amsdu, + struct ieee80211_rx_status *status) +{ + struct sk_buff *msdu; + + while ((msdu = __skb_dequeue(amsdu))) { + /* Setup per-MSDU flags */ + if (skb_queue_empty(amsdu)) + status->flag &= ~RX_FLAG_AMSDU_MORE; + else + status->flag |= RX_FLAG_AMSDU_MORE; + + ath10k_process_rx(ar, status, msdu); + } +} + +static int ath10k_unchain_msdu(struct sk_buff_head *amsdu) +{ + struct sk_buff *skb, *first; int space; int total_len = 0; @@ -1141,99 +1235,142 @@ static int ath10k_unchain_msdu(struct sk_buff *msdu_head) * skb? */ - msdu_head->next = NULL; + first = __skb_dequeue(amsdu); /* Allocate total length all at once. */ - while (next) { - total_len += next->len; - next = next->next; - } + skb_queue_walk(amsdu, skb) + total_len += skb->len; - space = total_len - skb_tailroom(msdu_head); + space = total_len - skb_tailroom(first); if ((space > 0) && - (pskb_expand_head(msdu_head, 0, space, GFP_ATOMIC) < 0)) { + (pskb_expand_head(first, 0, space, GFP_ATOMIC) < 0)) { /* TODO: bump some rx-oom error stat */ /* put it back together so we can free the * whole list at once. */ - msdu_head->next = to_free; + __skb_queue_head(amsdu, first); return -1; } /* Walk list again, copying contents into * msdu_head */ - next = to_free; - while (next) { - skb_copy_from_linear_data(next, skb_put(msdu_head, next->len), - next->len); - next = next->next; + while ((skb = __skb_dequeue(amsdu))) { + skb_copy_from_linear_data(skb, skb_put(first, skb->len), + skb->len); + dev_kfree_skb_any(skb); } - /* If here, we have consolidated skb. Free the - * fragments and pass the main skb on up the - * stack. - */ - ath10k_htt_rx_free_msdu_chain(to_free); + __skb_queue_head(amsdu, first); return 0; } -static bool ath10k_htt_rx_amsdu_allowed(struct ath10k_htt *htt, - struct sk_buff *head, - bool channel_set, - u32 attention) +static void ath10k_htt_rx_h_unchain(struct ath10k *ar, + struct sk_buff_head *amsdu, + bool chained) { - struct ath10k *ar = htt->ar; + struct sk_buff *first; + struct htt_rx_desc *rxd; + enum rx_msdu_decap_format decap; - if (head->len == 0) { - ath10k_dbg(ar, ATH10K_DBG_HTT, - "htt rx dropping due to zero-len\n"); - return false; - } + first = skb_peek(amsdu); + rxd = (void *)first->data - sizeof(*rxd); + decap = MS(__le32_to_cpu(rxd->msdu_start.info1), + RX_MSDU_START_INFO1_DECAP_FORMAT); - if (attention & RX_ATTENTION_FLAGS_DECRYPT_ERR) { - ath10k_dbg(ar, ATH10K_DBG_HTT, - "htt rx dropping due to decrypt-err\n"); - return false; + if (!chained) + return; + + /* FIXME: Current unchaining logic can only handle simple case of raw + * msdu chaining. If decapping is other than raw the chaining may be + * more complex and this isn't handled by the current code. Don't even + * try re-constructing such frames - it'll be pretty much garbage. + */ + if (decap != RX_MSDU_DECAP_RAW || + skb_queue_len(amsdu) != 1 + rxd->frag_info.ring2_more_count) { + __skb_queue_purge(amsdu); + return; } - if (!channel_set) { - ath10k_warn(ar, "no channel configured; ignoring frame!\n"); + ath10k_unchain_msdu(amsdu); +} + +static bool ath10k_htt_rx_amsdu_allowed(struct ath10k *ar, + struct sk_buff_head *amsdu, + struct ieee80211_rx_status *rx_status) +{ + struct sk_buff *msdu; + struct htt_rx_desc *rxd; + bool is_mgmt; + bool has_fcs_err; + + msdu = skb_peek(amsdu); + rxd = (void *)msdu->data - sizeof(*rxd); + + /* FIXME: It might be a good idea to do some fuzzy-testing to drop + * invalid/dangerous frames. + */ + + if (!rx_status->freq) { + ath10k_warn(ar, "no channel configured; ignoring frame(s)!\n"); return false; } - /* Skip mgmt frames while we handle this in WMI */ - if (attention & RX_ATTENTION_FLAGS_MGMT_TYPE) { + is_mgmt = !!(rxd->attention.flags & + __cpu_to_le32(RX_ATTENTION_FLAGS_MGMT_TYPE)); + has_fcs_err = !!(rxd->attention.flags & + __cpu_to_le32(RX_ATTENTION_FLAGS_FCS_ERR)); + + /* Management frames are handled via WMI events. The pros of such + * approach is that channel is explicitly provided in WMI events + * whereas HTT doesn't provide channel information for Rxed frames. + * + * However some firmware revisions don't report corrupted frames via + * WMI so don't drop them. + */ + if (is_mgmt && !has_fcs_err) { ath10k_dbg(ar, ATH10K_DBG_HTT, "htt rx mgmt ctrl\n"); return false; } - if (test_bit(ATH10K_CAC_RUNNING, &htt->ar->dev_flags)) { - ath10k_dbg(ar, ATH10K_DBG_HTT, - "htt rx CAC running\n"); + if (test_bit(ATH10K_CAC_RUNNING, &ar->dev_flags)) { + ath10k_dbg(ar, ATH10K_DBG_HTT, "htt rx cac running\n"); return false; } return true; } +static void ath10k_htt_rx_h_filter(struct ath10k *ar, + struct sk_buff_head *amsdu, + struct ieee80211_rx_status *rx_status) +{ + if (skb_queue_empty(amsdu)) + return; + + if (ath10k_htt_rx_amsdu_allowed(ar, amsdu, rx_status)) + return; + + __skb_queue_purge(amsdu); +} + static void ath10k_htt_rx_handler(struct ath10k_htt *htt, struct htt_rx_indication *rx) { struct ath10k *ar = htt->ar; struct ieee80211_rx_status *rx_status = &htt->rx_status; struct htt_rx_indication_mpdu_range *mpdu_ranges; - struct ieee80211_hdr *hdr; + struct sk_buff_head amsdu; int num_mpdu_ranges; - u32 attention; int fw_desc_len; u8 *fw_desc; - bool channel_set; - int i, j; - int ret; + int i, ret, mpdu_count = 0; lockdep_assert_held(&htt->rx_ring.lock); + if (htt->rx_confused) + return; + fw_desc_len = __le16_to_cpu(rx->prefix.fw_rx_desc_bytes); fw_desc = (u8 *)&rx->fw_desc; @@ -1241,85 +1378,33 @@ static void ath10k_htt_rx_handler(struct ath10k_htt *htt, HTT_RX_INDICATION_INFO1_NUM_MPDU_RANGES); mpdu_ranges = htt_rx_ind_get_mpdu_ranges(rx); - /* Fill this once, while this is per-ppdu */ - if (rx->ppdu.info0 & HTT_RX_INDICATION_INFO0_START_VALID) { - memset(rx_status, 0, sizeof(*rx_status)); - rx_status->signal = ATH10K_DEFAULT_NOISE_FLOOR + - rx->ppdu.combined_rssi; - } - - if (rx->ppdu.info0 & HTT_RX_INDICATION_INFO0_END_VALID) { - /* TSF available only in 32-bit */ - rx_status->mactime = __le32_to_cpu(rx->ppdu.tsf) & 0xffffffff; - rx_status->flag |= RX_FLAG_MACTIME_END; - } - - channel_set = ath10k_htt_rx_h_channel(htt->ar, rx_status); - - if (channel_set) { - ath10k_htt_rx_h_rates(htt->ar, rx_status->band, - rx->ppdu.info0, - __le32_to_cpu(rx->ppdu.info1), - __le32_to_cpu(rx->ppdu.info2), - rx_status); - } - ath10k_dbg_dump(ar, ATH10K_DBG_HTT_DUMP, NULL, "htt rx ind: ", rx, sizeof(*rx) + (sizeof(struct htt_rx_indication_mpdu_range) * num_mpdu_ranges)); - for (i = 0; i < num_mpdu_ranges; i++) { - for (j = 0; j < mpdu_ranges[i].mpdu_count; j++) { - struct sk_buff *msdu_head, *msdu_tail; - - attention = 0; - msdu_head = NULL; - msdu_tail = NULL; - ret = ath10k_htt_rx_amsdu_pop(htt, - &fw_desc, - &fw_desc_len, - &msdu_head, - &msdu_tail, - &attention); - - if (ret < 0) { - ath10k_warn(ar, "failed to pop amsdu from htt rx ring %d\n", - ret); - ath10k_htt_rx_free_msdu_chain(msdu_head); - continue; - } - - if (!ath10k_htt_rx_amsdu_allowed(htt, msdu_head, - channel_set, - attention)) { - ath10k_htt_rx_free_msdu_chain(msdu_head); - continue; - } - - if (ret > 0 && - ath10k_unchain_msdu(msdu_head) < 0) { - ath10k_htt_rx_free_msdu_chain(msdu_head); - continue; - } - - if (attention & RX_ATTENTION_FLAGS_FCS_ERR) - rx_status->flag |= RX_FLAG_FAILED_FCS_CRC; - else - rx_status->flag &= ~RX_FLAG_FAILED_FCS_CRC; - - if (attention & RX_ATTENTION_FLAGS_TKIP_MIC_ERR) - rx_status->flag |= RX_FLAG_MMIC_ERROR; - else - rx_status->flag &= ~RX_FLAG_MMIC_ERROR; - - hdr = ath10k_htt_rx_skb_get_hdr(msdu_head); - - if (ath10k_htt_rx_hdr_is_amsdu(hdr)) - ath10k_htt_rx_amsdu(htt, rx_status, msdu_head); - else - ath10k_htt_rx_msdu(htt, rx_status, msdu_head); + for (i = 0; i < num_mpdu_ranges; i++) + mpdu_count += mpdu_ranges[i].mpdu_count; + + while (mpdu_count--) { + __skb_queue_head_init(&amsdu); + ret = ath10k_htt_rx_amsdu_pop(htt, &fw_desc, + &fw_desc_len, &amsdu); + if (ret < 0) { + ath10k_warn(ar, "rx ring became corrupted: %d\n", ret); + __skb_queue_purge(&amsdu); + /* FIXME: It's probably a good idea to reboot the + * device instead of leaving it inoperable. + */ + htt->rx_confused = true; + break; } + + ath10k_htt_rx_h_ppdu(ar, &amsdu, rx_status); + ath10k_htt_rx_h_unchain(ar, &amsdu, ret > 0); + ath10k_htt_rx_h_filter(ar, &amsdu, rx_status); + ath10k_htt_rx_h_mpdu(ar, &amsdu, rx_status); + ath10k_htt_rx_h_deliver(ar, &amsdu, rx_status); } tasklet_schedule(&htt->rx_replenish_task); @@ -1329,30 +1414,20 @@ static void ath10k_htt_rx_frag_handler(struct ath10k_htt *htt, struct htt_rx_fragment_indication *frag) { struct ath10k *ar = htt->ar; - struct sk_buff *msdu_head, *msdu_tail; - enum htt_rx_mpdu_encrypt_type enctype; - struct htt_rx_desc *rxd; - enum rx_msdu_decap_format fmt; struct ieee80211_rx_status *rx_status = &htt->rx_status; - struct ieee80211_hdr *hdr; + struct sk_buff_head amsdu; int ret; - bool tkip_mic_err; - bool decrypt_err; u8 *fw_desc; - int fw_desc_len, hdrlen, paramlen; - int trim; - u32 attention = 0; + int fw_desc_len; fw_desc_len = __le16_to_cpu(frag->fw_rx_desc_bytes); fw_desc = (u8 *)frag->fw_msdu_rx_desc; - msdu_head = NULL; - msdu_tail = NULL; + __skb_queue_head_init(&amsdu); spin_lock_bh(&htt->rx_ring.lock); ret = ath10k_htt_rx_amsdu_pop(htt, &fw_desc, &fw_desc_len, - &msdu_head, &msdu_tail, - &attention); + &amsdu); spin_unlock_bh(&htt->rx_ring.lock); tasklet_schedule(&htt->rx_replenish_task); @@ -1362,77 +1437,21 @@ static void ath10k_htt_rx_frag_handler(struct ath10k_htt *htt, if (ret) { ath10k_warn(ar, "failed to pop amsdu from httr rx ring for fragmented rx %d\n", ret); - ath10k_htt_rx_free_msdu_chain(msdu_head); + __skb_queue_purge(&amsdu); return; } - /* FIXME: implement signal strength */ - rx_status->flag |= RX_FLAG_NO_SIGNAL_VAL; - - hdr = (struct ieee80211_hdr *)msdu_head->data; - rxd = (void *)msdu_head->data - sizeof(*rxd); - tkip_mic_err = !!(attention & RX_ATTENTION_FLAGS_TKIP_MIC_ERR); - decrypt_err = !!(attention & RX_ATTENTION_FLAGS_DECRYPT_ERR); - fmt = MS(__le32_to_cpu(rxd->msdu_start.info1), - RX_MSDU_START_INFO1_DECAP_FORMAT); - - if (fmt != RX_MSDU_DECAP_RAW) { - ath10k_warn(ar, "we dont support non-raw fragmented rx yet\n"); - dev_kfree_skb_any(msdu_head); - goto end; - } - - enctype = MS(__le32_to_cpu(rxd->mpdu_start.info0), - RX_MPDU_START_INFO0_ENCRYPT_TYPE); - ath10k_htt_rx_h_protected(htt, rx_status, msdu_head, enctype, fmt, - true); - msdu_head->ip_summed = ath10k_htt_rx_get_csum_state(msdu_head); - - if (tkip_mic_err) - ath10k_warn(ar, "tkip mic error\n"); - - if (decrypt_err) { - ath10k_warn(ar, "decryption err in fragmented rx\n"); - dev_kfree_skb_any(msdu_head); - goto end; - } - - if (enctype != HTT_RX_MPDU_ENCRYPT_NONE) { - hdrlen = ieee80211_hdrlen(hdr->frame_control); - paramlen = ath10k_htt_rx_crypto_param_len(ar, enctype); - - /* It is more efficient to move the header than the payload */ - memmove((void *)msdu_head->data + paramlen, - (void *)msdu_head->data, - hdrlen); - skb_pull(msdu_head, paramlen); - hdr = (struct ieee80211_hdr *)msdu_head->data; - } - - /* remove trailing FCS */ - trim = 4; - - /* remove crypto trailer */ - trim += ath10k_htt_rx_crypto_tail_len(ar, enctype); - - /* last fragment of TKIP frags has MIC */ - if (!ieee80211_has_morefrags(hdr->frame_control) && - enctype == HTT_RX_MPDU_ENCRYPT_TKIP_WPA) - trim += MICHAEL_MIC_LEN; - - if (trim > msdu_head->len) { - ath10k_warn(ar, "htt rx fragment: trailer longer than the frame itself? drop\n"); - dev_kfree_skb_any(msdu_head); - goto end; + if (skb_queue_len(&amsdu) != 1) { + ath10k_warn(ar, "failed to pop frag amsdu: too many msdus\n"); + __skb_queue_purge(&amsdu); + return; } - skb_trim(msdu_head, msdu_head->len - trim); - - ath10k_dbg_dump(ar, ATH10K_DBG_HTT_DUMP, NULL, "htt rx frag mpdu: ", - msdu_head->data, msdu_head->len); - ath10k_process_rx(htt->ar, rx_status, msdu_head); + ath10k_htt_rx_h_ppdu(ar, &amsdu, rx_status); + ath10k_htt_rx_h_filter(ar, &amsdu, rx_status); + ath10k_htt_rx_h_mpdu(ar, &amsdu, rx_status); + ath10k_htt_rx_h_deliver(ar, &amsdu, rx_status); -end: if (fw_desc_len > 0) { ath10k_dbg(ar, ATH10K_DBG_HTT, "expecting more fragmented rx in one indication %d\n", diff --git a/drivers/net/wireless/ath/ath10k/htt_tx.c b/drivers/net/wireless/ath/ath10k/htt_tx.c index 5b7e42f7377..4bc51d8a14a 100644 --- a/drivers/net/wireless/ath/ath10k/htt_tx.c +++ b/drivers/net/wireless/ath/ath10k/htt_tx.c @@ -554,13 +554,14 @@ int ath10k_htt_tx(struct ath10k_htt *htt, struct sk_buff *msdu) skb_cb->htt.txbuf->cmd_tx.len = __cpu_to_le16(msdu->len); skb_cb->htt.txbuf->cmd_tx.id = __cpu_to_le16(msdu_id); skb_cb->htt.txbuf->cmd_tx.frags_paddr = __cpu_to_le32(frags_paddr); - skb_cb->htt.txbuf->cmd_tx.peerid = __cpu_to_le32(HTT_INVALID_PEERID); + skb_cb->htt.txbuf->cmd_tx.peerid = __cpu_to_le16(HTT_INVALID_PEERID); + skb_cb->htt.txbuf->cmd_tx.freq = __cpu_to_le16(skb_cb->htt.freq); trace_ath10k_htt_tx(ar, msdu_id, msdu->len, vdev_id, tid); ath10k_dbg(ar, ATH10K_DBG_HTT, - "htt tx flags0 %hhu flags1 %hu len %d id %hu frags_paddr %08x, msdu_paddr %08x vdev %hhu tid %hhu\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, - (u32)skb_cb->paddr, vdev_id, tid); + (u32)skb_cb->paddr, vdev_id, tid, skb_cb->htt.freq); ath10k_dbg_dump(ar, ATH10K_DBG_HTT_DUMP, NULL, "htt tx msdu: ", msdu->data, msdu->len); trace_ath10k_tx_hdr(ar, msdu->data, msdu->len); diff --git a/drivers/net/wireless/ath/ath10k/hw.h b/drivers/net/wireless/ath/ath10k/hw.h index 392c2501d0a..dfedfd0e0f3 100644 --- a/drivers/net/wireless/ath/ath10k/hw.h +++ b/drivers/net/wireless/ath/ath10k/hw.h @@ -97,11 +97,13 @@ struct ath10k_pktlog_hdr { #define TARGET_DMA_BURST_SIZE 0 #define TARGET_MAC_AGGR_DELIM 0 #define TARGET_AST_SKID_LIMIT 16 -#define TARGET_NUM_PEERS 16 +#define TARGET_NUM_STATIONS 16 +#define TARGET_NUM_PEERS ((TARGET_NUM_STATIONS) + \ + (TARGET_NUM_VDEVS)) #define TARGET_NUM_OFFLOAD_PEERS 0 #define TARGET_NUM_OFFLOAD_REORDER_BUFS 0 #define TARGET_NUM_PEER_KEYS 2 -#define TARGET_NUM_TIDS (2 * ((TARGET_NUM_PEERS) + (TARGET_NUM_VDEVS))) +#define TARGET_NUM_TIDS ((TARGET_NUM_PEERS) * 2) #define TARGET_TX_CHAIN_MASK (BIT(0) | BIT(1) | BIT(2)) #define TARGET_RX_CHAIN_MASK (BIT(0) | BIT(1) | BIT(2)) #define TARGET_RX_TIMEOUT_LO_PRI 100 @@ -132,12 +134,15 @@ struct ath10k_pktlog_hdr { #define TARGET_10X_DMA_BURST_SIZE 0 #define TARGET_10X_MAC_AGGR_DELIM 0 #define TARGET_10X_AST_SKID_LIMIT 16 -#define TARGET_10X_NUM_PEERS (128 + (TARGET_10X_NUM_VDEVS)) -#define TARGET_10X_NUM_PEERS_MAX 128 +#define TARGET_10X_NUM_STATIONS 128 +#define TARGET_10X_NUM_PEERS ((TARGET_10X_NUM_STATIONS) + \ + (TARGET_10X_NUM_VDEVS)) #define TARGET_10X_NUM_OFFLOAD_PEERS 0 #define TARGET_10X_NUM_OFFLOAD_REORDER_BUFS 0 #define TARGET_10X_NUM_PEER_KEYS 2 -#define TARGET_10X_NUM_TIDS 256 +#define TARGET_10X_NUM_TIDS_MAX 256 +#define TARGET_10X_NUM_TIDS min((TARGET_10X_NUM_TIDS_MAX), \ + (TARGET_10X_NUM_PEERS) * 2) #define TARGET_10X_TX_CHAIN_MASK (BIT(0) | BIT(1) | BIT(2)) #define TARGET_10X_RX_CHAIN_MASK (BIT(0) | BIT(1) | BIT(2)) #define TARGET_10X_RX_TIMEOUT_LO_PRI 100 diff --git a/drivers/net/wireless/ath/ath10k/mac.c b/drivers/net/wireless/ath/ath10k/mac.c index 1245ac8c5c6..c4005670cba 100644 --- a/drivers/net/wireless/ath/ath10k/mac.c +++ b/drivers/net/wireless/ath/ath10k/mac.c @@ -136,7 +136,9 @@ static int ath10k_install_peer_wep_keys(struct ath10k_vif *arvif, if (ret) return ret; + spin_lock_bh(&ar->data_lock); peer->keys[i] = arvif->wep_keys[i]; + spin_unlock_bh(&ar->data_lock); } return 0; @@ -173,12 +175,39 @@ static int ath10k_clear_peer_keys(struct ath10k_vif *arvif, ath10k_warn(ar, "failed to remove peer wep key %d: %d\n", i, ret); + spin_lock_bh(&ar->data_lock); peer->keys[i] = NULL; + spin_unlock_bh(&ar->data_lock); } return first_errno; } +bool ath10k_mac_is_peer_wep_key_set(struct ath10k *ar, const u8 *addr, + u8 keyidx) +{ + struct ath10k_peer *peer; + int i; + + lockdep_assert_held(&ar->data_lock); + + /* We don't know which vdev this peer belongs to, + * since WMI doesn't give us that information. + * + * FIXME: multi-bss needs to be handled. + */ + peer = ath10k_peer_find(ar, 0, addr); + if (!peer) + return false; + + for (i = 0; i < ARRAY_SIZE(peer->keys); i++) { + if (peer->keys[i] && peer->keys[i]->keyidx == keyidx) + return true; + } + + return false; +} + static int ath10k_clear_vdev_key(struct ath10k_vif *arvif, struct ieee80211_key_conf *key) { @@ -326,6 +355,9 @@ static int ath10k_peer_create(struct ath10k *ar, u32 vdev_id, const u8 *addr) lockdep_assert_held(&ar->conf_mutex); + if (ar->num_peers >= ar->max_num_peers) + return -ENOBUFS; + ret = ath10k_wmi_peer_create(ar, vdev_id, addr); if (ret) { ath10k_warn(ar, "failed to create wmi peer %pM on vdev %i: %i\n", @@ -339,9 +371,8 @@ static int ath10k_peer_create(struct ath10k *ar, u32 vdev_id, const u8 *addr) addr, vdev_id, ret); return ret; } - spin_lock_bh(&ar->data_lock); + ar->num_peers++; - spin_unlock_bh(&ar->data_lock); return 0; } @@ -391,15 +422,11 @@ static int ath10k_mac_set_kickout(struct ath10k_vif *arvif) return 0; } -static int ath10k_mac_set_rts(struct ath10k_vif *arvif, u32 value) +static int ath10k_mac_set_rts(struct ath10k_vif *arvif, u32 value) { struct ath10k *ar = arvif->ar; u32 vdev_param; - if (value != 0xFFFFFFFF) - value = min_t(u32, arvif->ar->hw->wiphy->rts_threshold, - ATH10K_RTS_MAX); - vdev_param = ar->wmi.vdev_param->rts_threshold; return ath10k_wmi_vdev_set_param(ar, arvif->vdev_id, vdev_param, value); } @@ -432,9 +459,7 @@ static int ath10k_peer_delete(struct ath10k *ar, u32 vdev_id, const u8 *addr) if (ret) return ret; - spin_lock_bh(&ar->data_lock); ar->num_peers--; - spin_unlock_bh(&ar->data_lock); return 0; } @@ -471,8 +496,10 @@ static void ath10k_peer_cleanup_all(struct ath10k *ar) list_del(&peer->list); kfree(peer); } - ar->num_peers = 0; spin_unlock_bh(&ar->data_lock); + + ar->num_peers = 0; + ar->num_stations = 0; } /************************/ @@ -1997,6 +2024,18 @@ static void ath10k_tx_h_add_p2p_noa_ie(struct ath10k *ar, } } +static bool ath10k_mac_need_offchan_tx_work(struct ath10k *ar) +{ + /* FIXME: Not really sure since when the behaviour changed. At some + * point new firmware stopped requiring creation of peer entries for + * offchannel tx (and actually creating them causes issues with wmi-htc + * tx credit replenishment and reliability). Assuming it's at least 3.4 + * because that's when the `freq` was introduced to TX_FRM HTT command. + */ + return !(ar->htt.target_version_major >= 3 && + ar->htt.target_version_minor >= 4); +} + static void ath10k_tx_htt(struct ath10k *ar, struct sk_buff *skb) { struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data; @@ -2172,10 +2211,10 @@ void __ath10k_scan_finish(struct ath10k *ar) case ATH10K_SCAN_IDLE: break; case ATH10K_SCAN_RUNNING: - case ATH10K_SCAN_ABORTING: if (ar->scan.is_roc) ieee80211_remain_on_channel_expired(ar->hw); - else + case ATH10K_SCAN_ABORTING: + if (!ar->scan.is_roc) ieee80211_scan_completed(ar->hw, (ar->scan.state == ATH10K_SCAN_ABORTING)); @@ -2341,16 +2380,21 @@ static void ath10k_tx(struct ieee80211_hw *hw, if (info->flags & IEEE80211_TX_CTL_TX_OFFCHAN) { spin_lock_bh(&ar->data_lock); - ATH10K_SKB_CB(skb)->htt.is_offchan = true; + 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); - ath10k_dbg(ar, ATH10K_DBG_MAC, "queued offchannel skb %p\n", - skb); + if (ath10k_mac_need_offchan_tx_work(ar)) { + ATH10K_SKB_CB(skb)->htt.freq = 0; + ATH10K_SKB_CB(skb)->htt.is_offchan = true; - skb_queue_tail(&ar->offchan_tx_queue, skb); - ieee80211_queue_work(hw, &ar->offchan_tx_work); - return; + ath10k_dbg(ar, ATH10K_DBG_MAC, "queued offchannel skb %p\n", + skb); + + skb_queue_tail(&ar->offchan_tx_queue, skb); + ieee80211_queue_work(hw, &ar->offchan_tx_work); + return; + } } ath10k_tx_htt(ar, skb); @@ -2414,12 +2458,28 @@ static int ath10k_get_antenna(struct ieee80211_hw *hw, u32 *tx_ant, u32 *rx_ant) return 0; } +static void ath10k_check_chain_mask(struct ath10k *ar, u32 cm, const char *dbg) +{ + /* It is not clear that allowing gaps in chainmask + * is helpful. Probably it will not do what user + * is hoping for, so warn in that case. + */ + if (cm == 15 || cm == 7 || cm == 3 || cm == 1 || cm == 0) + return; + + ath10k_warn(ar, "mac %s antenna chainmask may be invalid: 0x%x. Suggested values: 15, 7, 3, 1 or 0.\n", + dbg, cm); +} + static int __ath10k_set_antenna(struct ath10k *ar, u32 tx_ant, u32 rx_ant) { int ret; lockdep_assert_held(&ar->conf_mutex); + ath10k_check_chain_mask(ar, tx_ant, "tx"); + ath10k_check_chain_mask(ar, rx_ant, "rx"); + ar->cfg_tx_chainmask = tx_ant; ar->cfg_rx_chainmask = rx_ant; @@ -2782,6 +2842,17 @@ static int ath10k_config(struct ieee80211_hw *hw, u32 changed) return ret; } +static u32 get_nss_from_chainmask(u16 chain_mask) +{ + if ((chain_mask & 0x15) == 0x15) + return 4; + else if ((chain_mask & 0x7) == 0x7) + return 3; + else if ((chain_mask & 0x3) == 0x3) + return 2; + return 1; +} + /* * TODO: * Figure out how to handle WMI_VDEV_SUBTYPE_P2P_DEVICE, @@ -2914,6 +2985,20 @@ static int ath10k_add_interface(struct ieee80211_hw *hw, goto err_vdev_delete; } + if (ar->cfg_tx_chainmask) { + u16 nss = get_nss_from_chainmask(ar->cfg_tx_chainmask); + + vdev_param = ar->wmi.vdev_param->nss; + ret = ath10k_wmi_vdev_set_param(ar, arvif->vdev_id, vdev_param, + nss); + if (ret) { + ath10k_warn(ar, "failed to set vdev %i chainmask 0x%x, nss %i: %d\n", + arvif->vdev_id, ar->cfg_tx_chainmask, nss, + ret); + goto err_vdev_delete; + } + } + if (arvif->vdev_type == WMI_VDEV_TYPE_AP) { ret = ath10k_peer_create(ar, arvif->vdev_id, vif->addr); if (ret) { @@ -3014,10 +3099,10 @@ static void ath10k_remove_interface(struct ieee80211_hw *hw, struct ath10k_vif *arvif = ath10k_vif_to_arvif(vif); int ret; - mutex_lock(&ar->conf_mutex); - cancel_work_sync(&arvif->wep_key_work); + mutex_lock(&ar->conf_mutex); + spin_lock_bh(&ar->data_lock); ath10k_mac_vif_beacon_cleanup(arvif); spin_unlock_bh(&ar->data_lock); @@ -3511,6 +3596,37 @@ static void ath10k_sta_rc_update_wk(struct work_struct *wk) mutex_unlock(&ar->conf_mutex); } +static int ath10k_mac_inc_num_stations(struct ath10k_vif *arvif) +{ + struct ath10k *ar = arvif->ar; + + lockdep_assert_held(&ar->conf_mutex); + + if (arvif->vdev_type != WMI_VDEV_TYPE_AP && + arvif->vdev_type != WMI_VDEV_TYPE_IBSS) + return 0; + + if (ar->num_stations >= ar->max_num_stations) + return -ENOBUFS; + + ar->num_stations++; + + return 0; +} + +static void ath10k_mac_dec_num_stations(struct ath10k_vif *arvif) +{ + struct ath10k *ar = arvif->ar; + + lockdep_assert_held(&ar->conf_mutex); + + if (arvif->vdev_type != WMI_VDEV_TYPE_AP && + arvif->vdev_type != WMI_VDEV_TYPE_IBSS) + return; + + ar->num_stations--; +} + static int ath10k_sta_state(struct ieee80211_hw *hw, struct ieee80211_vif *vif, struct ieee80211_sta *sta, @@ -3520,7 +3636,6 @@ static int ath10k_sta_state(struct ieee80211_hw *hw, struct ath10k *ar = hw->priv; struct ath10k_vif *arvif = ath10k_vif_to_arvif(vif); struct ath10k_sta *arsta = (struct ath10k_sta *)sta->drv_priv; - int max_num_peers; int ret = 0; if (old_state == IEEE80211_STA_NOTEXIST && @@ -3542,26 +3657,26 @@ static int ath10k_sta_state(struct ieee80211_hw *hw, /* * New station addition. */ - if (test_bit(ATH10K_FW_FEATURE_WMI_10X, ar->fw_features)) - max_num_peers = TARGET_10X_NUM_PEERS_MAX - 1; - else - max_num_peers = TARGET_NUM_PEERS; + ath10k_dbg(ar, ATH10K_DBG_MAC, + "mac vdev %d peer create %pM (new sta) sta %d / %d peer %d / %d\n", + arvif->vdev_id, sta->addr, + ar->num_stations + 1, ar->max_num_stations, + ar->num_peers + 1, ar->max_num_peers); - if (ar->num_peers >= max_num_peers) { - ath10k_warn(ar, "number of peers exceeded: peers number %d (max peers %d)\n", - ar->num_peers, max_num_peers); - ret = -ENOBUFS; + ret = ath10k_mac_inc_num_stations(arvif); + if (ret) { + ath10k_warn(ar, "refusing to associate station: too many connected already (%d)\n", + ar->max_num_stations); goto exit; } - ath10k_dbg(ar, ATH10K_DBG_MAC, - "mac vdev %d peer create %pM (new sta) num_peers %d\n", - arvif->vdev_id, sta->addr, ar->num_peers); - ret = ath10k_peer_create(ar, arvif->vdev_id, sta->addr); - if (ret) + if (ret) { ath10k_warn(ar, "failed to add peer %pM for vdev %d when adding a new sta: %i\n", sta->addr, arvif->vdev_id, ret); + ath10k_mac_dec_num_stations(arvif); + goto exit; + } if (vif->type == NL80211_IFTYPE_STATION) { WARN_ON(arvif->is_started); @@ -3572,6 +3687,7 @@ static int ath10k_sta_state(struct ieee80211_hw *hw, arvif->vdev_id, ret); WARN_ON(ath10k_peer_delete(ar, arvif->vdev_id, sta->addr)); + ath10k_mac_dec_num_stations(arvif); goto exit; } @@ -3602,6 +3718,7 @@ static int ath10k_sta_state(struct ieee80211_hw *hw, ath10k_warn(ar, "failed to delete peer %pM for vdev %d: %i\n", sta->addr, arvif->vdev_id, ret); + ath10k_mac_dec_num_stations(arvif); } else if (old_state == IEEE80211_STA_AUTH && new_state == IEEE80211_STA_ASSOC && (vif->type == NL80211_IFTYPE_AP || @@ -3790,6 +3907,8 @@ static int ath10k_remain_on_channel(struct ieee80211_hw *hw, if (ret) goto exit; + duration = max(duration, WMI_SCAN_CHAN_MIN_TIME_MSEC); + memset(&arg, 0, sizeof(arg)); ath10k_wmi_start_scan_init(ar, &arg); arg.vdev_id = arvif->vdev_id; @@ -4106,6 +4225,10 @@ ath10k_default_bitrate_mask(struct ath10k *ar, u32 legacy = 0x00ff; u8 ht = 0xff, i; u16 vht = 0x3ff; + u16 nrf = ar->num_rf_chains; + + if (ar->cfg_tx_chainmask) + nrf = get_nss_from_chainmask(ar->cfg_tx_chainmask); switch (band) { case IEEE80211_BAND_2GHZ: @@ -4121,11 +4244,11 @@ ath10k_default_bitrate_mask(struct ath10k *ar, if (mask->control[band].legacy != legacy) return false; - for (i = 0; i < ar->num_rf_chains; i++) + for (i = 0; i < nrf; i++) if (mask->control[band].ht_mcs[i] != ht) return false; - for (i = 0; i < ar->num_rf_chains; i++) + for (i = 0; i < nrf; i++) if (mask->control[band].vht_mcs[i] != vht) return false; @@ -4376,6 +4499,9 @@ static int ath10k_set_bitrate_mask(struct ieee80211_hw *hw, u8 fixed_nss = ar->num_rf_chains; u8 force_sgi; + if (ar->cfg_tx_chainmask) + fixed_nss = get_nss_from_chainmask(ar->cfg_tx_chainmask); + force_sgi = mask->control[band].gi; if (force_sgi == NL80211_TXRATE_FORCE_LGI) return -EINVAL; @@ -4905,10 +5031,6 @@ int ath10k_mac_register(struct ath10k *ar) IEEE80211_HW_AP_LINK_PS | IEEE80211_HW_SPECTRUM_MGMT; - /* MSDU can have HTT TX fragment pushed in front. The additional 4 - * bytes is used for padding/alignment if necessary. */ - ar->hw->extra_tx_headroom += sizeof(struct htt_data_tx_desc_frag)*2 + 4; - ar->hw->wiphy->features |= NL80211_FEATURE_STATIC_SMPS; if (ar->ht_cap_info & WMI_HT_CAP_DYNAMIC_SMPS) diff --git a/drivers/net/wireless/ath/ath10k/mac.h b/drivers/net/wireless/ath/ath10k/mac.h index 4e3c989aa84..68296117d20 100644 --- a/drivers/net/wireless/ath/ath10k/mac.h +++ b/drivers/net/wireless/ath/ath10k/mac.h @@ -21,6 +21,8 @@ #include <net/mac80211.h> #include "core.h" +#define WEP_KEYID_SHIFT 6 + struct ath10k_generic_iter { struct ath10k *ar; int ret; @@ -41,6 +43,8 @@ void ath10k_mgmt_over_wmi_tx_work(struct work_struct *work); void ath10k_halt(struct ath10k *ar); void ath10k_mac_vif_beacon_free(struct ath10k_vif *arvif); void ath10k_drain_tx(struct ath10k *ar); +bool ath10k_mac_is_peer_wep_key_set(struct ath10k *ar, const u8 *addr, + u8 keyidx); static inline struct ath10k_vif *ath10k_vif_to_arvif(struct ieee80211_vif *vif) { diff --git a/drivers/net/wireless/ath/ath10k/pci.c b/drivers/net/wireless/ath/ath10k/pci.c index 3a6b8a5ca96..7abb8367119 100644 --- a/drivers/net/wireless/ath/ath10k/pci.c +++ b/drivers/net/wireless/ath/ath10k/pci.c @@ -823,20 +823,24 @@ static void ath10k_pci_ce_send_done(struct ath10k_ce_pipe *ce_state) struct ath10k *ar = ce_state->ar; struct ath10k_pci *ar_pci = ath10k_pci_priv(ar); struct ath10k_hif_cb *cb = &ar_pci->msg_callbacks_current; - void *transfer_context; + struct sk_buff_head list; + struct sk_buff *skb; u32 ce_data; unsigned int nbytes; unsigned int transfer_id; - while (ath10k_ce_completed_send_next(ce_state, &transfer_context, - &ce_data, &nbytes, - &transfer_id) == 0) { + __skb_queue_head_init(&list); + while (ath10k_ce_completed_send_next(ce_state, (void **)&skb, &ce_data, + &nbytes, &transfer_id) == 0) { /* no need to call tx completion for NULL pointers */ - if (transfer_context == NULL) + if (skb == NULL) continue; - cb->tx_completion(ar, transfer_context, transfer_id); + __skb_queue_tail(&list, skb); } + + while ((skb = __skb_dequeue(&list))) + cb->tx_completion(ar, skb); } /* Called by lower (CE) layer when data is received from the Target. */ @@ -847,12 +851,14 @@ static void ath10k_pci_ce_recv_data(struct ath10k_ce_pipe *ce_state) struct ath10k_pci_pipe *pipe_info = &ar_pci->pipe_info[ce_state->id]; struct ath10k_hif_cb *cb = &ar_pci->msg_callbacks_current; struct sk_buff *skb; + struct sk_buff_head list; void *transfer_context; u32 ce_data; unsigned int nbytes, max_nbytes; unsigned int transfer_id; unsigned int flags; + __skb_queue_head_init(&list); while (ath10k_ce_completed_recv_next(ce_state, &transfer_context, &ce_data, &nbytes, &transfer_id, &flags) == 0) { @@ -869,13 +875,16 @@ static void ath10k_pci_ce_recv_data(struct ath10k_ce_pipe *ce_state) } skb_put(skb, nbytes); + __skb_queue_tail(&list, skb); + } + while ((skb = __skb_dequeue(&list))) { ath10k_dbg(ar, ATH10K_DBG_PCI, "pci rx ce pipe %d len %d\n", ce_state->id, skb->len); ath10k_dbg_dump(ar, ATH10K_DBG_PCI_DUMP, NULL, "pci rx: ", skb->data, skb->len); - cb->rx_completion(ar, skb, pipe_info->pipe_num); + cb->rx_completion(ar, skb); } ath10k_pci_rx_post_pipe(pipe_info); @@ -1263,7 +1272,7 @@ static void ath10k_pci_tx_pipe_cleanup(struct ath10k_pci_pipe *pci_pipe) id = MS(__le16_to_cpu(ce_desc[i].flags), CE_DESC_FLAGS_META_DATA); - ar_pci->msg_callbacks_current.tx_completion(ar, skb, id); + ar_pci->msg_callbacks_current.tx_completion(ar, skb); } } @@ -1988,6 +1997,7 @@ static int ath10k_pci_hif_resume(struct ath10k *ar) static const struct ath10k_hif_ops ath10k_pci_hif_ops = { .tx_sg = ath10k_pci_hif_tx_sg, .diag_read = ath10k_pci_hif_diag_read, + .diag_write = ath10k_pci_diag_write_mem, .exchange_bmi_msg = ath10k_pci_hif_exchange_bmi_msg, .start = ath10k_pci_hif_start, .stop = ath10k_pci_hif_stop, @@ -1998,6 +2008,8 @@ static const struct ath10k_hif_ops ath10k_pci_hif_ops = { .get_free_queue_number = ath10k_pci_hif_get_free_queue_number, .power_up = ath10k_pci_hif_power_up, .power_down = ath10k_pci_hif_power_down, + .read32 = ath10k_pci_read32, + .write32 = ath10k_pci_write32, #ifdef CONFIG_PM .suspend = ath10k_pci_hif_suspend, .resume = ath10k_pci_hif_resume, diff --git a/drivers/net/wireless/ath/ath10k/trace.h b/drivers/net/wireless/ath/ath10k/trace.h index ceea5668f3f..b289378b6e3 100644 --- a/drivers/net/wireless/ath/ath10k/trace.h +++ b/drivers/net/wireless/ath/ath10k/trace.h @@ -21,9 +21,11 @@ #include "core.h" #if !defined(_TRACE_H_) -static inline u32 ath10k_frm_hdr_len(void *buf) +static inline u32 ath10k_frm_hdr_len(const void *buf) { - return ieee80211_hdrlen(((struct ieee80211_hdr *)buf)->frame_control); + const struct ieee80211_hdr *hdr = buf; + + return ieee80211_hdrlen(hdr->frame_control); } #endif @@ -145,7 +147,8 @@ TRACE_EVENT(ath10k_log_dbg_dump, ); TRACE_EVENT(ath10k_wmi_cmd, - TP_PROTO(struct ath10k *ar, int id, void *buf, size_t buf_len, int ret), + TP_PROTO(struct ath10k *ar, int id, const void *buf, size_t buf_len, + int ret), TP_ARGS(ar, id, buf, buf_len, ret), @@ -178,7 +181,7 @@ TRACE_EVENT(ath10k_wmi_cmd, ); TRACE_EVENT(ath10k_wmi_event, - TP_PROTO(struct ath10k *ar, int id, void *buf, size_t buf_len), + TP_PROTO(struct ath10k *ar, int id, const void *buf, size_t buf_len), TP_ARGS(ar, id, buf, buf_len), @@ -208,7 +211,7 @@ TRACE_EVENT(ath10k_wmi_event, ); TRACE_EVENT(ath10k_htt_stats, - TP_PROTO(struct ath10k *ar, void *buf, size_t buf_len), + TP_PROTO(struct ath10k *ar, const void *buf, size_t buf_len), TP_ARGS(ar, buf, buf_len), @@ -235,7 +238,7 @@ TRACE_EVENT(ath10k_htt_stats, ); TRACE_EVENT(ath10k_wmi_dbglog, - TP_PROTO(struct ath10k *ar, void *buf, size_t buf_len), + TP_PROTO(struct ath10k *ar, const void *buf, size_t buf_len), TP_ARGS(ar, buf, buf_len), @@ -262,7 +265,7 @@ TRACE_EVENT(ath10k_wmi_dbglog, ); TRACE_EVENT(ath10k_htt_pktlog, - TP_PROTO(struct ath10k *ar, void *buf, u16 buf_len), + TP_PROTO(struct ath10k *ar, const void *buf, u16 buf_len), TP_ARGS(ar, buf, buf_len), @@ -349,7 +352,7 @@ TRACE_EVENT(ath10k_txrx_tx_unref, ); DECLARE_EVENT_CLASS(ath10k_hdr_event, - TP_PROTO(struct ath10k *ar, void *data, size_t len), + TP_PROTO(struct ath10k *ar, const void *data, size_t len), TP_ARGS(ar, data, len), @@ -376,7 +379,7 @@ DECLARE_EVENT_CLASS(ath10k_hdr_event, ); DECLARE_EVENT_CLASS(ath10k_payload_event, - TP_PROTO(struct ath10k *ar, void *data, size_t len), + TP_PROTO(struct ath10k *ar, const void *data, size_t len), TP_ARGS(ar, data, len), @@ -404,27 +407,27 @@ DECLARE_EVENT_CLASS(ath10k_payload_event, ); DEFINE_EVENT(ath10k_hdr_event, ath10k_tx_hdr, - TP_PROTO(struct ath10k *ar, void *data, size_t len), + TP_PROTO(struct ath10k *ar, const void *data, size_t len), TP_ARGS(ar, data, len) ); DEFINE_EVENT(ath10k_payload_event, ath10k_tx_payload, - TP_PROTO(struct ath10k *ar, void *data, size_t len), + TP_PROTO(struct ath10k *ar, const void *data, size_t len), TP_ARGS(ar, data, len) ); DEFINE_EVENT(ath10k_hdr_event, ath10k_rx_hdr, - TP_PROTO(struct ath10k *ar, void *data, size_t len), + TP_PROTO(struct ath10k *ar, const void *data, size_t len), TP_ARGS(ar, data, len) ); DEFINE_EVENT(ath10k_payload_event, ath10k_rx_payload, - TP_PROTO(struct ath10k *ar, void *data, size_t len), + TP_PROTO(struct ath10k *ar, const void *data, size_t len), TP_ARGS(ar, data, len) ); TRACE_EVENT(ath10k_htt_rx_desc, - TP_PROTO(struct ath10k *ar, void *data, size_t len), + TP_PROTO(struct ath10k *ar, const void *data, size_t len), TP_ARGS(ar, data, len), diff --git a/drivers/net/wireless/ath/ath10k/wmi.c b/drivers/net/wireless/ath/ath10k/wmi.c index c2bc8282f6c..c0f3e4d0926 100644 --- a/drivers/net/wireless/ath/ath10k/wmi.c +++ b/drivers/net/wireless/ath/ath10k/wmi.c @@ -1113,6 +1113,40 @@ static inline u8 get_rate_idx(u32 rate, enum ieee80211_band band) return rate_idx; } +/* If keys are configured, HW decrypts all frames + * with protected bit set. Mark such frames as decrypted. + */ +static void ath10k_wmi_handle_wep_reauth(struct ath10k *ar, + struct sk_buff *skb, + struct ieee80211_rx_status *status) +{ + struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data; + unsigned int hdrlen; + bool peer_key; + u8 *addr, keyidx; + + if (!ieee80211_is_auth(hdr->frame_control) || + !ieee80211_has_protected(hdr->frame_control)) + return; + + hdrlen = ieee80211_hdrlen(hdr->frame_control); + if (skb->len < (hdrlen + IEEE80211_WEP_IV_LEN)) + return; + + keyidx = skb->data[hdrlen + (IEEE80211_WEP_IV_LEN - 1)] >> WEP_KEYID_SHIFT; + addr = ieee80211_get_SA(hdr); + + spin_lock_bh(&ar->data_lock); + peer_key = ath10k_mac_is_peer_wep_key_set(ar, addr, keyidx); + spin_unlock_bh(&ar->data_lock); + + if (peer_key) { + ath10k_dbg(ar, ATH10K_DBG_MAC, + "mac wep key present for peer %pM\n", addr); + status->flag |= RX_FLAG_DECRYPTED; + } +} + static int ath10k_wmi_event_mgmt_rx(struct ath10k *ar, struct sk_buff *skb) { struct wmi_mgmt_rx_event_v1 *ev_v1; @@ -1166,8 +1200,11 @@ static int ath10k_wmi_event_mgmt_rx(struct ath10k *ar, struct sk_buff *skb) return 0; } - if (rx_status & WMI_RX_STATUS_ERR_CRC) - status->flag |= RX_FLAG_FAILED_FCS_CRC; + if (rx_status & WMI_RX_STATUS_ERR_CRC) { + dev_kfree_skb(skb); + return 0; + } + if (rx_status & WMI_RX_STATUS_ERR_MIC) status->flag |= RX_FLAG_MMIC_ERROR; @@ -1200,6 +1237,8 @@ static int ath10k_wmi_event_mgmt_rx(struct ath10k *ar, struct sk_buff *skb) hdr = (struct ieee80211_hdr *)skb->data; fc = le16_to_cpu(hdr->frame_control); + ath10k_wmi_handle_wep_reauth(ar, skb, status); + /* FW delivers WEP Shared Auth frame with Protected Bit set and * encrypted payload. However in case of PMF it delivers decrypted * frames with Protected Bit set. */ @@ -2261,7 +2300,7 @@ static void ath10k_wmi_event_debug_print(struct ath10k *ar, /* the last byte is always reserved for the null character */ buf[i] = '\0'; - ath10k_dbg(ar, ATH10K_DBG_WMI, "wmi event debug print '%s'\n", buf); + ath10k_dbg(ar, ATH10K_DBG_WMI_PRINT, "wmi print '%s'\n", buf); } static void ath10k_wmi_event_pdev_qvit(struct ath10k *ar, struct sk_buff *skb) @@ -2418,6 +2457,7 @@ static int ath10k_wmi_main_pull_svc_rdy_ev(struct sk_buff *skb, arg->eeprom_rd = ev->hal_reg_capabilities.eeprom_rd; arg->num_mem_reqs = ev->num_mem_reqs; arg->service_map = ev->wmi_service_bitmap; + arg->service_map_len = sizeof(ev->wmi_service_bitmap); n = min_t(size_t, __le32_to_cpu(arg->num_mem_reqs), ARRAY_SIZE(arg->mem_reqs)); @@ -2452,6 +2492,7 @@ static int ath10k_wmi_10x_pull_svc_rdy_ev(struct sk_buff *skb, arg->eeprom_rd = ev->hal_reg_capabilities.eeprom_rd; arg->num_mem_reqs = ev->num_mem_reqs; arg->service_map = ev->wmi_service_bitmap; + arg->service_map_len = sizeof(ev->wmi_service_bitmap); n = min_t(size_t, __le32_to_cpu(arg->num_mem_reqs), ARRAY_SIZE(arg->mem_reqs)); @@ -2470,15 +2511,18 @@ static void ath10k_wmi_event_service_ready(struct ath10k *ar, { struct wmi_svc_rdy_ev_arg arg = {}; u32 num_units, req_id, unit_size, num_mem_reqs, num_unit_info, i; - DECLARE_BITMAP(svc_bmap, WMI_SERVICE_MAX) = {}; int ret; + memset(&ar->wmi.svc_map, 0, sizeof(ar->wmi.svc_map)); + if (test_bit(ATH10K_FW_FEATURE_WMI_10X, ar->fw_features)) { ret = ath10k_wmi_10x_pull_svc_rdy_ev(skb, &arg); - wmi_10x_svc_map(arg.service_map, svc_bmap); + wmi_10x_svc_map(arg.service_map, ar->wmi.svc_map, + arg.service_map_len); } else { ret = ath10k_wmi_main_pull_svc_rdy_ev(skb, &arg); - wmi_main_svc_map(arg.service_map, svc_bmap); + wmi_main_svc_map(arg.service_map, ar->wmi.svc_map, + arg.service_map_len); } if (ret) { @@ -2500,9 +2544,8 @@ static void ath10k_wmi_event_service_ready(struct ath10k *ar, ar->num_rf_chains = __le32_to_cpu(arg.num_rf_chains); ar->ath_common.regulatory.current_rd = __le32_to_cpu(arg.eeprom_rd); - ath10k_debug_read_service_map(ar, svc_bmap, sizeof(svc_bmap)); ath10k_dbg_dump(ar, ATH10K_DBG_WMI, NULL, "wmi svc: ", - arg.service_map, sizeof(arg.service_map)); + arg.service_map, arg.service_map_len); /* only manually set fw features when not using FW IE format */ if (ar->fw_api == 1 && ar->fw_version_build > 636) @@ -3142,7 +3185,7 @@ static int ath10k_wmi_main_cmd_init(struct ath10k *ar) u32 len, val; config.num_vdevs = __cpu_to_le32(TARGET_NUM_VDEVS); - config.num_peers = __cpu_to_le32(TARGET_NUM_PEERS + TARGET_NUM_VDEVS); + config.num_peers = __cpu_to_le32(TARGET_NUM_PEERS); config.num_offload_peers = __cpu_to_le32(TARGET_NUM_OFFLOAD_PEERS); config.num_offload_reorder_bufs = diff --git a/drivers/net/wireless/ath/ath10k/wmi.h b/drivers/net/wireless/ath/ath10k/wmi.h index a38d788a610..21391929d31 100644 --- a/drivers/net/wireless/ath/ath10k/wmi.h +++ b/drivers/net/wireless/ath/ath10k/wmi.h @@ -222,128 +222,131 @@ static inline char *wmi_service_name(int service_id) #undef SVCSTR } -#define WMI_SERVICE_IS_ENABLED(wmi_svc_bmap, svc_id) \ - (__le32_to_cpu((wmi_svc_bmap)[(svc_id)/(sizeof(u32))]) & \ +#define WMI_SERVICE_IS_ENABLED(wmi_svc_bmap, svc_id, len) \ + ((svc_id) < (len) && \ + __le32_to_cpu((wmi_svc_bmap)[(svc_id)/(sizeof(u32))]) & \ BIT((svc_id)%(sizeof(u32)))) -#define SVCMAP(x, y) \ +#define SVCMAP(x, y, len) \ do { \ - if (WMI_SERVICE_IS_ENABLED((in), (x))) \ + if (WMI_SERVICE_IS_ENABLED((in), (x), (len))) \ __set_bit(y, out); \ } while (0) -static inline void wmi_10x_svc_map(const __le32 *in, unsigned long *out) +static inline void wmi_10x_svc_map(const __le32 *in, unsigned long *out, + size_t len) { SVCMAP(WMI_10X_SERVICE_BEACON_OFFLOAD, - WMI_SERVICE_BEACON_OFFLOAD); + WMI_SERVICE_BEACON_OFFLOAD, len); SVCMAP(WMI_10X_SERVICE_SCAN_OFFLOAD, - WMI_SERVICE_SCAN_OFFLOAD); + WMI_SERVICE_SCAN_OFFLOAD, len); SVCMAP(WMI_10X_SERVICE_ROAM_OFFLOAD, - WMI_SERVICE_ROAM_OFFLOAD); + WMI_SERVICE_ROAM_OFFLOAD, len); SVCMAP(WMI_10X_SERVICE_BCN_MISS_OFFLOAD, - WMI_SERVICE_BCN_MISS_OFFLOAD); + WMI_SERVICE_BCN_MISS_OFFLOAD, len); SVCMAP(WMI_10X_SERVICE_STA_PWRSAVE, - WMI_SERVICE_STA_PWRSAVE); + WMI_SERVICE_STA_PWRSAVE, len); SVCMAP(WMI_10X_SERVICE_STA_ADVANCED_PWRSAVE, - WMI_SERVICE_STA_ADVANCED_PWRSAVE); + WMI_SERVICE_STA_ADVANCED_PWRSAVE, len); SVCMAP(WMI_10X_SERVICE_AP_UAPSD, - WMI_SERVICE_AP_UAPSD); + WMI_SERVICE_AP_UAPSD, len); SVCMAP(WMI_10X_SERVICE_AP_DFS, - WMI_SERVICE_AP_DFS); + WMI_SERVICE_AP_DFS, len); SVCMAP(WMI_10X_SERVICE_11AC, - WMI_SERVICE_11AC); + WMI_SERVICE_11AC, len); SVCMAP(WMI_10X_SERVICE_BLOCKACK, - WMI_SERVICE_BLOCKACK); + WMI_SERVICE_BLOCKACK, len); SVCMAP(WMI_10X_SERVICE_PHYERR, - WMI_SERVICE_PHYERR); + WMI_SERVICE_PHYERR, len); SVCMAP(WMI_10X_SERVICE_BCN_FILTER, - WMI_SERVICE_BCN_FILTER); + WMI_SERVICE_BCN_FILTER, len); SVCMAP(WMI_10X_SERVICE_RTT, - WMI_SERVICE_RTT); + WMI_SERVICE_RTT, len); SVCMAP(WMI_10X_SERVICE_RATECTRL, - WMI_SERVICE_RATECTRL); + WMI_SERVICE_RATECTRL, len); SVCMAP(WMI_10X_SERVICE_WOW, - WMI_SERVICE_WOW); + WMI_SERVICE_WOW, len); SVCMAP(WMI_10X_SERVICE_RATECTRL_CACHE, - WMI_SERVICE_RATECTRL_CACHE); + WMI_SERVICE_RATECTRL_CACHE, len); SVCMAP(WMI_10X_SERVICE_IRAM_TIDS, - WMI_SERVICE_IRAM_TIDS); + WMI_SERVICE_IRAM_TIDS, len); SVCMAP(WMI_10X_SERVICE_BURST, - WMI_SERVICE_BURST); + WMI_SERVICE_BURST, len); SVCMAP(WMI_10X_SERVICE_SMART_ANTENNA_SW_SUPPORT, - WMI_SERVICE_SMART_ANTENNA_SW_SUPPORT); + WMI_SERVICE_SMART_ANTENNA_SW_SUPPORT, len); SVCMAP(WMI_10X_SERVICE_FORCE_FW_HANG, - WMI_SERVICE_FORCE_FW_HANG); + WMI_SERVICE_FORCE_FW_HANG, len); SVCMAP(WMI_10X_SERVICE_SMART_ANTENNA_HW_SUPPORT, - WMI_SERVICE_SMART_ANTENNA_HW_SUPPORT); + WMI_SERVICE_SMART_ANTENNA_HW_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, + size_t len) { SVCMAP(WMI_MAIN_SERVICE_BEACON_OFFLOAD, - WMI_SERVICE_BEACON_OFFLOAD); + WMI_SERVICE_BEACON_OFFLOAD, len); SVCMAP(WMI_MAIN_SERVICE_SCAN_OFFLOAD, - WMI_SERVICE_SCAN_OFFLOAD); + WMI_SERVICE_SCAN_OFFLOAD, len); SVCMAP(WMI_MAIN_SERVICE_ROAM_OFFLOAD, - WMI_SERVICE_ROAM_OFFLOAD); + WMI_SERVICE_ROAM_OFFLOAD, len); SVCMAP(WMI_MAIN_SERVICE_BCN_MISS_OFFLOAD, - WMI_SERVICE_BCN_MISS_OFFLOAD); + WMI_SERVICE_BCN_MISS_OFFLOAD, len); SVCMAP(WMI_MAIN_SERVICE_STA_PWRSAVE, - WMI_SERVICE_STA_PWRSAVE); + WMI_SERVICE_STA_PWRSAVE, len); SVCMAP(WMI_MAIN_SERVICE_STA_ADVANCED_PWRSAVE, - WMI_SERVICE_STA_ADVANCED_PWRSAVE); + WMI_SERVICE_STA_ADVANCED_PWRSAVE, len); SVCMAP(WMI_MAIN_SERVICE_AP_UAPSD, - WMI_SERVICE_AP_UAPSD); + WMI_SERVICE_AP_UAPSD, len); SVCMAP(WMI_MAIN_SERVICE_AP_DFS, - WMI_SERVICE_AP_DFS); + WMI_SERVICE_AP_DFS, len); SVCMAP(WMI_MAIN_SERVICE_11AC, - WMI_SERVICE_11AC); + WMI_SERVICE_11AC, len); SVCMAP(WMI_MAIN_SERVICE_BLOCKACK, - WMI_SERVICE_BLOCKACK); + WMI_SERVICE_BLOCKACK, len); SVCMAP(WMI_MAIN_SERVICE_PHYERR, - WMI_SERVICE_PHYERR); + WMI_SERVICE_PHYERR, len); SVCMAP(WMI_MAIN_SERVICE_BCN_FILTER, - WMI_SERVICE_BCN_FILTER); + WMI_SERVICE_BCN_FILTER, len); SVCMAP(WMI_MAIN_SERVICE_RTT, - WMI_SERVICE_RTT); + WMI_SERVICE_RTT, len); SVCMAP(WMI_MAIN_SERVICE_RATECTRL, - WMI_SERVICE_RATECTRL); + WMI_SERVICE_RATECTRL, len); SVCMAP(WMI_MAIN_SERVICE_WOW, - WMI_SERVICE_WOW); + WMI_SERVICE_WOW, len); SVCMAP(WMI_MAIN_SERVICE_RATECTRL_CACHE, - WMI_SERVICE_RATECTRL_CACHE); + WMI_SERVICE_RATECTRL_CACHE, len); SVCMAP(WMI_MAIN_SERVICE_IRAM_TIDS, - WMI_SERVICE_IRAM_TIDS); + WMI_SERVICE_IRAM_TIDS, len); SVCMAP(WMI_MAIN_SERVICE_ARPNS_OFFLOAD, - WMI_SERVICE_ARPNS_OFFLOAD); + WMI_SERVICE_ARPNS_OFFLOAD, len); SVCMAP(WMI_MAIN_SERVICE_NLO, - WMI_SERVICE_NLO); + WMI_SERVICE_NLO, len); SVCMAP(WMI_MAIN_SERVICE_GTK_OFFLOAD, - WMI_SERVICE_GTK_OFFLOAD); + WMI_SERVICE_GTK_OFFLOAD, len); SVCMAP(WMI_MAIN_SERVICE_SCAN_SCH, - WMI_SERVICE_SCAN_SCH); + WMI_SERVICE_SCAN_SCH, len); SVCMAP(WMI_MAIN_SERVICE_CSA_OFFLOAD, - WMI_SERVICE_CSA_OFFLOAD); + WMI_SERVICE_CSA_OFFLOAD, len); SVCMAP(WMI_MAIN_SERVICE_CHATTER, - WMI_SERVICE_CHATTER); + WMI_SERVICE_CHATTER, len); SVCMAP(WMI_MAIN_SERVICE_COEX_FREQAVOID, - WMI_SERVICE_COEX_FREQAVOID); + WMI_SERVICE_COEX_FREQAVOID, len); SVCMAP(WMI_MAIN_SERVICE_PACKET_POWER_SAVE, - WMI_SERVICE_PACKET_POWER_SAVE); + WMI_SERVICE_PACKET_POWER_SAVE, len); SVCMAP(WMI_MAIN_SERVICE_FORCE_FW_HANG, - WMI_SERVICE_FORCE_FW_HANG); + WMI_SERVICE_FORCE_FW_HANG, len); SVCMAP(WMI_MAIN_SERVICE_GPIO, - WMI_SERVICE_GPIO); + WMI_SERVICE_GPIO, len); SVCMAP(WMI_MAIN_SERVICE_STA_DTIM_PS_MODULATED_DTIM, - WMI_SERVICE_STA_DTIM_PS_MODULATED_DTIM); + WMI_SERVICE_STA_DTIM_PS_MODULATED_DTIM, len); SVCMAP(WMI_MAIN_SERVICE_STA_UAPSD_BASIC_AUTO_TRIG, - WMI_SERVICE_STA_UAPSD_BASIC_AUTO_TRIG); + WMI_SERVICE_STA_UAPSD_BASIC_AUTO_TRIG, len); SVCMAP(WMI_MAIN_SERVICE_STA_UAPSD_VAR_AUTO_TRIG, - WMI_SERVICE_STA_UAPSD_VAR_AUTO_TRIG); + WMI_SERVICE_STA_UAPSD_VAR_AUTO_TRIG, len); SVCMAP(WMI_MAIN_SERVICE_STA_KEEP_ALIVE, - WMI_SERVICE_STA_KEEP_ALIVE); + WMI_SERVICE_STA_KEEP_ALIVE, len); SVCMAP(WMI_MAIN_SERVICE_TX_ENCAP, - WMI_SERVICE_TX_ENCAP); + WMI_SERVICE_TX_ENCAP, len); } #undef SVCMAP @@ -1952,6 +1955,11 @@ struct wmi_ssid_list { #define WLAN_SCAN_PARAMS_MAX_BSSID 4 #define WLAN_SCAN_PARAMS_MAX_IE_LEN 256 +/* Values lower than this may be refused by some firmware revisions with a scan + * completion with a timedout reason. + */ +#define WMI_SCAN_CHAN_MIN_TIME_MSEC 40 + /* Scan priority numbers must be sequential, starting with 0 */ enum wmi_scan_priority { WMI_SCAN_PRIORITY_VERY_LOW = 0, @@ -4547,7 +4555,6 @@ struct wmi_dbglog_cfg_cmd { __le32 config_valid; } __packed; -#define ATH10K_RTS_MAX 2347 #define ATH10K_FRAGMT_THRESHOLD_MIN 540 #define ATH10K_FRAGMT_THRESHOLD_MAX 2346 @@ -4572,6 +4579,7 @@ struct wmi_svc_rdy_ev_arg { __le32 eeprom_rd; __le32 num_mem_reqs; const __le32 *service_map; + size_t service_map_len; const struct wlan_host_mem_req *mem_reqs[WMI_MAX_MEM_REQS]; }; |