diff options
author | David S. Miller <davem@davemloft.net> | 2020-09-11 23:32:31 +0300 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2020-09-11 23:32:31 +0300 |
commit | e7a08121e0f4954101605b30c2cf725ccdef7ec7 (patch) | |
tree | a47f13676ec2b6a3fc647780c0221c8d6c2eec38 /drivers/net/wireless/ath/ath10k | |
parent | 9984c0bb22dcae688ef8588e2621133850ff49bc (diff) | |
parent | 5941d003f0a60877a956cc3cae6e3850b46fad0a (diff) | |
download | linux-e7a08121e0f4954101605b30c2cf725ccdef7ec7.tar.xz |
Merge tag 'wireless-drivers-next-2020-09-11' of git://git.kernel.org/pub/scm/linux/kernel/git/kvalo/wireless-drivers-next
Kalle Valo says:
====================
wireless-drivers-next patches for v5.10
First set of patches for v5.10. Most noteworthy here is ath11k getting
initial support for QCA6390 and IPQ6018 devices. But most of the
patches are cleanup: W=1 warning fixes, fallthrough keywords, DMA API
changes and tasklet API changes.
Major changes:
ath10k
* support SDIO firmware codedumps
* support station specific TID configurations
ath11k
* add support for IPQ6018
* add support for QCA6390 PCI devices
ath9k
* add support for NL80211_EXT_FEATURE_CAN_REPLACE_PTK0 to improve PTK0
rekeying
wcn36xx
* add support for TX ack
====================
Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'drivers/net/wireless/ath/ath10k')
22 files changed, 1791 insertions, 237 deletions
diff --git a/drivers/net/wireless/ath/ath10k/bmi.c b/drivers/net/wireless/ath/ath10k/bmi.c index 5b6db6e66f65..4481ed375f55 100644 --- a/drivers/net/wireless/ath/ath10k/bmi.c +++ b/drivers/net/wireless/ath/ath10k/bmi.c @@ -12,18 +12,11 @@ void ath10k_bmi_start(struct ath10k *ar) { - int ret; - ath10k_dbg(ar, ATH10K_DBG_BMI, "bmi start\n"); ar->bmi.done_sent = false; - - /* Enable hardware clock to speed up firmware download */ - if (ar->hw_params.hw_ops->enable_pll_clk) { - ret = ar->hw_params.hw_ops->enable_pll_clk(ar); - ath10k_dbg(ar, ATH10K_DBG_BMI, "bmi enable pll ret %d\n", ret); - } } +EXPORT_SYMBOL(ath10k_bmi_start); int ath10k_bmi_done(struct ath10k *ar) { @@ -197,6 +190,7 @@ int ath10k_bmi_read_memory(struct ath10k *ar, return 0; } +EXPORT_SYMBOL(ath10k_bmi_read_memory); int ath10k_bmi_write_soc_reg(struct ath10k *ar, u32 address, u32 reg_val) { diff --git a/drivers/net/wireless/ath/ath10k/ce.c b/drivers/net/wireless/ath/ath10k/ce.c index 294fbc1e89ab..c45c814fd122 100644 --- a/drivers/net/wireless/ath/ath10k/ce.c +++ b/drivers/net/wireless/ath/ath10k/ce.c @@ -1299,29 +1299,24 @@ void ath10k_ce_per_engine_service(struct ath10k *ar, unsigned int ce_id) struct ath10k_hw_ce_host_wm_regs *wm_regs = ar->hw_ce_regs->wm_regs; u32 ctrl_addr = ce_state->ctrl_addr; - spin_lock_bh(&ce->ce_lock); - - /* Clear the copy-complete interrupts that will be handled here. */ + /* + * Clear before handling + * + * Misc CE interrupts are not being handled, but still need + * to be cleared. + * + * NOTE: When the last copy engine interrupt is cleared the + * hardware will go to sleep. Once this happens any access to + * the CE registers can cause a hardware fault. + */ ath10k_ce_engine_int_status_clear(ar, ctrl_addr, - wm_regs->cc_mask); - - spin_unlock_bh(&ce->ce_lock); + wm_regs->cc_mask | wm_regs->wm_mask); if (ce_state->recv_cb) ce_state->recv_cb(ce_state); if (ce_state->send_cb) ce_state->send_cb(ce_state); - - spin_lock_bh(&ce->ce_lock); - - /* - * Misc CE interrupts are not being handled, but still need - * to be cleared. - */ - ath10k_ce_engine_int_status_clear(ar, ctrl_addr, wm_regs->wm_mask); - - spin_unlock_bh(&ce->ce_lock); } EXPORT_SYMBOL(ath10k_ce_per_engine_service); @@ -1372,45 +1367,55 @@ static void ath10k_ce_per_engine_handler_adjust(struct ath10k_ce_pipe *ce_state) ath10k_ce_watermark_intr_disable(ar, ctrl_addr); } -int ath10k_ce_disable_interrupts(struct ath10k *ar) +void ath10k_ce_disable_interrupt(struct ath10k *ar, int ce_id) { struct ath10k_ce *ce = ath10k_ce_priv(ar); struct ath10k_ce_pipe *ce_state; u32 ctrl_addr; - int ce_id; - for (ce_id = 0; ce_id < CE_COUNT; ce_id++) { - ce_state = &ce->ce_states[ce_id]; - if (ce_state->attr_flags & CE_ATTR_POLL) - continue; + ce_state = &ce->ce_states[ce_id]; + if (ce_state->attr_flags & CE_ATTR_POLL) + return; - ctrl_addr = ath10k_ce_base_address(ar, ce_id); + ctrl_addr = ath10k_ce_base_address(ar, ce_id); - ath10k_ce_copy_complete_intr_disable(ar, ctrl_addr); - ath10k_ce_error_intr_disable(ar, ctrl_addr); - ath10k_ce_watermark_intr_disable(ar, ctrl_addr); - } + ath10k_ce_copy_complete_intr_disable(ar, ctrl_addr); + ath10k_ce_error_intr_disable(ar, ctrl_addr); + ath10k_ce_watermark_intr_disable(ar, ctrl_addr); +} +EXPORT_SYMBOL(ath10k_ce_disable_interrupt); - return 0; +void ath10k_ce_disable_interrupts(struct ath10k *ar) +{ + int ce_id; + + for (ce_id = 0; ce_id < CE_COUNT; ce_id++) + ath10k_ce_disable_interrupt(ar, ce_id); } EXPORT_SYMBOL(ath10k_ce_disable_interrupts); -void ath10k_ce_enable_interrupts(struct ath10k *ar) +void ath10k_ce_enable_interrupt(struct ath10k *ar, int ce_id) { struct ath10k_ce *ce = ath10k_ce_priv(ar); - int ce_id; struct ath10k_ce_pipe *ce_state; + ce_state = &ce->ce_states[ce_id]; + if (ce_state->attr_flags & CE_ATTR_POLL) + return; + + ath10k_ce_per_engine_handler_adjust(ce_state); +} +EXPORT_SYMBOL(ath10k_ce_enable_interrupt); + +void ath10k_ce_enable_interrupts(struct ath10k *ar) +{ + int ce_id; + /* Enable interrupts for copy engine that * are not using polling mode. */ - for (ce_id = 0; ce_id < CE_COUNT; ce_id++) { - ce_state = &ce->ce_states[ce_id]; - if (ce_state->attr_flags & CE_ATTR_POLL) - continue; - - ath10k_ce_per_engine_handler_adjust(ce_state); - } + for (ce_id = 0; ce_id < CE_COUNT; ce_id++) + ath10k_ce_enable_interrupt(ar, ce_id); } EXPORT_SYMBOL(ath10k_ce_enable_interrupts); @@ -1555,7 +1560,7 @@ ath10k_ce_alloc_src_ring(struct ath10k *ar, unsigned int ce_id, ret = ath10k_ce_alloc_shadow_base(ar, src_ring, nentries); if (ret) { dma_free_coherent(ar->dev, - (nentries * sizeof(struct ce_desc_64) + + (nentries * sizeof(struct ce_desc) + CE_DESC_RING_ALIGN), src_ring->base_addr_owner_space_unaligned, base_addr); diff --git a/drivers/net/wireless/ath/ath10k/ce.h b/drivers/net/wireless/ath/ath10k/ce.h index 75df79d43120..666ce384a1d8 100644 --- a/drivers/net/wireless/ath/ath10k/ce.h +++ b/drivers/net/wireless/ath/ath10k/ce.h @@ -255,10 +255,13 @@ int ath10k_ce_cancel_send_next(struct ath10k_ce_pipe *ce_state, /*==================CE Interrupt Handlers====================*/ void ath10k_ce_per_engine_service_any(struct ath10k *ar); void ath10k_ce_per_engine_service(struct ath10k *ar, unsigned int ce_id); -int ath10k_ce_disable_interrupts(struct ath10k *ar); +void ath10k_ce_disable_interrupt(struct ath10k *ar, int ce_id); +void ath10k_ce_disable_interrupts(struct ath10k *ar); +void ath10k_ce_enable_interrupt(struct ath10k *ar, int ce_id); void ath10k_ce_enable_interrupts(struct ath10k *ar); void ath10k_ce_dump_registers(struct ath10k *ar, struct ath10k_fw_crash_data *crash_data); + void ath10k_ce_alloc_rri(struct ath10k *ar); void ath10k_ce_free_rri(struct ath10k *ar); @@ -369,18 +372,14 @@ static inline u32 ath10k_ce_base_address(struct ath10k *ar, unsigned int ce_id) (((x) & CE_WRAPPER_INTERRUPT_SUMMARY_HOST_MSI_MASK) >> \ CE_WRAPPER_INTERRUPT_SUMMARY_HOST_MSI_LSB) #define CE_WRAPPER_INTERRUPT_SUMMARY_ADDRESS 0x0000 -#define CE_INTERRUPT_SUMMARY (GENMASK(CE_COUNT_MAX - 1, 0)) static inline u32 ath10k_ce_interrupt_summary(struct ath10k *ar) { struct ath10k_ce *ce = ath10k_ce_priv(ar); - if (!ar->hw_params.per_ce_irq) - return CE_WRAPPER_INTERRUPT_SUMMARY_HOST_MSI_GET( - ce->bus_ops->read32((ar), CE_WRAPPER_BASE_ADDRESS + - CE_WRAPPER_INTERRUPT_SUMMARY_ADDRESS)); - else - return CE_INTERRUPT_SUMMARY; + return CE_WRAPPER_INTERRUPT_SUMMARY_HOST_MSI_GET( + ce->bus_ops->read32((ar), CE_WRAPPER_BASE_ADDRESS + + CE_WRAPPER_INTERRUPT_SUMMARY_ADDRESS)); } /* Host software's Copy Engine configuration. */ diff --git a/drivers/net/wireless/ath/ath10k/core.c b/drivers/net/wireless/ath/ath10k/core.c index 340ce327ac14..5f4e1219684b 100644 --- a/drivers/net/wireless/ath/ath10k/core.c +++ b/drivers/net/wireless/ath/ath10k/core.c @@ -119,7 +119,6 @@ static const struct ath10k_hw_params ath10k_hw_params_list[] = { .num_wds_entries = 0x20, .target_64bit = false, .rx_ring_fill_level = HTT_RX_RING_FILL_LEVEL, - .per_ce_irq = false, .shadow_reg_support = false, .rri_on_ddr = false, .hw_filter_reset_required = true, @@ -155,7 +154,6 @@ static const struct ath10k_hw_params ath10k_hw_params_list[] = { .num_wds_entries = 0x20, .target_64bit = false, .rx_ring_fill_level = HTT_RX_RING_FILL_LEVEL, - .per_ce_irq = false, .shadow_reg_support = false, .rri_on_ddr = false, .hw_filter_reset_required = true, @@ -220,7 +218,6 @@ static const struct ath10k_hw_params ath10k_hw_params_list[] = { .num_wds_entries = 0x20, .target_64bit = false, .rx_ring_fill_level = HTT_RX_RING_FILL_LEVEL, - .per_ce_irq = false, .shadow_reg_support = false, .rri_on_ddr = false, .hw_filter_reset_required = true, @@ -255,7 +252,6 @@ static const struct ath10k_hw_params ath10k_hw_params_list[] = { .num_wds_entries = 0x20, .target_64bit = false, .rx_ring_fill_level = HTT_RX_RING_FILL_LEVEL, - .per_ce_irq = false, .shadow_reg_support = false, .rri_on_ddr = false, .hw_filter_reset_required = true, @@ -290,7 +286,6 @@ static const struct ath10k_hw_params ath10k_hw_params_list[] = { .num_wds_entries = 0x20, .target_64bit = false, .rx_ring_fill_level = HTT_RX_RING_FILL_LEVEL, - .per_ce_irq = false, .shadow_reg_support = false, .rri_on_ddr = false, .hw_filter_reset_required = true, @@ -328,12 +323,12 @@ static const struct ath10k_hw_params ath10k_hw_params_list[] = { .num_wds_entries = 0x20, .target_64bit = false, .rx_ring_fill_level = HTT_RX_RING_FILL_LEVEL, - .per_ce_irq = false, .shadow_reg_support = false, .rri_on_ddr = false, .hw_filter_reset_required = true, .fw_diag_ce_download = true, .tx_stats_over_pktlog = false, + .supports_peer_stats_info = true, }, { .id = QCA99X0_HW_2_0_DEV_VERSION, @@ -369,7 +364,6 @@ static const struct ath10k_hw_params ath10k_hw_params_list[] = { .num_wds_entries = 0x20, .target_64bit = false, .rx_ring_fill_level = HTT_RX_RING_FILL_LEVEL, - .per_ce_irq = false, .shadow_reg_support = false, .rri_on_ddr = false, .hw_filter_reset_required = true, @@ -417,7 +411,6 @@ static const struct ath10k_hw_params ath10k_hw_params_list[] = { .num_wds_entries = 0x20, .target_64bit = false, .rx_ring_fill_level = HTT_RX_RING_FILL_LEVEL, - .per_ce_irq = false, .shadow_reg_support = false, .rri_on_ddr = false, .hw_filter_reset_required = true, @@ -462,7 +455,6 @@ static const struct ath10k_hw_params ath10k_hw_params_list[] = { .num_wds_entries = 0x20, .target_64bit = false, .rx_ring_fill_level = HTT_RX_RING_FILL_LEVEL, - .per_ce_irq = false, .shadow_reg_support = false, .rri_on_ddr = false, .hw_filter_reset_required = true, @@ -497,7 +489,6 @@ static const struct ath10k_hw_params ath10k_hw_params_list[] = { .num_wds_entries = 0x20, .target_64bit = false, .rx_ring_fill_level = HTT_RX_RING_FILL_LEVEL, - .per_ce_irq = false, .shadow_reg_support = false, .rri_on_ddr = false, .hw_filter_reset_required = true, @@ -534,7 +525,6 @@ static const struct ath10k_hw_params ath10k_hw_params_list[] = { .num_wds_entries = 0x20, .target_64bit = false, .rx_ring_fill_level = HTT_RX_RING_FILL_LEVEL, - .per_ce_irq = false, .shadow_reg_support = false, .rri_on_ddr = false, .hw_filter_reset_required = true, @@ -603,7 +593,6 @@ static const struct ath10k_hw_params ath10k_hw_params_list[] = { .num_wds_entries = 0x20, .target_64bit = false, .rx_ring_fill_level = HTT_RX_RING_FILL_LEVEL, - .per_ce_irq = false, .shadow_reg_support = false, .rri_on_ddr = false, .hw_filter_reset_required = true, @@ -631,7 +620,6 @@ static const struct ath10k_hw_params ath10k_hw_params_list[] = { .num_wds_entries = TARGET_HL_TLV_NUM_WDS_ENTRIES, .target_64bit = true, .rx_ring_fill_level = HTT_RX_RING_FILL_LEVEL_DUAL_MAC, - .per_ce_irq = true, .shadow_reg_support = true, .rri_on_ddr = true, .hw_filter_reset_required = false, @@ -740,6 +728,16 @@ static int ath10k_init_sdio(struct ath10k *ar, enum ath10k_firmware_mode mode) if (ret) return ret; + ret = ath10k_bmi_read32(ar, hi_option_flag2, ¶m); + if (ret) + return ret; + + param |= HI_OPTION_SDIO_CRASH_DUMP_ENHANCEMENT_HOST; + + ret = ath10k_bmi_write32(ar, hi_option_flag2, param); + if (ret) + return ret; + return 0; } @@ -2320,7 +2318,7 @@ static void ath10k_core_restart(struct work_struct *work) break; case ATH10K_STATE_RESTARTED: ar->state = ATH10K_STATE_WEDGED; - /* fall through */ + fallthrough; case ATH10K_STATE_WEDGED: ath10k_warn(ar, "device is wedged, will not restart\n"); break; @@ -2614,6 +2612,13 @@ int ath10k_core_start(struct ath10k *ar, enum ath10k_firmware_mode mode, ar->running_fw->fw_file.fw_features)) { ath10k_bmi_start(ar); + /* Enable hardware clock to speed up firmware download */ + if (ar->hw_params.hw_ops->enable_pll_clk) { + status = ar->hw_params.hw_ops->enable_pll_clk(ar); + ath10k_dbg(ar, ATH10K_DBG_BOOT, "boot enable pll ret %d\n", + status); + } + if (ath10k_init_configure_target(ar)) { status = -EINVAL; goto err; @@ -2797,6 +2802,10 @@ int ath10k_core_start(struct ath10k *ar, enum ath10k_firmware_mode mode, if (test_bit(WMI_SERVICE_REPORT_AIRTIME, ar->wmi.svc_map)) val |= WMI_10_4_REPORT_AIRTIME; + if (test_bit(WMI_SERVICE_EXT_PEER_TID_CONFIGS_SUPPORT, + ar->wmi.svc_map)) + val |= WMI_10_4_EXT_PEER_TID_CONFIGS_SUPPORT; + status = ath10k_mac_ext_resource_config(ar, val); if (status) { ath10k_err(ar, diff --git a/drivers/net/wireless/ath/ath10k/core.h b/drivers/net/wireless/ath/ath10k/core.h index 5c18f6c20462..4cf5bd4896bc 100644 --- a/drivers/net/wireless/ath/ath10k/core.h +++ b/drivers/net/wireless/ath/ath10k/core.h @@ -82,6 +82,8 @@ /* Default Airtime weight multipler (Tuned for multiclient performance) */ #define ATH10K_AIRTIME_WEIGHT_MULTIPLIER 4 +#define ATH10K_MAX_RETRY_COUNT 30 + struct ath10k; static inline const char *ath10k_bus_str(enum ath10k_bus bus) @@ -109,6 +111,7 @@ enum ath10k_skb_flags { ATH10K_SKB_F_MGMT = BIT(3), ATH10K_SKB_F_QOS = BIT(4), ATH10K_SKB_F_RAW_TX = BIT(5), + ATH10K_SKB_F_NOACK_TID = BIT(6), }; struct ath10k_skb_cb { @@ -509,6 +512,8 @@ struct ath10k_htt_tx_stats { u64 ack_fails; }; +#define ATH10K_TID_MAX 8 + struct ath10k_sta { struct ath10k_vif *arvif; @@ -542,6 +547,13 @@ struct ath10k_sta { #endif /* Protected with ar->data_lock */ u32 peer_ps_state; + struct work_struct tid_config_wk; + int noack[ATH10K_TID_MAX]; + int retry_long[ATH10K_TID_MAX]; + int ampdu[ATH10K_TID_MAX]; + u8 rate_ctrl[ATH10K_TID_MAX]; + u32 rate_code[ATH10K_TID_MAX]; + int rtscts[ATH10K_TID_MAX]; }; #define ATH10K_VDEV_SETUP_TIMEOUT_HZ (5 * HZ) @@ -614,6 +626,14 @@ struct ath10k_vif { /* For setting VHT peer fixed rate, protected by conf_mutex */ int vht_num_rates; u8 vht_pfr; + u32 tid_conf_changed[ATH10K_TID_MAX]; + int noack[ATH10K_TID_MAX]; + int retry_long[ATH10K_TID_MAX]; + int ampdu[ATH10K_TID_MAX]; + u8 rate_ctrl[ATH10K_TID_MAX]; + u32 rate_code[ATH10K_TID_MAX]; + int rtscts[ATH10K_TID_MAX]; + u32 tids_rst; }; struct ath10k_vif_iter { diff --git a/drivers/net/wireless/ath/ath10k/coredump.c b/drivers/net/wireless/ath/ath10k/coredump.c index 2a4498067024..7eb72290a925 100644 --- a/drivers/net/wireless/ath/ath10k/coredump.c +++ b/drivers/net/wireless/ath/ath10k/coredump.c @@ -270,6 +270,277 @@ static const struct ath10k_mem_section qca6174_hw21_register_sections[] = { {0x80010, 0x80020}, }; +static const struct ath10k_mem_section qca6174_hw30_sdio_register_sections[] = { + {0x800, 0x810}, + {0x820, 0x82C}, + {0x830, 0x8F4}, + {0x90C, 0x91C}, + {0xA14, 0xA18}, + {0xA84, 0xA94}, + {0xAA8, 0xAD4}, + {0xADC, 0xB40}, + {0x1000, 0x10A4}, + {0x10BC, 0x111C}, + {0x1134, 0x1138}, + {0x1144, 0x114C}, + {0x1150, 0x115C}, + {0x1160, 0x1178}, + {0x1240, 0x1260}, + {0x2000, 0x207C}, + {0x3000, 0x3014}, + {0x4000, 0x4014}, + {0x5000, 0x5124}, + {0x6000, 0x6040}, + {0x6080, 0x60CC}, + {0x6100, 0x611C}, + {0x6140, 0x61D8}, + {0x6200, 0x6238}, + {0x6240, 0x628C}, + {0x62C0, 0x62EC}, + {0x6380, 0x63E8}, + {0x6400, 0x6440}, + {0x6480, 0x64CC}, + {0x6500, 0x651C}, + {0x6540, 0x6580}, + {0x6600, 0x6638}, + {0x6640, 0x668C}, + {0x66C0, 0x66EC}, + {0x6780, 0x67E8}, + {0x7080, 0x708C}, + {0x70C0, 0x70C8}, + {0x7400, 0x741C}, + {0x7440, 0x7454}, + {0x7800, 0x7818}, + {0x8010, 0x8060}, + {0x8080, 0x8084}, + {0x80A0, 0x80A4}, + {0x80C0, 0x80C4}, + {0x80E0, 0x80ec}, + {0x8110, 0x8128}, + {0x9000, 0x9004}, + {0xF000, 0xF0E0}, + {0xF140, 0xF190}, + {0xF250, 0xF25C}, + {0xF260, 0xF268}, + {0xF26C, 0xF2A8}, + {0x10008, 0x1000C}, + {0x10014, 0x10018}, + {0x1001C, 0x10020}, + {0x10024, 0x10028}, + {0x10030, 0x10034}, + {0x10040, 0x10054}, + {0x10058, 0x1007C}, + {0x10080, 0x100C4}, + {0x100C8, 0x10114}, + {0x1012C, 0x10130}, + {0x10138, 0x10144}, + {0x10200, 0x10220}, + {0x10230, 0x10250}, + {0x10260, 0x10280}, + {0x10290, 0x102B0}, + {0x102C0, 0x102DC}, + {0x102E0, 0x102F4}, + {0x102FC, 0x1037C}, + {0x10380, 0x10390}, + {0x10800, 0x10828}, + {0x10840, 0x10844}, + {0x10880, 0x10884}, + {0x108C0, 0x108E8}, + {0x10900, 0x10928}, + {0x10940, 0x10944}, + {0x10980, 0x10984}, + {0x109C0, 0x109E8}, + {0x10A00, 0x10A28}, + {0x10A40, 0x10A50}, + {0x11000, 0x11028}, + {0x11030, 0x11034}, + {0x11038, 0x11068}, + {0x11070, 0x11074}, + {0x11078, 0x110A8}, + {0x110B0, 0x110B4}, + {0x110B8, 0x110E8}, + {0x110F0, 0x110F4}, + {0x110F8, 0x11128}, + {0x11138, 0x11144}, + {0x11178, 0x11180}, + {0x111B8, 0x111C0}, + {0x111F8, 0x11200}, + {0x11238, 0x1123C}, + {0x11270, 0x11274}, + {0x11278, 0x1127C}, + {0x112B0, 0x112B4}, + {0x112B8, 0x112BC}, + {0x112F0, 0x112F4}, + {0x112F8, 0x112FC}, + {0x11338, 0x1133C}, + {0x11378, 0x1137C}, + {0x113B8, 0x113BC}, + {0x113F8, 0x113FC}, + {0x11438, 0x11440}, + {0x11478, 0x11480}, + {0x114B8, 0x114BC}, + {0x114F8, 0x114FC}, + {0x11538, 0x1153C}, + {0x11578, 0x1157C}, + {0x115B8, 0x115BC}, + {0x115F8, 0x115FC}, + {0x11638, 0x1163C}, + {0x11678, 0x1167C}, + {0x116B8, 0x116BC}, + {0x116F8, 0x116FC}, + {0x11738, 0x1173C}, + {0x11778, 0x1177C}, + {0x117B8, 0x117BC}, + {0x117F8, 0x117FC}, + {0x17000, 0x1701C}, + {0x17020, 0x170AC}, + {0x18000, 0x18050}, + {0x18054, 0x18074}, + {0x18080, 0x180D4}, + {0x180DC, 0x18104}, + {0x18108, 0x1813C}, + {0x18144, 0x18148}, + {0x18168, 0x18174}, + {0x18178, 0x18180}, + {0x181C8, 0x181E0}, + {0x181E4, 0x181E8}, + {0x181EC, 0x1820C}, + {0x1825C, 0x18280}, + {0x18284, 0x18290}, + {0x18294, 0x182A0}, + {0x18300, 0x18304}, + {0x18314, 0x18320}, + {0x18328, 0x18350}, + {0x1835C, 0x1836C}, + {0x18370, 0x18390}, + {0x18398, 0x183AC}, + {0x183BC, 0x183D8}, + {0x183DC, 0x183F4}, + {0x18400, 0x186F4}, + {0x186F8, 0x1871C}, + {0x18720, 0x18790}, + {0x19800, 0x19830}, + {0x19834, 0x19840}, + {0x19880, 0x1989C}, + {0x198A4, 0x198B0}, + {0x198BC, 0x19900}, + {0x19C00, 0x19C88}, + {0x19D00, 0x19D20}, + {0x19E00, 0x19E7C}, + {0x19E80, 0x19E94}, + {0x19E98, 0x19EAC}, + {0x19EB0, 0x19EBC}, + {0x19F70, 0x19F74}, + {0x19F80, 0x19F8C}, + {0x19FA0, 0x19FB4}, + {0x19FC0, 0x19FD8}, + {0x1A000, 0x1A200}, + {0x1A204, 0x1A210}, + {0x1A228, 0x1A22C}, + {0x1A230, 0x1A248}, + {0x1A250, 0x1A270}, + {0x1A280, 0x1A290}, + {0x1A2A0, 0x1A2A4}, + {0x1A2C0, 0x1A2EC}, + {0x1A300, 0x1A3BC}, + {0x1A3F0, 0x1A3F4}, + {0x1A3F8, 0x1A434}, + {0x1A438, 0x1A444}, + {0x1A448, 0x1A468}, + {0x1A580, 0x1A58C}, + {0x1A644, 0x1A654}, + {0x1A670, 0x1A698}, + {0x1A6AC, 0x1A6B0}, + {0x1A6D0, 0x1A6D4}, + {0x1A6EC, 0x1A70C}, + {0x1A710, 0x1A738}, + {0x1A7C0, 0x1A7D0}, + {0x1A7D4, 0x1A7D8}, + {0x1A7DC, 0x1A7E4}, + {0x1A7F0, 0x1A7F8}, + {0x1A888, 0x1A89C}, + {0x1A8A8, 0x1A8AC}, + {0x1A8C0, 0x1A8DC}, + {0x1A8F0, 0x1A8FC}, + {0x1AE04, 0x1AE08}, + {0x1AE18, 0x1AE24}, + {0x1AF80, 0x1AF8C}, + {0x1AFA0, 0x1AFB4}, + {0x1B000, 0x1B200}, + {0x1B284, 0x1B288}, + {0x1B2D0, 0x1B2D8}, + {0x1B2DC, 0x1B2EC}, + {0x1B300, 0x1B340}, + {0x1B374, 0x1B378}, + {0x1B380, 0x1B384}, + {0x1B388, 0x1B38C}, + {0x1B404, 0x1B408}, + {0x1B420, 0x1B428}, + {0x1B440, 0x1B444}, + {0x1B448, 0x1B44C}, + {0x1B450, 0x1B458}, + {0x1B45C, 0x1B468}, + {0x1B584, 0x1B58C}, + {0x1B68C, 0x1B690}, + {0x1B6AC, 0x1B6B0}, + {0x1B7F0, 0x1B7F8}, + {0x1C800, 0x1CC00}, + {0x1CE00, 0x1CE04}, + {0x1CF80, 0x1CF84}, + {0x1D200, 0x1D800}, + {0x1E000, 0x20014}, + {0x20100, 0x20124}, + {0x21400, 0x217A8}, + {0x21800, 0x21BA8}, + {0x21C00, 0x21FA8}, + {0x22000, 0x223A8}, + {0x22400, 0x227A8}, + {0x22800, 0x22BA8}, + {0x22C00, 0x22FA8}, + {0x23000, 0x233A8}, + {0x24000, 0x24034}, + + /* EFUSE0,1,2 is disabled here + * because its state may be reset + * + * {0x24800, 0x24804}, + * {0x25000, 0x25004}, + * {0x25800, 0x25804}, + */ + + {0x26000, 0x26064}, + {0x27000, 0x27024}, + {0x34000, 0x3400C}, + {0x34400, 0x3445C}, + {0x34800, 0x3485C}, + {0x34C00, 0x34C5C}, + {0x35000, 0x3505C}, + {0x35400, 0x3545C}, + {0x35800, 0x3585C}, + {0x35C00, 0x35C5C}, + {0x36000, 0x3605C}, + {0x38000, 0x38064}, + {0x38070, 0x380E0}, + {0x3A000, 0x3A074}, + + /* DBI windows is skipped here, it can be only accessed when pcie + * is active (not in reset) and CORE_CTRL_PCIE_LTSSM_EN = 0 && + * PCIE_CTRL_APP_LTSSM_ENALBE=0. + * {0x3C000 , 0x3C004}, + */ + + {0x40000, 0x400A4}, + + /* SI register is skiped here. + * Because it will cause bus hang + * + * {0x50000, 0x50018}, + */ + + {0x80000, 0x8000C}, + {0x80010, 0x80020}, +}; + static const struct ath10k_mem_section qca6174_hw30_register_sections[] = { {0x800, 0x810}, {0x820, 0x82C}, @@ -602,6 +873,59 @@ static const struct ath10k_mem_region qca6174_hw21_mem_regions[] = { }, }; +static const struct ath10k_mem_region qca6174_hw30_sdio_mem_regions[] = { + { + .type = ATH10K_MEM_REGION_TYPE_DRAM, + .start = 0x400000, + .len = 0xa8000, + .name = "DRAM", + .section_table = { + .sections = NULL, + .size = 0, + }, + }, + { + .type = ATH10K_MEM_REGION_TYPE_AXI, + .start = 0xa0000, + .len = 0x18000, + .name = "AXI", + .section_table = { + .sections = NULL, + .size = 0, + }, + }, + { + .type = ATH10K_MEM_REGION_TYPE_IRAM1, + .start = 0x00980000, + .len = 0x00080000, + .name = "IRAM1", + .section_table = { + .sections = NULL, + .size = 0, + }, + }, + { + .type = ATH10K_MEM_REGION_TYPE_IRAM2, + .start = 0x00a00000, + .len = 0x00040000, + .name = "IRAM2", + .section_table = { + .sections = NULL, + .size = 0, + }, + }, + { + .type = ATH10K_MEM_REGION_TYPE_REG, + .start = 0x800, + .len = 0x80020 - 0x800, + .name = "REG_TOTAL", + .section_table = { + .sections = qca6174_hw30_sdio_register_sections, + .size = ARRAY_SIZE(qca6174_hw30_sdio_register_sections), + }, + }, +}; + static const struct ath10k_mem_region qca6174_hw30_mem_regions[] = { { .type = ATH10K_MEM_REGION_TYPE_DRAM, @@ -968,6 +1292,7 @@ static const struct ath10k_hw_mem_layout hw_mem_layouts[] = { { .hw_id = QCA6174_HW_1_0_VERSION, .hw_rev = ATH10K_HW_QCA6174, + .bus = ATH10K_BUS_PCI, .region_table = { .regions = qca6174_hw10_mem_regions, .size = ARRAY_SIZE(qca6174_hw10_mem_regions), @@ -976,6 +1301,7 @@ static const struct ath10k_hw_mem_layout hw_mem_layouts[] = { { .hw_id = QCA6174_HW_1_1_VERSION, .hw_rev = ATH10K_HW_QCA6174, + .bus = ATH10K_BUS_PCI, .region_table = { .regions = qca6174_hw10_mem_regions, .size = ARRAY_SIZE(qca6174_hw10_mem_regions), @@ -984,6 +1310,7 @@ static const struct ath10k_hw_mem_layout hw_mem_layouts[] = { { .hw_id = QCA6174_HW_1_3_VERSION, .hw_rev = ATH10K_HW_QCA6174, + .bus = ATH10K_BUS_PCI, .region_table = { .regions = qca6174_hw10_mem_regions, .size = ARRAY_SIZE(qca6174_hw10_mem_regions), @@ -992,6 +1319,7 @@ static const struct ath10k_hw_mem_layout hw_mem_layouts[] = { { .hw_id = QCA6174_HW_2_1_VERSION, .hw_rev = ATH10K_HW_QCA6174, + .bus = ATH10K_BUS_PCI, .region_table = { .regions = qca6174_hw21_mem_regions, .size = ARRAY_SIZE(qca6174_hw21_mem_regions), @@ -1000,6 +1328,7 @@ static const struct ath10k_hw_mem_layout hw_mem_layouts[] = { { .hw_id = QCA6174_HW_3_0_VERSION, .hw_rev = ATH10K_HW_QCA6174, + .bus = ATH10K_BUS_PCI, .region_table = { .regions = qca6174_hw30_mem_regions, .size = ARRAY_SIZE(qca6174_hw30_mem_regions), @@ -1008,14 +1337,25 @@ static const struct ath10k_hw_mem_layout hw_mem_layouts[] = { { .hw_id = QCA6174_HW_3_2_VERSION, .hw_rev = ATH10K_HW_QCA6174, + .bus = ATH10K_BUS_PCI, .region_table = { .regions = qca6174_hw30_mem_regions, .size = ARRAY_SIZE(qca6174_hw30_mem_regions), }, }, { + .hw_id = QCA6174_HW_3_2_VERSION, + .hw_rev = ATH10K_HW_QCA6174, + .bus = ATH10K_BUS_SDIO, + .region_table = { + .regions = qca6174_hw30_sdio_mem_regions, + .size = ARRAY_SIZE(qca6174_hw30_sdio_mem_regions), + }, + }, + { .hw_id = QCA9377_HW_1_1_DEV_VERSION, .hw_rev = ATH10K_HW_QCA9377, + .bus = ATH10K_BUS_PCI, .region_table = { .regions = qca6174_hw30_mem_regions, .size = ARRAY_SIZE(qca6174_hw30_mem_regions), @@ -1024,6 +1364,7 @@ static const struct ath10k_hw_mem_layout hw_mem_layouts[] = { { .hw_id = QCA988X_HW_2_0_VERSION, .hw_rev = ATH10K_HW_QCA988X, + .bus = ATH10K_BUS_PCI, .region_table = { .regions = qca988x_hw20_mem_regions, .size = ARRAY_SIZE(qca988x_hw20_mem_regions), @@ -1032,6 +1373,7 @@ static const struct ath10k_hw_mem_layout hw_mem_layouts[] = { { .hw_id = QCA9984_HW_1_0_DEV_VERSION, .hw_rev = ATH10K_HW_QCA9984, + .bus = ATH10K_BUS_PCI, .region_table = { .regions = qca9984_hw10_mem_regions, .size = ARRAY_SIZE(qca9984_hw10_mem_regions), @@ -1040,6 +1382,7 @@ static const struct ath10k_hw_mem_layout hw_mem_layouts[] = { { .hw_id = QCA9888_HW_2_0_DEV_VERSION, .hw_rev = ATH10K_HW_QCA9888, + .bus = ATH10K_BUS_PCI, .region_table = { .regions = qca9984_hw10_mem_regions, .size = ARRAY_SIZE(qca9984_hw10_mem_regions), @@ -1048,6 +1391,7 @@ static const struct ath10k_hw_mem_layout hw_mem_layouts[] = { { .hw_id = QCA99X0_HW_2_0_DEV_VERSION, .hw_rev = ATH10K_HW_QCA99X0, + .bus = ATH10K_BUS_PCI, .region_table = { .regions = qca99x0_hw20_mem_regions, .size = ARRAY_SIZE(qca99x0_hw20_mem_regions), @@ -1056,6 +1400,7 @@ static const struct ath10k_hw_mem_layout hw_mem_layouts[] = { { .hw_id = QCA4019_HW_1_0_DEV_VERSION, .hw_rev = ATH10K_HW_QCA4019, + .bus = ATH10K_BUS_AHB, .region_table = { .regions = qca4019_hw10_mem_regions, .size = ARRAY_SIZE(qca4019_hw10_mem_regions), @@ -1064,6 +1409,7 @@ static const struct ath10k_hw_mem_layout hw_mem_layouts[] = { { .hw_id = WCN3990_HW_1_0_DEV_VERSION, .hw_rev = ATH10K_HW_WCN3990, + .bus = ATH10K_BUS_SNOC, .region_table = { .regions = wcn399x_hw10_mem_regions, .size = ARRAY_SIZE(wcn399x_hw10_mem_regions), @@ -1111,7 +1457,8 @@ const struct ath10k_hw_mem_layout *ath10k_coredump_get_mem_layout(struct ath10k for (i = 0; i < ARRAY_SIZE(hw_mem_layouts); i++) { if (ar->target_version == hw_mem_layouts[i].hw_id && - ar->hw_rev == hw_mem_layouts[i].hw_rev) + ar->hw_rev == hw_mem_layouts[i].hw_rev && + hw_mem_layouts[i].bus == ar->hif.bus) return &hw_mem_layouts[i]; } diff --git a/drivers/net/wireless/ath/ath10k/coredump.h b/drivers/net/wireless/ath/ath10k/coredump.h index e760ce1a5f1e..42404e246e0e 100644 --- a/drivers/net/wireless/ath/ath10k/coredump.h +++ b/drivers/net/wireless/ath/ath10k/coredump.h @@ -156,6 +156,7 @@ struct ath10k_mem_region { struct ath10k_hw_mem_layout { u32 hw_id; u32 hw_rev; + enum ath10k_bus bus; struct { const struct ath10k_mem_region *regions; diff --git a/drivers/net/wireless/ath/ath10k/htt_rx.c b/drivers/net/wireless/ath/ath10k/htt_rx.c index d787cbead56a..5c1af2021883 100644 --- a/drivers/net/wireless/ath/ath10k/htt_rx.c +++ b/drivers/net/wireless/ath/ath10k/htt_rx.c @@ -142,6 +142,14 @@ static int __ath10k_htt_rx_ring_fill_n(struct ath10k_htt *htt, int num) BUILD_BUG_ON(HTT_RX_RING_FILL_LEVEL >= HTT_RX_RING_SIZE / 2); idx = __le32_to_cpu(*htt->rx_ring.alloc_idx.vaddr); + + if (idx < 0 || idx >= htt->rx_ring.size) { + ath10k_err(htt->ar, "rx ring index is not valid, firmware malfunctioning?\n"); + idx &= htt->rx_ring.size_mask; + ret = -ENOMEM; + goto fail; + } + while (num > 0) { skb = dev_alloc_skb(HTT_RX_BUF_SIZE + HTT_RX_DESC_ALIGN); if (!skb) { @@ -941,6 +949,7 @@ static void ath10k_htt_rx_h_rates(struct ath10k *ar, u8 preamble = 0; u8 group_id; u32 info1, info2, info3; + u32 stbc, nsts_su; info1 = __le32_to_cpu(rxd->ppdu_start.info1); info2 = __le32_to_cpu(rxd->ppdu_start.info2); @@ -985,11 +994,16 @@ static void ath10k_htt_rx_h_rates(struct ath10k *ar, */ bw = info2 & 3; sgi = info3 & 1; + stbc = (info2 >> 3) & 1; group_id = (info2 >> 4) & 0x3F; if (GROUP_ID_IS_SU_MIMO(group_id)) { mcs = (info3 >> 4) & 0x0F; - nss = ((info2 >> 10) & 0x07) + 1; + nsts_su = ((info2 >> 10) & 0x07); + if (stbc) + nss = (nsts_su >> 2) + 1; + else + nss = (nsts_su + 1); } else { /* Hardware doesn't decode VHT-SIG-B into Rx descriptor * so it's impossible to decode MCS. Also since @@ -3017,7 +3031,7 @@ static int ath10k_htt_rx_in_ord_ind(struct ath10k *ar, struct sk_buff *skb) ath10k_htt_rx_h_enqueue(ar, &amsdu, status); break; case -EAGAIN: - /* fall through */ + fallthrough; default: /* Should not happen. */ ath10k_warn(ar, "failed to extract amsdu: %d\n", ret); @@ -3575,12 +3589,14 @@ ath10k_update_per_peer_tx_stats(struct ath10k *ar, } if (ar->htt.disable_tx_comp) { - arsta->tx_retries += peer_stats->retry_pkts; arsta->tx_failed += peer_stats->failed_pkts; - ath10k_dbg(ar, ATH10K_DBG_HTT, "htt tx retries %d tx failed %d\n", - arsta->tx_retries, arsta->tx_failed); + ath10k_dbg(ar, ATH10K_DBG_HTT, "tx failed %d\n", + arsta->tx_failed); } + arsta->tx_retries += peer_stats->retry_pkts; + ath10k_dbg(ar, ATH10K_DBG_HTT, "htt tx retries %d", arsta->tx_retries); + if (ath10k_debug_is_extd_tx_stats_enabled(ar)) ath10k_accumulate_per_peer_tx_stats(ar, arsta, peer_stats, rate_idx); diff --git a/drivers/net/wireless/ath/ath10k/htt_tx.c b/drivers/net/wireless/ath/ath10k/htt_tx.c index bbe869575855..1fc0a312ab58 100644 --- a/drivers/net/wireless/ath/ath10k/htt_tx.c +++ b/drivers/net/wireless/ath/ath10k/htt_tx.c @@ -1314,7 +1314,7 @@ static int ath10k_htt_tx_hl(struct ath10k_htt *htt, enum ath10k_hw_txrx_mode txm case ATH10K_HW_TXRX_RAW: case ATH10K_HW_TXRX_NATIVE_WIFI: flags0 |= HTT_DATA_TX_DESC_FLAGS0_MAC_HDR_PRESENT; - /* fall through */ + fallthrough; case ATH10K_HW_TXRX_ETHERNET: flags0 |= SM(txmode, HTT_DATA_TX_DESC_FLAGS0_PKT_TYPE); break; @@ -1460,7 +1460,7 @@ static int ath10k_htt_tx_32(struct ath10k_htt *htt, case ATH10K_HW_TXRX_RAW: case ATH10K_HW_TXRX_NATIVE_WIFI: flags0 |= HTT_DATA_TX_DESC_FLAGS0_MAC_HDR_PRESENT; - /* fall through */ + fallthrough; case ATH10K_HW_TXRX_ETHERNET: if (ar->hw_params.continuous_frag_desc) { ext_desc_t = htt->frag_desc.vaddr_desc_32; @@ -1662,7 +1662,7 @@ static int ath10k_htt_tx_64(struct ath10k_htt *htt, case ATH10K_HW_TXRX_RAW: case ATH10K_HW_TXRX_NATIVE_WIFI: flags0 |= HTT_DATA_TX_DESC_FLAGS0_MAC_HDR_PRESENT; - /* fall through */ + fallthrough; case ATH10K_HW_TXRX_ETHERNET: if (ar->hw_params.continuous_frag_desc) { ext_desc_t = htt->frag_desc.vaddr_desc_64; diff --git a/drivers/net/wireless/ath/ath10k/hw.h b/drivers/net/wireless/ath/ath10k/hw.h index f16edcb9f326..c6ded21f5ed6 100644 --- a/drivers/net/wireless/ath/ath10k/hw.h +++ b/drivers/net/wireless/ath/ath10k/hw.h @@ -593,9 +593,6 @@ struct ath10k_hw_params { /* Target rx ring fill level */ u32 rx_ring_fill_level; - /* target supporting per ce IRQ */ - bool per_ce_irq; - /* target supporting shadow register for ce write */ bool shadow_reg_support; diff --git a/drivers/net/wireless/ath/ath10k/mac.c b/drivers/net/wireless/ath/ath10k/mac.c index b37902222517..2e3eb5bbe49c 100644 --- a/drivers/net/wireless/ath/ath10k/mac.c +++ b/drivers/net/wireless/ath/ath10k/mac.c @@ -2468,17 +2468,17 @@ ath10k_peer_assoc_h_vht_limit(u16 tx_mcs_set, idx_limit = -1; switch (idx_limit) { - case 0: /* fall through */ - case 1: /* fall through */ - case 2: /* fall through */ - case 3: /* fall through */ - case 4: /* fall through */ - case 5: /* fall through */ - case 6: /* fall through */ + case 0: + case 1: + case 2: + case 3: + case 4: + case 5: + case 6: default: /* see ath10k_mac_can_set_bitrate_mask() */ WARN_ON(1); - /* fall through */ + fallthrough; case -1: mcs = IEEE80211_VHT_MCS_NOT_SUPPORTED; break; @@ -3013,6 +3013,69 @@ static void ath10k_bss_disassoc(struct ieee80211_hw *hw, cancel_delayed_work_sync(&arvif->connection_loss_work); } +static int ath10k_new_peer_tid_config(struct ath10k *ar, + struct ieee80211_sta *sta, + struct ath10k_vif *arvif) +{ + struct wmi_per_peer_per_tid_cfg_arg arg = {}; + struct ath10k_sta *arsta = (struct ath10k_sta *)sta->drv_priv; + bool config_apply; + int ret, i; + + for (i = 0; i < ATH10K_TID_MAX; i++) { + config_apply = false; + if (arvif->retry_long[i] || arvif->ampdu[i] || + arvif->rate_ctrl[i] || arvif->rtscts[i]) { + config_apply = true; + arg.tid = i; + arg.vdev_id = arvif->vdev_id; + arg.retry_count = arvif->retry_long[i]; + arg.aggr_control = arvif->ampdu[i]; + arg.rate_ctrl = arvif->rate_ctrl[i]; + arg.rcode_flags = arvif->rate_code[i]; + + if (arvif->rtscts[i]) + arg.ext_tid_cfg_bitmap = + WMI_EXT_TID_RTS_CTS_CONFIG; + else + arg.ext_tid_cfg_bitmap = 0; + + arg.rtscts_ctrl = arvif->rtscts[i]; + } + + if (arvif->noack[i]) { + arg.ack_policy = arvif->noack[i]; + arg.rate_ctrl = WMI_TID_CONFIG_RATE_CONTROL_DEFAULT_LOWEST_RATE; + arg.aggr_control = WMI_TID_CONFIG_AGGR_CONTROL_DISABLE; + config_apply = true; + } + + /* Assign default value(-1) to newly connected station. + * This is to identify station specific tid configuration not + * configured for the station. + */ + arsta->retry_long[i] = -1; + arsta->noack[i] = -1; + arsta->ampdu[i] = -1; + + if (!config_apply) + continue; + + ether_addr_copy(arg.peer_macaddr.addr, sta->addr); + + ret = ath10k_wmi_set_per_peer_per_tid_cfg(ar, &arg); + if (ret) { + ath10k_warn(ar, "failed to set per tid retry/aggr config for sta %pM: %d\n", + sta->addr, ret); + return ret; + } + + memset(&arg, 0, sizeof(arg)); + } + + return 0; +} + static int ath10k_station_assoc(struct ath10k *ar, struct ieee80211_vif *vif, struct ieee80211_sta *sta, @@ -3078,7 +3141,10 @@ static int ath10k_station_assoc(struct ath10k *ar, } } - return ret; + if (!test_bit(WMI_SERVICE_PEER_TID_CONFIGS_SUPPORT, ar->wmi.svc_map)) + return ret; + + return ath10k_new_peer_tid_config(ar, sta, arvif); } static int ath10k_station_disassoc(struct ath10k *ar, @@ -3626,7 +3692,10 @@ static void ath10k_mac_tx_h_fill_cb(struct ath10k *ar, const struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); bool is_data = ieee80211_is_data(hdr->frame_control) || ieee80211_is_data_qos(hdr->frame_control); + struct ath10k_vif *arvif = (void *)vif->drv_priv; struct ath10k_sta *arsta; + u8 tid, *qos_ctl; + bool noack = false; cb->flags = 0; if (!ath10k_tx_h_use_hwcrypto(vif, skb)) @@ -3635,8 +3704,27 @@ static void ath10k_mac_tx_h_fill_cb(struct ath10k *ar, if (ieee80211_is_mgmt(hdr->frame_control)) cb->flags |= ATH10K_SKB_F_MGMT; - if (ieee80211_is_data_qos(hdr->frame_control)) + if (ieee80211_is_data_qos(hdr->frame_control)) { cb->flags |= ATH10K_SKB_F_QOS; + qos_ctl = ieee80211_get_qos_ctl(hdr); + tid = (*qos_ctl) & IEEE80211_QOS_CTL_TID_MASK; + + if (arvif->noack[tid] == WMI_PEER_TID_CONFIG_NOACK) + noack = true; + + if (sta) { + arsta = (struct ath10k_sta *)sta->drv_priv; + + if (arsta->noack[tid] == WMI_PEER_TID_CONFIG_NOACK) + noack = true; + + if (arsta->noack[tid] == WMI_PEER_TID_CONFIG_ACK) + noack = false; + } + + if (noack) + cb->flags |= ATH10K_SKB_F_NOACK_TID; + } /* Data frames encrypted in software will be posted to firmware * with tx encap mode set to RAW. Ex: Multicast traffic generated @@ -4238,7 +4326,7 @@ void __ath10k_scan_finish(struct ath10k *ar) } else if (ar->scan.roc_notify) { ieee80211_remain_on_channel_expired(ar->hw); } - /* fall through */ + fallthrough; case ATH10K_SCAN_STARTING: ar->scan.state = ATH10K_SCAN_IDLE; ar->scan_channel = NULL; @@ -6597,6 +6685,581 @@ out: return ret; } +struct ath10k_mac_iter_tid_conf_data { + struct ieee80211_vif *curr_vif; + struct ath10k *ar; + bool reset_config; +}; + +static bool +ath10k_mac_bitrate_mask_has_single_rate(struct ath10k *ar, + enum nl80211_band band, + const struct cfg80211_bitrate_mask *mask, + int *vht_num_rates) +{ + int num_rates = 0; + int i, tmp; + + num_rates += hweight32(mask->control[band].legacy); + + for (i = 0; i < ARRAY_SIZE(mask->control[band].ht_mcs); i++) + num_rates += hweight8(mask->control[band].ht_mcs[i]); + + *vht_num_rates = 0; + for (i = 0; i < ARRAY_SIZE(mask->control[band].vht_mcs); i++) { + tmp = hweight16(mask->control[band].vht_mcs[i]); + num_rates += tmp; + *vht_num_rates += tmp; + } + + return num_rates == 1; +} + +static int +ath10k_mac_bitrate_mask_get_single_rate(struct ath10k *ar, + enum nl80211_band band, + const struct cfg80211_bitrate_mask *mask, + u8 *rate, u8 *nss, bool vht_only) +{ + int rate_idx; + int i; + u16 bitrate; + u8 preamble; + u8 hw_rate; + + if (vht_only) + goto next; + + if (hweight32(mask->control[band].legacy) == 1) { + rate_idx = ffs(mask->control[band].legacy) - 1; + + if (ar->phy_capability & WHAL_WLAN_11A_CAPABILITY) + rate_idx += ATH10K_MAC_FIRST_OFDM_RATE_IDX; + + hw_rate = ath10k_wmi_legacy_rates[rate_idx].hw_value; + bitrate = ath10k_wmi_legacy_rates[rate_idx].bitrate; + + if (ath10k_mac_bitrate_is_cck(bitrate)) + preamble = WMI_RATE_PREAMBLE_CCK; + else + preamble = WMI_RATE_PREAMBLE_OFDM; + + *nss = 1; + *rate = preamble << 6 | + (*nss - 1) << 4 | + hw_rate << 0; + + return 0; + } + + for (i = 0; i < ARRAY_SIZE(mask->control[band].ht_mcs); i++) { + if (hweight8(mask->control[band].ht_mcs[i]) == 1) { + *nss = i + 1; + *rate = WMI_RATE_PREAMBLE_HT << 6 | + (*nss - 1) << 4 | + (ffs(mask->control[band].ht_mcs[i]) - 1); + + return 0; + } + } + +next: + for (i = 0; i < ARRAY_SIZE(mask->control[band].vht_mcs); i++) { + if (hweight16(mask->control[band].vht_mcs[i]) == 1) { + *nss = i + 1; + *rate = WMI_RATE_PREAMBLE_VHT << 6 | + (*nss - 1) << 4 | + (ffs(mask->control[band].vht_mcs[i]) - 1); + + return 0; + } + } + + return -EINVAL; +} + +static int ath10k_mac_validate_rate_mask(struct ath10k *ar, + struct ieee80211_sta *sta, + u32 rate_ctrl_flag, u8 nss) +{ + if (nss > sta->rx_nss) { + ath10k_warn(ar, "Invalid nss field, configured %u limit %u\n", + nss, sta->rx_nss); + return -EINVAL; + } + + if (ATH10K_HW_PREAMBLE(rate_ctrl_flag) == WMI_RATE_PREAMBLE_VHT) { + if (!sta->vht_cap.vht_supported) { + ath10k_warn(ar, "Invalid VHT rate for sta %pM\n", + sta->addr); + return -EINVAL; + } + } else if (ATH10K_HW_PREAMBLE(rate_ctrl_flag) == WMI_RATE_PREAMBLE_HT) { + if (!sta->ht_cap.ht_supported || sta->vht_cap.vht_supported) { + ath10k_warn(ar, "Invalid HT rate for sta %pM\n", + sta->addr); + return -EINVAL; + } + } else { + if (sta->ht_cap.ht_supported || sta->vht_cap.vht_supported) + return -EINVAL; + } + + return 0; +} + +static int +ath10k_mac_tid_bitrate_config(struct ath10k *ar, + struct ieee80211_vif *vif, + struct ieee80211_sta *sta, + u32 *rate_ctrl_flag, u8 *rate_ctrl, + enum nl80211_tx_rate_setting txrate_type, + const struct cfg80211_bitrate_mask *mask) +{ + struct cfg80211_chan_def def; + enum nl80211_band band; + u8 nss, rate; + int vht_num_rates, ret; + + if (WARN_ON(ath10k_mac_vif_chan(vif, &def))) + return -EINVAL; + + if (txrate_type == NL80211_TX_RATE_AUTOMATIC) { + *rate_ctrl = WMI_TID_CONFIG_RATE_CONTROL_AUTO; + *rate_ctrl_flag = 0; + return 0; + } + + band = def.chan->band; + + if (!ath10k_mac_bitrate_mask_has_single_rate(ar, band, mask, + &vht_num_rates)) { + return -EINVAL; + } + + ret = ath10k_mac_bitrate_mask_get_single_rate(ar, band, mask, + &rate, &nss, false); + if (ret) { + ath10k_warn(ar, "failed to get single rate: %d\n", + ret); + return ret; + } + + *rate_ctrl_flag = rate; + + if (sta && ath10k_mac_validate_rate_mask(ar, sta, *rate_ctrl_flag, nss)) + return -EINVAL; + + if (txrate_type == NL80211_TX_RATE_FIXED) + *rate_ctrl = WMI_TID_CONFIG_RATE_CONTROL_FIXED_RATE; + else if (txrate_type == NL80211_TX_RATE_LIMITED && + (test_bit(WMI_SERVICE_EXT_PEER_TID_CONFIGS_SUPPORT, + ar->wmi.svc_map))) + *rate_ctrl = WMI_PEER_TID_CONFIG_RATE_UPPER_CAP; + else + return -EOPNOTSUPP; + + return 0; +} + +static int ath10k_mac_set_tid_config(struct ath10k *ar, struct ieee80211_sta *sta, + struct ieee80211_vif *vif, u32 changed, + struct wmi_per_peer_per_tid_cfg_arg *arg) +{ + struct ath10k_vif *arvif = (void *)vif->drv_priv; + struct ath10k_sta *arsta; + int ret; + + if (sta) { + if (!sta->wme) + return -ENOTSUPP; + + arsta = (struct ath10k_sta *)sta->drv_priv; + + if (changed & BIT(NL80211_TID_CONFIG_ATTR_NOACK)) { + if ((arsta->retry_long[arg->tid] > 0 || + arsta->rate_code[arg->tid] > 0 || + arsta->ampdu[arg->tid] == + WMI_TID_CONFIG_AGGR_CONTROL_ENABLE) && + arg->ack_policy == WMI_PEER_TID_CONFIG_NOACK) { + changed &= ~BIT(NL80211_TID_CONFIG_ATTR_NOACK); + arg->ack_policy = 0; + arg->aggr_control = 0; + arg->rate_ctrl = 0; + arg->rcode_flags = 0; + } + } + + if (changed & BIT(NL80211_TID_CONFIG_ATTR_AMPDU_CTRL)) { + if (arsta->noack[arg->tid] == WMI_PEER_TID_CONFIG_NOACK || + arvif->noack[arg->tid] == WMI_PEER_TID_CONFIG_NOACK) { + arg->aggr_control = 0; + changed &= ~BIT(NL80211_TID_CONFIG_ATTR_RETRY_LONG); + } + } + + if (changed & (BIT(NL80211_TID_CONFIG_ATTR_TX_RATE) | + BIT(NL80211_TID_CONFIG_ATTR_TX_RATE_TYPE))) { + if (arsta->noack[arg->tid] == WMI_PEER_TID_CONFIG_NOACK || + arvif->noack[arg->tid] == WMI_PEER_TID_CONFIG_NOACK) { + arg->rate_ctrl = 0; + arg->rcode_flags = 0; + } + } + + ether_addr_copy(arg->peer_macaddr.addr, sta->addr); + + ret = ath10k_wmi_set_per_peer_per_tid_cfg(ar, arg); + if (ret) + return ret; + + /* Store the configured parameters in success case */ + if (changed & BIT(NL80211_TID_CONFIG_ATTR_NOACK)) { + arsta->noack[arg->tid] = arg->ack_policy; + arg->ack_policy = 0; + arg->aggr_control = 0; + arg->rate_ctrl = 0; + arg->rcode_flags = 0; + } + + if (changed & BIT(NL80211_TID_CONFIG_ATTR_RETRY_LONG)) { + arsta->retry_long[arg->tid] = arg->retry_count; + arg->retry_count = 0; + } + + if (changed & BIT(NL80211_TID_CONFIG_ATTR_AMPDU_CTRL)) { + arsta->ampdu[arg->tid] = arg->aggr_control; + arg->aggr_control = 0; + } + + if (changed & (BIT(NL80211_TID_CONFIG_ATTR_TX_RATE) | + BIT(NL80211_TID_CONFIG_ATTR_TX_RATE_TYPE))) { + arsta->rate_ctrl[arg->tid] = arg->rate_ctrl; + arg->rate_ctrl = 0; + arg->rcode_flags = 0; + } + + if (changed & BIT(NL80211_TID_CONFIG_ATTR_RTSCTS_CTRL)) { + arsta->rtscts[arg->tid] = arg->rtscts_ctrl; + arg->ext_tid_cfg_bitmap = 0; + } + } else { + if (changed & BIT(NL80211_TID_CONFIG_ATTR_NOACK)) { + if ((arvif->retry_long[arg->tid] || + arvif->rate_code[arg->tid] || + arvif->ampdu[arg->tid] == + WMI_TID_CONFIG_AGGR_CONTROL_ENABLE) && + arg->ack_policy == WMI_PEER_TID_CONFIG_NOACK) { + changed &= ~BIT(NL80211_TID_CONFIG_ATTR_NOACK); + } else { + arvif->noack[arg->tid] = arg->ack_policy; + arvif->ampdu[arg->tid] = arg->aggr_control; + arvif->rate_ctrl[arg->tid] = arg->rate_ctrl; + } + } + + if (changed & BIT(NL80211_TID_CONFIG_ATTR_RETRY_LONG)) { + if (arvif->noack[arg->tid] == WMI_PEER_TID_CONFIG_NOACK) + changed &= ~BIT(NL80211_TID_CONFIG_ATTR_RETRY_LONG); + else + arvif->retry_long[arg->tid] = arg->retry_count; + } + + if (changed & BIT(NL80211_TID_CONFIG_ATTR_AMPDU_CTRL)) { + if (arvif->noack[arg->tid] == WMI_PEER_TID_CONFIG_NOACK) + changed &= ~BIT(NL80211_TID_CONFIG_ATTR_AMPDU_CTRL); + else + arvif->ampdu[arg->tid] = arg->aggr_control; + } + + if (changed & (BIT(NL80211_TID_CONFIG_ATTR_TX_RATE) | + BIT(NL80211_TID_CONFIG_ATTR_TX_RATE_TYPE))) { + if (arvif->noack[arg->tid] == WMI_PEER_TID_CONFIG_NOACK) { + changed &= ~(BIT(NL80211_TID_CONFIG_ATTR_TX_RATE) | + BIT(NL80211_TID_CONFIG_ATTR_TX_RATE_TYPE)); + } else { + arvif->rate_ctrl[arg->tid] = arg->rate_ctrl; + arvif->rate_code[arg->tid] = arg->rcode_flags; + } + } + + if (changed & BIT(NL80211_TID_CONFIG_ATTR_RTSCTS_CTRL)) { + arvif->rtscts[arg->tid] = arg->rtscts_ctrl; + arg->ext_tid_cfg_bitmap = 0; + } + + if (changed) + arvif->tid_conf_changed[arg->tid] |= changed; + } + + return 0; +} + +static int +ath10k_mac_parse_tid_config(struct ath10k *ar, + struct ieee80211_sta *sta, + struct ieee80211_vif *vif, + struct cfg80211_tid_cfg *tid_conf, + struct wmi_per_peer_per_tid_cfg_arg *arg) +{ + u32 changed = tid_conf->mask; + int ret = 0, i = 0; + + if (!changed) + return -EINVAL; + + while (i < ATH10K_TID_MAX) { + if (!(tid_conf->tids & BIT(i))) { + i++; + continue; + } + + arg->tid = i; + + if (changed & BIT(NL80211_TID_CONFIG_ATTR_NOACK)) { + if (tid_conf->noack == NL80211_TID_CONFIG_ENABLE) { + arg->ack_policy = WMI_PEER_TID_CONFIG_NOACK; + arg->rate_ctrl = + WMI_TID_CONFIG_RATE_CONTROL_DEFAULT_LOWEST_RATE; + arg->aggr_control = + WMI_TID_CONFIG_AGGR_CONTROL_DISABLE; + } else { + arg->ack_policy = + WMI_PEER_TID_CONFIG_ACK; + arg->rate_ctrl = + WMI_TID_CONFIG_RATE_CONTROL_AUTO; + arg->aggr_control = + WMI_TID_CONFIG_AGGR_CONTROL_ENABLE; + } + } + + if (changed & BIT(NL80211_TID_CONFIG_ATTR_RETRY_LONG)) + arg->retry_count = tid_conf->retry_long; + + if (changed & BIT(NL80211_TID_CONFIG_ATTR_AMPDU_CTRL)) { + if (tid_conf->noack == NL80211_TID_CONFIG_ENABLE) + arg->aggr_control = WMI_TID_CONFIG_AGGR_CONTROL_ENABLE; + else + arg->aggr_control = WMI_TID_CONFIG_AGGR_CONTROL_DISABLE; + } + + if (changed & (BIT(NL80211_TID_CONFIG_ATTR_TX_RATE) | + BIT(NL80211_TID_CONFIG_ATTR_TX_RATE_TYPE))) { + ret = ath10k_mac_tid_bitrate_config(ar, vif, sta, + &arg->rcode_flags, + &arg->rate_ctrl, + tid_conf->txrate_type, + &tid_conf->txrate_mask); + if (ret) { + ath10k_warn(ar, "failed to configure bitrate mask %d\n", + ret); + arg->rcode_flags = 0; + arg->rate_ctrl = 0; + } + } + + if (changed & BIT(NL80211_TID_CONFIG_ATTR_RTSCTS_CTRL)) { + if (tid_conf->rtscts) + arg->rtscts_ctrl = tid_conf->rtscts; + + arg->ext_tid_cfg_bitmap = WMI_EXT_TID_RTS_CTS_CONFIG; + } + + ret = ath10k_mac_set_tid_config(ar, sta, vif, changed, arg); + if (ret) + return ret; + i++; + } + + return ret; +} + +static int ath10k_mac_reset_tid_config(struct ath10k *ar, + struct ieee80211_sta *sta, + struct ath10k_vif *arvif, + u8 tids) +{ + struct ath10k_sta *arsta = (struct ath10k_sta *)sta->drv_priv; + struct wmi_per_peer_per_tid_cfg_arg arg; + int ret = 0, i = 0; + + arg.vdev_id = arvif->vdev_id; + while (i < ATH10K_TID_MAX) { + if (!(tids & BIT(i))) { + i++; + continue; + } + + arg.tid = i; + arg.ack_policy = WMI_PEER_TID_CONFIG_ACK; + arg.retry_count = ATH10K_MAX_RETRY_COUNT; + arg.rate_ctrl = WMI_TID_CONFIG_RATE_CONTROL_AUTO; + arg.aggr_control = WMI_TID_CONFIG_AGGR_CONTROL_ENABLE; + arg.rtscts_ctrl = WMI_TID_CONFIG_RTSCTS_CONTROL_ENABLE; + arg.ext_tid_cfg_bitmap = WMI_EXT_TID_RTS_CTS_CONFIG; + + ether_addr_copy(arg.peer_macaddr.addr, sta->addr); + + ret = ath10k_wmi_set_per_peer_per_tid_cfg(ar, &arg); + if (ret) + return ret; + + if (!arvif->tids_rst) { + arsta->retry_long[i] = -1; + arsta->noack[i] = -1; + arsta->ampdu[i] = -1; + arsta->rate_code[i] = -1; + arsta->rate_ctrl[i] = 0; + arsta->rtscts[i] = -1; + } else { + arvif->retry_long[i] = 0; + arvif->noack[i] = 0; + arvif->ampdu[i] = 0; + arvif->rate_code[i] = 0; + arvif->rate_ctrl[i] = 0; + arvif->rtscts[i] = 0; + } + + i++; + } + + return ret; +} + +static void ath10k_sta_tid_cfg_wk(struct work_struct *wk) +{ + struct wmi_per_peer_per_tid_cfg_arg arg = {}; + struct ieee80211_sta *sta; + struct ath10k_sta *arsta; + struct ath10k_vif *arvif; + struct ath10k *ar; + bool config_apply; + int ret, i; + u32 changed; + u8 nss; + + arsta = container_of(wk, struct ath10k_sta, tid_config_wk); + sta = container_of((void *)arsta, struct ieee80211_sta, drv_priv); + arvif = arsta->arvif; + ar = arvif->ar; + + mutex_lock(&ar->conf_mutex); + + if (arvif->tids_rst) { + ret = ath10k_mac_reset_tid_config(ar, sta, arvif, + arvif->tids_rst); + goto exit; + } + + ether_addr_copy(arg.peer_macaddr.addr, sta->addr); + + for (i = 0; i < ATH10K_TID_MAX; i++) { + config_apply = false; + changed = arvif->tid_conf_changed[i]; + + if (changed & BIT(NL80211_TID_CONFIG_ATTR_NOACK)) { + if (arsta->noack[i] != -1) { + arg.ack_policy = 0; + } else { + config_apply = true; + arg.ack_policy = arvif->noack[i]; + arg.aggr_control = arvif->ampdu[i]; + arg.rate_ctrl = arvif->rate_ctrl[i]; + } + } + + if (changed & BIT(NL80211_TID_CONFIG_ATTR_RETRY_LONG)) { + if (arsta->retry_long[i] != -1 || + arsta->noack[i] == WMI_PEER_TID_CONFIG_NOACK || + arvif->noack[i] == WMI_PEER_TID_CONFIG_NOACK) { + arg.retry_count = 0; + } else { + arg.retry_count = arvif->retry_long[i]; + config_apply = true; + } + } + + if (changed & BIT(NL80211_TID_CONFIG_ATTR_AMPDU_CTRL)) { + if (arsta->ampdu[i] != -1 || + arsta->noack[i] == WMI_PEER_TID_CONFIG_NOACK || + arvif->noack[i] == WMI_PEER_TID_CONFIG_NOACK) { + arg.aggr_control = 0; + } else { + arg.aggr_control = arvif->ampdu[i]; + config_apply = true; + } + } + + if (changed & (BIT(NL80211_TID_CONFIG_ATTR_TX_RATE) | + BIT(NL80211_TID_CONFIG_ATTR_TX_RATE_TYPE))) { + nss = ATH10K_HW_NSS(arvif->rate_code[i]); + ret = ath10k_mac_validate_rate_mask(ar, sta, + arvif->rate_code[i], + nss); + if (ret && + arvif->rate_ctrl[i] > WMI_TID_CONFIG_RATE_CONTROL_AUTO) { + arg.rate_ctrl = 0; + arg.rcode_flags = 0; + } + + if (arsta->rate_ctrl[i] > + WMI_TID_CONFIG_RATE_CONTROL_AUTO || + arsta->noack[i] == WMI_PEER_TID_CONFIG_NOACK || + arvif->noack[i] == WMI_PEER_TID_CONFIG_NOACK) { + arg.rate_ctrl = 0; + arg.rcode_flags = 0; + } else { + arg.rate_ctrl = arvif->rate_ctrl[i]; + arg.rcode_flags = arvif->rate_code[i]; + config_apply = true; + } + } + + if (changed & BIT(NL80211_TID_CONFIG_ATTR_RTSCTS_CTRL)) { + if (arsta->rtscts[i]) { + arg.rtscts_ctrl = 0; + arg.ext_tid_cfg_bitmap = 0; + } else { + arg.rtscts_ctrl = arvif->rtscts[i] - 1; + arg.ext_tid_cfg_bitmap = + WMI_EXT_TID_RTS_CTS_CONFIG; + config_apply = true; + } + } + + arg.tid = i; + + if (config_apply) { + ret = ath10k_wmi_set_per_peer_per_tid_cfg(ar, &arg); + if (ret) + ath10k_warn(ar, "failed to set per tid config for sta %pM: %d\n", + sta->addr, ret); + } + + arg.ack_policy = 0; + arg.retry_count = 0; + arg.aggr_control = 0; + arg.rate_ctrl = 0; + arg.rcode_flags = 0; + } + +exit: + mutex_unlock(&ar->conf_mutex); +} + +static void ath10k_mac_vif_stations_tid_conf(void *data, + struct ieee80211_sta *sta) +{ + struct ath10k_sta *arsta = (struct ath10k_sta *)sta->drv_priv; + struct ath10k_mac_iter_tid_conf_data *iter_data = data; + struct ieee80211_vif *sta_vif = arsta->arvif->vif; + + if (sta_vif != iter_data->curr_vif || !sta->wme) + return; + + ieee80211_queue_work(iter_data->ar->hw, &arsta->tid_config_wk); +} + static int ath10k_sta_state(struct ieee80211_hw *hw, struct ieee80211_vif *vif, struct ieee80211_sta *sta, @@ -6616,6 +7279,7 @@ static int ath10k_sta_state(struct ieee80211_hw *hw, arsta->arvif = arvif; arsta->peer_ps_state = WMI_PEER_PS_STATE_DISABLED; INIT_WORK(&arsta->update_wk, ath10k_sta_rc_update_wk); + INIT_WORK(&arsta->tid_config_wk, ath10k_sta_tid_cfg_wk); for (i = 0; i < ARRAY_SIZE(sta->txq); i++) ath10k_mac_txq_init(sta->txq[i]); @@ -6623,8 +7287,10 @@ static int ath10k_sta_state(struct ieee80211_hw *hw, /* cancel must be done outside the mutex to avoid deadlock */ if ((old_state == IEEE80211_STA_NONE && - new_state == IEEE80211_STA_NOTEXIST)) + new_state == IEEE80211_STA_NOTEXIST)) { cancel_work_sync(&arsta->update_wk); + cancel_work_sync(&arsta->tid_config_wk); + } mutex_lock(&ar->conf_mutex); @@ -7033,8 +7699,6 @@ exit: return ret; } -#define ATH10K_ROC_TIMEOUT_HZ (2 * HZ) - static int ath10k_remain_on_channel(struct ieee80211_hw *hw, struct ieee80211_vif *vif, struct ieee80211_channel *chan, @@ -7278,7 +7942,7 @@ ath10k_mac_update_bss_chan_survey(struct ath10k *ar, struct ieee80211_channel *channel) { int ret; - enum wmi_bss_survey_req_type type = WMI_BSS_SURVEY_REQ_TYPE_READ_CLEAR; + enum wmi_bss_survey_req_type type = WMI_BSS_SURVEY_REQ_TYPE_READ; lockdep_assert_held(&ar->conf_mutex); @@ -7347,30 +8011,6 @@ exit: } static bool -ath10k_mac_bitrate_mask_has_single_rate(struct ath10k *ar, - enum nl80211_band band, - const struct cfg80211_bitrate_mask *mask, - int *vht_num_rates) -{ - int num_rates = 0; - int i, tmp; - - num_rates += hweight32(mask->control[band].legacy); - - for (i = 0; i < ARRAY_SIZE(mask->control[band].ht_mcs); i++) - num_rates += hweight8(mask->control[band].ht_mcs[i]); - - *vht_num_rates = 0; - for (i = 0; i < ARRAY_SIZE(mask->control[band].vht_mcs); i++) { - tmp = hweight16(mask->control[band].vht_mcs[i]); - num_rates += tmp; - *vht_num_rates += tmp; - } - - return num_rates == 1; -} - -static bool ath10k_mac_bitrate_mask_get_single_nss(struct ath10k *ar, enum nl80211_band band, const struct cfg80211_bitrate_mask *mask, @@ -7419,69 +8059,6 @@ ath10k_mac_bitrate_mask_get_single_nss(struct ath10k *ar, return true; } -static int -ath10k_mac_bitrate_mask_get_single_rate(struct ath10k *ar, - enum nl80211_band band, - const struct cfg80211_bitrate_mask *mask, - u8 *rate, u8 *nss, bool vht_only) -{ - int rate_idx; - int i; - u16 bitrate; - u8 preamble; - u8 hw_rate; - - if (vht_only) - goto next; - - if (hweight32(mask->control[band].legacy) == 1) { - rate_idx = ffs(mask->control[band].legacy) - 1; - - if (ar->phy_capability & WHAL_WLAN_11A_CAPABILITY) - rate_idx += ATH10K_MAC_FIRST_OFDM_RATE_IDX; - - hw_rate = ath10k_wmi_legacy_rates[rate_idx].hw_value; - bitrate = ath10k_wmi_legacy_rates[rate_idx].bitrate; - - if (ath10k_mac_bitrate_is_cck(bitrate)) - preamble = WMI_RATE_PREAMBLE_CCK; - else - preamble = WMI_RATE_PREAMBLE_OFDM; - - *nss = 1; - *rate = preamble << 6 | - (*nss - 1) << 4 | - hw_rate << 0; - - return 0; - } - - for (i = 0; i < ARRAY_SIZE(mask->control[band].ht_mcs); i++) { - if (hweight8(mask->control[band].ht_mcs[i]) == 1) { - *nss = i + 1; - *rate = WMI_RATE_PREAMBLE_HT << 6 | - (*nss - 1) << 4 | - (ffs(mask->control[band].ht_mcs[i]) - 1); - - return 0; - } - } - -next: - for (i = 0; i < ARRAY_SIZE(mask->control[band].vht_mcs); i++) { - if (hweight16(mask->control[band].vht_mcs[i]) == 1) { - *nss = i + 1; - *rate = WMI_RATE_PREAMBLE_VHT << 6 | - (*nss - 1) << 4 | - (ffs(mask->control[band].vht_mcs[i]) - 1); - - return 0; - } - } - - return -EINVAL; -} - static int ath10k_mac_set_fixed_rate_params(struct ath10k_vif *arvif, u8 rate, u8 nss, u8 sgi, u8 ldpc) { @@ -8363,19 +8940,32 @@ static void ath10k_mac_get_rate_flags_ht(struct ath10k *ar, u32 rate, u8 nss, u8 u8 *flags, u8 *bw) { struct ath10k_index_ht_data_rate_type *mcs_rate; + u8 index; + size_t len_nss1 = ARRAY_SIZE(supported_ht_mcs_rate_nss1); + size_t len_nss2 = ARRAY_SIZE(supported_ht_mcs_rate_nss2); + + if (mcs >= (len_nss1 + len_nss2)) { + ath10k_warn(ar, "not supported mcs %d in current rate table", mcs); + return; + } mcs_rate = (struct ath10k_index_ht_data_rate_type *) ((nss == 1) ? &supported_ht_mcs_rate_nss1 : &supported_ht_mcs_rate_nss2); - if (rate == mcs_rate[mcs].supported_rate[0]) { + if (mcs >= len_nss1) + index = mcs - len_nss1; + else + index = mcs; + + if (rate == mcs_rate[index].supported_rate[0]) { *bw = RATE_INFO_BW_20; - } else if (rate == mcs_rate[mcs].supported_rate[1]) { + } else if (rate == mcs_rate[index].supported_rate[1]) { *bw |= RATE_INFO_BW_40; - } else if (rate == mcs_rate[mcs].supported_rate[2]) { + } else if (rate == mcs_rate[index].supported_rate[2]) { *bw |= RATE_INFO_BW_20; *flags |= RATE_INFO_FLAGS_SHORT_GI; - } else if (rate == mcs_rate[mcs].supported_rate[3]) { + } else if (rate == mcs_rate[index].supported_rate[3]) { *bw |= RATE_INFO_BW_40; *flags |= RATE_INFO_FLAGS_SHORT_GI; } else { @@ -8436,6 +9026,9 @@ static void ath10k_mac_parse_bitrate(struct ath10k *ar, u32 rate_code, u8 mcs = WMI_TLV_GET_HW_RC_RATE_V1(rate_code); u8 flags = 0, bw = 0; + ath10k_dbg(ar, ATH10K_DBG_MAC, "mac parse rate code 0x%x bitrate %d kbps\n", + rate_code, bitrate_kbps); + if (preamble == WMI_RATE_PREAMBLE_HT) mode = ATH10K_PHY_MODE_HT; else if (preamble == WMI_RATE_PREAMBLE_VHT) @@ -8528,29 +9121,99 @@ static void ath10k_sta_statistics(struct ieee80211_hw *hw, sinfo->rx_duration = arsta->rx_duration; sinfo->filled |= BIT_ULL(NL80211_STA_INFO_RX_DURATION); - if (!arsta->txrate.legacy && !arsta->txrate.nss) - return; - - if (arsta->txrate.legacy) { - sinfo->txrate.legacy = arsta->txrate.legacy; - } else { - sinfo->txrate.mcs = arsta->txrate.mcs; - sinfo->txrate.nss = arsta->txrate.nss; - sinfo->txrate.bw = arsta->txrate.bw; + if (arsta->txrate.legacy || arsta->txrate.nss) { + if (arsta->txrate.legacy) { + sinfo->txrate.legacy = arsta->txrate.legacy; + } else { + sinfo->txrate.mcs = arsta->txrate.mcs; + sinfo->txrate.nss = arsta->txrate.nss; + sinfo->txrate.bw = arsta->txrate.bw; + } + sinfo->txrate.flags = arsta->txrate.flags; + sinfo->filled |= BIT_ULL(NL80211_STA_INFO_TX_BITRATE); } - sinfo->txrate.flags = arsta->txrate.flags; - sinfo->filled |= BIT_ULL(NL80211_STA_INFO_TX_BITRATE); if (ar->htt.disable_tx_comp) { - sinfo->tx_retries = arsta->tx_retries; - sinfo->filled |= BIT_ULL(NL80211_STA_INFO_TX_RETRIES); sinfo->tx_failed = arsta->tx_failed; sinfo->filled |= BIT_ULL(NL80211_STA_INFO_TX_FAILED); } + sinfo->tx_retries = arsta->tx_retries; + sinfo->filled |= BIT_ULL(NL80211_STA_INFO_TX_RETRIES); + ath10k_mac_sta_get_peer_stats_info(ar, sta, sinfo); } +static int ath10k_mac_op_set_tid_config(struct ieee80211_hw *hw, + struct ieee80211_vif *vif, + struct ieee80211_sta *sta, + struct cfg80211_tid_config *tid_config) +{ + struct ath10k *ar = hw->priv; + struct ath10k_vif *arvif = (void *)vif->drv_priv; + struct ath10k_mac_iter_tid_conf_data data = {}; + struct wmi_per_peer_per_tid_cfg_arg arg = {}; + int ret, i; + + mutex_lock(&ar->conf_mutex); + arg.vdev_id = arvif->vdev_id; + + arvif->tids_rst = 0; + memset(arvif->tid_conf_changed, 0, sizeof(arvif->tid_conf_changed)); + + for (i = 0; i < tid_config->n_tid_conf; i++) { + ret = ath10k_mac_parse_tid_config(ar, sta, vif, + &tid_config->tid_conf[i], + &arg); + if (ret) + goto exit; + } + + if (sta) + goto exit; + + ret = 0; + arvif->tids_rst = 0; + data.curr_vif = vif; + data.ar = ar; + + ieee80211_iterate_stations_atomic(hw, ath10k_mac_vif_stations_tid_conf, + &data); + +exit: + mutex_unlock(&ar->conf_mutex); + return ret; +} + +static int ath10k_mac_op_reset_tid_config(struct ieee80211_hw *hw, + struct ieee80211_vif *vif, + struct ieee80211_sta *sta, + u8 tids) +{ + struct ath10k_vif *arvif = (void *)vif->drv_priv; + struct ath10k_mac_iter_tid_conf_data data = {}; + struct ath10k *ar = hw->priv; + int ret = 0; + + mutex_lock(&ar->conf_mutex); + + if (sta) { + arvif->tids_rst = 0; + ret = ath10k_mac_reset_tid_config(ar, sta, arvif, tids); + goto exit; + } + + arvif->tids_rst = tids; + data.curr_vif = vif; + data.ar = ar; + ieee80211_iterate_stations_atomic(hw, ath10k_mac_vif_stations_tid_conf, + &data); + +exit: + mutex_unlock(&ar->conf_mutex); + return ret; +} + static const struct ieee80211_ops ath10k_ops = { .tx = ath10k_mac_op_tx, .wake_tx_queue = ath10k_mac_op_wake_tx_queue, @@ -8594,6 +9257,8 @@ static const struct ieee80211_ops ath10k_ops = { .switch_vif_chanctx = ath10k_mac_op_switch_vif_chanctx, .sta_pre_rcu_remove = ath10k_mac_op_sta_pre_rcu_remove, .sta_statistics = ath10k_sta_statistics, + .set_tid_config = ath10k_mac_op_set_tid_config, + .reset_tid_config = ath10k_mac_op_reset_tid_config, CFG80211_TESTMODE_CMD(ath10k_tm_cmd) @@ -9264,6 +9929,28 @@ int ath10k_mac_register(struct ath10k *ar) if (test_bit(WMI_SERVICE_TX_PWR_PER_PEER, ar->wmi.svc_map)) wiphy_ext_feature_set(ar->hw->wiphy, NL80211_EXT_FEATURE_STA_TX_PWR); + + if (test_bit(WMI_SERVICE_PEER_TID_CONFIGS_SUPPORT, ar->wmi.svc_map)) { + ar->hw->wiphy->tid_config_support.vif |= + BIT(NL80211_TID_CONFIG_ATTR_NOACK) | + BIT(NL80211_TID_CONFIG_ATTR_RETRY_SHORT) | + BIT(NL80211_TID_CONFIG_ATTR_RETRY_LONG) | + BIT(NL80211_TID_CONFIG_ATTR_AMPDU_CTRL) | + BIT(NL80211_TID_CONFIG_ATTR_TX_RATE) | + BIT(NL80211_TID_CONFIG_ATTR_TX_RATE_TYPE); + + if (test_bit(WMI_SERVICE_EXT_PEER_TID_CONFIGS_SUPPORT, + ar->wmi.svc_map)) { + ar->hw->wiphy->tid_config_support.vif |= + BIT(NL80211_TID_CONFIG_ATTR_RTSCTS_CTRL); + } + + ar->hw->wiphy->tid_config_support.peer = + ar->hw->wiphy->tid_config_support.vif; + ar->hw->wiphy->max_data_retry_count = ATH10K_MAX_RETRY_COUNT; + } else { + ar->ops->set_tid_config = NULL; + } /* * on LL hardware queues are managed entirely by the FW * so we only advertise to mac we can do the queues thing diff --git a/drivers/net/wireless/ath/ath10k/pci.c b/drivers/net/wireless/ath/ath10k/pci.c index cfde7791291a..36426efdb2ea 100644 --- a/drivers/net/wireless/ath/ath10k/pci.c +++ b/drivers/net/wireless/ath/ath10k/pci.c @@ -2184,7 +2184,7 @@ err_req: if (ret == 0 && resp_len) { *resp_len = min(*resp_len, xfer.resp_len); - memcpy(resp, tresp, xfer.resp_len); + memcpy(resp, tresp, *resp_len); } err_dma: kfree(treq); diff --git a/drivers/net/wireless/ath/ath10k/sdio.c b/drivers/net/wireless/ath/ath10k/sdio.c index 63f882c690bf..81ddaafb6721 100644 --- a/drivers/net/wireless/ath/ath10k/sdio.c +++ b/drivers/net/wireless/ath/ath10k/sdio.c @@ -23,6 +23,9 @@ #include "targaddrs.h" #include "trace.h" #include "sdio.h" +#include "coredump.h" + +void ath10k_sdio_fw_crashed_dump(struct ath10k *ar); #define ATH10K_SDIO_VSG_BUF_SIZE (64 * 1024) @@ -557,6 +560,10 @@ static int ath10k_sdio_mbox_rx_alloc(struct ath10k *ar, le16_to_cpu(htc_hdr->len), ATH10K_HTC_MBOX_MAX_PAYLOAD_LENGTH); ret = -ENOMEM; + + queue_work(ar->workqueue, &ar->restart_work); + ath10k_warn(ar, "exceeds length, start recovery\n"); + goto err; } @@ -912,10 +919,9 @@ static int ath10k_sdio_mbox_proc_cpu_intr(struct ath10k *ar) out: mutex_unlock(&irq_data->mtx); - if (cpu_int_status & MBOX_CPU_STATUS_ENABLE_ASSERT_MASK) { - ath10k_err(ar, "firmware crashed!\n"); - queue_work(ar->workqueue, &ar->restart_work); - } + if (cpu_int_status & MBOX_CPU_STATUS_ENABLE_ASSERT_MASK) + ath10k_sdio_fw_crashed_dump(ar); + return ret; } @@ -2181,6 +2187,323 @@ static int ath10k_sdio_napi_poll(struct napi_struct *ctx, int budget) return done; } +static int ath10k_sdio_read_host_interest_value(struct ath10k *ar, + u32 item_offset, + u32 *val) +{ + u32 addr; + int ret; + + addr = host_interest_item_address(item_offset); + + ret = ath10k_sdio_diag_read32(ar, addr, val); + + if (ret) + ath10k_warn(ar, "unable to read host interest offset %d value\n", + item_offset); + + return ret; +} + +static int ath10k_sdio_read_mem(struct ath10k *ar, u32 address, void *buf, + u32 buf_len) +{ + u32 val; + int i, ret; + + for (i = 0; i < buf_len; i += 4) { + ret = ath10k_sdio_diag_read32(ar, address + i, &val); + if (ret) { + ath10k_warn(ar, "unable to read mem %d value\n", address + i); + break; + } + memcpy(buf + i, &val, 4); + } + + return ret; +} + +static bool ath10k_sdio_is_fast_dump_supported(struct ath10k *ar) +{ + u32 param; + + ath10k_sdio_read_host_interest_value(ar, HI_ITEM(hi_option_flag2), ¶m); + + ath10k_dbg(ar, ATH10K_DBG_SDIO, "sdio hi_option_flag2 %x\n", param); + + return param & HI_OPTION_SDIO_CRASH_DUMP_ENHANCEMENT_FW; +} + +static void ath10k_sdio_dump_registers(struct ath10k *ar, + struct ath10k_fw_crash_data *crash_data, + bool fast_dump) +{ + u32 reg_dump_values[REG_DUMP_COUNT_QCA988X] = {}; + int i, ret; + u32 reg_dump_area; + + ret = ath10k_sdio_read_host_interest_value(ar, HI_ITEM(hi_failure_state), + ®_dump_area); + if (ret) { + ath10k_warn(ar, "failed to read firmware dump area: %d\n", ret); + return; + } + + if (fast_dump) + ret = ath10k_bmi_read_memory(ar, reg_dump_area, reg_dump_values, + sizeof(reg_dump_values)); + else + ret = ath10k_sdio_read_mem(ar, reg_dump_area, reg_dump_values, + sizeof(reg_dump_values)); + + if (ret) { + ath10k_warn(ar, "failed to read firmware dump value: %d\n", ret); + return; + } + + ath10k_err(ar, "firmware register dump:\n"); + for (i = 0; i < ARRAY_SIZE(reg_dump_values); i += 4) + ath10k_err(ar, "[%02d]: 0x%08X 0x%08X 0x%08X 0x%08X\n", + i, + reg_dump_values[i], + reg_dump_values[i + 1], + reg_dump_values[i + 2], + reg_dump_values[i + 3]); + + if (!crash_data) + return; + + for (i = 0; i < ARRAY_SIZE(reg_dump_values); i++) + crash_data->registers[i] = __cpu_to_le32(reg_dump_values[i]); +} + +static int ath10k_sdio_dump_memory_section(struct ath10k *ar, + const struct ath10k_mem_region *mem_region, + u8 *buf, size_t buf_len) +{ + const struct ath10k_mem_section *cur_section, *next_section; + unsigned int count, section_size, skip_size; + int ret, i, j; + + if (!mem_region || !buf) + return 0; + + cur_section = &mem_region->section_table.sections[0]; + + if (mem_region->start > cur_section->start) { + ath10k_warn(ar, "incorrect memdump region 0x%x with section start address 0x%x.\n", + mem_region->start, cur_section->start); + return 0; + } + + skip_size = cur_section->start - mem_region->start; + + /* fill the gap between the first register section and register + * start address + */ + for (i = 0; i < skip_size; i++) { + *buf = ATH10K_MAGIC_NOT_COPIED; + buf++; + } + + count = 0; + + for (i = 0; cur_section; i++) { + section_size = cur_section->end - cur_section->start; + + if (section_size <= 0) { + ath10k_warn(ar, "incorrect ramdump format with start address 0x%x and stop address 0x%x\n", + cur_section->start, + cur_section->end); + break; + } + + if ((i + 1) == mem_region->section_table.size) { + /* last section */ + next_section = NULL; + skip_size = 0; + } else { + next_section = cur_section + 1; + + if (cur_section->end > next_section->start) { + ath10k_warn(ar, "next ramdump section 0x%x is smaller than current end address 0x%x\n", + next_section->start, + cur_section->end); + break; + } + + skip_size = next_section->start - cur_section->end; + } + + if (buf_len < (skip_size + section_size)) { + ath10k_warn(ar, "ramdump buffer is too small: %zu\n", buf_len); + break; + } + + buf_len -= skip_size + section_size; + + /* read section to dest memory */ + ret = ath10k_sdio_read_mem(ar, cur_section->start, + buf, section_size); + if (ret) { + ath10k_warn(ar, "failed to read ramdump from section 0x%x: %d\n", + cur_section->start, ret); + break; + } + + buf += section_size; + count += section_size; + + /* fill in the gap between this section and the next */ + for (j = 0; j < skip_size; j++) { + *buf = ATH10K_MAGIC_NOT_COPIED; + buf++; + } + + count += skip_size; + + if (!next_section) + /* this was the last section */ + break; + + cur_section = next_section; + } + + return count; +} + +/* if an error happened returns < 0, otherwise the length */ +static int ath10k_sdio_dump_memory_generic(struct ath10k *ar, + const struct ath10k_mem_region *current_region, + u8 *buf, + bool fast_dump) +{ + int ret; + + if (current_region->section_table.size > 0) + /* Copy each section individually. */ + return ath10k_sdio_dump_memory_section(ar, + current_region, + buf, + current_region->len); + + /* No individiual memory sections defined so we can + * copy the entire memory region. + */ + if (fast_dump) + ret = ath10k_bmi_read_memory(ar, + current_region->start, + buf, + current_region->len); + else + ret = ath10k_sdio_read_mem(ar, + current_region->start, + buf, + current_region->len); + + if (ret) { + ath10k_warn(ar, "failed to copy ramdump region %s: %d\n", + current_region->name, ret); + return ret; + } + + return current_region->len; +} + +static void ath10k_sdio_dump_memory(struct ath10k *ar, + struct ath10k_fw_crash_data *crash_data, + bool fast_dump) +{ + const struct ath10k_hw_mem_layout *mem_layout; + const struct ath10k_mem_region *current_region; + struct ath10k_dump_ram_data_hdr *hdr; + u32 count; + size_t buf_len; + int ret, i; + u8 *buf; + + if (!crash_data) + return; + + mem_layout = ath10k_coredump_get_mem_layout(ar); + if (!mem_layout) + return; + + current_region = &mem_layout->region_table.regions[0]; + + buf = crash_data->ramdump_buf; + buf_len = crash_data->ramdump_buf_len; + + memset(buf, 0, buf_len); + + for (i = 0; i < mem_layout->region_table.size; i++) { + count = 0; + + if (current_region->len > buf_len) { + ath10k_warn(ar, "memory region %s size %d is larger that remaining ramdump buffer size %zu\n", + current_region->name, + current_region->len, + buf_len); + break; + } + + /* Reserve space for the header. */ + hdr = (void *)buf; + buf += sizeof(*hdr); + buf_len -= sizeof(*hdr); + + ret = ath10k_sdio_dump_memory_generic(ar, current_region, buf, + fast_dump); + if (ret >= 0) + count = ret; + + hdr->region_type = cpu_to_le32(current_region->type); + hdr->start = cpu_to_le32(current_region->start); + hdr->length = cpu_to_le32(count); + + if (count == 0) + /* Note: the header remains, just with zero length. */ + break; + + buf += count; + buf_len -= count; + + current_region++; + } +} + +void ath10k_sdio_fw_crashed_dump(struct ath10k *ar) +{ + struct ath10k_fw_crash_data *crash_data; + char guid[UUID_STRING_LEN + 1]; + bool fast_dump; + + fast_dump = ath10k_sdio_is_fast_dump_supported(ar); + + if (fast_dump) + ath10k_bmi_start(ar); + + ar->stats.fw_crash_counter++; + + ath10k_sdio_disable_intrs(ar); + + crash_data = ath10k_coredump_new(ar); + + if (crash_data) + scnprintf(guid, sizeof(guid), "%pUl", &crash_data->guid); + else + scnprintf(guid, sizeof(guid), "n/a"); + + ath10k_err(ar, "firmware crashed! (guid %s)\n", guid); + ath10k_print_driver_info(ar); + ath10k_sdio_dump_registers(ar, crash_data, fast_dump); + ath10k_sdio_dump_memory(ar, crash_data, fast_dump); + + ath10k_sdio_enable_intrs(ar); + + queue_work(ar->workqueue, &ar->restart_work); +} + static int ath10k_sdio_probe(struct sdio_func *func, const struct sdio_device_id *id) { diff --git a/drivers/net/wireless/ath/ath10k/snoc.c b/drivers/net/wireless/ath/ath10k/snoc.c index 354d49b1cd45..fd41f25456dc 100644 --- a/drivers/net/wireless/ath/ath10k/snoc.c +++ b/drivers/net/wireless/ath/ath10k/snoc.c @@ -3,6 +3,7 @@ * Copyright (c) 2018 The Linux Foundation. All rights reserved. */ +#include <linux/bits.h> #include <linux/clk.h> #include <linux/kernel.h> #include <linux/module.h> @@ -45,6 +46,7 @@ static const char * const ath10k_regulators[] = { "vdd-1.8-xo", "vdd-1.3-rfa", "vdd-3.3-ch0", + "vdd-3.3-ch1", }; static const char * const ath10k_clocks[] = { @@ -923,6 +925,7 @@ static int ath10k_snoc_hif_start(struct ath10k *ar) { struct ath10k_snoc *ar_snoc = ath10k_snoc_priv(ar); + bitmap_clear(ar_snoc->pending_ce_irqs, 0, CE_COUNT_MAX); napi_enable(&ar->napi); ath10k_snoc_irq_enable(ar); ath10k_snoc_rx_post(ar); @@ -1158,7 +1161,9 @@ static irqreturn_t ath10k_snoc_per_engine_handler(int irq, void *arg) return IRQ_HANDLED; } - ath10k_snoc_irq_disable(ar); + ath10k_ce_disable_interrupt(ar, ce_id); + set_bit(ce_id, ar_snoc->pending_ce_irqs); + napi_schedule(&ar->napi); return IRQ_HANDLED; @@ -1167,20 +1172,25 @@ static irqreturn_t ath10k_snoc_per_engine_handler(int irq, void *arg) static int ath10k_snoc_napi_poll(struct napi_struct *ctx, int budget) { struct ath10k *ar = container_of(ctx, struct ath10k, napi); + struct ath10k_snoc *ar_snoc = ath10k_snoc_priv(ar); int done = 0; + int ce_id; if (test_bit(ATH10K_FLAG_CRASH_FLUSH, &ar->dev_flags)) { napi_complete(ctx); return done; } - ath10k_ce_per_engine_service_any(ar); + for (ce_id = 0; ce_id < CE_COUNT; ce_id++) + if (test_and_clear_bit(ce_id, ar_snoc->pending_ce_irqs)) { + ath10k_ce_per_engine_service(ar, ce_id); + ath10k_ce_enable_interrupt(ar, ce_id); + } + done = ath10k_htt_txrx_compl_task(ar, budget); - if (done < budget) { + if (done < budget) napi_complete(ctx); - ath10k_snoc_irq_enable(ar); - } return done; } @@ -1772,9 +1782,18 @@ static int ath10k_snoc_remove(struct platform_device *pdev) return 0; } +static void ath10k_snoc_shutdown(struct platform_device *pdev) +{ + struct ath10k *ar = platform_get_drvdata(pdev); + + ath10k_dbg(ar, ATH10K_DBG_SNOC, "snoc shutdown\n"); + ath10k_snoc_remove(pdev); +} + static struct platform_driver ath10k_snoc_driver = { .probe = ath10k_snoc_probe, .remove = ath10k_snoc_remove, + .shutdown = ath10k_snoc_shutdown, .driver = { .name = "ath10k_snoc", .of_match_table = ath10k_snoc_dt_match, diff --git a/drivers/net/wireless/ath/ath10k/snoc.h b/drivers/net/wireless/ath/ath10k/snoc.h index a3dd06f6ac62..5095d1893681 100644 --- a/drivers/net/wireless/ath/ath10k/snoc.h +++ b/drivers/net/wireless/ath/ath10k/snoc.h @@ -78,6 +78,7 @@ struct ath10k_snoc { unsigned long flags; bool xo_cal_supported; u32 xo_cal_data; + DECLARE_BITMAP(pending_ce_irqs, CE_COUNT_MAX); }; static inline struct ath10k_snoc *ath10k_snoc_priv(struct ath10k *ar) diff --git a/drivers/net/wireless/ath/ath10k/targaddrs.h b/drivers/net/wireless/ath/ath10k/targaddrs.h index dff6c8ac9dba..ec556bb88d65 100644 --- a/drivers/net/wireless/ath/ath10k/targaddrs.h +++ b/drivers/net/wireless/ath/ath10k/targaddrs.h @@ -334,6 +334,17 @@ struct host_interest { #define HI_ACS_FLAGS_SDIO_REDUCE_TX_COMPL_FW_ACK (1 << 17) /* + * If both SDIO_CRASH_DUMP_ENHANCEMENT_HOST and SDIO_CRASH_DUMP_ENHANCEMENT_FW + * flags are set, then crashdump upload will be done using the BMI host/target + * communication channel. + */ +/* HOST to support using BMI dump FW memory when hit assert */ +#define HI_OPTION_SDIO_CRASH_DUMP_ENHANCEMENT_HOST 0x400 + +/* FW to support using BMI dump FW memory when hit assert */ +#define HI_OPTION_SDIO_CRASH_DUMP_ENHANCEMENT_FW 0x800 + +/* * CONSOLE FLAGS * * Bit Range Meaning diff --git a/drivers/net/wireless/ath/ath10k/txrx.c b/drivers/net/wireless/ath/ath10k/txrx.c index f46b9083bbf1..aefe1f7f906c 100644 --- a/drivers/net/wireless/ath/ath10k/txrx.c +++ b/drivers/net/wireless/ath/ath10k/txrx.c @@ -50,6 +50,7 @@ int ath10k_txrx_tx_unref(struct ath10k_htt *htt, struct ath10k_skb_cb *skb_cb; struct ath10k_txq *artxq; struct sk_buff *msdu; + u8 flags; ath10k_dbg(ar, ATH10K_DBG_HTT, "htt tx completion msdu_id %u status %d\n", @@ -78,6 +79,7 @@ int ath10k_txrx_tx_unref(struct ath10k_htt *htt, artxq->num_fw_queued--; } + flags = skb_cb->flags; ath10k_htt_tx_free_msdu_id(htt, tx_done->msdu_id); ath10k_htt_tx_dec_pending(htt); if (htt->num_pending_tx == 0) @@ -101,18 +103,21 @@ int ath10k_txrx_tx_unref(struct ath10k_htt *htt, trace_ath10k_txrx_tx_unref(ar, tx_done->msdu_id); - if (!(info->flags & IEEE80211_TX_CTL_NO_ACK)) + if (!(info->flags & IEEE80211_TX_CTL_NO_ACK) && + !(flags & ATH10K_SKB_F_NOACK_TID)) info->flags |= IEEE80211_TX_STAT_ACK; if (tx_done->status == HTT_TX_COMPL_STATE_NOACK) info->flags &= ~IEEE80211_TX_STAT_ACK; if ((tx_done->status == HTT_TX_COMPL_STATE_ACK) && - (info->flags & IEEE80211_TX_CTL_NO_ACK)) + ((info->flags & IEEE80211_TX_CTL_NO_ACK) || + (flags & ATH10K_SKB_F_NOACK_TID))) info->flags |= IEEE80211_TX_STAT_NOACK_TRANSMITTED; if (tx_done->status == HTT_TX_COMPL_STATE_DISCARD) { - if (info->flags & IEEE80211_TX_CTL_NO_ACK) + if ((info->flags & IEEE80211_TX_CTL_NO_ACK) || + (flags & ATH10K_SKB_F_NOACK_TID)) info->flags &= ~IEEE80211_TX_STAT_NOACK_TRANSMITTED; else info->flags &= ~IEEE80211_TX_STAT_ACK; diff --git a/drivers/net/wireless/ath/ath10k/wmi-ops.h b/drivers/net/wireless/ath/ath10k/wmi-ops.h index 0dd484f85082..aa57d807491c 100644 --- a/drivers/net/wireless/ath/ath10k/wmi-ops.h +++ b/drivers/net/wireless/ath/ath10k/wmi-ops.h @@ -224,6 +224,8 @@ struct wmi_ops { struct sk_buff *(*gen_bb_timing) (struct ath10k *ar, const struct wmi_bb_timing_cfg_arg *arg); + struct sk_buff *(*gen_per_peer_per_tid_cfg)(struct ath10k *ar, + const struct wmi_per_peer_per_tid_cfg_arg *arg); }; @@ -1656,4 +1658,21 @@ ath10k_wmi_pdev_bb_timing(struct ath10k *ar, return ath10k_wmi_cmd_send(ar, skb, ar->wmi.cmd->set_bb_timing_cmdid); } + +static inline int +ath10k_wmi_set_per_peer_per_tid_cfg(struct ath10k *ar, + const struct wmi_per_peer_per_tid_cfg_arg *arg) +{ + struct sk_buff *skb; + + if (!ar->wmi.ops->gen_per_peer_per_tid_cfg) + return -EOPNOTSUPP; + + skb = ar->wmi.ops->gen_per_peer_per_tid_cfg(ar, arg); + if (IS_ERR(skb)) + return PTR_ERR(skb); + + return ath10k_wmi_cmd_send(ar, skb, + ar->wmi.cmd->per_peer_per_tid_config_cmdid); +} #endif diff --git a/drivers/net/wireless/ath/ath10k/wmi-tlv.h b/drivers/net/wireless/ath/ath10k/wmi-tlv.h index e77b97ca5c7f..b39c9b78b32b 100644 --- a/drivers/net/wireless/ath/ath10k/wmi-tlv.h +++ b/drivers/net/wireless/ath/ath10k/wmi-tlv.h @@ -1614,6 +1614,8 @@ wmi_tlv_svc_map(const __le32 *in, unsigned long *out, size_t len) WMI_SERVICE_MESH_11S, len); SVCMAP(WMI_TLV_SERVICE_SYNC_DELETE_CMDS, WMI_SERVICE_SYNC_DELETE_CMDS, len); + SVCMAP(WMI_TLV_SERVICE_PEER_STATS_INFO, + WMI_SERVICE_PEER_STATS, len); } static inline void diff --git a/drivers/net/wireless/ath/ath10k/wmi.c b/drivers/net/wireless/ath/ath10k/wmi.c index b661d4ec5d52..1fa7107a5051 100644 --- a/drivers/net/wireless/ath/ath10k/wmi.c +++ b/drivers/net/wireless/ath/ath10k/wmi.c @@ -740,6 +740,7 @@ static struct wmi_cmd_map wmi_10_4_cmd_map = { .tdls_peer_update_cmdid = WMI_10_4_TDLS_PEER_UPDATE_CMDID, .tdls_set_offchan_mode_cmdid = WMI_10_4_TDLS_SET_OFFCHAN_MODE_CMDID, .radar_found_cmdid = WMI_10_4_RADAR_FOUND_CMDID, + .per_peer_per_tid_config_cmdid = WMI_10_4_PER_PEER_PER_TID_CONFIG_CMDID, }; static struct wmi_peer_param_map wmi_peer_param_map = { @@ -6551,7 +6552,7 @@ static struct sk_buff *ath10k_wmi_op_gen_init(struct ath10k *ar) struct wmi_init_cmd *cmd; struct sk_buff *buf; struct wmi_resource_config config = {}; - u32 len, val; + u32 val; config.num_vdevs = __cpu_to_le32(TARGET_NUM_VDEVS); config.num_peers = __cpu_to_le32(TARGET_NUM_PEERS); @@ -6603,10 +6604,8 @@ static struct sk_buff *ath10k_wmi_op_gen_init(struct ath10k *ar) config.num_msdu_desc = __cpu_to_le32(TARGET_NUM_MSDU_DESC); config.max_frag_entries = __cpu_to_le32(TARGET_MAX_FRAG_ENTRIES); - len = sizeof(*cmd) + - (sizeof(struct host_memory_chunk) * ar->wmi.num_mem_chunks); - - buf = ath10k_wmi_alloc_skb(ar, len); + buf = ath10k_wmi_alloc_skb(ar, struct_size(cmd, mem_chunks.items, + ar->wmi.num_mem_chunks)); if (!buf) return ERR_PTR(-ENOMEM); @@ -6624,7 +6623,7 @@ static struct sk_buff *ath10k_wmi_10_1_op_gen_init(struct ath10k *ar) struct wmi_init_cmd_10x *cmd; struct sk_buff *buf; struct wmi_resource_config_10x config = {}; - u32 len, val; + u32 val; config.num_vdevs = __cpu_to_le32(TARGET_10X_NUM_VDEVS); config.num_peers = __cpu_to_le32(TARGET_10X_NUM_PEERS); @@ -6668,10 +6667,8 @@ static struct sk_buff *ath10k_wmi_10_1_op_gen_init(struct ath10k *ar) config.num_msdu_desc = __cpu_to_le32(TARGET_10X_NUM_MSDU_DESC); config.max_frag_entries = __cpu_to_le32(TARGET_10X_MAX_FRAG_ENTRIES); - len = sizeof(*cmd) + - (sizeof(struct host_memory_chunk) * ar->wmi.num_mem_chunks); - - buf = ath10k_wmi_alloc_skb(ar, len); + buf = ath10k_wmi_alloc_skb(ar, struct_size(cmd, mem_chunks.items, + ar->wmi.num_mem_chunks)); if (!buf) return ERR_PTR(-ENOMEM); @@ -6689,7 +6686,7 @@ static struct sk_buff *ath10k_wmi_10_2_op_gen_init(struct ath10k *ar) struct wmi_init_cmd_10_2 *cmd; struct sk_buff *buf; struct wmi_resource_config_10x config = {}; - u32 len, val, features; + u32 val, features; config.num_vdevs = __cpu_to_le32(TARGET_10X_NUM_VDEVS); config.num_peer_keys = __cpu_to_le32(TARGET_10X_NUM_PEER_KEYS); @@ -6741,10 +6738,8 @@ static struct sk_buff *ath10k_wmi_10_2_op_gen_init(struct ath10k *ar) config.num_msdu_desc = __cpu_to_le32(TARGET_10X_NUM_MSDU_DESC); config.max_frag_entries = __cpu_to_le32(TARGET_10X_MAX_FRAG_ENTRIES); - len = sizeof(*cmd) + - (sizeof(struct host_memory_chunk) * ar->wmi.num_mem_chunks); - - buf = ath10k_wmi_alloc_skb(ar, len); + buf = ath10k_wmi_alloc_skb(ar, struct_size(cmd, mem_chunks.items, + ar->wmi.num_mem_chunks)); if (!buf) return ERR_PTR(-ENOMEM); @@ -6776,7 +6771,6 @@ static struct sk_buff *ath10k_wmi_10_4_op_gen_init(struct ath10k *ar) struct wmi_init_cmd_10_4 *cmd; struct sk_buff *buf; struct wmi_resource_config_10_4 config = {}; - u32 len; config.num_vdevs = __cpu_to_le32(ar->max_num_vdevs); config.num_peers = __cpu_to_le32(ar->max_num_peers); @@ -6838,10 +6832,8 @@ static struct sk_buff *ath10k_wmi_10_4_op_gen_init(struct ath10k *ar) config.iphdr_pad_config = __cpu_to_le32(TARGET_10_4_IPHDR_PAD_CONFIG); config.qwrap_config = __cpu_to_le32(TARGET_10_4_QWRAP_CONFIG); - len = sizeof(*cmd) + - (sizeof(struct host_memory_chunk) * ar->wmi.num_mem_chunks); - - buf = ath10k_wmi_alloc_skb(ar, len); + buf = ath10k_wmi_alloc_skb(ar, struct_size(cmd, mem_chunks.items, + ar->wmi.num_mem_chunks)); if (!buf) return ERR_PTR(-ENOMEM); @@ -7549,12 +7541,9 @@ ath10k_wmi_op_gen_scan_chan_list(struct ath10k *ar, struct sk_buff *skb; struct wmi_channel_arg *ch; struct wmi_channel *ci; - int len; int i; - len = sizeof(*cmd) + arg->n_channels * sizeof(struct wmi_channel); - - skb = ath10k_wmi_alloc_skb(ar, len); + skb = ath10k_wmi_alloc_skb(ar, struct_size(cmd, chan_info, arg->n_channels)); if (!skb) return ERR_PTR(-EINVAL); @@ -9005,6 +8994,39 @@ ath10k_wmi_10_4_gen_radar_found(struct ath10k *ar, } static struct sk_buff * +ath10k_wmi_10_4_gen_per_peer_per_tid_cfg(struct ath10k *ar, + const struct wmi_per_peer_per_tid_cfg_arg *arg) +{ + struct wmi_peer_per_tid_cfg_cmd *cmd; + struct sk_buff *skb; + + skb = ath10k_wmi_alloc_skb(ar, sizeof(*cmd)); + if (!skb) + return ERR_PTR(-ENOMEM); + + memset(skb->data, 0, sizeof(*cmd)); + + cmd = (struct wmi_peer_per_tid_cfg_cmd *)skb->data; + cmd->vdev_id = cpu_to_le32(arg->vdev_id); + ether_addr_copy(cmd->peer_macaddr.addr, arg->peer_macaddr.addr); + cmd->tid = cpu_to_le32(arg->tid); + cmd->ack_policy = cpu_to_le32(arg->ack_policy); + cmd->aggr_control = cpu_to_le32(arg->aggr_control); + cmd->rate_control = cpu_to_le32(arg->rate_ctrl); + cmd->retry_count = cpu_to_le32(arg->retry_count); + cmd->rcode_flags = cpu_to_le32(arg->rcode_flags); + cmd->ext_tid_cfg_bitmap = cpu_to_le32(arg->ext_tid_cfg_bitmap); + cmd->rtscts_ctrl = cpu_to_le32(arg->rtscts_ctrl); + + ath10k_dbg(ar, ATH10K_DBG_WMI, + "wmi noack tid %d vdev id %d ack_policy %d aggr %u rate_ctrl %u rcflag %u retry_count %d rtscts %d ext_tid_cfg_bitmap %d mac_addr %pM\n", + arg->tid, arg->vdev_id, arg->ack_policy, arg->aggr_control, + arg->rate_ctrl, arg->rcode_flags, arg->retry_count, + arg->rtscts_ctrl, arg->ext_tid_cfg_bitmap, arg->peer_macaddr.addr); + return skb; +} + +static struct sk_buff * ath10k_wmi_op_gen_echo(struct ath10k *ar, u32 value) { struct wmi_echo_cmd *cmd; @@ -9413,6 +9435,7 @@ static const struct wmi_ops wmi_10_4_ops = { .gen_pdev_get_tpc_table_cmdid = ath10k_wmi_10_4_op_gen_pdev_get_tpc_table_cmdid, .gen_radar_found = ath10k_wmi_10_4_gen_radar_found, + .gen_per_peer_per_tid_cfg = ath10k_wmi_10_4_gen_per_peer_per_tid_cfg, /* shared with 10.2 */ .pull_echo_ev = ath10k_wmi_op_pull_echo_ev, diff --git a/drivers/net/wireless/ath/ath10k/wmi.h b/drivers/net/wireless/ath/ath10k/wmi.h index 511144b36231..4898e19b0af6 100644 --- a/drivers/net/wireless/ath/ath10k/wmi.h +++ b/drivers/net/wireless/ath/ath10k/wmi.h @@ -203,6 +203,8 @@ enum wmi_service { WMI_SERVICE_SYNC_DELETE_CMDS, WMI_SERVICE_TX_PWR_PER_PEER, WMI_SERVICE_SUPPORT_EXTEND_ADDRESS, + WMI_SERVICE_PEER_TID_CONFIGS_SUPPORT, + WMI_SERVICE_EXT_PEER_TID_CONFIGS_SUPPORT, /* Remember to add the new value to wmi_service_name()! */ @@ -503,6 +505,8 @@ static inline char *wmi_service_name(enum wmi_service service_id) SVCSTR(WMI_SERVICE_SYNC_DELETE_CMDS); SVCSTR(WMI_SERVICE_TX_PWR_PER_PEER); SVCSTR(WMI_SERVICE_SUPPORT_EXTEND_ADDRESS); + SVCSTR(WMI_SERVICE_PEER_TID_CONFIGS_SUPPORT); + SVCSTR(WMI_SERVICE_EXT_PEER_TID_CONFIGS_SUPPORT); case WMI_SERVICE_MAX: return NULL; @@ -834,6 +838,10 @@ static inline void wmi_10_4_svc_map(const __le32 *in, unsigned long *out, WMI_SERVICE_TX_PWR_PER_PEER, len); SVCMAP(WMI_10_4_SERVICE_RESET_CHIP, WMI_SERVICE_RESET_CHIP, len); + SVCMAP(WMI_10_4_SERVICE_PEER_TID_CONFIGS_SUPPORT, + WMI_SERVICE_PEER_TID_CONFIGS_SUPPORT, len); + SVCMAP(WMI_10_4_SERVICE_EXT_PEER_TID_CONFIGS_SUPPORT, + WMI_SERVICE_PEER_TID_CONFIGS_SUPPORT, len); } #undef SVCMAP @@ -1036,6 +1044,7 @@ struct wmi_cmd_map { u32 tdls_set_offchan_mode_cmdid; u32 radar_found_cmdid; u32 set_bb_timing_cmdid; + u32 per_peer_per_tid_config_cmdid; }; /* @@ -1877,6 +1886,8 @@ enum wmi_10_4_cmd_id { WMI_10_4_PDEV_SET_BRIDGE_MACADDR_CMDID, WMI_10_4_ATF_GROUP_WMM_AC_CONFIG_REQUEST_CMDID, WMI_10_4_RADAR_FOUND_CMDID, + WMI_10_4_PEER_CFR_CAPTURE_CMDID, + WMI_10_4_PER_PEER_PER_TID_CONFIG_CMDID, WMI_10_4_PDEV_UTF_CMDID = WMI_10_4_END_CMDID - 1, }; @@ -7220,6 +7231,71 @@ struct wmi_tdls_peer_event { __le32 vdev_id; } __packed; +enum wmi_tid_aggr_control_conf { + WMI_TID_CONFIG_AGGR_CONTROL_IGNORE, + WMI_TID_CONFIG_AGGR_CONTROL_ENABLE, + WMI_TID_CONFIG_AGGR_CONTROL_DISABLE, +}; + +enum wmi_noack_tid_conf { + WMI_NOACK_TID_CONFIG_IGNORE_ACK_POLICY, + WMI_PEER_TID_CONFIG_ACK, + WMI_PEER_TID_CONFIG_NOACK, +}; + +enum wmi_tid_rate_ctrl_conf { + WMI_TID_CONFIG_RATE_CONTROL_IGNORE, + WMI_TID_CONFIG_RATE_CONTROL_AUTO, + WMI_TID_CONFIG_RATE_CONTROL_FIXED_RATE, + WMI_TID_CONFIG_RATE_CONTROL_DEFAULT_LOWEST_RATE, + WMI_PEER_TID_CONFIG_RATE_UPPER_CAP, +}; + +enum wmi_tid_rtscts_control_conf { + WMI_TID_CONFIG_RTSCTS_CONTROL_ENABLE, + WMI_TID_CONFIG_RTSCTS_CONTROL_DISABLE, +}; + +enum wmi_ext_tid_config_map { + WMI_EXT_TID_RTS_CTS_CONFIG = BIT(0), +}; + +struct wmi_per_peer_per_tid_cfg_arg { + u32 vdev_id; + struct wmi_mac_addr peer_macaddr; + u32 tid; + enum wmi_noack_tid_conf ack_policy; + enum wmi_tid_aggr_control_conf aggr_control; + u8 rate_ctrl; + u32 retry_count; + u32 rcode_flags; + u32 ext_tid_cfg_bitmap; + u32 rtscts_ctrl; +}; + +struct wmi_peer_per_tid_cfg_cmd { + __le32 vdev_id; + struct wmi_mac_addr peer_macaddr; + __le32 tid; + + /* see enum wmi_noack_tid_conf */ + __le32 ack_policy; + + /* see enum wmi_tid_aggr_control_conf */ + __le32 aggr_control; + + /* see enum wmi_tid_rate_ctrl_conf */ + __le32 rate_control; + __le32 rcode_flags; + __le32 retry_count; + + /* See enum wmi_ext_tid_config_map */ + __le32 ext_tid_cfg_bitmap; + + /* see enum wmi_tid_rtscts_control_conf */ + __le32 rtscts_ctrl; +} __packed; + enum wmi_txbf_conf { WMI_TXBF_CONF_UNSUPPORTED, WMI_TXBF_CONF_BEFORE_ASSOC, diff --git a/drivers/net/wireless/ath/ath10k/wow.c b/drivers/net/wireless/ath/ath10k/wow.c index 8c26adddd034..7d65c115669f 100644 --- a/drivers/net/wireless/ath/ath10k/wow.c +++ b/drivers/net/wireless/ath/ath10k/wow.c @@ -275,7 +275,7 @@ static int ath10k_vif_wow_set_wakeups(struct ath10k_vif *arvif, switch (arvif->vdev_type) { case WMI_VDEV_TYPE_IBSS: __set_bit(WOW_BEACON_EVENT, &wow_mask); - /* fall through */ + fallthrough; case WMI_VDEV_TYPE_AP: __set_bit(WOW_DEAUTH_RECVD_EVENT, &wow_mask); __set_bit(WOW_DISASSOC_RECVD_EVENT, &wow_mask); |