diff --git a/package/kernel/mac80211/ath.mk b/package/kernel/mac80211/ath.mk index bf2da0ae8..065afd398 100644 --- a/package/kernel/mac80211/ath.mk +++ b/package/kernel/mac80211/ath.mk @@ -12,6 +12,8 @@ PKG_CONFIG_DEPENDS += \ CONFIG_ATH9K_TX99 \ CONFIG_ATH10K_LEDS \ CONFIG_ATH10K_THERMAL \ + CONFIG_ATH11K_MEM_PROFILE_512MB \ + CONFIG_ATH11K_MEM_PROFILE_1GB \ CONFIG_ATH_USER_REGD ifdef CONFIG_PACKAGE_MAC80211_DEBUGFS @@ -54,6 +56,8 @@ config-$(CONFIG_ATH9K_TX99) += ATH9K_TX99 config-$(CONFIG_ATH9K_UBNTHSR) += ATH9K_UBNTHSR config-$(CONFIG_ATH10K_LEDS) += ATH10K_LEDS config-$(CONFIG_ATH10K_THERMAL) += ATH10K_THERMAL +config-$(CONFIG_ATH11K_MEM_PROFILE_512MB) += ATH11K_MEM_PROFILE_512MB +config-$(CONFIG_ATH11K_MEM_PROFILE_1GB) += ATH11K_MEM_PROFILE_1GB config-$(call config_package,ath9k-htc) += ATH9K_HTC config-$(call config_package,ath10k) += ATH10K ATH10K_PCI @@ -284,7 +288,6 @@ define KernelPackage/ath10k/config config ATH10K_THERMAL bool "Enable thermal sensors and throttling support" - default y depends on PACKAGE_kmod-ath10k || PACKAGE_kmod-ath10k-smallbuffers endef @@ -300,9 +303,9 @@ define KernelPackage/ath11k TITLE:=Qualcomm 802.11ax wireless chipset support (common code) URL:=https://wireless.wiki.kernel.org/en/users/drivers/ath11k DEPENDS+= +kmod-ath +@DRIVER_11N_SUPPORT +@DRIVER_11AC_SUPPORT +@DRIVER_11AX_SUPPORT \ - +kmod-crypto-michael-mic +ATH11K_THERMAL:kmod-hwmon-core +ATH11K_THERMAL:kmod-thermal + +kmod-qcom-qmi-helpers +kmod-crypto-michael-mic +ATH11K_THERMAL:kmod-hwmon-core \ + +ATH11K_THERMAL:kmod-thermal FILES:=$(PKG_BUILD_DIR)/drivers/net/wireless/ath/ath11k/ath11k.ko - AUTOLOAD:=$(call AutoProbe,ath11k) endef define KernelPackage/ath11k/description @@ -317,13 +320,29 @@ define KernelPackage/ath11k/config depends on PACKAGE_kmod-ath11k default y if TARGET_ipq807x + if PACKAGE_kmod-ath11k + + choice + prompt "ath11k memory profile" + default ATH11K_MEM_PROFILE_512MB + help + This allows selecting the ath11k memory size profile to be used. + + config ATH11K_MEM_PROFILE_512MB + bool "Use limits for the 512MB memory size" + + config ATH11K_MEM_PROFILE_1GB + bool "Use limits for the 1GB memory size" + + endchoice + endif endef define KernelPackage/ath11k-ahb $(call KernelPackage/mac80211/Default) TITLE:=Qualcomm 802.11ax AHB wireless chipset support URL:=https://wireless.wiki.kernel.org/en/users/drivers/ath11k - DEPENDS+= @TARGET_ipq807x +kmod-ath11k + DEPENDS+= @TARGET_ipq807x +kmod-ath11k +LINUX_5_15:kmod-qrtr-smd FILES:=$(PKG_BUILD_DIR)/drivers/net/wireless/ath/ath11k/ath11k_ahb.ko AUTOLOAD:=$(call AutoProbe,ath11k_ahb) endef @@ -337,7 +356,7 @@ define KernelPackage/ath11k-pci $(call KernelPackage/mac80211/Default) TITLE:=Qualcomm 802.11ax PCI wireless chipset support URL:=https://wireless.wiki.kernel.org/en/users/drivers/ath11k - DEPENDS+= @PCI_SUPPORT @TARGET_ipq807x +kmod-ath11k + DEPENDS+= @PCI_SUPPORT +kmod-qrtr-mhi +kmod-ath11k FILES:=$(PKG_BUILD_DIR)/drivers/net/wireless/ath/ath11k/ath11k_pci.ko AUTOLOAD:=$(call AutoProbe,ath11k_pci) endef @@ -375,7 +394,7 @@ endef define KernelPackage/ar5523 $(call KernelPackage/mac80211/Default) TITLE:=Driver for Atheros AR5523 USB sticks - DEPENDS:=@USB_SUPPORT +kmod-mac80211 +kmod-ath +kmod-usb-core +kmod-input-core + DEPENDS:=@USB_SUPPORT +kmod-mac80211 +kmod-ath +kmod-usb-core +kmod-input-core FILES:=$(PKG_BUILD_DIR)/drivers/net/wireless/ath/ar5523/ar5523.ko AUTOLOAD:=$(call AutoProbe,ar5523) endef diff --git a/package/kernel/mac80211/patches/ath11k/0002-ath11k-fix-4-addr-tx-failure-for-AP-and-STA-modes.patch b/package/kernel/mac80211/patches/ath11k/0002-ath11k-fix-4-addr-tx-failure-for-AP-and-STA-modes.patch new file mode 100644 index 000000000..a88ffa5ff --- /dev/null +++ b/package/kernel/mac80211/patches/ath11k/0002-ath11k-fix-4-addr-tx-failure-for-AP-and-STA-modes.patch @@ -0,0 +1,151 @@ +From 34c67dc366419e06129dad0f32f521842bdff9bc Mon Sep 17 00:00:00 2001 +From: Sathishkumar Muruganandam +Date: Wed, 21 Jul 2021 00:31:46 +0300 +Subject: [PATCH 002/120] ath11k: fix 4-addr tx failure for AP and STA modes + +Ath11k FW requires peer parameter WMI_PEER_USE_4ADDR to be set for +4-addr peers allowing 4-address frame transmission to those peers. + +Add ath11k driver callback for sta_set_4addr() to queue new workq +set_4addr_wk only once based on new boolean, use_4addr_set. + +sta_set_4addr() will be called during 4-addr STA association cases +applicable for both AP and STA modes. + +In ath11k_sta_set_4addr_wk(), + +AP mode: + WMI_PEER_USE_4ADDR will be set for the corresponding + associated 4-addr STA(s) + +STA mode: + WMI_PEER_USE_4ADDR will be set for the AP to which the + 4-addr STA got associated. + +Tested-on: IPQ8074 WLAN.HK.2.1.0.1-01238-QCAHKSWPL_SILICONZ-1 + +Signed-off-by: Sathishkumar Muruganandam +Signed-off-by: Jouni Malinen +Signed-off-by: Kalle Valo +Link: https://lore.kernel.org/r/20210720213147.90042-1-jouni@codeaurora.org +--- + drivers/net/wireless/ath/ath11k/core.h | 3 ++ + drivers/net/wireless/ath/ath11k/mac.c | 48 ++++++++++++++++++++++++-- + 2 files changed, 49 insertions(+), 2 deletions(-) + +--- a/drivers/net/wireless/ath/ath11k/core.h ++++ b/drivers/net/wireless/ath/ath11k/core.h +@@ -362,6 +362,7 @@ struct ath11k_sta { + enum hal_pn_type pn_type; + + struct work_struct update_wk; ++ struct work_struct set_4addr_wk; + struct rate_info txrate; + struct rate_info last_txrate; + u64 rx_duration; +@@ -374,6 +375,8 @@ struct ath11k_sta { + /* protected by conf_mutex */ + bool aggr_mode; + #endif ++ ++ bool use_4addr_set; + }; + + #define ATH11K_MIN_5G_FREQ 4150 +--- a/drivers/net/wireless/ath/ath11k/mac.c ++++ b/drivers/net/wireless/ath/ath11k/mac.c +@@ -3155,6 +3155,31 @@ static void ath11k_sta_rc_update_wk(stru + mutex_unlock(&ar->conf_mutex); + } + ++static void ath11k_sta_set_4addr_wk(struct work_struct *wk) ++{ ++ struct ath11k *ar; ++ struct ath11k_vif *arvif; ++ struct ath11k_sta *arsta; ++ struct ieee80211_sta *sta; ++ int ret = 0; ++ ++ arsta = container_of(wk, struct ath11k_sta, set_4addr_wk); ++ sta = container_of((void *)arsta, struct ieee80211_sta, drv_priv); ++ arvif = arsta->arvif; ++ ar = arvif->ar; ++ ++ ath11k_dbg(ar->ab, ATH11K_DBG_MAC, ++ "setting USE_4ADDR for peer %pM\n", sta->addr); ++ ++ ret = ath11k_wmi_set_peer_param(ar, sta->addr, ++ arvif->vdev_id, ++ WMI_PEER_USE_4ADDR, 1); ++ ++ if (ret) ++ ath11k_warn(ar->ab, "failed to set peer %pM 4addr capability: %d\n", ++ sta->addr, ret); ++} ++ + static int ath11k_mac_inc_num_stations(struct ath11k_vif *arvif, + struct ieee80211_sta *sta) + { +@@ -3234,11 +3259,13 @@ static int ath11k_mac_station_add(struct + } + + if (ieee80211_vif_is_mesh(vif)) { ++ ath11k_dbg(ab, ATH11K_DBG_MAC, ++ "setting USE_4ADDR for mesh STA %pM\n", sta->addr); + ret = ath11k_wmi_set_peer_param(ar, sta->addr, + arvif->vdev_id, + WMI_PEER_USE_4ADDR, 1); + if (ret) { +- ath11k_warn(ab, "failed to STA %pM 4addr capability: %d\n", ++ ath11k_warn(ab, "failed to set mesh STA %pM 4addr capability: %d\n", + sta->addr, ret); + goto free_tx_stats; + } +@@ -3291,8 +3318,10 @@ static int ath11k_mac_op_sta_state(struc + + /* 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->set_4addr_wk); ++ } + + mutex_lock(&ar->conf_mutex); + +@@ -3301,6 +3330,7 @@ static int ath11k_mac_op_sta_state(struc + memset(arsta, 0, sizeof(*arsta)); + arsta->arvif = arvif; + INIT_WORK(&arsta->update_wk, ath11k_sta_rc_update_wk); ++ INIT_WORK(&arsta->set_4addr_wk, ath11k_sta_set_4addr_wk); + + ret = ath11k_mac_station_add(ar, vif, sta); + if (ret) +@@ -3395,6 +3425,19 @@ out: + return ret; + } + ++static void ath11k_mac_op_sta_set_4addr(struct ieee80211_hw *hw, ++ struct ieee80211_vif *vif, ++ struct ieee80211_sta *sta, bool enabled) ++{ ++ struct ath11k *ar = hw->priv; ++ struct ath11k_sta *arsta = (struct ath11k_sta *)sta->drv_priv; ++ ++ if (enabled && !arsta->use_4addr_set) { ++ ieee80211_queue_work(ar->hw, &arsta->set_4addr_wk); ++ arsta->use_4addr_set = true; ++ } ++} ++ + static void ath11k_mac_op_sta_rc_update(struct ieee80211_hw *hw, + struct ieee80211_vif *vif, + struct ieee80211_sta *sta, +@@ -6180,6 +6223,7 @@ static const struct ieee80211_ops ath11k + .cancel_hw_scan = ath11k_mac_op_cancel_hw_scan, + .set_key = ath11k_mac_op_set_key, + .sta_state = ath11k_mac_op_sta_state, ++ .sta_set_4addr = ath11k_mac_op_sta_set_4addr, + .sta_set_txpwr = ath11k_mac_op_sta_set_txpwr, + .sta_rc_update = ath11k_mac_op_sta_rc_update, + .conf_tx = ath11k_mac_op_conf_tx, diff --git a/package/kernel/mac80211/patches/ath11k/0003-ath11k-fix-4addr-multicast-packet-tx.patch b/package/kernel/mac80211/patches/ath11k/0003-ath11k-fix-4addr-multicast-packet-tx.patch new file mode 100644 index 000000000..ca1399b5d --- /dev/null +++ b/package/kernel/mac80211/patches/ath11k/0003-ath11k-fix-4addr-multicast-packet-tx.patch @@ -0,0 +1,123 @@ +From e20cfa3b62aeb1b5fc5ffa86a007af97f9954767 Mon Sep 17 00:00:00 2001 +From: Karthikeyan Periyasamy +Date: Wed, 21 Jul 2021 00:31:47 +0300 +Subject: [PATCH 003/120] ath11k: fix 4addr multicast packet tx + +In 4addr, AP wired backbone to STA wired backbone ping fails due to ARP +request not getting answered. Here 4addr ARP multicast packet is sent in +3addr, so that 4addr STA not honouring the 3addr ARP multicast packet. +Fix this issue by sending out multicast packet in 4addr format, firmware +expects peer meta flag instead of vdev meta flag in Tx descriptor. + +Tested-on: IPQ8074 hw2.0 AHB WLAN.HK.2.4.0.1-01641-QCAHKSWPL_SILICONZ-1 + +Signed-off-by: Karthikeyan Periyasamy +Signed-off-by: Jouni Malinen +Signed-off-by: Kalle Valo +Link: https://lore.kernel.org/r/20210720213147.90042-2-jouni@codeaurora.org +--- + drivers/net/wireless/ath/ath11k/core.h | 1 + + drivers/net/wireless/ath/ath11k/dp_tx.c | 12 ++++++++++-- + drivers/net/wireless/ath/ath11k/dp_tx.h | 2 +- + drivers/net/wireless/ath/ath11k/mac.c | 6 +++++- + drivers/net/wireless/ath/ath11k/peer.c | 11 +++++++++++ + 5 files changed, 28 insertions(+), 4 deletions(-) + +--- a/drivers/net/wireless/ath/ath11k/core.h ++++ b/drivers/net/wireless/ath/ath11k/core.h +@@ -377,6 +377,7 @@ struct ath11k_sta { + #endif + + bool use_4addr_set; ++ u16 tcl_metadata; + }; + + #define ATH11K_MIN_5G_FREQ 4150 +--- a/drivers/net/wireless/ath/ath11k/dp_tx.c ++++ b/drivers/net/wireless/ath/ath11k/dp_tx.c +@@ -78,7 +78,7 @@ enum hal_encrypt_type ath11k_dp_tx_get_e + } + + int ath11k_dp_tx(struct ath11k *ar, struct ath11k_vif *arvif, +- struct sk_buff *skb) ++ struct ath11k_sta *arsta, struct sk_buff *skb) + { + struct ath11k_base *ab = ar->ab; + struct ath11k_dp *dp = &ab->dp; +@@ -145,7 +145,15 @@ tcl_ring_sel: + FIELD_PREP(DP_TX_DESC_ID_MSDU_ID, ret) | + FIELD_PREP(DP_TX_DESC_ID_POOL_ID, pool_id); + ti.encap_type = ath11k_dp_tx_get_encap_type(arvif, skb); +- ti.meta_data_flags = arvif->tcl_metadata; ++ ++ if (ieee80211_has_a4(hdr->frame_control) && ++ is_multicast_ether_addr(hdr->addr3) && arsta && ++ arsta->use_4addr_set) { ++ ti.meta_data_flags = arsta->tcl_metadata; ++ ti.flags0 |= FIELD_PREP(HAL_TCL_DATA_CMD_INFO1_TO_FW, 1); ++ } else { ++ ti.meta_data_flags = arvif->tcl_metadata; ++ } + + if (ti.encap_type == HAL_TCL_ENCAP_TYPE_RAW) { + if (skb_cb->flags & ATH11K_SKB_CIPHER_SET) { +--- a/drivers/net/wireless/ath/ath11k/dp_tx.h ++++ b/drivers/net/wireless/ath/ath11k/dp_tx.h +@@ -17,7 +17,7 @@ struct ath11k_dp_htt_wbm_tx_status { + + int ath11k_dp_tx_htt_h2t_ver_req_msg(struct ath11k_base *ab); + int ath11k_dp_tx(struct ath11k *ar, struct ath11k_vif *arvif, +- struct sk_buff *skb); ++ struct ath11k_sta *arsta, struct sk_buff *skb); + void ath11k_dp_tx_completion_handler(struct ath11k_base *ab, int ring_id); + int ath11k_dp_tx_send_reo_cmd(struct ath11k_base *ab, struct dp_rx_tid *rx_tid, + enum hal_reo_cmd_type type, +--- a/drivers/net/wireless/ath/ath11k/mac.c ++++ b/drivers/net/wireless/ath/ath11k/mac.c +@@ -4356,6 +4356,7 @@ static void ath11k_mac_op_tx(struct ieee + struct ath11k_vif *arvif = ath11k_vif_to_arvif(vif); + struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data; + struct ieee80211_key_conf *key = info->control.hw_key; ++ struct ath11k_sta *arsta = NULL; + u32 info_flags = info->flags; + bool is_prb_rsp; + int ret; +@@ -4381,7 +4382,10 @@ static void ath11k_mac_op_tx(struct ieee + return; + } + +- ret = ath11k_dp_tx(ar, arvif, skb); ++ if (control->sta) ++ arsta = (struct ath11k_sta *)control->sta->drv_priv; ++ ++ ret = ath11k_dp_tx(ar, arvif, arsta, skb); + if (ret) { + ath11k_warn(ar->ab, "failed to transmit frame %d\n", ret); + ieee80211_free_txskb(ar->hw, skb); +--- a/drivers/net/wireless/ath/ath11k/peer.c ++++ b/drivers/net/wireless/ath/ath11k/peer.c +@@ -251,6 +251,7 @@ int ath11k_peer_create(struct ath11k *ar + struct ieee80211_sta *sta, struct peer_create_params *param) + { + struct ath11k_peer *peer; ++ struct ath11k_sta *arsta; + int ret; + + lockdep_assert_held(&ar->conf_mutex); +@@ -319,6 +320,16 @@ int ath11k_peer_create(struct ath11k *ar + peer->sec_type = HAL_ENCRYPT_TYPE_OPEN; + peer->sec_type_grp = HAL_ENCRYPT_TYPE_OPEN; + ++ if (sta) { ++ arsta = (struct ath11k_sta *)sta->drv_priv; ++ arsta->tcl_metadata |= FIELD_PREP(HTT_TCL_META_DATA_TYPE, 0) | ++ FIELD_PREP(HTT_TCL_META_DATA_PEER_ID, ++ peer->peer_id); ++ ++ /* set HTT extension valid bit to 0 by default */ ++ arsta->tcl_metadata &= ~HTT_TCL_META_DATA_VALID_HTT; ++ } ++ + ar->num_peers++; + + spin_unlock_bh(&ar->ab->base_lock); diff --git a/package/kernel/mac80211/patches/ath11k/0004-ath11k-Rename-atf_config-to-flag1-in-target_resource.patch b/package/kernel/mac80211/patches/ath11k/0004-ath11k-Rename-atf_config-to-flag1-in-target_resource.patch new file mode 100644 index 000000000..429324183 --- /dev/null +++ b/package/kernel/mac80211/patches/ath11k/0004-ath11k-Rename-atf_config-to-flag1-in-target_resource.patch @@ -0,0 +1,42 @@ +From 7e9fb2418a4c092a363d23e97973c9624150e5b2 Mon Sep 17 00:00:00 2001 +From: Seevalamuthu Mariappan +Date: Wed, 21 Jul 2021 00:49:20 +0300 +Subject: [PATCH 004/120] ath11k: Rename atf_config to flag1 in + target_resource_config + +The flag's purpose is not only meant for ATF configs. Rename atf_config +to flag1, so it can be used for future purposes. + +Tested-on: IPQ8074 hw2.0 AHB WLAN.HK.2.1.0.1-01228-QCAHKSWPL_SILICONZ-1 + +Signed-off-by: Seevalamuthu Mariappan +Signed-off-by: Jouni Malinen +Signed-off-by: Kalle Valo +Link: https://lore.kernel.org/r/20210720214922.118078-1-jouni@codeaurora.org +--- + drivers/net/wireless/ath/ath11k/wmi.c | 2 +- + drivers/net/wireless/ath/ath11k/wmi.h | 2 +- + 2 files changed, 2 insertions(+), 2 deletions(-) + +--- a/drivers/net/wireless/ath/ath11k/wmi.c ++++ b/drivers/net/wireless/ath/ath11k/wmi.c +@@ -3496,7 +3496,7 @@ ath11k_wmi_copy_resource_config(struct w + wmi_cfg->bpf_instruction_size = tg_cfg->bpf_instruction_size; + wmi_cfg->max_bssid_rx_filters = tg_cfg->max_bssid_rx_filters; + wmi_cfg->use_pdev_id = tg_cfg->use_pdev_id; +- wmi_cfg->flag1 = tg_cfg->atf_config; ++ wmi_cfg->flag1 = tg_cfg->flag1; + wmi_cfg->peer_map_unmap_v2_support = tg_cfg->peer_map_unmap_v2_support; + wmi_cfg->sched_params = tg_cfg->sched_params; + wmi_cfg->twt_ap_pdev_count = tg_cfg->twt_ap_pdev_count; +--- a/drivers/net/wireless/ath/ath11k/wmi.h ++++ b/drivers/net/wireless/ath/ath11k/wmi.h +@@ -5015,7 +5015,7 @@ struct target_resource_config { + u32 vo_minfree; + u32 rx_batchmode; + u32 tt_support; +- u32 atf_config; ++ u32 flag1; + u32 iphdr_pad_config; + u32 qwrap_config:16, + alloc_frag_desc_for_data_pkt:16; diff --git a/package/kernel/mac80211/patches/ath11k/0005-ath11k-add-support-in-survey-dump-with-bss_chan_info.patch b/package/kernel/mac80211/patches/ath11k/0005-ath11k-add-support-in-survey-dump-with-bss_chan_info.patch new file mode 100644 index 000000000..17e80cc79 --- /dev/null +++ b/package/kernel/mac80211/patches/ath11k/0005-ath11k-add-support-in-survey-dump-with-bss_chan_info.patch @@ -0,0 +1,51 @@ +From 9b4dd38b46cf24d8cb3ab433661cdc23a35160d0 Mon Sep 17 00:00:00 2001 +From: Seevalamuthu Mariappan +Date: Wed, 21 Jul 2021 00:49:21 +0300 +Subject: [PATCH 005/120] ath11k: add support in survey dump with bss_chan_info + +Survey dump statistics is not displaying channel rx and tx time because +the service flag is not enabled. Enable the service flag "bss_chan_info" +in wmi_resource_config to fetch and print the stats for the specific +pdev. + +Tested-on: IPQ8074 hw2.0 AHB WLAN.HK.2.1.0.1-01228-QCAHKSWPL_SILICONZ-1 + +Signed-off-by: Ritesh Singh +Signed-off-by: Seevalamuthu Mariappan +Signed-off-by: Jouni Malinen +Signed-off-by: Kalle Valo +Link: https://lore.kernel.org/r/20210720214922.118078-2-jouni@codeaurora.org +--- + drivers/net/wireless/ath/ath11k/hw.c | 2 ++ + drivers/net/wireless/ath/ath11k/wmi.h | 2 ++ + 2 files changed, 4 insertions(+) + +--- a/drivers/net/wireless/ath/ath11k/hw.c ++++ b/drivers/net/wireless/ath/ath11k/hw.c +@@ -97,6 +97,7 @@ static void ath11k_init_wmi_config_qca63 + config->num_multicast_filter_entries = 0x20; + config->num_wow_filters = 0x16; + config->num_keep_alive_pattern = 0; ++ config->flag1 |= WMI_RSRC_CFG_FLAG1_BSS_CHANNEL_INFO_64; + } + + static void ath11k_hw_ipq8074_reo_setup(struct ath11k_base *ab) +@@ -197,6 +198,7 @@ static void ath11k_init_wmi_config_ipq80 + config->peer_map_unmap_v2_support = 1; + config->twt_ap_pdev_count = ab->num_radios; + config->twt_ap_sta_count = 1000; ++ config->flag1 |= WMI_RSRC_CFG_FLAG1_BSS_CHANNEL_INFO_64; + } + + static int ath11k_hw_mac_id_to_pdev_id_ipq8074(struct ath11k_hw_params *hw, +--- a/drivers/net/wireless/ath/ath11k/wmi.h ++++ b/drivers/net/wireless/ath/ath11k/wmi.h +@@ -2244,6 +2244,8 @@ struct wmi_init_cmd { + u32 num_host_mem_chunks; + } __packed; + ++#define WMI_RSRC_CFG_FLAG1_BSS_CHANNEL_INFO_64 BIT(5) ++ + struct wmi_resource_config { + u32 tlv_header; + u32 num_vdevs; diff --git a/package/kernel/mac80211/patches/ath11k/0007-ath11k-move-static-function-ath11k_mac_vdev_setup_sy.patch b/package/kernel/mac80211/patches/ath11k/0007-ath11k-move-static-function-ath11k_mac_vdev_setup_sy.patch new file mode 100644 index 000000000..8d319efcd --- /dev/null +++ b/package/kernel/mac80211/patches/ath11k/0007-ath11k-move-static-function-ath11k_mac_vdev_setup_sy.patch @@ -0,0 +1,65 @@ +From d37b4862312c980d1f6843d11a14ad4eda242c8d Mon Sep 17 00:00:00 2001 +From: Seevalamuthu Mariappan +Date: Tue, 21 Sep 2021 16:39:29 +0300 +Subject: [PATCH 007/120] ath11k: move static function + ath11k_mac_vdev_setup_sync to top + +This is to prepare for monitor mode clean up. +No functional changes are done. + +Co-developed-by: Miles Hu +Signed-off-by: Miles Hu +Co-developed-by: Vasanthakumar Thiagarajan +Signed-off-by: Vasanthakumar Thiagarajan +Signed-off-by: Seevalamuthu Mariappan +Signed-off-by: Jouni Malinen +Signed-off-by: Kalle Valo +Link: https://lore.kernel.org/r/20210721162053.46290-2-jouni@codeaurora.org +--- + drivers/net/wireless/ath/ath11k/mac.c | 28 +++++++++++++-------------- + 1 file changed, 14 insertions(+), 14 deletions(-) + +--- a/drivers/net/wireless/ath/ath11k/mac.c ++++ b/drivers/net/wireless/ath/ath11k/mac.c +@@ -731,6 +731,20 @@ static int ath11k_monitor_vdev_up(struct + return 0; + } + ++static inline int ath11k_mac_vdev_setup_sync(struct ath11k *ar) ++{ ++ lockdep_assert_held(&ar->conf_mutex); ++ ++ if (test_bit(ATH11K_FLAG_CRASH_FLUSH, &ar->ab->dev_flags)) ++ return -ESHUTDOWN; ++ ++ if (!wait_for_completion_timeout(&ar->vdev_setup_done, ++ ATH11K_VDEV_SETUP_TIMEOUT_HZ)) ++ return -ETIMEDOUT; ++ ++ return ar->last_wmi_vdev_start_status ? -EINVAL : 0; ++} ++ + static int ath11k_mac_op_config(struct ieee80211_hw *hw, u32 changed) + { + /* mac80211 requires this op to be present and that's why +@@ -5165,20 +5179,6 @@ static void ath11k_mac_op_remove_chanctx + mutex_unlock(&ar->conf_mutex); + } + +-static inline int ath11k_mac_vdev_setup_sync(struct ath11k *ar) +-{ +- lockdep_assert_held(&ar->conf_mutex); +- +- if (test_bit(ATH11K_FLAG_CRASH_FLUSH, &ar->ab->dev_flags)) +- return -ESHUTDOWN; +- +- if (!wait_for_completion_timeout(&ar->vdev_setup_done, +- ATH11K_VDEV_SETUP_TIMEOUT_HZ)) +- return -ETIMEDOUT; +- +- return ar->last_wmi_vdev_start_status ? -EINVAL : 0; +-} +- + static int + ath11k_mac_vdev_start_restart(struct ath11k_vif *arvif, + const struct cfg80211_chan_def *chandef, diff --git a/package/kernel/mac80211/patches/ath11k/0008-ath11k-add-separate-APIs-for-monitor-mode.patch b/package/kernel/mac80211/patches/ath11k/0008-ath11k-add-separate-APIs-for-monitor-mode.patch new file mode 100644 index 000000000..21aca94e8 --- /dev/null +++ b/package/kernel/mac80211/patches/ath11k/0008-ath11k-add-separate-APIs-for-monitor-mode.patch @@ -0,0 +1,442 @@ +From 64e06b78a92744d43d3993ba623d2686d8f937e7 Mon Sep 17 00:00:00 2001 +From: Seevalamuthu Mariappan +Date: Tue, 21 Sep 2021 16:39:29 +0300 +Subject: [PATCH 008/120] ath11k: add separate APIs for monitor mode + +Add separate APIs for monitor_vdev_create/monitor_vdev_delete +and monitor_vdev_start/monitor_vdev_stop. + +Tested-on: IPQ8074 hw2.0 AHB WLAN.HK.2.4.0.1-01725-QCAHKSWPL_SILICONZ-1 + +Co-developed-by: Miles Hu +Signed-off-by: Miles Hu +Co-developed-by: Vasanthakumar Thiagarajan +Signed-off-by: Vasanthakumar Thiagarajan +Signed-off-by: Seevalamuthu Mariappan +Signed-off-by: Jouni Malinen +Signed-off-by: Kalle Valo +Link: https://lore.kernel.org/r/20210721162053.46290-3-jouni@codeaurora.org +--- + drivers/net/wireless/ath/ath11k/core.h | 5 +- + drivers/net/wireless/ath/ath11k/mac.c | 371 ++++++++++++++++++++++++- + 2 files changed, 370 insertions(+), 6 deletions(-) + +--- a/drivers/net/wireless/ath/ath11k/core.h ++++ b/drivers/net/wireless/ath/ath11k/core.h +@@ -194,6 +194,9 @@ enum ath11k_dev_flags { + + enum ath11k_monitor_flags { + ATH11K_FLAG_MONITOR_ENABLED, ++ ATH11K_FLAG_MONITOR_CONF_ENABLED, ++ ATH11K_FLAG_MONITOR_STARTED, ++ ATH11K_FLAG_MONITOR_VDEV_CREATED, + }; + + struct ath11k_vif { +@@ -488,7 +491,6 @@ struct ath11k { + u32 chan_tx_pwr; + u32 num_stations; + u32 max_num_stations; +- bool monitor_present; + /* To synchronize concurrent synchronous mac80211 callback operations, + * concurrent debugfs configuration and concurrent FW statistics events. + */ +@@ -563,6 +565,7 @@ struct ath11k { + struct ath11k_per_peer_tx_stats cached_stats; + u32 last_ppdu_id; + u32 cached_ppdu_id; ++ int monitor_vdev_id; + #ifdef CPTCFG_ATH11K_DEBUGFS + struct ath11k_debug debug; + #endif +--- a/drivers/net/wireless/ath/ath11k/mac.c ++++ b/drivers/net/wireless/ath/ath11k/mac.c +@@ -745,14 +745,370 @@ static inline int ath11k_mac_vdev_setup_ + return ar->last_wmi_vdev_start_status ? -EINVAL : 0; + } + +-static int ath11k_mac_op_config(struct ieee80211_hw *hw, u32 changed) ++static void ++ath11k_mac_get_any_chandef_iter(struct ieee80211_hw *hw, ++ struct ieee80211_chanctx_conf *conf, ++ void *data) + { +- /* mac80211 requires this op to be present and that's why +- * there's an empty function, this can be extended when +- * required. +- */ ++ struct cfg80211_chan_def **def = data; ++ ++ *def = &conf->def; ++} ++ ++static int ath11k_mac_monitor_vdev_start(struct ath11k *ar, int vdev_id, ++ struct cfg80211_chan_def *chandef) ++{ ++ struct ieee80211_channel *channel; ++ struct wmi_vdev_start_req_arg arg = {}; ++ int ret; ++ ++ lockdep_assert_held(&ar->conf_mutex); ++ ++ channel = chandef->chan; ++ ++ arg.vdev_id = vdev_id; ++ arg.channel.freq = channel->center_freq; ++ arg.channel.band_center_freq1 = chandef->center_freq1; ++ arg.channel.band_center_freq2 = chandef->center_freq2; ++ ++ arg.channel.mode = ath11k_phymodes[chandef->chan->band][chandef->width]; ++ arg.channel.chan_radar = !!(channel->flags & IEEE80211_CHAN_RADAR); ++ ++ arg.channel.min_power = 0; ++ arg.channel.max_power = channel->max_power * 2; ++ arg.channel.max_reg_power = channel->max_reg_power * 2; ++ arg.channel.max_antenna_gain = channel->max_antenna_gain * 2; ++ ++ arg.pref_tx_streams = ar->num_tx_chains; ++ arg.pref_rx_streams = ar->num_rx_chains; ++ ++ arg.channel.passive = !!(chandef->chan->flags & IEEE80211_CHAN_NO_IR); ++ ++ reinit_completion(&ar->vdev_setup_done); ++ reinit_completion(&ar->vdev_delete_done); ++ ++ ret = ath11k_wmi_vdev_start(ar, &arg, false); ++ if (ret) { ++ ath11k_warn(ar->ab, "failed to request monitor vdev %i start: %d\n", ++ vdev_id, ret); ++ return ret; ++ } ++ ++ ret = ath11k_mac_vdev_setup_sync(ar); ++ if (ret) { ++ ath11k_warn(ar->ab, "failed to synchronize setup for monitor vdev %i start: %d\n", ++ vdev_id, ret); ++ return ret; ++ } ++ ++ ret = ath11k_wmi_vdev_up(ar, vdev_id, 0, ar->mac_addr); ++ if (ret) { ++ ath11k_warn(ar->ab, "failed to put up monitor vdev %i: %d\n", ++ vdev_id, ret); ++ goto vdev_stop; ++ } ++ ++ ath11k_dbg(ar->ab, ATH11K_DBG_MAC, "mac monitor vdev %i started\n", ++ vdev_id); + + return 0; ++ ++vdev_stop: ++ reinit_completion(&ar->vdev_setup_done); ++ ++ ret = ath11k_wmi_vdev_stop(ar, vdev_id); ++ if (ret) { ++ ath11k_warn(ar->ab, "failed to stop monitor vdev %i after start failure: %d\n", ++ vdev_id, ret); ++ return ret; ++ } ++ ++ ret = ath11k_mac_vdev_setup_sync(ar); ++ if (ret) { ++ ath11k_warn(ar->ab, "failed to synchronize setup for vdev %i stop: %d\n", ++ vdev_id, ret); ++ return ret; ++ } ++ ++ return -EIO; ++} ++ ++static int ath11k_mac_monitor_vdev_stop(struct ath11k *ar) ++{ ++ int ret; ++ ++ lockdep_assert_held(&ar->conf_mutex); ++ ++ reinit_completion(&ar->vdev_setup_done); ++ ++ ret = ath11k_wmi_vdev_stop(ar, ar->monitor_vdev_id); ++ if (ret) { ++ ath11k_warn(ar->ab, "failed to request monitor vdev %i stop: %d\n", ++ ar->monitor_vdev_id, ret); ++ return ret; ++ } ++ ++ ret = ath11k_mac_vdev_setup_sync(ar); ++ if (ret) { ++ ath11k_warn(ar->ab, "failed to synchronize monitor vdev %i stop: %d\n", ++ ar->monitor_vdev_id, ret); ++ return ret; ++ } ++ ++ ret = ath11k_wmi_vdev_down(ar, ar->monitor_vdev_id); ++ if (ret) { ++ ath11k_warn(ar->ab, "failed to put down monitor vdev %i: %d\n", ++ ar->monitor_vdev_id, ret); ++ return ret; ++ } ++ ++ ath11k_dbg(ar->ab, ATH11K_DBG_MAC, "mac monitor vdev %i stopped\n", ++ ar->monitor_vdev_id); ++ ++ return 0; ++} ++ ++static int ath11k_mac_monitor_vdev_create(struct ath11k *ar) ++{ ++ struct ath11k_pdev *pdev = ar->pdev; ++ struct vdev_create_params param = {}; ++ int bit, ret; ++ u8 tmp_addr[6] = {0}; ++ u16 nss; ++ ++ lockdep_assert_held(&ar->conf_mutex); ++ ++ if (test_bit(ATH11K_FLAG_MONITOR_VDEV_CREATED, &ar->monitor_flags)) ++ return 0; ++ ++ if (ar->ab->free_vdev_map == 0) { ++ ath11k_warn(ar->ab, "failed to find free vdev id for monitor vdev\n"); ++ return -ENOMEM; ++ } ++ ++ bit = __ffs64(ar->ab->free_vdev_map); ++ ++ ar->monitor_vdev_id = bit; ++ ++ param.if_id = ar->monitor_vdev_id; ++ param.type = WMI_VDEV_TYPE_MONITOR; ++ param.subtype = WMI_VDEV_SUBTYPE_NONE; ++ param.pdev_id = pdev->pdev_id; ++ ++ if (pdev->cap.supported_bands & WMI_HOST_WLAN_2G_CAP) { ++ param.chains[NL80211_BAND_2GHZ].tx = ar->num_tx_chains; ++ param.chains[NL80211_BAND_2GHZ].rx = ar->num_rx_chains; ++ } ++ if (pdev->cap.supported_bands & WMI_HOST_WLAN_5G_CAP) { ++ param.chains[NL80211_BAND_5GHZ].tx = ar->num_tx_chains; ++ param.chains[NL80211_BAND_5GHZ].rx = ar->num_rx_chains; ++ } ++ ++ ret = ath11k_wmi_vdev_create(ar, tmp_addr, ¶m); ++ if (ret) { ++ ath11k_warn(ar->ab, "failed to request monitor vdev %i creation: %d\n", ++ ar->monitor_vdev_id, ret); ++ ar->monitor_vdev_id = -1; ++ return ret; ++ } ++ ++ nss = get_num_chains(ar->cfg_tx_chainmask) ? : 1; ++ ret = ath11k_wmi_vdev_set_param_cmd(ar, ar->monitor_vdev_id, ++ WMI_VDEV_PARAM_NSS, nss); ++ if (ret) { ++ ath11k_warn(ar->ab, "failed to set vdev %d chainmask 0x%x, nss %d :%d\n", ++ ar->monitor_vdev_id, ar->cfg_tx_chainmask, nss, ret); ++ goto err_vdev_del; ++ } ++ ++ ret = ath11k_mac_txpower_recalc(ar); ++ if (ret) { ++ ath11k_warn(ar->ab, "failed to recalc txpower for monitor vdev %d: %d\n", ++ ar->monitor_vdev_id, ret); ++ goto err_vdev_del; ++ } ++ ++ ar->allocated_vdev_map |= 1LL << ar->monitor_vdev_id; ++ ar->ab->free_vdev_map &= ~(1LL << ar->monitor_vdev_id); ++ ar->num_created_vdevs++; ++ set_bit(ATH11K_FLAG_MONITOR_VDEV_CREATED, &ar->monitor_flags); ++ ++ ath11k_dbg(ar->ab, ATH11K_DBG_MAC, "mac monitor vdev %d created\n", ++ ar->monitor_vdev_id); ++ ++ return 0; ++ ++err_vdev_del: ++ ath11k_wmi_vdev_delete(ar, ar->monitor_vdev_id); ++ ar->monitor_vdev_id = -1; ++ return ret; ++} ++ ++static int ath11k_mac_monitor_vdev_delete(struct ath11k *ar) ++{ ++ int ret; ++ unsigned long time_left; ++ ++ lockdep_assert_held(&ar->conf_mutex); ++ ++ if (!test_bit(ATH11K_FLAG_MONITOR_VDEV_CREATED, &ar->monitor_flags)) ++ return 0; ++ ++ reinit_completion(&ar->vdev_delete_done); ++ ++ ret = ath11k_wmi_vdev_delete(ar, ar->monitor_vdev_id); ++ if (ret) { ++ ath11k_warn(ar->ab, "failed to request wmi monitor vdev %i removal: %d\n", ++ ar->monitor_vdev_id, ret); ++ return ret; ++ } ++ ++ time_left = wait_for_completion_timeout(&ar->vdev_delete_done, ++ ATH11K_VDEV_DELETE_TIMEOUT_HZ); ++ if (time_left == 0) { ++ ath11k_warn(ar->ab, "Timeout in receiving vdev delete response\n"); ++ } else { ++ ath11k_dbg(ar->ab, ATH11K_DBG_MAC, "mac monitor vdev %d deleted\n", ++ ar->monitor_vdev_id); ++ ++ ar->allocated_vdev_map &= ~(1LL << ar->monitor_vdev_id); ++ ar->ab->free_vdev_map |= 1LL << (ar->monitor_vdev_id); ++ ar->num_created_vdevs--; ++ ar->monitor_vdev_id = -1; ++ clear_bit(ATH11K_FLAG_MONITOR_VDEV_CREATED, &ar->monitor_flags); ++ } ++ ++ return ret; ++} ++ ++static int ath11k_mac_monitor_start(struct ath11k *ar) ++{ ++ struct cfg80211_chan_def *chandef = NULL; ++ int ret; ++ ++ lockdep_assert_held(&ar->conf_mutex); ++ ++ if (test_bit(ATH11K_FLAG_MONITOR_STARTED, &ar->monitor_flags)) ++ return 0; ++ ++ ieee80211_iter_chan_contexts_atomic(ar->hw, ++ ath11k_mac_get_any_chandef_iter, ++ &chandef); ++ if (!chandef) ++ return 0; ++ ++ ret = ath11k_mac_monitor_vdev_start(ar, ar->monitor_vdev_id, chandef); ++ if (ret) { ++ ath11k_warn(ar->ab, "failed to start monitor vdev: %d\n", ret); ++ ath11k_mac_monitor_vdev_delete(ar); ++ return ret; ++ } ++ ++ set_bit(ATH11K_FLAG_MONITOR_STARTED, &ar->monitor_flags); ++ ++ ar->num_started_vdevs++; ++ ret = ath11k_dp_tx_htt_monitor_mode_ring_config(ar, false); ++ if (ret) { ++ ath11k_warn(ar->ab, "failed to configure htt monitor mode ring during start: %d", ++ ret); ++ return ret; ++ } ++ ++ ath11k_dbg(ar->ab, ATH11K_DBG_MAC, "mac monitor started\n"); ++ ++ return 0; ++} ++ ++static int ath11k_mac_monitor_stop(struct ath11k *ar) ++{ ++ int ret; ++ ++ lockdep_assert_held(&ar->conf_mutex); ++ ++ if (!test_bit(ATH11K_FLAG_MONITOR_STARTED, &ar->monitor_flags)) ++ return 0; ++ ++ ret = ath11k_mac_monitor_vdev_stop(ar); ++ if (ret) { ++ ath11k_warn(ar->ab, "failed to stop monitor vdev: %d\n", ret); ++ return ret; ++ } ++ ++ clear_bit(ATH11K_FLAG_MONITOR_STARTED, &ar->monitor_flags); ++ ar->num_started_vdevs--; ++ ++ ret = ath11k_dp_tx_htt_monitor_mode_ring_config(ar, true); ++ if (ret) { ++ ath11k_warn(ar->ab, "failed to configure htt monitor mode ring during stop: %d", ++ ret); ++ return ret; ++ } ++ ++ ath11k_dbg(ar->ab, ATH11K_DBG_MAC, "mac monitor stopped ret %d\n", ret); ++ ++ return 0; ++} ++ ++static int ath11k_mac_op_config(struct ieee80211_hw *hw, u32 changed) ++{ ++ struct ath11k *ar = hw->priv; ++ struct ieee80211_conf *conf = &hw->conf; ++ int ret = 0; ++ ++ mutex_lock(&ar->conf_mutex); ++ ++ if (changed & IEEE80211_CONF_CHANGE_MONITOR) { ++ if (conf->flags & IEEE80211_CONF_MONITOR) { ++ set_bit(ATH11K_FLAG_MONITOR_CONF_ENABLED, &ar->monitor_flags); ++ ++ if (test_bit(ATH11K_FLAG_MONITOR_VDEV_CREATED, ++ &ar->monitor_flags)) ++ goto out; ++ ++ ret = ath11k_mac_monitor_vdev_create(ar); ++ if (ret) { ++ ath11k_warn(ar->ab, "failed to create monitor vdev: %d", ++ ret); ++ goto out; ++ } ++ ++ ret = ath11k_mac_monitor_start(ar); ++ if (ret) { ++ ath11k_warn(ar->ab, "failed to start monitor: %d", ++ ret); ++ goto err_mon_del; ++ } ++ } else { ++ clear_bit(ATH11K_FLAG_MONITOR_CONF_ENABLED, &ar->monitor_flags); ++ ++ if (!test_bit(ATH11K_FLAG_MONITOR_VDEV_CREATED, ++ &ar->monitor_flags)) ++ goto out; ++ ++ ret = ath11k_mac_monitor_stop(ar); ++ if (ret) { ++ ath11k_warn(ar->ab, "failed to stop monitor: %d", ++ ret); ++ goto out; ++ } ++ ++ ret = ath11k_mac_monitor_vdev_delete(ar); ++ if (ret) { ++ ath11k_warn(ar->ab, "failed to delete monitor vdev: %d", ++ ret); ++ goto out; ++ } ++ } ++ } ++ ++out: ++ mutex_unlock(&ar->conf_mutex); ++ return ret; ++ ++err_mon_del: ++ ath11k_mac_monitor_vdev_delete(ar); ++ mutex_unlock(&ar->conf_mutex); ++ return ret; + } + + static int ath11k_mac_setup_bcn_tmpl(struct ath11k_vif *arvif) +@@ -6771,7 +7127,12 @@ int ath11k_mac_allocate(struct ath11k_ba + + INIT_WORK(&ar->wmi_mgmt_tx_work, ath11k_mgmt_over_wmi_tx_work); + skb_queue_head_init(&ar->wmi_mgmt_tx_queue); ++ + clear_bit(ATH11K_FLAG_MONITOR_ENABLED, &ar->monitor_flags); ++ clear_bit(ATH11K_FLAG_MONITOR_STARTED, &ar->monitor_flags); ++ ++ ar->monitor_vdev_id = -1; ++ clear_bit(ATH11K_FLAG_MONITOR_VDEV_CREATED, &ar->monitor_flags); + } + + return 0; diff --git a/package/kernel/mac80211/patches/ath11k/0009-ath11k-monitor-mode-clean-up-to-use-separate-APIs.patch b/package/kernel/mac80211/patches/ath11k/0009-ath11k-monitor-mode-clean-up-to-use-separate-APIs.patch new file mode 100644 index 000000000..c7f15a506 --- /dev/null +++ b/package/kernel/mac80211/patches/ath11k/0009-ath11k-monitor-mode-clean-up-to-use-separate-APIs.patch @@ -0,0 +1,370 @@ +From 689a5e6fff75229ac7c2af7a9c51dc2d3ca1882b Mon Sep 17 00:00:00 2001 +From: Seevalamuthu Mariappan +Date: Tue, 21 Sep 2021 16:39:30 +0300 +Subject: [PATCH 009/120] ath11k: monitor mode clean up to use separate APIs + +If monitor interface is enabled in co-exist mode, only local traffic are +captured. It's caused by missing monitor vdev in co-exist mode. So, +monitor mode clean up is done with separate Monitor APIs. For this, +introduce flags monitor_started and monitor_vdev_created. + +Tested-on: IPQ8074 hw2.0 AHB WLAN.HK.2.4.0.1-01725-QCAHKSWPL_SILICONZ-1 + +Co-developed-by: Miles Hu +Signed-off-by: Miles Hu +Co-developed-by: Vasanthakumar Thiagarajan +Signed-off-by: Vasanthakumar Thiagarajan +Signed-off-by: Seevalamuthu Mariappan +Signed-off-by: Jouni Malinen +Signed-off-by: Kalle Valo +Link: https://lore.kernel.org/r/20210721162053.46290-4-jouni@codeaurora.org +--- + drivers/net/wireless/ath/ath11k/core.h | 1 - + drivers/net/wireless/ath/ath11k/dp_rx.c | 2 +- + drivers/net/wireless/ath/ath11k/dp_tx.c | 8 +- + drivers/net/wireless/ath/ath11k/mac.c | 150 ++++++++++++++++-------- + 4 files changed, 110 insertions(+), 51 deletions(-) + +--- a/drivers/net/wireless/ath/ath11k/core.h ++++ b/drivers/net/wireless/ath/ath11k/core.h +@@ -193,7 +193,6 @@ enum ath11k_dev_flags { + }; + + enum ath11k_monitor_flags { +- ATH11K_FLAG_MONITOR_ENABLED, + ATH11K_FLAG_MONITOR_CONF_ENABLED, + ATH11K_FLAG_MONITOR_STARTED, + ATH11K_FLAG_MONITOR_VDEV_CREATED, +--- a/drivers/net/wireless/ath/ath11k/dp_rx.c ++++ b/drivers/net/wireless/ath/ath11k/dp_rx.c +@@ -5032,7 +5032,7 @@ int ath11k_dp_rx_process_mon_rings(struc + struct ath11k *ar = ath11k_ab_to_ar(ab, mac_id); + int ret = 0; + +- if (test_bit(ATH11K_FLAG_MONITOR_ENABLED, &ar->monitor_flags)) ++ if (test_bit(ATH11K_FLAG_MONITOR_STARTED, &ar->monitor_flags)) + ret = ath11k_dp_mon_process_rx(ab, mac_id, napi, budget); + else + ret = ath11k_dp_rx_process_mon_status(ab, mac_id, napi, budget); +--- a/drivers/net/wireless/ath/ath11k/dp_tx.c ++++ b/drivers/net/wireless/ath/ath11k/dp_tx.c +@@ -1076,12 +1076,16 @@ int ath11k_dp_tx_htt_monitor_mode_ring_c + + for (i = 0; i < ab->hw_params.num_rxmda_per_pdev; i++) { + ring_id = dp->rx_mon_status_refill_ring[i].refill_buf_ring.ring_id; +- if (!reset) ++ if (!reset) { + tlv_filter.rx_filter = + HTT_RX_MON_FILTER_TLV_FLAGS_MON_STATUS_RING; +- else ++ } else { + tlv_filter = ath11k_mac_mon_status_filter_default; + ++ if (ath11k_debugfs_is_extd_rx_stats_enabled(ar)) ++ tlv_filter.rx_filter = ath11k_debugfs_rx_filter(ar); ++ } ++ + ret = ath11k_dp_tx_htt_rx_filter_setup(ab, ring_id, + dp->mac_id + i, + HAL_RXDMA_MONITOR_STATUS, +--- a/drivers/net/wireless/ath/ath11k/mac.c ++++ b/drivers/net/wireless/ath/ath11k/mac.c +@@ -715,22 +715,6 @@ void ath11k_mac_peer_cleanup_all(struct + ar->num_stations = 0; + } + +-static int ath11k_monitor_vdev_up(struct ath11k *ar, int vdev_id) +-{ +- int ret = 0; +- +- ret = ath11k_wmi_vdev_up(ar, vdev_id, 0, ar->mac_addr); +- if (ret) { +- ath11k_warn(ar->ab, "failed to put up monitor vdev %i: %d\n", +- vdev_id, ret); +- return ret; +- } +- +- ath11k_dbg(ar->ab, ATH11K_DBG_MAC, "mac monitor vdev %i started\n", +- vdev_id); +- return 0; +-} +- + static inline int ath11k_mac_vdev_setup_sync(struct ath11k *ar) + { + lockdep_assert_held(&ar->conf_mutex); +@@ -2326,7 +2310,7 @@ static int ath11k_mac_config_obss_pd(str + + /* Set and enable SRG/non-SRG OBSS PD Threshold */ + param_id = WMI_PDEV_PARAM_SET_CMD_OBSS_PD_THRESHOLD; +- if (test_bit(ATH11K_FLAG_MONITOR_ENABLED, &ar->monitor_flags)) { ++ if (test_bit(ATH11K_FLAG_MONITOR_STARTED, &ar->monitor_flags)) { + ret = ath11k_wmi_pdev_set_param(ar, param_id, 0, pdev_id); + if (ret) + ath11k_warn(ar->ab, +@@ -5100,8 +5084,8 @@ static int ath11k_mac_op_add_interface(s + } + + if (ar->num_created_vdevs > (TARGET_NUM_VDEVS - 1)) { +- ath11k_warn(ab, "failed to create vdev, reached max vdev limit %d\n", +- TARGET_NUM_VDEVS); ++ ath11k_warn(ab, "failed to create vdev %u, reached max vdev limit %d\n", ++ ar->num_created_vdevs, TARGET_NUM_VDEVS); + ret = -EBUSY; + goto err; + } +@@ -5141,6 +5125,7 @@ static int ath11k_mac_op_add_interface(s + break; + case NL80211_IFTYPE_MONITOR: + arvif->vdev_type = WMI_VDEV_TYPE_MONITOR; ++ ar->monitor_vdev_id = bit; + break; + default: + WARN_ON(1); +@@ -5242,6 +5227,9 @@ static int ath11k_mac_op_add_interface(s + goto err_peer_del; + } + break; ++ case WMI_VDEV_TYPE_MONITOR: ++ set_bit(ATH11K_FLAG_MONITOR_VDEV_CREATED, &ar->monitor_flags); ++ break; + default: + break; + } +@@ -5262,6 +5250,16 @@ static int ath11k_mac_op_add_interface(s + + ath11k_dp_vdev_tx_attach(ar, arvif); + ++ if (vif->type != NL80211_IFTYPE_MONITOR && ++ test_bit(ATH11K_FLAG_MONITOR_CONF_ENABLED, &ar->monitor_flags)) { ++ ret = ath11k_mac_monitor_vdev_create(ar); ++ if (ret) { ++ ath11k_warn(ar->ab, "failed to create monitor vdev during add interface: %d", ++ ret); ++ goto err_peer_del; ++ } ++ } ++ + mutex_unlock(&ar->conf_mutex); + + return 0; +@@ -5359,6 +5357,18 @@ static void ath11k_mac_op_remove_interfa + ath11k_dbg(ab, ATH11K_DBG_MAC, "vdev %pM deleted, vdev_id %d\n", + vif->addr, arvif->vdev_id); + ++ if (arvif->vdev_type == WMI_VDEV_TYPE_MONITOR) { ++ clear_bit(ATH11K_FLAG_MONITOR_VDEV_CREATED, &ar->monitor_flags); ++ ar->monitor_vdev_id = -1; ++ } else if (test_bit(ATH11K_FLAG_MONITOR_VDEV_CREATED, &ar->monitor_flags) && ++ !test_bit(ATH11K_FLAG_MONITOR_STARTED, &ar->monitor_flags)) { ++ ret = ath11k_mac_monitor_vdev_delete(ar); ++ if (ret) ++ /* continue even if there's an error */ ++ ath11k_warn(ar->ab, "failed to delete vdev monitor during remove interface: %d", ++ ret); ++ } ++ + err_vdev_del: + spin_lock_bh(&ar->data_lock); + list_del(&arvif->list); +@@ -5378,7 +5388,6 @@ err_vdev_del: + + /* Recalc txpower for remaining vdev */ + ath11k_mac_txpower_recalc(ar); +- clear_bit(ATH11K_FLAG_MONITOR_ENABLED, &ar->monitor_flags); + + /* TODO: recal traffic pause state based on the available vdevs */ + +@@ -5401,8 +5410,6 @@ static void ath11k_mac_op_configure_filt + u64 multicast) + { + struct ath11k *ar = hw->priv; +- bool reset_flag = false; +- int ret = 0; + + mutex_lock(&ar->conf_mutex); + +@@ -5410,23 +5417,6 @@ static void ath11k_mac_op_configure_filt + *total_flags &= SUPPORTED_FILTERS; + ar->filter_flags = *total_flags; + +- /* For monitor mode */ +- reset_flag = !(ar->filter_flags & FIF_BCN_PRBRESP_PROMISC); +- +- ret = ath11k_dp_tx_htt_monitor_mode_ring_config(ar, reset_flag); +- if (!ret) { +- if (!reset_flag) +- set_bit(ATH11K_FLAG_MONITOR_ENABLED, &ar->monitor_flags); +- else +- clear_bit(ATH11K_FLAG_MONITOR_ENABLED, &ar->monitor_flags); +- } else { +- ath11k_warn(ar->ab, +- "fail to set monitor filter: %d\n", ret); +- } +- ath11k_dbg(ar->ab, ATH11K_DBG_MAC, +- "changed_flags:0x%x, total_flags:0x%x, reset_flag:%d\n", +- changed_flags, *total_flags, reset_flag); +- + mutex_unlock(&ar->conf_mutex); + } + +@@ -5617,7 +5607,9 @@ ath11k_mac_vdev_start_restart(struct ath + return ret; + } + +- ar->num_started_vdevs++; ++ if (!restart) ++ ar->num_started_vdevs++; ++ + ath11k_dbg(ab, ATH11K_DBG_MAC, "vdev %pM started, vdev_id %d\n", + arvif->vif->addr, arvif->vdev_id); + +@@ -5745,12 +5737,16 @@ ath11k_mac_update_vif_chan(struct ath11k + struct ath11k_vif *arvif; + int ret; + int i; ++ bool monitor_vif = false; + + lockdep_assert_held(&ar->conf_mutex); + + for (i = 0; i < n_vifs; i++) { + arvif = (void *)vifs[i].vif->drv_priv; + ++ if (vifs[i].vif->type == NL80211_IFTYPE_MONITOR) ++ monitor_vif = true; ++ + ath11k_dbg(ab, ATH11K_DBG_MAC, + "mac chanctx switch vdev_id %i freq %u->%u width %d->%d\n", + arvif->vdev_id, +@@ -5771,6 +5767,8 @@ ath11k_mac_update_vif_chan(struct ath11k + arvif->vdev_id, ret); + continue; + } ++ ++ ar->num_started_vdevs--; + } + + /* All relevant vdevs are downed and associated channel resources +@@ -5808,6 +5806,24 @@ ath11k_mac_update_vif_chan(struct ath11k + continue; + } + } ++ ++ /* Restart the internal monitor vdev on new channel */ ++ if (!monitor_vif && ++ test_bit(ATH11K_FLAG_MONITOR_VDEV_CREATED, &ar->monitor_flags)) { ++ ret = ath11k_mac_monitor_stop(ar); ++ if (ret) { ++ ath11k_warn(ar->ab, "failed to stop monitor during vif channel update: %d", ++ ret); ++ return; ++ } ++ ++ ret = ath11k_mac_monitor_start(ar); ++ if (ret) { ++ ath11k_warn(ar->ab, "failed to start monitor during vif channel update: %d", ++ ret); ++ return; ++ } ++ } + } + + static void +@@ -5887,7 +5903,7 @@ static int ath11k_start_vdev_delay(struc + } + + if (arvif->vdev_type == WMI_VDEV_TYPE_MONITOR) { +- ret = ath11k_monitor_vdev_up(ar, arvif->vdev_id); ++ ret = ath11k_wmi_vdev_up(ar, arvif->vdev_id, 0, ar->mac_addr); + if (ret) { + ath11k_warn(ab, "failed put monitor up: %d\n", ret); + return ret; +@@ -5947,6 +5963,18 @@ ath11k_mac_op_assign_vif_chanctx(struct + } + } + ++ if (arvif->vdev_type == WMI_VDEV_TYPE_MONITOR) { ++ ret = ath11k_mac_monitor_start(ar); ++ if (ret) { ++ ath11k_warn(ar->ab, "failed to start monitor during vif channel context assignment: %d", ++ ret); ++ goto out; ++ } ++ ++ arvif->is_started = true; ++ goto out; ++ } ++ + ret = ath11k_mac_vdev_start(arvif, &ctx->def); + if (ret) { + ath11k_warn(ab, "failed to start vdev %i addr %pM on freq %d: %d\n", +@@ -5954,14 +5982,19 @@ ath11k_mac_op_assign_vif_chanctx(struct + ctx->def.chan->center_freq, ret); + goto out; + } +- if (arvif->vdev_type == WMI_VDEV_TYPE_MONITOR) { +- ret = ath11k_monitor_vdev_up(ar, arvif->vdev_id); +- if (ret) +- goto out; +- } + + arvif->is_started = true; + ++ if (arvif->vdev_type != WMI_VDEV_TYPE_MONITOR && ++ test_bit(ATH11K_FLAG_MONITOR_VDEV_CREATED, &ar->monitor_flags)) { ++ ret = ath11k_mac_monitor_start(ar); ++ if (ret) { ++ ath11k_warn(ar->ab, "failed to start monitor during vif channel context assignment: %d", ++ ret); ++ goto out; ++ } ++ } ++ + /* TODO: Setup ps and cts/rts protection */ + + ret = 0; +@@ -5995,6 +6028,20 @@ ath11k_mac_op_unassign_vif_chanctx(struc + ath11k_peer_find_by_addr(ab, ar->mac_addr)) + ath11k_peer_delete(ar, arvif->vdev_id, ar->mac_addr); + ++ if (arvif->vdev_type == WMI_VDEV_TYPE_MONITOR) { ++ ret = ath11k_mac_monitor_stop(ar); ++ if (ret) { ++ ath11k_warn(ar->ab, "failed to stop monitor during vif channel context unassignment: %d", ++ ret); ++ mutex_unlock(&ar->conf_mutex); ++ return; ++ } ++ ++ arvif->is_started = false; ++ mutex_unlock(&ar->conf_mutex); ++ return; ++ } ++ + ret = ath11k_mac_vdev_stop(arvif); + if (ret) + ath11k_warn(ab, "failed to stop vdev %i: %d\n", +@@ -6006,6 +6053,16 @@ ath11k_mac_op_unassign_vif_chanctx(struc + arvif->vdev_type == WMI_VDEV_TYPE_MONITOR) + ath11k_wmi_vdev_down(ar, arvif->vdev_id); + ++ if (arvif->vdev_type != WMI_VDEV_TYPE_MONITOR && ++ ar->num_started_vdevs == 1 && ++ test_bit(ATH11K_FLAG_MONITOR_VDEV_CREATED, &ar->monitor_flags)) { ++ ret = ath11k_mac_monitor_stop(ar); ++ if (ret) ++ /* continue even if there's an error */ ++ ath11k_warn(ar->ab, "failed to stop monitor during vif channel context unassignment: %d", ++ ret); ++ } ++ + mutex_unlock(&ar->conf_mutex); + } + +@@ -7128,7 +7185,6 @@ int ath11k_mac_allocate(struct ath11k_ba + INIT_WORK(&ar->wmi_mgmt_tx_work, ath11k_mgmt_over_wmi_tx_work); + skb_queue_head_init(&ar->wmi_mgmt_tx_queue); + +- clear_bit(ATH11K_FLAG_MONITOR_ENABLED, &ar->monitor_flags); + clear_bit(ATH11K_FLAG_MONITOR_STARTED, &ar->monitor_flags); + + ar->monitor_vdev_id = -1; diff --git a/package/kernel/mac80211/patches/ath11k/0010-ath11k-add-support-for-setting-fixed-HE-rate-gi-ltf.patch b/package/kernel/mac80211/patches/ath11k/0010-ath11k-add-support-for-setting-fixed-HE-rate-gi-ltf.patch new file mode 100644 index 000000000..d14ef5e2e --- /dev/null +++ b/package/kernel/mac80211/patches/ath11k/0010-ath11k-add-support-for-setting-fixed-HE-rate-gi-ltf.patch @@ -0,0 +1,1020 @@ +From 61fe43e7216df6e9a912d831aafc7142fa20f280 Mon Sep 17 00:00:00 2001 +From: Miles Hu +Date: Fri, 24 Sep 2021 16:52:45 +0300 +Subject: [PATCH 010/120] ath11k: add support for setting fixed HE rate/gi/ltf + +Support setting fixed HE rate/gi/ltf values that we are now able to send +to the kernel using nl80211. The added code is reusing parts of the +existing code path already used for HT/VHT. The new helpers are +symmetric to how we do it for HT/VHT. + +Tested-on: IPQ8074 hw2.0 AHB WLAN.HK.2.5.0.1-00235-QCAHKSWPL_SILICONZ-1 + +Signed-off-by: Miles Hu +Co-developed-by: Aloka Dixit +Signed-off-by: Aloka Dixit +Co-developed-by: Lavanya Suresh +Signed-off-by: Lavanya Suresh +Co-developed-by: Pradeep Chitrapu +Signed-off-by: Pradeep Chitrapu +Signed-off-by: Venkateswara Naralasetty +Signed-off-by: Jouni Malinen +Signed-off-by: Kalle Valo +Link: https://lore.kernel.org/r/20210721173615.75637-1-jouni@codeaurora.org +--- + drivers/net/wireless/ath/ath11k/mac.c | 595 ++++++++++++++++++++++++-- + drivers/net/wireless/ath/ath11k/wmi.c | 4 +- + drivers/net/wireless/ath/ath11k/wmi.h | 22 + + 3 files changed, 580 insertions(+), 41 deletions(-) + +--- a/drivers/net/wireless/ath/ath11k/mac.c ++++ b/drivers/net/wireless/ath/ath11k/mac.c +@@ -354,6 +354,18 @@ ath11k_mac_max_vht_nss(const u16 vht_mcs + return 1; + } + ++static u32 ++ath11k_mac_max_he_nss(const u16 he_mcs_mask[NL80211_HE_NSS_MAX]) ++{ ++ int nss; ++ ++ for (nss = NL80211_HE_NSS_MAX - 1; nss >= 0; nss--) ++ if (he_mcs_mask[nss]) ++ return nss + 1; ++ ++ return 1; ++} ++ + static u8 ath11k_parse_mpdudensity(u8 mpdudensity) + { + /* 802.11n D2.0 defined values for "Minimum MPDU Start Spacing": +@@ -1447,6 +1459,14 @@ static void ath11k_peer_assoc_h_ht(struc + arg->peer_rate_caps |= WMI_HOST_RC_CW40_FLAG; + } + ++ /* As firmware handles this two flags (IEEE80211_HT_CAP_SGI_20 ++ * and IEEE80211_HT_CAP_SGI_40) for enabling SGI, we reset ++ * both flags if guard interval is Default GI ++ */ ++ if (arvif->bitrate_mask.control[band].gi == NL80211_TXRATE_DEFAULT_GI) ++ arg->peer_ht_caps &= ~(IEEE80211_HT_CAP_SGI_20 | ++ IEEE80211_HT_CAP_SGI_40); ++ + if (arvif->bitrate_mask.control[band].gi != NL80211_TXRATE_FORCE_LGI) { + if (ht_cap->cap & (IEEE80211_HT_CAP_SGI_20 | + IEEE80211_HT_CAP_SGI_40)) +@@ -1570,10 +1590,11 @@ static void ath11k_peer_assoc_h_vht(stru + struct ath11k_vif *arvif = (void *)vif->drv_priv; + struct cfg80211_chan_def def; + enum nl80211_band band; +- const u16 *vht_mcs_mask; ++ u16 *vht_mcs_mask; + u8 ampdu_factor; + u8 max_nss, vht_mcs; +- int i; ++ int i, vht_nss, nss_idx; ++ bool user_rate_valid = true; + + if (WARN_ON(ath11k_mac_vif_chan(vif, &def))) + return; +@@ -1616,6 +1637,24 @@ static void ath11k_peer_assoc_h_vht(stru + if (sta->bandwidth == IEEE80211_STA_RX_BW_160) + arg->bw_160 = true; + ++ vht_nss = ath11k_mac_max_vht_nss(vht_mcs_mask); ++ ++ if (vht_nss > sta->rx_nss) { ++ user_rate_valid = false; ++ for (nss_idx = sta->rx_nss - 1; nss_idx >= 0; nss_idx--) { ++ if (vht_mcs_mask[nss_idx]) { ++ user_rate_valid = true; ++ break; ++ } ++ } ++ } ++ ++ if (!user_rate_valid) { ++ ath11k_dbg(ar->ab, ATH11K_DBG_MAC, "mac setting vht range mcs value to peer supported nss %d for peer %pM\n", ++ sta->rx_nss, sta->addr); ++ vht_mcs_mask[sta->rx_nss - 1] = vht_mcs_mask[vht_nss - 1]; ++ } ++ + /* Calculate peer NSS capability from VHT capabilities if STA + * supports VHT. + */ +@@ -1654,18 +1693,100 @@ static void ath11k_peer_assoc_h_vht(stru + /* TODO: rxnss_override */ + } + ++static int ath11k_mac_get_max_he_mcs_map(u16 mcs_map, int nss) ++{ ++ switch ((mcs_map >> (2 * nss)) & 0x3) { ++ case IEEE80211_HE_MCS_SUPPORT_0_7: return BIT(8) - 1; ++ case IEEE80211_HE_MCS_SUPPORT_0_9: return BIT(10) - 1; ++ case IEEE80211_HE_MCS_SUPPORT_0_11: return BIT(12) - 1; ++ } ++ return 0; ++} ++ ++static u16 ath11k_peer_assoc_h_he_limit(u16 tx_mcs_set, ++ const u16 he_mcs_limit[NL80211_HE_NSS_MAX]) ++{ ++ int idx_limit; ++ int nss; ++ u16 mcs_map; ++ u16 mcs; ++ ++ for (nss = 0; nss < NL80211_HE_NSS_MAX; nss++) { ++ mcs_map = ath11k_mac_get_max_he_mcs_map(tx_mcs_set, nss) & ++ he_mcs_limit[nss]; ++ ++ if (mcs_map) ++ idx_limit = fls(mcs_map) - 1; ++ else ++ idx_limit = -1; ++ ++ switch (idx_limit) { ++ case 0 ... 7: ++ mcs = IEEE80211_HE_MCS_SUPPORT_0_7; ++ break; ++ case 8: ++ case 9: ++ mcs = IEEE80211_HE_MCS_SUPPORT_0_9; ++ break; ++ case 10: ++ case 11: ++ mcs = IEEE80211_HE_MCS_SUPPORT_0_11; ++ break; ++ default: ++ WARN_ON(1); ++ fallthrough; ++ case -1: ++ mcs = IEEE80211_HE_MCS_NOT_SUPPORTED; ++ break; ++ } ++ ++ tx_mcs_set &= ~(0x3 << (nss * 2)); ++ tx_mcs_set |= mcs << (nss * 2); ++ } ++ ++ return tx_mcs_set; ++} ++ ++static bool ++ath11k_peer_assoc_h_he_masked(const u16 he_mcs_mask[NL80211_HE_NSS_MAX]) ++{ ++ int nss; ++ ++ for (nss = 0; nss < NL80211_HE_NSS_MAX; nss++) ++ if (he_mcs_mask[nss]) ++ return false; ++ ++ return true; ++} ++ + static void ath11k_peer_assoc_h_he(struct ath11k *ar, + struct ieee80211_vif *vif, + struct ieee80211_sta *sta, + struct peer_assoc_params *arg) + { ++ struct ath11k_vif *arvif = (void *)vif->drv_priv; ++ struct cfg80211_chan_def def; + const struct ieee80211_sta_he_cap *he_cap = &sta->he_cap; + u8 ampdu_factor; +- u16 v; ++ enum nl80211_band band; ++ u16 *he_mcs_mask; ++ u8 max_nss, he_mcs; ++ u16 he_tx_mcs = 0, v = 0; ++ int i, he_nss, nss_idx; ++ bool user_rate_valid = true; ++ ++ if (WARN_ON(ath11k_mac_vif_chan(vif, &def))) ++ return; + + if (!he_cap->has_he) + return; + ++ band = def.chan->band; ++ he_mcs_mask = arvif->bitrate_mask.control[band].he_mcs; ++ ++ if (ath11k_peer_assoc_h_he_masked(he_mcs_mask)) ++ return; ++ + arg->he_flag = true; + + memcpy_and_pad(&arg->peer_he_cap_macinfo, +@@ -1742,25 +1863,48 @@ static void ath11k_peer_assoc_h_he(struc + if (he_cap->he_cap_elem.mac_cap_info[0] & IEEE80211_HE_MAC_CAP0_TWT_REQ) + arg->twt_requester = true; + ++ he_nss = ath11k_mac_max_he_nss(he_mcs_mask); ++ ++ if (he_nss > sta->rx_nss) { ++ user_rate_valid = false; ++ for (nss_idx = sta->rx_nss - 1; nss_idx >= 0; nss_idx--) { ++ if (he_mcs_mask[nss_idx]) { ++ user_rate_valid = true; ++ break; ++ } ++ } ++ } ++ ++ if (!user_rate_valid) { ++ ath11k_dbg(ar->ab, ATH11K_DBG_MAC, "mac setting he range mcs value to peer supported nss %d for peer %pM\n", ++ sta->rx_nss, sta->addr); ++ he_mcs_mask[sta->rx_nss - 1] = he_mcs_mask[he_nss - 1]; ++ } ++ + switch (sta->bandwidth) { + case IEEE80211_STA_RX_BW_160: + if (he_cap->he_cap_elem.phy_cap_info[0] & + IEEE80211_HE_PHY_CAP0_CHANNEL_WIDTH_SET_80PLUS80_MHZ_IN_5G) { + v = le16_to_cpu(he_cap->he_mcs_nss_supp.rx_mcs_80p80); ++ v = ath11k_peer_assoc_h_he_limit(v, he_mcs_mask); + arg->peer_he_rx_mcs_set[WMI_HECAP_TXRX_MCS_NSS_IDX_80_80] = v; + + v = le16_to_cpu(he_cap->he_mcs_nss_supp.tx_mcs_80p80); + arg->peer_he_tx_mcs_set[WMI_HECAP_TXRX_MCS_NSS_IDX_80_80] = v; + + arg->peer_he_mcs_count++; ++ he_tx_mcs = v; + } + v = le16_to_cpu(he_cap->he_mcs_nss_supp.rx_mcs_160); + arg->peer_he_rx_mcs_set[WMI_HECAP_TXRX_MCS_NSS_IDX_160] = v; + + v = le16_to_cpu(he_cap->he_mcs_nss_supp.tx_mcs_160); ++ v = ath11k_peer_assoc_h_he_limit(v, he_mcs_mask); + arg->peer_he_tx_mcs_set[WMI_HECAP_TXRX_MCS_NSS_IDX_160] = v; + + arg->peer_he_mcs_count++; ++ if (!he_tx_mcs) ++ he_tx_mcs = v; + fallthrough; + + default: +@@ -1768,11 +1912,34 @@ static void ath11k_peer_assoc_h_he(struc + arg->peer_he_rx_mcs_set[WMI_HECAP_TXRX_MCS_NSS_IDX_80] = v; + + v = le16_to_cpu(he_cap->he_mcs_nss_supp.tx_mcs_80); ++ v = ath11k_peer_assoc_h_he_limit(v, he_mcs_mask); + arg->peer_he_tx_mcs_set[WMI_HECAP_TXRX_MCS_NSS_IDX_80] = v; + + arg->peer_he_mcs_count++; ++ if (!he_tx_mcs) ++ he_tx_mcs = v; + break; + } ++ ++ /* Calculate peer NSS capability from HE capabilities if STA ++ * supports HE. ++ */ ++ for (i = 0, max_nss = 0, he_mcs = 0; i < NL80211_HE_NSS_MAX; i++) { ++ he_mcs = he_tx_mcs >> (2 * i) & 3; ++ ++ /* In case of fixed rates, MCS Range in he_tx_mcs might have ++ * unsupported range, with he_mcs_mask set, so check either of them ++ * to find nss. ++ */ ++ if (he_mcs != IEEE80211_HE_MCS_NOT_SUPPORTED || ++ he_mcs_mask[i]) ++ max_nss = i + 1; ++ } ++ arg->peer_nss = min(sta->rx_nss, max_nss); ++ ++ ath11k_dbg(ar->ab, ATH11K_DBG_MAC, ++ "mac he peer %pM nss %d mcs cnt %d\n", ++ sta->addr, arg->peer_nss, arg->peer_he_mcs_count); + } + + static void ath11k_peer_assoc_h_smps(struct ieee80211_sta *sta, +@@ -1975,6 +2142,7 @@ static void ath11k_peer_assoc_h_phymode( + enum nl80211_band band; + const u8 *ht_mcs_mask; + const u16 *vht_mcs_mask; ++ const u16 *he_mcs_mask; + enum wmi_phy_mode phymode = MODE_UNKNOWN; + + if (WARN_ON(ath11k_mac_vif_chan(vif, &def))) +@@ -1983,10 +2151,12 @@ static void ath11k_peer_assoc_h_phymode( + band = def.chan->band; + ht_mcs_mask = arvif->bitrate_mask.control[band].ht_mcs; + vht_mcs_mask = arvif->bitrate_mask.control[band].vht_mcs; ++ he_mcs_mask = arvif->bitrate_mask.control[band].he_mcs; + + switch (band) { + case NL80211_BAND_2GHZ: +- if (sta->he_cap.has_he) { ++ if (sta->he_cap.has_he && ++ !ath11k_peer_assoc_h_he_masked(he_mcs_mask)) { + if (sta->bandwidth == IEEE80211_STA_RX_BW_80) + phymode = MODE_11AX_HE80_2G; + else if (sta->bandwidth == IEEE80211_STA_RX_BW_40) +@@ -2014,7 +2184,8 @@ static void ath11k_peer_assoc_h_phymode( + case NL80211_BAND_5GHZ: + case NL80211_BAND_6GHZ: + /* Check HE first */ +- if (sta->he_cap.has_he) { ++ if (sta->he_cap.has_he && ++ !ath11k_peer_assoc_h_he_masked(he_mcs_mask)) { + phymode = ath11k_mac_get_phymode_he(ar, sta); + } else if (sta->vht_cap.vht_supported && + !ath11k_peer_assoc_h_vht_masked(vht_mcs_mask)) { +@@ -3241,6 +3412,20 @@ ath11k_mac_bitrate_mask_num_vht_rates(st + } + + static int ++ath11k_mac_bitrate_mask_num_he_rates(struct ath11k *ar, ++ enum nl80211_band band, ++ const struct cfg80211_bitrate_mask *mask) ++{ ++ int num_rates = 0; ++ int i; ++ ++ for (i = 0; i < ARRAY_SIZE(mask->control[band].he_mcs); i++) ++ num_rates += hweight16(mask->control[band].he_mcs[i]); ++ ++ return num_rates; ++} ++ ++static int + ath11k_mac_set_peer_vht_fixed_rate(struct ath11k_vif *arvif, + struct ieee80211_sta *sta, + const struct cfg80211_bitrate_mask *mask, +@@ -3268,6 +3453,10 @@ ath11k_mac_set_peer_vht_fixed_rate(struc + return -EINVAL; + } + ++ /* Avoid updating invalid nss as fixed rate*/ ++ if (nss > sta->rx_nss) ++ return -EINVAL; ++ + ath11k_dbg(ar->ab, ATH11K_DBG_MAC, + "Setting Fixed VHT Rate for peer %pM. Device will not switch to any other selected rates", + sta->addr); +@@ -3286,6 +3475,57 @@ ath11k_mac_set_peer_vht_fixed_rate(struc + return ret; + } + ++static int ++ath11k_mac_set_peer_he_fixed_rate(struct ath11k_vif *arvif, ++ struct ieee80211_sta *sta, ++ const struct cfg80211_bitrate_mask *mask, ++ enum nl80211_band band) ++{ ++ struct ath11k *ar = arvif->ar; ++ u8 he_rate, nss; ++ u32 rate_code; ++ int ret, i; ++ ++ lockdep_assert_held(&ar->conf_mutex); ++ ++ nss = 0; ++ ++ for (i = 0; i < ARRAY_SIZE(mask->control[band].he_mcs); i++) { ++ if (hweight16(mask->control[band].he_mcs[i]) == 1) { ++ nss = i + 1; ++ he_rate = ffs(mask->control[band].he_mcs[i]) - 1; ++ } ++ } ++ ++ if (!nss) { ++ ath11k_warn(ar->ab, "No single he fixed rate found to set for %pM", ++ sta->addr); ++ return -EINVAL; ++ } ++ ++ /* Avoid updating invalid nss as fixed rate */ ++ if (nss > sta->rx_nss) ++ return -EINVAL; ++ ++ ath11k_dbg(ar->ab, ATH11K_DBG_MAC, ++ "mac setting fixed he rate for peer %pM, device will not switch to any other selected rates", ++ sta->addr); ++ ++ rate_code = ATH11K_HW_RATE_CODE(he_rate, nss - 1, ++ WMI_RATE_PREAMBLE_HE); ++ ++ ret = ath11k_wmi_set_peer_param(ar, sta->addr, ++ arvif->vdev_id, ++ WMI_PEER_PARAM_FIXED_RATE, ++ rate_code); ++ if (ret) ++ ath11k_warn(ar->ab, ++ "failed to update sta %pM fixed rate %d: %d\n", ++ sta->addr, rate_code, ret); ++ ++ return ret; ++} ++ + static int ath11k_station_assoc(struct ath11k *ar, + struct ieee80211_vif *vif, + struct ieee80211_sta *sta, +@@ -3297,7 +3537,7 @@ static int ath11k_station_assoc(struct a + struct cfg80211_chan_def def; + enum nl80211_band band; + struct cfg80211_bitrate_mask *mask; +- u8 num_vht_rates; ++ u8 num_vht_rates, num_he_rates; + + lockdep_assert_held(&ar->conf_mutex); + +@@ -3323,9 +3563,10 @@ static int ath11k_station_assoc(struct a + } + + num_vht_rates = ath11k_mac_bitrate_mask_num_vht_rates(ar, band, mask); ++ num_he_rates = ath11k_mac_bitrate_mask_num_he_rates(ar, band, mask); + +- /* If single VHT rate is configured (by set_bitrate_mask()), +- * peer_assoc will disable VHT. This is now enabled by a peer specific ++ /* If single VHT/HE rate is configured (by set_bitrate_mask()), ++ * peer_assoc will disable VHT/HE. This is now enabled by a peer specific + * fixed param. + * Note that all other rates and NSS will be disabled for this peer. + */ +@@ -3334,6 +3575,11 @@ static int ath11k_station_assoc(struct a + band); + if (ret) + return ret; ++ } else if (sta->he_cap.has_he && num_he_rates == 1) { ++ ret = ath11k_mac_set_peer_he_fixed_rate(arvif, sta, mask, ++ band); ++ if (ret) ++ return ret; + } + + /* Re-assoc is run only to update supported rates for given station. It +@@ -3404,8 +3650,9 @@ static void ath11k_sta_rc_update_wk(stru + enum nl80211_band band; + const u8 *ht_mcs_mask; + const u16 *vht_mcs_mask; ++ const u16 *he_mcs_mask; + u32 changed, bw, nss, smps; +- int err, num_vht_rates; ++ int err, num_vht_rates, num_he_rates; + const struct cfg80211_bitrate_mask *mask; + struct peer_assoc_params peer_arg; + +@@ -3420,6 +3667,7 @@ static void ath11k_sta_rc_update_wk(stru + band = def.chan->band; + ht_mcs_mask = arvif->bitrate_mask.control[band].ht_mcs; + vht_mcs_mask = arvif->bitrate_mask.control[band].vht_mcs; ++ he_mcs_mask = arvif->bitrate_mask.control[band].he_mcs; + + spin_lock_bh(&ar->data_lock); + +@@ -3435,8 +3683,9 @@ static void ath11k_sta_rc_update_wk(stru + mutex_lock(&ar->conf_mutex); + + nss = max_t(u32, 1, nss); +- nss = min(nss, max(ath11k_mac_max_ht_nss(ht_mcs_mask), +- ath11k_mac_max_vht_nss(vht_mcs_mask))); ++ nss = min(nss, max(max(ath11k_mac_max_ht_nss(ht_mcs_mask), ++ ath11k_mac_max_vht_nss(vht_mcs_mask)), ++ ath11k_mac_max_he_nss(he_mcs_mask))); + + if (changed & IEEE80211_RC_BW_CHANGED) { + err = ath11k_wmi_set_peer_param(ar, sta->addr, arvif->vdev_id, +@@ -3472,6 +3721,8 @@ static void ath11k_sta_rc_update_wk(stru + mask = &arvif->bitrate_mask; + num_vht_rates = ath11k_mac_bitrate_mask_num_vht_rates(ar, band, + mask); ++ num_he_rates = ath11k_mac_bitrate_mask_num_he_rates(ar, band, ++ mask); + + /* Peer_assoc_prepare will reject vht rates in + * bitrate_mask if its not available in range format and +@@ -3487,11 +3738,25 @@ static void ath11k_sta_rc_update_wk(stru + if (sta->vht_cap.vht_supported && num_vht_rates == 1) { + ath11k_mac_set_peer_vht_fixed_rate(arvif, sta, mask, + band); ++ } else if (sta->he_cap.has_he && num_he_rates == 1) { ++ ath11k_mac_set_peer_he_fixed_rate(arvif, sta, mask, ++ band); + } else { +- /* If the peer is non-VHT or no fixed VHT rate ++ /* If the peer is non-VHT/HE or no fixed VHT/HE rate + * is provided in the new bitrate mask we set the +- * other rates using peer_assoc command. ++ * other rates using peer_assoc command. Also clear ++ * the peer fixed rate settings as it has higher proprity ++ * than peer assoc + */ ++ err = ath11k_wmi_set_peer_param(ar, sta->addr, ++ arvif->vdev_id, ++ WMI_PEER_PARAM_FIXED_RATE, ++ WMI_FIXED_RATE_NONE); ++ if (err) ++ ath11k_warn(ar->ab, ++ "failed to disable peer fixed rate for sta %pM: %d\n", ++ sta->addr, err); ++ + ath11k_peer_assoc_prepare(ar, arvif->vif, sta, + &peer_arg, true); + +@@ -5101,10 +5366,13 @@ static int ath11k_mac_op_add_interface(s + + for (i = 0; i < ARRAY_SIZE(arvif->bitrate_mask.control); i++) { + arvif->bitrate_mask.control[i].legacy = 0xffffffff; ++ arvif->bitrate_mask.control[i].gi = NL80211_TXRATE_FORCE_SGI; + memset(arvif->bitrate_mask.control[i].ht_mcs, 0xff, + sizeof(arvif->bitrate_mask.control[i].ht_mcs)); + memset(arvif->bitrate_mask.control[i].vht_mcs, 0xff, + sizeof(arvif->bitrate_mask.control[i].vht_mcs)); ++ memset(arvif->bitrate_mask.control[i].he_mcs, 0xff, ++ sizeof(arvif->bitrate_mask.control[i].he_mcs)); + } + + bit = __ffs64(ab->free_vdev_map); +@@ -6180,9 +6448,26 @@ ath11k_mac_has_single_legacy_rate(struct + if (ath11k_mac_bitrate_mask_num_vht_rates(ar, band, mask)) + return false; + ++ if (ath11k_mac_bitrate_mask_num_he_rates(ar, band, mask)) ++ return false; ++ + return num_rates == 1; + } + ++static __le16 ++ath11k_mac_get_tx_mcs_map(const struct ieee80211_sta_he_cap *he_cap) ++{ ++ if (he_cap->he_cap_elem.phy_cap_info[0] & ++ IEEE80211_HE_PHY_CAP0_CHANNEL_WIDTH_SET_80PLUS80_MHZ_IN_5G) ++ return he_cap->he_mcs_nss_supp.tx_mcs_80p80; ++ ++ if (he_cap->he_cap_elem.phy_cap_info[0] & ++ IEEE80211_HE_PHY_CAP0_CHANNEL_WIDTH_SET_160MHZ_IN_5G) ++ return he_cap->he_mcs_nss_supp.tx_mcs_160; ++ ++ return he_cap->he_mcs_nss_supp.tx_mcs_80; ++} ++ + static bool + ath11k_mac_bitrate_mask_get_single_nss(struct ath11k *ar, + enum nl80211_band band, +@@ -6191,8 +6476,10 @@ ath11k_mac_bitrate_mask_get_single_nss(s + { + struct ieee80211_supported_band *sband = &ar->mac.sbands[band]; + u16 vht_mcs_map = le16_to_cpu(sband->vht_cap.vht_mcs.tx_mcs_map); ++ u16 he_mcs_map = 0; + u8 ht_nss_mask = 0; + u8 vht_nss_mask = 0; ++ u8 he_nss_mask = 0; + int i; + + /* No need to consider legacy here. Basic rates are always present +@@ -6219,7 +6506,20 @@ ath11k_mac_bitrate_mask_get_single_nss(s + return false; + } + +- if (ht_nss_mask != vht_nss_mask) ++ he_mcs_map = le16_to_cpu(ath11k_mac_get_tx_mcs_map(&sband->iftype_data->he_cap)); ++ ++ for (i = 0; i < ARRAY_SIZE(mask->control[band].he_mcs); i++) { ++ if (mask->control[band].he_mcs[i] == 0) ++ continue; ++ ++ if (mask->control[band].he_mcs[i] == ++ ath11k_mac_get_max_he_mcs_map(he_mcs_map, i)) ++ he_nss_mask |= BIT(i); ++ else ++ return false; ++ } ++ ++ if (ht_nss_mask != vht_nss_mask || ht_nss_mask != he_nss_mask) + return false; + + if (ht_nss_mask == 0) +@@ -6266,42 +6566,125 @@ ath11k_mac_get_single_legacy_rate(struct + return 0; + } + +-static int ath11k_mac_set_fixed_rate_params(struct ath11k_vif *arvif, +- u32 rate, u8 nss, u8 sgi, u8 ldpc) ++static int ++ath11k_mac_set_fixed_rate_gi_ltf(struct ath11k_vif *arvif, u8 he_gi, u8 he_ltf) + { + struct ath11k *ar = arvif->ar; +- u32 vdev_param; + int ret; + +- lockdep_assert_held(&ar->conf_mutex); ++ /* 0.8 = 0, 1.6 = 2 and 3.2 = 3. */ ++ if (he_gi && he_gi != 0xFF) ++ he_gi += 1; + +- ath11k_dbg(ar->ab, ATH11K_DBG_MAC, "mac set fixed rate params vdev %i rate 0x%02x nss %u sgi %u\n", +- arvif->vdev_id, rate, nss, sgi); ++ ret = ath11k_wmi_vdev_set_param_cmd(ar, arvif->vdev_id, ++ WMI_VDEV_PARAM_SGI, he_gi); ++ if (ret) { ++ ath11k_warn(ar->ab, "failed to set he gi %d: %d\n", ++ he_gi, ret); ++ return ret; ++ } ++ /* start from 1 */ ++ if (he_ltf != 0xFF) ++ he_ltf += 1; + +- vdev_param = WMI_VDEV_PARAM_FIXED_RATE; + ret = ath11k_wmi_vdev_set_param_cmd(ar, arvif->vdev_id, +- vdev_param, rate); ++ WMI_VDEV_PARAM_HE_LTF, he_ltf); + if (ret) { +- ath11k_warn(ar->ab, "failed to set fixed rate param 0x%02x: %d\n", +- rate, ret); ++ ath11k_warn(ar->ab, "failed to set he ltf %d: %d\n", ++ he_ltf, ret); + return ret; + } + +- vdev_param = WMI_VDEV_PARAM_NSS; ++ return 0; ++} ++ ++static int ++ath11k_mac_set_auto_rate_gi_ltf(struct ath11k_vif *arvif, u16 he_gi, u8 he_ltf) ++{ ++ struct ath11k *ar = arvif->ar; ++ int ret; ++ u32 he_ar_gi_ltf; ++ ++ if (he_gi != 0xFF) { ++ switch (he_gi) { ++ case NL80211_RATE_INFO_HE_GI_0_8: ++ he_gi = WMI_AUTORATE_800NS_GI; ++ break; ++ case NL80211_RATE_INFO_HE_GI_1_6: ++ he_gi = WMI_AUTORATE_1600NS_GI; ++ break; ++ case NL80211_RATE_INFO_HE_GI_3_2: ++ he_gi = WMI_AUTORATE_3200NS_GI; ++ break; ++ default: ++ ath11k_warn(ar->ab, "invalid he gi: %d\n", he_gi); ++ return -EINVAL; ++ } ++ } ++ ++ if (he_ltf != 0xFF) { ++ switch (he_ltf) { ++ case NL80211_RATE_INFO_HE_1XLTF: ++ he_ltf = WMI_HE_AUTORATE_LTF_1X; ++ break; ++ case NL80211_RATE_INFO_HE_2XLTF: ++ he_ltf = WMI_HE_AUTORATE_LTF_2X; ++ break; ++ case NL80211_RATE_INFO_HE_4XLTF: ++ he_ltf = WMI_HE_AUTORATE_LTF_4X; ++ break; ++ default: ++ ath11k_warn(ar->ab, "invalid he ltf: %d\n", he_ltf); ++ return -EINVAL; ++ } ++ } ++ ++ he_ar_gi_ltf = he_gi | he_ltf; + ret = ath11k_wmi_vdev_set_param_cmd(ar, arvif->vdev_id, +- vdev_param, nss); ++ WMI_VDEV_PARAM_AUTORATE_MISC_CFG, ++ he_ar_gi_ltf); + if (ret) { +- ath11k_warn(ar->ab, "failed to set nss param %d: %d\n", +- nss, ret); ++ ath11k_warn(ar->ab, ++ "failed to set he autorate gi %u ltf %u: %d\n", ++ he_gi, he_ltf, ret); + return ret; + } + +- vdev_param = WMI_VDEV_PARAM_SGI; ++ return 0; ++} ++ ++static int ath11k_mac_set_rate_params(struct ath11k_vif *arvif, ++ u32 rate, u8 nss, u8 sgi, u8 ldpc, ++ u8 he_gi, u8 he_ltf, bool he_fixed_rate) ++{ ++ struct ath11k *ar = arvif->ar; ++ u32 vdev_param; ++ int ret; ++ ++ lockdep_assert_held(&ar->conf_mutex); ++ ++ ath11k_dbg(ar->ab, ATH11K_DBG_MAC, ++ "mac set rate params vdev %i rate 0x%02x nss 0x%02x sgi 0x%02x ldpc 0x%02x he_gi 0x%02x he_ltf 0x%02x he_fixed_rate %d\n", ++ arvif->vdev_id, rate, nss, sgi, ldpc, he_gi, ++ he_ltf, he_fixed_rate); ++ ++ if (!arvif->vif->bss_conf.he_support) { ++ vdev_param = WMI_VDEV_PARAM_FIXED_RATE; ++ ret = ath11k_wmi_vdev_set_param_cmd(ar, arvif->vdev_id, ++ vdev_param, rate); ++ if (ret) { ++ ath11k_warn(ar->ab, "failed to set fixed rate param 0x%02x: %d\n", ++ rate, ret); ++ return ret; ++ } ++ } ++ ++ vdev_param = WMI_VDEV_PARAM_NSS; + ret = ath11k_wmi_vdev_set_param_cmd(ar, arvif->vdev_id, +- vdev_param, sgi); ++ vdev_param, nss); + if (ret) { +- ath11k_warn(ar->ab, "failed to set sgi param %d: %d\n", +- sgi, ret); ++ ath11k_warn(ar->ab, "failed to set nss param %d: %d\n", ++ nss, ret); + return ret; + } + +@@ -6314,6 +6697,35 @@ static int ath11k_mac_set_fixed_rate_par + return ret; + } + ++ if (arvif->vif->bss_conf.he_support) { ++ if (he_fixed_rate) { ++ ret = ath11k_mac_set_fixed_rate_gi_ltf(arvif, he_gi, ++ he_ltf); ++ if (ret) { ++ ath11k_warn(ar->ab, "failed to set fixed rate gi ltf: %d\n", ++ ret); ++ return ret; ++ } ++ } else { ++ ret = ath11k_mac_set_auto_rate_gi_ltf(arvif, he_gi, ++ he_ltf); ++ if (ret) { ++ ath11k_warn(ar->ab, "failed to set auto rate gi ltf: %d\n", ++ ret); ++ return ret; ++ } ++ } ++ } else { ++ vdev_param = WMI_VDEV_PARAM_SGI; ++ ret = ath11k_wmi_vdev_set_param_cmd(ar, arvif->vdev_id, ++ vdev_param, sgi); ++ if (ret) { ++ ath11k_warn(ar->ab, "failed to set sgi param %d: %d\n", ++ sgi, ret); ++ return ret; ++ } ++ } ++ + return 0; + } + +@@ -6342,6 +6754,31 @@ ath11k_mac_vht_mcs_range_present(struct + return true; + } + ++static bool ++ath11k_mac_he_mcs_range_present(struct ath11k *ar, ++ enum nl80211_band band, ++ const struct cfg80211_bitrate_mask *mask) ++{ ++ int i; ++ u16 he_mcs; ++ ++ for (i = 0; i < NL80211_HE_NSS_MAX; i++) { ++ he_mcs = mask->control[band].he_mcs[i]; ++ ++ switch (he_mcs) { ++ case 0: ++ case BIT(8) - 1: ++ case BIT(10) - 1: ++ case BIT(12) - 1: ++ break; ++ default: ++ return false; ++ } ++ } ++ ++ return true; ++} ++ + static void ath11k_mac_set_bitrate_mask_iter(void *data, + struct ieee80211_sta *sta) + { +@@ -6373,6 +6810,54 @@ static void ath11k_mac_disable_peer_fixe + sta->addr, ret); + } + ++static bool ++ath11k_mac_validate_vht_he_fixed_rate_settings(struct ath11k *ar, enum nl80211_band band, ++ const struct cfg80211_bitrate_mask *mask) ++{ ++ bool he_fixed_rate = false, vht_fixed_rate = false; ++ struct ath11k_peer *peer, *tmp; ++ const u16 *vht_mcs_mask, *he_mcs_mask; ++ u8 vht_nss, he_nss; ++ bool ret = true; ++ ++ vht_mcs_mask = mask->control[band].vht_mcs; ++ he_mcs_mask = mask->control[band].he_mcs; ++ ++ if (ath11k_mac_bitrate_mask_num_vht_rates(ar, band, mask) == 1) ++ vht_fixed_rate = true; ++ ++ if (ath11k_mac_bitrate_mask_num_he_rates(ar, band, mask) == 1) ++ he_fixed_rate = true; ++ ++ if (!vht_fixed_rate && !he_fixed_rate) ++ return true; ++ ++ vht_nss = ath11k_mac_max_vht_nss(vht_mcs_mask); ++ he_nss = ath11k_mac_max_he_nss(he_mcs_mask); ++ ++ rcu_read_lock(); ++ spin_lock_bh(&ar->ab->base_lock); ++ list_for_each_entry_safe(peer, tmp, &ar->ab->peers, list) { ++ if (peer->sta) { ++ if (vht_fixed_rate && (!peer->sta->vht_cap.vht_supported || ++ peer->sta->rx_nss < vht_nss)) { ++ ret = false; ++ goto out; ++ } ++ if (he_fixed_rate && (!peer->sta->he_cap.has_he || ++ peer->sta->rx_nss < he_nss)) { ++ ret = false; ++ goto out; ++ } ++ } ++ } ++ ++out: ++ spin_unlock_bh(&ar->ab->base_lock); ++ rcu_read_unlock(); ++ return ret; ++} ++ + static int + ath11k_mac_op_set_bitrate_mask(struct ieee80211_hw *hw, + struct ieee80211_vif *vif, +@@ -6384,6 +6869,9 @@ ath11k_mac_op_set_bitrate_mask(struct ie + enum nl80211_band band; + const u8 *ht_mcs_mask; + const u16 *vht_mcs_mask; ++ const u16 *he_mcs_mask; ++ u8 he_ltf = 0; ++ u8 he_gi = 0; + u32 rate; + u8 nss; + u8 sgi; +@@ -6391,6 +6879,7 @@ ath11k_mac_op_set_bitrate_mask(struct ie + int single_nss; + int ret; + int num_rates; ++ bool he_fixed_rate = false; + + if (ath11k_mac_vif_chan(vif, &def)) + return -EPERM; +@@ -6398,12 +6887,16 @@ ath11k_mac_op_set_bitrate_mask(struct ie + band = def.chan->band; + ht_mcs_mask = mask->control[band].ht_mcs; + vht_mcs_mask = mask->control[band].vht_mcs; ++ he_mcs_mask = mask->control[band].he_mcs; + ldpc = !!(ar->ht_cap_info & WMI_HT_CAP_LDPC); + + sgi = mask->control[band].gi; + if (sgi == NL80211_TXRATE_FORCE_LGI) + return -EINVAL; + ++ he_gi = mask->control[band].he_gi; ++ he_ltf = mask->control[band].he_ltf; ++ + /* mac80211 doesn't support sending a fixed HT/VHT MCS alone, rather it + * requires passing atleast one of used basic rates along with them. + * Fixed rate setting across different preambles(legacy, HT, VHT) is +@@ -6427,11 +6920,22 @@ ath11k_mac_op_set_bitrate_mask(struct ie + &single_nss)) { + rate = WMI_FIXED_RATE_NONE; + nss = single_nss; ++ mutex_lock(&ar->conf_mutex); ++ arvif->bitrate_mask = *mask; ++ ieee80211_iterate_stations_atomic(ar->hw, ++ ath11k_mac_set_bitrate_mask_iter, ++ arvif); ++ mutex_unlock(&ar->conf_mutex); + } else { + rate = WMI_FIXED_RATE_NONE; ++ ++ if (!ath11k_mac_validate_vht_he_fixed_rate_settings(ar, band, mask)) ++ ath11k_warn(ar->ab, ++ "could not update fixed rate settings to all peers due to mcs/nss incompaitiblity\n"); + nss = min_t(u32, ar->num_tx_chains, +- max(ath11k_mac_max_ht_nss(ht_mcs_mask), +- ath11k_mac_max_vht_nss(vht_mcs_mask))); ++ max(max(ath11k_mac_max_ht_nss(ht_mcs_mask), ++ ath11k_mac_max_vht_nss(vht_mcs_mask)), ++ ath11k_mac_max_he_nss(he_mcs_mask))); + + /* If multiple rates across different preambles are given + * we can reconfigure this info with all peers using PEER_ASSOC +@@ -6462,16 +6966,28 @@ ath11k_mac_op_set_bitrate_mask(struct ie + * RATEMASK CMD + */ + ath11k_warn(ar->ab, +- "Setting more than one MCS Value in bitrate mask not supported\n"); ++ "setting %d mcs values in bitrate mask not supported\n", ++ num_rates); + return -EINVAL; + } + ++ num_rates = ath11k_mac_bitrate_mask_num_he_rates(ar, band, ++ mask); ++ if (num_rates == 1) ++ he_fixed_rate = true; ++ ++ if (!ath11k_mac_he_mcs_range_present(ar, band, mask) && ++ num_rates > 1) { ++ ath11k_warn(ar->ab, ++ "Setting more than one HE MCS Value in bitrate mask not supported\n"); ++ return -EINVAL; ++ } ++ ++ mutex_lock(&ar->conf_mutex); + ieee80211_iterate_stations_atomic(ar->hw, + ath11k_mac_disable_peer_fixed_rate, + arvif); + +- mutex_lock(&ar->conf_mutex); +- + arvif->bitrate_mask = *mask; + ieee80211_iterate_stations_atomic(ar->hw, + ath11k_mac_set_bitrate_mask_iter, +@@ -6482,9 +6998,10 @@ ath11k_mac_op_set_bitrate_mask(struct ie + + mutex_lock(&ar->conf_mutex); + +- ret = ath11k_mac_set_fixed_rate_params(arvif, rate, nss, sgi, ldpc); ++ ret = ath11k_mac_set_rate_params(arvif, rate, nss, sgi, ldpc, he_gi, ++ he_ltf, he_fixed_rate); + if (ret) { +- ath11k_warn(ar->ab, "failed to set fixed rate params on vdev %i: %d\n", ++ ath11k_warn(ar->ab, "failed to set rate params on vdev %i: %d\n", + arvif->vdev_id, ret); + } + +--- a/drivers/net/wireless/ath/ath11k/wmi.c ++++ b/drivers/net/wireless/ath/ath11k/wmi.c +@@ -1904,8 +1904,8 @@ int ath11k_wmi_send_peer_assoc_cmd(struc + FIELD_PREP(WMI_TLV_LEN, + sizeof(*he_mcs) - TLV_HDR_SIZE); + +- he_mcs->rx_mcs_set = param->peer_he_rx_mcs_set[i]; +- he_mcs->tx_mcs_set = param->peer_he_tx_mcs_set[i]; ++ he_mcs->rx_mcs_set = param->peer_he_tx_mcs_set[i]; ++ he_mcs->tx_mcs_set = param->peer_he_rx_mcs_set[i]; + ptr += sizeof(*he_mcs); + } + +--- a/drivers/net/wireless/ath/ath11k/wmi.h ++++ b/drivers/net/wireless/ath/ath11k/wmi.h +@@ -119,6 +119,22 @@ enum { + WMI_HOST_WLAN_2G_5G_CAP = 0x3, + }; + ++/* Parameters used for WMI_VDEV_PARAM_AUTORATE_MISC_CFG command. ++ * Used only for HE auto rate mode. ++ */ ++enum { ++ /* HE LTF related configuration */ ++ WMI_HE_AUTORATE_LTF_1X = BIT(0), ++ WMI_HE_AUTORATE_LTF_2X = BIT(1), ++ WMI_HE_AUTORATE_LTF_4X = BIT(2), ++ ++ /* HE GI related configuration */ ++ WMI_AUTORATE_400NS_GI = BIT(8), ++ WMI_AUTORATE_800NS_GI = BIT(9), ++ WMI_AUTORATE_1600NS_GI = BIT(10), ++ WMI_AUTORATE_3200NS_GI = BIT(11), ++}; ++ + /* + * wmi command groups. + */ +@@ -1044,7 +1060,9 @@ enum wmi_tlv_vdev_param { + WMI_VDEV_PARAM_HE_RANGE_EXT, + WMI_VDEV_PARAM_ENABLE_BCAST_PROBE_RESPONSE, + WMI_VDEV_PARAM_FILS_MAX_CHANNEL_GUARD_TIME, ++ WMI_VDEV_PARAM_HE_LTF = 0x74, + WMI_VDEV_PARAM_BA_MODE = 0x7e, ++ WMI_VDEV_PARAM_AUTORATE_MISC_CFG = 0x80, + WMI_VDEV_PARAM_SET_HE_SOUNDING_MODE = 0x87, + WMI_VDEV_PARAM_6GHZ_PARAMS = 0x99, + WMI_VDEV_PARAM_PROTOTYPE = 0x8000, +@@ -3920,7 +3938,11 @@ struct wmi_vht_rate_set { + + struct wmi_he_rate_set { + u32 tlv_header; ++ ++ /* MCS at which the peer can receive */ + u32 rx_mcs_set; ++ ++ /* MCS at which the peer can transmit */ + u32 tx_mcs_set; + } __packed; + diff --git a/package/kernel/mac80211/patches/ath11k/0011-ath11k-add-support-for-80P80-and-160-MHz-bandwidth.patch b/package/kernel/mac80211/patches/ath11k/0011-ath11k-add-support-for-80P80-and-160-MHz-bandwidth.patch new file mode 100644 index 000000000..6eaf32a4c --- /dev/null +++ b/package/kernel/mac80211/patches/ath11k/0011-ath11k-add-support-for-80P80-and-160-MHz-bandwidth.patch @@ -0,0 +1,322 @@ +From f552d6fd2f27ce9430c74482c46272838e2de688 Mon Sep 17 00:00:00 2001 +From: P Praneesh +Date: Fri, 24 Sep 2021 16:52:46 +0300 +Subject: [PATCH 011/120] ath11k: add support for 80P80 and 160 MHz bandwidth + +For 160 MHz, nss_ratio_enabled flag is added to indicate firmware +supports sending NSS ratio information from firmware as a part of +service ready ext event. Extract this NSS ratio info from service +ready ext event and save this information in ath11k_pdev_cap to +calculate NSS ratio. + +Current firmware configurations support two types of NSS ratio +which is WMI_NSS_RATIO_1_NSS for QCN9074 and WMI_NSS_RATIO_1BY2_NSS +for IPQ8074. Based on this two configuration, max supported +NSS getting calculated. + +Move ath11k_peer_assoc_h_phymode() before ath11k_peer_assoc_h_vht() +to get arg->peer_phymode updated. + +Tested-on: QCN9074 hw1.0 PCI WLAN.HK.2.4.0.1-00097-QCAHKSWPL_SILICONZ-1 +Tested-on: IPQ8074 hw2.0 AHB WLAN.HK.2.4.0.1-01467-QCAHKSWPL_SILICONZ-1 + +Co-developed-by: Ganesh Sesetti +Signed-off-by: Ganesh Sesetti +Co-developed-by: Sathishkumar Muruganandam +Signed-off-by: Sathishkumar Muruganandam +Signed-off-by: P Praneesh +Signed-off-by: Jouni Malinen +Signed-off-by: Kalle Valo +Link: https://lore.kernel.org/r/20210721173615.75637-2-jouni@codeaurora.org +--- + drivers/net/wireless/ath/ath11k/core.h | 2 + + drivers/net/wireless/ath/ath11k/mac.c | 95 ++++++++++++++++++++++---- + drivers/net/wireless/ath/ath11k/mac.h | 3 + + drivers/net/wireless/ath/ath11k/wmi.c | 20 +++++- + drivers/net/wireless/ath/ath11k/wmi.h | 30 ++++++++ + 5 files changed, 136 insertions(+), 14 deletions(-) + +--- a/drivers/net/wireless/ath/ath11k/core.h ++++ b/drivers/net/wireless/ath/ath11k/core.h +@@ -597,6 +597,8 @@ struct ath11k_pdev_cap { + u32 tx_chain_mask_shift; + u32 rx_chain_mask_shift; + struct ath11k_band_cap band[NUM_NL80211_BANDS]; ++ bool nss_ratio_enabled; ++ u8 nss_ratio_info; + }; + + struct ath11k_pdev { +--- a/drivers/net/wireless/ath/ath11k/mac.c ++++ b/drivers/net/wireless/ath/ath11k/mac.c +@@ -1581,6 +1581,34 @@ ath11k_peer_assoc_h_vht_limit(u16 tx_mcs + return tx_mcs_set; + } + ++static u8 ath11k_get_nss_160mhz(struct ath11k *ar, ++ u8 max_nss) ++{ ++ u8 nss_ratio_info = ar->pdev->cap.nss_ratio_info; ++ u8 max_sup_nss = 0; ++ ++ switch (nss_ratio_info) { ++ case WMI_NSS_RATIO_1BY2_NSS: ++ max_sup_nss = max_nss >> 1; ++ break; ++ case WMI_NSS_RATIO_3BY4_NSS: ++ ath11k_warn(ar->ab, "WMI_NSS_RATIO_3BY4_NSS not supported\n"); ++ break; ++ case WMI_NSS_RATIO_1_NSS: ++ max_sup_nss = max_nss; ++ break; ++ case WMI_NSS_RATIO_2_NSS: ++ ath11k_warn(ar->ab, "WMI_NSS_RATIO_2_NSS not supported\n"); ++ break; ++ default: ++ ath11k_warn(ar->ab, "invalid nss ratio received from firmware: %d\n", ++ nss_ratio_info); ++ break; ++ } ++ ++ return max_sup_nss; ++} ++ + static void ath11k_peer_assoc_h_vht(struct ath11k *ar, + struct ieee80211_vif *vif, + struct ieee80211_sta *sta, +@@ -1595,6 +1623,7 @@ static void ath11k_peer_assoc_h_vht(stru + u8 max_nss, vht_mcs; + int i, vht_nss, nss_idx; + bool user_rate_valid = true; ++ u32 rx_nss, tx_nss, nss_160; + + if (WARN_ON(ath11k_mac_vif_chan(vif, &def))) + return; +@@ -1687,10 +1716,29 @@ static void ath11k_peer_assoc_h_vht(stru + /* TODO: Check */ + arg->tx_max_mcs_nss = 0xFF; + +- ath11k_dbg(ar->ab, ATH11K_DBG_MAC, "mac vht peer %pM max_mpdu %d flags 0x%x\n", +- sta->addr, arg->peer_max_mpdu, arg->peer_flags); ++ if (arg->peer_phymode == MODE_11AC_VHT160 || ++ arg->peer_phymode == MODE_11AC_VHT80_80) { ++ tx_nss = ath11k_get_nss_160mhz(ar, max_nss); ++ rx_nss = min(arg->peer_nss, tx_nss); ++ arg->peer_bw_rxnss_override = ATH11K_BW_NSS_MAP_ENABLE; ++ ++ if (!rx_nss) { ++ ath11k_warn(ar->ab, "invalid max_nss\n"); ++ return; ++ } ++ ++ if (arg->peer_phymode == MODE_11AC_VHT160) ++ nss_160 = FIELD_PREP(ATH11K_PEER_RX_NSS_160MHZ, rx_nss - 1); ++ else ++ nss_160 = FIELD_PREP(ATH11K_PEER_RX_NSS_80_80MHZ, rx_nss - 1); + +- /* TODO: rxnss_override */ ++ arg->peer_bw_rxnss_override |= nss_160; ++ } ++ ++ ath11k_dbg(ar->ab, ATH11K_DBG_MAC, ++ "mac vht peer %pM max_mpdu %d flags 0x%x nss_override 0x%x\n", ++ sta->addr, arg->peer_max_mpdu, arg->peer_flags, ++ arg->peer_bw_rxnss_override); + } + + static int ath11k_mac_get_max_he_mcs_map(u16 mcs_map, int nss) +@@ -1774,6 +1822,7 @@ static void ath11k_peer_assoc_h_he(struc + u16 he_tx_mcs = 0, v = 0; + int i, he_nss, nss_idx; + bool user_rate_valid = true; ++ u32 rx_nss, tx_nss, nss_160; + + if (WARN_ON(ath11k_mac_vif_chan(vif, &def))) + return; +@@ -1937,9 +1986,30 @@ static void ath11k_peer_assoc_h_he(struc + } + arg->peer_nss = min(sta->rx_nss, max_nss); + ++ if (arg->peer_phymode == MODE_11AX_HE160 || ++ arg->peer_phymode == MODE_11AX_HE80_80) { ++ tx_nss = ath11k_get_nss_160mhz(ar, max_nss); ++ rx_nss = min(arg->peer_nss, tx_nss); ++ arg->peer_bw_rxnss_override = ATH11K_BW_NSS_MAP_ENABLE; ++ ++ if (!rx_nss) { ++ ath11k_warn(ar->ab, "invalid max_nss\n"); ++ return; ++ } ++ ++ if (arg->peer_phymode == MODE_11AX_HE160) ++ nss_160 = FIELD_PREP(ATH11K_PEER_RX_NSS_160MHZ, rx_nss - 1); ++ else ++ nss_160 = FIELD_PREP(ATH11K_PEER_RX_NSS_80_80MHZ, rx_nss - 1); ++ ++ arg->peer_bw_rxnss_override |= nss_160; ++ } ++ + ath11k_dbg(ar->ab, ATH11K_DBG_MAC, +- "mac he peer %pM nss %d mcs cnt %d\n", +- sta->addr, arg->peer_nss, arg->peer_he_mcs_count); ++ "mac he peer %pM nss %d mcs cnt %d nss_override 0x%x\n", ++ sta->addr, arg->peer_nss, ++ arg->peer_he_mcs_count, ++ arg->peer_bw_rxnss_override); + } + + static void ath11k_peer_assoc_h_smps(struct ieee80211_sta *sta, +@@ -2227,11 +2297,11 @@ static void ath11k_peer_assoc_prepare(st + ath11k_peer_assoc_h_basic(ar, vif, sta, arg); + ath11k_peer_assoc_h_crypto(ar, vif, sta, arg); + ath11k_peer_assoc_h_rates(ar, vif, sta, arg); ++ ath11k_peer_assoc_h_phymode(ar, vif, sta, arg); + ath11k_peer_assoc_h_ht(ar, vif, sta, arg); + ath11k_peer_assoc_h_vht(ar, vif, sta, arg); + ath11k_peer_assoc_h_he(ar, vif, sta, arg); + ath11k_peer_assoc_h_qos(ar, vif, sta, arg); +- ath11k_peer_assoc_h_phymode(ar, vif, sta, arg); + ath11k_peer_assoc_h_smps(sta, arg); + + /* TODO: amsdu_disable req? */ +@@ -4427,11 +4497,6 @@ ath11k_create_vht_cap(struct ath11k *ar, + + ath11k_set_vht_txbf_cap(ar, &vht_cap.cap); + +- /* TODO: Enable back VHT160 mode once association issues are fixed */ +- /* Disabling VHT160 and VHT80+80 modes */ +- vht_cap.cap &= ~IEEE80211_VHT_CAP_SUPP_CHAN_WIDTH_MASK; +- vht_cap.cap &= ~IEEE80211_VHT_CAP_SHORT_GI_160; +- + rxmcs_map = 0; + txmcs_map = 0; + for (i = 0; i < 8; i++) { +@@ -7345,7 +7410,9 @@ static int ath11k_mac_setup_iface_combin + combinations[0].radar_detect_widths = BIT(NL80211_CHAN_WIDTH_20_NOHT) | + BIT(NL80211_CHAN_WIDTH_20) | + BIT(NL80211_CHAN_WIDTH_40) | +- BIT(NL80211_CHAN_WIDTH_80); ++ BIT(NL80211_CHAN_WIDTH_80) | ++ BIT(NL80211_CHAN_WIDTH_80P80) | ++ BIT(NL80211_CHAN_WIDTH_160); + + ar->hw->wiphy->iface_combinations = combinations; + ar->hw->wiphy->n_iface_combinations = 1; +@@ -7484,6 +7551,10 @@ static int __ath11k_mac_register(struct + ieee80211_hw_set(ar->hw, SUPPORTS_TX_FRAG); + ieee80211_hw_set(ar->hw, REPORTS_LOW_ACK); + ieee80211_hw_set(ar->hw, SUPPORTS_TX_ENCAP_OFFLOAD); ++ ++ if (cap->nss_ratio_enabled) ++ ieee80211_hw_set(ar->hw, SUPPORTS_VHT_EXT_NSS_BW); ++ + if (ht_cap & WMI_HT_CAP_ENABLED) { + ieee80211_hw_set(ar->hw, AMPDU_AGGREGATION); + ieee80211_hw_set(ar->hw, TX_AMPDU_SETUP_IN_HW); +--- a/drivers/net/wireless/ath/ath11k/mac.h ++++ b/drivers/net/wireless/ath/ath11k/mac.h +@@ -115,6 +115,9 @@ struct ath11k_generic_iter { + #define WMI_MAX_SPATIAL_STREAM 3 + + #define ATH11K_CHAN_WIDTH_NUM 8 ++#define ATH11K_BW_NSS_MAP_ENABLE BIT(31) ++#define ATH11K_PEER_RX_NSS_160MHZ GENMASK(2, 0) ++#define ATH11K_PEER_RX_NSS_80_80MHZ GENMASK(5, 3) + + #define ATH11K_OBSS_PD_MAX_THRESHOLD -82 + #define ATH11K_OBSS_PD_NON_SRG_MAX_THRESHOLD -62 +--- a/drivers/net/wireless/ath/ath11k/wmi.c ++++ b/drivers/net/wireless/ath/ath11k/wmi.c +@@ -360,6 +360,10 @@ ath11k_pull_mac_phy_cap_svc_ready_ext(st + pdev_cap->he_mcs = mac_phy_caps->he_supp_mcs_5g; + pdev_cap->tx_chain_mask = mac_phy_caps->tx_chain_mask_5g; + pdev_cap->rx_chain_mask = mac_phy_caps->rx_chain_mask_5g; ++ pdev_cap->nss_ratio_enabled = ++ WMI_NSS_RATIO_ENABLE_DISABLE_GET(mac_phy_caps->nss_ratio); ++ pdev_cap->nss_ratio_info = ++ WMI_NSS_RATIO_INFO_GET(mac_phy_caps->nss_ratio); + } else { + return -EINVAL; + } +@@ -783,14 +787,26 @@ int ath11k_wmi_vdev_down(struct ath11k * + static void ath11k_wmi_put_wmi_channel(struct wmi_channel *chan, + struct wmi_vdev_start_req_arg *arg) + { ++ u32 center_freq1 = arg->channel.band_center_freq1; ++ + memset(chan, 0, sizeof(*chan)); + + chan->mhz = arg->channel.freq; + chan->band_center_freq1 = arg->channel.band_center_freq1; +- if (arg->channel.mode == MODE_11AC_VHT80_80) ++ ++ if (arg->channel.mode == MODE_11AX_HE160) { ++ if (arg->channel.freq > arg->channel.band_center_freq1) ++ chan->band_center_freq1 = center_freq1 + 40; ++ else ++ chan->band_center_freq1 = center_freq1 - 40; ++ ++ chan->band_center_freq2 = arg->channel.band_center_freq1; ++ ++ } else if (arg->channel.mode == MODE_11AC_VHT80_80) { + chan->band_center_freq2 = arg->channel.band_center_freq2; +- else ++ } else { + chan->band_center_freq2 = 0; ++ } + + chan->info |= FIELD_PREP(WMI_CHAN_INFO_MODE, arg->channel.mode); + if (arg->channel.passive) +--- a/drivers/net/wireless/ath/ath11k/wmi.h ++++ b/drivers/net/wireless/ath/ath11k/wmi.h +@@ -2146,6 +2146,24 @@ enum wmi_direct_buffer_module { + WMI_DIRECT_BUF_MAX + }; + ++/* enum wmi_nss_ratio - NSS ratio received from FW during service ready ext ++ * event ++ * WMI_NSS_RATIO_1BY2_NSS -Max nss of 160MHz is equals to half of the max nss ++ * of 80MHz ++ * WMI_NSS_RATIO_3BY4_NSS - Max nss of 160MHz is equals to 3/4 of the max nss ++ * of 80MHz ++ * WMI_NSS_RATIO_1_NSS - Max nss of 160MHz is equals to the max nss of 80MHz ++ * WMI_NSS_RATIO_2_NSS - Max nss of 160MHz is equals to two times the max ++ * nss of 80MHz ++ */ ++ ++enum wmi_nss_ratio { ++ WMI_NSS_RATIO_1BY2_NSS = 0x0, ++ WMI_NSS_RATIO_3BY4_NSS = 0x1, ++ WMI_NSS_RATIO_1_NSS = 0x2, ++ WMI_NSS_RATIO_2_NSS = 0x3, ++}; ++ + struct wmi_host_pdev_band_to_mac { + u32 pdev_id; + u32 start_freq; +@@ -2390,6 +2408,12 @@ struct wmi_hw_mode_capabilities { + } __packed; + + #define WMI_MAX_HECAP_PHY_SIZE (3) ++#define WMI_NSS_RATIO_ENABLE_DISABLE_BITPOS BIT(0) ++#define WMI_NSS_RATIO_ENABLE_DISABLE_GET(_val) \ ++ FIELD_GET(WMI_NSS_RATIO_ENABLE_DISABLE_BITPOS, _val) ++#define WMI_NSS_RATIO_INFO_BITPOS GENMASK(4, 1) ++#define WMI_NSS_RATIO_INFO_GET(_val) \ ++ FIELD_GET(WMI_NSS_RATIO_INFO_BITPOS, _val) + + struct wmi_mac_phy_capabilities { + u32 hw_mode_id; +@@ -2423,6 +2447,12 @@ struct wmi_mac_phy_capabilities { + u32 he_cap_info_2g_ext; + u32 he_cap_info_5g_ext; + u32 he_cap_info_internal; ++ u32 wireless_modes; ++ u32 low_2ghz_chan_freq; ++ u32 high_2ghz_chan_freq; ++ u32 low_5ghz_chan_freq; ++ u32 high_5ghz_chan_freq; ++ u32 nss_ratio; + } __packed; + + struct wmi_hal_reg_capabilities_ext { diff --git a/package/kernel/mac80211/patches/ath11k/0012-ath11k-Refactor-spectral-FFT-bin-size.patch b/package/kernel/mac80211/patches/ath11k/0012-ath11k-Refactor-spectral-FFT-bin-size.patch new file mode 100644 index 000000000..9a74a5796 --- /dev/null +++ b/package/kernel/mac80211/patches/ath11k/0012-ath11k-Refactor-spectral-FFT-bin-size.patch @@ -0,0 +1,165 @@ +From cc2ad7541486f1f755949c1ccd17e14a15bf1f4e Mon Sep 17 00:00:00 2001 +From: Karthikeyan Periyasamy +Date: Fri, 24 Sep 2021 16:52:46 +0300 +Subject: [PATCH 012/120] ath11k: Refactor spectral FFT bin size + +In IPQ8074, actual FFT bin size is two bytes but hardware reports it +with extra pad size of two bytes for each FFT bin. So finally each FFT +bin advertise as four bytes size in the collected data. This FFT pad is +not advertised in IPQ6018 platform. To accommodate this different +behavior across the platforms, introduce the hw param fft_pad_sz and use +it in spectral process. Also group all the spectral params under the new +structure in hw param structure for scalable in future. + +Tested-on: IPQ8074 hw2.0 AHB WLAN.HK.2.4.0.1-01492-QCAHKSWPL_SILICONZ-1 +Tested-on: IPQ6018 hw1.0 AHB WLAN.HK.2.4.0.1-00330-QCAHKSWPL_SILICONZ-1 + +Signed-off-by: Karthikeyan Periyasamy +Signed-off-by: Jouni Malinen +Signed-off-by: Kalle Valo +Link: https://lore.kernel.org/r/20210721180809.90960-2-jouni@codeaurora.org +--- + drivers/net/wireless/ath/ath11k/core.c | 33 +++++++++++++++++++--- + drivers/net/wireless/ath/ath11k/hw.h | 6 +++- + drivers/net/wireless/ath/ath11k/spectral.c | 13 ++++----- + 3 files changed, 40 insertions(+), 12 deletions(-) + +--- a/drivers/net/wireless/ath/ath11k/core.c ++++ b/drivers/net/wireless/ath/ath11k/core.c +@@ -59,7 +59,14 @@ static const struct ath11k_hw_params ath + .vdev_start_delay = false, + .htt_peer_map_v2 = true, + .tcl_0_only = false, +- .spectral_fft_sz = 2, ++ ++ .spectral = { ++ .fft_sz = 2, ++ /* HW bug, expected BIN size is 2 bytes but HW report as 4 bytes. ++ * so added pad size as 2 bytes to compensate the BIN size ++ */ ++ .fft_pad_sz = 2, ++ }, + + .interface_modes = BIT(NL80211_IFTYPE_STATION) | + BIT(NL80211_IFTYPE_AP) | +@@ -100,7 +107,11 @@ static const struct ath11k_hw_params ath + .vdev_start_delay = false, + .htt_peer_map_v2 = true, + .tcl_0_only = false, +- .spectral_fft_sz = 4, ++ ++ .spectral = { ++ .fft_sz = 4, ++ .fft_pad_sz = 0, ++ }, + + .interface_modes = BIT(NL80211_IFTYPE_STATION) | + BIT(NL80211_IFTYPE_AP) | +@@ -141,7 +152,11 @@ static const struct ath11k_hw_params ath + .vdev_start_delay = true, + .htt_peer_map_v2 = false, + .tcl_0_only = true, +- .spectral_fft_sz = 0, ++ ++ .spectral = { ++ .fft_sz = 0, ++ .fft_pad_sz = 0, ++ }, + + .interface_modes = BIT(NL80211_IFTYPE_STATION) | + BIT(NL80211_IFTYPE_AP), +@@ -180,6 +195,12 @@ static const struct ath11k_hw_params ath + .vdev_start_delay = false, + .htt_peer_map_v2 = true, + .tcl_0_only = false, ++ ++ .spectral = { ++ .fft_sz = 0, ++ .fft_pad_sz = 0, ++ }, ++ + .interface_modes = BIT(NL80211_IFTYPE_STATION) | + BIT(NL80211_IFTYPE_AP) | + BIT(NL80211_IFTYPE_MESH_POINT), +@@ -219,7 +240,11 @@ static const struct ath11k_hw_params ath + .vdev_start_delay = true, + .htt_peer_map_v2 = false, + .tcl_0_only = true, +- .spectral_fft_sz = 0, ++ ++ .spectral = { ++ .fft_sz = 0, ++ .fft_pad_sz = 0, ++ }, + + .interface_modes = BIT(NL80211_IFTYPE_STATION) | + BIT(NL80211_IFTYPE_AP), +--- a/drivers/net/wireless/ath/ath11k/hw.h ++++ b/drivers/net/wireless/ath/ath11k/hw.h +@@ -153,7 +153,11 @@ struct ath11k_hw_params { + bool vdev_start_delay; + bool htt_peer_map_v2; + bool tcl_0_only; +- u8 spectral_fft_sz; ++ ++ struct { ++ u8 fft_sz; ++ u8 fft_pad_sz; ++ } spectral; + + u16 interface_modes; + bool supports_monitor; +--- a/drivers/net/wireless/ath/ath11k/spectral.c ++++ b/drivers/net/wireless/ath/ath11k/spectral.c +@@ -11,8 +11,6 @@ + #define ATH11K_SPECTRAL_EVENT_TIMEOUT_MS 1 + + #define ATH11K_SPECTRAL_DWORD_SIZE 4 +-/* HW bug, expected BIN size is 2 bytes but HW report as 4 bytes */ +-#define ATH11K_SPECTRAL_BIN_SIZE 4 + #define ATH11K_SPECTRAL_ATH11K_MIN_BINS 64 + #define ATH11K_SPECTRAL_ATH11K_MIN_IB_BINS 32 + #define ATH11K_SPECTRAL_ATH11K_MAX_IB_BINS 256 +@@ -585,12 +583,12 @@ int ath11k_spectral_process_fft(struct a + struct spectral_tlv *tlv; + int tlv_len, bin_len, num_bins; + u16 length, freq; +- u8 chan_width_mhz; ++ u8 chan_width_mhz, bin_sz; + int ret; + + lockdep_assert_held(&ar->spectral.lock); + +- if (!ab->hw_params.spectral_fft_sz) { ++ if (!ab->hw_params.spectral.fft_sz) { + ath11k_warn(ab, "invalid bin size type for hw rev %d\n", + ab->hw_rev); + return -EINVAL; +@@ -608,7 +606,8 @@ int ath11k_spectral_process_fft(struct a + return -EINVAL; + } + +- num_bins = bin_len / ATH11K_SPECTRAL_BIN_SIZE; ++ bin_sz = ab->hw_params.spectral.fft_sz + ab->hw_params.spectral.fft_pad_sz; ++ num_bins = bin_len / bin_sz; + /* Only In-band bins are useful to user for visualize */ + num_bins >>= 1; + +@@ -658,7 +657,7 @@ int ath11k_spectral_process_fft(struct a + fft_sample->freq2 = __cpu_to_be16(freq); + + ath11k_spectral_parse_fft(fft_sample->data, fft_report->bins, num_bins, +- ab->hw_params.spectral_fft_sz); ++ ab->hw_params.spectral.fft_sz); + + fft_sample->max_exp = ath11k_spectral_get_max_exp(fft_sample->max_index, + search.peak_mag, +@@ -966,7 +965,7 @@ int ath11k_spectral_init(struct ath11k_b + ab->wmi_ab.svc_map)) + return 0; + +- if (!ab->hw_params.spectral_fft_sz) ++ if (!ab->hw_params.spectral.fft_sz) + return 0; + + for (i = 0; i < ab->num_radios; i++) { diff --git a/package/kernel/mac80211/patches/ath11k/0013-ath11k-Introduce-spectral-hw-configurable-param.patch b/package/kernel/mac80211/patches/ath11k/0013-ath11k-Introduce-spectral-hw-configurable-param.patch new file mode 100644 index 000000000..45660c62f --- /dev/null +++ b/package/kernel/mac80211/patches/ath11k/0013-ath11k-Introduce-spectral-hw-configurable-param.patch @@ -0,0 +1,168 @@ +From 1cae9c0009d35cec94ad8e1b06ebcb2d704626bf Mon Sep 17 00:00:00 2001 +From: Karthikeyan Periyasamy +Date: Fri, 24 Sep 2021 16:52:46 +0300 +Subject: [PATCH 013/120] ath11k: Introduce spectral hw configurable param + +Below parameters have been identified as configurable across the platforms. +So to scale the spectral across the platforms, move these parameter +into hw param. + + 1. Maximum FFT bins + 2. Summary report pad size + 3. FFT report header length + +Tested-on: IPQ8074 hw2.0 AHB WLAN.HK.2.4.0.1-01492-QCAHKSWPL_SILICONZ-1 +Tested-on: IPQ6018 hw1.0 AHB WLAN.HK.2.4.0.1-00330-QCAHKSWPL_SILICONZ-1 + +Signed-off-by: Karthikeyan Periyasamy +Signed-off-by: Jouni Malinen +Signed-off-by: Kalle Valo +Link: https://lore.kernel.org/r/20210721180809.90960-3-jouni@codeaurora.org +--- + drivers/net/wireless/ath/ath11k/core.c | 12 +++++++++ + drivers/net/wireless/ath/ath11k/hw.h | 3 +++ + drivers/net/wireless/ath/ath11k/spectral.c | 29 +++++++++++----------- + 3 files changed, 30 insertions(+), 14 deletions(-) + +--- a/drivers/net/wireless/ath/ath11k/core.c ++++ b/drivers/net/wireless/ath/ath11k/core.c +@@ -66,6 +66,9 @@ static const struct ath11k_hw_params ath + * so added pad size as 2 bytes to compensate the BIN size + */ + .fft_pad_sz = 2, ++ .summary_pad_sz = 0, ++ .fft_hdr_len = 16, ++ .max_fft_bins = 512, + }, + + .interface_modes = BIT(NL80211_IFTYPE_STATION) | +@@ -111,6 +114,9 @@ static const struct ath11k_hw_params ath + .spectral = { + .fft_sz = 4, + .fft_pad_sz = 0, ++ .summary_pad_sz = 0, ++ .fft_hdr_len = 16, ++ .max_fft_bins = 512, + }, + + .interface_modes = BIT(NL80211_IFTYPE_STATION) | +@@ -156,6 +162,9 @@ static const struct ath11k_hw_params ath + .spectral = { + .fft_sz = 0, + .fft_pad_sz = 0, ++ .summary_pad_sz = 0, ++ .fft_hdr_len = 0, ++ .max_fft_bins = 0, + }, + + .interface_modes = BIT(NL80211_IFTYPE_STATION) | +@@ -244,6 +253,9 @@ static const struct ath11k_hw_params ath + .spectral = { + .fft_sz = 0, + .fft_pad_sz = 0, ++ .summary_pad_sz = 0, ++ .fft_hdr_len = 0, ++ .max_fft_bins = 0, + }, + + .interface_modes = BIT(NL80211_IFTYPE_STATION) | +--- a/drivers/net/wireless/ath/ath11k/hw.h ++++ b/drivers/net/wireless/ath/ath11k/hw.h +@@ -157,6 +157,9 @@ struct ath11k_hw_params { + struct { + u8 fft_sz; + u8 fft_pad_sz; ++ u8 summary_pad_sz; ++ u8 fft_hdr_len; ++ u16 max_fft_bins; + } spectral; + + u16 interface_modes; +--- a/drivers/net/wireless/ath/ath11k/spectral.c ++++ b/drivers/net/wireless/ath/ath11k/spectral.c +@@ -11,20 +11,20 @@ + #define ATH11K_SPECTRAL_EVENT_TIMEOUT_MS 1 + + #define ATH11K_SPECTRAL_DWORD_SIZE 4 +-#define ATH11K_SPECTRAL_ATH11K_MIN_BINS 64 +-#define ATH11K_SPECTRAL_ATH11K_MIN_IB_BINS 32 +-#define ATH11K_SPECTRAL_ATH11K_MAX_IB_BINS 256 ++#define ATH11K_SPECTRAL_MIN_BINS 64 ++#define ATH11K_SPECTRAL_MIN_IB_BINS (ATH11K_SPECTRAL_MIN_BINS >> 1) ++#define ATH11K_SPECTRAL_MAX_IB_BINS(x) ((x)->hw_params.spectral.max_fft_bins >> 1) + + #define ATH11K_SPECTRAL_SCAN_COUNT_MAX 4095 + + /* Max channel computed by sum of 2g and 5g band channels */ + #define ATH11K_SPECTRAL_TOTAL_CHANNEL 41 + #define ATH11K_SPECTRAL_SAMPLES_PER_CHANNEL 70 +-#define ATH11K_SPECTRAL_PER_SAMPLE_SIZE (sizeof(struct fft_sample_ath11k) + \ +- ATH11K_SPECTRAL_ATH11K_MAX_IB_BINS) ++#define ATH11K_SPECTRAL_PER_SAMPLE_SIZE(x) (sizeof(struct fft_sample_ath11k) + \ ++ ATH11K_SPECTRAL_MAX_IB_BINS(x)) + #define ATH11K_SPECTRAL_TOTAL_SAMPLE (ATH11K_SPECTRAL_TOTAL_CHANNEL * \ + ATH11K_SPECTRAL_SAMPLES_PER_CHANNEL) +-#define ATH11K_SPECTRAL_SUB_BUFF_SIZE ATH11K_SPECTRAL_PER_SAMPLE_SIZE ++#define ATH11K_SPECTRAL_SUB_BUFF_SIZE(x) ATH11K_SPECTRAL_PER_SAMPLE_SIZE(x) + #define ATH11K_SPECTRAL_NUM_SUB_BUF ATH11K_SPECTRAL_TOTAL_SAMPLE + + #define ATH11K_SPECTRAL_20MHZ 20 +@@ -446,8 +446,8 @@ static ssize_t ath11k_write_file_spectra + if (kstrtoul(buf, 0, &val)) + return -EINVAL; + +- if (val < ATH11K_SPECTRAL_ATH11K_MIN_BINS || +- val > SPECTRAL_ATH11K_MAX_NUM_BINS) ++ if (val < ATH11K_SPECTRAL_MIN_BINS || ++ val > ar->ab->hw_params.spectral.max_fft_bins) + return -EINVAL; + + if (!is_power_of_2(val)) +@@ -598,7 +598,7 @@ int ath11k_spectral_process_fft(struct a + tlv_len = FIELD_GET(SPECTRAL_TLV_HDR_LEN, __le32_to_cpu(tlv->header)); + /* convert Dword into bytes */ + tlv_len *= ATH11K_SPECTRAL_DWORD_SIZE; +- bin_len = tlv_len - (sizeof(*fft_report) - sizeof(*tlv)); ++ bin_len = tlv_len - ab->hw_params.spectral.fft_hdr_len; + + if (data_len < (bin_len + sizeof(*fft_report))) { + ath11k_warn(ab, "mismatch in expected bin len %d and data len %d\n", +@@ -611,8 +611,8 @@ int ath11k_spectral_process_fft(struct a + /* Only In-band bins are useful to user for visualize */ + num_bins >>= 1; + +- if (num_bins < ATH11K_SPECTRAL_ATH11K_MIN_IB_BINS || +- num_bins > ATH11K_SPECTRAL_ATH11K_MAX_IB_BINS || ++ if (num_bins < ATH11K_SPECTRAL_MIN_IB_BINS || ++ num_bins > ATH11K_SPECTRAL_MAX_IB_BINS(ab) || + !is_power_of_2(num_bins)) { + ath11k_warn(ab, "Invalid num of bins %d\n", num_bins); + return -EINVAL; +@@ -693,7 +693,7 @@ static int ath11k_spectral_process_data( + goto unlock; + } + +- sample_sz = sizeof(*fft_sample) + ATH11K_SPECTRAL_ATH11K_MAX_IB_BINS; ++ sample_sz = sizeof(*fft_sample) + ATH11K_SPECTRAL_MAX_IB_BINS(ab); + fft_sample = kmalloc(sample_sz, GFP_ATOMIC); + if (!fft_sample) { + ret = -ENOBUFS; +@@ -741,7 +741,8 @@ static int ath11k_spectral_process_data( + * is 4 DWORD size (16 bytes). + * Need to remove this workaround once HW bug fixed + */ +- tlv_len = sizeof(*summary) - sizeof(*tlv); ++ tlv_len = sizeof(*summary) - sizeof(*tlv) + ++ ab->hw_params.spectral.summary_pad_sz; + + if (tlv_len < (sizeof(*summary) - sizeof(*tlv))) { + ath11k_warn(ab, "failed to parse spectral summary at bytes %d tlv_len:%d\n", +@@ -904,7 +905,7 @@ static inline int ath11k_spectral_debug_ + + ar->spectral.rfs_scan = relay_open("spectral_scan", + ar->debug.debugfs_pdev, +- ATH11K_SPECTRAL_SUB_BUFF_SIZE, ++ ATH11K_SPECTRAL_SUB_BUFF_SIZE(ar->ab), + ATH11K_SPECTRAL_NUM_SUB_BUF, + &rfs_scan_cb, NULL); + if (!ar->spectral.rfs_scan) { diff --git a/package/kernel/mac80211/patches/ath11k/0014-ath11k-Fix-the-spectral-minimum-FFT-bin-count.patch b/package/kernel/mac80211/patches/ath11k/0014-ath11k-Fix-the-spectral-minimum-FFT-bin-count.patch new file mode 100644 index 000000000..d38b2fd31 --- /dev/null +++ b/package/kernel/mac80211/patches/ath11k/0014-ath11k-Fix-the-spectral-minimum-FFT-bin-count.patch @@ -0,0 +1,33 @@ +From 6dfd20c8a6cd1fcf2c68d86c9d678f42535f6ade Mon Sep 17 00:00:00 2001 +From: Karthikeyan Periyasamy +Date: Fri, 24 Sep 2021 16:52:46 +0300 +Subject: [PATCH 014/120] ath11k: Fix the spectral minimum FFT bin count + +User was not able to configure the spectral with the FFT bin count 32. +In all supported platforms, the expected minimum FFT bin count is 32 but +it was wrongly defined as 64. This restrict the user to not configure +down to the actually supported minimum FFT bin count. So update the +minimum FFT bin count as 32. + +Tested-on: IPQ8074 hw2.0 AHB WLAN.HK.2.4.0.1-01492-QCAHKSWPL_SILICONZ-1 +Tested-on: IPQ6018 hw1.0 AHB WLAN.HK.2.4.0.1-00330-QCAHKSWPL_SILICONZ-1 + +Signed-off-by: Karthikeyan Periyasamy +Signed-off-by: Jouni Malinen +Signed-off-by: Kalle Valo +Link: https://lore.kernel.org/r/20210721180809.90960-4-jouni@codeaurora.org +--- + drivers/net/wireless/ath/ath11k/spectral.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +--- a/drivers/net/wireless/ath/ath11k/spectral.c ++++ b/drivers/net/wireless/ath/ath11k/spectral.c +@@ -11,7 +11,7 @@ + #define ATH11K_SPECTRAL_EVENT_TIMEOUT_MS 1 + + #define ATH11K_SPECTRAL_DWORD_SIZE 4 +-#define ATH11K_SPECTRAL_MIN_BINS 64 ++#define ATH11K_SPECTRAL_MIN_BINS 32 + #define ATH11K_SPECTRAL_MIN_IB_BINS (ATH11K_SPECTRAL_MIN_BINS >> 1) + #define ATH11K_SPECTRAL_MAX_IB_BINS(x) ((x)->hw_params.spectral.max_fft_bins >> 1) + diff --git a/package/kernel/mac80211/patches/ath11k/0015-ath11k-Add-spectral-scan-support-for-QCN9074.patch b/package/kernel/mac80211/patches/ath11k/0015-ath11k-Add-spectral-scan-support-for-QCN9074.patch new file mode 100644 index 000000000..24de4fc78 --- /dev/null +++ b/package/kernel/mac80211/patches/ath11k/0015-ath11k-Add-spectral-scan-support-for-QCN9074.patch @@ -0,0 +1,36 @@ +From b72e86c07e9881d249fbb7511060692f3fb6b687 Mon Sep 17 00:00:00 2001 +From: Karthikeyan Periyasamy +Date: Fri, 24 Sep 2021 16:52:46 +0300 +Subject: [PATCH 015/120] ath11k: Add spectral scan support for QCN9074 + +Populate the below hw parameters as per the QCN9074 support + 1. FFT bin size as two bytes + 2. Maximum FFT bin count as 1024 + 3. Summary report pad size as 16 + 4. FFT report header length as 24 + +Tested-on: QCN9074 hw1.0 PCI WLAN.HK.2.4.0.1-01492-QCAHKSWPL_SILICONZ-1 + +Signed-off-by: Karthikeyan Periyasamy +Signed-off-by: Jouni Malinen +Signed-off-by: Kalle Valo +Link: https://lore.kernel.org/r/20210721180809.90960-5-jouni@codeaurora.org +--- + drivers/net/wireless/ath/ath11k/core.c | 5 ++++- + 1 file changed, 4 insertions(+), 1 deletion(-) + +--- a/drivers/net/wireless/ath/ath11k/core.c ++++ b/drivers/net/wireless/ath/ath11k/core.c +@@ -206,8 +206,11 @@ static const struct ath11k_hw_params ath + .tcl_0_only = false, + + .spectral = { +- .fft_sz = 0, ++ .fft_sz = 2, + .fft_pad_sz = 0, ++ .summary_pad_sz = 16, ++ .fft_hdr_len = 24, ++ .max_fft_bins = 1024, + }, + + .interface_modes = BIT(NL80211_IFTYPE_STATION) | diff --git a/package/kernel/mac80211/patches/ath11k/0016-ath11k-Wstringop-overread-warning.patch b/package/kernel/mac80211/patches/ath11k/0016-ath11k-Wstringop-overread-warning.patch new file mode 100644 index 000000000..e1dbe606d --- /dev/null +++ b/package/kernel/mac80211/patches/ath11k/0016-ath11k-Wstringop-overread-warning.patch @@ -0,0 +1,44 @@ +From eb19efed836a51ee30a602abe2dd21a97c47bbcc Mon Sep 17 00:00:00 2001 +From: Arnd Bergmann +Date: Fri, 24 Sep 2021 16:52:52 +0300 +Subject: [PATCH 016/120] ath11k: Wstringop-overread warning + +gcc-11 with the kernel address sanitizer prints a warning for this +driver: + +In function 'ath11k_peer_assoc_h_vht', + inlined from 'ath11k_peer_assoc_prepare' at drivers/net/wireless/ath/ath11k/mac.c:1632:2: +drivers/net/wireless/ath/ath11k/mac.c:1164:13: error: 'ath11k_peer_assoc_h_vht_masked' reading 16 bytes from a region of size 4 [-Werror=stringop-overread] + 1164 | if (ath11k_peer_assoc_h_vht_masked(vht_mcs_mask)) + | ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +drivers/net/wireless/ath/ath11k/mac.c: In function 'ath11k_peer_assoc_prepare': +drivers/net/wireless/ath/ath11k/mac.c:1164:13: note: referencing argument 1 of type 'const u16 *' {aka 'const short unsigned int *'} +drivers/net/wireless/ath/ath11k/mac.c:969:1: note: in a call to function 'ath11k_peer_assoc_h_vht_masked' + 969 | ath11k_peer_assoc_h_vht_masked(const u16 vht_mcs_mask[NL80211_VHT_NSS_MAX]) + | ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +According to analysis from gcc developers, this is a glitch in the +way gcc tracks the size of struct members. This should really get +fixed in gcc, but it's also easy to work around this instance +by changing the function prototype to no include the length of +the array. + +Link: https://gcc.gnu.org/bugzilla/show_bug.cgi?id=99673 +Signed-off-by: Arnd Bergmann +Signed-off-by: Kalle Valo +Link: https://lore.kernel.org/r/20210322160253.4032422-5-arnd@kernel.org +--- + drivers/net/wireless/ath/ath11k/mac.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +--- a/drivers/net/wireless/ath/ath11k/mac.c ++++ b/drivers/net/wireless/ath/ath11k/mac.c +@@ -1401,7 +1401,7 @@ ath11k_peer_assoc_h_ht_masked(const u8 h + } + + static bool +-ath11k_peer_assoc_h_vht_masked(const u16 vht_mcs_mask[NL80211_VHT_NSS_MAX]) ++ath11k_peer_assoc_h_vht_masked(const u16 vht_mcs_mask[]) + { + int nss; + diff --git a/package/kernel/mac80211/patches/ath11k/0017-ath11k-use-hw_params-to-access-board_size-and-cal_of.patch b/package/kernel/mac80211/patches/ath11k/0017-ath11k-use-hw_params-to-access-board_size-and-cal_of.patch new file mode 100644 index 000000000..865450a08 --- /dev/null +++ b/package/kernel/mac80211/patches/ath11k/0017-ath11k-use-hw_params-to-access-board_size-and-cal_of.patch @@ -0,0 +1,114 @@ +From c72aa32d6d1c04fa83d4c0e6849e4e60d9d39ae4 Mon Sep 17 00:00:00 2001 +From: Anilkumar Kolli +Date: Tue, 28 Sep 2021 12:05:39 +0300 +Subject: [PATCH 017/120] ath11k: use hw_params to access board_size and + cal_offset + +Reuse board_size from hw_params, add cal_offset to hw params. +This patch is clean up only, there is no change in functionality. + +cal_size was unused, so remove that. + +Tested-on: IPQ8074 hw2.0 AHB WLAN.HK.2.4.0.1-00009-QCAHKSWPL_SILICONZ-1 +Tested-on: QCN9074 hw1.0 PCI WLAN.HK.2.4.0.1-01838-QCAHKSWPL_SILICONZ-1 + +Signed-off-by: Anilkumar Kolli +Signed-off-by: Jouni Malinen +Signed-off-by: Kalle Valo +Link: https://lore.kernel.org/r/20210721201927.100369-2-jouni@codeaurora.org +--- + drivers/net/wireless/ath/ath11k/core.c | 10 +++++----- + drivers/net/wireless/ath/ath11k/hw.h | 2 +- + drivers/net/wireless/ath/ath11k/qmi.c | 4 ++-- + drivers/net/wireless/ath/ath11k/qmi.h | 2 -- + 4 files changed, 8 insertions(+), 10 deletions(-) + +--- a/drivers/net/wireless/ath/ath11k/core.c ++++ b/drivers/net/wireless/ath/ath11k/core.c +@@ -37,7 +37,7 @@ static const struct ath11k_hw_params ath + .fw = { + .dir = "IPQ8074/hw2.0", + .board_size = 256 * 1024, +- .cal_size = 256 * 1024, ++ .cal_offset = 128 * 1024, + }, + .max_radios = 3, + .bdf_addr = 0x4B0C0000, +@@ -88,7 +88,7 @@ static const struct ath11k_hw_params ath + .fw = { + .dir = "IPQ6018/hw1.0", + .board_size = 256 * 1024, +- .cal_size = 256 * 1024, ++ .cal_offset = 128 * 1024, + }, + .max_radios = 2, + .bdf_addr = 0x4ABC0000, +@@ -136,7 +136,7 @@ static const struct ath11k_hw_params ath + .fw = { + .dir = "QCA6390/hw2.0", + .board_size = 256 * 1024, +- .cal_size = 256 * 1024, ++ .cal_offset = 128 * 1024, + }, + .max_radios = 3, + .bdf_addr = 0x4B0C0000, +@@ -183,7 +183,7 @@ static const struct ath11k_hw_params ath + .fw = { + .dir = "QCN9074/hw1.0", + .board_size = 256 * 1024, +- .cal_size = 256 * 1024, ++ .cal_offset = 128 * 1024, + }, + .max_radios = 1, + .single_pdev_only = false, +@@ -230,7 +230,7 @@ static const struct ath11k_hw_params ath + .fw = { + .dir = "WCN6855/hw2.0", + .board_size = 256 * 1024, +- .cal_size = 256 * 1024, ++ .cal_offset = 128 * 1024, + }, + .max_radios = 3, + .bdf_addr = 0x4B0C0000, +--- a/drivers/net/wireless/ath/ath11k/hw.h ++++ b/drivers/net/wireless/ath/ath11k/hw.h +@@ -128,7 +128,7 @@ struct ath11k_hw_params { + struct { + const char *dir; + size_t board_size; +- size_t cal_size; ++ size_t cal_offset; + } fw; + + const struct ath11k_hw_ops *hw_ops; +--- a/drivers/net/wireless/ath/ath11k/qmi.c ++++ b/drivers/net/wireless/ath/ath11k/qmi.c +@@ -1953,7 +1953,7 @@ ath11k_qmi_prepare_bdf_download(struct a + fw_size = min_t(u32, ab->hw_params.fw.board_size, + fw_entry->size); + +- memcpy_toio(bdf_addr + ATH11K_QMI_CALDATA_OFFSET, ++ memcpy_toio(bdf_addr + ab->hw_params.fw.cal_offset, + fw_entry->data, fw_size); + + release_firmware(fw_entry); +@@ -1979,7 +1979,7 @@ static int ath11k_qmi_load_bdf_fixed_add + return -ENOMEM; + memset(&resp, 0, sizeof(resp)); + +- bdf_addr = ioremap(ab->hw_params.bdf_addr, ATH11K_QMI_BDF_MAX_SIZE); ++ bdf_addr = ioremap(ab->hw_params.bdf_addr, ab->hw_params.fw.board_size); + if (!bdf_addr) { + ath11k_warn(ab, "failed ioremap for board file\n"); + ret = -EIO; +--- a/drivers/net/wireless/ath/ath11k/qmi.h ++++ b/drivers/net/wireless/ath/ath11k/qmi.h +@@ -13,8 +13,6 @@ + #define ATH11K_QMI_WLANFW_TIMEOUT_MS 5000 + #define ATH11K_QMI_MAX_BDF_FILE_NAME_SIZE 64 + #define ATH11K_QMI_CALDB_ADDRESS 0x4BA00000 +-#define ATH11K_QMI_BDF_MAX_SIZE (256 * 1024) +-#define ATH11K_QMI_CALDATA_OFFSET (128 * 1024) + #define ATH11K_QMI_WLANFW_MAX_BUILD_ID_LEN_V01 128 + #define ATH11K_QMI_WLFW_SERVICE_ID_V01 0x45 + #define ATH11K_QMI_WLFW_SERVICE_VERS_V01 0x01 diff --git a/package/kernel/mac80211/patches/ath11k/0018-ath11k-clean-up-BDF-download-functions.patch b/package/kernel/mac80211/patches/ath11k/0018-ath11k-clean-up-BDF-download-functions.patch new file mode 100644 index 000000000..387f4331d --- /dev/null +++ b/package/kernel/mac80211/patches/ath11k/0018-ath11k-clean-up-BDF-download-functions.patch @@ -0,0 +1,357 @@ +From 336e7b53c82fc74d261024773a0fab43623a94fb Mon Sep 17 00:00:00 2001 +From: Anilkumar Kolli +Date: Tue, 28 Sep 2021 12:05:39 +0300 +Subject: [PATCH 018/120] ath11k: clean up BDF download functions + +In current code, AHB/PCI uses two separate functions to download +BDF file. Refactor code and make a common function to send QMI BDF +download request for both AHB and PCI devices. This patch has no +functional change. + +Tested-on: IPQ8074 hw2.0 AHB WLAN.HK.2.4.0.1-00009-QCAHKSWPL_SILICONZ-1 +Tested-on: QCN9074 hw1.0 PCI WLAN.HK.2.4.0.1-01838-QCAHKSWPL_SILICONZ-1 + +Signed-off-by: Anilkumar Kolli +Signed-off-by: Jouni Malinen +Signed-off-by: Kalle Valo +Link: https://lore.kernel.org/r/20210721201927.100369-3-jouni@codeaurora.org +--- + drivers/net/wireless/ath/ath11k/qmi.c | 248 +++++++++++--------------- + 1 file changed, 101 insertions(+), 147 deletions(-) + +--- a/drivers/net/wireless/ath/ath11k/qmi.c ++++ b/drivers/net/wireless/ath/ath11k/qmi.c +@@ -1917,98 +1917,72 @@ out: + return ret; + } + +-static int +-ath11k_qmi_prepare_bdf_download(struct ath11k_base *ab, int type, +- struct qmi_wlanfw_bdf_download_req_msg_v01 *req, +- void __iomem *bdf_addr) +-{ +- const struct firmware *fw_entry; +- struct ath11k_board_data bd; +- u32 fw_size; +- int ret; +- +- switch (type) { +- case ATH11K_QMI_FILE_TYPE_BDF_GOLDEN: +- memset(&bd, 0, sizeof(bd)); +- +- ret = ath11k_core_fetch_bdf(ab, &bd); +- if (ret) { +- ath11k_warn(ab, "failed to load board file: %d\n", ret); +- return ret; +- } +- +- fw_size = min_t(u32, ab->hw_params.fw.board_size, bd.len); +- memcpy_toio(bdf_addr, bd.data, fw_size); +- ath11k_core_free_bdf(ab, &bd); +- break; +- case ATH11K_QMI_FILE_TYPE_CALDATA: +- fw_entry = ath11k_core_firmware_request(ab, ATH11K_DEFAULT_CAL_FILE); +- if (IS_ERR(fw_entry)) { +- ret = PTR_ERR(fw_entry); +- ath11k_warn(ab, "failed to load %s: %d\n", +- ATH11K_DEFAULT_CAL_FILE, ret); +- return ret; +- } +- +- fw_size = min_t(u32, ab->hw_params.fw.board_size, +- fw_entry->size); +- +- memcpy_toio(bdf_addr + ab->hw_params.fw.cal_offset, +- fw_entry->data, fw_size); +- +- release_firmware(fw_entry); +- break; +- default: +- return -EINVAL; +- } +- +- req->total_size = fw_size; +- return 0; +-} +- +-static int ath11k_qmi_load_bdf_fixed_addr(struct ath11k_base *ab) ++static int ath11k_qmi_load_file_target_mem(struct ath11k_base *ab, ++ const u8 *data, u32 len, u8 type) + { + struct qmi_wlanfw_bdf_download_req_msg_v01 *req; + struct qmi_wlanfw_bdf_download_resp_msg_v01 resp; + struct qmi_txn txn = {}; ++ const u8 *temp = data; + void __iomem *bdf_addr = NULL; +- int type, ret; ++ int ret; ++ u32 remaining = len; + + req = kzalloc(sizeof(*req), GFP_KERNEL); + if (!req) + return -ENOMEM; ++ + memset(&resp, 0, sizeof(resp)); + +- bdf_addr = ioremap(ab->hw_params.bdf_addr, ab->hw_params.fw.board_size); +- if (!bdf_addr) { +- ath11k_warn(ab, "failed ioremap for board file\n"); +- ret = -EIO; +- goto out; ++ if (ab->bus_params.fixed_bdf_addr) { ++ bdf_addr = ioremap(ab->hw_params.bdf_addr, ab->hw_params.fw.board_size); ++ if (!bdf_addr) { ++ ath11k_warn(ab, "qmi ioremap error for bdf_addr\n"); ++ ret = -EIO; ++ goto err_free_req; ++ } + } + +- for (type = 0; type < ATH11K_QMI_MAX_FILE_TYPE; type++) { ++ while (remaining) { + req->valid = 1; + req->file_id_valid = 1; + req->file_id = ab->qmi.target.board_id; + req->total_size_valid = 1; ++ req->total_size = remaining; + req->seg_id_valid = 1; +- req->seg_id = type; +- req->data_valid = 0; +- req->data_len = ATH11K_QMI_MAX_BDF_FILE_NAME_SIZE; +- req->bdf_type = 0; +- req->bdf_type_valid = 0; ++ req->data_valid = 1; ++ req->bdf_type = type; ++ req->bdf_type_valid = 1; + req->end_valid = 1; +- req->end = 1; ++ req->end = 0; + +- ret = ath11k_qmi_prepare_bdf_download(ab, type, req, bdf_addr); +- if (ret < 0) +- goto out_qmi_bdf; ++ if (remaining > QMI_WLANFW_MAX_DATA_SIZE_V01) { ++ req->data_len = QMI_WLANFW_MAX_DATA_SIZE_V01; ++ } else { ++ req->data_len = remaining; ++ req->end = 1; ++ } ++ ++ if (ab->bus_params.fixed_bdf_addr) { ++ req->data_valid = 0; ++ req->end = 1; ++ req->data_len = ATH11K_QMI_MAX_BDF_FILE_NAME_SIZE; ++ } else { ++ memcpy(req->data, temp, req->data_len); ++ } ++ ++ if (ab->bus_params.fixed_bdf_addr) { ++ if (type == ATH11K_QMI_FILE_TYPE_CALDATA) ++ bdf_addr += ab->hw_params.fw.cal_offset; ++ ++ memcpy_toio(bdf_addr, temp, len); ++ } + + ret = qmi_txn_init(&ab->qmi.handle, &txn, + qmi_wlanfw_bdf_download_resp_msg_v01_ei, + &resp); + if (ret < 0) +- goto out_qmi_bdf; ++ goto err_iounmap; + + ath11k_dbg(ab, ATH11K_DBG_QMI, "qmi bdf download req fixed addr type %d\n", + type); +@@ -2019,54 +1993,59 @@ static int ath11k_qmi_load_bdf_fixed_add + qmi_wlanfw_bdf_download_req_msg_v01_ei, req); + if (ret < 0) { + qmi_txn_cancel(&txn); +- goto out_qmi_bdf; ++ goto err_iounmap; + } + + ret = qmi_txn_wait(&txn, msecs_to_jiffies(ATH11K_QMI_WLANFW_TIMEOUT_MS)); +- if (ret < 0) +- goto out_qmi_bdf; ++ if (ret < 0) { ++ ath11k_warn(ab, "failed to wait board file download request: %d\n", ++ ret); ++ goto err_iounmap; ++ } + + if (resp.resp.result != QMI_RESULT_SUCCESS_V01) { + ath11k_warn(ab, "board file download request failed: %d %d\n", + resp.resp.result, resp.resp.error); + ret = -EINVAL; +- goto out_qmi_bdf; ++ goto err_iounmap; ++ } ++ ++ if (ab->bus_params.fixed_bdf_addr) { ++ remaining = 0; ++ } else { ++ remaining -= req->data_len; ++ temp += req->data_len; ++ req->seg_id++; ++ ath11k_dbg(ab, ATH11K_DBG_QMI, "qmi bdf download request remaining %i\n", ++ remaining); + } + } + +-out_qmi_bdf: +- iounmap(bdf_addr); +-out: ++err_iounmap: ++ if (ab->bus_params.fixed_bdf_addr) ++ iounmap(bdf_addr); ++ ++err_free_req: + kfree(req); ++ + return ret; + } + + static int ath11k_qmi_load_bdf_qmi(struct ath11k_base *ab) + { +- struct qmi_wlanfw_bdf_download_req_msg_v01 *req; +- struct qmi_wlanfw_bdf_download_resp_msg_v01 resp; ++ char filename[ATH11K_QMI_MAX_BDF_FILE_NAME_SIZE]; ++ const struct firmware *fw_entry; + struct ath11k_board_data bd; +- unsigned int remaining; +- struct qmi_txn txn = {}; +- int ret; +- const u8 *temp; +- int bdf_type; +- +- req = kzalloc(sizeof(*req), GFP_KERNEL); +- if (!req) +- return -ENOMEM; +- memset(&resp, 0, sizeof(resp)); ++ u32 fw_size, file_type; ++ int ret = 0, bdf_type; + + memset(&bd, 0, sizeof(bd)); + ret = ath11k_core_fetch_bdf(ab, &bd); + if (ret) { +- ath11k_warn(ab, "failed to fetch board file: %d\n", ret); ++ ath11k_warn(ab, "qmi failed to fetch board file: %d\n", ret); + goto out; + } + +- temp = bd.data; +- remaining = bd.len; +- + if (bd.len >= SELFMAG && memcmp(bd.data, ELFMAG, SELFMAG) == 0) + bdf_type = ATH11K_QMI_BDF_TYPE_ELF; + else +@@ -2074,67 +2053,45 @@ static int ath11k_qmi_load_bdf_qmi(struc + + ath11k_dbg(ab, ATH11K_DBG_QMI, "qmi bdf_type %d\n", bdf_type); + +- while (remaining) { +- req->valid = 1; +- req->file_id_valid = 1; +- req->file_id = ab->qmi.target.board_id; +- req->total_size_valid = 1; +- req->total_size = bd.len; +- req->seg_id_valid = 1; +- req->data_valid = 1; +- req->data_len = ATH11K_QMI_MAX_BDF_FILE_NAME_SIZE; +- req->bdf_type = bdf_type; +- req->bdf_type_valid = 1; +- req->end_valid = 1; +- req->end = 0; +- +- if (remaining > QMI_WLANFW_MAX_DATA_SIZE_V01) { +- req->data_len = QMI_WLANFW_MAX_DATA_SIZE_V01; +- } else { +- req->data_len = remaining; +- req->end = 1; +- } +- +- memcpy(req->data, temp, req->data_len); +- +- ret = qmi_txn_init(&ab->qmi.handle, &txn, +- qmi_wlanfw_bdf_download_resp_msg_v01_ei, +- &resp); +- if (ret < 0) +- goto out_qmi_bdf; ++ fw_size = bd.len; ++ fw_size = min_t(u32, ab->hw_params.fw.board_size, bd.len); + +- ath11k_dbg(ab, ATH11K_DBG_QMI, "qmi bdf download request remaining %i\n", +- remaining); ++ ret = ath11k_qmi_load_file_target_mem(ab, bd.data, fw_size, bdf_type); ++ if (ret < 0) { ++ ath11k_warn(ab, "qmi failed to load bdf file\n"); ++ goto out; ++ } + +- ret = qmi_send_request(&ab->qmi.handle, NULL, &txn, +- QMI_WLANFW_BDF_DOWNLOAD_REQ_V01, +- QMI_WLANFW_BDF_DOWNLOAD_REQ_MSG_V01_MAX_LEN, +- qmi_wlanfw_bdf_download_req_msg_v01_ei, req); +- if (ret < 0) { +- qmi_txn_cancel(&txn); +- goto out_qmi_bdf; +- } ++ /* QCA6390 does not support cal data file, skip it */ ++ if (bdf_type == ATH11K_QMI_BDF_TYPE_ELF) ++ goto out; + +- ret = qmi_txn_wait(&txn, msecs_to_jiffies(ATH11K_QMI_WLANFW_TIMEOUT_MS)); +- if (ret < 0) +- goto out_qmi_bdf; ++ file_type = ATH11K_QMI_FILE_TYPE_CALDATA; ++ fw_entry = ath11k_core_firmware_request(ab, ATH11K_DEFAULT_CAL_FILE); ++ if (IS_ERR(fw_entry)) { ++ ret = PTR_ERR(fw_entry); ++ ath11k_warn(ab, ++ "qmi failed to load CAL data file:%s\n", ++ filename); ++ goto out; ++ } + +- if (resp.resp.result != QMI_RESULT_SUCCESS_V01) { +- ath11k_warn(ab, "bdf download request failed: %d %d\n", +- resp.resp.result, resp.resp.error); +- ret = resp.resp.result; +- goto out_qmi_bdf; +- } +- remaining -= req->data_len; +- temp += req->data_len; +- req->seg_id++; ++ fw_size = min_t(u32, ab->hw_params.fw.board_size, fw_entry->size); ++ ret = ath11k_qmi_load_file_target_mem(ab, fw_entry->data, fw_size, file_type); ++ if (ret < 0) { ++ ath11k_warn(ab, "qmi failed to load caldata\n"); ++ goto out_qmi_cal; + } + +-out_qmi_bdf: +- ath11k_core_free_bdf(ab, &bd); ++ ath11k_dbg(ab, ATH11K_DBG_QMI, "qmi caldata downloaded: type: %u\n", ++ file_type); + ++out_qmi_cal: ++ release_firmware(fw_entry); + out: +- kfree(req); ++ ath11k_core_free_bdf(ab, &bd); ++ ath11k_dbg(ab, ATH11K_DBG_QMI, "qmi BDF download sequence completed\n"); ++ + return ret; + } + +@@ -2519,10 +2476,7 @@ static int ath11k_qmi_event_load_bdf(str + return ret; + } + +- if (ab->bus_params.fixed_bdf_addr) +- ret = ath11k_qmi_load_bdf_fixed_addr(ab); +- else +- ret = ath11k_qmi_load_bdf_qmi(ab); ++ ret = ath11k_qmi_load_bdf_qmi(ab); + if (ret < 0) { + ath11k_warn(ab, "failed to load board data file: %d\n", ret); + return ret; diff --git a/package/kernel/mac80211/patches/ath11k/0019-ath11k-add-caldata-file-for-multiple-radios.patch b/package/kernel/mac80211/patches/ath11k/0019-ath11k-add-caldata-file-for-multiple-radios.patch new file mode 100644 index 000000000..a545ed4d9 --- /dev/null +++ b/package/kernel/mac80211/patches/ath11k/0019-ath11k-add-caldata-file-for-multiple-radios.patch @@ -0,0 +1,68 @@ +From e82dfe7b5608592c270cc69100cb4322069f949d Mon Sep 17 00:00:00 2001 +From: Anilkumar Kolli +Date: Tue, 28 Sep 2021 12:05:39 +0300 +Subject: [PATCH 019/120] ath11k: add caldata file for multiple radios + +If multiple PCI cards are attached, each needs its own caldata file. + +Added new Caldata file name, +PCI Bus: + cal-pci-0001:01:00.0.bin + cal-pci-0000:01:00.0.bin +AHB Bus: + cal-ahb-c000000.wifi1.bin + +Tested-on: IPQ8074 hw2.0 AHB WLAN.HK.2.4.0.1-00009-QCAHKSWPL_SILICONZ-1 +Tested-on: QCN9074 hw1.0 PCI WLAN.HK.2.4.0.1-01838-QCAHKSWPL_SILICONZ-1 + +Signed-off-by: Anilkumar Kolli +Signed-off-by: Jouni Malinen +Signed-off-by: Kalle Valo +Link: https://lore.kernel.org/r/20210721201927.100369-4-jouni@codeaurora.org +--- + drivers/net/wireless/ath/ath11k/qmi.c | 13 +++++++++++-- + 1 file changed, 11 insertions(+), 2 deletions(-) + +--- a/drivers/net/wireless/ath/ath11k/qmi.c ++++ b/drivers/net/wireless/ath/ath11k/qmi.c +@@ -2033,6 +2033,7 @@ err_free_req: + + static int ath11k_qmi_load_bdf_qmi(struct ath11k_base *ab) + { ++ struct device *dev = ab->dev; + char filename[ATH11K_QMI_MAX_BDF_FILE_NAME_SIZE]; + const struct firmware *fw_entry; + struct ath11k_board_data bd; +@@ -2067,6 +2068,14 @@ static int ath11k_qmi_load_bdf_qmi(struc + goto out; + + file_type = ATH11K_QMI_FILE_TYPE_CALDATA; ++ ++ /* cal--.bin */ ++ snprintf(filename, sizeof(filename), "cal-%s-%s.bin", ++ ath11k_bus_str(ab->hif.bus), dev_name(dev)); ++ fw_entry = ath11k_core_firmware_request(ab, filename); ++ if (!IS_ERR(fw_entry)) ++ goto success; ++ + fw_entry = ath11k_core_firmware_request(ab, ATH11K_DEFAULT_CAL_FILE); + if (IS_ERR(fw_entry)) { + ret = PTR_ERR(fw_entry); +@@ -2076,6 +2085,7 @@ static int ath11k_qmi_load_bdf_qmi(struc + goto out; + } + ++success: + fw_size = min_t(u32, ab->hw_params.fw.board_size, fw_entry->size); + ret = ath11k_qmi_load_file_target_mem(ab, fw_entry->data, fw_size, file_type); + if (ret < 0) { +@@ -2083,8 +2093,7 @@ static int ath11k_qmi_load_bdf_qmi(struc + goto out_qmi_cal; + } + +- ath11k_dbg(ab, ATH11K_DBG_QMI, "qmi caldata downloaded: type: %u\n", +- file_type); ++ ath11k_dbg(ab, ATH11K_DBG_QMI, "qmi caldata type: %u\n", file_type); + + out_qmi_cal: + release_firmware(fw_entry); diff --git a/package/kernel/mac80211/patches/ath11k/0020-ath11k-add-caldata-download-support-from-EEPROM.patch b/package/kernel/mac80211/patches/ath11k/0020-ath11k-add-caldata-download-support-from-EEPROM.patch new file mode 100644 index 000000000..a925a87e7 --- /dev/null +++ b/package/kernel/mac80211/patches/ath11k/0020-ath11k-add-caldata-download-support-from-EEPROM.patch @@ -0,0 +1,282 @@ +From 4ba3b05ebd0c3e98c7dd8c7ee03aed9d80299b79 Mon Sep 17 00:00:00 2001 +From: Anilkumar Kolli +Date: Tue, 28 Sep 2021 12:05:39 +0300 +Subject: [PATCH 020/120] ath11k: add caldata download support from EEPROM + +Firmware updates EEPROM support capability in QMI FW caps, send QMI BDF +download request message with file type EEPROM, to get caldata download +from EEPROM. Firmware takes more time to update cal data from EEPROM, so +increase QMI timeout. + +Tested-on: QCN9074 hw1.0 PCI WLAN.HK.2.4.0.1-01838-QCAHKSWPL_SILICONZ-1 + +Signed-off-by: Anilkumar Kolli +Signed-off-by: Jouni Malinen +Signed-off-by: Kalle Valo +Link: https://lore.kernel.org/r/20210721201927.100369-5-jouni@codeaurora.org +--- + drivers/net/wireless/ath/ath11k/qmi.c | 139 +++++++++++++++++++++----- + drivers/net/wireless/ath/ath11k/qmi.h | 16 ++- + 2 files changed, 127 insertions(+), 28 deletions(-) + +--- a/drivers/net/wireless/ath/ath11k/qmi.c ++++ b/drivers/net/wireless/ath/ath11k/qmi.c +@@ -951,6 +951,78 @@ static struct qmi_elem_info qmi_wlanfw_c + num_macs), + }, + { ++ .data_type = QMI_OPT_FLAG, ++ .elem_len = 1, ++ .elem_size = sizeof(u8), ++ .array_type = NO_ARRAY, ++ .tlv_type = 0x16, ++ .offset = offsetof(struct qmi_wlanfw_cap_resp_msg_v01, ++ voltage_mv_valid), ++ }, ++ { ++ .data_type = QMI_UNSIGNED_4_BYTE, ++ .elem_len = 1, ++ .elem_size = sizeof(u32), ++ .array_type = NO_ARRAY, ++ .tlv_type = 0x16, ++ .offset = offsetof(struct qmi_wlanfw_cap_resp_msg_v01, ++ voltage_mv), ++ }, ++ { ++ .data_type = QMI_OPT_FLAG, ++ .elem_len = 1, ++ .elem_size = sizeof(u8), ++ .array_type = NO_ARRAY, ++ .tlv_type = 0x17, ++ .offset = offsetof(struct qmi_wlanfw_cap_resp_msg_v01, ++ time_freq_hz_valid), ++ }, ++ { ++ .data_type = QMI_UNSIGNED_4_BYTE, ++ .elem_len = 1, ++ .elem_size = sizeof(u32), ++ .array_type = NO_ARRAY, ++ .tlv_type = 0x17, ++ .offset = offsetof(struct qmi_wlanfw_cap_resp_msg_v01, ++ time_freq_hz), ++ }, ++ { ++ .data_type = QMI_OPT_FLAG, ++ .elem_len = 1, ++ .elem_size = sizeof(u8), ++ .array_type = NO_ARRAY, ++ .tlv_type = 0x18, ++ .offset = offsetof(struct qmi_wlanfw_cap_resp_msg_v01, ++ otp_version_valid), ++ }, ++ { ++ .data_type = QMI_UNSIGNED_4_BYTE, ++ .elem_len = 1, ++ .elem_size = sizeof(u32), ++ .array_type = NO_ARRAY, ++ .tlv_type = 0x18, ++ .offset = offsetof(struct qmi_wlanfw_cap_resp_msg_v01, ++ otp_version), ++ }, ++ { ++ .data_type = QMI_OPT_FLAG, ++ .elem_len = 1, ++ .elem_size = sizeof(u8), ++ .array_type = NO_ARRAY, ++ .tlv_type = 0x19, ++ .offset = offsetof(struct qmi_wlanfw_cap_resp_msg_v01, ++ eeprom_read_timeout_valid), ++ }, ++ { ++ .data_type = QMI_UNSIGNED_4_BYTE, ++ .elem_len = 1, ++ .elem_size = sizeof(u32), ++ .array_type = NO_ARRAY, ++ .tlv_type = 0x19, ++ .offset = offsetof(struct qmi_wlanfw_cap_resp_msg_v01, ++ eeprom_read_timeout), ++ }, ++ { + .data_type = QMI_EOTI, + .array_type = NO_ARRAY, + .tlv_type = QMI_COMMON_TLV_TYPE, +@@ -1846,8 +1918,8 @@ static int ath11k_qmi_request_target_cap + memset(&req, 0, sizeof(req)); + memset(&resp, 0, sizeof(resp)); + +- ret = qmi_txn_init(&ab->qmi.handle, &txn, +- qmi_wlanfw_cap_resp_msg_v01_ei, &resp); ++ ret = qmi_txn_init(&ab->qmi.handle, &txn, qmi_wlanfw_cap_resp_msg_v01_ei, ++ &resp); + if (ret < 0) + goto out; + +@@ -1900,6 +1972,12 @@ static int ath11k_qmi_request_target_cap + strlcpy(ab->qmi.target.fw_build_id, resp.fw_build_id, + sizeof(ab->qmi.target.fw_build_id)); + ++ if (resp.eeprom_read_timeout_valid) { ++ ab->qmi.target.eeprom_caldata = ++ resp.eeprom_read_timeout; ++ ath11k_dbg(ab, ATH11K_DBG_QMI, "qmi cal data supported from eeprom\n"); ++ } ++ + ath11k_info(ab, "chip_id 0x%x chip_family 0x%x board_id 0x%x soc_id 0x%x\n", + ab->qmi.target.chip_id, ab->qmi.target.chip_family, + ab->qmi.target.board_id, ab->qmi.target.soc_id); +@@ -1963,7 +2041,8 @@ static int ath11k_qmi_load_file_target_m + req->end = 1; + } + +- if (ab->bus_params.fixed_bdf_addr) { ++ if (ab->bus_params.fixed_bdf_addr || ++ type == ATH11K_QMI_FILE_TYPE_EEPROM) { + req->data_valid = 0; + req->end = 1; + req->data_len = ATH11K_QMI_MAX_BDF_FILE_NAME_SIZE; +@@ -2010,7 +2089,8 @@ static int ath11k_qmi_load_file_target_m + goto err_iounmap; + } + +- if (ab->bus_params.fixed_bdf_addr) { ++ if (ab->bus_params.fixed_bdf_addr || ++ type == ATH11K_QMI_FILE_TYPE_EEPROM) { + remaining = 0; + } else { + remaining -= req->data_len; +@@ -2039,6 +2119,7 @@ static int ath11k_qmi_load_bdf_qmi(struc + struct ath11k_board_data bd; + u32 fw_size, file_type; + int ret = 0, bdf_type; ++ const u8 *tmp; + + memset(&bd, 0, sizeof(bd)); + ret = ath11k_core_fetch_bdf(ab, &bd); +@@ -2063,31 +2144,38 @@ static int ath11k_qmi_load_bdf_qmi(struc + goto out; + } + +- /* QCA6390 does not support cal data file, skip it */ ++ /* QCA6390 does not support cal data, skip it */ + if (bdf_type == ATH11K_QMI_BDF_TYPE_ELF) + goto out; + +- file_type = ATH11K_QMI_FILE_TYPE_CALDATA; ++ if (ab->qmi.target.eeprom_caldata) { ++ file_type = ATH11K_QMI_FILE_TYPE_EEPROM; ++ tmp = filename; ++ fw_size = ATH11K_QMI_MAX_BDF_FILE_NAME_SIZE; ++ } else { ++ file_type = ATH11K_QMI_FILE_TYPE_CALDATA; + +- /* cal--.bin */ +- snprintf(filename, sizeof(filename), "cal-%s-%s.bin", +- ath11k_bus_str(ab->hif.bus), dev_name(dev)); +- fw_entry = ath11k_core_firmware_request(ab, filename); +- if (!IS_ERR(fw_entry)) +- goto success; +- +- fw_entry = ath11k_core_firmware_request(ab, ATH11K_DEFAULT_CAL_FILE); +- if (IS_ERR(fw_entry)) { +- ret = PTR_ERR(fw_entry); +- ath11k_warn(ab, +- "qmi failed to load CAL data file:%s\n", +- filename); +- goto out; ++ /* cal--.bin */ ++ snprintf(filename, sizeof(filename), "cal-%s-%s.bin", ++ ath11k_bus_str(ab->hif.bus), dev_name(dev)); ++ fw_entry = ath11k_core_firmware_request(ab, filename); ++ if (!IS_ERR(fw_entry)) ++ goto success; ++ ++ fw_entry = ath11k_core_firmware_request(ab, ATH11K_DEFAULT_CAL_FILE); ++ if (IS_ERR(fw_entry)) { ++ ret = PTR_ERR(fw_entry); ++ ath11k_warn(ab, ++ "qmi failed to load CAL data file:%s\n", ++ filename); ++ goto out; ++ } ++success: ++ fw_size = min_t(u32, ab->hw_params.fw.board_size, fw_entry->size); ++ tmp = fw_entry->data; + } + +-success: +- fw_size = min_t(u32, ab->hw_params.fw.board_size, fw_entry->size); +- ret = ath11k_qmi_load_file_target_mem(ab, fw_entry->data, fw_size, file_type); ++ ret = ath11k_qmi_load_file_target_mem(ab, tmp, fw_size, file_type); + if (ret < 0) { + ath11k_warn(ab, "qmi failed to load caldata\n"); + goto out_qmi_cal; +@@ -2096,7 +2184,8 @@ success: + ath11k_dbg(ab, ATH11K_DBG_QMI, "qmi caldata type: %u\n", file_type); + + out_qmi_cal: +- release_firmware(fw_entry); ++ if (!ab->qmi.target.eeprom_caldata) ++ release_firmware(fw_entry); + out: + ath11k_core_free_bdf(ab, &bd); + ath11k_dbg(ab, ATH11K_DBG_QMI, "qmi BDF download sequence completed\n"); +--- a/drivers/net/wireless/ath/ath11k/qmi.h ++++ b/drivers/net/wireless/ath/ath11k/qmi.h +@@ -10,7 +10,7 @@ + #include + + #define ATH11K_HOST_VERSION_STRING "WIN" +-#define ATH11K_QMI_WLANFW_TIMEOUT_MS 5000 ++#define ATH11K_QMI_WLANFW_TIMEOUT_MS 10000 + #define ATH11K_QMI_MAX_BDF_FILE_NAME_SIZE 64 + #define ATH11K_QMI_CALDB_ADDRESS 0x4BA00000 + #define ATH11K_QMI_WLANFW_MAX_BUILD_ID_LEN_V01 128 +@@ -42,6 +42,7 @@ struct ath11k_base; + enum ath11k_qmi_file_type { + ATH11K_QMI_FILE_TYPE_BDF_GOLDEN, + ATH11K_QMI_FILE_TYPE_CALDATA, ++ ATH11K_QMI_FILE_TYPE_EEPROM, + ATH11K_QMI_MAX_FILE_TYPE, + }; + +@@ -102,6 +103,7 @@ struct target_info { + u32 board_id; + u32 soc_id; + u32 fw_version; ++ u32 eeprom_caldata; + char fw_build_timestamp[ATH11K_QMI_WLANFW_MAX_TIMESTAMP_LEN_V01 + 1]; + char fw_build_id[ATH11K_QMI_WLANFW_MAX_BUILD_ID_LEN_V01 + 1]; + char bdf_ext[ATH11K_QMI_BDF_EXT_STR_LENGTH]; +@@ -133,7 +135,7 @@ struct ath11k_qmi { + wait_queue_head_t cold_boot_waitq; + }; + +-#define QMI_WLANFW_HOST_CAP_REQ_MSG_V01_MAX_LEN 189 ++#define QMI_WLANFW_HOST_CAP_REQ_MSG_V01_MAX_LEN 261 + #define QMI_WLANFW_HOST_CAP_REQ_V01 0x0034 + #define QMI_WLANFW_HOST_CAP_RESP_MSG_V01_MAX_LEN 7 + #define QMI_WLFW_HOST_CAP_RESP_V01 0x0034 +@@ -283,7 +285,7 @@ struct qmi_wlanfw_fw_cold_cal_done_ind_m + }; + + #define QMI_WLANFW_CAP_REQ_MSG_V01_MAX_LEN 0 +-#define QMI_WLANFW_CAP_RESP_MSG_V01_MAX_LEN 207 ++#define QMI_WLANFW_CAP_RESP_MSG_V01_MAX_LEN 235 + #define QMI_WLANFW_CAP_REQ_V01 0x0024 + #define QMI_WLANFW_CAP_RESP_V01 0x0024 + +@@ -364,6 +366,14 @@ struct qmi_wlanfw_cap_resp_msg_v01 { + char fw_build_id[ATH11K_QMI_WLANFW_MAX_BUILD_ID_LEN_V01 + 1]; + u8 num_macs_valid; + u8 num_macs; ++ u8 voltage_mv_valid; ++ u32 voltage_mv; ++ u8 time_freq_hz_valid; ++ u32 time_freq_hz; ++ u8 otp_version_valid; ++ u32 otp_version; ++ u8 eeprom_read_timeout_valid; ++ u32 eeprom_read_timeout; + }; + + struct qmi_wlanfw_cap_req_msg_v01 { diff --git a/package/kernel/mac80211/patches/ath11k/0021-ath11k-Replace-one-element-array-with-flexible-array.patch b/package/kernel/mac80211/patches/ath11k/0021-ath11k-Replace-one-element-array-with-flexible-array.patch new file mode 100644 index 000000000..0c73d1831 --- /dev/null +++ b/package/kernel/mac80211/patches/ath11k/0021-ath11k-Replace-one-element-array-with-flexible-array.patch @@ -0,0 +1,145 @@ +From b2549465cdeac3847487ce88b15ca47c37b60b88 Mon Sep 17 00:00:00 2001 +From: "Gustavo A. R. Silva" +Date: Tue, 28 Sep 2021 12:05:44 +0300 +Subject: [PATCH 021/120] ath11k: Replace one-element array with flexible-array + member + +There is a regular need in the kernel to provide a way to declare having a +dynamically sized set of trailing elements in a structure. Kernel code +should always use "flexible array members"[1] for these cases. The older +style of one-element or zero-length arrays should no longer be used[2]. + +Refactor the code a bit according to the use of a flexible-array member in +struct scan_chan_list_params instead of a one-element array, and use the +struct_size() helper. + +Also, save 25 (too many) bytes that were being allocated: + +$ pahole -C channel_param drivers/net/wireless/ath/ath11k/reg.o +struct channel_param { + u8 chan_id; /* 0 1 */ + u8 pwr; /* 1 1 */ + u32 mhz; /* 2 4 */ + + /* Bitfield combined with next fields */ + + u32 half_rate:1; /* 4:16 4 */ + u32 quarter_rate:1; /* 4:17 4 */ + u32 dfs_set:1; /* 4:18 4 */ + u32 dfs_set_cfreq2:1; /* 4:19 4 */ + u32 is_chan_passive:1; /* 4:20 4 */ + u32 allow_ht:1; /* 4:21 4 */ + u32 allow_vht:1; /* 4:22 4 */ + u32 allow_he:1; /* 4:23 4 */ + u32 set_agile:1; /* 4:24 4 */ + u32 psc_channel:1; /* 4:25 4 */ + + /* XXX 6 bits hole, try to pack */ + + u32 phy_mode; /* 8 4 */ + u32 cfreq1; /* 12 4 */ + u32 cfreq2; /* 16 4 */ + char maxpower; /* 20 1 */ + char minpower; /* 21 1 */ + char maxregpower; /* 22 1 */ + u8 antennamax; /* 23 1 */ + u8 reg_class_id; /* 24 1 */ + + /* size: 25, cachelines: 1, members: 21 */ + /* sum members: 23 */ + /* sum bitfield members: 10 bits, bit holes: 1, sum bit holes: 6 bits */ + /* last cacheline: 25 bytes */ +} __attribute__((__packed__)); + +as previously, sizeof(struct scan_chan_list_params) was 32 bytes: + +$ pahole -C scan_chan_list_params drivers/net/wireless/ath/ath11k/reg.o +struct scan_chan_list_params { + u32 pdev_id; /* 0 4 */ + u16 nallchans; /* 4 2 */ + struct channel_param ch_param[1]; /* 6 25 */ + + /* size: 32, cachelines: 1, members: 3 */ + /* padding: 1 */ + /* last cacheline: 32 bytes */ +}; + +and now with the flexible array transformation it is just 8 bytes: + +$ pahole -C scan_chan_list_params drivers/net/wireless/ath/ath11k/reg.o +struct scan_chan_list_params { + u32 pdev_id; /* 0 4 */ + u16 nallchans; /* 4 2 */ + struct channel_param ch_param[]; /* 6 0 */ + + /* size: 8, cachelines: 1, members: 3 */ + /* padding: 2 */ + /* last cacheline: 8 bytes */ +}; + +This helps with the ongoing efforts to globally enable -Warray-bounds and +get us closer to being able to tighten the FORTIFY_SOURCE routines on +memcpy(). + +This issue was found with the help of Coccinelle and audited and fixed, +manually. + +[1] https://en.wikipedia.org/wiki/Flexible_array_member +[2] https://www.kernel.org/doc/html/v5.10/process/deprecated.html#zero-length-and-one-element-arrays + +Link: https://github.com/KSPP/linux/issues/79 +Link: https://github.com/KSPP/linux/issues/109 +Signed-off-by: Gustavo A. R. Silva +Signed-off-by: Kalle Valo +Link: https://lore.kernel.org/r/20210823172159.GA25800@embeddedor +--- + drivers/net/wireless/ath/ath11k/reg.c | 7 ++----- + drivers/net/wireless/ath/ath11k/wmi.c | 2 +- + drivers/net/wireless/ath/ath11k/wmi.h | 2 +- + 3 files changed, 4 insertions(+), 7 deletions(-) + +--- a/drivers/net/wireless/ath/ath11k/reg.c ++++ b/drivers/net/wireless/ath/ath11k/reg.c +@@ -97,7 +97,6 @@ int ath11k_reg_update_chan_list(struct a + struct channel_param *ch; + enum nl80211_band band; + int num_channels = 0; +- int params_len; + int i, ret; + + bands = hw->wiphy->bands; +@@ -117,10 +116,8 @@ int ath11k_reg_update_chan_list(struct a + if (WARN_ON(!num_channels)) + return -EINVAL; + +- params_len = sizeof(struct scan_chan_list_params) + +- num_channels * sizeof(struct channel_param); +- params = kzalloc(params_len, GFP_KERNEL); +- ++ params = kzalloc(struct_size(params, ch_param, num_channels), ++ GFP_KERNEL); + if (!params) + return -ENOMEM; + +--- a/drivers/net/wireless/ath/ath11k/wmi.c ++++ b/drivers/net/wireless/ath/ath11k/wmi.c +@@ -2302,7 +2302,7 @@ int ath11k_wmi_send_scan_chan_list_cmd(s + u16 num_send_chans, num_sends = 0, max_chan_limit = 0; + u32 *reg1, *reg2; + +- tchan_info = &chan_list->ch_param[0]; ++ tchan_info = chan_list->ch_param; + while (chan_list->nallchans) { + len = sizeof(*cmd) + TLV_HDR_SIZE; + max_chan_limit = (wmi->wmi_ab->max_msg_len[ar->pdev_idx] - len) / +--- a/drivers/net/wireless/ath/ath11k/wmi.h ++++ b/drivers/net/wireless/ath/ath11k/wmi.h +@@ -3659,7 +3659,7 @@ struct wmi_stop_scan_cmd { + struct scan_chan_list_params { + u32 pdev_id; + u16 nallchans; +- struct channel_param ch_param[1]; ++ struct channel_param ch_param[]; + }; + + struct wmi_scan_chan_list_cmd { diff --git a/package/kernel/mac80211/patches/ath11k/0022-ath11k-qmi-avoid-error-messages-when-dma-allocation-.patch b/package/kernel/mac80211/patches/ath11k/0022-ath11k-qmi-avoid-error-messages-when-dma-allocation-.patch new file mode 100644 index 000000000..c9a7ff61f --- /dev/null +++ b/package/kernel/mac80211/patches/ath11k/0022-ath11k-qmi-avoid-error-messages-when-dma-allocation-.patch @@ -0,0 +1,28 @@ +From b9b5948cdd7bc8d9fa31c78cbbb04382c815587f Mon Sep 17 00:00:00 2001 +From: Aaron Ma +Date: Tue, 28 Sep 2021 12:05:43 +0300 +Subject: [PATCH 022/120] ath11k: qmi: avoid error messages when dma allocation + fails + +qmi tries to allocate a large contiguous dma memory at first, +on the AMD Ryzen platform it fails, then retries with small slices. +So set flag GFP_NOWARN to avoid flooding dmesg. + +Signed-off-by: Aaron Ma +Signed-off-by: Kalle Valo +Link: https://lore.kernel.org/r/20210823063258.37747-1-aaron.ma@canonical.com +--- + drivers/net/wireless/ath/ath11k/qmi.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +--- a/drivers/net/wireless/ath/ath11k/qmi.c ++++ b/drivers/net/wireless/ath/ath11k/qmi.c +@@ -1842,7 +1842,7 @@ static int ath11k_qmi_alloc_target_mem_c + chunk->vaddr = dma_alloc_coherent(ab->dev, + chunk->size, + &chunk->paddr, +- GFP_KERNEL); ++ GFP_KERNEL | __GFP_NOWARN); + if (!chunk->vaddr) { + if (ab->qmi.mem_seg_count <= ATH11K_QMI_FW_MEM_REQ_SEGMENT_CNT) { + ath11k_dbg(ab, ATH11K_DBG_QMI, diff --git a/package/kernel/mac80211/patches/ath11k/0024-ath11k-Add-support-for-RX-decapsulation-offload.patch b/package/kernel/mac80211/patches/ath11k/0024-ath11k-Add-support-for-RX-decapsulation-offload.patch new file mode 100644 index 000000000..e17fe4d38 --- /dev/null +++ b/package/kernel/mac80211/patches/ath11k/0024-ath11k-Add-support-for-RX-decapsulation-offload.patch @@ -0,0 +1,596 @@ +From 2167fa606c0f0e64b95a04f9bc42d9fd5360838a Mon Sep 17 00:00:00 2001 +From: Sriram R +Date: Tue, 28 Sep 2021 12:05:40 +0300 +Subject: [PATCH 024/120] ath11k: Add support for RX decapsulation offload + +Add support for rx decapsulation offload by advertising +the support to mac80211 during registration. Also ensure +the frames have the RX_FLAG_8023 flag set in decap offload +frames before passing to mac80211. + +Since the packets delivered to the driver are in 802.3 format, these +can be sent to the network core with minimal processing in mac80211. +This helps in releasing some CPU cycles in the host processor and +thereby improving the performance. + +Two exceptions are made before passing decap frames, one is +for EAPOL packets since mac80211 8023 fast rx for the sta +is set only after authorization, other case is for multicast +packets to validate PN in mac80211. In both the cases the +decap frames are converted to 80211 frame and sent to mac80211. + +Ethernet decap can be enabled by using frame_mode modparam: + +insmod ath11k frame_mode=2 + +Tested-on: IPQ8074 hw2.0 AHB WLAN.HK.2.5.0.1-00844-QCAHKSWPL_SILICONZ-1 v2 + +Co-developed-by: Manikanta Pubbisetty +Signed-off-by: Manikanta Pubbisetty +Signed-off-by: Sriram R +Signed-off-by: Jouni Malinen +Signed-off-by: Kalle Valo +Link: https://lore.kernel.org/r/20210721204217.120572-1-jouni@codeaurora.org +--- + drivers/net/wireless/ath/ath11k/core.h | 4 + + drivers/net/wireless/ath/ath11k/dp_rx.c | 194 +++++++++++++-------- + drivers/net/wireless/ath/ath11k/hal_desc.h | 2 + + drivers/net/wireless/ath/ath11k/hw.c | 43 +++++ + drivers/net/wireless/ath/ath11k/hw.h | 2 + + drivers/net/wireless/ath/ath11k/mac.c | 25 ++- + 6 files changed, 198 insertions(+), 72 deletions(-) + +--- a/drivers/net/wireless/ath/ath11k/core.h ++++ b/drivers/net/wireless/ath/ath11k/core.h +@@ -93,6 +93,8 @@ struct ath11k_skb_rxcb { + bool is_first_msdu; + bool is_last_msdu; + bool is_continuation; ++ bool is_mcbc; ++ bool is_eapol; + struct hal_rx_desc *rx_desc; + u8 err_rel_src; + u8 err_code; +@@ -100,6 +102,8 @@ struct ath11k_skb_rxcb { + u8 unmapped; + u8 is_frag; + u8 tid; ++ u16 peer_id; ++ u16 seq_no; + }; + + enum ath11k_hw_rev { +--- a/drivers/net/wireless/ath/ath11k/dp_rx.c ++++ b/drivers/net/wireless/ath/ath11k/dp_rx.c +@@ -270,6 +270,18 @@ static bool ath11k_dp_rx_h_attn_is_mcbc( + __le32_to_cpu(attn->info1))); + } + ++static bool ath11k_dp_rxdesc_mac_addr2_valid(struct ath11k_base *ab, ++ struct hal_rx_desc *desc) ++{ ++ return ab->hw_params.hw_ops->rx_desc_mac_addr2_valid(desc); ++} ++ ++static u8 *ath11k_dp_rxdesc_mpdu_start_addr2(struct ath11k_base *ab, ++ struct hal_rx_desc *desc) ++{ ++ return ab->hw_params.hw_ops->rx_desc_mpdu_start_addr2(desc); ++} ++ + static void ath11k_dp_service_mon_ring(struct timer_list *t) + { + struct ath11k_base *ab = from_timer(ab, t, mon_reap_timer); +@@ -2156,6 +2168,7 @@ static void ath11k_dp_rx_h_undecap(struc + { + u8 *first_hdr; + u8 decap; ++ struct ethhdr *ehdr; + + first_hdr = ath11k_dp_rx_h_80211_hdr(ar->ab, rx_desc); + decap = ath11k_dp_rx_h_msdu_start_decap_type(ar->ab, rx_desc); +@@ -2170,9 +2183,22 @@ static void ath11k_dp_rx_h_undecap(struc + decrypted); + break; + case DP_RX_DECAP_TYPE_ETHERNET2_DIX: +- /* TODO undecap support for middle/last msdu's of amsdu */ +- ath11k_dp_rx_h_undecap_eth(ar, msdu, first_hdr, +- enctype, status); ++ ehdr = (struct ethhdr *)msdu->data; ++ ++ /* mac80211 allows fast path only for authorized STA */ ++ if (ehdr->h_proto == cpu_to_be16(ETH_P_PAE)) { ++ ATH11K_SKB_RXCB(msdu)->is_eapol = true; ++ ath11k_dp_rx_h_undecap_eth(ar, msdu, first_hdr, ++ enctype, status); ++ break; ++ } ++ ++ /* PN for mcast packets will be validated in mac80211; ++ * remove eth header and add 802.11 header. ++ */ ++ if (ATH11K_SKB_RXCB(msdu)->is_mcbc && decrypted) ++ ath11k_dp_rx_h_undecap_eth(ar, msdu, first_hdr, ++ enctype, status); + break; + case DP_RX_DECAP_TYPE_8023: + /* TODO: Handle undecap for these formats */ +@@ -2180,35 +2206,62 @@ static void ath11k_dp_rx_h_undecap(struc + } + } + ++static struct ath11k_peer * ++ath11k_dp_rx_h_find_peer(struct ath11k_base *ab, struct sk_buff *msdu) ++{ ++ struct ath11k_skb_rxcb *rxcb = ATH11K_SKB_RXCB(msdu); ++ struct hal_rx_desc *rx_desc = rxcb->rx_desc; ++ struct ath11k_peer *peer = NULL; ++ ++ lockdep_assert_held(&ab->base_lock); ++ ++ if (rxcb->peer_id) ++ peer = ath11k_peer_find_by_id(ab, rxcb->peer_id); ++ ++ if (peer) ++ return peer; ++ ++ if (!rx_desc || !(ath11k_dp_rxdesc_mac_addr2_valid(ab, rx_desc))) ++ return NULL; ++ ++ peer = ath11k_peer_find_by_addr(ab, ++ ath11k_dp_rxdesc_mpdu_start_addr2(ab, rx_desc)); ++ return peer; ++} ++ + static void ath11k_dp_rx_h_mpdu(struct ath11k *ar, + struct sk_buff *msdu, + struct hal_rx_desc *rx_desc, + struct ieee80211_rx_status *rx_status) + { +- bool fill_crypto_hdr, mcast; ++ bool fill_crypto_hdr; + enum hal_encrypt_type enctype; + bool is_decrypted = false; ++ struct ath11k_skb_rxcb *rxcb; + struct ieee80211_hdr *hdr; + struct ath11k_peer *peer; + struct rx_attention *rx_attention; + u32 err_bitmap; + +- hdr = (struct ieee80211_hdr *)msdu->data; +- + /* PN for multicast packets will be checked in mac80211 */ ++ rxcb = ATH11K_SKB_RXCB(msdu); ++ fill_crypto_hdr = ath11k_dp_rx_h_attn_is_mcbc(ar->ab, rx_desc); ++ rxcb->is_mcbc = fill_crypto_hdr; + +- mcast = is_multicast_ether_addr(hdr->addr1); +- fill_crypto_hdr = mcast; ++ if (rxcb->is_mcbc) { ++ rxcb->peer_id = ath11k_dp_rx_h_mpdu_start_peer_id(ar->ab, rx_desc); ++ rxcb->seq_no = ath11k_dp_rx_h_mpdu_start_seq_no(ar->ab, rx_desc); ++ } + + spin_lock_bh(&ar->ab->base_lock); +- peer = ath11k_peer_find_by_addr(ar->ab, hdr->addr2); ++ peer = ath11k_dp_rx_h_find_peer(ar->ab, msdu); + if (peer) { +- if (mcast) ++ if (rxcb->is_mcbc) + enctype = peer->sec_type_grp; + else + enctype = peer->sec_type; + } else { +- enctype = HAL_ENCRYPT_TYPE_OPEN; ++ enctype = ath11k_dp_rx_h_mpdu_start_enctype(ar->ab, rx_desc); + } + spin_unlock_bh(&ar->ab->base_lock); + +@@ -2247,8 +2300,11 @@ static void ath11k_dp_rx_h_mpdu(struct a + if (!is_decrypted || fill_crypto_hdr) + return; + +- hdr = (void *)msdu->data; +- hdr->frame_control &= ~__cpu_to_le16(IEEE80211_FCTL_PROTECTED); ++ if (ath11k_dp_rx_h_msdu_start_decap_type(ar->ab, rx_desc) != ++ DP_RX_DECAP_TYPE_ETHERNET2_DIX) { ++ hdr = (void *)msdu->data; ++ hdr->frame_control &= ~__cpu_to_le16(IEEE80211_FCTL_PROTECTED); ++ } + } + + static void ath11k_dp_rx_h_rate(struct ath11k *ar, struct hal_rx_desc *rx_desc, +@@ -2365,51 +2421,49 @@ static void ath11k_dp_rx_h_ppdu(struct a + ath11k_dp_rx_h_rate(ar, rx_desc, rx_status); + } + +-static char *ath11k_print_get_tid(struct ieee80211_hdr *hdr, char *out, +- size_t size) +-{ +- u8 *qc; +- int tid; +- +- if (!ieee80211_is_data_qos(hdr->frame_control)) +- return ""; +- +- qc = ieee80211_get_qos_ctl(hdr); +- tid = *qc & IEEE80211_QOS_CTL_TID_MASK; +- snprintf(out, size, "tid %d", tid); +- +- return out; +-} +- + static void ath11k_dp_rx_deliver_msdu(struct ath11k *ar, struct napi_struct *napi, +- struct sk_buff *msdu) ++ struct sk_buff *msdu, ++ struct ieee80211_rx_status *status) + { + static const struct ieee80211_radiotap_he known = { + .data1 = cpu_to_le16(IEEE80211_RADIOTAP_HE_DATA1_DATA_MCS_KNOWN | + IEEE80211_RADIOTAP_HE_DATA1_BW_RU_ALLOC_KNOWN), + .data2 = cpu_to_le16(IEEE80211_RADIOTAP_HE_DATA2_GI_KNOWN), + }; +- struct ieee80211_rx_status *status; +- struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)msdu->data; ++ struct ieee80211_rx_status *rx_status; + struct ieee80211_radiotap_he *he = NULL; +- char tid[32]; +- +- status = IEEE80211_SKB_RXCB(msdu); +- if (status->encoding == RX_ENC_HE) { ++ struct ieee80211_sta *pubsta = NULL; ++ struct ath11k_peer *peer; ++ struct ath11k_skb_rxcb *rxcb = ATH11K_SKB_RXCB(msdu); ++ u8 decap = DP_RX_DECAP_TYPE_RAW; ++ bool is_mcbc = rxcb->is_mcbc; ++ bool is_eapol = rxcb->is_eapol; ++ ++ if (status->encoding == RX_ENC_HE && ++ !(status->flag & RX_FLAG_RADIOTAP_HE) && ++ !(status->flag & RX_FLAG_SKIP_MONITOR)) { + he = skb_push(msdu, sizeof(known)); + memcpy(he, &known, sizeof(known)); + status->flag |= RX_FLAG_RADIOTAP_HE; + } + ++ if (!(status->flag & RX_FLAG_ONLY_MONITOR)) ++ decap = ath11k_dp_rx_h_msdu_start_decap_type(ar->ab, rxcb->rx_desc); ++ ++ spin_lock_bh(&ar->ab->base_lock); ++ peer = ath11k_dp_rx_h_find_peer(ar->ab, msdu); ++ if (peer && peer->sta) ++ pubsta = peer->sta; ++ spin_unlock_bh(&ar->ab->base_lock); ++ + ath11k_dbg(ar->ab, ATH11K_DBG_DATA, +- "rx skb %pK len %u peer %pM %s %s sn %u %s%s%s%s%s%s%s %srate_idx %u vht_nss %u freq %u band %u flag 0x%x fcs-err %i mic-err %i amsdu-more %i\n", ++ "rx skb %pK len %u peer %pM %d %s sn %u %s%s%s%s%s%s%s %srate_idx %u vht_nss %u freq %u band %u flag 0x%x fcs-err %i mic-err %i amsdu-more %i\n", + msdu, + msdu->len, +- ieee80211_get_SA(hdr), +- ath11k_print_get_tid(hdr, tid, sizeof(tid)), +- is_multicast_ether_addr(ieee80211_get_DA(hdr)) ? +- "mcast" : "ucast", +- (__le16_to_cpu(hdr->seq_ctrl) & IEEE80211_SCTL_SEQ) >> 4, ++ peer ? peer->addr : NULL, ++ rxcb->tid, ++ is_mcbc ? "mcast" : "ucast", ++ rxcb->seq_no, + (status->encoding == RX_ENC_LEGACY) ? "legacy" : "", + (status->encoding == RX_ENC_HT) ? "ht" : "", + (status->encoding == RX_ENC_VHT) ? "vht" : "", +@@ -2429,22 +2483,32 @@ static void ath11k_dp_rx_deliver_msdu(st + ath11k_dbg_dump(ar->ab, ATH11K_DBG_DP_RX, NULL, "dp rx msdu: ", + msdu->data, msdu->len); + ++ rx_status = IEEE80211_SKB_RXCB(msdu); ++ *rx_status = *status; ++ + /* TODO: trace rx packet */ + +- ieee80211_rx_napi(ar->hw, NULL, msdu, napi); ++ /* PN for multicast packets are not validate in HW, ++ * so skip 802.3 rx path ++ * Also, fast_rx expectes the STA to be authorized, hence ++ * eapol packets are sent in slow path. ++ */ ++ if (decap == DP_RX_DECAP_TYPE_ETHERNET2_DIX && !is_eapol && ++ !(is_mcbc && rx_status->flag & RX_FLAG_DECRYPTED)) ++ rx_status->flag |= RX_FLAG_8023; ++ ++ ieee80211_rx_napi(ar->hw, pubsta, msdu, napi); + } + + static int ath11k_dp_rx_process_msdu(struct ath11k *ar, + struct sk_buff *msdu, +- struct sk_buff_head *msdu_list) ++ struct sk_buff_head *msdu_list, ++ struct ieee80211_rx_status *rx_status) + { + struct ath11k_base *ab = ar->ab; + struct hal_rx_desc *rx_desc, *lrx_desc; + struct rx_attention *rx_attention; +- struct ieee80211_rx_status rx_status = {0}; +- struct ieee80211_rx_status *status; + struct ath11k_skb_rxcb *rxcb; +- struct ieee80211_hdr *hdr; + struct sk_buff *last_buf; + u8 l3_pad_bytes; + u8 *hdr_status; +@@ -2500,19 +2564,11 @@ static int ath11k_dp_rx_process_msdu(str + } + } + +- hdr = (struct ieee80211_hdr *)msdu->data; +- +- /* Process only data frames */ +- if (!ieee80211_is_data(hdr->frame_control)) +- return -EINVAL; +- +- ath11k_dp_rx_h_ppdu(ar, rx_desc, &rx_status); +- ath11k_dp_rx_h_mpdu(ar, msdu, rx_desc, &rx_status); ++ ath11k_dp_rx_h_ppdu(ar, rx_desc, rx_status); ++ ath11k_dp_rx_h_mpdu(ar, msdu, rx_desc, rx_status); + +- rx_status.flag |= RX_FLAG_SKIP_MONITOR | RX_FLAG_DUP_VALIDATED; ++ rx_status->flag |= RX_FLAG_SKIP_MONITOR | RX_FLAG_DUP_VALIDATED; + +- status = IEEE80211_SKB_RXCB(msdu); +- *status = rx_status; + return 0; + + free_out: +@@ -2527,6 +2583,7 @@ static void ath11k_dp_rx_process_receive + struct ath11k_skb_rxcb *rxcb; + struct sk_buff *msdu; + struct ath11k *ar; ++ struct ieee80211_rx_status rx_status = {0}; + u8 mac_id; + int ret; + +@@ -2549,7 +2606,7 @@ static void ath11k_dp_rx_process_receive + continue; + } + +- ret = ath11k_dp_rx_process_msdu(ar, msdu, msdu_list); ++ ret = ath11k_dp_rx_process_msdu(ar, msdu, msdu_list, &rx_status); + if (ret) { + ath11k_dbg(ab, ATH11K_DBG_DATA, + "Unable to process msdu %d", ret); +@@ -2557,7 +2614,7 @@ static void ath11k_dp_rx_process_receive + continue; + } + +- ath11k_dp_rx_deliver_msdu(ar, napi, msdu); ++ ath11k_dp_rx_deliver_msdu(ar, napi, msdu, &rx_status); + (*quota)--; + } + +@@ -2639,10 +2696,14 @@ try_again: + RX_MSDU_DESC_INFO0_LAST_MSDU_IN_MPDU); + rxcb->is_continuation = !!(desc.rx_msdu_info.info0 & + RX_MSDU_DESC_INFO0_MSDU_CONTINUATION); +- rxcb->mac_id = mac_id; ++ rxcb->peer_id = FIELD_GET(RX_MPDU_DESC_META_DATA_PEER_ID, ++ desc.rx_mpdu_info.meta_data); ++ rxcb->seq_no = FIELD_GET(RX_MPDU_DESC_INFO0_SEQ_NUM, ++ desc.rx_mpdu_info.info0); + rxcb->tid = FIELD_GET(HAL_REO_DEST_RING_INFO0_RX_QUEUE_NUM, + desc.info0); + ++ rxcb->mac_id = mac_id; + __skb_queue_tail(&msdu_list, msdu); + + if (total_msdu_reaped >= quota && !rxcb->is_continuation) { +@@ -3944,7 +4005,6 @@ static void ath11k_dp_rx_wbm_err(struct + { + struct ath11k_skb_rxcb *rxcb = ATH11K_SKB_RXCB(msdu); + struct ieee80211_rx_status rxs = {0}; +- struct ieee80211_rx_status *status; + bool drop = true; + + switch (rxcb->err_rel_src) { +@@ -3964,10 +4024,7 @@ static void ath11k_dp_rx_wbm_err(struct + return; + } + +- status = IEEE80211_SKB_RXCB(msdu); +- *status = rxs; +- +- ath11k_dp_rx_deliver_msdu(ar, napi, msdu); ++ ath11k_dp_rx_deliver_msdu(ar, napi, msdu, &rxs); + } + + int ath11k_dp_rx_process_wbm_err(struct ath11k_base *ab, +@@ -4851,7 +4908,7 @@ static int ath11k_dp_rx_mon_deliver(stru + { + struct ath11k_pdev_dp *dp = &ar->dp; + struct sk_buff *mon_skb, *skb_next, *header; +- struct ieee80211_rx_status *rxs = &dp->rx_status, *status; ++ struct ieee80211_rx_status *rxs = &dp->rx_status; + + mon_skb = ath11k_dp_rx_mon_merg_msdus(ar, mac_id, head_msdu, + tail_msdu, rxs); +@@ -4877,10 +4934,7 @@ static int ath11k_dp_rx_mon_deliver(stru + } + rxs->flag |= RX_FLAG_ONLY_MONITOR; + +- status = IEEE80211_SKB_RXCB(mon_skb); +- *status = *rxs; +- +- ath11k_dp_rx_deliver_msdu(ar, napi, mon_skb); ++ ath11k_dp_rx_deliver_msdu(ar, napi, mon_skb, rxs); + mon_skb = skb_next; + } while (mon_skb); + rxs->flag = 0; +--- a/drivers/net/wireless/ath/ath11k/hal_desc.h ++++ b/drivers/net/wireless/ath/ath11k/hal_desc.h +@@ -496,6 +496,8 @@ struct hal_tlv_hdr { + #define RX_MPDU_DESC_INFO0_DA_IDX_TIMEOUT BIT(29) + #define RX_MPDU_DESC_INFO0_RAW_MPDU BIT(30) + ++#define RX_MPDU_DESC_META_DATA_PEER_ID GENMASK(15, 0) ++ + struct rx_mpdu_desc { + u32 info0; /* %RX_MPDU_DESC_INFO */ + u32 meta_data; +--- a/drivers/net/wireless/ath/ath11k/hw.c ++++ b/drivers/net/wireless/ath/ath11k/hw.c +@@ -374,6 +374,17 @@ static void ath11k_hw_ipq8074_rx_desc_se + desc->u.ipq8074.msdu_start.info1 = __cpu_to_le32(info); + } + ++static bool ath11k_hw_ipq8074_rx_desc_mac_addr2_valid(struct hal_rx_desc *desc) ++{ ++ return __le32_to_cpu(desc->u.ipq8074.mpdu_start.info1) & ++ RX_MPDU_START_INFO1_MAC_ADDR2_VALID; ++} ++ ++static u8 *ath11k_hw_ipq8074_rx_desc_mpdu_start_addr2(struct hal_rx_desc *desc) ++{ ++ return desc->u.ipq8074.mpdu_start.addr2; ++} ++ + static + struct rx_attention *ath11k_hw_ipq8074_rx_desc_get_attention(struct hal_rx_desc *desc) + { +@@ -545,6 +556,17 @@ static u8 *ath11k_hw_qcn9074_rx_desc_get + return &desc->u.qcn9074.msdu_payload[0]; + } + ++static bool ath11k_hw_ipq9074_rx_desc_mac_addr2_valid(struct hal_rx_desc *desc) ++{ ++ return __le32_to_cpu(desc->u.qcn9074.mpdu_start.info11) & ++ RX_MPDU_START_INFO11_MAC_ADDR2_VALID; ++} ++ ++static u8 *ath11k_hw_ipq9074_rx_desc_mpdu_start_addr2(struct hal_rx_desc *desc) ++{ ++ return desc->u.qcn9074.mpdu_start.addr2; ++} ++ + static bool ath11k_hw_wcn6855_rx_desc_get_first_msdu(struct hal_rx_desc *desc) + { + return !!FIELD_GET(RX_MSDU_END_INFO2_FIRST_MSDU_WCN6855, +@@ -705,6 +727,17 @@ static u8 *ath11k_hw_wcn6855_rx_desc_get + return &desc->u.wcn6855.msdu_payload[0]; + } + ++static bool ath11k_hw_wcn6855_rx_desc_mac_addr2_valid(struct hal_rx_desc *desc) ++{ ++ return __le32_to_cpu(desc->u.wcn6855.mpdu_start.info1) & ++ RX_MPDU_START_INFO1_MAC_ADDR2_VALID; ++} ++ ++static u8 *ath11k_hw_wcn6855_rx_desc_mpdu_start_addr2(struct hal_rx_desc *desc) ++{ ++ return desc->u.wcn6855.mpdu_start.addr2; ++} ++ + static void ath11k_hw_wcn6855_reo_setup(struct ath11k_base *ab) + { + u32 reo_base = HAL_SEQ_WCSS_UMAC_REO_REG; +@@ -801,6 +834,8 @@ const struct ath11k_hw_ops ipq8074_ops = + .rx_desc_get_msdu_payload = ath11k_hw_ipq8074_rx_desc_get_msdu_payload, + .reo_setup = ath11k_hw_ipq8074_reo_setup, + .mpdu_info_get_peerid = ath11k_hw_ipq8074_mpdu_info_get_peerid, ++ .rx_desc_mac_addr2_valid = ath11k_hw_ipq8074_rx_desc_mac_addr2_valid, ++ .rx_desc_mpdu_start_addr2 = ath11k_hw_ipq8074_rx_desc_mpdu_start_addr2, + }; + + const struct ath11k_hw_ops ipq6018_ops = { +@@ -837,6 +872,8 @@ const struct ath11k_hw_ops ipq6018_ops = + .rx_desc_get_msdu_payload = ath11k_hw_ipq8074_rx_desc_get_msdu_payload, + .reo_setup = ath11k_hw_ipq8074_reo_setup, + .mpdu_info_get_peerid = ath11k_hw_ipq8074_mpdu_info_get_peerid, ++ .rx_desc_mac_addr2_valid = ath11k_hw_ipq8074_rx_desc_mac_addr2_valid, ++ .rx_desc_mpdu_start_addr2 = ath11k_hw_ipq8074_rx_desc_mpdu_start_addr2, + }; + + const struct ath11k_hw_ops qca6390_ops = { +@@ -873,6 +910,8 @@ const struct ath11k_hw_ops qca6390_ops = + .rx_desc_get_msdu_payload = ath11k_hw_ipq8074_rx_desc_get_msdu_payload, + .reo_setup = ath11k_hw_ipq8074_reo_setup, + .mpdu_info_get_peerid = ath11k_hw_ipq8074_mpdu_info_get_peerid, ++ .rx_desc_mac_addr2_valid = ath11k_hw_ipq8074_rx_desc_mac_addr2_valid, ++ .rx_desc_mpdu_start_addr2 = ath11k_hw_ipq8074_rx_desc_mpdu_start_addr2, + }; + + const struct ath11k_hw_ops qcn9074_ops = { +@@ -909,6 +948,8 @@ const struct ath11k_hw_ops qcn9074_ops = + .rx_desc_get_msdu_payload = ath11k_hw_qcn9074_rx_desc_get_msdu_payload, + .reo_setup = ath11k_hw_ipq8074_reo_setup, + .mpdu_info_get_peerid = ath11k_hw_ipq8074_mpdu_info_get_peerid, ++ .rx_desc_mac_addr2_valid = ath11k_hw_ipq9074_rx_desc_mac_addr2_valid, ++ .rx_desc_mpdu_start_addr2 = ath11k_hw_ipq9074_rx_desc_mpdu_start_addr2, + }; + + const struct ath11k_hw_ops wcn6855_ops = { +@@ -945,6 +986,8 @@ const struct ath11k_hw_ops wcn6855_ops = + .rx_desc_get_msdu_payload = ath11k_hw_wcn6855_rx_desc_get_msdu_payload, + .reo_setup = ath11k_hw_wcn6855_reo_setup, + .mpdu_info_get_peerid = ath11k_hw_wcn6855_mpdu_info_get_peerid, ++ .rx_desc_mac_addr2_valid = ath11k_hw_wcn6855_rx_desc_mac_addr2_valid, ++ .rx_desc_mpdu_start_addr2 = ath11k_hw_wcn6855_rx_desc_mpdu_start_addr2, + }; + + #define ATH11K_TX_RING_MASK_0 0x1 +--- a/drivers/net/wireless/ath/ath11k/hw.h ++++ b/drivers/net/wireless/ath/ath11k/hw.h +@@ -209,6 +209,8 @@ struct ath11k_hw_ops { + u8 *(*rx_desc_get_msdu_payload)(struct hal_rx_desc *desc); + void (*reo_setup)(struct ath11k_base *ab); + u16 (*mpdu_info_get_peerid)(u8 *tlv_data); ++ bool (*rx_desc_mac_addr2_valid)(struct hal_rx_desc *desc); ++ u8* (*rx_desc_mpdu_start_addr2)(struct hal_rx_desc *desc); + }; + + extern const struct ath11k_hw_ops ipq8074_ops; +--- a/drivers/net/wireless/ath/ath11k/mac.c ++++ b/drivers/net/wireless/ath/ath11k/mac.c +@@ -5370,7 +5370,8 @@ static void ath11k_mac_op_update_vif_off + if (ath11k_frame_mode != ATH11K_HW_TXRX_ETHERNET || + (vif->type != NL80211_IFTYPE_STATION && + vif->type != NL80211_IFTYPE_AP)) +- vif->offload_flags &= ~IEEE80211_OFFLOAD_ENCAP_ENABLED; ++ vif->offload_flags &= ~(IEEE80211_OFFLOAD_ENCAP_ENABLED | ++ IEEE80211_OFFLOAD_DECAP_ENABLED); + + if (vif->offload_flags & IEEE80211_OFFLOAD_ENCAP_ENABLED) + param_value = ATH11K_HW_TXRX_ETHERNET; +@@ -5386,6 +5387,22 @@ static void ath11k_mac_op_update_vif_off + arvif->vdev_id, ret); + vif->offload_flags &= ~IEEE80211_OFFLOAD_ENCAP_ENABLED; + } ++ ++ param_id = WMI_VDEV_PARAM_RX_DECAP_TYPE; ++ if (vif->offload_flags & IEEE80211_OFFLOAD_DECAP_ENABLED) ++ param_value = ATH11K_HW_TXRX_ETHERNET; ++ else if (test_bit(ATH11K_FLAG_RAW_MODE, &ab->dev_flags)) ++ param_value = ATH11K_HW_TXRX_RAW; ++ else ++ param_value = ATH11K_HW_TXRX_NATIVE_WIFI; ++ ++ ret = ath11k_wmi_vdev_set_param_cmd(ar, arvif->vdev_id, ++ param_id, param_value); ++ if (ret) { ++ ath11k_warn(ab, "failed to set vdev %d rx decap mode: %d\n", ++ arvif->vdev_id, ret); ++ vif->offload_flags &= ~IEEE80211_OFFLOAD_DECAP_ENABLED; ++ } + } + + static int ath11k_mac_op_add_interface(struct ieee80211_hw *hw, +@@ -7550,7 +7567,11 @@ static int __ath11k_mac_register(struct + ieee80211_hw_set(ar->hw, QUEUE_CONTROL); + ieee80211_hw_set(ar->hw, SUPPORTS_TX_FRAG); + ieee80211_hw_set(ar->hw, REPORTS_LOW_ACK); +- ieee80211_hw_set(ar->hw, SUPPORTS_TX_ENCAP_OFFLOAD); ++ ++ if (ath11k_frame_mode == ATH11K_HW_TXRX_ETHERNET) { ++ ieee80211_hw_set(ar->hw, SUPPORTS_TX_ENCAP_OFFLOAD); ++ ieee80211_hw_set(ar->hw, SUPPORTS_RX_DECAP_OFFLOAD); ++ } + + if (cap->nss_ratio_enabled) + ieee80211_hw_set(ar->hw, SUPPORTS_VHT_EXT_NSS_BW); diff --git a/package/kernel/mac80211/patches/ath11k/0025-ath11k-Fix-pktlog-lite-rx-events.patch b/package/kernel/mac80211/patches/ath11k/0025-ath11k-Fix-pktlog-lite-rx-events.patch new file mode 100644 index 000000000..bf419f03a --- /dev/null +++ b/package/kernel/mac80211/patches/ath11k/0025-ath11k-Fix-pktlog-lite-rx-events.patch @@ -0,0 +1,186 @@ +From ab18e3bc1c138f2b4358c6905a45afb7289d5086 Mon Sep 17 00:00:00 2001 +From: Anilkumar Kolli +Date: Tue, 28 Sep 2021 12:05:40 +0300 +Subject: [PATCH 025/120] ath11k: Fix pktlog lite rx events + +Fix sending rx_buf_sz to ath11k_dp_tx_htt_rx_filter_setup() +to enable pktlog full or lite mode. Depending on mode update the +trace buffer with log type full/lite. + +Pktlog lite is a lighter version of pktlog. This can be used to capture +PPDU stats. These are useful for firmware performance debugging. + +pktlog lite dumps are enabled using, + echo "0x0 1" > ath11k/IPQ8074 hw2.0/mac0/pktlog_filter + +Tested On: IPQ8074 hw2.0 AHB WLAN.HK.2.1.0.1-01233-QCAHKSWPL_SILICONZ-1 v2 + +Signed-off-by: Anilkumar Kolli +Signed-off-by: Jouni Malinen +Signed-off-by: Kalle Valo +Link: https://lore.kernel.org/r/20210721212029.142388-1-jouni@codeaurora.org +--- + drivers/net/wireless/ath/ath11k/debugfs.c | 25 +++++++++++++++++++---- + drivers/net/wireless/ath/ath11k/dp.h | 1 + + drivers/net/wireless/ath/ath11k/dp_rx.c | 16 ++++++++++++--- + drivers/net/wireless/ath/ath11k/trace.h | 11 ++++++---- + 4 files changed, 42 insertions(+), 11 deletions(-) + +--- a/drivers/net/wireless/ath/ath11k/debugfs.c ++++ b/drivers/net/wireless/ath/ath11k/debugfs.c +@@ -902,7 +902,7 @@ static ssize_t ath11k_write_pktlog_filte + struct htt_rx_ring_tlv_filter tlv_filter = {0}; + u32 rx_filter = 0, ring_id, filter, mode; + u8 buf[128] = {0}; +- int i, ret; ++ int i, ret, rx_buf_sz = 0; + ssize_t rc; + + mutex_lock(&ar->conf_mutex); +@@ -940,6 +940,17 @@ static ssize_t ath11k_write_pktlog_filte + } + } + ++ /* Clear rx filter set for monitor mode and rx status */ ++ for (i = 0; i < ab->hw_params.num_rxmda_per_pdev; i++) { ++ ring_id = ar->dp.rx_mon_status_refill_ring[i].refill_buf_ring.ring_id; ++ ret = ath11k_dp_tx_htt_rx_filter_setup(ar->ab, ring_id, ar->dp.mac_id, ++ HAL_RXDMA_MONITOR_STATUS, ++ rx_buf_sz, &tlv_filter); ++ if (ret) { ++ ath11k_warn(ar->ab, "failed to set rx filter for monitor status ring\n"); ++ goto out; ++ } ++ } + #define HTT_RX_FILTER_TLV_LITE_MODE \ + (HTT_RX_FILTER_TLV_FLAGS_PPDU_START | \ + HTT_RX_FILTER_TLV_FLAGS_PPDU_END | \ +@@ -955,6 +966,7 @@ static ssize_t ath11k_write_pktlog_filte + HTT_RX_FILTER_TLV_FLAGS_MPDU_END | + HTT_RX_FILTER_TLV_FLAGS_PACKET_HEADER | + HTT_RX_FILTER_TLV_FLAGS_ATTENTION; ++ rx_buf_sz = DP_RX_BUFFER_SIZE; + } else if (mode == ATH11K_PKTLOG_MODE_LITE) { + ret = ath11k_dp_tx_htt_h2t_ppdu_stats_req(ar, + HTT_PPDU_STATS_TAG_PKTLOG); +@@ -964,7 +976,12 @@ static ssize_t ath11k_write_pktlog_filte + } + + rx_filter = HTT_RX_FILTER_TLV_LITE_MODE; ++ rx_buf_sz = DP_RX_BUFFER_SIZE_LITE; + } else { ++ rx_buf_sz = DP_RX_BUFFER_SIZE; ++ tlv_filter = ath11k_mac_mon_status_filter_default; ++ rx_filter = tlv_filter.rx_filter; ++ + ret = ath11k_dp_tx_htt_h2t_ppdu_stats_req(ar, + HTT_PPDU_STATS_TAG_DEFAULT); + if (ret) { +@@ -988,7 +1005,7 @@ static ssize_t ath11k_write_pktlog_filte + ret = ath11k_dp_tx_htt_rx_filter_setup(ab, ring_id, + ar->dp.mac_id + i, + HAL_RXDMA_MONITOR_STATUS, +- DP_RX_BUFFER_SIZE, &tlv_filter); ++ rx_buf_sz, &tlv_filter); + + if (ret) { + ath11k_warn(ab, "failed to set rx filter for monitor status ring\n"); +@@ -996,8 +1013,8 @@ static ssize_t ath11k_write_pktlog_filte + } + } + +- ath11k_dbg(ab, ATH11K_DBG_WMI, "pktlog filter %d mode %s\n", +- filter, ((mode == ATH11K_PKTLOG_MODE_FULL) ? "full" : "lite")); ++ ath11k_info(ab, "pktlog mode %s\n", ++ ((mode == ATH11K_PKTLOG_MODE_FULL) ? "full" : "lite")); + + ar->debug.pktlog_filter = filter; + ar->debug.pktlog_mode = mode; +--- a/drivers/net/wireless/ath/ath11k/dp.h ++++ b/drivers/net/wireless/ath/ath11k/dp.h +@@ -195,6 +195,7 @@ struct ath11k_pdev_dp { + #define DP_RXDMA_MONITOR_DESC_RING_SIZE 4096 + + #define DP_RX_BUFFER_SIZE 2048 ++#define DP_RX_BUFFER_SIZE_LITE 1024 + #define DP_RX_BUFFER_ALIGN_SIZE 128 + + #define DP_RXDMA_BUF_COOKIE_BUF_ID GENMASK(17, 0) +--- a/drivers/net/wireless/ath/ath11k/dp_rx.c ++++ b/drivers/net/wireless/ath/ath11k/dp_rx.c +@@ -3033,6 +3033,8 @@ int ath11k_dp_rx_process_mon_status(stru + struct ath11k_peer *peer; + struct ath11k_sta *arsta; + int num_buffs_reaped = 0; ++ u32 rx_buf_sz; ++ u16 log_type = 0; + + __skb_queue_head_init(&skb_list); + +@@ -3045,8 +3047,16 @@ int ath11k_dp_rx_process_mon_status(stru + memset(&ppdu_info, 0, sizeof(ppdu_info)); + ppdu_info.peer_id = HAL_INVALID_PEERID; + +- if (ath11k_debugfs_is_pktlog_rx_stats_enabled(ar)) +- trace_ath11k_htt_rxdesc(ar, skb->data, DP_RX_BUFFER_SIZE); ++ if (ath11k_debugfs_is_pktlog_lite_mode_enabled(ar)) { ++ log_type = ATH11K_PKTLOG_TYPE_LITE_RX; ++ rx_buf_sz = DP_RX_BUFFER_SIZE_LITE; ++ } else if (ath11k_debugfs_is_pktlog_rx_stats_enabled(ar)) { ++ log_type = ATH11K_PKTLOG_TYPE_RX_STATBUF; ++ rx_buf_sz = DP_RX_BUFFER_SIZE; ++ } ++ ++ if (log_type) ++ trace_ath11k_htt_rxdesc(ar, skb->data, log_type, rx_buf_sz); + + hal_status = ath11k_hal_rx_parse_mon_status(ab, &ppdu_info, skb); + +@@ -3074,7 +3084,7 @@ int ath11k_dp_rx_process_mon_status(stru + ath11k_dp_rx_update_peer_stats(arsta, &ppdu_info); + + if (ath11k_debugfs_is_pktlog_peer_valid(ar, peer->addr)) +- trace_ath11k_htt_rxdesc(ar, skb->data, DP_RX_BUFFER_SIZE); ++ trace_ath11k_htt_rxdesc(ar, skb->data, log_type, rx_buf_sz); + + spin_unlock_bh(&ab->base_lock); + rcu_read_unlock(); +--- a/drivers/net/wireless/ath/ath11k/trace.h ++++ b/drivers/net/wireless/ath/ath11k/trace.h +@@ -79,14 +79,15 @@ TRACE_EVENT(ath11k_htt_ppdu_stats, + ); + + TRACE_EVENT(ath11k_htt_rxdesc, +- TP_PROTO(struct ath11k *ar, const void *data, size_t len), ++ TP_PROTO(struct ath11k *ar, const void *data, size_t log_type, size_t len), + +- TP_ARGS(ar, data, len), ++ TP_ARGS(ar, data, log_type, len), + + TP_STRUCT__entry( + __string(device, dev_name(ar->ab->dev)) + __string(driver, dev_driver_string(ar->ab->dev)) + __field(u16, len) ++ __field(u16, log_type) + __dynamic_array(u8, rxdesc, len) + ), + +@@ -94,14 +95,16 @@ TRACE_EVENT(ath11k_htt_rxdesc, + __assign_str(device, dev_name(ar->ab->dev)); + __assign_str(driver, dev_driver_string(ar->ab->dev)); + __entry->len = len; ++ __entry->log_type = log_type; + memcpy(__get_dynamic_array(rxdesc), data, len); + ), + + TP_printk( +- "%s %s rxdesc len %d", ++ "%s %s rxdesc len %d type %d", + __get_str(driver), + __get_str(device), +- __entry->len ++ __entry->len, ++ __entry->log_type + ) + ); + diff --git a/package/kernel/mac80211/patches/ath11k/0026-ath11k-Update-pdev-tx-and-rx-firmware-stats.patch b/package/kernel/mac80211/patches/ath11k/0026-ath11k-Update-pdev-tx-and-rx-firmware-stats.patch new file mode 100644 index 000000000..0c1d8833e --- /dev/null +++ b/package/kernel/mac80211/patches/ath11k/0026-ath11k-Update-pdev-tx-and-rx-firmware-stats.patch @@ -0,0 +1,250 @@ +From f394e4eae8e2c0579063e5473f1e321d22d3fe43 Mon Sep 17 00:00:00 2001 +From: Sriram R +Date: Tue, 28 Sep 2021 12:05:40 +0300 +Subject: [PATCH 026/120] ath11k: Update pdev tx and rx firmware stats + +Update the fields of pdev tx and tx firmware stats structure. +Missing fields resulted in wrong fw stats to be displayed as below. + +root@OpenWrt:/# cat /sys/kernel/debug/ath11k/ + ipq8074\ hw2.0/mac0/fw_stats/pdev_stats | grep Illegal +Illegal rate phy errors 36839112 + +Note that this struct was missing its members from initial driver +support and this change doesn't introduce/modify the structure for +firmware changes. + +Tested-on: IPQ8074 hw2.0 AHB WLAN.HK.2.4.0.1-01734-QCAHKSWPL_SILICONZ-1 v2 + +Signed-off-by: Sriram R +Signed-off-by: Jouni Malinen +Signed-off-by: Kalle Valo +Link: https://lore.kernel.org/r/20210721212029.142388-2-jouni@codeaurora.org +--- + drivers/net/wireless/ath/ath11k/core.h | 29 ++++++++++++++++++ + drivers/net/wireless/ath/ath11k/wmi.c | 41 ++++++++++++++++++++++++- + drivers/net/wireless/ath/ath11k/wmi.h | 42 ++++++++++++++++++++++++++ + 3 files changed, 111 insertions(+), 1 deletion(-) + +--- a/drivers/net/wireless/ath/ath11k/core.h ++++ b/drivers/net/wireless/ath/ath11k/core.h +@@ -806,12 +806,15 @@ struct ath11k_fw_stats_pdev { + s32 hw_reaped; + /* Num underruns */ + s32 underrun; ++ /* Num hw paused */ ++ u32 hw_paused; + /* Num PPDUs cleaned up in TX abort */ + s32 tx_abort; + /* Num MPDUs requeued by SW */ + s32 mpdus_requeued; + /* excessive retries */ + u32 tx_ko; ++ u32 tx_xretry; + /* data hw rate code */ + u32 data_rc; + /* Scheduler self triggers */ +@@ -832,6 +835,30 @@ struct ath11k_fw_stats_pdev { + u32 phy_underrun; + /* MPDU is more than txop limit */ + u32 txop_ovf; ++ /* Num sequences posted */ ++ u32 seq_posted; ++ /* Num sequences failed in queueing */ ++ u32 seq_failed_queueing; ++ /* Num sequences completed */ ++ u32 seq_completed; ++ /* Num sequences restarted */ ++ u32 seq_restarted; ++ /* Num of MU sequences posted */ ++ u32 mu_seq_posted; ++ /* Num MPDUs flushed by SW, HWPAUSED, SW TXABORT ++ * (Reset,channel change) ++ */ ++ s32 mpdus_sw_flush; ++ /* Num MPDUs filtered by HW, all filter condition (TTL expired) */ ++ s32 mpdus_hw_filter; ++ /* Num MPDUs truncated by PDG (TXOP, TBTT, ++ * PPDU_duration based on rate, dyn_bw) ++ */ ++ s32 mpdus_truncated; ++ /* Num MPDUs that was tried but didn't receive ACK or BA */ ++ s32 mpdus_ack_failed; ++ /* Num MPDUs that was dropped du to expiry. */ ++ s32 mpdus_expired; + + /* PDEV RX stats */ + /* Cnts any change in ring routing mid-ppdu */ +@@ -857,6 +884,8 @@ struct ath11k_fw_stats_pdev { + s32 phy_err_drop; + /* Number of mpdu errors - FCS, MIC, ENC etc. */ + s32 mpdu_errs; ++ /* Num overflow errors */ ++ s32 rx_ovfl_errs; + }; + + struct ath11k_fw_stats_vdev { +--- a/drivers/net/wireless/ath/ath11k/wmi.c ++++ b/drivers/net/wireless/ath/ath11k/wmi.c +@@ -5251,9 +5251,11 @@ ath11k_wmi_pull_pdev_stats_tx(const stru + dst->hw_queued = src->hw_queued; + dst->hw_reaped = src->hw_reaped; + dst->underrun = src->underrun; ++ dst->hw_paused = src->hw_paused; + dst->tx_abort = src->tx_abort; + dst->mpdus_requeued = src->mpdus_requeued; + dst->tx_ko = src->tx_ko; ++ dst->tx_xretry = src->tx_xretry; + dst->data_rc = src->data_rc; + dst->self_triggers = src->self_triggers; + dst->sw_retry_failure = src->sw_retry_failure; +@@ -5264,6 +5266,16 @@ ath11k_wmi_pull_pdev_stats_tx(const stru + dst->stateless_tid_alloc_failure = src->stateless_tid_alloc_failure; + dst->phy_underrun = src->phy_underrun; + dst->txop_ovf = src->txop_ovf; ++ dst->seq_posted = src->seq_posted; ++ dst->seq_failed_queueing = src->seq_failed_queueing; ++ dst->seq_completed = src->seq_completed; ++ dst->seq_restarted = src->seq_restarted; ++ dst->mu_seq_posted = src->mu_seq_posted; ++ dst->mpdus_sw_flush = src->mpdus_sw_flush; ++ dst->mpdus_hw_filter = src->mpdus_hw_filter; ++ dst->mpdus_truncated = src->mpdus_truncated; ++ dst->mpdus_ack_failed = src->mpdus_ack_failed; ++ dst->mpdus_expired = src->mpdus_expired; + } + + static void ath11k_wmi_pull_pdev_stats_rx(const struct wmi_pdev_stats_rx *src, +@@ -5283,6 +5295,7 @@ static void ath11k_wmi_pull_pdev_stats_r + dst->phy_errs = src->phy_errs; + dst->phy_err_drop = src->phy_err_drop; + dst->mpdu_errs = src->mpdu_errs; ++ dst->rx_ovfl_errs = src->rx_ovfl_errs; + } + + static void +@@ -5520,11 +5533,15 @@ ath11k_wmi_fw_pdev_tx_stats_fill(const s + len += scnprintf(buf + len, buf_len - len, "%30s %10d\n", + "Num underruns", pdev->underrun); + len += scnprintf(buf + len, buf_len - len, "%30s %10d\n", ++ "Num HW Paused", pdev->hw_paused); ++ len += scnprintf(buf + len, buf_len - len, "%30s %10d\n", + "PPDUs cleaned", pdev->tx_abort); + len += scnprintf(buf + len, buf_len - len, "%30s %10d\n", + "MPDUs requeued", pdev->mpdus_requeued); + len += scnprintf(buf + len, buf_len - len, "%30s %10u\n", +- "Excessive retries", pdev->tx_ko); ++ "PPDU OK", pdev->tx_ko); ++ len += scnprintf(buf + len, buf_len - len, "%30s %10u\n", ++ "Excessive retries", pdev->tx_xretry); + len += scnprintf(buf + len, buf_len - len, "%30s %10u\n", + "HW rate", pdev->data_rc); + len += scnprintf(buf + len, buf_len - len, "%30s %10u\n", +@@ -5548,6 +5565,26 @@ ath11k_wmi_fw_pdev_tx_stats_fill(const s + "PHY underrun", pdev->phy_underrun); + len += scnprintf(buf + len, buf_len - len, "%30s %10u\n", + "MPDU is more than txop limit", pdev->txop_ovf); ++ len += scnprintf(buf + len, buf_len - len, "%30s %10u\n", ++ "Num sequences posted", pdev->seq_posted); ++ len += scnprintf(buf + len, buf_len - len, "%30s %10u\n", ++ "Num seq failed queueing ", pdev->seq_failed_queueing); ++ len += scnprintf(buf + len, buf_len - len, "%30s %10u\n", ++ "Num sequences completed ", pdev->seq_completed); ++ len += scnprintf(buf + len, buf_len - len, "%30s %10u\n", ++ "Num sequences restarted ", pdev->seq_restarted); ++ len += scnprintf(buf + len, buf_len - len, "%30s %10u\n", ++ "Num of MU sequences posted ", pdev->mu_seq_posted); ++ len += scnprintf(buf + len, buf_len - len, "%30s %10u\n", ++ "Num of MPDUS SW flushed ", pdev->mpdus_sw_flush); ++ len += scnprintf(buf + len, buf_len - len, "%30s %10u\n", ++ "Num of MPDUS HW filtered ", pdev->mpdus_hw_filter); ++ len += scnprintf(buf + len, buf_len - len, "%30s %10u\n", ++ "Num of MPDUS truncated ", pdev->mpdus_truncated); ++ len += scnprintf(buf + len, buf_len - len, "%30s %10u\n", ++ "Num of MPDUS ACK failed ", pdev->mpdus_ack_failed); ++ len += scnprintf(buf + len, buf_len - len, "%30s %10u\n", ++ "Num of MPDUS expired ", pdev->mpdus_expired); + *length = len; + } + +@@ -5592,6 +5629,8 @@ ath11k_wmi_fw_pdev_rx_stats_fill(const s + "PHY errors drops", pdev->phy_err_drop); + len += scnprintf(buf + len, buf_len - len, "%30s %10d\n", + "MPDU errors (FCS, MIC, ENC)", pdev->mpdu_errs); ++ len += scnprintf(buf + len, buf_len - len, "%30s %10d\n", ++ "Overflow errors", pdev->rx_ovfl_errs); + *length = len; + } + +--- a/drivers/net/wireless/ath/ath11k/wmi.h ++++ b/drivers/net/wireless/ath/ath11k/wmi.h +@@ -4223,6 +4223,9 @@ struct wmi_pdev_stats_tx { + /* Num underruns */ + s32 underrun; + ++ /* Num hw paused */ ++ u32 hw_paused; ++ + /* Num PPDUs cleaned up in TX abort */ + s32 tx_abort; + +@@ -4232,6 +4235,8 @@ struct wmi_pdev_stats_tx { + /* excessive retries */ + u32 tx_ko; + ++ u32 tx_xretry; ++ + /* data hw rate code */ + u32 data_rc; + +@@ -4261,6 +4266,40 @@ struct wmi_pdev_stats_tx { + + /* MPDU is more than txop limit */ + u32 txop_ovf; ++ ++ /* Num sequences posted */ ++ u32 seq_posted; ++ ++ /* Num sequences failed in queueing */ ++ u32 seq_failed_queueing; ++ ++ /* Num sequences completed */ ++ u32 seq_completed; ++ ++ /* Num sequences restarted */ ++ u32 seq_restarted; ++ ++ /* Num of MU sequences posted */ ++ u32 mu_seq_posted; ++ ++ /* Num MPDUs flushed by SW, HWPAUSED, SW TXABORT ++ * (Reset,channel change) ++ */ ++ s32 mpdus_sw_flush; ++ ++ /* Num MPDUs filtered by HW, all filter condition (TTL expired) */ ++ s32 mpdus_hw_filter; ++ ++ /* Num MPDUs truncated by PDG (TXOP, TBTT, ++ * PPDU_duration based on rate, dyn_bw) ++ */ ++ s32 mpdus_truncated; ++ ++ /* Num MPDUs that was tried but didn't receive ACK or BA */ ++ s32 mpdus_ack_failed; ++ ++ /* Num MPDUs that was dropped du to expiry. */ ++ s32 mpdus_expired; + } __packed; + + struct wmi_pdev_stats_rx { +@@ -4295,6 +4334,9 @@ struct wmi_pdev_stats_rx { + + /* Number of mpdu errors - FCS, MIC, ENC etc. */ + s32 mpdu_errs; ++ ++ /* Num overflow errors */ ++ s32 rx_ovfl_errs; + } __packed; + + struct wmi_pdev_stats { diff --git a/package/kernel/mac80211/patches/ath11k/0029-ath11k-Add-vdev-start-flag-to-disable-hardware-encry.patch b/package/kernel/mac80211/patches/ath11k/0029-ath11k-Add-vdev-start-flag-to-disable-hardware-encry.patch new file mode 100644 index 000000000..de68ef97c --- /dev/null +++ b/package/kernel/mac80211/patches/ath11k/0029-ath11k-Add-vdev-start-flag-to-disable-hardware-encry.patch @@ -0,0 +1,48 @@ +From 8717db7ee802b71fa3f2a79b265b1325bc61210c Mon Sep 17 00:00:00 2001 +From: Seevalamuthu Mariappan +Date: Tue, 28 Sep 2021 12:05:40 +0300 +Subject: [PATCH 029/120] ath11k: Add vdev start flag to disable hardware + encryption + +Firmware blocks all data traffic until the key is plumbed. But, with +software encryption mode, key is never plumbed to firmware. Due to this, +a traffic failure in software encryption mode has been observed. Hence, +firmware has introduced a flag to differentiate software encryption +mode. This flag can be passed during vdev_start command. + +Enable WMI_VDEV_START_HW_ENCRYPTION_DISABLED flag in vdev_start command +to notify firmware to disable hardware encryption for a vdev. This is set +if raw mode software encryption is enabled. + +Tested-on: IPQ8074 hw2.0 AHB WLAN.HK.2.4.0.1-01421-QCAHKSWPL_SILICONZ-1 + +Signed-off-by: Seevalamuthu Mariappan +Signed-off-by: Jouni Malinen +Signed-off-by: Kalle Valo +Link: https://lore.kernel.org/r/20210721212029.142388-5-jouni@codeaurora.org +--- + drivers/net/wireless/ath/ath11k/wmi.c | 2 ++ + drivers/net/wireless/ath/ath11k/wmi.h | 1 + + 2 files changed, 3 insertions(+) + +--- a/drivers/net/wireless/ath/ath11k/wmi.c ++++ b/drivers/net/wireless/ath/ath11k/wmi.c +@@ -884,6 +884,8 @@ int ath11k_wmi_vdev_start(struct ath11k + } + + cmd->flags |= WMI_VDEV_START_LDPC_RX_ENABLED; ++ if (test_bit(ATH11K_FLAG_HW_CRYPTO_DISABLED, &ar->ab->dev_flags)) ++ cmd->flags |= WMI_VDEV_START_HW_ENCRYPTION_DISABLED; + + ptr = skb->data + sizeof(*cmd); + chan = ptr; +--- a/drivers/net/wireless/ath/ath11k/wmi.h ++++ b/drivers/net/wireless/ath/ath11k/wmi.h +@@ -2577,6 +2577,7 @@ struct wmi_vdev_down_cmd { + #define WMI_VDEV_START_HIDDEN_SSID BIT(0) + #define WMI_VDEV_START_PMF_ENABLED BIT(1) + #define WMI_VDEV_START_LDPC_RX_ENABLED BIT(3) ++#define WMI_VDEV_START_HW_ENCRYPTION_DISABLED BIT(4) + + struct wmi_ssid { + u32 ssid_len; diff --git a/package/kernel/mac80211/patches/ath11k/0030-ath11k-Assign-free_vdev_map-value-before-ieee80211_r.patch b/package/kernel/mac80211/patches/ath11k/0030-ath11k-Assign-free_vdev_map-value-before-ieee80211_r.patch new file mode 100644 index 000000000..d4e1fefca --- /dev/null +++ b/package/kernel/mac80211/patches/ath11k/0030-ath11k-Assign-free_vdev_map-value-before-ieee80211_r.patch @@ -0,0 +1,62 @@ +From 3c79cb4d63c0d58462d439efa0db328008354deb Mon Sep 17 00:00:00 2001 +From: Seevalamuthu Mariappan +Date: Tue, 28 Sep 2021 12:05:40 +0300 +Subject: [PATCH 030/120] ath11k: Assign free_vdev_map value before + ieee80211_register_hw + +Firmware crash is seen randomly, because of sending wrong vdev_id +in vdev_create command. This is due to free_vdev_map value being 0. +free_vdev_map is getting assigned after ieee80211_register_hw. In +some race conditions, add_interface api is getting called before +assigning value to free_vdev_map. Fix this by assigning free_vdev_map +before ieee80211_register_hw. + +Also, moved ar->cc_freq_hz and ar->txmgmt_idr initialization before +ieee80211_register_hw to avoid such race conditions. + +Tested-on: IPQ8074 hw2.0 AHB WLAN.HK.2.5.0.1-00948-QCAHKSWPL_SILICONZ-1 +Tested-on: QCN9074 hw1.0 PCI WLAN.HK.2.4.0.1-01734-QCAHKSWPL_SILICONZ-1 + +Signed-off-by: Seevalamuthu Mariappan +Signed-off-by: Jouni Malinen +Signed-off-by: Kalle Valo +Link: https://lore.kernel.org/r/20210721212029.142388-6-jouni@codeaurora.org +--- + drivers/net/wireless/ath/ath11k/mac.c | 14 +++++++------- + 1 file changed, 7 insertions(+), 7 deletions(-) + +--- a/drivers/net/wireless/ath/ath11k/mac.c ++++ b/drivers/net/wireless/ath/ath11k/mac.c +@@ -7701,6 +7701,10 @@ int ath11k_mac_register(struct ath11k_ba + if (test_bit(ATH11K_FLAG_REGISTERED, &ab->dev_flags)) + return 0; + ++ /* Initialize channel counters frequency value in hertz */ ++ ab->cc_freq_hz = IPQ8074_CC_FREQ_HERTZ; ++ ab->free_vdev_map = (1LL << (ab->num_radios * TARGET_NUM_VDEVS)) - 1; ++ + for (i = 0; i < ab->num_radios; i++) { + pdev = &ab->pdevs[i]; + ar = pdev->ar; +@@ -7711,18 +7715,14 @@ int ath11k_mac_register(struct ath11k_ba + ar->mac_addr[4] += i; + } + ++ idr_init(&ar->txmgmt_idr); ++ spin_lock_init(&ar->txmgmt_idr_lock); ++ + ret = __ath11k_mac_register(ar); + if (ret) + goto err_cleanup; +- +- idr_init(&ar->txmgmt_idr); +- spin_lock_init(&ar->txmgmt_idr_lock); + } + +- /* Initialize channel counters frequency value in hertz */ +- ab->cc_freq_hz = IPQ8074_CC_FREQ_HERTZ; +- ab->free_vdev_map = (1LL << (ab->num_radios * TARGET_NUM_VDEVS)) - 1; +- + return 0; + + err_cleanup: diff --git a/package/kernel/mac80211/patches/ath11k/0031-ath11k-Fix-crash-during-firmware-recovery-on-reo-cmd.patch b/package/kernel/mac80211/patches/ath11k/0031-ath11k-Fix-crash-during-firmware-recovery-on-reo-cmd.patch new file mode 100644 index 000000000..482534626 --- /dev/null +++ b/package/kernel/mac80211/patches/ath11k/0031-ath11k-Fix-crash-during-firmware-recovery-on-reo-cmd.patch @@ -0,0 +1,63 @@ +From 8ee8d38ca4727667e05a1dedf546162207bde9fa Mon Sep 17 00:00:00 2001 +From: Sriram R +Date: Tue, 28 Sep 2021 12:05:40 +0300 +Subject: [PATCH 031/120] ath11k: Fix crash during firmware recovery on reo cmd + ring access + +In scenario when a peer is disassociating, there could be +multiple places where a reo cmd ring is accessed, such as +during aggregation teardown, tid queue cleanup, etc. + +When this happens during firmware recovery where accessing of FW/HW +resources/registers is not recommended, accessing reo cmd ring in +this case could lead to crash or undefined behaviour. + +Hence avoid this by checking for corresponding flag to avoid +accessing reo cmd ring during firmware recovery. + +Sample crash: + +[ 3936.456050] Unhandled fault: imprecise external abort (0x1c06) at 0x54bb842a +[ 3936.456411] WARN: Access Violation!!!, Run "cat /sys/kernel/debug/qcom_debug_logs/tz_log" for more details +[ 3936.467997] pgd = b4474000 +[ 3936.477440] [54bb842a] *pgd=6fa61831, *pte=7f95d59f, *ppte=7f95de7e + +[ 3937.177436] [<8030ab10>] (_raw_spin_unlock_bh) from [<7f5e9eb8>] (ath11k_hal_reo_cmd_send+0x440/0x458 [ath11k]) +[ 3937.185730] [<7f5e9eb8>] (ath11k_hal_reo_cmd_send [ath11k]) from [<7f601c4c>] (ath11k_dp_tx_send_reo_cmd+0x2c/0xcc [ath11k]) +[ 3937.195524] [<7f601c4c>] (ath11k_dp_tx_send_reo_cmd [ath11k]) from [<7f602f10>] (ath11k_peer_rx_tid_reo_update+0x84/0xbc [ath11k]) +[ 3937.206984] [<7f602f10>] (ath11k_peer_rx_tid_reo_update [ath11k]) from [<7f605a9c>] (ath11k_dp_rx_ampdu_stop+0xa8/0x130 [ath11k]) +[ 3937.218532] [<7f605a9c>] (ath11k_dp_rx_ampdu_stop [ath11k]) from [<7f5f6730>] (ath11k_mac_op_ampdu_action+0x6c/0x98 [ath11k]) +[ 3937.230250] [<7f5f6730>] (ath11k_mac_op_ampdu_action [ath11k]) from [] (___ieee80211_stop_rx_ba_session+0x98/0x144 [mac80211]) +[ 3937.241499] [] (___ieee80211_stop_rx_ba_session [mac80211]) from [] (ieee80211_sta_tear_down_BA_sessions+0x4c/0xf4 [) +[ 3937.253833] [] (ieee80211_sta_tear_down_BA_sessions [mac80211]) from [] (ieee80211_sta_eosp+0x5b8/0x960 [mac80211]) +[ 3937.266764] [] (ieee80211_sta_eosp [mac80211]) from [] (__sta_info_flush+0x9c/0x134 [mac80211]) +[ 3937.278826] [] (__sta_info_flush [mac80211]) from [] (ieee80211_stop_ap+0x14c/0x28c [mac80211]) +[ 3937.289240] [] (ieee80211_stop_ap [mac80211]) from [<7f509cf0>] (__cfg80211_stop_ap+0x4c/0xd8 [cfg80211]) +[ 3937.299629] [<7f509cf0>] (__cfg80211_stop_ap [cfg80211]) from [<7f4dddec>] (cfg80211_leave+0x24/0x30 [cfg80211]) +[ 3937.310041] [<7f4dddec>] (cfg80211_leave [cfg80211]) from [<7f4de03c>] (cfg80211_netdev_notifier_call+0x174/0x48c [cfg80211]) +[ 3937.320457] [<7f4de03c>] (cfg80211_netdev_notifier_call [cfg80211]) from [<80339928>] (notifier_call_chain+0x40/0x68) +[ 3937.331636] [<80339928>] (notifier_call_chain) from [<803399a8>] (raw_notifier_call_chain+0x14/0x1c) +[ 3937.342221] [<803399a8>] (raw_notifier_call_chain) from [<8073bb00>] (call_netdevice_notifiers+0xc/0x14) + +Tested-on: IPQ8074 hw2.0 AHB WLAN.HK.2.1.0.1-01240-QCAHKSWPL_SILICONZ-1 + +Signed-off-by: Sriram R +Signed-off-by: Jouni Malinen +Signed-off-by: Kalle Valo +Link: https://lore.kernel.org/r/20210721212029.142388-7-jouni@codeaurora.org +--- + drivers/net/wireless/ath/ath11k/dp_tx.c | 3 +++ + 1 file changed, 3 insertions(+) + +--- a/drivers/net/wireless/ath/ath11k/dp_tx.c ++++ b/drivers/net/wireless/ath/ath11k/dp_tx.c +@@ -622,6 +622,9 @@ int ath11k_dp_tx_send_reo_cmd(struct ath + struct hal_srng *cmd_ring; + int cmd_num; + ++ if (test_bit(ATH11K_FLAG_CRASH_FLUSH, &ab->dev_flags)) ++ return -ESHUTDOWN; ++ + cmd_ring = &ab->hal.srng_list[dp->reo_cmd_ring.ring_id]; + cmd_num = ath11k_hal_reo_cmd_send(ab, cmd_ring, type, cmd); + diff --git a/package/kernel/mac80211/patches/ath11k/0032-ath11k-Avoid-No-VIF-found-warning-message.patch b/package/kernel/mac80211/patches/ath11k/0032-ath11k-Avoid-No-VIF-found-warning-message.patch new file mode 100644 index 000000000..8fa03018e --- /dev/null +++ b/package/kernel/mac80211/patches/ath11k/0032-ath11k-Avoid-No-VIF-found-warning-message.patch @@ -0,0 +1,44 @@ +From 79feedfea7793d91293ab72fac5fc66aae0c6a85 Mon Sep 17 00:00:00 2001 +From: Karthikeyan Periyasamy +Date: Tue, 28 Sep 2021 12:05:41 +0300 +Subject: [PATCH 032/120] ath11k: Avoid "No VIF found" warning message + +Facing below warning prints when we do wifi down in multiple VAPs scenario. + +warning print: + +ath11k c000000.wifi: No VIF found for vdev 2 +... +ath11k c000000.wifi: No VIF found for vdev 0 + +In ath11k_mac_get_arvif_by_vdev_id(), we iterate all the radio to get the +arvif for the requested vdev_id through ath11k_mac_get_arvif(). +ath11k_mac_get_arvif() throws a warning message if the given vdev_id is +not found in the given radio. So to avoid the warning message, add +the allocated_vdev_map cross check against the given vdev_id before using +ath11k_mac_get_arvif() to ensure that vdev_id is allocated in the +given radio. + +Tested-on: IPQ8074 hw2.0 AHB WLAN.HK.2.4.0.1-01492-QCAHKSWPL_SILICONZ-1 +Tested-on: IPQ6018 hw1.0 AHB WLAN.HK.2.4.0.1-00330-QCAHKSWPL_SILICONZ-1 + +Signed-off-by: Karthikeyan Periyasamy +Signed-off-by: Jouni Malinen +Signed-off-by: Kalle Valo +Link: https://lore.kernel.org/r/20210721212029.142388-8-jouni@codeaurora.org +--- + drivers/net/wireless/ath/ath11k/mac.c | 3 ++- + 1 file changed, 2 insertions(+), 1 deletion(-) + +--- a/drivers/net/wireless/ath/ath11k/mac.c ++++ b/drivers/net/wireless/ath/ath11k/mac.c +@@ -500,7 +500,8 @@ struct ath11k_vif *ath11k_mac_get_arvif_ + + for (i = 0; i < ab->num_radios; i++) { + pdev = rcu_dereference(ab->pdevs_active[i]); +- if (pdev && pdev->ar) { ++ if (pdev && pdev->ar && ++ (pdev->ar->allocated_vdev_map & (1LL << vdev_id))) { + arvif = ath11k_mac_get_arvif(pdev->ar, vdev_id); + if (arvif) + return arvif; diff --git a/package/kernel/mac80211/patches/ath11k/0033-ath11k-Add-wmi-peer-create-conf-event-in-wmi_tlv_eve.patch b/package/kernel/mac80211/patches/ath11k/0033-ath11k-Add-wmi-peer-create-conf-event-in-wmi_tlv_eve.patch new file mode 100644 index 000000000..ad9c3d67d --- /dev/null +++ b/package/kernel/mac80211/patches/ath11k/0033-ath11k-Add-wmi-peer-create-conf-event-in-wmi_tlv_eve.patch @@ -0,0 +1,51 @@ +From 94a6df31dcf042f74db8209680d04546ce964ad5 Mon Sep 17 00:00:00 2001 +From: P Praneesh +Date: Tue, 28 Sep 2021 12:05:41 +0300 +Subject: [PATCH 033/120] ath11k: Add wmi peer create conf event in + wmi_tlv_event_id + +When the driver sends a peer create cmd, the firmware responds with +WMI_PEER_CREATE_CONF_EVENTID to confirm the firmware received +WMI_PEER_CREATE_CMDID. Since the peer create conf event is not handled +in ath11k_wmi_tlv_op_rx, we are getting unknown event id warning prints +during peer creation. + +Add WMI_PEER_CREATE_CONF_EVENTID in wmi_tlv_event_id and handle +the same as unsupported event id under wmi logs. + +warning prints: +[ 4382.230817] ath11k_pci 0000:01:00.0: Unknown eventid: 0x601a + +Tested-on: IPQ8074 hw2.0 AHB WLAN.HK.2.4.0.1-01695-QCAHKSWPL_SILICONZ-1 + +Signed-off-by: P Praneesh +Signed-off-by: Jouni Malinen +Signed-off-by: Kalle Valo +Link: https://lore.kernel.org/r/20210721212029.142388-9-jouni@codeaurora.org +--- + drivers/net/wireless/ath/ath11k/wmi.c | 1 + + drivers/net/wireless/ath/ath11k/wmi.h | 3 +++ + 2 files changed, 4 insertions(+) + +--- a/drivers/net/wireless/ath/ath11k/wmi.c ++++ b/drivers/net/wireless/ath/ath11k/wmi.c +@@ -7136,6 +7136,7 @@ static void ath11k_wmi_tlv_op_rx(struct + case WMI_TWT_ENABLE_EVENTID: + case WMI_TWT_DISABLE_EVENTID: + case WMI_PDEV_DMA_RING_CFG_RSP_EVENTID: ++ case WMI_PEER_CREATE_CONF_EVENTID: + ath11k_dbg(ab, ATH11K_DBG_WMI, + "ignoring unsupported event 0x%x\n", id); + break; +--- a/drivers/net/wireless/ath/ath11k/wmi.h ++++ b/drivers/net/wireless/ath/ath11k/wmi.h +@@ -663,6 +663,9 @@ enum wmi_tlv_event_id { + WMI_PEER_RESERVED9_EVENTID, + WMI_PEER_RESERVED10_EVENTID, + WMI_PEER_OPER_MODE_CHANGE_EVENTID, ++ WMI_PEER_TX_PN_RESPONSE_EVENTID, ++ WMI_PEER_CFR_CAPTURE_EVENTID, ++ WMI_PEER_CREATE_CONF_EVENTID, + WMI_MGMT_RX_EVENTID = WMI_TLV_CMD(WMI_GRP_MGMT), + WMI_HOST_SWBA_EVENTID, + WMI_TBTTOFFSET_UPDATE_EVENTID, diff --git a/package/kernel/mac80211/patches/ath11k/0034-ath11k-add-channel-2-into-6-GHz-channel-list.patch b/package/kernel/mac80211/patches/ath11k/0034-ath11k-add-channel-2-into-6-GHz-channel-list.patch new file mode 100644 index 000000000..353296a9a --- /dev/null +++ b/package/kernel/mac80211/patches/ath11k/0034-ath11k-add-channel-2-into-6-GHz-channel-list.patch @@ -0,0 +1,43 @@ +From 4a9550f536cc9c62210f77d875f000e560fc64b1 Mon Sep 17 00:00:00 2001 +From: Pradeep Kumar Chitrapu +Date: Tue, 28 Sep 2021 14:00:43 +0300 +Subject: [PATCH 034/120] ath11k: add channel 2 into 6 GHz channel list + +Add support for the 6 GHz channel 2 with center frequency 5935 MHz and +operating class 136 per IEEE Std 802.11ax-2021, Table E-4. + +Signed-off-by: Pradeep Kumar Chitrapu +Signed-off-by: Jouni Malinen +Signed-off-by: Kalle Valo +Link: https://lore.kernel.org/r/20210722102054.43419-1-jouni@codeaurora.org +--- + drivers/net/wireless/ath/ath11k/core.h | 4 ++-- + drivers/net/wireless/ath/ath11k/mac.c | 3 +++ + 2 files changed, 5 insertions(+), 2 deletions(-) + +--- a/drivers/net/wireless/ath/ath11k/core.h ++++ b/drivers/net/wireless/ath/ath11k/core.h +@@ -387,9 +387,9 @@ struct ath11k_sta { + }; + + #define ATH11K_MIN_5G_FREQ 4150 +-#define ATH11K_MIN_6G_FREQ 5945 ++#define ATH11K_MIN_6G_FREQ 5925 + #define ATH11K_MAX_6G_FREQ 7115 +-#define ATH11K_NUM_CHANS 100 ++#define ATH11K_NUM_CHANS 101 + #define ATH11K_MAX_5G_CHAN 173 + + enum ath11k_state { +--- a/drivers/net/wireless/ath/ath11k/mac.c ++++ b/drivers/net/wireless/ath/ath11k/mac.c +@@ -150,6 +150,9 @@ static const struct ieee80211_channel at + CHAN6G(225, 7075, 0), + CHAN6G(229, 7095, 0), + CHAN6G(233, 7115, 0), ++ ++ /* new addition in IEEE Std 802.11ax-2021 */ ++ CHAN6G(2, 5935, 0), + }; + + static struct ieee80211_rate ath11k_legacy_rates[] = { diff --git a/package/kernel/mac80211/patches/ath11k/0036-ath11k-fix-survey-dump-collection-in-6-GHz.patch b/package/kernel/mac80211/patches/ath11k/0036-ath11k-fix-survey-dump-collection-in-6-GHz.patch new file mode 100644 index 000000000..4198732aa --- /dev/null +++ b/package/kernel/mac80211/patches/ath11k/0036-ath11k-fix-survey-dump-collection-in-6-GHz.patch @@ -0,0 +1,35 @@ +From b6b142f644d2d88e2ceabe0aa4479e0a09ba1ea9 Mon Sep 17 00:00:00 2001 +From: Pradeep Kumar Chitrapu +Date: Tue, 28 Sep 2021 14:00:43 +0300 +Subject: [PATCH 036/120] ath11k: fix survey dump collection in 6 GHz + +When ath11k receives survey request, choose the 6 GHz band when enabled. +Without this, survey request does not include any 6 GHz band results, +thereby causing auto channel selection to fail. + +Tested-on: QCN9074 hw1.0 PCI WLAN.HK.2.4.0.1-01386-QCAHKSWPL_SILICONZ-1 + +Signed-off-by: Pradeep Kumar Chitrapu +Signed-off-by: Jouni Malinen +Signed-off-by: Kalle Valo +Link: https://lore.kernel.org/r/20210722102054.43419-3-jouni@codeaurora.org +--- + drivers/net/wireless/ath/ath11k/mac.c | 6 ++++++ + 1 file changed, 6 insertions(+) + +--- a/drivers/net/wireless/ath/ath11k/mac.c ++++ b/drivers/net/wireless/ath/ath11k/mac.c +@@ -7172,7 +7172,13 @@ static int ath11k_mac_op_get_survey(stru + + if (!sband) + sband = hw->wiphy->bands[NL80211_BAND_5GHZ]; ++ if (sband && idx >= sband->n_channels) { ++ idx -= sband->n_channels; ++ sband = NULL; ++ } + ++ if (!sband) ++ sband = hw->wiphy->bands[NL80211_BAND_6GHZ]; + if (!sband || idx >= sband->n_channels) { + ret = -ENOENT; + goto exit; diff --git a/package/kernel/mac80211/patches/ath11k/0037-ath11k-re-enable-ht_cap-vht_cap-for-5G-band-for-WCN6.patch b/package/kernel/mac80211/patches/ath11k/0037-ath11k-re-enable-ht_cap-vht_cap-for-5G-band-for-WCN6.patch new file mode 100644 index 000000000..a21d07a93 --- /dev/null +++ b/package/kernel/mac80211/patches/ath11k/0037-ath11k-re-enable-ht_cap-vht_cap-for-5G-band-for-WCN6.patch @@ -0,0 +1,35 @@ +From 54f40f552afd5a07e635a52221ec4b0ce765c374 Mon Sep 17 00:00:00 2001 +From: Wen Gong +Date: Tue, 28 Sep 2021 14:00:43 +0300 +Subject: [PATCH 037/120] ath11k: re-enable ht_cap/vht_cap for 5G band for + WCN6855 + +WCN6855 uses single_pdev_only, so it supports both the 5G and 6G bands +in the same ath11k/pdev and it needs to enable ht_cap/vht_cap for the 5G +band, otherwise it will downgrade to non-HT mode for the 5G band. Some +chips like QCN9074 only support the 6G band, not the 5G band, and use +the flag ar->supports_6ghz which is true to discard ht_cap/vht_cap. + +Tested-on: WCN6855 hw2.0 PCI WLAN.HSP.1.1-01720.1-QCAHSPSWPL_V1_V2_SILICONZ_LITE-1 + +Signed-off-by: Wen Gong +Signed-off-by: Jouni Malinen +Signed-off-by: Kalle Valo +Link: https://lore.kernel.org/r/20210804181217.88751-2-jouni@codeaurora.org +--- + drivers/net/wireless/ath/ath11k/mac.c | 4 +++- + 1 file changed, 3 insertions(+), 1 deletion(-) + +--- a/drivers/net/wireless/ath/ath11k/mac.c ++++ b/drivers/net/wireless/ath/ath11k/mac.c +@@ -4545,7 +4545,9 @@ static void ath11k_mac_setup_ht_vht_cap( + rate_cap_rx_chainmask); + } + +- if (cap->supported_bands & WMI_HOST_WLAN_5G_CAP && !ar->supports_6ghz) { ++ if (cap->supported_bands & WMI_HOST_WLAN_5G_CAP && ++ (ar->ab->hw_params.single_pdev_only || ++ !ar->supports_6ghz)) { + band = &ar->mac.sbands[NL80211_BAND_5GHZ]; + ht_cap = cap->band[NL80211_BAND_5GHZ].ht_cap_info; + if (ht_cap_info) diff --git a/package/kernel/mac80211/patches/ath11k/0038-ath11k-enable-6G-channels-for-WCN6855.patch b/package/kernel/mac80211/patches/ath11k/0038-ath11k-enable-6G-channels-for-WCN6855.patch new file mode 100644 index 000000000..0e6f52553 --- /dev/null +++ b/package/kernel/mac80211/patches/ath11k/0038-ath11k-enable-6G-channels-for-WCN6855.patch @@ -0,0 +1,98 @@ +From 74bba5e5ba45d511a944082d76b64cc1849e4c2e Mon Sep 17 00:00:00 2001 +From: Wen Gong +Date: Tue, 28 Sep 2021 14:00:43 +0300 +Subject: [PATCH 038/120] ath11k: enable 6G channels for WCN6855 + +For some chips such as WCN6855, single_pdev_only is set in struct +ath11k_hw_params which means ath11k calls ieee80211_register_hw() only +once and create only one device interface, and that device interface +supports all 2G/5G/6G channels. + +ath11k_mac_setup_channels_rates() sets up the channels and it is called +for each device interface. It is called only once for single_pdev_only, +and then set up all channels for 2G/5G/6G. The logic of +ath11k_mac_setup_channels_rates() is not suitable for single_pdev_only, +it leads to all 6G channels being disabled for the device interface +which is single_pdev_only such as WCN6855. + +Add channel frequency checks for the 6G band and enable the 6G channels +properly based on what is supported by the chip. + +Tested-on: WCN6855 hw2.0 PCI WLAN.HSP.1.1-01720.1-QCAHSPSWPL_V1_V2_SILICONZ_LITE-1 + +Signed-off-by: Wen Gong +Signed-off-by: Jouni Malinen +Signed-off-by: Kalle Valo +Link: https://lore.kernel.org/r/20210804181217.88751-3-jouni@codeaurora.org +--- + drivers/net/wireless/ath/ath11k/mac.c | 25 ++++++++++++++++--------- + 1 file changed, 16 insertions(+), 9 deletions(-) + +--- a/drivers/net/wireless/ath/ath11k/mac.c ++++ b/drivers/net/wireless/ath/ath11k/mac.c +@@ -7312,7 +7312,7 @@ static int ath11k_mac_setup_channels_rat + u32 supported_bands) + { + struct ieee80211_supported_band *band; +- struct ath11k_hal_reg_capabilities_ext *reg_cap; ++ struct ath11k_hal_reg_capabilities_ext *reg_cap, *temp_reg_cap; + void *channels; + u32 phy_id; + +@@ -7322,6 +7322,7 @@ static int ath11k_mac_setup_channels_rat + ATH11K_NUM_CHANS); + + reg_cap = &ar->ab->hal_reg_cap[ar->pdev_idx]; ++ temp_reg_cap = reg_cap; + + if (supported_bands & WMI_HOST_WLAN_2G_CAP) { + channels = kmemdup(ath11k_2ghz_channels, +@@ -7340,11 +7341,11 @@ static int ath11k_mac_setup_channels_rat + + if (ar->ab->hw_params.single_pdev_only) { + phy_id = ath11k_get_phy_id(ar, WMI_HOST_WLAN_2G_CAP); +- reg_cap = &ar->ab->hal_reg_cap[phy_id]; ++ temp_reg_cap = &ar->ab->hal_reg_cap[phy_id]; + } + ath11k_mac_update_ch_list(ar, band, +- reg_cap->low_2ghz_chan, +- reg_cap->high_2ghz_chan); ++ temp_reg_cap->low_2ghz_chan, ++ temp_reg_cap->high_2ghz_chan); + } + + if (supported_bands & WMI_HOST_WLAN_5G_CAP) { +@@ -7364,9 +7365,15 @@ static int ath11k_mac_setup_channels_rat + band->n_bitrates = ath11k_a_rates_size; + band->bitrates = ath11k_a_rates; + ar->hw->wiphy->bands[NL80211_BAND_6GHZ] = band; ++ ++ if (ar->ab->hw_params.single_pdev_only) { ++ phy_id = ath11k_get_phy_id(ar, WMI_HOST_WLAN_5G_CAP); ++ temp_reg_cap = &ar->ab->hal_reg_cap[phy_id]; ++ } ++ + ath11k_mac_update_ch_list(ar, band, +- reg_cap->low_5ghz_chan, +- reg_cap->high_5ghz_chan); ++ temp_reg_cap->low_5ghz_chan, ++ temp_reg_cap->high_5ghz_chan); + } + + if (reg_cap->low_5ghz_chan < ATH11K_MIN_6G_FREQ) { +@@ -7389,12 +7396,12 @@ static int ath11k_mac_setup_channels_rat + + if (ar->ab->hw_params.single_pdev_only) { + phy_id = ath11k_get_phy_id(ar, WMI_HOST_WLAN_5G_CAP); +- reg_cap = &ar->ab->hal_reg_cap[phy_id]; ++ temp_reg_cap = &ar->ab->hal_reg_cap[phy_id]; + } + + ath11k_mac_update_ch_list(ar, band, +- reg_cap->low_5ghz_chan, +- reg_cap->high_5ghz_chan); ++ temp_reg_cap->low_5ghz_chan, ++ temp_reg_cap->high_5ghz_chan); + } + } + diff --git a/package/kernel/mac80211/patches/ath11k/0039-ath11k-copy-cap-info-of-6G-band-under-WMI_HOST_WLAN_.patch b/package/kernel/mac80211/patches/ath11k/0039-ath11k-copy-cap-info-of-6G-band-under-WMI_HOST_WLAN_.patch new file mode 100644 index 000000000..135a5e8f0 --- /dev/null +++ b/package/kernel/mac80211/patches/ath11k/0039-ath11k-copy-cap-info-of-6G-band-under-WMI_HOST_WLAN_.patch @@ -0,0 +1,54 @@ +From 0f17ae43823b237c73ff138bc067229f7c57e3a2 Mon Sep 17 00:00:00 2001 +From: Wen Gong +Date: Tue, 28 Sep 2021 14:00:43 +0300 +Subject: [PATCH 039/120] ath11k: copy cap info of 6G band under + WMI_HOST_WLAN_5G_CAP for WCN6855 + +WCN6855 has 2 phys, one is 2G, another is 5G/6G, so it should copy the +cap info of 6G band under the check of WMI_HOST_WLAN_5G_CAP as well as +for the 5G band. Some chips like QCN9074 only have 6G, not have 2G and +5G, and this 6G capability is also under WMI_HOST_WLAN_5G_CAP, so this +change will not disturb it. + +Tested-on: WCN6855 hw2.0 PCI WLAN.HSP.1.1-01720.1-QCAHSPSWPL_V1_V2_SILICONZ_LITE-1 + +Signed-off-by: Wen Gong +Signed-off-by: Jouni Malinen +Signed-off-by: Kalle Valo +Link: https://lore.kernel.org/r/20210804181217.88751-4-jouni@codeaurora.org +--- + drivers/net/wireless/ath/ath11k/wmi.c | 22 +++++++++++----------- + 1 file changed, 11 insertions(+), 11 deletions(-) + +--- a/drivers/net/wireless/ath/ath11k/wmi.c ++++ b/drivers/net/wireless/ath/ath11k/wmi.c +@@ -407,18 +407,18 @@ ath11k_pull_mac_phy_cap_svc_ready_ext(st + sizeof(u32) * PSOC_HOST_MAX_PHY_SIZE); + memcpy(&cap_band->he_ppet, &mac_phy_caps->he_ppet5g, + sizeof(struct ath11k_ppe_threshold)); +- } + +- cap_band = &pdev_cap->band[NL80211_BAND_6GHZ]; +- cap_band->max_bw_supported = mac_phy_caps->max_bw_supported_5g; +- cap_band->ht_cap_info = mac_phy_caps->ht_cap_info_5g; +- cap_band->he_cap_info[0] = mac_phy_caps->he_cap_info_5g; +- cap_band->he_cap_info[1] = mac_phy_caps->he_cap_info_5g_ext; +- cap_band->he_mcs = mac_phy_caps->he_supp_mcs_5g; +- memcpy(cap_band->he_cap_phy_info, &mac_phy_caps->he_cap_phy_info_5g, +- sizeof(u32) * PSOC_HOST_MAX_PHY_SIZE); +- memcpy(&cap_band->he_ppet, &mac_phy_caps->he_ppet5g, +- sizeof(struct ath11k_ppe_threshold)); ++ cap_band = &pdev_cap->band[NL80211_BAND_6GHZ]; ++ cap_band->max_bw_supported = mac_phy_caps->max_bw_supported_5g; ++ cap_band->ht_cap_info = mac_phy_caps->ht_cap_info_5g; ++ cap_band->he_cap_info[0] = mac_phy_caps->he_cap_info_5g; ++ cap_band->he_cap_info[1] = mac_phy_caps->he_cap_info_5g_ext; ++ cap_band->he_mcs = mac_phy_caps->he_supp_mcs_5g; ++ memcpy(cap_band->he_cap_phy_info, &mac_phy_caps->he_cap_phy_info_5g, ++ sizeof(u32) * PSOC_HOST_MAX_PHY_SIZE); ++ memcpy(&cap_band->he_ppet, &mac_phy_caps->he_ppet5g, ++ sizeof(struct ath11k_ppe_threshold)); ++ } + + return 0; + } diff --git a/package/kernel/mac80211/patches/ath11k/0040-ath11k-Drop-MSDU-with-length-error-in-DP-rx-path.patch b/package/kernel/mac80211/patches/ath11k/0040-ath11k-Drop-MSDU-with-length-error-in-DP-rx-path.patch new file mode 100644 index 000000000..85901c3ce --- /dev/null +++ b/package/kernel/mac80211/patches/ath11k/0040-ath11k-Drop-MSDU-with-length-error-in-DP-rx-path.patch @@ -0,0 +1,57 @@ +From cd18ed4cf8051ceb8590263f5914cb9bb58b0f25 Mon Sep 17 00:00:00 2001 +From: Baochen Qiang +Date: Tue, 28 Sep 2021 14:00:43 +0300 +Subject: [PATCH 040/120] ath11k: Drop MSDU with length error in DP rx path + +There are MSDUs whose length are invalid. For example, +attackers may inject on purpose truncated A-MSDUs with +invalid MSDU length. + +Such MSDUs are marked with an err bit set in rx attention +tlvs, so we can check and drop them. + +Tested-on: QCA6390 hw2.0 PCI WLAN.HST.1.0.1-01740-QCAHSTSWPLZ_V2_TO_X86-1 +Tested-on: WCN6855 hw2.0 PCI WLAN.HSP.1.1-01720.1-QCAHSPSWPL_V1_V2_SILICONZ_LITE-1 + +Signed-off-by: Baochen Qiang +Signed-off-by: Jouni Malinen +Signed-off-by: Kalle Valo +Link: https://lore.kernel.org/r/20210913180246.193388-2-jouni@codeaurora.org +--- + drivers/net/wireless/ath/ath11k/dp_rx.c | 18 ++++++++++++++++++ + 1 file changed, 18 insertions(+) + +--- a/drivers/net/wireless/ath/ath11k/dp_rx.c ++++ b/drivers/net/wireless/ath/ath11k/dp_rx.c +@@ -142,6 +142,18 @@ static u32 ath11k_dp_rx_h_attn_mpdu_err( + return errmap; + } + ++static bool ath11k_dp_rx_h_attn_msdu_len_err(struct ath11k_base *ab, ++ struct hal_rx_desc *desc) ++{ ++ struct rx_attention *rx_attention; ++ u32 errmap; ++ ++ rx_attention = ath11k_dp_rx_get_attention(ab, desc); ++ errmap = ath11k_dp_rx_h_attn_mpdu_err(rx_attention); ++ ++ return errmap & DP_RX_MPDU_ERR_MSDU_LEN; ++} ++ + static u16 ath11k_dp_rx_h_msdu_start_msdu_len(struct ath11k_base *ab, + struct hal_rx_desc *desc) + { +@@ -2525,6 +2537,12 @@ static int ath11k_dp_rx_process_msdu(str + } + + rx_desc = (struct hal_rx_desc *)msdu->data; ++ if (ath11k_dp_rx_h_attn_msdu_len_err(ab, rx_desc)) { ++ ath11k_warn(ar->ab, "msdu len not valid\n"); ++ ret = -EIO; ++ goto free_out; ++ } ++ + lrx_desc = (struct hal_rx_desc *)last_buf->data; + rx_attention = ath11k_dp_rx_get_attention(ab, lrx_desc); + if (!ath11k_dp_rx_h_attn_msdu_done(rx_attention)) { diff --git a/package/kernel/mac80211/patches/ath11k/0041-ath11k-Fix-inaccessible-debug-registers.patch b/package/kernel/mac80211/patches/ath11k/0041-ath11k-Fix-inaccessible-debug-registers.patch new file mode 100644 index 000000000..f05438662 --- /dev/null +++ b/package/kernel/mac80211/patches/ath11k/0041-ath11k-Fix-inaccessible-debug-registers.patch @@ -0,0 +1,46 @@ +From 8a0b899f169d6b6102918327d026922140194fff Mon Sep 17 00:00:00 2001 +From: Baochen Qiang +Date: Tue, 28 Sep 2021 14:00:44 +0300 +Subject: [PATCH 041/120] ath11k: Fix inaccessible debug registers + +Current code clears debug registers after SOC global reset performed +in ath11k_pci_sw_reset. However at that time those registers are +not accessible due to reset, thus they are actually not cleared at all. +For WCN6855, it may cause target fail to initialize. This issue can be +fixed by moving clear action ahead. + +In addition, on some specific platforms, need to add delay to wait +those registers to become accessible. + +Tested-on: WCN6855 hw2.0 PCI WLAN.HSP.1.1-01720.1-QCAHSPSWPL_V1_V2_SILICONZ_LITE-1 + +Signed-off-by: Baochen Qiang +Signed-off-by: Jouni Malinen +Signed-off-by: Kalle Valo +Link: https://lore.kernel.org/r/20210913180246.193388-3-jouni@codeaurora.org +--- + drivers/net/wireless/ath/ath11k/pci.c | 4 +++- + 1 file changed, 3 insertions(+), 1 deletion(-) + +--- a/drivers/net/wireless/ath/ath11k/pci.c ++++ b/drivers/net/wireless/ath/ath11k/pci.c +@@ -430,6 +430,8 @@ static void ath11k_pci_force_wake(struct + + static void ath11k_pci_sw_reset(struct ath11k_base *ab, bool power_on) + { ++ mdelay(100); ++ + if (power_on) { + ath11k_pci_enable_ltssm(ab); + ath11k_pci_clear_all_intrs(ab); +@@ -439,9 +441,9 @@ static void ath11k_pci_sw_reset(struct a + } + + ath11k_mhi_clear_vector(ab); ++ ath11k_pci_clear_dbg_registers(ab); + ath11k_pci_soc_global_reset(ab); + ath11k_mhi_set_mhictrl_reset(ab); +- ath11k_pci_clear_dbg_registers(ab); + } + + int ath11k_pci_get_msi_irq(struct device *dev, unsigned int vector) diff --git a/package/kernel/mac80211/patches/ath11k/0043-ath11k-Rename-macro-ARRAY_TO_STRING-to-PRINT_ARRAY_T.patch b/package/kernel/mac80211/patches/ath11k/0043-ath11k-Rename-macro-ARRAY_TO_STRING-to-PRINT_ARRAY_T.patch new file mode 100644 index 000000000..e5c7ea4a0 --- /dev/null +++ b/package/kernel/mac80211/patches/ath11k/0043-ath11k-Rename-macro-ARRAY_TO_STRING-to-PRINT_ARRAY_T.patch @@ -0,0 +1,853 @@ +From 9e2e2d7a4dd490ff6e95e37611070d3b3a9cf58b Mon Sep 17 00:00:00 2001 +From: Seevalamuthu Mariappan +Date: Tue, 28 Sep 2021 14:00:44 +0300 +Subject: [PATCH 043/120] ath11k: Rename macro ARRAY_TO_STRING to + PRINT_ARRAY_TO_BUF + +Renaming of macro is done to describe the macro functionality +better as the macro functionality is modified in next patch-sets. +No functional changes are done. + +Signed-off-by: Seevalamuthu Mariappan +Signed-off-by: Jouni Malinen +Signed-off-by: Kalle Valo +Link: https://lore.kernel.org/r/20210913223148.208026-2-jouni@codeaurora.org +--- + .../wireless/ath/ath11k/debugfs_htt_stats.c | 378 +++++++++--------- + 1 file changed, 189 insertions(+), 189 deletions(-) + +--- a/drivers/net/wireless/ath/ath11k/debugfs_htt_stats.c ++++ b/drivers/net/wireless/ath/ath11k/debugfs_htt_stats.c +@@ -18,7 +18,7 @@ + + #define HTT_TLV_HDR_LEN 4 + +-#define ARRAY_TO_STRING(out, arr, len) \ ++#define PRINT_ARRAY_TO_BUF(out, arr, len) \ + do { \ + int index = 0; u8 i; \ + for (i = 0; i < len; i++) { \ +@@ -195,7 +195,7 @@ htt_print_tx_pdev_stats_urrn_tlv_v(const + + len += HTT_DBG_OUT(buf + len, buf_len - len, "HTT_TX_PDEV_STATS_URRN_TLV_V:"); + +- ARRAY_TO_STRING(urrn_stats, htt_stats_buf->urrn_stats, num_elems); ++ PRINT_ARRAY_TO_BUF(urrn_stats, htt_stats_buf->urrn_stats, num_elems); + len += HTT_DBG_OUT(buf + len, buf_len - len, "urrn_stats = %s\n", urrn_stats); + + if (len >= buf_len) +@@ -220,7 +220,7 @@ htt_print_tx_pdev_stats_flush_tlv_v(cons + + len += HTT_DBG_OUT(buf + len, buf_len - len, "HTT_TX_PDEV_STATS_FLUSH_TLV_V:"); + +- ARRAY_TO_STRING(flush_errs, htt_stats_buf->flush_errs, num_elems); ++ PRINT_ARRAY_TO_BUF(flush_errs, htt_stats_buf->flush_errs, num_elems); + len += HTT_DBG_OUT(buf + len, buf_len - len, "flush_errs = %s\n", flush_errs); + + if (len >= buf_len) +@@ -245,7 +245,7 @@ htt_print_tx_pdev_stats_sifs_tlv_v(const + + len += HTT_DBG_OUT(buf + len, buf_len - len, "HTT_TX_PDEV_STATS_SIFS_TLV_V:"); + +- ARRAY_TO_STRING(sifs_status, htt_stats_buf->sifs_status, num_elems); ++ PRINT_ARRAY_TO_BUF(sifs_status, htt_stats_buf->sifs_status, num_elems); + len += HTT_DBG_OUT(buf + len, buf_len - len, "sifs_status = %s\n", + sifs_status); + +@@ -271,7 +271,7 @@ htt_print_tx_pdev_stats_phy_err_tlv_v(co + + len += HTT_DBG_OUT(buf + len, buf_len - len, "HTT_TX_PDEV_STATS_PHY_ERR_TLV_V:"); + +- ARRAY_TO_STRING(phy_errs, htt_stats_buf->phy_errs, num_elems); ++ PRINT_ARRAY_TO_BUF(phy_errs, htt_stats_buf->phy_errs, num_elems); + len += HTT_DBG_OUT(buf + len, buf_len - len, "phy_errs = %s\n", phy_errs); + + if (len >= buf_len) +@@ -297,7 +297,7 @@ htt_print_tx_pdev_stats_sifs_hist_tlv_v( + len += HTT_DBG_OUT(buf + len, buf_len - len, + "HTT_TX_PDEV_STATS_SIFS_HIST_TLV_V:"); + +- ARRAY_TO_STRING(sifs_hist_status, htt_stats_buf->sifs_hist_status, num_elems); ++ PRINT_ARRAY_TO_BUF(sifs_hist_status, htt_stats_buf->sifs_hist_status, num_elems); + len += HTT_DBG_OUT(buf + len, buf_len - len, "sifs_hist_status = %s\n", + sifs_hist_status); + +@@ -363,9 +363,9 @@ htt_print_tx_pdev_stats_tried_mpdu_cnt_h + htt_stats_buf->hist_bin_size); + + if (required_buffer_size < HTT_MAX_STRING_LEN) { +- ARRAY_TO_STRING(tried_mpdu_cnt_hist, +- htt_stats_buf->tried_mpdu_cnt_hist, +- num_elements); ++ PRINT_ARRAY_TO_BUF(tried_mpdu_cnt_hist, ++ htt_stats_buf->tried_mpdu_cnt_hist, ++ num_elements); + len += HTT_DBG_OUT(buf + len, buf_len - len, "tried_mpdu_cnt_hist = %s\n", + tried_mpdu_cnt_hist); + } else { +@@ -667,9 +667,9 @@ static inline void htt_print_counter_tlv + + len += HTT_DBG_OUT(buf + len, buf_len - len, "HTT_COUNTER_TLV:"); + +- ARRAY_TO_STRING(counter_name, +- htt_stats_buf->counter_name, +- HTT_MAX_COUNTER_NAME); ++ PRINT_ARRAY_TO_BUF(counter_name, ++ htt_stats_buf->counter_name, ++ HTT_MAX_COUNTER_NAME); + len += HTT_DBG_OUT(buf + len, buf_len - len, "counter_name = %s ", counter_name); + len += HTT_DBG_OUT(buf + len, buf_len - len, "count = %u\n", + htt_stats_buf->count); +@@ -794,54 +794,54 @@ static inline void htt_print_tx_peer_rat + htt_stats_buf->ack_rssi); + + memset(str_buf, 0x0, HTT_MAX_STRING_LEN); +- ARRAY_TO_STRING(str_buf, htt_stats_buf->tx_mcs, +- HTT_TX_PDEV_STATS_NUM_MCS_COUNTERS); ++ PRINT_ARRAY_TO_BUF(str_buf, htt_stats_buf->tx_mcs, ++ HTT_TX_PDEV_STATS_NUM_MCS_COUNTERS); + len += HTT_DBG_OUT(buf + len, buf_len - len, "tx_mcs = %s ", str_buf); + + memset(str_buf, 0x0, HTT_MAX_STRING_LEN); +- ARRAY_TO_STRING(str_buf, htt_stats_buf->tx_su_mcs, +- HTT_TX_PDEV_STATS_NUM_MCS_COUNTERS); ++ PRINT_ARRAY_TO_BUF(str_buf, htt_stats_buf->tx_su_mcs, ++ HTT_TX_PDEV_STATS_NUM_MCS_COUNTERS); + len += HTT_DBG_OUT(buf + len, buf_len - len, "tx_su_mcs = %s ", str_buf); + + memset(str_buf, 0x0, HTT_MAX_STRING_LEN); +- ARRAY_TO_STRING(str_buf, htt_stats_buf->tx_mu_mcs, +- HTT_TX_PDEV_STATS_NUM_MCS_COUNTERS); ++ PRINT_ARRAY_TO_BUF(str_buf, htt_stats_buf->tx_mu_mcs, ++ HTT_TX_PDEV_STATS_NUM_MCS_COUNTERS); + len += HTT_DBG_OUT(buf + len, buf_len - len, "tx_mu_mcs = %s ", str_buf); + + memset(str_buf, 0x0, HTT_MAX_STRING_LEN); +- ARRAY_TO_STRING(str_buf, +- htt_stats_buf->tx_nss, +- HTT_TX_PDEV_STATS_NUM_SPATIAL_STREAMS); ++ PRINT_ARRAY_TO_BUF(str_buf, ++ htt_stats_buf->tx_nss, ++ HTT_TX_PDEV_STATS_NUM_SPATIAL_STREAMS); + len += HTT_DBG_OUT(buf + len, buf_len - len, "tx_nss = %s ", str_buf); + + memset(str_buf, 0x0, HTT_MAX_STRING_LEN); +- ARRAY_TO_STRING(str_buf, +- htt_stats_buf->tx_bw, +- HTT_TX_PDEV_STATS_NUM_BW_COUNTERS); ++ PRINT_ARRAY_TO_BUF(str_buf, ++ htt_stats_buf->tx_bw, ++ HTT_TX_PDEV_STATS_NUM_BW_COUNTERS); + len += HTT_DBG_OUT(buf + len, buf_len - len, "tx_bw = %s ", str_buf); + + memset(str_buf, 0x0, HTT_MAX_STRING_LEN); +- ARRAY_TO_STRING(str_buf, htt_stats_buf->tx_stbc, +- HTT_TX_PDEV_STATS_NUM_MCS_COUNTERS); ++ PRINT_ARRAY_TO_BUF(str_buf, htt_stats_buf->tx_stbc, ++ HTT_TX_PDEV_STATS_NUM_MCS_COUNTERS); + len += HTT_DBG_OUT(buf + len, buf_len - len, "tx_stbc = %s ", str_buf); + + memset(str_buf, 0x0, HTT_MAX_STRING_LEN); +- ARRAY_TO_STRING(str_buf, htt_stats_buf->tx_pream, +- HTT_TX_PDEV_STATS_NUM_PREAMBLE_TYPES); ++ PRINT_ARRAY_TO_BUF(str_buf, htt_stats_buf->tx_pream, ++ HTT_TX_PDEV_STATS_NUM_PREAMBLE_TYPES); + len += HTT_DBG_OUT(buf + len, buf_len - len, "tx_pream = %s ", str_buf); + + for (j = 0; j < HTT_TX_PEER_STATS_NUM_GI_COUNTERS; j++) { +- ARRAY_TO_STRING(tx_gi[j], +- htt_stats_buf->tx_gi[j], +- HTT_TX_PEER_STATS_NUM_MCS_COUNTERS); ++ PRINT_ARRAY_TO_BUF(tx_gi[j], ++ htt_stats_buf->tx_gi[j], ++ HTT_TX_PEER_STATS_NUM_MCS_COUNTERS); + len += HTT_DBG_OUT(buf + len, buf_len - len, "tx_gi[%u] = %s ", +- j, tx_gi[j]); ++ j, tx_gi[j]); + } + + memset(str_buf, 0x0, HTT_MAX_STRING_LEN); +- ARRAY_TO_STRING(str_buf, +- htt_stats_buf->tx_dcm, +- HTT_TX_PDEV_STATS_NUM_DCM_COUNTERS); ++ PRINT_ARRAY_TO_BUF(str_buf, ++ htt_stats_buf->tx_dcm, ++ HTT_TX_PDEV_STATS_NUM_DCM_COUNTERS); + len += HTT_DBG_OUT(buf + len, buf_len - len, "tx_dcm = %s\n", str_buf); + + if (len >= buf_len) +@@ -895,47 +895,47 @@ static inline void htt_print_rx_peer_rat + htt_stats_buf->rssi_comb); + + memset(str_buf, 0x0, HTT_MAX_STRING_LEN); +- ARRAY_TO_STRING(str_buf, htt_stats_buf->rx_mcs, +- HTT_RX_PDEV_STATS_NUM_MCS_COUNTERS); ++ PRINT_ARRAY_TO_BUF(str_buf, htt_stats_buf->rx_mcs, ++ HTT_RX_PDEV_STATS_NUM_MCS_COUNTERS); + len += HTT_DBG_OUT(buf + len, buf_len - len, "rx_mcs = %s ", str_buf); + + memset(str_buf, 0x0, HTT_MAX_STRING_LEN); +- ARRAY_TO_STRING(str_buf, htt_stats_buf->rx_nss, +- HTT_RX_PDEV_STATS_NUM_SPATIAL_STREAMS); ++ PRINT_ARRAY_TO_BUF(str_buf, htt_stats_buf->rx_nss, ++ HTT_RX_PDEV_STATS_NUM_SPATIAL_STREAMS); + len += HTT_DBG_OUT(buf + len, buf_len - len, "rx_nss = %s ", str_buf); + + memset(str_buf, 0x0, HTT_MAX_STRING_LEN); +- ARRAY_TO_STRING(str_buf, htt_stats_buf->rx_dcm, +- HTT_RX_PDEV_STATS_NUM_DCM_COUNTERS); ++ PRINT_ARRAY_TO_BUF(str_buf, htt_stats_buf->rx_dcm, ++ HTT_RX_PDEV_STATS_NUM_DCM_COUNTERS); + len += HTT_DBG_OUT(buf + len, buf_len - len, "rx_dcm = %s ", str_buf); + + memset(str_buf, 0x0, HTT_MAX_STRING_LEN); +- ARRAY_TO_STRING(str_buf, htt_stats_buf->rx_stbc, +- HTT_RX_PDEV_STATS_NUM_MCS_COUNTERS); ++ PRINT_ARRAY_TO_BUF(str_buf, htt_stats_buf->rx_stbc, ++ HTT_RX_PDEV_STATS_NUM_MCS_COUNTERS); + len += HTT_DBG_OUT(buf + len, buf_len - len, "rx_stbc = %s ", str_buf); + + memset(str_buf, 0x0, HTT_MAX_STRING_LEN); +- ARRAY_TO_STRING(str_buf, htt_stats_buf->rx_bw, +- HTT_RX_PDEV_STATS_NUM_BW_COUNTERS); ++ PRINT_ARRAY_TO_BUF(str_buf, htt_stats_buf->rx_bw, ++ HTT_RX_PDEV_STATS_NUM_BW_COUNTERS); + len += HTT_DBG_OUT(buf + len, buf_len - len, "rx_bw = %s ", str_buf); + + for (j = 0; j < HTT_RX_PEER_STATS_NUM_SPATIAL_STREAMS; j++) { +- ARRAY_TO_STRING(rssi_chain[j], htt_stats_buf->rssi_chain[j], +- HTT_RX_PEER_STATS_NUM_BW_COUNTERS); ++ PRINT_ARRAY_TO_BUF(rssi_chain[j], htt_stats_buf->rssi_chain[j], ++ HTT_RX_PEER_STATS_NUM_BW_COUNTERS); + len += HTT_DBG_OUT(buf + len, buf_len - len, "rssi_chain[%u] = %s ", + j, rssi_chain[j]); + } + + for (j = 0; j < HTT_RX_PEER_STATS_NUM_GI_COUNTERS; j++) { +- ARRAY_TO_STRING(rx_gi[j], htt_stats_buf->rx_gi[j], +- HTT_RX_PDEV_STATS_NUM_MCS_COUNTERS); ++ PRINT_ARRAY_TO_BUF(rx_gi[j], htt_stats_buf->rx_gi[j], ++ HTT_RX_PDEV_STATS_NUM_MCS_COUNTERS); + len += HTT_DBG_OUT(buf + len, buf_len - len, "rx_gi[%u] = %s ", +- j, rx_gi[j]); ++ j, rx_gi[j]); + } + + memset(str_buf, 0x0, HTT_MAX_STRING_LEN); +- ARRAY_TO_STRING(str_buf, htt_stats_buf->rx_pream, +- HTT_RX_PDEV_STATS_NUM_PREAMBLE_TYPES); ++ PRINT_ARRAY_TO_BUF(str_buf, htt_stats_buf->rx_pream, ++ HTT_RX_PDEV_STATS_NUM_PREAMBLE_TYPES); + len += HTT_DBG_OUT(buf + len, buf_len - len, "rx_pream = %s\n", str_buf); + + if (len >= buf_len) +@@ -1115,10 +1115,10 @@ htt_print_tx_hwq_difs_latency_stats_tlv_ + len += HTT_DBG_OUT(buf + len, buf_len - len, "hist_intvl = %u", + htt_stats_buf->hist_intvl); + +- ARRAY_TO_STRING(difs_latency_hist, htt_stats_buf->difs_latency_hist, +- data_len); ++ PRINT_ARRAY_TO_BUF(difs_latency_hist, htt_stats_buf->difs_latency_hist, ++ data_len); + len += HTT_DBG_OUT(buf + len, buf_len - len, "difs_latency_hist = %s\n", +- difs_latency_hist); ++ difs_latency_hist); + + if (len >= buf_len) + buf[buf_len - 1] = 0; +@@ -1145,7 +1145,7 @@ htt_print_tx_hwq_cmd_result_stats_tlv_v( + len += HTT_DBG_OUT(buf + len, buf_len - len, + "HTT_TX_HWQ_CMD_RESULT_STATS_TLV_V:"); + +- ARRAY_TO_STRING(cmd_result, htt_stats_buf->cmd_result, data_len); ++ PRINT_ARRAY_TO_BUF(cmd_result, htt_stats_buf->cmd_result, data_len); + + len += HTT_DBG_OUT(buf + len, buf_len - len, "cmd_result = %s\n", cmd_result); + +@@ -1173,7 +1173,7 @@ htt_print_tx_hwq_cmd_stall_stats_tlv_v(c + + len += HTT_DBG_OUT(buf + len, buf_len - len, "HTT_TX_HWQ_CMD_STALL_STATS_TLV_V:"); + +- ARRAY_TO_STRING(cmd_stall_status, htt_stats_buf->cmd_stall_status, num_elems); ++ PRINT_ARRAY_TO_BUF(cmd_stall_status, htt_stats_buf->cmd_stall_status, num_elems); + len += HTT_DBG_OUT(buf + len, buf_len - len, "cmd_stall_status = %s\n", + cmd_stall_status); + +@@ -1202,7 +1202,7 @@ htt_print_tx_hwq_fes_result_stats_tlv_v( + len += HTT_DBG_OUT(buf + len, buf_len - len, + "HTT_TX_HWQ_FES_RESULT_STATS_TLV_V:"); + +- ARRAY_TO_STRING(fes_result, htt_stats_buf->fes_result, num_elems); ++ PRINT_ARRAY_TO_BUF(fes_result, htt_stats_buf->fes_result, num_elems); + len += HTT_DBG_OUT(buf + len, buf_len - len, "fes_result = %s\n", fes_result); + + if (len >= buf_len) +@@ -1233,9 +1233,9 @@ htt_print_tx_hwq_tried_mpdu_cnt_hist_tlv + htt_stats_buf->hist_bin_size); + + if (required_buffer_size < HTT_MAX_STRING_LEN) { +- ARRAY_TO_STRING(tried_mpdu_cnt_hist, +- htt_stats_buf->tried_mpdu_cnt_hist, +- num_elements); ++ PRINT_ARRAY_TO_BUF(tried_mpdu_cnt_hist, ++ htt_stats_buf->tried_mpdu_cnt_hist, ++ num_elements); + len += HTT_DBG_OUT(buf + len, buf_len - len, + "tried_mpdu_cnt_hist = %s\n", + tried_mpdu_cnt_hist); +@@ -1269,9 +1269,9 @@ htt_print_tx_hwq_txop_used_cnt_hist_tlv_ + "HTT_TX_HWQ_TXOP_USED_CNT_HIST_TLV_V:"); + + if (required_buffer_size < HTT_MAX_STRING_LEN) { +- ARRAY_TO_STRING(txop_used_cnt_hist, +- htt_stats_buf->txop_used_cnt_hist, +- num_elements); ++ PRINT_ARRAY_TO_BUF(txop_used_cnt_hist, ++ htt_stats_buf->txop_used_cnt_hist, ++ num_elements); + len += HTT_DBG_OUT(buf + len, buf_len - len, "txop_used_cnt_hist = %s\n", + txop_used_cnt_hist); + } else { +@@ -1790,8 +1790,8 @@ htt_print_sched_txq_cmd_posted_tlv_v(con + + len += HTT_DBG_OUT(buf + len, buf_len - len, "HTT_SCHED_TXQ_CMD_POSTED_TLV_V:"); + +- ARRAY_TO_STRING(sched_cmd_posted, htt_stats_buf->sched_cmd_posted, +- num_elements); ++ PRINT_ARRAY_TO_BUF(sched_cmd_posted, htt_stats_buf->sched_cmd_posted, ++ num_elements); + len += HTT_DBG_OUT(buf + len, buf_len - len, "sched_cmd_posted = %s\n", + sched_cmd_posted); + +@@ -1817,8 +1817,8 @@ htt_print_sched_txq_cmd_reaped_tlv_v(con + + len += HTT_DBG_OUT(buf + len, buf_len - len, "HTT_SCHED_TXQ_CMD_REAPED_TLV_V:"); + +- ARRAY_TO_STRING(sched_cmd_reaped, htt_stats_buf->sched_cmd_reaped, +- num_elements); ++ PRINT_ARRAY_TO_BUF(sched_cmd_reaped, htt_stats_buf->sched_cmd_reaped, ++ num_elements); + len += HTT_DBG_OUT(buf + len, buf_len - len, "sched_cmd_reaped = %s\n", + sched_cmd_reaped); + +@@ -1847,8 +1847,8 @@ htt_print_sched_txq_sched_order_su_tlv_v + len += HTT_DBG_OUT(buf + len, buf_len - len, + "HTT_SCHED_TXQ_SCHED_ORDER_SU_TLV_V:"); + +- ARRAY_TO_STRING(sched_order_su, htt_stats_buf->sched_order_su, +- sched_order_su_num_entries); ++ PRINT_ARRAY_TO_BUF(sched_order_su, htt_stats_buf->sched_order_su, ++ sched_order_su_num_entries); + len += HTT_DBG_OUT(buf + len, buf_len - len, "sched_order_su = %s\n", + sched_order_su); + +@@ -1876,8 +1876,8 @@ htt_print_sched_txq_sched_ineligibility_ + len += HTT_DBG_OUT(buf + len, buf_len - len, + "HTT_SCHED_TXQ_SCHED_INELIGIBILITY_V:"); + +- ARRAY_TO_STRING(sched_ineligibility, htt_stats_buf->sched_ineligibility, +- sched_ineligibility_num_entries); ++ PRINT_ARRAY_TO_BUF(sched_ineligibility, htt_stats_buf->sched_ineligibility, ++ sched_ineligibility_num_entries); + len += HTT_DBG_OUT(buf + len, buf_len - len, "sched_ineligibility = %s\n", + sched_ineligibility); + +@@ -1992,8 +1992,8 @@ htt_print_tx_tqm_gen_mpdu_stats_tlv_v(co + + len += HTT_DBG_OUT(buf + len, buf_len - len, "HTT_TX_TQM_GEN_MPDU_STATS_TLV_V:"); + +- ARRAY_TO_STRING(gen_mpdu_end_reason, htt_stats_buf->gen_mpdu_end_reason, +- num_elements); ++ PRINT_ARRAY_TO_BUF(gen_mpdu_end_reason, htt_stats_buf->gen_mpdu_end_reason, ++ num_elements); + len += HTT_DBG_OUT(buf + len, buf_len - len, "gen_mpdu_end_reason = %s\n", + gen_mpdu_end_reason); + +@@ -2020,8 +2020,8 @@ htt_print_tx_tqm_list_mpdu_stats_tlv_v(c + len += HTT_DBG_OUT(buf + len, buf_len - len, + "HTT_TX_TQM_LIST_MPDU_STATS_TLV_V:"); + +- ARRAY_TO_STRING(list_mpdu_end_reason, htt_stats_buf->list_mpdu_end_reason, +- num_elems); ++ PRINT_ARRAY_TO_BUF(list_mpdu_end_reason, htt_stats_buf->list_mpdu_end_reason, ++ num_elems); + len += HTT_DBG_OUT(buf + len, buf_len - len, "list_mpdu_end_reason = %s\n", + list_mpdu_end_reason); + if (len >= buf_len) +@@ -2047,8 +2047,8 @@ htt_print_tx_tqm_list_mpdu_cnt_tlv_v(con + + len += HTT_DBG_OUT(buf + len, buf_len - len, "HTT_TX_TQM_LIST_MPDU_CNT_TLV_V:"); + +- ARRAY_TO_STRING(list_mpdu_cnt_hist, htt_stats_buf->list_mpdu_cnt_hist, +- num_elems); ++ PRINT_ARRAY_TO_BUF(list_mpdu_cnt_hist, htt_stats_buf->list_mpdu_cnt_hist, ++ num_elems); + len += HTT_DBG_OUT(buf + len, buf_len - len, "list_mpdu_cnt_hist = %s\n", + list_mpdu_cnt_hist); + +@@ -2539,9 +2539,9 @@ htt_print_tx_de_fw2wbm_ring_full_hist_tl + "HTT_TX_DE_FW2WBM_RING_FULL_HIST_TLV"); + + if (required_buffer_size < HTT_MAX_STRING_LEN) { +- ARRAY_TO_STRING(fw2wbm_ring_full_hist, +- htt_stats_buf->fw2wbm_ring_full_hist, +- num_elements); ++ PRINT_ARRAY_TO_BUF(fw2wbm_ring_full_hist, ++ htt_stats_buf->fw2wbm_ring_full_hist, ++ num_elements); + len += HTT_DBG_OUT(buf + len, buf_len - len, + "fw2wbm_ring_full_hist = %s\n", + fw2wbm_ring_full_hist); +@@ -2634,13 +2634,13 @@ static inline void htt_print_ring_if_sta + len += HTT_DBG_OUT(buf + len, buf_len - len, "cons_blockwait_count = %u", + htt_stats_buf->cons_blockwait_count); + +- ARRAY_TO_STRING(low_wm_hit_count, htt_stats_buf->low_wm_hit_count, +- HTT_STATS_LOW_WM_BINS); ++ PRINT_ARRAY_TO_BUF(low_wm_hit_count, htt_stats_buf->low_wm_hit_count, ++ HTT_STATS_LOW_WM_BINS); + len += HTT_DBG_OUT(buf + len, buf_len - len, "low_wm_hit_count = %s ", + low_wm_hit_count); + +- ARRAY_TO_STRING(high_wm_hit_count, htt_stats_buf->high_wm_hit_count, +- HTT_STATS_HIGH_WM_BINS); ++ PRINT_ARRAY_TO_BUF(high_wm_hit_count, htt_stats_buf->high_wm_hit_count, ++ HTT_STATS_HIGH_WM_BINS); + len += HTT_DBG_OUT(buf + len, buf_len - len, "high_wm_hit_count = %s\n", + high_wm_hit_count); + +@@ -2687,9 +2687,9 @@ static inline void htt_print_sfm_client_ + + len += HTT_DBG_OUT(buf + len, buf_len - len, "HTT_SFM_CLIENT_USER_TLV_V:"); + +- ARRAY_TO_STRING(dwords_used_by_user_n, +- htt_stats_buf->dwords_used_by_user_n, +- num_elems); ++ PRINT_ARRAY_TO_BUF(dwords_used_by_user_n, ++ htt_stats_buf->dwords_used_by_user_n, ++ num_elems); + len += HTT_DBG_OUT(buf + len, buf_len - len, "dwords_used_by_user_n = %s\n", + dwords_used_by_user_n); + +@@ -2889,73 +2889,73 @@ static inline void htt_print_tx_pdev_rat + htt_stats_buf->tx_legacy_ofdm_rate[7]); + + memset(str_buf, 0x0, HTT_MAX_STRING_LEN); +- ARRAY_TO_STRING(str_buf, htt_stats_buf->tx_mcs, +- HTT_TX_PDEV_STATS_NUM_MCS_COUNTERS); ++ PRINT_ARRAY_TO_BUF(str_buf, htt_stats_buf->tx_mcs, ++ HTT_TX_PDEV_STATS_NUM_MCS_COUNTERS); + len += HTT_DBG_OUT(buf + len, buf_len - len, "tx_mcs = %s ", str_buf); + + memset(str_buf, 0x0, HTT_MAX_STRING_LEN); +- ARRAY_TO_STRING(str_buf, htt_stats_buf->ac_mu_mimo_tx_mcs, +- HTT_TX_PDEV_STATS_NUM_MCS_COUNTERS); ++ PRINT_ARRAY_TO_BUF(str_buf, htt_stats_buf->ac_mu_mimo_tx_mcs, ++ HTT_TX_PDEV_STATS_NUM_MCS_COUNTERS); + len += HTT_DBG_OUT(buf + len, buf_len - len, "ac_mu_mimo_tx_mcs = %s ", str_buf); + + memset(str_buf, 0x0, HTT_MAX_STRING_LEN); +- ARRAY_TO_STRING(str_buf, htt_stats_buf->ax_mu_mimo_tx_mcs, +- HTT_TX_PDEV_STATS_NUM_MCS_COUNTERS); ++ PRINT_ARRAY_TO_BUF(str_buf, htt_stats_buf->ax_mu_mimo_tx_mcs, ++ HTT_TX_PDEV_STATS_NUM_MCS_COUNTERS); + len += HTT_DBG_OUT(buf + len, buf_len - len, "ax_mu_mimo_tx_mcs = %s ", str_buf); + + memset(str_buf, 0x0, HTT_MAX_STRING_LEN); +- ARRAY_TO_STRING(str_buf, htt_stats_buf->ofdma_tx_mcs, +- HTT_TX_PDEV_STATS_NUM_MCS_COUNTERS); ++ PRINT_ARRAY_TO_BUF(str_buf, htt_stats_buf->ofdma_tx_mcs, ++ HTT_TX_PDEV_STATS_NUM_MCS_COUNTERS); + len += HTT_DBG_OUT(buf + len, buf_len - len, "ofdma_tx_mcs = %s ", str_buf); + + memset(str_buf, 0x0, HTT_MAX_STRING_LEN); +- ARRAY_TO_STRING(str_buf, htt_stats_buf->tx_nss, +- HTT_TX_PDEV_STATS_NUM_SPATIAL_STREAMS); ++ PRINT_ARRAY_TO_BUF(str_buf, htt_stats_buf->tx_nss, ++ HTT_TX_PDEV_STATS_NUM_SPATIAL_STREAMS); + len += HTT_DBG_OUT(buf + len, buf_len - len, "tx_nss = %s ", str_buf); + + memset(str_buf, 0x0, HTT_MAX_STRING_LEN); +- ARRAY_TO_STRING(str_buf, htt_stats_buf->ac_mu_mimo_tx_nss, +- HTT_TX_PDEV_STATS_NUM_SPATIAL_STREAMS); ++ PRINT_ARRAY_TO_BUF(str_buf, htt_stats_buf->ac_mu_mimo_tx_nss, ++ HTT_TX_PDEV_STATS_NUM_SPATIAL_STREAMS); + len += HTT_DBG_OUT(buf + len, buf_len - len, "ac_mu_mimo_tx_nss = %s ", str_buf); + + memset(str_buf, 0x0, HTT_MAX_STRING_LEN); +- ARRAY_TO_STRING(str_buf, htt_stats_buf->ax_mu_mimo_tx_nss, +- HTT_TX_PDEV_STATS_NUM_SPATIAL_STREAMS); ++ PRINT_ARRAY_TO_BUF(str_buf, htt_stats_buf->ax_mu_mimo_tx_nss, ++ HTT_TX_PDEV_STATS_NUM_SPATIAL_STREAMS); + len += HTT_DBG_OUT(buf + len, buf_len - len, "ax_mu_mimo_tx_nss = %s ", str_buf); + + memset(str_buf, 0x0, HTT_MAX_STRING_LEN); +- ARRAY_TO_STRING(str_buf, htt_stats_buf->ofdma_tx_nss, +- HTT_TX_PDEV_STATS_NUM_SPATIAL_STREAMS); ++ PRINT_ARRAY_TO_BUF(str_buf, htt_stats_buf->ofdma_tx_nss, ++ HTT_TX_PDEV_STATS_NUM_SPATIAL_STREAMS); + len += HTT_DBG_OUT(buf + len, buf_len - len, "ofdma_tx_nss = %s ", str_buf); + + memset(str_buf, 0x0, HTT_MAX_STRING_LEN); +- ARRAY_TO_STRING(str_buf, htt_stats_buf->tx_bw, +- HTT_TX_PDEV_STATS_NUM_BW_COUNTERS); ++ PRINT_ARRAY_TO_BUF(str_buf, htt_stats_buf->tx_bw, ++ HTT_TX_PDEV_STATS_NUM_BW_COUNTERS); + len += HTT_DBG_OUT(buf + len, buf_len - len, "tx_bw = %s ", str_buf); + + memset(str_buf, 0x0, HTT_MAX_STRING_LEN); +- ARRAY_TO_STRING(str_buf, htt_stats_buf->ac_mu_mimo_tx_bw, +- HTT_TX_PDEV_STATS_NUM_BW_COUNTERS); ++ PRINT_ARRAY_TO_BUF(str_buf, htt_stats_buf->ac_mu_mimo_tx_bw, ++ HTT_TX_PDEV_STATS_NUM_BW_COUNTERS); + len += HTT_DBG_OUT(buf + len, buf_len - len, "ac_mu_mimo_tx_bw = %s ", str_buf); + + memset(str_buf, 0x0, HTT_MAX_STRING_LEN); +- ARRAY_TO_STRING(str_buf, htt_stats_buf->ax_mu_mimo_tx_bw, +- HTT_TX_PDEV_STATS_NUM_BW_COUNTERS); ++ PRINT_ARRAY_TO_BUF(str_buf, htt_stats_buf->ax_mu_mimo_tx_bw, ++ HTT_TX_PDEV_STATS_NUM_BW_COUNTERS); + len += HTT_DBG_OUT(buf + len, buf_len - len, "ax_mu_mimo_tx_bw = %s ", str_buf); + + memset(str_buf, 0x0, HTT_MAX_STRING_LEN); +- ARRAY_TO_STRING(str_buf, htt_stats_buf->ofdma_tx_bw, +- HTT_TX_PDEV_STATS_NUM_BW_COUNTERS); ++ PRINT_ARRAY_TO_BUF(str_buf, htt_stats_buf->ofdma_tx_bw, ++ HTT_TX_PDEV_STATS_NUM_BW_COUNTERS); + len += HTT_DBG_OUT(buf + len, buf_len - len, "ofdma_tx_bw = %s ", str_buf); + + memset(str_buf, 0x0, HTT_MAX_STRING_LEN); +- ARRAY_TO_STRING(str_buf, htt_stats_buf->tx_stbc, +- HTT_TX_PDEV_STATS_NUM_MCS_COUNTERS); ++ PRINT_ARRAY_TO_BUF(str_buf, htt_stats_buf->tx_stbc, ++ HTT_TX_PDEV_STATS_NUM_MCS_COUNTERS); + len += HTT_DBG_OUT(buf + len, buf_len - len, "tx_stbc = %s ", str_buf); + + memset(str_buf, 0x0, HTT_MAX_STRING_LEN); +- ARRAY_TO_STRING(str_buf, htt_stats_buf->tx_pream, +- HTT_TX_PDEV_STATS_NUM_PREAMBLE_TYPES); ++ PRINT_ARRAY_TO_BUF(str_buf, htt_stats_buf->tx_pream, ++ HTT_TX_PDEV_STATS_NUM_PREAMBLE_TYPES); + len += HTT_DBG_OUT(buf + len, buf_len - len, "tx_pream = %s ", str_buf); + + len += HTT_DBG_OUT(buf + len, buf_len - len, "HE LTF: 1x: %u, 2x: %u, 4x: %u", +@@ -2965,16 +2965,16 @@ static inline void htt_print_tx_pdev_rat + + /* SU GI Stats */ + for (j = 0; j < HTT_TX_PDEV_STATS_NUM_GI_COUNTERS; j++) { +- ARRAY_TO_STRING(tx_gi[j], htt_stats_buf->tx_gi[j], +- HTT_TX_PDEV_STATS_NUM_MCS_COUNTERS); ++ PRINT_ARRAY_TO_BUF(tx_gi[j], htt_stats_buf->tx_gi[j], ++ HTT_TX_PDEV_STATS_NUM_MCS_COUNTERS); + len += HTT_DBG_OUT(buf + len, buf_len - len, "tx_gi[%u] = %s ", + j, tx_gi[j]); + } + + /* AC MU-MIMO GI Stats */ + for (j = 0; j < HTT_TX_PDEV_STATS_NUM_GI_COUNTERS; j++) { +- ARRAY_TO_STRING(tx_gi[j], htt_stats_buf->ac_mu_mimo_tx_gi[j], +- HTT_TX_PDEV_STATS_NUM_MCS_COUNTERS); ++ PRINT_ARRAY_TO_BUF(tx_gi[j], htt_stats_buf->ac_mu_mimo_tx_gi[j], ++ HTT_TX_PDEV_STATS_NUM_MCS_COUNTERS); + len += HTT_DBG_OUT(buf + len, buf_len - len, + "ac_mu_mimo_tx_gi[%u] = %s ", + j, tx_gi[j]); +@@ -2982,8 +2982,8 @@ static inline void htt_print_tx_pdev_rat + + /* AX MU-MIMO GI Stats */ + for (j = 0; j < HTT_TX_PDEV_STATS_NUM_GI_COUNTERS; j++) { +- ARRAY_TO_STRING(tx_gi[j], htt_stats_buf->ax_mu_mimo_tx_gi[j], +- HTT_TX_PDEV_STATS_NUM_MCS_COUNTERS); ++ PRINT_ARRAY_TO_BUF(tx_gi[j], htt_stats_buf->ax_mu_mimo_tx_gi[j], ++ HTT_TX_PDEV_STATS_NUM_MCS_COUNTERS); + len += HTT_DBG_OUT(buf + len, buf_len - len, + "ax_mu_mimo_tx_gi[%u] = %s ", + j, tx_gi[j]); +@@ -2991,15 +2991,15 @@ static inline void htt_print_tx_pdev_rat + + /* DL OFDMA GI Stats */ + for (j = 0; j < HTT_TX_PDEV_STATS_NUM_GI_COUNTERS; j++) { +- ARRAY_TO_STRING(tx_gi[j], htt_stats_buf->ofdma_tx_gi[j], +- HTT_TX_PDEV_STATS_NUM_MCS_COUNTERS); ++ PRINT_ARRAY_TO_BUF(tx_gi[j], htt_stats_buf->ofdma_tx_gi[j], ++ HTT_TX_PDEV_STATS_NUM_MCS_COUNTERS); + len += HTT_DBG_OUT(buf + len, buf_len - len, "ofdma_tx_gi[%u] = %s ", + j, tx_gi[j]); + } + + memset(str_buf, 0x0, HTT_MAX_STRING_LEN); +- ARRAY_TO_STRING(str_buf, htt_stats_buf->tx_dcm, +- HTT_TX_PDEV_STATS_NUM_DCM_COUNTERS); ++ PRINT_ARRAY_TO_BUF(str_buf, htt_stats_buf->tx_dcm, ++ HTT_TX_PDEV_STATS_NUM_DCM_COUNTERS); + len += HTT_DBG_OUT(buf + len, buf_len - len, "tx_dcm = %s\n", str_buf); + + if (len >= buf_len) +@@ -3064,28 +3064,28 @@ static inline void htt_print_rx_pdev_rat + htt_stats_buf->rssi_in_dbm); + + memset(str_buf, 0x0, HTT_MAX_STRING_LEN); +- ARRAY_TO_STRING(str_buf, htt_stats_buf->rx_mcs, +- HTT_RX_PDEV_STATS_NUM_MCS_COUNTERS); ++ PRINT_ARRAY_TO_BUF(str_buf, htt_stats_buf->rx_mcs, ++ HTT_RX_PDEV_STATS_NUM_MCS_COUNTERS); + len += HTT_DBG_OUT(buf + len, buf_len - len, "rx_mcs = %s ", str_buf); + + memset(str_buf, 0x0, HTT_MAX_STRING_LEN); +- ARRAY_TO_STRING(str_buf, htt_stats_buf->rx_nss, +- HTT_RX_PDEV_STATS_NUM_SPATIAL_STREAMS); ++ PRINT_ARRAY_TO_BUF(str_buf, htt_stats_buf->rx_nss, ++ HTT_RX_PDEV_STATS_NUM_SPATIAL_STREAMS); + len += HTT_DBG_OUT(buf + len, buf_len - len, "rx_nss = %s ", str_buf); + + memset(str_buf, 0x0, HTT_MAX_STRING_LEN); +- ARRAY_TO_STRING(str_buf, htt_stats_buf->rx_dcm, +- HTT_RX_PDEV_STATS_NUM_DCM_COUNTERS); ++ PRINT_ARRAY_TO_BUF(str_buf, htt_stats_buf->rx_dcm, ++ HTT_RX_PDEV_STATS_NUM_DCM_COUNTERS); + len += HTT_DBG_OUT(buf + len, buf_len - len, "rx_dcm = %s ", str_buf); + + memset(str_buf, 0x0, HTT_MAX_STRING_LEN); +- ARRAY_TO_STRING(str_buf, htt_stats_buf->rx_stbc, +- HTT_RX_PDEV_STATS_NUM_MCS_COUNTERS); ++ PRINT_ARRAY_TO_BUF(str_buf, htt_stats_buf->rx_stbc, ++ HTT_RX_PDEV_STATS_NUM_MCS_COUNTERS); + len += HTT_DBG_OUT(buf + len, buf_len - len, "rx_stbc = %s ", str_buf); + + memset(str_buf, 0x0, HTT_MAX_STRING_LEN); +- ARRAY_TO_STRING(str_buf, htt_stats_buf->rx_bw, +- HTT_RX_PDEV_STATS_NUM_BW_COUNTERS); ++ PRINT_ARRAY_TO_BUF(str_buf, htt_stats_buf->rx_bw, ++ HTT_RX_PDEV_STATS_NUM_BW_COUNTERS); + len += HTT_DBG_OUT(buf + len, buf_len - len, "rx_bw = %s ", str_buf); + len += HTT_DBG_OUT(buf + len, buf_len - len, "rx_evm_nss_count = %u", + htt_stats_buf->nss_count); +@@ -3115,22 +3115,22 @@ static inline void htt_print_rx_pdev_rat + len += HTT_DBG_OUT(buf + len, buf_len - len, "pilot_evm_dB_mean = %s ", str_buf); + + for (j = 0; j < HTT_RX_PDEV_STATS_NUM_SPATIAL_STREAMS; j++) { +- ARRAY_TO_STRING(rssi_chain[j], htt_stats_buf->rssi_chain[j], +- HTT_RX_PDEV_STATS_NUM_BW_COUNTERS); ++ PRINT_ARRAY_TO_BUF(rssi_chain[j], htt_stats_buf->rssi_chain[j], ++ HTT_RX_PDEV_STATS_NUM_BW_COUNTERS); + len += HTT_DBG_OUT(buf + len, buf_len - len, "rssi_chain[%u] = %s ", + j, rssi_chain[j]); + } + + for (j = 0; j < HTT_RX_PDEV_STATS_NUM_GI_COUNTERS; j++) { +- ARRAY_TO_STRING(rx_gi[j], htt_stats_buf->rx_gi[j], +- HTT_RX_PDEV_STATS_NUM_MCS_COUNTERS); ++ PRINT_ARRAY_TO_BUF(rx_gi[j], htt_stats_buf->rx_gi[j], ++ HTT_RX_PDEV_STATS_NUM_MCS_COUNTERS); + len += HTT_DBG_OUT(buf + len, buf_len - len, "rx_gi[%u] = %s ", + j, rx_gi[j]); + } + + memset(str_buf, 0x0, HTT_MAX_STRING_LEN); +- ARRAY_TO_STRING(str_buf, htt_stats_buf->rx_pream, +- HTT_RX_PDEV_STATS_NUM_PREAMBLE_TYPES); ++ PRINT_ARRAY_TO_BUF(str_buf, htt_stats_buf->rx_pream, ++ HTT_RX_PDEV_STATS_NUM_PREAMBLE_TYPES); + len += HTT_DBG_OUT(buf + len, buf_len - len, "rx_pream = %s", str_buf); + + len += HTT_DBG_OUT(buf + len, buf_len - len, "rx_11ax_su_ext = %u", +@@ -3145,14 +3145,14 @@ static inline void htt_print_rx_pdev_rat + htt_stats_buf->txbf); + + memset(str_buf, 0x0, HTT_MAX_STRING_LEN); +- ARRAY_TO_STRING(str_buf, htt_stats_buf->rx_legacy_cck_rate, +- HTT_RX_PDEV_STATS_NUM_LEGACY_CCK_STATS); ++ PRINT_ARRAY_TO_BUF(str_buf, htt_stats_buf->rx_legacy_cck_rate, ++ HTT_RX_PDEV_STATS_NUM_LEGACY_CCK_STATS); + len += HTT_DBG_OUT(buf + len, buf_len - len, "rx_legacy_cck_rate = %s ", + str_buf); + + memset(str_buf, 0x0, HTT_MAX_STRING_LEN); +- ARRAY_TO_STRING(str_buf, htt_stats_buf->rx_legacy_ofdm_rate, +- HTT_RX_PDEV_STATS_NUM_LEGACY_OFDM_STATS); ++ PRINT_ARRAY_TO_BUF(str_buf, htt_stats_buf->rx_legacy_ofdm_rate, ++ HTT_RX_PDEV_STATS_NUM_LEGACY_OFDM_STATS); + len += HTT_DBG_OUT(buf + len, buf_len - len, "rx_legacy_ofdm_rate = %s ", + str_buf); + +@@ -3164,25 +3164,25 @@ static inline void htt_print_rx_pdev_rat + htt_stats_buf->rx_11ax_ul_ofdma); + + memset(str_buf, 0x0, HTT_MAX_STRING_LEN); +- ARRAY_TO_STRING(str_buf, htt_stats_buf->ul_ofdma_rx_mcs, +- HTT_RX_PDEV_STATS_NUM_MCS_COUNTERS); ++ PRINT_ARRAY_TO_BUF(str_buf, htt_stats_buf->ul_ofdma_rx_mcs, ++ HTT_RX_PDEV_STATS_NUM_MCS_COUNTERS); + len += HTT_DBG_OUT(buf + len, buf_len - len, "ul_ofdma_rx_mcs = %s ", str_buf); + + for (j = 0; j < HTT_RX_PDEV_STATS_NUM_GI_COUNTERS; j++) { +- ARRAY_TO_STRING(rx_gi[j], htt_stats_buf->ul_ofdma_rx_gi[j], +- HTT_RX_PDEV_STATS_NUM_MCS_COUNTERS); ++ PRINT_ARRAY_TO_BUF(rx_gi[j], htt_stats_buf->ul_ofdma_rx_gi[j], ++ HTT_RX_PDEV_STATS_NUM_MCS_COUNTERS); + len += HTT_DBG_OUT(buf + len, buf_len - len, "ul_ofdma_rx_gi[%u] = %s ", + j, rx_gi[j]); + } + + memset(str_buf, 0x0, HTT_MAX_STRING_LEN); +- ARRAY_TO_STRING(str_buf, htt_stats_buf->ul_ofdma_rx_nss, +- HTT_RX_PDEV_STATS_NUM_SPATIAL_STREAMS); ++ PRINT_ARRAY_TO_BUF(str_buf, htt_stats_buf->ul_ofdma_rx_nss, ++ HTT_RX_PDEV_STATS_NUM_SPATIAL_STREAMS); + len += HTT_DBG_OUT(buf + len, buf_len - len, "ul_ofdma_rx_nss = %s ", str_buf); + + memset(str_buf, 0x0, HTT_MAX_STRING_LEN); +- ARRAY_TO_STRING(str_buf, htt_stats_buf->ul_ofdma_rx_bw, +- HTT_RX_PDEV_STATS_NUM_BW_COUNTERS); ++ PRINT_ARRAY_TO_BUF(str_buf, htt_stats_buf->ul_ofdma_rx_bw, ++ HTT_RX_PDEV_STATS_NUM_BW_COUNTERS); + len += HTT_DBG_OUT(buf + len, buf_len - len, "ul_ofdma_rx_bw = %s ", str_buf); + + len += HTT_DBG_OUT(buf + len, buf_len - len, "ul_ofdma_rx_stbc = %u", +@@ -3191,25 +3191,25 @@ static inline void htt_print_rx_pdev_rat + htt_stats_buf->ul_ofdma_rx_ldpc); + + memset(str_buf, 0x0, HTT_MAX_STRING_LEN); +- ARRAY_TO_STRING(str_buf, htt_stats_buf->rx_ulofdma_non_data_ppdu, +- HTT_RX_PDEV_MAX_OFDMA_NUM_USER); ++ PRINT_ARRAY_TO_BUF(str_buf, htt_stats_buf->rx_ulofdma_non_data_ppdu, ++ HTT_RX_PDEV_MAX_OFDMA_NUM_USER); + len += HTT_DBG_OUT(buf + len, buf_len - len, "rx_ulofdma_non_data_ppdu = %s ", + str_buf); + + memset(str_buf, 0x0, HTT_MAX_STRING_LEN); +- ARRAY_TO_STRING(str_buf, htt_stats_buf->rx_ulofdma_data_ppdu, +- HTT_RX_PDEV_MAX_OFDMA_NUM_USER); ++ PRINT_ARRAY_TO_BUF(str_buf, htt_stats_buf->rx_ulofdma_data_ppdu, ++ HTT_RX_PDEV_MAX_OFDMA_NUM_USER); + len += HTT_DBG_OUT(buf + len, buf_len - len, "rx_ulofdma_data_ppdu = %s ", + str_buf); + + memset(str_buf, 0x0, HTT_MAX_STRING_LEN); +- ARRAY_TO_STRING(str_buf, htt_stats_buf->rx_ulofdma_mpdu_ok, +- HTT_RX_PDEV_MAX_OFDMA_NUM_USER); ++ PRINT_ARRAY_TO_BUF(str_buf, htt_stats_buf->rx_ulofdma_mpdu_ok, ++ HTT_RX_PDEV_MAX_OFDMA_NUM_USER); + len += HTT_DBG_OUT(buf + len, buf_len - len, "rx_ulofdma_mpdu_ok = %s ", str_buf); + + memset(str_buf, 0x0, HTT_MAX_STRING_LEN); +- ARRAY_TO_STRING(str_buf, htt_stats_buf->rx_ulofdma_mpdu_fail, +- HTT_RX_PDEV_MAX_OFDMA_NUM_USER); ++ PRINT_ARRAY_TO_BUF(str_buf, htt_stats_buf->rx_ulofdma_mpdu_fail, ++ HTT_RX_PDEV_MAX_OFDMA_NUM_USER); + len += HTT_DBG_OUT(buf + len, buf_len - len, "rx_ulofdma_mpdu_fail = %s", + str_buf); + +@@ -3320,9 +3320,9 @@ htt_print_rx_soc_fw_refill_ring_empty_tl + len += HTT_DBG_OUT(buf + len, buf_len - len, + "HTT_RX_SOC_FW_REFILL_RING_EMPTY_TLV_V:"); + +- ARRAY_TO_STRING(refill_ring_empty_cnt, +- htt_stats_buf->refill_ring_empty_cnt, +- num_elems); ++ PRINT_ARRAY_TO_BUF(refill_ring_empty_cnt, ++ htt_stats_buf->refill_ring_empty_cnt, ++ num_elems); + len += HTT_DBG_OUT(buf + len, buf_len - len, "refill_ring_empty_cnt = %s\n", + refill_ring_empty_cnt); + +@@ -3350,9 +3350,9 @@ htt_print_rx_soc_fw_refill_ring_num_rxdm + len += HTT_DBG_OUT(buf + len, buf_len - len, + "HTT_RX_SOC_FW_REFILL_RING_NUM_RXDMA_ERR_TLV_V:"); + +- ARRAY_TO_STRING(rxdma_err_cnt, +- htt_stats_buf->rxdma_err, +- num_elems); ++ PRINT_ARRAY_TO_BUF(rxdma_err_cnt, ++ htt_stats_buf->rxdma_err, ++ num_elems); + len += HTT_DBG_OUT(buf + len, buf_len - len, "rxdma_err = %s\n", + rxdma_err_cnt); + +@@ -3379,9 +3379,9 @@ htt_print_rx_soc_fw_refill_ring_num_reo_ + len += HTT_DBG_OUT(buf + len, buf_len - len, + "HTT_RX_SOC_FW_REFILL_RING_NUM_REO_ERR_TLV_V:"); + +- ARRAY_TO_STRING(reo_err_cnt, +- htt_stats_buf->reo_err, +- num_elems); ++ PRINT_ARRAY_TO_BUF(reo_err_cnt, ++ htt_stats_buf->reo_err, ++ num_elems); + len += HTT_DBG_OUT(buf + len, buf_len - len, "reo_err = %s\n", + reo_err_cnt); + +@@ -3447,9 +3447,9 @@ htt_print_rx_soc_fw_refill_ring_num_refi + len += HTT_DBG_OUT(buf + len, buf_len - len, + "HTT_RX_SOC_FW_REFILL_RING_NUM_REFILL_TLV_V:"); + +- ARRAY_TO_STRING(refill_ring_num_refill, +- htt_stats_buf->refill_ring_num_refill, +- num_elems); ++ PRINT_ARRAY_TO_BUF(refill_ring_num_refill, ++ htt_stats_buf->refill_ring_num_refill, ++ num_elems); + len += HTT_DBG_OUT(buf + len, buf_len - len, "refill_ring_num_refill = %s\n", + refill_ring_num_refill); + +@@ -3491,15 +3491,15 @@ static inline void htt_print_rx_pdev_fw_ + len += HTT_DBG_OUT(buf + len, buf_len - len, "fw_ring_mpdu_ind = %u", + htt_stats_buf->fw_ring_mpdu_ind); + +- ARRAY_TO_STRING(fw_ring_mgmt_subtype, +- htt_stats_buf->fw_ring_mgmt_subtype, +- HTT_STATS_SUBTYPE_MAX); ++ PRINT_ARRAY_TO_BUF(fw_ring_mgmt_subtype, ++ htt_stats_buf->fw_ring_mgmt_subtype, ++ HTT_STATS_SUBTYPE_MAX); + len += HTT_DBG_OUT(buf + len, buf_len - len, "fw_ring_mgmt_subtype = %s ", + fw_ring_mgmt_subtype); + +- ARRAY_TO_STRING(fw_ring_ctrl_subtype, +- htt_stats_buf->fw_ring_ctrl_subtype, +- HTT_STATS_SUBTYPE_MAX); ++ PRINT_ARRAY_TO_BUF(fw_ring_ctrl_subtype, ++ htt_stats_buf->fw_ring_ctrl_subtype, ++ HTT_STATS_SUBTYPE_MAX); + len += HTT_DBG_OUT(buf + len, buf_len - len, "fw_ring_ctrl_subtype = %s ", + fw_ring_ctrl_subtype); + len += HTT_DBG_OUT(buf + len, buf_len - len, "fw_ring_mcast_data_msdu = %u", +@@ -3597,9 +3597,9 @@ htt_print_rx_pdev_fw_ring_mpdu_err_tlv_v + len += HTT_DBG_OUT(buf + len, buf_len - len, + "HTT_RX_PDEV_FW_RING_MPDU_ERR_TLV_V:"); + +- ARRAY_TO_STRING(fw_ring_mpdu_err, +- htt_stats_buf->fw_ring_mpdu_err, +- HTT_RX_STATS_RXDMA_MAX_ERR); ++ PRINT_ARRAY_TO_BUF(fw_ring_mpdu_err, ++ htt_stats_buf->fw_ring_mpdu_err, ++ HTT_RX_STATS_RXDMA_MAX_ERR); + len += HTT_DBG_OUT(buf + len, buf_len - len, "fw_ring_mpdu_err = %s\n", + fw_ring_mpdu_err); + +@@ -3625,9 +3625,9 @@ htt_print_rx_pdev_fw_mpdu_drop_tlv_v(con + + len += HTT_DBG_OUT(buf + len, buf_len - len, "HTT_RX_PDEV_FW_MPDU_DROP_TLV_V:"); + +- ARRAY_TO_STRING(fw_mpdu_drop, +- htt_stats_buf->fw_mpdu_drop, +- num_elems); ++ PRINT_ARRAY_TO_BUF(fw_mpdu_drop, ++ htt_stats_buf->fw_mpdu_drop, ++ num_elems); + len += HTT_DBG_OUT(buf + len, buf_len - len, "fw_mpdu_drop = %s\n", fw_mpdu_drop); + + if (len >= buf_len) +@@ -3654,9 +3654,9 @@ htt_print_rx_pdev_fw_stats_phy_err_tlv(c + len += HTT_DBG_OUT(buf + len, buf_len - len, "total_phy_err_nct = %u", + htt_stats_buf->total_phy_err_cnt); + +- ARRAY_TO_STRING(phy_errs, +- htt_stats_buf->phy_err, +- HTT_STATS_PHY_ERR_MAX); ++ PRINT_ARRAY_TO_BUF(phy_errs, ++ htt_stats_buf->phy_err, ++ HTT_STATS_PHY_ERR_MAX); + len += HTT_DBG_OUT(buf + len, buf_len - len, "phy_errs = %s\n", phy_errs); + + if (len >= buf_len) diff --git a/package/kernel/mac80211/patches/ath11k/0044-ath11k-Replace-HTT_DBG_OUT-with-scnprintf.patch b/package/kernel/mac80211/patches/ath11k/0044-ath11k-Replace-HTT_DBG_OUT-with-scnprintf.patch new file mode 100644 index 000000000..9d6dd3e23 --- /dev/null +++ b/package/kernel/mac80211/patches/ath11k/0044-ath11k-Replace-HTT_DBG_OUT-with-scnprintf.patch @@ -0,0 +1,4451 @@ +From 6f442799bcfd62931ca100c7c5916bb5fc034302 Mon Sep 17 00:00:00 2001 +From: Seevalamuthu Mariappan +Date: Tue, 28 Sep 2021 14:00:44 +0300 +Subject: [PATCH 044/120] ath11k: Replace HTT_DBG_OUT with scnprintf + +Get rid of macro HTT_DBG_OUT and replace it with scnprintf(). +The macro does not do anything else. Added required new line +characters to scnprintf() for proper display. + +Tested-on: IPQ8074 hw2.0 AHB WLAN.HK.2.5.0.1-01105-QCAHKSWPL_SILICONZ-1 + +Signed-off-by: Seevalamuthu Mariappan +Signed-off-by: Jouni Malinen +Signed-off-by: Kalle Valo +Link: https://lore.kernel.org/r/20210913223148.208026-3-jouni@codeaurora.org +--- + .../wireless/ath/ath11k/debugfs_htt_stats.c | 3370 ++++++++--------- + 1 file changed, 1683 insertions(+), 1687 deletions(-) + +--- a/drivers/net/wireless/ath/ath11k/debugfs_htt_stats.c ++++ b/drivers/net/wireless/ath/ath11k/debugfs_htt_stats.c +@@ -10,9 +10,6 @@ + #include "debug.h" + #include "debugfs_htt_stats.h" + +-#define HTT_DBG_OUT(buf, len, fmt, ...) \ +- scnprintf(buf, len, fmt "\n", ##__VA_ARGS__) +- + #define HTT_MAX_STRING_LEN 256 + #define HTT_MAX_PRINT_CHAR_PER_ELEM 15 + +@@ -43,17 +40,17 @@ static inline void htt_print_stats_strin + + tag_len = tag_len >> 2; + +- len += HTT_DBG_OUT(buf + len, buf_len - len, "HTT_STATS_STRING_TLV:"); ++ len += scnprintf(buf + len, buf_len - len, "HTT_STATS_STRING_TLV:\n"); + + for (i = 0; i < tag_len; i++) { + index += scnprintf(&data[index], +- HTT_MAX_STRING_LEN - index, +- "%.*s", 4, (char *)&(htt_stats_buf->data[i])); ++ HTT_MAX_STRING_LEN - index, ++ "%.*s", 4, (char *)&(htt_stats_buf->data[i])); + if (index >= HTT_MAX_STRING_LEN) + break; + } + +- len += HTT_DBG_OUT(buf + len, buf_len - len, "data = %s\n", data); ++ len += scnprintf(buf + len, buf_len - len, "data = %s\n\n", data); + + if (len >= buf_len) + buf[buf_len - 1] = 0; +@@ -71,107 +68,107 @@ static inline void htt_print_tx_pdev_sta + u32 len = stats_req->buf_len; + u32 buf_len = ATH11K_HTT_STATS_BUF_SIZE; + +- len += HTT_DBG_OUT(buf + len, buf_len - len, "HTT_TX_PDEV_STATS_CMN_TLV:"); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "mac_id = %u", +- htt_stats_buf->mac_id__word & 0xFF); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "hw_queued = %u", +- htt_stats_buf->hw_queued); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "hw_reaped = %u", +- htt_stats_buf->hw_reaped); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "underrun = %u", +- htt_stats_buf->underrun); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "hw_paused = %u", +- htt_stats_buf->hw_paused); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "hw_flush = %u", +- htt_stats_buf->hw_flush); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "hw_filt = %u", +- htt_stats_buf->hw_filt); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "tx_abort = %u", +- htt_stats_buf->tx_abort); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "mpdu_requeued = %u", +- htt_stats_buf->mpdu_requeued); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "tx_xretry = %u", +- htt_stats_buf->tx_xretry); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "data_rc = %u", +- htt_stats_buf->data_rc); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "mpdu_dropped_xretry = %u", +- htt_stats_buf->mpdu_dropped_xretry); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "illegal_rate_phy_err = %u", +- htt_stats_buf->illgl_rate_phy_err); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "cont_xretry = %u", +- htt_stats_buf->cont_xretry); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "tx_timeout = %u", +- htt_stats_buf->tx_timeout); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "pdev_resets = %u", +- htt_stats_buf->pdev_resets); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "phy_underrun = %u", +- htt_stats_buf->phy_underrun); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "txop_ovf = %u", +- htt_stats_buf->txop_ovf); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "seq_posted = %u", +- htt_stats_buf->seq_posted); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "seq_failed_queueing = %u", +- htt_stats_buf->seq_failed_queueing); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "seq_completed = %u", +- htt_stats_buf->seq_completed); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "seq_restarted = %u", +- htt_stats_buf->seq_restarted); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "mu_seq_posted = %u", +- htt_stats_buf->mu_seq_posted); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "seq_switch_hw_paused = %u", +- htt_stats_buf->seq_switch_hw_paused); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "next_seq_posted_dsr = %u", +- htt_stats_buf->next_seq_posted_dsr); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "seq_posted_isr = %u", +- htt_stats_buf->seq_posted_isr); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "seq_ctrl_cached = %u", +- htt_stats_buf->seq_ctrl_cached); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "mpdu_count_tqm = %u", +- htt_stats_buf->mpdu_count_tqm); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "msdu_count_tqm = %u", +- htt_stats_buf->msdu_count_tqm); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "mpdu_removed_tqm = %u", +- htt_stats_buf->mpdu_removed_tqm); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "msdu_removed_tqm = %u", +- htt_stats_buf->msdu_removed_tqm); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "mpdus_sw_flush = %u", +- htt_stats_buf->mpdus_sw_flush); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "mpdus_hw_filter = %u", +- htt_stats_buf->mpdus_hw_filter); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "mpdus_truncated = %u", +- htt_stats_buf->mpdus_truncated); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "mpdus_ack_failed = %u", +- htt_stats_buf->mpdus_ack_failed); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "mpdus_expired = %u", +- htt_stats_buf->mpdus_expired); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "mpdus_seq_hw_retry = %u", +- htt_stats_buf->mpdus_seq_hw_retry); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "ack_tlv_proc = %u", +- htt_stats_buf->ack_tlv_proc); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "coex_abort_mpdu_cnt_valid = %u", +- htt_stats_buf->coex_abort_mpdu_cnt_valid); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "coex_abort_mpdu_cnt = %u", +- htt_stats_buf->coex_abort_mpdu_cnt); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "num_total_ppdus_tried_ota = %u", +- htt_stats_buf->num_total_ppdus_tried_ota); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "num_data_ppdus_tried_ota = %u", +- htt_stats_buf->num_data_ppdus_tried_ota); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "local_ctrl_mgmt_enqued = %u", +- htt_stats_buf->local_ctrl_mgmt_enqued); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "local_ctrl_mgmt_freed = %u", +- htt_stats_buf->local_ctrl_mgmt_freed); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "local_data_enqued = %u", +- htt_stats_buf->local_data_enqued); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "local_data_freed = %u", +- htt_stats_buf->local_data_freed); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "mpdu_tried = %u", +- htt_stats_buf->mpdu_tried); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "isr_wait_seq_posted = %u", +- htt_stats_buf->isr_wait_seq_posted); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "tx_active_dur_us_low = %u", +- htt_stats_buf->tx_active_dur_us_low); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "tx_active_dur_us_high = %u\n", +- htt_stats_buf->tx_active_dur_us_high); ++ len += scnprintf(buf + len, buf_len - len, "HTT_TX_PDEV_STATS_CMN_TLV:\n"); ++ len += scnprintf(buf + len, buf_len - len, "mac_id = %u\n", ++ htt_stats_buf->mac_id__word & 0xFF); ++ len += scnprintf(buf + len, buf_len - len, "hw_queued = %u\n", ++ htt_stats_buf->hw_queued); ++ len += scnprintf(buf + len, buf_len - len, "hw_reaped = %u\n", ++ htt_stats_buf->hw_reaped); ++ len += scnprintf(buf + len, buf_len - len, "underrun = %u\n", ++ htt_stats_buf->underrun); ++ len += scnprintf(buf + len, buf_len - len, "hw_paused = %u\n", ++ htt_stats_buf->hw_paused); ++ len += scnprintf(buf + len, buf_len - len, "hw_flush = %u\n", ++ htt_stats_buf->hw_flush); ++ len += scnprintf(buf + len, buf_len - len, "hw_filt = %u\n", ++ htt_stats_buf->hw_filt); ++ len += scnprintf(buf + len, buf_len - len, "tx_abort = %u\n", ++ htt_stats_buf->tx_abort); ++ len += scnprintf(buf + len, buf_len - len, "mpdu_requeued = %u\n", ++ htt_stats_buf->mpdu_requeued); ++ len += scnprintf(buf + len, buf_len - len, "tx_xretry = %u\n", ++ htt_stats_buf->tx_xretry); ++ len += scnprintf(buf + len, buf_len - len, "data_rc = %u\n", ++ htt_stats_buf->data_rc); ++ len += scnprintf(buf + len, buf_len - len, "mpdu_dropped_xretry = %u\n", ++ htt_stats_buf->mpdu_dropped_xretry); ++ len += scnprintf(buf + len, buf_len - len, "illegal_rate_phy_err = %u\n", ++ htt_stats_buf->illgl_rate_phy_err); ++ len += scnprintf(buf + len, buf_len - len, "cont_xretry = %u\n", ++ htt_stats_buf->cont_xretry); ++ len += scnprintf(buf + len, buf_len - len, "tx_timeout = %u\n", ++ htt_stats_buf->tx_timeout); ++ len += scnprintf(buf + len, buf_len - len, "pdev_resets = %u\n", ++ htt_stats_buf->pdev_resets); ++ len += scnprintf(buf + len, buf_len - len, "phy_underrun = %u\n", ++ htt_stats_buf->phy_underrun); ++ len += scnprintf(buf + len, buf_len - len, "txop_ovf = %u\n", ++ htt_stats_buf->txop_ovf); ++ len += scnprintf(buf + len, buf_len - len, "seq_posted = %u\n", ++ htt_stats_buf->seq_posted); ++ len += scnprintf(buf + len, buf_len - len, "seq_failed_queueing = %u\n", ++ htt_stats_buf->seq_failed_queueing); ++ len += scnprintf(buf + len, buf_len - len, "seq_completed = %u\n", ++ htt_stats_buf->seq_completed); ++ len += scnprintf(buf + len, buf_len - len, "seq_restarted = %u\n", ++ htt_stats_buf->seq_restarted); ++ len += scnprintf(buf + len, buf_len - len, "mu_seq_posted = %u\n", ++ htt_stats_buf->mu_seq_posted); ++ len += scnprintf(buf + len, buf_len - len, "seq_switch_hw_paused = %u\n", ++ htt_stats_buf->seq_switch_hw_paused); ++ len += scnprintf(buf + len, buf_len - len, "next_seq_posted_dsr = %u\n", ++ htt_stats_buf->next_seq_posted_dsr); ++ len += scnprintf(buf + len, buf_len - len, "seq_posted_isr = %u\n", ++ htt_stats_buf->seq_posted_isr); ++ len += scnprintf(buf + len, buf_len - len, "seq_ctrl_cached = %u\n", ++ htt_stats_buf->seq_ctrl_cached); ++ len += scnprintf(buf + len, buf_len - len, "mpdu_count_tqm = %u\n", ++ htt_stats_buf->mpdu_count_tqm); ++ len += scnprintf(buf + len, buf_len - len, "msdu_count_tqm = %u\n", ++ htt_stats_buf->msdu_count_tqm); ++ len += scnprintf(buf + len, buf_len - len, "mpdu_removed_tqm = %u\n", ++ htt_stats_buf->mpdu_removed_tqm); ++ len += scnprintf(buf + len, buf_len - len, "msdu_removed_tqm = %u\n", ++ htt_stats_buf->msdu_removed_tqm); ++ len += scnprintf(buf + len, buf_len - len, "mpdus_sw_flush = %u\n", ++ htt_stats_buf->mpdus_sw_flush); ++ len += scnprintf(buf + len, buf_len - len, "mpdus_hw_filter = %u\n", ++ htt_stats_buf->mpdus_hw_filter); ++ len += scnprintf(buf + len, buf_len - len, "mpdus_truncated = %u\n", ++ htt_stats_buf->mpdus_truncated); ++ len += scnprintf(buf + len, buf_len - len, "mpdus_ack_failed = %u\n", ++ htt_stats_buf->mpdus_ack_failed); ++ len += scnprintf(buf + len, buf_len - len, "mpdus_expired = %u\n", ++ htt_stats_buf->mpdus_expired); ++ len += scnprintf(buf + len, buf_len - len, "mpdus_seq_hw_retry = %u\n", ++ htt_stats_buf->mpdus_seq_hw_retry); ++ len += scnprintf(buf + len, buf_len - len, "ack_tlv_proc = %u\n", ++ htt_stats_buf->ack_tlv_proc); ++ len += scnprintf(buf + len, buf_len - len, "coex_abort_mpdu_cnt_valid = %u\n", ++ htt_stats_buf->coex_abort_mpdu_cnt_valid); ++ len += scnprintf(buf + len, buf_len - len, "coex_abort_mpdu_cnt = %u\n", ++ htt_stats_buf->coex_abort_mpdu_cnt); ++ len += scnprintf(buf + len, buf_len - len, "num_total_ppdus_tried_ota = %u\n", ++ htt_stats_buf->num_total_ppdus_tried_ota); ++ len += scnprintf(buf + len, buf_len - len, "num_data_ppdus_tried_ota = %u\n", ++ htt_stats_buf->num_data_ppdus_tried_ota); ++ len += scnprintf(buf + len, buf_len - len, "local_ctrl_mgmt_enqued = %u\n", ++ htt_stats_buf->local_ctrl_mgmt_enqued); ++ len += scnprintf(buf + len, buf_len - len, "local_ctrl_mgmt_freed = %u\n", ++ htt_stats_buf->local_ctrl_mgmt_freed); ++ len += scnprintf(buf + len, buf_len - len, "local_data_enqued = %u\n", ++ htt_stats_buf->local_data_enqued); ++ len += scnprintf(buf + len, buf_len - len, "local_data_freed = %u\n", ++ htt_stats_buf->local_data_freed); ++ len += scnprintf(buf + len, buf_len - len, "mpdu_tried = %u\n", ++ htt_stats_buf->mpdu_tried); ++ len += scnprintf(buf + len, buf_len - len, "isr_wait_seq_posted = %u\n", ++ htt_stats_buf->isr_wait_seq_posted); ++ len += scnprintf(buf + len, buf_len - len, "tx_active_dur_us_low = %u\n", ++ htt_stats_buf->tx_active_dur_us_low); ++ len += scnprintf(buf + len, buf_len - len, "tx_active_dur_us_high = %u\n\n", ++ htt_stats_buf->tx_active_dur_us_high); + + if (len >= buf_len) + buf[buf_len - 1] = 0; +@@ -193,10 +190,10 @@ htt_print_tx_pdev_stats_urrn_tlv_v(const + char urrn_stats[HTT_MAX_STRING_LEN] = {0}; + u16 num_elems = min_t(u16, (tag_len >> 2), HTT_TX_PDEV_MAX_URRN_STATS); + +- len += HTT_DBG_OUT(buf + len, buf_len - len, "HTT_TX_PDEV_STATS_URRN_TLV_V:"); ++ len += scnprintf(buf + len, buf_len - len, "HTT_TX_PDEV_STATS_URRN_TLV_V:\n"); + + PRINT_ARRAY_TO_BUF(urrn_stats, htt_stats_buf->urrn_stats, num_elems); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "urrn_stats = %s\n", urrn_stats); ++ len += scnprintf(buf + len, buf_len - len, "urrn_stats = %s\n\n", urrn_stats); + + if (len >= buf_len) + buf[buf_len - 1] = 0; +@@ -218,10 +215,10 @@ htt_print_tx_pdev_stats_flush_tlv_v(cons + char flush_errs[HTT_MAX_STRING_LEN] = {0}; + u16 num_elems = min_t(u16, (tag_len >> 2), HTT_TX_PDEV_MAX_FLUSH_REASON_STATS); + +- len += HTT_DBG_OUT(buf + len, buf_len - len, "HTT_TX_PDEV_STATS_FLUSH_TLV_V:"); ++ len += scnprintf(buf + len, buf_len - len, "HTT_TX_PDEV_STATS_FLUSH_TLV_V:\n"); + + PRINT_ARRAY_TO_BUF(flush_errs, htt_stats_buf->flush_errs, num_elems); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "flush_errs = %s\n", flush_errs); ++ len += scnprintf(buf + len, buf_len - len, "flush_errs = %s\n\n", flush_errs); + + if (len >= buf_len) + buf[buf_len - 1] = 0; +@@ -243,11 +240,11 @@ htt_print_tx_pdev_stats_sifs_tlv_v(const + char sifs_status[HTT_MAX_STRING_LEN] = {0}; + u16 num_elems = min_t(u16, (tag_len >> 2), HTT_TX_PDEV_MAX_SIFS_BURST_STATS); + +- len += HTT_DBG_OUT(buf + len, buf_len - len, "HTT_TX_PDEV_STATS_SIFS_TLV_V:"); ++ len += scnprintf(buf + len, buf_len - len, "HTT_TX_PDEV_STATS_SIFS_TLV_V:\n"); + + PRINT_ARRAY_TO_BUF(sifs_status, htt_stats_buf->sifs_status, num_elems); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "sifs_status = %s\n", +- sifs_status); ++ len += scnprintf(buf + len, buf_len - len, "sifs_status = %s\n\n", ++ sifs_status); + + if (len >= buf_len) + buf[buf_len - 1] = 0; +@@ -269,10 +266,10 @@ htt_print_tx_pdev_stats_phy_err_tlv_v(co + char phy_errs[HTT_MAX_STRING_LEN] = {0}; + u16 num_elems = min_t(u16, (tag_len >> 2), HTT_TX_PDEV_MAX_PHY_ERR_STATS); + +- len += HTT_DBG_OUT(buf + len, buf_len - len, "HTT_TX_PDEV_STATS_PHY_ERR_TLV_V:"); ++ len += scnprintf(buf + len, buf_len - len, "HTT_TX_PDEV_STATS_PHY_ERR_TLV_V:\n"); + + PRINT_ARRAY_TO_BUF(phy_errs, htt_stats_buf->phy_errs, num_elems); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "phy_errs = %s\n", phy_errs); ++ len += scnprintf(buf + len, buf_len - len, "phy_errs = %s\n\n", phy_errs); + + if (len >= buf_len) + buf[buf_len - 1] = 0; +@@ -294,12 +291,12 @@ htt_print_tx_pdev_stats_sifs_hist_tlv_v( + char sifs_hist_status[HTT_MAX_STRING_LEN] = {0}; + u16 num_elems = min_t(u16, (tag_len >> 2), HTT_TX_PDEV_MAX_SIFS_BURST_HIST_STATS); + +- len += HTT_DBG_OUT(buf + len, buf_len - len, +- "HTT_TX_PDEV_STATS_SIFS_HIST_TLV_V:"); ++ len += scnprintf(buf + len, buf_len - len, ++ "HTT_TX_PDEV_STATS_SIFS_HIST_TLV_V:\n"); + + PRINT_ARRAY_TO_BUF(sifs_hist_status, htt_stats_buf->sifs_hist_status, num_elems); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "sifs_hist_status = %s\n", +- sifs_hist_status); ++ len += scnprintf(buf + len, buf_len - len, "sifs_hist_status = %s\n\n", ++ sifs_hist_status); + + if (len >= buf_len) + buf[buf_len - 1] = 0; +@@ -318,23 +315,23 @@ htt_print_tx_pdev_stats_tx_ppdu_stats_tl + u32 len = stats_req->buf_len; + u32 buf_len = ATH11K_HTT_STATS_BUF_SIZE; + +- len += HTT_DBG_OUT(buf + len, buf_len - len, +- "HTT_TX_PDEV_STATS_TX_PPDU_STATS_TLV_V:"); ++ len += scnprintf(buf + len, buf_len - len, ++ "HTT_TX_PDEV_STATS_TX_PPDU_STATS_TLV_V:\n"); + +- len += HTT_DBG_OUT(buf + len, buf_len - len, "num_data_ppdus_legacy_su = %u", +- htt_stats_buf->num_data_ppdus_legacy_su); ++ len += scnprintf(buf + len, buf_len - len, "num_data_ppdus_legacy_su = %u\n", ++ htt_stats_buf->num_data_ppdus_legacy_su); + +- len += HTT_DBG_OUT(buf + len, buf_len - len, "num_data_ppdus_ac_su = %u", +- htt_stats_buf->num_data_ppdus_ac_su); ++ len += scnprintf(buf + len, buf_len - len, "num_data_ppdus_ac_su = %u\n", ++ htt_stats_buf->num_data_ppdus_ac_su); + +- len += HTT_DBG_OUT(buf + len, buf_len - len, "num_data_ppdus_ax_su = %u", +- htt_stats_buf->num_data_ppdus_ax_su); ++ len += scnprintf(buf + len, buf_len - len, "num_data_ppdus_ax_su = %u\n", ++ htt_stats_buf->num_data_ppdus_ax_su); + +- len += HTT_DBG_OUT(buf + len, buf_len - len, "num_data_ppdus_ac_su_txbf = %u", +- htt_stats_buf->num_data_ppdus_ac_su_txbf); ++ len += scnprintf(buf + len, buf_len - len, "num_data_ppdus_ac_su_txbf = %u\n", ++ htt_stats_buf->num_data_ppdus_ac_su_txbf); + +- len += HTT_DBG_OUT(buf + len, buf_len - len, "num_data_ppdus_ax_su_txbf = %u\n", +- htt_stats_buf->num_data_ppdus_ax_su_txbf); ++ len += scnprintf(buf + len, buf_len - len, "num_data_ppdus_ax_su_txbf = %u\n\n", ++ htt_stats_buf->num_data_ppdus_ax_su_txbf); + + if (len >= buf_len) + buf[buf_len - 1] = 0; +@@ -357,20 +354,20 @@ htt_print_tx_pdev_stats_tried_mpdu_cnt_h + u32 num_elements = ((tag_len - sizeof(htt_stats_buf->hist_bin_size)) >> 2); + u32 required_buffer_size = HTT_MAX_PRINT_CHAR_PER_ELEM * num_elements; + +- len += HTT_DBG_OUT(buf + len, buf_len - len, +- "HTT_TX_PDEV_STATS_TRIED_MPDU_CNT_HIST_TLV_V:"); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "TRIED_MPDU_CNT_HIST_BIN_SIZE : %u", +- htt_stats_buf->hist_bin_size); ++ len += scnprintf(buf + len, buf_len - len, ++ "HTT_TX_PDEV_STATS_TRIED_MPDU_CNT_HIST_TLV_V:\n"); ++ len += scnprintf(buf + len, buf_len - len, "TRIED_MPDU_CNT_HIST_BIN_SIZE : %u\n", ++ htt_stats_buf->hist_bin_size); + + if (required_buffer_size < HTT_MAX_STRING_LEN) { + PRINT_ARRAY_TO_BUF(tried_mpdu_cnt_hist, + htt_stats_buf->tried_mpdu_cnt_hist, + num_elements); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "tried_mpdu_cnt_hist = %s\n", +- tried_mpdu_cnt_hist); ++ len += scnprintf(buf + len, buf_len - len, "tried_mpdu_cnt_hist = %s\n\n", ++ tried_mpdu_cnt_hist); + } else { +- len += HTT_DBG_OUT(buf + len, buf_len - len, +- "INSUFFICIENT PRINT BUFFER\n"); ++ len += scnprintf(buf + len, buf_len - len, ++ "INSUFFICIENT PRINT BUFFER\n\n"); + } + + if (len >= buf_len) +@@ -390,14 +387,14 @@ static inline void htt_print_hw_stats_in + u32 buf_len = ATH11K_HTT_STATS_BUF_SIZE; + char hw_intr_name[HTT_STATS_MAX_HW_INTR_NAME_LEN + 1] = {0}; + +- len += HTT_DBG_OUT(buf + len, buf_len - len, "HTT_HW_STATS_INTR_MISC_TLV:"); ++ len += scnprintf(buf + len, buf_len - len, "HTT_HW_STATS_INTR_MISC_TLV:\n"); + memcpy(hw_intr_name, &(htt_stats_buf->hw_intr_name[0]), + HTT_STATS_MAX_HW_INTR_NAME_LEN); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "hw_intr_name = %s ", hw_intr_name); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "mask = %u", +- htt_stats_buf->mask); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "count = %u\n", +- htt_stats_buf->count); ++ len += scnprintf(buf + len, buf_len - len, "hw_intr_name = %s\n", hw_intr_name); ++ len += scnprintf(buf + len, buf_len - len, "mask = %u\n", ++ htt_stats_buf->mask); ++ len += scnprintf(buf + len, buf_len - len, "count = %u\n\n", ++ htt_stats_buf->count); + + if (len >= buf_len) + buf[buf_len - 1] = 0; +@@ -417,13 +414,13 @@ htt_print_hw_stats_wd_timeout_tlv(const + u32 buf_len = ATH11K_HTT_STATS_BUF_SIZE; + char hw_module_name[HTT_STATS_MAX_HW_MODULE_NAME_LEN + 1] = {0}; + +- len += HTT_DBG_OUT(buf + len, buf_len - len, "HTT_HW_STATS_WD_TIMEOUT_TLV:"); ++ len += scnprintf(buf + len, buf_len - len, "HTT_HW_STATS_WD_TIMEOUT_TLV:\n"); + memcpy(hw_module_name, &(htt_stats_buf->hw_module_name[0]), + HTT_STATS_MAX_HW_MODULE_NAME_LEN); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "hw_module_name = %s ", +- hw_module_name); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "count = %u", +- htt_stats_buf->count); ++ len += scnprintf(buf + len, buf_len - len, "hw_module_name = %s\n", ++ hw_module_name); ++ len += scnprintf(buf + len, buf_len - len, "count = %u\n", ++ htt_stats_buf->count); + + if (len >= buf_len) + buf[buf_len - 1] = 0; +@@ -441,29 +438,29 @@ static inline void htt_print_hw_stats_pd + u32 len = stats_req->buf_len; + u32 buf_len = ATH11K_HTT_STATS_BUF_SIZE; + +- len += HTT_DBG_OUT(buf + len, buf_len - len, "HTT_HW_STATS_PDEV_ERRS_TLV:"); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "mac_id = %u", +- htt_stats_buf->mac_id__word & 0xFF); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "tx_abort = %u", +- htt_stats_buf->tx_abort); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "tx_abort_fail_count = %u", +- htt_stats_buf->tx_abort_fail_count); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "rx_abort = %u", +- htt_stats_buf->rx_abort); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "rx_abort_fail_count = %u", +- htt_stats_buf->rx_abort_fail_count); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "warm_reset = %u", +- htt_stats_buf->warm_reset); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "cold_reset = %u", +- htt_stats_buf->cold_reset); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "tx_flush = %u", +- htt_stats_buf->tx_flush); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "tx_glb_reset = %u", +- htt_stats_buf->tx_glb_reset); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "tx_txq_reset = %u", +- htt_stats_buf->tx_txq_reset); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "rx_timeout_reset = %u\n", +- htt_stats_buf->rx_timeout_reset); ++ len += scnprintf(buf + len, buf_len - len, "HTT_HW_STATS_PDEV_ERRS_TLV:\n"); ++ len += scnprintf(buf + len, buf_len - len, "mac_id = %u\n", ++ htt_stats_buf->mac_id__word & 0xFF); ++ len += scnprintf(buf + len, buf_len - len, "tx_abort = %u\n", ++ htt_stats_buf->tx_abort); ++ len += scnprintf(buf + len, buf_len - len, "tx_abort_fail_count = %u\n", ++ htt_stats_buf->tx_abort_fail_count); ++ len += scnprintf(buf + len, buf_len - len, "rx_abort = %u\n", ++ htt_stats_buf->rx_abort); ++ len += scnprintf(buf + len, buf_len - len, "rx_abort_fail_count = %u\n", ++ htt_stats_buf->rx_abort_fail_count); ++ len += scnprintf(buf + len, buf_len - len, "warm_reset = %u\n", ++ htt_stats_buf->warm_reset); ++ len += scnprintf(buf + len, buf_len - len, "cold_reset = %u\n", ++ htt_stats_buf->cold_reset); ++ len += scnprintf(buf + len, buf_len - len, "tx_flush = %u\n", ++ htt_stats_buf->tx_flush); ++ len += scnprintf(buf + len, buf_len - len, "tx_glb_reset = %u\n", ++ htt_stats_buf->tx_glb_reset); ++ len += scnprintf(buf + len, buf_len - len, "tx_txq_reset = %u\n", ++ htt_stats_buf->tx_txq_reset); ++ len += scnprintf(buf + len, buf_len - len, "rx_timeout_reset = %u\n\n", ++ htt_stats_buf->rx_timeout_reset); + + if (len >= buf_len) + buf[buf_len - 1] = 0; +@@ -481,35 +478,34 @@ static inline void htt_print_msdu_flow_s + u32 len = stats_req->buf_len; + u32 buf_len = ATH11K_HTT_STATS_BUF_SIZE; + +- len += HTT_DBG_OUT(buf + len, buf_len - len, "HTT_MSDU_FLOW_STATS_TLV:"); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "last_update_timestamp = %u", +- htt_stats_buf->last_update_timestamp); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "last_add_timestamp = %u", +- htt_stats_buf->last_add_timestamp); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "last_remove_timestamp = %u", +- htt_stats_buf->last_remove_timestamp); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "total_processed_msdu_count = %u", +- htt_stats_buf->total_processed_msdu_count); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "cur_msdu_count_in_flowq = %u", +- htt_stats_buf->cur_msdu_count_in_flowq); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "sw_peer_id = %u", +- htt_stats_buf->sw_peer_id); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "tx_flow_no = %u", +- htt_stats_buf->tx_flow_no__tid_num__drop_rule & 0xFFFF); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "tid_num = %u", +- (htt_stats_buf->tx_flow_no__tid_num__drop_rule & 0xF0000) >> +- 16); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "drop_rule = %u", +- (htt_stats_buf->tx_flow_no__tid_num__drop_rule & 0x100000) >> +- 20); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "last_cycle_enqueue_count = %u", +- htt_stats_buf->last_cycle_enqueue_count); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "last_cycle_dequeue_count = %u", +- htt_stats_buf->last_cycle_dequeue_count); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "last_cycle_drop_count = %u", +- htt_stats_buf->last_cycle_drop_count); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "current_drop_th = %u\n", +- htt_stats_buf->current_drop_th); ++ len += scnprintf(buf + len, buf_len - len, "HTT_MSDU_FLOW_STATS_TLV:\n"); ++ len += scnprintf(buf + len, buf_len - len, "last_update_timestamp = %u\n", ++ htt_stats_buf->last_update_timestamp); ++ len += scnprintf(buf + len, buf_len - len, "last_add_timestamp = %u\n", ++ htt_stats_buf->last_add_timestamp); ++ len += scnprintf(buf + len, buf_len - len, "last_remove_timestamp = %u\n", ++ htt_stats_buf->last_remove_timestamp); ++ len += scnprintf(buf + len, buf_len - len, "total_processed_msdu_count = %u\n", ++ htt_stats_buf->total_processed_msdu_count); ++ len += scnprintf(buf + len, buf_len - len, "cur_msdu_count_in_flowq = %u\n", ++ htt_stats_buf->cur_msdu_count_in_flowq); ++ len += scnprintf(buf + len, buf_len - len, "sw_peer_id = %u\n", ++ htt_stats_buf->sw_peer_id); ++ len += scnprintf(buf + len, buf_len - len, "tx_flow_no = %u\n", ++ htt_stats_buf->tx_flow_no__tid_num__drop_rule & 0xFFFF); ++ len += scnprintf(buf + len, buf_len - len, "tid_num = %u\n", ++ (htt_stats_buf->tx_flow_no__tid_num__drop_rule & 0xF0000) >> 16); ++ len += scnprintf(buf + len, buf_len - len, "drop_rule = %u\n", ++ (htt_stats_buf->tx_flow_no__tid_num__drop_rule & 0x100000) >> ++ 20); ++ len += scnprintf(buf + len, buf_len - len, "last_cycle_enqueue_count = %u\n", ++ htt_stats_buf->last_cycle_enqueue_count); ++ len += scnprintf(buf + len, buf_len - len, "last_cycle_dequeue_count = %u\n", ++ htt_stats_buf->last_cycle_dequeue_count); ++ len += scnprintf(buf + len, buf_len - len, "last_cycle_drop_count = %u\n", ++ htt_stats_buf->last_cycle_drop_count); ++ len += scnprintf(buf + len, buf_len - len, "current_drop_th = %u\n\n", ++ htt_stats_buf->current_drop_th); + + if (len >= buf_len) + buf[buf_len - 1] = 0; +@@ -528,38 +524,38 @@ static inline void htt_print_tx_tid_stat + u32 buf_len = ATH11K_HTT_STATS_BUF_SIZE; + char tid_name[MAX_HTT_TID_NAME + 1] = {0}; + +- len += HTT_DBG_OUT(buf + len, buf_len - len, "HTT_TX_TID_STATS_TLV:"); ++ len += scnprintf(buf + len, buf_len - len, "HTT_TX_TID_STATS_TLV:\n"); + memcpy(tid_name, &(htt_stats_buf->tid_name[0]), MAX_HTT_TID_NAME); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "tid_name = %s ", tid_name); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "sw_peer_id = %u", +- htt_stats_buf->sw_peer_id__tid_num & 0xFFFF); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "tid_num = %u", +- (htt_stats_buf->sw_peer_id__tid_num & 0xFFFF0000) >> 16); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "num_sched_pending = %u", +- htt_stats_buf->num_sched_pending__num_ppdu_in_hwq & 0xFF); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "num_ppdu_in_hwq = %u", +- (htt_stats_buf->num_sched_pending__num_ppdu_in_hwq & +- 0xFF00) >> 8); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "tid_flags = 0x%x", +- htt_stats_buf->tid_flags); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "hw_queued = %u", +- htt_stats_buf->hw_queued); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "hw_reaped = %u", +- htt_stats_buf->hw_reaped); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "mpdus_hw_filter = %u", +- htt_stats_buf->mpdus_hw_filter); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "qdepth_bytes = %u", +- htt_stats_buf->qdepth_bytes); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "qdepth_num_msdu = %u", +- htt_stats_buf->qdepth_num_msdu); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "qdepth_num_mpdu = %u", +- htt_stats_buf->qdepth_num_mpdu); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "last_scheduled_tsmp = %u", +- htt_stats_buf->last_scheduled_tsmp); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "pause_module_id = %u", +- htt_stats_buf->pause_module_id); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "block_module_id = %u\n", +- htt_stats_buf->block_module_id); ++ len += scnprintf(buf + len, buf_len - len, "tid_name = %s\n", tid_name); ++ len += scnprintf(buf + len, buf_len - len, "sw_peer_id = %u\n", ++ htt_stats_buf->sw_peer_id__tid_num & 0xFFFF); ++ len += scnprintf(buf + len, buf_len - len, "tid_num = %u\n", ++ (htt_stats_buf->sw_peer_id__tid_num & 0xFFFF0000) >> 16); ++ len += scnprintf(buf + len, buf_len - len, "num_sched_pending = %u\n", ++ htt_stats_buf->num_sched_pending__num_ppdu_in_hwq & 0xFF); ++ len += scnprintf(buf + len, buf_len - len, "num_ppdu_in_hwq = %u\n", ++ (htt_stats_buf->num_sched_pending__num_ppdu_in_hwq & ++ 0xFF00) >> 8); ++ len += scnprintf(buf + len, buf_len - len, "tid_flags = 0x%x\n", ++ htt_stats_buf->tid_flags); ++ len += scnprintf(buf + len, buf_len - len, "hw_queued = %u\n", ++ htt_stats_buf->hw_queued); ++ len += scnprintf(buf + len, buf_len - len, "hw_reaped = %u\n", ++ htt_stats_buf->hw_reaped); ++ len += scnprintf(buf + len, buf_len - len, "mpdus_hw_filter = %u\n", ++ htt_stats_buf->mpdus_hw_filter); ++ len += scnprintf(buf + len, buf_len - len, "qdepth_bytes = %u\n", ++ htt_stats_buf->qdepth_bytes); ++ len += scnprintf(buf + len, buf_len - len, "qdepth_num_msdu = %u\n", ++ htt_stats_buf->qdepth_num_msdu); ++ len += scnprintf(buf + len, buf_len - len, "qdepth_num_mpdu = %u\n", ++ htt_stats_buf->qdepth_num_mpdu); ++ len += scnprintf(buf + len, buf_len - len, "last_scheduled_tsmp = %u\n", ++ htt_stats_buf->last_scheduled_tsmp); ++ len += scnprintf(buf + len, buf_len - len, "pause_module_id = %u\n", ++ htt_stats_buf->pause_module_id); ++ len += scnprintf(buf + len, buf_len - len, "block_module_id = %u\n\n", ++ htt_stats_buf->block_module_id); + + if (len >= buf_len) + buf[buf_len - 1] = 0; +@@ -578,42 +574,42 @@ static inline void htt_print_tx_tid_stat + u32 buf_len = ATH11K_HTT_STATS_BUF_SIZE; + char tid_name[MAX_HTT_TID_NAME + 1] = {0}; + +- len += HTT_DBG_OUT(buf + len, buf_len - len, "HTT_TX_TID_STATS_V1_TLV:"); ++ len += scnprintf(buf + len, buf_len - len, "HTT_TX_TID_STATS_V1_TLV:\n"); + memcpy(tid_name, &(htt_stats_buf->tid_name[0]), MAX_HTT_TID_NAME); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "tid_name = %s ", tid_name); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "sw_peer_id = %u", +- htt_stats_buf->sw_peer_id__tid_num & 0xFFFF); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "tid_num = %u", +- (htt_stats_buf->sw_peer_id__tid_num & 0xFFFF0000) >> 16); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "num_sched_pending = %u", +- htt_stats_buf->num_sched_pending__num_ppdu_in_hwq & 0xFF); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "num_ppdu_in_hwq = %u", +- (htt_stats_buf->num_sched_pending__num_ppdu_in_hwq & +- 0xFF00) >> 8); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "tid_flags = 0x%x", +- htt_stats_buf->tid_flags); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "max_qdepth_bytes = %u", +- htt_stats_buf->max_qdepth_bytes); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "max_qdepth_n_msdus = %u", +- htt_stats_buf->max_qdepth_n_msdus); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "rsvd = %u", +- htt_stats_buf->rsvd); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "qdepth_bytes = %u", +- htt_stats_buf->qdepth_bytes); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "qdepth_num_msdu = %u", +- htt_stats_buf->qdepth_num_msdu); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "qdepth_num_mpdu = %u", +- htt_stats_buf->qdepth_num_mpdu); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "last_scheduled_tsmp = %u", +- htt_stats_buf->last_scheduled_tsmp); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "pause_module_id = %u", +- htt_stats_buf->pause_module_id); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "block_module_id = %u", +- htt_stats_buf->block_module_id); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "allow_n_flags = 0x%x", +- htt_stats_buf->allow_n_flags); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "sendn_frms_allowed = %u\n", +- htt_stats_buf->sendn_frms_allowed); ++ len += scnprintf(buf + len, buf_len - len, "tid_name = %s\n", tid_name); ++ len += scnprintf(buf + len, buf_len - len, "sw_peer_id = %u\n", ++ htt_stats_buf->sw_peer_id__tid_num & 0xFFFF); ++ len += scnprintf(buf + len, buf_len - len, "tid_num = %u\n", ++ (htt_stats_buf->sw_peer_id__tid_num & 0xFFFF0000) >> 16); ++ len += scnprintf(buf + len, buf_len - len, "num_sched_pending = %u\n", ++ htt_stats_buf->num_sched_pending__num_ppdu_in_hwq & 0xFF); ++ len += scnprintf(buf + len, buf_len - len, "num_ppdu_in_hwq = %u\n", ++ (htt_stats_buf->num_sched_pending__num_ppdu_in_hwq & ++ 0xFF00) >> 8); ++ len += scnprintf(buf + len, buf_len - len, "tid_flags = 0x%x\n", ++ htt_stats_buf->tid_flags); ++ len += scnprintf(buf + len, buf_len - len, "max_qdepth_bytes = %u\n", ++ htt_stats_buf->max_qdepth_bytes); ++ len += scnprintf(buf + len, buf_len - len, "max_qdepth_n_msdus = %u\n", ++ htt_stats_buf->max_qdepth_n_msdus); ++ len += scnprintf(buf + len, buf_len - len, "rsvd = %u\n", ++ htt_stats_buf->rsvd); ++ len += scnprintf(buf + len, buf_len - len, "qdepth_bytes = %u\n", ++ htt_stats_buf->qdepth_bytes); ++ len += scnprintf(buf + len, buf_len - len, "qdepth_num_msdu = %u\n", ++ htt_stats_buf->qdepth_num_msdu); ++ len += scnprintf(buf + len, buf_len - len, "qdepth_num_mpdu = %u\n", ++ htt_stats_buf->qdepth_num_mpdu); ++ len += scnprintf(buf + len, buf_len - len, "last_scheduled_tsmp = %u\n", ++ htt_stats_buf->last_scheduled_tsmp); ++ len += scnprintf(buf + len, buf_len - len, "pause_module_id = %u\n", ++ htt_stats_buf->pause_module_id); ++ len += scnprintf(buf + len, buf_len - len, "block_module_id = %u\n", ++ htt_stats_buf->block_module_id); ++ len += scnprintf(buf + len, buf_len - len, "allow_n_flags = 0x%x\n", ++ htt_stats_buf->allow_n_flags); ++ len += scnprintf(buf + len, buf_len - len, "sendn_frms_allowed = %u\n\n", ++ htt_stats_buf->sendn_frms_allowed); + + if (len >= buf_len) + buf[buf_len - 1] = 0; +@@ -632,21 +628,21 @@ static inline void htt_print_rx_tid_stat + u32 buf_len = ATH11K_HTT_STATS_BUF_SIZE; + char tid_name[MAX_HTT_TID_NAME + 1] = {0}; + +- len += HTT_DBG_OUT(buf + len, buf_len - len, "HTT_RX_TID_STATS_TLV:"); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "sw_peer_id = %u", +- htt_stats_buf->sw_peer_id__tid_num & 0xFFFF); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "tid_num = %u", +- (htt_stats_buf->sw_peer_id__tid_num & 0xFFFF0000) >> 16); ++ len += scnprintf(buf + len, buf_len - len, "HTT_RX_TID_STATS_TLV:\n"); ++ len += scnprintf(buf + len, buf_len - len, "sw_peer_id = %u\n", ++ htt_stats_buf->sw_peer_id__tid_num & 0xFFFF); ++ len += scnprintf(buf + len, buf_len - len, "tid_num = %u\n", ++ (htt_stats_buf->sw_peer_id__tid_num & 0xFFFF0000) >> 16); + memcpy(tid_name, &(htt_stats_buf->tid_name[0]), MAX_HTT_TID_NAME); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "tid_name = %s ", tid_name); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "dup_in_reorder = %u", +- htt_stats_buf->dup_in_reorder); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "dup_past_outside_window = %u", +- htt_stats_buf->dup_past_outside_window); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "dup_past_within_window = %u", +- htt_stats_buf->dup_past_within_window); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "rxdesc_err_decrypt = %u\n", +- htt_stats_buf->rxdesc_err_decrypt); ++ len += scnprintf(buf + len, buf_len - len, "tid_name = %s\n", tid_name); ++ len += scnprintf(buf + len, buf_len - len, "dup_in_reorder = %u\n", ++ htt_stats_buf->dup_in_reorder); ++ len += scnprintf(buf + len, buf_len - len, "dup_past_outside_window = %u\n", ++ htt_stats_buf->dup_past_outside_window); ++ len += scnprintf(buf + len, buf_len - len, "dup_past_within_window = %u\n", ++ htt_stats_buf->dup_past_within_window); ++ len += scnprintf(buf + len, buf_len - len, "rxdesc_err_decrypt = %u\n\n", ++ htt_stats_buf->rxdesc_err_decrypt); + + if (len >= buf_len) + buf[buf_len - 1] = 0; +@@ -665,14 +661,14 @@ static inline void htt_print_counter_tlv + u32 buf_len = ATH11K_HTT_STATS_BUF_SIZE; + char counter_name[HTT_MAX_STRING_LEN] = {0}; + +- len += HTT_DBG_OUT(buf + len, buf_len - len, "HTT_COUNTER_TLV:"); ++ len += scnprintf(buf + len, buf_len - len, "HTT_COUNTER_TLV:\n"); + + PRINT_ARRAY_TO_BUF(counter_name, + htt_stats_buf->counter_name, + HTT_MAX_COUNTER_NAME); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "counter_name = %s ", counter_name); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "count = %u\n", +- htt_stats_buf->count); ++ len += scnprintf(buf + len, buf_len - len, "counter_name = %s\n", counter_name); ++ len += scnprintf(buf + len, buf_len - len, "count = %u\n\n", ++ htt_stats_buf->count); + + if (len >= buf_len) + buf[buf_len - 1] = 0; +@@ -690,35 +686,35 @@ static inline void htt_print_peer_stats_ + u32 len = stats_req->buf_len; + u32 buf_len = ATH11K_HTT_STATS_BUF_SIZE; + +- len += HTT_DBG_OUT(buf + len, buf_len - len, "HTT_PEER_STATS_CMN_TLV:"); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "ppdu_cnt = %u", +- htt_stats_buf->ppdu_cnt); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "mpdu_cnt = %u", +- htt_stats_buf->mpdu_cnt); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "msdu_cnt = %u", +- htt_stats_buf->msdu_cnt); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "pause_bitmap = %u", +- htt_stats_buf->pause_bitmap); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "block_bitmap = %u", +- htt_stats_buf->block_bitmap); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "last_rssi = %d", +- htt_stats_buf->rssi); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "enqueued_count = %llu", +- htt_stats_buf->peer_enqueued_count_low | +- ((u64)htt_stats_buf->peer_enqueued_count_high << 32)); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "dequeued_count = %llu", +- htt_stats_buf->peer_dequeued_count_low | +- ((u64)htt_stats_buf->peer_dequeued_count_high << 32)); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "dropped_count = %llu", +- htt_stats_buf->peer_dropped_count_low | +- ((u64)htt_stats_buf->peer_dropped_count_high << 32)); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "transmitted_ppdu_bytes = %llu", +- htt_stats_buf->ppdu_transmitted_bytes_low | +- ((u64)htt_stats_buf->ppdu_transmitted_bytes_high << 32)); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "ttl_removed_count = %u", +- htt_stats_buf->peer_ttl_removed_count); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "inactive_time = %u\n", +- htt_stats_buf->inactive_time); ++ len += scnprintf(buf + len, buf_len - len, "HTT_PEER_STATS_CMN_TLV:\n"); ++ len += scnprintf(buf + len, buf_len - len, "ppdu_cnt = %u\n", ++ htt_stats_buf->ppdu_cnt); ++ len += scnprintf(buf + len, buf_len - len, "mpdu_cnt = %u\n", ++ htt_stats_buf->mpdu_cnt); ++ len += scnprintf(buf + len, buf_len - len, "msdu_cnt = %u\n", ++ htt_stats_buf->msdu_cnt); ++ len += scnprintf(buf + len, buf_len - len, "pause_bitmap = %u\n", ++ htt_stats_buf->pause_bitmap); ++ len += scnprintf(buf + len, buf_len - len, "block_bitmap = %u\n", ++ htt_stats_buf->block_bitmap); ++ len += scnprintf(buf + len, buf_len - len, "last_rssi = %d\n", ++ htt_stats_buf->rssi); ++ len += scnprintf(buf + len, buf_len - len, "enqueued_count = %llu\n", ++ htt_stats_buf->peer_enqueued_count_low | ++ ((u64)htt_stats_buf->peer_enqueued_count_high << 32)); ++ len += scnprintf(buf + len, buf_len - len, "dequeued_count = %llu\n", ++ htt_stats_buf->peer_dequeued_count_low | ++ ((u64)htt_stats_buf->peer_dequeued_count_high << 32)); ++ len += scnprintf(buf + len, buf_len - len, "dropped_count = %llu\n", ++ htt_stats_buf->peer_dropped_count_low | ++ ((u64)htt_stats_buf->peer_dropped_count_high << 32)); ++ len += scnprintf(buf + len, buf_len - len, "transmitted_ppdu_bytes = %llu\n", ++ htt_stats_buf->ppdu_transmitted_bytes_low | ++ ((u64)htt_stats_buf->ppdu_transmitted_bytes_high << 32)); ++ len += scnprintf(buf + len, buf_len - len, "ttl_removed_count = %u\n", ++ htt_stats_buf->peer_ttl_removed_count); ++ len += scnprintf(buf + len, buf_len - len, "inactive_time = %u\n\n", ++ htt_stats_buf->inactive_time); + + if (len >= buf_len) + buf[buf_len - 1] = 0; +@@ -736,29 +732,29 @@ static inline void htt_print_peer_detail + u32 len = stats_req->buf_len; + u32 buf_len = ATH11K_HTT_STATS_BUF_SIZE; + +- len += HTT_DBG_OUT(buf + len, buf_len - len, "HTT_PEER_DETAILS_TLV:"); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "peer_type = %u", +- htt_stats_buf->peer_type); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "sw_peer_id = %u", +- htt_stats_buf->sw_peer_id); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "vdev_id = %u", +- htt_stats_buf->vdev_pdev_ast_idx & 0xFF); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "pdev_id = %u", +- (htt_stats_buf->vdev_pdev_ast_idx & 0xFF00) >> 8); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "ast_idx = %u", +- (htt_stats_buf->vdev_pdev_ast_idx & 0xFFFF0000) >> 16); +- len += HTT_DBG_OUT(buf + len, buf_len - len, +- "mac_addr = %02x:%02x:%02x:%02x:%02x:%02x", +- htt_stats_buf->mac_addr.mac_addr_l32 & 0xFF, +- (htt_stats_buf->mac_addr.mac_addr_l32 & 0xFF00) >> 8, +- (htt_stats_buf->mac_addr.mac_addr_l32 & 0xFF0000) >> 16, +- (htt_stats_buf->mac_addr.mac_addr_l32 & 0xFF000000) >> 24, +- (htt_stats_buf->mac_addr.mac_addr_h16 & 0xFF), +- (htt_stats_buf->mac_addr.mac_addr_h16 & 0xFF00) >> 8); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "peer_flags = 0x%x", +- htt_stats_buf->peer_flags); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "qpeer_flags = 0x%x\n", +- htt_stats_buf->qpeer_flags); ++ len += scnprintf(buf + len, buf_len - len, "HTT_PEER_DETAILS_TLV:\n"); ++ len += scnprintf(buf + len, buf_len - len, "peer_type = %u\n", ++ htt_stats_buf->peer_type); ++ len += scnprintf(buf + len, buf_len - len, "sw_peer_id = %u\n", ++ htt_stats_buf->sw_peer_id); ++ len += scnprintf(buf + len, buf_len - len, "vdev_id = %u\n", ++ htt_stats_buf->vdev_pdev_ast_idx & 0xFF); ++ len += scnprintf(buf + len, buf_len - len, "pdev_id = %u\n", ++ (htt_stats_buf->vdev_pdev_ast_idx & 0xFF00) >> 8); ++ len += scnprintf(buf + len, buf_len - len, "ast_idx = %u\n", ++ (htt_stats_buf->vdev_pdev_ast_idx & 0xFFFF0000) >> 16); ++ len += scnprintf(buf + len, buf_len - len, ++ "mac_addr = %02x:%02x:%02x:%02x:%02x:%02x\n", ++ htt_stats_buf->mac_addr.mac_addr_l32 & 0xFF, ++ (htt_stats_buf->mac_addr.mac_addr_l32 & 0xFF00) >> 8, ++ (htt_stats_buf->mac_addr.mac_addr_l32 & 0xFF0000) >> 16, ++ (htt_stats_buf->mac_addr.mac_addr_l32 & 0xFF000000) >> 24, ++ (htt_stats_buf->mac_addr.mac_addr_h16 & 0xFF), ++ (htt_stats_buf->mac_addr.mac_addr_h16 & 0xFF00) >> 8); ++ len += scnprintf(buf + len, buf_len - len, "peer_flags = 0x%x\n", ++ htt_stats_buf->peer_flags); ++ len += scnprintf(buf + len, buf_len - len, "qpeer_flags = 0x%x\n\n", ++ htt_stats_buf->qpeer_flags); + + if (len >= buf_len) + buf[buf_len - 1] = 0; +@@ -785,64 +781,64 @@ static inline void htt_print_tx_peer_rat + goto fail; + } + +- len += HTT_DBG_OUT(buf + len, buf_len - len, "HTT_TX_PEER_RATE_STATS_TLV:"); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "tx_ldpc = %u", +- htt_stats_buf->tx_ldpc); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "rts_cnt = %u", +- htt_stats_buf->rts_cnt); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "ack_rssi = %u", +- htt_stats_buf->ack_rssi); ++ len += scnprintf(buf + len, buf_len - len, "HTT_TX_PEER_RATE_STATS_TLV:\n"); ++ len += scnprintf(buf + len, buf_len - len, "tx_ldpc = %u\n", ++ htt_stats_buf->tx_ldpc); ++ len += scnprintf(buf + len, buf_len - len, "rts_cnt = %u\n", ++ htt_stats_buf->rts_cnt); ++ len += scnprintf(buf + len, buf_len - len, "ack_rssi = %u\n", ++ htt_stats_buf->ack_rssi); + + memset(str_buf, 0x0, HTT_MAX_STRING_LEN); + PRINT_ARRAY_TO_BUF(str_buf, htt_stats_buf->tx_mcs, + HTT_TX_PDEV_STATS_NUM_MCS_COUNTERS); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "tx_mcs = %s ", str_buf); ++ len += scnprintf(buf + len, buf_len - len, "tx_mcs = %s\n", str_buf); + + memset(str_buf, 0x0, HTT_MAX_STRING_LEN); + PRINT_ARRAY_TO_BUF(str_buf, htt_stats_buf->tx_su_mcs, + HTT_TX_PDEV_STATS_NUM_MCS_COUNTERS); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "tx_su_mcs = %s ", str_buf); ++ len += scnprintf(buf + len, buf_len - len, "tx_su_mcs = %s\n", str_buf); + + memset(str_buf, 0x0, HTT_MAX_STRING_LEN); + PRINT_ARRAY_TO_BUF(str_buf, htt_stats_buf->tx_mu_mcs, + HTT_TX_PDEV_STATS_NUM_MCS_COUNTERS); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "tx_mu_mcs = %s ", str_buf); ++ len += scnprintf(buf + len, buf_len - len, "tx_mu_mcs = %s\n", str_buf); + + memset(str_buf, 0x0, HTT_MAX_STRING_LEN); + PRINT_ARRAY_TO_BUF(str_buf, + htt_stats_buf->tx_nss, + HTT_TX_PDEV_STATS_NUM_SPATIAL_STREAMS); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "tx_nss = %s ", str_buf); ++ len += scnprintf(buf + len, buf_len - len, "tx_nss = %s\n", str_buf); + + memset(str_buf, 0x0, HTT_MAX_STRING_LEN); + PRINT_ARRAY_TO_BUF(str_buf, + htt_stats_buf->tx_bw, + HTT_TX_PDEV_STATS_NUM_BW_COUNTERS); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "tx_bw = %s ", str_buf); ++ len += scnprintf(buf + len, buf_len - len, "tx_bw = %s\n", str_buf); + + memset(str_buf, 0x0, HTT_MAX_STRING_LEN); + PRINT_ARRAY_TO_BUF(str_buf, htt_stats_buf->tx_stbc, + HTT_TX_PDEV_STATS_NUM_MCS_COUNTERS); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "tx_stbc = %s ", str_buf); ++ len += scnprintf(buf + len, buf_len - len, "tx_stbc = %s\n", str_buf); + + memset(str_buf, 0x0, HTT_MAX_STRING_LEN); + PRINT_ARRAY_TO_BUF(str_buf, htt_stats_buf->tx_pream, + HTT_TX_PDEV_STATS_NUM_PREAMBLE_TYPES); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "tx_pream = %s ", str_buf); ++ len += scnprintf(buf + len, buf_len - len, "tx_pream = %s\n", str_buf); + + for (j = 0; j < HTT_TX_PEER_STATS_NUM_GI_COUNTERS; j++) { + PRINT_ARRAY_TO_BUF(tx_gi[j], + htt_stats_buf->tx_gi[j], + HTT_TX_PEER_STATS_NUM_MCS_COUNTERS); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "tx_gi[%u] = %s ", +- j, tx_gi[j]); ++ len += scnprintf(buf + len, buf_len - len, "tx_gi[%u] = %s\n", ++ j, tx_gi[j]); + } + + memset(str_buf, 0x0, HTT_MAX_STRING_LEN); + PRINT_ARRAY_TO_BUF(str_buf, + htt_stats_buf->tx_dcm, + HTT_TX_PDEV_STATS_NUM_DCM_COUNTERS); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "tx_dcm = %s\n", str_buf); ++ len += scnprintf(buf + len, buf_len - len, "tx_dcm = %s\n\n", str_buf); + + if (len >= buf_len) + buf[buf_len - 1] = 0; +@@ -880,63 +876,63 @@ static inline void htt_print_rx_peer_rat + goto fail; + } + +- len += HTT_DBG_OUT(buf + len, buf_len - len, "HTT_RX_PEER_RATE_STATS_TLV:"); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "nsts = %u", +- htt_stats_buf->nsts); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "rx_ldpc = %u", +- htt_stats_buf->rx_ldpc); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "rts_cnt = %u", +- htt_stats_buf->rts_cnt); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "rssi_mgmt = %u", +- htt_stats_buf->rssi_mgmt); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "rssi_data = %u", +- htt_stats_buf->rssi_data); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "rssi_comb = %u", +- htt_stats_buf->rssi_comb); ++ len += scnprintf(buf + len, buf_len - len, "HTT_RX_PEER_RATE_STATS_TLV:\n"); ++ len += scnprintf(buf + len, buf_len - len, "nsts = %u\n", ++ htt_stats_buf->nsts); ++ len += scnprintf(buf + len, buf_len - len, "rx_ldpc = %u\n", ++ htt_stats_buf->rx_ldpc); ++ len += scnprintf(buf + len, buf_len - len, "rts_cnt = %u\n", ++ htt_stats_buf->rts_cnt); ++ len += scnprintf(buf + len, buf_len - len, "rssi_mgmt = %u\n", ++ htt_stats_buf->rssi_mgmt); ++ len += scnprintf(buf + len, buf_len - len, "rssi_data = %u\n", ++ htt_stats_buf->rssi_data); ++ len += scnprintf(buf + len, buf_len - len, "rssi_comb = %u\n", ++ htt_stats_buf->rssi_comb); + + memset(str_buf, 0x0, HTT_MAX_STRING_LEN); + PRINT_ARRAY_TO_BUF(str_buf, htt_stats_buf->rx_mcs, + HTT_RX_PDEV_STATS_NUM_MCS_COUNTERS); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "rx_mcs = %s ", str_buf); ++ len += scnprintf(buf + len, buf_len - len, "rx_mcs = %s\n", str_buf); + + memset(str_buf, 0x0, HTT_MAX_STRING_LEN); + PRINT_ARRAY_TO_BUF(str_buf, htt_stats_buf->rx_nss, + HTT_RX_PDEV_STATS_NUM_SPATIAL_STREAMS); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "rx_nss = %s ", str_buf); ++ len += scnprintf(buf + len, buf_len - len, "rx_nss = %s\n", str_buf); + + memset(str_buf, 0x0, HTT_MAX_STRING_LEN); + PRINT_ARRAY_TO_BUF(str_buf, htt_stats_buf->rx_dcm, + HTT_RX_PDEV_STATS_NUM_DCM_COUNTERS); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "rx_dcm = %s ", str_buf); ++ len += scnprintf(buf + len, buf_len - len, "rx_dcm = %s\n", str_buf); + + memset(str_buf, 0x0, HTT_MAX_STRING_LEN); + PRINT_ARRAY_TO_BUF(str_buf, htt_stats_buf->rx_stbc, + HTT_RX_PDEV_STATS_NUM_MCS_COUNTERS); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "rx_stbc = %s ", str_buf); ++ len += scnprintf(buf + len, buf_len - len, "rx_stbc = %s\n", str_buf); + + memset(str_buf, 0x0, HTT_MAX_STRING_LEN); + PRINT_ARRAY_TO_BUF(str_buf, htt_stats_buf->rx_bw, + HTT_RX_PDEV_STATS_NUM_BW_COUNTERS); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "rx_bw = %s ", str_buf); ++ len += scnprintf(buf + len, buf_len - len, "rx_bw = %s\n", str_buf); + + for (j = 0; j < HTT_RX_PEER_STATS_NUM_SPATIAL_STREAMS; j++) { + PRINT_ARRAY_TO_BUF(rssi_chain[j], htt_stats_buf->rssi_chain[j], + HTT_RX_PEER_STATS_NUM_BW_COUNTERS); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "rssi_chain[%u] = %s ", +- j, rssi_chain[j]); ++ len += scnprintf(buf + len, buf_len - len, "rssi_chain[%u] = %s\n", ++ j, rssi_chain[j]); + } + + for (j = 0; j < HTT_RX_PEER_STATS_NUM_GI_COUNTERS; j++) { + PRINT_ARRAY_TO_BUF(rx_gi[j], htt_stats_buf->rx_gi[j], + HTT_RX_PDEV_STATS_NUM_MCS_COUNTERS); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "rx_gi[%u] = %s ", +- j, rx_gi[j]); ++ len += scnprintf(buf + len, buf_len - len, "rx_gi[%u] = %s\n", ++ j, rx_gi[j]); + } + + memset(str_buf, 0x0, HTT_MAX_STRING_LEN); + PRINT_ARRAY_TO_BUF(str_buf, htt_stats_buf->rx_pream, + HTT_RX_PDEV_STATS_NUM_PREAMBLE_TYPES); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "rx_pream = %s\n", str_buf); ++ len += scnprintf(buf + len, buf_len - len, "rx_pream = %s\n\n", str_buf); + + if (len >= buf_len) + buf[buf_len - 1] = 0; +@@ -962,13 +958,13 @@ htt_print_tx_hwq_mu_mimo_sch_stats_tlv(c + u32 len = stats_req->buf_len; + u32 buf_len = ATH11K_HTT_STATS_BUF_SIZE; + +- len += HTT_DBG_OUT(buf + len, buf_len - len, "HTT_TX_HWQ_MU_MIMO_SCH_STATS_TLV:"); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "mu_mimo_sch_posted = %u", +- htt_stats_buf->mu_mimo_sch_posted); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "mu_mimo_sch_failed = %u", +- htt_stats_buf->mu_mimo_sch_failed); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "mu_mimo_ppdu_posted = %u\n", +- htt_stats_buf->mu_mimo_ppdu_posted); ++ len += scnprintf(buf + len, buf_len - len, "HTT_TX_HWQ_MU_MIMO_SCH_STATS_TLV:\n"); ++ len += scnprintf(buf + len, buf_len - len, "mu_mimo_sch_posted = %u\n", ++ htt_stats_buf->mu_mimo_sch_posted); ++ len += scnprintf(buf + len, buf_len - len, "mu_mimo_sch_failed = %u\n", ++ htt_stats_buf->mu_mimo_sch_failed); ++ len += scnprintf(buf + len, buf_len - len, "mu_mimo_ppdu_posted = %u\n\n", ++ htt_stats_buf->mu_mimo_ppdu_posted); + + if (len >= buf_len) + buf[buf_len - 1] = 0; +@@ -987,22 +983,22 @@ htt_print_tx_hwq_mu_mimo_mpdu_stats_tlv( + u32 len = stats_req->buf_len; + u32 buf_len = ATH11K_HTT_STATS_BUF_SIZE; + +- len += HTT_DBG_OUT(buf + len, buf_len - len, +- "HTT_TX_HWQ_MU_MIMO_MPDU_STATS_TLV:"); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "mu_mimo_mpdus_queued_usr = %u", +- htt_stats_buf->mu_mimo_mpdus_queued_usr); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "mu_mimo_mpdus_tried_usr = %u", +- htt_stats_buf->mu_mimo_mpdus_tried_usr); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "mu_mimo_mpdus_failed_usr = %u", +- htt_stats_buf->mu_mimo_mpdus_failed_usr); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "mu_mimo_mpdus_requeued_usr = %u", +- htt_stats_buf->mu_mimo_mpdus_requeued_usr); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "mu_mimo_err_no_ba_usr = %u", +- htt_stats_buf->mu_mimo_err_no_ba_usr); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "mu_mimo_mpdu_underrun_usr = %u", +- htt_stats_buf->mu_mimo_mpdu_underrun_usr); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "mu_mimo_ampdu_underrun_usr = %u\n", +- htt_stats_buf->mu_mimo_ampdu_underrun_usr); ++ len += scnprintf(buf + len, buf_len - len, ++ "HTT_TX_HWQ_MU_MIMO_MPDU_STATS_TLV:\n"); ++ len += scnprintf(buf + len, buf_len - len, "mu_mimo_mpdus_queued_usr = %u\n", ++ htt_stats_buf->mu_mimo_mpdus_queued_usr); ++ len += scnprintf(buf + len, buf_len - len, "mu_mimo_mpdus_tried_usr = %u\n", ++ htt_stats_buf->mu_mimo_mpdus_tried_usr); ++ len += scnprintf(buf + len, buf_len - len, "mu_mimo_mpdus_failed_usr = %u\n", ++ htt_stats_buf->mu_mimo_mpdus_failed_usr); ++ len += scnprintf(buf + len, buf_len - len, "mu_mimo_mpdus_requeued_usr = %u\n", ++ htt_stats_buf->mu_mimo_mpdus_requeued_usr); ++ len += scnprintf(buf + len, buf_len - len, "mu_mimo_err_no_ba_usr = %u\n", ++ htt_stats_buf->mu_mimo_err_no_ba_usr); ++ len += scnprintf(buf + len, buf_len - len, "mu_mimo_mpdu_underrun_usr = %u\n", ++ htt_stats_buf->mu_mimo_mpdu_underrun_usr); ++ len += scnprintf(buf + len, buf_len - len, "mu_mimo_ampdu_underrun_usr = %u\n\n", ++ htt_stats_buf->mu_mimo_ampdu_underrun_usr); + + if (len >= buf_len) + buf[buf_len - 1] = 0; +@@ -1021,11 +1017,11 @@ htt_print_tx_hwq_mu_mimo_cmn_stats_tlv(c + u32 len = stats_req->buf_len; + u32 buf_len = ATH11K_HTT_STATS_BUF_SIZE; + +- len += HTT_DBG_OUT(buf + len, buf_len - len, "HTT_TX_HWQ_MU_MIMO_CMN_STATS_TLV:"); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "mac_id = %u", +- htt_stats_buf->mac_id__hwq_id__word & 0xFF); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "hwq_id = %u\n", +- (htt_stats_buf->mac_id__hwq_id__word & 0xFF00) >> 8); ++ len += scnprintf(buf + len, buf_len - len, "HTT_TX_HWQ_MU_MIMO_CMN_STATS_TLV:\n"); ++ len += scnprintf(buf + len, buf_len - len, "mac_id = %u\n", ++ htt_stats_buf->mac_id__hwq_id__word & 0xFF); ++ len += scnprintf(buf + len, buf_len - len, "hwq_id = %u\n\n", ++ (htt_stats_buf->mac_id__hwq_id__word & 0xFF00) >> 8); + + if (len >= buf_len) + buf[buf_len - 1] = 0; +@@ -1044,51 +1040,51 @@ htt_print_tx_hwq_stats_cmn_tlv(const voi + u32 buf_len = ATH11K_HTT_STATS_BUF_SIZE; + + /* TODO: HKDBG */ +- len += HTT_DBG_OUT(buf + len, buf_len - len, "HTT_TX_HWQ_STATS_CMN_TLV:"); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "mac_id = %u", +- htt_stats_buf->mac_id__hwq_id__word & 0xFF); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "hwq_id = %u", +- (htt_stats_buf->mac_id__hwq_id__word & 0xFF00) >> 8); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "xretry = %u", +- htt_stats_buf->xretry); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "underrun_cnt = %u", +- htt_stats_buf->underrun_cnt); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "flush_cnt = %u", +- htt_stats_buf->flush_cnt); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "filt_cnt = %u", +- htt_stats_buf->filt_cnt); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "null_mpdu_bmap = %u", +- htt_stats_buf->null_mpdu_bmap); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "user_ack_failure = %u", +- htt_stats_buf->user_ack_failure); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "ack_tlv_proc = %u", +- htt_stats_buf->ack_tlv_proc); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "sched_id_proc = %u", +- htt_stats_buf->sched_id_proc); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "null_mpdu_tx_count = %u", +- htt_stats_buf->null_mpdu_tx_count); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "mpdu_bmap_not_recvd = %u", +- htt_stats_buf->mpdu_bmap_not_recvd); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "num_bar = %u", +- htt_stats_buf->num_bar); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "rts = %u", +- htt_stats_buf->rts); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "cts2self = %u", +- htt_stats_buf->cts2self); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "qos_null = %u", +- htt_stats_buf->qos_null); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "mpdu_tried_cnt = %u", +- htt_stats_buf->mpdu_tried_cnt); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "mpdu_queued_cnt = %u", +- htt_stats_buf->mpdu_queued_cnt); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "mpdu_ack_fail_cnt = %u", +- htt_stats_buf->mpdu_ack_fail_cnt); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "mpdu_filt_cnt = %u", +- htt_stats_buf->mpdu_filt_cnt); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "false_mpdu_ack_count = %u", +- htt_stats_buf->false_mpdu_ack_count); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "txq_timeout = %u\n", +- htt_stats_buf->txq_timeout); ++ len += scnprintf(buf + len, buf_len - len, "HTT_TX_HWQ_STATS_CMN_TLV:\n"); ++ len += scnprintf(buf + len, buf_len - len, "mac_id = %u\n", ++ htt_stats_buf->mac_id__hwq_id__word & 0xFF); ++ len += scnprintf(buf + len, buf_len - len, "hwq_id = %u\n", ++ (htt_stats_buf->mac_id__hwq_id__word & 0xFF00) >> 8); ++ len += scnprintf(buf + len, buf_len - len, "xretry = %u\n", ++ htt_stats_buf->xretry); ++ len += scnprintf(buf + len, buf_len - len, "underrun_cnt = %u\n", ++ htt_stats_buf->underrun_cnt); ++ len += scnprintf(buf + len, buf_len - len, "flush_cnt = %u\n", ++ htt_stats_buf->flush_cnt); ++ len += scnprintf(buf + len, buf_len - len, "filt_cnt = %u\n", ++ htt_stats_buf->filt_cnt); ++ len += scnprintf(buf + len, buf_len - len, "null_mpdu_bmap = %u\n", ++ htt_stats_buf->null_mpdu_bmap); ++ len += scnprintf(buf + len, buf_len - len, "user_ack_failure = %u\n", ++ htt_stats_buf->user_ack_failure); ++ len += scnprintf(buf + len, buf_len - len, "ack_tlv_proc = %u\n", ++ htt_stats_buf->ack_tlv_proc); ++ len += scnprintf(buf + len, buf_len - len, "sched_id_proc = %u\n", ++ htt_stats_buf->sched_id_proc); ++ len += scnprintf(buf + len, buf_len - len, "null_mpdu_tx_count = %u\n", ++ htt_stats_buf->null_mpdu_tx_count); ++ len += scnprintf(buf + len, buf_len - len, "mpdu_bmap_not_recvd = %u\n", ++ htt_stats_buf->mpdu_bmap_not_recvd); ++ len += scnprintf(buf + len, buf_len - len, "num_bar = %u\n", ++ htt_stats_buf->num_bar); ++ len += scnprintf(buf + len, buf_len - len, "rts = %u\n", ++ htt_stats_buf->rts); ++ len += scnprintf(buf + len, buf_len - len, "cts2self = %u\n", ++ htt_stats_buf->cts2self); ++ len += scnprintf(buf + len, buf_len - len, "qos_null = %u\n", ++ htt_stats_buf->qos_null); ++ len += scnprintf(buf + len, buf_len - len, "mpdu_tried_cnt = %u\n", ++ htt_stats_buf->mpdu_tried_cnt); ++ len += scnprintf(buf + len, buf_len - len, "mpdu_queued_cnt = %u\n", ++ htt_stats_buf->mpdu_queued_cnt); ++ len += scnprintf(buf + len, buf_len - len, "mpdu_ack_fail_cnt = %u\n", ++ htt_stats_buf->mpdu_ack_fail_cnt); ++ len += scnprintf(buf + len, buf_len - len, "mpdu_filt_cnt = %u\n", ++ htt_stats_buf->mpdu_filt_cnt); ++ len += scnprintf(buf + len, buf_len - len, "false_mpdu_ack_count = %u\n", ++ htt_stats_buf->false_mpdu_ack_count); ++ len += scnprintf(buf + len, buf_len - len, "txq_timeout = %u\n\n", ++ htt_stats_buf->txq_timeout); + + if (len >= buf_len) + buf[buf_len - 1] = 0; +@@ -1110,15 +1106,15 @@ htt_print_tx_hwq_difs_latency_stats_tlv_ + u16 data_len = min_t(u16, (tag_len >> 2), HTT_TX_HWQ_MAX_DIFS_LATENCY_BINS); + char difs_latency_hist[HTT_MAX_STRING_LEN] = {0}; + +- len += HTT_DBG_OUT(buf + len, buf_len - len, +- "HTT_TX_HWQ_DIFS_LATENCY_STATS_TLV_V:"); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "hist_intvl = %u", +- htt_stats_buf->hist_intvl); ++ len += scnprintf(buf + len, buf_len - len, ++ "HTT_TX_HWQ_DIFS_LATENCY_STATS_TLV_V:\n"); ++ len += scnprintf(buf + len, buf_len - len, "hist_intvl = %u\n", ++ htt_stats_buf->hist_intvl); + + PRINT_ARRAY_TO_BUF(difs_latency_hist, htt_stats_buf->difs_latency_hist, + data_len); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "difs_latency_hist = %s\n", +- difs_latency_hist); ++ len += scnprintf(buf + len, buf_len - len, "difs_latency_hist = %s\n\n", ++ difs_latency_hist); + + if (len >= buf_len) + buf[buf_len - 1] = 0; +@@ -1142,12 +1138,12 @@ htt_print_tx_hwq_cmd_result_stats_tlv_v( + + data_len = min_t(u16, (tag_len >> 2), HTT_TX_HWQ_MAX_CMD_RESULT_STATS); + +- len += HTT_DBG_OUT(buf + len, buf_len - len, +- "HTT_TX_HWQ_CMD_RESULT_STATS_TLV_V:"); ++ len += scnprintf(buf + len, buf_len - len, ++ "HTT_TX_HWQ_CMD_RESULT_STATS_TLV_V:\n"); + + PRINT_ARRAY_TO_BUF(cmd_result, htt_stats_buf->cmd_result, data_len); + +- len += HTT_DBG_OUT(buf + len, buf_len - len, "cmd_result = %s\n", cmd_result); ++ len += scnprintf(buf + len, buf_len - len, "cmd_result = %s\n\n", cmd_result); + + if (len >= buf_len) + buf[buf_len - 1] = 0; +@@ -1171,11 +1167,11 @@ htt_print_tx_hwq_cmd_stall_stats_tlv_v(c + + num_elems = min_t(u16, (tag_len >> 2), HTT_TX_HWQ_MAX_CMD_STALL_STATS); + +- len += HTT_DBG_OUT(buf + len, buf_len - len, "HTT_TX_HWQ_CMD_STALL_STATS_TLV_V:"); ++ len += scnprintf(buf + len, buf_len - len, "HTT_TX_HWQ_CMD_STALL_STATS_TLV_V:\n"); + + PRINT_ARRAY_TO_BUF(cmd_stall_status, htt_stats_buf->cmd_stall_status, num_elems); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "cmd_stall_status = %s\n", +- cmd_stall_status); ++ len += scnprintf(buf + len, buf_len - len, "cmd_stall_status = %s\n\n", ++ cmd_stall_status); + + if (len >= buf_len) + buf[buf_len - 1] = 0; +@@ -1199,11 +1195,11 @@ htt_print_tx_hwq_fes_result_stats_tlv_v( + + num_elems = min_t(u16, (tag_len >> 2), HTT_TX_HWQ_MAX_FES_RESULT_STATS); + +- len += HTT_DBG_OUT(buf + len, buf_len - len, +- "HTT_TX_HWQ_FES_RESULT_STATS_TLV_V:"); ++ len += scnprintf(buf + len, buf_len - len, ++ "HTT_TX_HWQ_FES_RESULT_STATS_TLV_V:\n"); + + PRINT_ARRAY_TO_BUF(fes_result, htt_stats_buf->fes_result, num_elems); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "fes_result = %s\n", fes_result); ++ len += scnprintf(buf + len, buf_len - len, "fes_result = %s\n\n", fes_result); + + if (len >= buf_len) + buf[buf_len - 1] = 0; +@@ -1227,21 +1223,21 @@ htt_print_tx_hwq_tried_mpdu_cnt_hist_tlv + sizeof(htt_stats_buf->hist_bin_size)) >> 2); + u32 required_buffer_size = HTT_MAX_PRINT_CHAR_PER_ELEM * num_elements; + +- len += HTT_DBG_OUT(buf + len, buf_len - len, +- "HTT_TX_HWQ_TRIED_MPDU_CNT_HIST_TLV_V:"); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "TRIED_MPDU_CNT_HIST_BIN_SIZE : %u", +- htt_stats_buf->hist_bin_size); ++ len += scnprintf(buf + len, buf_len - len, ++ "HTT_TX_HWQ_TRIED_MPDU_CNT_HIST_TLV_V:\n"); ++ len += scnprintf(buf + len, buf_len - len, "TRIED_MPDU_CNT_HIST_BIN_SIZE : %u\n", ++ htt_stats_buf->hist_bin_size); + + if (required_buffer_size < HTT_MAX_STRING_LEN) { + PRINT_ARRAY_TO_BUF(tried_mpdu_cnt_hist, + htt_stats_buf->tried_mpdu_cnt_hist, + num_elements); +- len += HTT_DBG_OUT(buf + len, buf_len - len, +- "tried_mpdu_cnt_hist = %s\n", +- tried_mpdu_cnt_hist); ++ len += scnprintf(buf + len, buf_len - len, ++ "tried_mpdu_cnt_hist = %s\n\n", ++ tried_mpdu_cnt_hist); + } else { +- len += HTT_DBG_OUT(buf + len, buf_len - len, +- "INSUFFICIENT PRINT BUFFER "); ++ len += scnprintf(buf + len, buf_len - len, ++ "INSUFFICIENT PRINT BUFFER\n"); + } + + if (len >= buf_len) +@@ -1265,18 +1261,18 @@ htt_print_tx_hwq_txop_used_cnt_hist_tlv_ + u32 num_elements = tag_len >> 2; + u32 required_buffer_size = HTT_MAX_PRINT_CHAR_PER_ELEM * num_elements; + +- len += HTT_DBG_OUT(buf + len, buf_len - len, +- "HTT_TX_HWQ_TXOP_USED_CNT_HIST_TLV_V:"); ++ len += scnprintf(buf + len, buf_len - len, ++ "HTT_TX_HWQ_TXOP_USED_CNT_HIST_TLV_V:\n"); + + if (required_buffer_size < HTT_MAX_STRING_LEN) { + PRINT_ARRAY_TO_BUF(txop_used_cnt_hist, + htt_stats_buf->txop_used_cnt_hist, + num_elements); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "txop_used_cnt_hist = %s\n", +- txop_used_cnt_hist); ++ len += scnprintf(buf + len, buf_len - len, "txop_used_cnt_hist = %s\n\n", ++ txop_used_cnt_hist); + } else { +- len += HTT_DBG_OUT(buf + len, buf_len - len, +- "INSUFFICIENT PRINT BUFFER "); ++ len += scnprintf(buf + len, buf_len - len, ++ "INSUFFICIENT PRINT BUFFER\n"); + } + if (len >= buf_len) + buf[buf_len - 1] = 0; +@@ -1300,86 +1296,86 @@ static inline void htt_print_tx_sounding + const u32 *cbf_160 = htt_stats_buf->cbf_160; + + if (htt_stats_buf->tx_sounding_mode == HTT_TX_AC_SOUNDING_MODE) { +- len += HTT_DBG_OUT(buf + len, buf_len - len, +- "\nHTT_TX_AC_SOUNDING_STATS_TLV:\n"); +- len += HTT_DBG_OUT(buf + len, buf_len - len, +- "ac_cbf_20 = IBF : %u, SU_SIFS : %u, SU_RBO : %u, MU_SIFS : %u, MU_RBO : %u ", +- cbf_20[HTT_IMPLICIT_TXBF_STEER_STATS], +- cbf_20[HTT_EXPLICIT_TXBF_SU_SIFS_STEER_STATS], +- cbf_20[HTT_EXPLICIT_TXBF_SU_RBO_STEER_STATS], +- cbf_20[HTT_EXPLICIT_TXBF_MU_SIFS_STEER_STATS], +- cbf_20[HTT_EXPLICIT_TXBF_MU_RBO_STEER_STATS]); +- len += HTT_DBG_OUT(buf + len, buf_len - len, +- "ac_cbf_40 = IBF : %u, SU_SIFS : %u, SU_RBO : %u, MU_SIFS : %u, MU_RBO : %u", +- cbf_40[HTT_IMPLICIT_TXBF_STEER_STATS], +- cbf_40[HTT_EXPLICIT_TXBF_SU_SIFS_STEER_STATS], +- cbf_40[HTT_EXPLICIT_TXBF_SU_RBO_STEER_STATS], +- cbf_40[HTT_EXPLICIT_TXBF_MU_SIFS_STEER_STATS], +- cbf_40[HTT_EXPLICIT_TXBF_MU_RBO_STEER_STATS]); +- len += HTT_DBG_OUT(buf + len, buf_len - len, +- "ac_cbf_80 = IBF : %u, SU_SIFS : %u, SU_RBO : %u, MU_SIFS : %u, MU_RBO : %u", +- cbf_80[HTT_IMPLICIT_TXBF_STEER_STATS], +- cbf_80[HTT_EXPLICIT_TXBF_SU_SIFS_STEER_STATS], +- cbf_80[HTT_EXPLICIT_TXBF_SU_RBO_STEER_STATS], +- cbf_80[HTT_EXPLICIT_TXBF_MU_SIFS_STEER_STATS], +- cbf_80[HTT_EXPLICIT_TXBF_MU_RBO_STEER_STATS]); +- len += HTT_DBG_OUT(buf + len, buf_len - len, +- "ac_cbf_160 = IBF : %u, SU_SIFS : %u, SU_RBO : %u, MU_SIFS : %u, MU_RBO : %u", +- cbf_160[HTT_IMPLICIT_TXBF_STEER_STATS], +- cbf_160[HTT_EXPLICIT_TXBF_SU_SIFS_STEER_STATS], +- cbf_160[HTT_EXPLICIT_TXBF_SU_RBO_STEER_STATS], +- cbf_160[HTT_EXPLICIT_TXBF_MU_SIFS_STEER_STATS], +- cbf_160[HTT_EXPLICIT_TXBF_MU_RBO_STEER_STATS]); ++ len += scnprintf(buf + len, buf_len - len, ++ "\nHTT_TX_AC_SOUNDING_STATS_TLV:\n\n"); ++ len += scnprintf(buf + len, buf_len - len, ++ "ac_cbf_20 = IBF : %u, SU_SIFS : %u, SU_RBO : %u, MU_SIFS : %u, MU_RBO : %u\n", ++ cbf_20[HTT_IMPLICIT_TXBF_STEER_STATS], ++ cbf_20[HTT_EXPLICIT_TXBF_SU_SIFS_STEER_STATS], ++ cbf_20[HTT_EXPLICIT_TXBF_SU_RBO_STEER_STATS], ++ cbf_20[HTT_EXPLICIT_TXBF_MU_SIFS_STEER_STATS], ++ cbf_20[HTT_EXPLICIT_TXBF_MU_RBO_STEER_STATS]); ++ len += scnprintf(buf + len, buf_len - len, ++ "ac_cbf_40 = IBF : %u, SU_SIFS : %u, SU_RBO : %u, MU_SIFS : %u, MU_RBO : %u\n", ++ cbf_40[HTT_IMPLICIT_TXBF_STEER_STATS], ++ cbf_40[HTT_EXPLICIT_TXBF_SU_SIFS_STEER_STATS], ++ cbf_40[HTT_EXPLICIT_TXBF_SU_RBO_STEER_STATS], ++ cbf_40[HTT_EXPLICIT_TXBF_MU_SIFS_STEER_STATS], ++ cbf_40[HTT_EXPLICIT_TXBF_MU_RBO_STEER_STATS]); ++ len += scnprintf(buf + len, buf_len - len, ++ "ac_cbf_80 = IBF : %u, SU_SIFS : %u, SU_RBO : %u, MU_SIFS : %u, MU_RBO : %u\n", ++ cbf_80[HTT_IMPLICIT_TXBF_STEER_STATS], ++ cbf_80[HTT_EXPLICIT_TXBF_SU_SIFS_STEER_STATS], ++ cbf_80[HTT_EXPLICIT_TXBF_SU_RBO_STEER_STATS], ++ cbf_80[HTT_EXPLICIT_TXBF_MU_SIFS_STEER_STATS], ++ cbf_80[HTT_EXPLICIT_TXBF_MU_RBO_STEER_STATS]); ++ len += scnprintf(buf + len, buf_len - len, ++ "ac_cbf_160 = IBF : %u, SU_SIFS : %u, SU_RBO : %u, MU_SIFS : %u, MU_RBO : %u\n", ++ cbf_160[HTT_IMPLICIT_TXBF_STEER_STATS], ++ cbf_160[HTT_EXPLICIT_TXBF_SU_SIFS_STEER_STATS], ++ cbf_160[HTT_EXPLICIT_TXBF_SU_RBO_STEER_STATS], ++ cbf_160[HTT_EXPLICIT_TXBF_MU_SIFS_STEER_STATS], ++ cbf_160[HTT_EXPLICIT_TXBF_MU_RBO_STEER_STATS]); + + for (i = 0; i < HTT_TX_PDEV_STATS_NUM_AC_MUMIMO_USER_STATS; i++) { +- len += HTT_DBG_OUT(buf + len, buf_len - len, +- "Sounding User %u = 20MHz: %u, 40MHz : %u, 80MHz: %u, 160MHz: %u ", +- i, +- htt_stats_buf->sounding[0], +- htt_stats_buf->sounding[1], +- htt_stats_buf->sounding[2], +- htt_stats_buf->sounding[3]); ++ len += scnprintf(buf + len, buf_len - len, ++ "Sounding User %u = 20MHz: %u, 40MHz : %u, 80MHz: %u, 160MHz: %u\n", ++ i, ++ htt_stats_buf->sounding[0], ++ htt_stats_buf->sounding[1], ++ htt_stats_buf->sounding[2], ++ htt_stats_buf->sounding[3]); + } + } else if (htt_stats_buf->tx_sounding_mode == HTT_TX_AX_SOUNDING_MODE) { +- len += HTT_DBG_OUT(buf + len, buf_len - len, +- "\nHTT_TX_AX_SOUNDING_STATS_TLV:\n"); +- len += HTT_DBG_OUT(buf + len, buf_len - len, +- "ax_cbf_20 = IBF : %u, SU_SIFS : %u, SU_RBO : %u, MU_SIFS : %u, MU_RBO : %u ", +- cbf_20[HTT_IMPLICIT_TXBF_STEER_STATS], +- cbf_20[HTT_EXPLICIT_TXBF_SU_SIFS_STEER_STATS], +- cbf_20[HTT_EXPLICIT_TXBF_SU_RBO_STEER_STATS], +- cbf_20[HTT_EXPLICIT_TXBF_MU_SIFS_STEER_STATS], +- cbf_20[HTT_EXPLICIT_TXBF_MU_RBO_STEER_STATS]); +- len += HTT_DBG_OUT(buf + len, buf_len - len, +- "ax_cbf_40 = IBF : %u, SU_SIFS : %u, SU_RBO : %u, MU_SIFS : %u, MU_RBO : %u", +- cbf_40[HTT_IMPLICIT_TXBF_STEER_STATS], +- cbf_40[HTT_EXPLICIT_TXBF_SU_SIFS_STEER_STATS], +- cbf_40[HTT_EXPLICIT_TXBF_SU_RBO_STEER_STATS], +- cbf_40[HTT_EXPLICIT_TXBF_MU_SIFS_STEER_STATS], +- cbf_40[HTT_EXPLICIT_TXBF_MU_RBO_STEER_STATS]); +- len += HTT_DBG_OUT(buf + len, buf_len - len, +- "ax_cbf_80 = IBF : %u, SU_SIFS : %u, SU_RBO : %u, MU_SIFS : %u, MU_RBO : %u", +- cbf_80[HTT_IMPLICIT_TXBF_STEER_STATS], +- cbf_80[HTT_EXPLICIT_TXBF_SU_SIFS_STEER_STATS], +- cbf_80[HTT_EXPLICIT_TXBF_SU_RBO_STEER_STATS], +- cbf_80[HTT_EXPLICIT_TXBF_MU_SIFS_STEER_STATS], +- cbf_80[HTT_EXPLICIT_TXBF_MU_RBO_STEER_STATS]); +- len += HTT_DBG_OUT(buf + len, buf_len - len, +- "ax_cbf_160 = IBF : %u, SU_SIFS : %u, SU_RBO : %u, MU_SIFS : %u, MU_RBO : %u", +- cbf_160[HTT_IMPLICIT_TXBF_STEER_STATS], +- cbf_160[HTT_EXPLICIT_TXBF_SU_SIFS_STEER_STATS], +- cbf_160[HTT_EXPLICIT_TXBF_SU_RBO_STEER_STATS], +- cbf_160[HTT_EXPLICIT_TXBF_MU_SIFS_STEER_STATS], +- cbf_160[HTT_EXPLICIT_TXBF_MU_RBO_STEER_STATS]); ++ len += scnprintf(buf + len, buf_len - len, ++ "\nHTT_TX_AX_SOUNDING_STATS_TLV:\n"); ++ len += scnprintf(buf + len, buf_len - len, ++ "ax_cbf_20 = IBF : %u, SU_SIFS : %u, SU_RBO : %u, MU_SIFS : %u, MU_RBO : %u\n", ++ cbf_20[HTT_IMPLICIT_TXBF_STEER_STATS], ++ cbf_20[HTT_EXPLICIT_TXBF_SU_SIFS_STEER_STATS], ++ cbf_20[HTT_EXPLICIT_TXBF_SU_RBO_STEER_STATS], ++ cbf_20[HTT_EXPLICIT_TXBF_MU_SIFS_STEER_STATS], ++ cbf_20[HTT_EXPLICIT_TXBF_MU_RBO_STEER_STATS]); ++ len += scnprintf(buf + len, buf_len - len, ++ "ax_cbf_40 = IBF : %u, SU_SIFS : %u, SU_RBO : %u, MU_SIFS : %u, MU_RBO : %u\n", ++ cbf_40[HTT_IMPLICIT_TXBF_STEER_STATS], ++ cbf_40[HTT_EXPLICIT_TXBF_SU_SIFS_STEER_STATS], ++ cbf_40[HTT_EXPLICIT_TXBF_SU_RBO_STEER_STATS], ++ cbf_40[HTT_EXPLICIT_TXBF_MU_SIFS_STEER_STATS], ++ cbf_40[HTT_EXPLICIT_TXBF_MU_RBO_STEER_STATS]); ++ len += scnprintf(buf + len, buf_len - len, ++ "ax_cbf_80 = IBF : %u, SU_SIFS : %u, SU_RBO : %u, MU_SIFS : %u, MU_RBO : %u\n", ++ cbf_80[HTT_IMPLICIT_TXBF_STEER_STATS], ++ cbf_80[HTT_EXPLICIT_TXBF_SU_SIFS_STEER_STATS], ++ cbf_80[HTT_EXPLICIT_TXBF_SU_RBO_STEER_STATS], ++ cbf_80[HTT_EXPLICIT_TXBF_MU_SIFS_STEER_STATS], ++ cbf_80[HTT_EXPLICIT_TXBF_MU_RBO_STEER_STATS]); ++ len += scnprintf(buf + len, buf_len - len, ++ "ax_cbf_160 = IBF : %u, SU_SIFS : %u, SU_RBO : %u, MU_SIFS : %u, MU_RBO : %u\n", ++ cbf_160[HTT_IMPLICIT_TXBF_STEER_STATS], ++ cbf_160[HTT_EXPLICIT_TXBF_SU_SIFS_STEER_STATS], ++ cbf_160[HTT_EXPLICIT_TXBF_SU_RBO_STEER_STATS], ++ cbf_160[HTT_EXPLICIT_TXBF_MU_SIFS_STEER_STATS], ++ cbf_160[HTT_EXPLICIT_TXBF_MU_RBO_STEER_STATS]); + + for (i = 0; i < HTT_TX_PDEV_STATS_NUM_AX_MUMIMO_USER_STATS; i++) { +- len += HTT_DBG_OUT(buf + len, buf_len - len, +- "Sounding User %u = 20MHz: %u, 40MHz : %u, 80MHz: %u, 160MHz: %u ", +- i, +- htt_stats_buf->sounding[0], +- htt_stats_buf->sounding[1], +- htt_stats_buf->sounding[2], +- htt_stats_buf->sounding[3]); ++ len += scnprintf(buf + len, buf_len - len, ++ "Sounding User %u = 20MHz: %u, 40MHz : %u, 80MHz: %u, 160MHz: %u\n", ++ i, ++ htt_stats_buf->sounding[0], ++ htt_stats_buf->sounding[1], ++ htt_stats_buf->sounding[2], ++ htt_stats_buf->sounding[3]); + } + } + +@@ -1400,31 +1396,31 @@ htt_print_tx_selfgen_cmn_stats_tlv(const + u32 len = stats_req->buf_len; + u32 buf_len = ATH11K_HTT_STATS_BUF_SIZE; + +- len += HTT_DBG_OUT(buf + len, buf_len - len, "HTT_TX_SELFGEN_CMN_STATS_TLV:"); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "mac_id = %u", +- htt_stats_buf->mac_id__word & 0xFF); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "su_bar = %u", +- htt_stats_buf->su_bar); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "rts = %u", +- htt_stats_buf->rts); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "cts2self = %u", +- htt_stats_buf->cts2self); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "qos_null = %u", +- htt_stats_buf->qos_null); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "delayed_bar_1 = %u", +- htt_stats_buf->delayed_bar_1); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "delayed_bar_2 = %u", +- htt_stats_buf->delayed_bar_2); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "delayed_bar_3 = %u", +- htt_stats_buf->delayed_bar_3); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "delayed_bar_4 = %u", +- htt_stats_buf->delayed_bar_4); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "delayed_bar_5 = %u", +- htt_stats_buf->delayed_bar_5); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "delayed_bar_6 = %u", +- htt_stats_buf->delayed_bar_6); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "delayed_bar_7 = %u\n", +- htt_stats_buf->delayed_bar_7); ++ len += scnprintf(buf + len, buf_len - len, "HTT_TX_SELFGEN_CMN_STATS_TLV:\n"); ++ len += scnprintf(buf + len, buf_len - len, "mac_id = %u\n", ++ htt_stats_buf->mac_id__word & 0xFF); ++ len += scnprintf(buf + len, buf_len - len, "su_bar = %u\n", ++ htt_stats_buf->su_bar); ++ len += scnprintf(buf + len, buf_len - len, "rts = %u\n", ++ htt_stats_buf->rts); ++ len += scnprintf(buf + len, buf_len - len, "cts2self = %u\n", ++ htt_stats_buf->cts2self); ++ len += scnprintf(buf + len, buf_len - len, "qos_null = %u\n", ++ htt_stats_buf->qos_null); ++ len += scnprintf(buf + len, buf_len - len, "delayed_bar_1 = %u\n", ++ htt_stats_buf->delayed_bar_1); ++ len += scnprintf(buf + len, buf_len - len, "delayed_bar_2 = %u\n", ++ htt_stats_buf->delayed_bar_2); ++ len += scnprintf(buf + len, buf_len - len, "delayed_bar_3 = %u\n", ++ htt_stats_buf->delayed_bar_3); ++ len += scnprintf(buf + len, buf_len - len, "delayed_bar_4 = %u\n", ++ htt_stats_buf->delayed_bar_4); ++ len += scnprintf(buf + len, buf_len - len, "delayed_bar_5 = %u\n", ++ htt_stats_buf->delayed_bar_5); ++ len += scnprintf(buf + len, buf_len - len, "delayed_bar_6 = %u\n", ++ htt_stats_buf->delayed_bar_6); ++ len += scnprintf(buf + len, buf_len - len, "delayed_bar_7 = %u\n\n", ++ htt_stats_buf->delayed_bar_7); + + if (len >= buf_len) + buf[buf_len - 1] = 0; +@@ -1443,21 +1439,21 @@ htt_print_tx_selfgen_ac_stats_tlv(const + u32 len = stats_req->buf_len; + u32 buf_len = ATH11K_HTT_STATS_BUF_SIZE; + +- len += HTT_DBG_OUT(buf + len, buf_len - len, "HTT_TX_SELFGEN_AC_STATS_TLV:"); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "ac_su_ndpa = %u", +- htt_stats_buf->ac_su_ndpa); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "ac_su_ndp = %u", +- htt_stats_buf->ac_su_ndp); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "ac_mu_mimo_ndpa = %u", +- htt_stats_buf->ac_mu_mimo_ndpa); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "ac_mu_mimo_ndp = %u", +- htt_stats_buf->ac_mu_mimo_ndp); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "ac_mu_mimo_brpoll_1 = %u", +- htt_stats_buf->ac_mu_mimo_brpoll_1); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "ac_mu_mimo_brpoll_2 = %u", +- htt_stats_buf->ac_mu_mimo_brpoll_2); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "ac_mu_mimo_brpoll_3 = %u\n", +- htt_stats_buf->ac_mu_mimo_brpoll_3); ++ len += scnprintf(buf + len, buf_len - len, "HTT_TX_SELFGEN_AC_STATS_TLV:\n"); ++ len += scnprintf(buf + len, buf_len - len, "ac_su_ndpa = %u\n", ++ htt_stats_buf->ac_su_ndpa); ++ len += scnprintf(buf + len, buf_len - len, "ac_su_ndp = %u\n", ++ htt_stats_buf->ac_su_ndp); ++ len += scnprintf(buf + len, buf_len - len, "ac_mu_mimo_ndpa = %u\n", ++ htt_stats_buf->ac_mu_mimo_ndpa); ++ len += scnprintf(buf + len, buf_len - len, "ac_mu_mimo_ndp = %u\n", ++ htt_stats_buf->ac_mu_mimo_ndp); ++ len += scnprintf(buf + len, buf_len - len, "ac_mu_mimo_brpoll_1 = %u\n", ++ htt_stats_buf->ac_mu_mimo_brpoll_1); ++ len += scnprintf(buf + len, buf_len - len, "ac_mu_mimo_brpoll_2 = %u\n", ++ htt_stats_buf->ac_mu_mimo_brpoll_2); ++ len += scnprintf(buf + len, buf_len - len, "ac_mu_mimo_brpoll_3 = %u\n\n", ++ htt_stats_buf->ac_mu_mimo_brpoll_3); + + if (len >= buf_len) + buf[buf_len - 1] = 0; +@@ -1476,37 +1472,37 @@ htt_print_tx_selfgen_ax_stats_tlv(const + u32 len = stats_req->buf_len; + u32 buf_len = ATH11K_HTT_STATS_BUF_SIZE; + +- len += HTT_DBG_OUT(buf + len, buf_len - len, "HTT_TX_SELFGEN_AX_STATS_TLV:"); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "ax_su_ndpa = %u", +- htt_stats_buf->ax_su_ndpa); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "ax_su_ndp = %u", +- htt_stats_buf->ax_su_ndp); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "ax_mu_mimo_ndpa = %u", +- htt_stats_buf->ax_mu_mimo_ndpa); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "ax_mu_mimo_ndp = %u", +- htt_stats_buf->ax_mu_mimo_ndp); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "ax_mu_mimo_brpoll_1 = %u", +- htt_stats_buf->ax_mu_mimo_brpoll_1); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "ax_mu_mimo_brpoll_2 = %u", +- htt_stats_buf->ax_mu_mimo_brpoll_2); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "ax_mu_mimo_brpoll_3 = %u", +- htt_stats_buf->ax_mu_mimo_brpoll_3); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "ax_mu_mimo_brpoll_4 = %u", +- htt_stats_buf->ax_mu_mimo_brpoll_4); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "ax_mu_mimo_brpoll_5 = %u", +- htt_stats_buf->ax_mu_mimo_brpoll_5); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "ax_mu_mimo_brpoll_6 = %u", +- htt_stats_buf->ax_mu_mimo_brpoll_6); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "ax_mu_mimo_brpoll_7 = %u", +- htt_stats_buf->ax_mu_mimo_brpoll_7); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "ax_basic_trigger = %u", +- htt_stats_buf->ax_basic_trigger); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "ax_bsr_trigger = %u", +- htt_stats_buf->ax_bsr_trigger); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "ax_mu_bar_trigger = %u", +- htt_stats_buf->ax_mu_bar_trigger); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "ax_mu_rts_trigger = %u\n", +- htt_stats_buf->ax_mu_rts_trigger); ++ len += scnprintf(buf + len, buf_len - len, "HTT_TX_SELFGEN_AX_STATS_TLV:\n"); ++ len += scnprintf(buf + len, buf_len - len, "ax_su_ndpa = %u\n", ++ htt_stats_buf->ax_su_ndpa); ++ len += scnprintf(buf + len, buf_len - len, "ax_su_ndp = %u\n", ++ htt_stats_buf->ax_su_ndp); ++ len += scnprintf(buf + len, buf_len - len, "ax_mu_mimo_ndpa = %u\n", ++ htt_stats_buf->ax_mu_mimo_ndpa); ++ len += scnprintf(buf + len, buf_len - len, "ax_mu_mimo_ndp = %u\n", ++ htt_stats_buf->ax_mu_mimo_ndp); ++ len += scnprintf(buf + len, buf_len - len, "ax_mu_mimo_brpoll_1 = %u\n", ++ htt_stats_buf->ax_mu_mimo_brpoll_1); ++ len += scnprintf(buf + len, buf_len - len, "ax_mu_mimo_brpoll_2 = %u\n", ++ htt_stats_buf->ax_mu_mimo_brpoll_2); ++ len += scnprintf(buf + len, buf_len - len, "ax_mu_mimo_brpoll_3 = %u\n", ++ htt_stats_buf->ax_mu_mimo_brpoll_3); ++ len += scnprintf(buf + len, buf_len - len, "ax_mu_mimo_brpoll_4 = %u\n", ++ htt_stats_buf->ax_mu_mimo_brpoll_4); ++ len += scnprintf(buf + len, buf_len - len, "ax_mu_mimo_brpoll_5 = %u\n", ++ htt_stats_buf->ax_mu_mimo_brpoll_5); ++ len += scnprintf(buf + len, buf_len - len, "ax_mu_mimo_brpoll_6 = %u\n", ++ htt_stats_buf->ax_mu_mimo_brpoll_6); ++ len += scnprintf(buf + len, buf_len - len, "ax_mu_mimo_brpoll_7 = %u\n", ++ htt_stats_buf->ax_mu_mimo_brpoll_7); ++ len += scnprintf(buf + len, buf_len - len, "ax_basic_trigger = %u\n", ++ htt_stats_buf->ax_basic_trigger); ++ len += scnprintf(buf + len, buf_len - len, "ax_bsr_trigger = %u\n", ++ htt_stats_buf->ax_bsr_trigger); ++ len += scnprintf(buf + len, buf_len - len, "ax_mu_bar_trigger = %u\n", ++ htt_stats_buf->ax_mu_bar_trigger); ++ len += scnprintf(buf + len, buf_len - len, "ax_mu_rts_trigger = %u\n\n", ++ htt_stats_buf->ax_mu_rts_trigger); + + if (len >= buf_len) + buf[buf_len - 1] = 0; +@@ -1525,21 +1521,21 @@ htt_print_tx_selfgen_ac_err_stats_tlv(co + u32 len = stats_req->buf_len; + u32 buf_len = ATH11K_HTT_STATS_BUF_SIZE; + +- len += HTT_DBG_OUT(buf + len, buf_len - len, "HTT_TX_SELFGEN_AC_ERR_STATS_TLV:"); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "ac_su_ndp_err = %u", +- htt_stats_buf->ac_su_ndp_err); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "ac_su_ndpa_err = %u", +- htt_stats_buf->ac_su_ndpa_err); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "ac_mu_mimo_ndpa_err = %u", +- htt_stats_buf->ac_mu_mimo_ndpa_err); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "ac_mu_mimo_ndp_err = %u", +- htt_stats_buf->ac_mu_mimo_ndp_err); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "ac_mu_mimo_brp1_err = %u", +- htt_stats_buf->ac_mu_mimo_brp1_err); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "ac_mu_mimo_brp2_err = %u", +- htt_stats_buf->ac_mu_mimo_brp2_err); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "ac_mu_mimo_brp3_err = %u\n", +- htt_stats_buf->ac_mu_mimo_brp3_err); ++ len += scnprintf(buf + len, buf_len - len, "HTT_TX_SELFGEN_AC_ERR_STATS_TLV:\n"); ++ len += scnprintf(buf + len, buf_len - len, "ac_su_ndp_err = %u\n", ++ htt_stats_buf->ac_su_ndp_err); ++ len += scnprintf(buf + len, buf_len - len, "ac_su_ndpa_err = %u\n", ++ htt_stats_buf->ac_su_ndpa_err); ++ len += scnprintf(buf + len, buf_len - len, "ac_mu_mimo_ndpa_err = %u\n", ++ htt_stats_buf->ac_mu_mimo_ndpa_err); ++ len += scnprintf(buf + len, buf_len - len, "ac_mu_mimo_ndp_err = %u\n", ++ htt_stats_buf->ac_mu_mimo_ndp_err); ++ len += scnprintf(buf + len, buf_len - len, "ac_mu_mimo_brp1_err = %u\n", ++ htt_stats_buf->ac_mu_mimo_brp1_err); ++ len += scnprintf(buf + len, buf_len - len, "ac_mu_mimo_brp2_err = %u\n", ++ htt_stats_buf->ac_mu_mimo_brp2_err); ++ len += scnprintf(buf + len, buf_len - len, "ac_mu_mimo_brp3_err = %u\n\n", ++ htt_stats_buf->ac_mu_mimo_brp3_err); + + if (len >= buf_len) + buf[buf_len - 1] = 0; +@@ -1558,37 +1554,37 @@ htt_print_tx_selfgen_ax_err_stats_tlv(co + u32 len = stats_req->buf_len; + u32 buf_len = ATH11K_HTT_STATS_BUF_SIZE; + +- len += HTT_DBG_OUT(buf + len, buf_len - len, "HTT_TX_SELFGEN_AX_ERR_STATS_TLV:"); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "ax_su_ndp_err = %u", +- htt_stats_buf->ax_su_ndp_err); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "ax_su_ndpa_err = %u", +- htt_stats_buf->ax_su_ndpa_err); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "ax_mu_mimo_ndpa_err = %u", +- htt_stats_buf->ax_mu_mimo_ndpa_err); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "ax_mu_mimo_ndp_err = %u", +- htt_stats_buf->ax_mu_mimo_ndp_err); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "ax_mu_mimo_brp1_err = %u", +- htt_stats_buf->ax_mu_mimo_brp1_err); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "ax_mu_mimo_brp2_err = %u", +- htt_stats_buf->ax_mu_mimo_brp2_err); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "ax_mu_mimo_brp3_err = %u", +- htt_stats_buf->ax_mu_mimo_brp3_err); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "ax_mu_mimo_brp4_err = %u", +- htt_stats_buf->ax_mu_mimo_brp4_err); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "ax_mu_mimo_brp5_err = %u", +- htt_stats_buf->ax_mu_mimo_brp5_err); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "ax_mu_mimo_brp6_err = %u", +- htt_stats_buf->ax_mu_mimo_brp6_err); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "ax_mu_mimo_brp7_err = %u", +- htt_stats_buf->ax_mu_mimo_brp7_err); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "ax_basic_trigger_err = %u", +- htt_stats_buf->ax_basic_trigger_err); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "ax_bsr_trigger_err = %u", +- htt_stats_buf->ax_bsr_trigger_err); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "ax_mu_bar_trigger_err = %u", +- htt_stats_buf->ax_mu_bar_trigger_err); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "ax_mu_rts_trigger_err = %u\n", +- htt_stats_buf->ax_mu_rts_trigger_err); ++ len += scnprintf(buf + len, buf_len - len, "HTT_TX_SELFGEN_AX_ERR_STATS_TLV:\n"); ++ len += scnprintf(buf + len, buf_len - len, "ax_su_ndp_err = %u\n", ++ htt_stats_buf->ax_su_ndp_err); ++ len += scnprintf(buf + len, buf_len - len, "ax_su_ndpa_err = %u\n", ++ htt_stats_buf->ax_su_ndpa_err); ++ len += scnprintf(buf + len, buf_len - len, "ax_mu_mimo_ndpa_err = %u\n", ++ htt_stats_buf->ax_mu_mimo_ndpa_err); ++ len += scnprintf(buf + len, buf_len - len, "ax_mu_mimo_ndp_err = %u\n", ++ htt_stats_buf->ax_mu_mimo_ndp_err); ++ len += scnprintf(buf + len, buf_len - len, "ax_mu_mimo_brp1_err = %u\n", ++ htt_stats_buf->ax_mu_mimo_brp1_err); ++ len += scnprintf(buf + len, buf_len - len, "ax_mu_mimo_brp2_err = %u\n", ++ htt_stats_buf->ax_mu_mimo_brp2_err); ++ len += scnprintf(buf + len, buf_len - len, "ax_mu_mimo_brp3_err = %u\n", ++ htt_stats_buf->ax_mu_mimo_brp3_err); ++ len += scnprintf(buf + len, buf_len - len, "ax_mu_mimo_brp4_err = %u\n", ++ htt_stats_buf->ax_mu_mimo_brp4_err); ++ len += scnprintf(buf + len, buf_len - len, "ax_mu_mimo_brp5_err = %u\n", ++ htt_stats_buf->ax_mu_mimo_brp5_err); ++ len += scnprintf(buf + len, buf_len - len, "ax_mu_mimo_brp6_err = %u\n", ++ htt_stats_buf->ax_mu_mimo_brp6_err); ++ len += scnprintf(buf + len, buf_len - len, "ax_mu_mimo_brp7_err = %u\n", ++ htt_stats_buf->ax_mu_mimo_brp7_err); ++ len += scnprintf(buf + len, buf_len - len, "ax_basic_trigger_err = %u\n", ++ htt_stats_buf->ax_basic_trigger_err); ++ len += scnprintf(buf + len, buf_len - len, "ax_bsr_trigger_err = %u\n", ++ htt_stats_buf->ax_bsr_trigger_err); ++ len += scnprintf(buf + len, buf_len - len, "ax_mu_bar_trigger_err = %u\n", ++ htt_stats_buf->ax_mu_bar_trigger_err); ++ len += scnprintf(buf + len, buf_len - len, "ax_mu_rts_trigger_err = %u\n\n", ++ htt_stats_buf->ax_mu_rts_trigger_err); + + if (len >= buf_len) + buf[buf_len - 1] = 0; +@@ -1608,35 +1604,35 @@ htt_print_tx_pdev_mu_mimo_sch_stats_tlv( + u32 buf_len = ATH11K_HTT_STATS_BUF_SIZE; + u8 i; + +- len += HTT_DBG_OUT(buf + len, buf_len - len, +- "HTT_TX_PDEV_MU_MIMO_SCH_STATS_TLV:"); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "mu_mimo_sch_posted = %u", +- htt_stats_buf->mu_mimo_sch_posted); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "mu_mimo_sch_failed = %u", +- htt_stats_buf->mu_mimo_sch_failed); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "mu_mimo_ppdu_posted = %u\n", +- htt_stats_buf->mu_mimo_ppdu_posted); ++ len += scnprintf(buf + len, buf_len - len, ++ "HTT_TX_PDEV_MU_MIMO_SCH_STATS_TLV:\n"); ++ len += scnprintf(buf + len, buf_len - len, "mu_mimo_sch_posted = %u\n", ++ htt_stats_buf->mu_mimo_sch_posted); ++ len += scnprintf(buf + len, buf_len - len, "mu_mimo_sch_failed = %u\n", ++ htt_stats_buf->mu_mimo_sch_failed); ++ len += scnprintf(buf + len, buf_len - len, "mu_mimo_ppdu_posted = %u\n\n", ++ htt_stats_buf->mu_mimo_ppdu_posted); + +- len += HTT_DBG_OUT(buf + len, buf_len - len, "11ac MU_MIMO SCH STATS:"); ++ len += scnprintf(buf + len, buf_len - len, "11ac MU_MIMO SCH STATS:\n"); + + for (i = 0; i < HTT_TX_PDEV_STATS_NUM_AC_MUMIMO_USER_STATS; i++) +- len += HTT_DBG_OUT(buf + len, buf_len - len, +- "ac_mu_mimo_sch_nusers_%u = %u", +- i, htt_stats_buf->ac_mu_mimo_sch_nusers[i]); ++ len += scnprintf(buf + len, buf_len - len, ++ "ac_mu_mimo_sch_nusers_%u = %u\n", ++ i, htt_stats_buf->ac_mu_mimo_sch_nusers[i]); + +- len += HTT_DBG_OUT(buf + len, buf_len - len, "\n11ax MU_MIMO SCH STATS:"); ++ len += scnprintf(buf + len, buf_len - len, "\n11ax MU_MIMO SCH STATS:\n"); + + for (i = 0; i < HTT_TX_PDEV_STATS_NUM_AX_MUMIMO_USER_STATS; i++) +- len += HTT_DBG_OUT(buf + len, buf_len - len, +- "ax_mu_mimo_sch_nusers_%u = %u", +- i, htt_stats_buf->ax_mu_mimo_sch_nusers[i]); ++ len += scnprintf(buf + len, buf_len - len, ++ "ax_mu_mimo_sch_nusers_%u = %u\n", ++ i, htt_stats_buf->ax_mu_mimo_sch_nusers[i]); + +- len += HTT_DBG_OUT(buf + len, buf_len - len, "\n11ax OFDMA SCH STATS:"); ++ len += scnprintf(buf + len, buf_len - len, "\n11ax OFDMA SCH STATS:\n"); + + for (i = 0; i < HTT_TX_PDEV_STATS_NUM_OFDMA_USER_STATS; i++) +- len += HTT_DBG_OUT(buf + len, buf_len - len, +- "ax_ofdma_sch_nusers_%u = %u", +- i, htt_stats_buf->ax_ofdma_sch_nusers[i]); ++ len += scnprintf(buf + len, buf_len - len, ++ "ax_ofdma_sch_nusers_%u = %u\n", ++ i, htt_stats_buf->ax_ofdma_sch_nusers[i]); + + if (len >= buf_len) + buf[buf_len - 1] = 0; +@@ -1657,114 +1653,114 @@ htt_print_tx_pdev_mu_mimo_mpdu_stats_tlv + + if (htt_stats_buf->tx_sched_mode == HTT_STATS_TX_SCHED_MODE_MU_MIMO_AC) { + if (!htt_stats_buf->user_index) +- len += HTT_DBG_OUT(buf + len, buf_len - len, +- "HTT_TX_PDEV_MU_MIMO_AC_MPDU_STATS:\n"); ++ len += scnprintf(buf + len, buf_len - len, ++ "HTT_TX_PDEV_MU_MIMO_AC_MPDU_STATS:\n"); + + if (htt_stats_buf->user_index < + HTT_TX_PDEV_STATS_NUM_AC_MUMIMO_USER_STATS) { +- len += HTT_DBG_OUT(buf + len, buf_len - len, +- "ac_mu_mimo_mpdus_queued_usr_%u = %u", +- htt_stats_buf->user_index, +- htt_stats_buf->mpdus_queued_usr); +- len += HTT_DBG_OUT(buf + len, buf_len - len, +- "ac_mu_mimo_mpdus_tried_usr_%u = %u", +- htt_stats_buf->user_index, +- htt_stats_buf->mpdus_tried_usr); +- len += HTT_DBG_OUT(buf + len, buf_len - len, +- "ac_mu_mimo_mpdus_failed_usr_%u = %u", +- htt_stats_buf->user_index, +- htt_stats_buf->mpdus_failed_usr); +- len += HTT_DBG_OUT(buf + len, buf_len - len, +- "ac_mu_mimo_mpdus_requeued_usr_%u = %u", +- htt_stats_buf->user_index, +- htt_stats_buf->mpdus_requeued_usr); +- len += HTT_DBG_OUT(buf + len, buf_len - len, +- "ac_mu_mimo_err_no_ba_usr_%u = %u", +- htt_stats_buf->user_index, +- htt_stats_buf->err_no_ba_usr); +- len += HTT_DBG_OUT(buf + len, buf_len - len, +- "ac_mu_mimo_mpdu_underrun_usr_%u = %u", +- htt_stats_buf->user_index, +- htt_stats_buf->mpdu_underrun_usr); +- len += HTT_DBG_OUT(buf + len, buf_len - len, +- "ac_mu_mimo_ampdu_underrun_usr_%u = %u\n", +- htt_stats_buf->user_index, +- htt_stats_buf->ampdu_underrun_usr); ++ len += scnprintf(buf + len, buf_len - len, ++ "ac_mu_mimo_mpdus_queued_usr_%u = %u\n", ++ htt_stats_buf->user_index, ++ htt_stats_buf->mpdus_queued_usr); ++ len += scnprintf(buf + len, buf_len - len, ++ "ac_mu_mimo_mpdus_tried_usr_%u = %u\n", ++ htt_stats_buf->user_index, ++ htt_stats_buf->mpdus_tried_usr); ++ len += scnprintf(buf + len, buf_len - len, ++ "ac_mu_mimo_mpdus_failed_usr_%u = %u\n", ++ htt_stats_buf->user_index, ++ htt_stats_buf->mpdus_failed_usr); ++ len += scnprintf(buf + len, buf_len - len, ++ "ac_mu_mimo_mpdus_requeued_usr_%u = %u\n", ++ htt_stats_buf->user_index, ++ htt_stats_buf->mpdus_requeued_usr); ++ len += scnprintf(buf + len, buf_len - len, ++ "ac_mu_mimo_err_no_ba_usr_%u = %u\n", ++ htt_stats_buf->user_index, ++ htt_stats_buf->err_no_ba_usr); ++ len += scnprintf(buf + len, buf_len - len, ++ "ac_mu_mimo_mpdu_underrun_usr_%u = %u\n", ++ htt_stats_buf->user_index, ++ htt_stats_buf->mpdu_underrun_usr); ++ len += scnprintf(buf + len, buf_len - len, ++ "ac_mu_mimo_ampdu_underrun_usr_%u = %u\n\n", ++ htt_stats_buf->user_index, ++ htt_stats_buf->ampdu_underrun_usr); + } + } + + if (htt_stats_buf->tx_sched_mode == HTT_STATS_TX_SCHED_MODE_MU_MIMO_AX) { + if (!htt_stats_buf->user_index) +- len += HTT_DBG_OUT(buf + len, buf_len - len, +- "HTT_TX_PDEV_MU_MIMO_AX_MPDU_STATS:\n"); ++ len += scnprintf(buf + len, buf_len - len, ++ "HTT_TX_PDEV_MU_MIMO_AX_MPDU_STATS:\n"); + + if (htt_stats_buf->user_index < + HTT_TX_PDEV_STATS_NUM_AX_MUMIMO_USER_STATS) { +- len += HTT_DBG_OUT(buf + len, buf_len - len, +- "ax_mu_mimo_mpdus_queued_usr_%u = %u", +- htt_stats_buf->user_index, +- htt_stats_buf->mpdus_queued_usr); +- len += HTT_DBG_OUT(buf + len, buf_len - len, +- "ax_mu_mimo_mpdus_tried_usr_%u = %u", +- htt_stats_buf->user_index, +- htt_stats_buf->mpdus_tried_usr); +- len += HTT_DBG_OUT(buf + len, buf_len - len, +- "ax_mu_mimo_mpdus_failed_usr_%u = %u", +- htt_stats_buf->user_index, +- htt_stats_buf->mpdus_failed_usr); +- len += HTT_DBG_OUT(buf + len, buf_len - len, +- "ax_mu_mimo_mpdus_requeued_usr_%u = %u", +- htt_stats_buf->user_index, +- htt_stats_buf->mpdus_requeued_usr); +- len += HTT_DBG_OUT(buf + len, buf_len - len, +- "ax_mu_mimo_err_no_ba_usr_%u = %u", +- htt_stats_buf->user_index, +- htt_stats_buf->err_no_ba_usr); +- len += HTT_DBG_OUT(buf + len, buf_len - len, +- "ax_mu_mimo_mpdu_underrun_usr_%u = %u", +- htt_stats_buf->user_index, +- htt_stats_buf->mpdu_underrun_usr); +- len += HTT_DBG_OUT(buf + len, buf_len - len, +- "ax_mu_mimo_ampdu_underrun_usr_%u = %u\n", +- htt_stats_buf->user_index, +- htt_stats_buf->ampdu_underrun_usr); ++ len += scnprintf(buf + len, buf_len - len, ++ "ax_mu_mimo_mpdus_queued_usr_%u = %u\n", ++ htt_stats_buf->user_index, ++ htt_stats_buf->mpdus_queued_usr); ++ len += scnprintf(buf + len, buf_len - len, ++ "ax_mu_mimo_mpdus_tried_usr_%u = %u\n", ++ htt_stats_buf->user_index, ++ htt_stats_buf->mpdus_tried_usr); ++ len += scnprintf(buf + len, buf_len - len, ++ "ax_mu_mimo_mpdus_failed_usr_%u = %u\n", ++ htt_stats_buf->user_index, ++ htt_stats_buf->mpdus_failed_usr); ++ len += scnprintf(buf + len, buf_len - len, ++ "ax_mu_mimo_mpdus_requeued_usr_%u = %u\n", ++ htt_stats_buf->user_index, ++ htt_stats_buf->mpdus_requeued_usr); ++ len += scnprintf(buf + len, buf_len - len, ++ "ax_mu_mimo_err_no_ba_usr_%u = %u\n", ++ htt_stats_buf->user_index, ++ htt_stats_buf->err_no_ba_usr); ++ len += scnprintf(buf + len, buf_len - len, ++ "ax_mu_mimo_mpdu_underrun_usr_%u = %u\n", ++ htt_stats_buf->user_index, ++ htt_stats_buf->mpdu_underrun_usr); ++ len += scnprintf(buf + len, buf_len - len, ++ "ax_mu_mimo_ampdu_underrun_usr_%u = %u\n\n", ++ htt_stats_buf->user_index, ++ htt_stats_buf->ampdu_underrun_usr); + } + } + + if (htt_stats_buf->tx_sched_mode == HTT_STATS_TX_SCHED_MODE_MU_OFDMA_AX) { + if (!htt_stats_buf->user_index) +- len += HTT_DBG_OUT(buf + len, buf_len - len, +- "HTT_TX_PDEV_AX_MU_OFDMA_MPDU_STATS:\n"); ++ len += scnprintf(buf + len, buf_len - len, ++ "HTT_TX_PDEV_AX_MU_OFDMA_MPDU_STATS:\n"); + + if (htt_stats_buf->user_index < HTT_TX_PDEV_STATS_NUM_OFDMA_USER_STATS) { +- len += HTT_DBG_OUT(buf + len, buf_len - len, +- "ax_mu_ofdma_mpdus_queued_usr_%u = %u", +- htt_stats_buf->user_index, +- htt_stats_buf->mpdus_queued_usr); +- len += HTT_DBG_OUT(buf + len, buf_len - len, +- "ax_mu_ofdma_mpdus_tried_usr_%u = %u", +- htt_stats_buf->user_index, +- htt_stats_buf->mpdus_tried_usr); +- len += HTT_DBG_OUT(buf + len, buf_len - len, +- "ax_mu_ofdma_mpdus_failed_usr_%u = %u", +- htt_stats_buf->user_index, +- htt_stats_buf->mpdus_failed_usr); +- len += HTT_DBG_OUT(buf + len, buf_len - len, +- "ax_mu_ofdma_mpdus_requeued_usr_%u = %u", +- htt_stats_buf->user_index, +- htt_stats_buf->mpdus_requeued_usr); +- len += HTT_DBG_OUT(buf + len, buf_len - len, +- "ax_mu_ofdma_err_no_ba_usr_%u = %u", +- htt_stats_buf->user_index, +- htt_stats_buf->err_no_ba_usr); +- len += HTT_DBG_OUT(buf + len, buf_len - len, +- "ax_mu_ofdma_mpdu_underrun_usr_%u = %u", +- htt_stats_buf->user_index, +- htt_stats_buf->mpdu_underrun_usr); +- len += HTT_DBG_OUT(buf + len, buf_len - len, +- "ax_mu_ofdma_ampdu_underrun_usr_%u = %u\n", +- htt_stats_buf->user_index, +- htt_stats_buf->ampdu_underrun_usr); ++ len += scnprintf(buf + len, buf_len - len, ++ "ax_mu_ofdma_mpdus_queued_usr_%u = %u\n", ++ htt_stats_buf->user_index, ++ htt_stats_buf->mpdus_queued_usr); ++ len += scnprintf(buf + len, buf_len - len, ++ "ax_mu_ofdma_mpdus_tried_usr_%u = %u\n", ++ htt_stats_buf->user_index, ++ htt_stats_buf->mpdus_tried_usr); ++ len += scnprintf(buf + len, buf_len - len, ++ "ax_mu_ofdma_mpdus_failed_usr_%u = %u\n", ++ htt_stats_buf->user_index, ++ htt_stats_buf->mpdus_failed_usr); ++ len += scnprintf(buf + len, buf_len - len, ++ "ax_mu_ofdma_mpdus_requeued_usr_%u = %u\n", ++ htt_stats_buf->user_index, ++ htt_stats_buf->mpdus_requeued_usr); ++ len += scnprintf(buf + len, buf_len - len, ++ "ax_mu_ofdma_err_no_ba_usr_%u = %u\n", ++ htt_stats_buf->user_index, ++ htt_stats_buf->err_no_ba_usr); ++ len += scnprintf(buf + len, buf_len - len, ++ "ax_mu_ofdma_mpdu_underrun_usr_%u = %u\n", ++ htt_stats_buf->user_index, ++ htt_stats_buf->mpdu_underrun_usr); ++ len += scnprintf(buf + len, buf_len - len, ++ "ax_mu_ofdma_ampdu_underrun_usr_%u = %u\n\n", ++ htt_stats_buf->user_index, ++ htt_stats_buf->ampdu_underrun_usr); + } + } + +@@ -1788,12 +1784,12 @@ htt_print_sched_txq_cmd_posted_tlv_v(con + char sched_cmd_posted[HTT_MAX_STRING_LEN] = {0}; + u16 num_elements = min_t(u16, (tag_len >> 2), HTT_TX_PDEV_SCHED_TX_MODE_MAX); + +- len += HTT_DBG_OUT(buf + len, buf_len - len, "HTT_SCHED_TXQ_CMD_POSTED_TLV_V:"); ++ len += scnprintf(buf + len, buf_len - len, "HTT_SCHED_TXQ_CMD_POSTED_TLV_V:\n"); + + PRINT_ARRAY_TO_BUF(sched_cmd_posted, htt_stats_buf->sched_cmd_posted, + num_elements); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "sched_cmd_posted = %s\n", +- sched_cmd_posted); ++ len += scnprintf(buf + len, buf_len - len, "sched_cmd_posted = %s\n\n", ++ sched_cmd_posted); + + if (len >= buf_len) + buf[buf_len - 1] = 0; +@@ -1815,12 +1811,12 @@ htt_print_sched_txq_cmd_reaped_tlv_v(con + char sched_cmd_reaped[HTT_MAX_STRING_LEN] = {0}; + u16 num_elements = min_t(u16, (tag_len >> 2), HTT_TX_PDEV_SCHED_TX_MODE_MAX); + +- len += HTT_DBG_OUT(buf + len, buf_len - len, "HTT_SCHED_TXQ_CMD_REAPED_TLV_V:"); ++ len += scnprintf(buf + len, buf_len - len, "HTT_SCHED_TXQ_CMD_REAPED_TLV_V:\n"); + + PRINT_ARRAY_TO_BUF(sched_cmd_reaped, htt_stats_buf->sched_cmd_reaped, + num_elements); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "sched_cmd_reaped = %s\n", +- sched_cmd_reaped); ++ len += scnprintf(buf + len, buf_len - len, "sched_cmd_reaped = %s\n\n", ++ sched_cmd_reaped); + + if (len >= buf_len) + buf[buf_len - 1] = 0; +@@ -1844,13 +1840,13 @@ htt_print_sched_txq_sched_order_su_tlv_v + u32 sched_order_su_num_entries = + min_t(u32, (tag_len >> 2), HTT_TX_PDEV_NUM_SCHED_ORDER_LOG); + +- len += HTT_DBG_OUT(buf + len, buf_len - len, +- "HTT_SCHED_TXQ_SCHED_ORDER_SU_TLV_V:"); ++ len += scnprintf(buf + len, buf_len - len, ++ "HTT_SCHED_TXQ_SCHED_ORDER_SU_TLV_V:\n"); + + PRINT_ARRAY_TO_BUF(sched_order_su, htt_stats_buf->sched_order_su, + sched_order_su_num_entries); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "sched_order_su = %s\n", +- sched_order_su); ++ len += scnprintf(buf + len, buf_len - len, "sched_order_su = %s\n\n", ++ sched_order_su); + + if (len >= buf_len) + buf[buf_len - 1] = 0; +@@ -1873,13 +1869,13 @@ htt_print_sched_txq_sched_ineligibility_ + /* each entry is u32, i.e. 4 bytes */ + u32 sched_ineligibility_num_entries = tag_len >> 2; + +- len += HTT_DBG_OUT(buf + len, buf_len - len, +- "HTT_SCHED_TXQ_SCHED_INELIGIBILITY_V:"); ++ len += scnprintf(buf + len, buf_len - len, ++ "HTT_SCHED_TXQ_SCHED_INELIGIBILITY_V:\n"); + + PRINT_ARRAY_TO_BUF(sched_ineligibility, htt_stats_buf->sched_ineligibility, + sched_ineligibility_num_entries); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "sched_ineligibility = %s\n", +- sched_ineligibility); ++ len += scnprintf(buf + len, buf_len - len, "sched_ineligibility = %s\n\n", ++ sched_ineligibility); + + if (len >= buf_len) + buf[buf_len - 1] = 0; +@@ -1898,54 +1894,54 @@ htt_print_tx_pdev_stats_sched_per_txq_tl + u32 len = stats_req->buf_len; + u32 buf_len = ATH11K_HTT_STATS_BUF_SIZE; + +- len += HTT_DBG_OUT(buf + len, buf_len - len, +- "HTT_TX_PDEV_STATS_SCHED_PER_TXQ_TLV:"); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "mac_id = %u", +- htt_stats_buf->mac_id__txq_id__word & 0xFF); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "txq_id = %u", +- (htt_stats_buf->mac_id__txq_id__word & 0xFF00) >> 8); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "sched_policy = %u", +- htt_stats_buf->sched_policy); +- len += HTT_DBG_OUT(buf + len, buf_len - len, +- "last_sched_cmd_posted_timestamp = %u", +- htt_stats_buf->last_sched_cmd_posted_timestamp); +- len += HTT_DBG_OUT(buf + len, buf_len - len, +- "last_sched_cmd_compl_timestamp = %u", +- htt_stats_buf->last_sched_cmd_compl_timestamp); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "sched_2_tac_lwm_count = %u", +- htt_stats_buf->sched_2_tac_lwm_count); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "sched_2_tac_ring_full = %u", +- htt_stats_buf->sched_2_tac_ring_full); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "sched_cmd_post_failure = %u", +- htt_stats_buf->sched_cmd_post_failure); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "num_active_tids = %u", +- htt_stats_buf->num_active_tids); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "num_ps_schedules = %u", +- htt_stats_buf->num_ps_schedules); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "sched_cmds_pending = %u", +- htt_stats_buf->sched_cmds_pending); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "num_tid_register = %u", +- htt_stats_buf->num_tid_register); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "num_tid_unregister = %u", +- htt_stats_buf->num_tid_unregister); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "num_qstats_queried = %u", +- htt_stats_buf->num_qstats_queried); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "qstats_update_pending = %u", +- htt_stats_buf->qstats_update_pending); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "last_qstats_query_timestamp = %u", +- htt_stats_buf->last_qstats_query_timestamp); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "num_tqm_cmdq_full = %u", +- htt_stats_buf->num_tqm_cmdq_full); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "num_de_sched_algo_trigger = %u", +- htt_stats_buf->num_de_sched_algo_trigger); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "num_rt_sched_algo_trigger = %u", +- htt_stats_buf->num_rt_sched_algo_trigger); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "num_tqm_sched_algo_trigger = %u", +- htt_stats_buf->num_tqm_sched_algo_trigger); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "notify_sched = %u\n", +- htt_stats_buf->notify_sched); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "dur_based_sendn_term = %u\n", +- htt_stats_buf->dur_based_sendn_term); ++ len += scnprintf(buf + len, buf_len - len, ++ "HTT_TX_PDEV_STATS_SCHED_PER_TXQ_TLV:\n"); ++ len += scnprintf(buf + len, buf_len - len, "mac_id = %u\n", ++ htt_stats_buf->mac_id__txq_id__word & 0xFF); ++ len += scnprintf(buf + len, buf_len - len, "txq_id = %u\n", ++ (htt_stats_buf->mac_id__txq_id__word & 0xFF00) >> 8); ++ len += scnprintf(buf + len, buf_len - len, "sched_policy = %u\n", ++ htt_stats_buf->sched_policy); ++ len += scnprintf(buf + len, buf_len - len, ++ "last_sched_cmd_posted_timestamp = %u\n", ++ htt_stats_buf->last_sched_cmd_posted_timestamp); ++ len += scnprintf(buf + len, buf_len - len, ++ "last_sched_cmd_compl_timestamp = %u\n", ++ htt_stats_buf->last_sched_cmd_compl_timestamp); ++ len += scnprintf(buf + len, buf_len - len, "sched_2_tac_lwm_count = %u\n", ++ htt_stats_buf->sched_2_tac_lwm_count); ++ len += scnprintf(buf + len, buf_len - len, "sched_2_tac_ring_full = %u\n", ++ htt_stats_buf->sched_2_tac_ring_full); ++ len += scnprintf(buf + len, buf_len - len, "sched_cmd_post_failure = %u\n", ++ htt_stats_buf->sched_cmd_post_failure); ++ len += scnprintf(buf + len, buf_len - len, "num_active_tids = %u\n", ++ htt_stats_buf->num_active_tids); ++ len += scnprintf(buf + len, buf_len - len, "num_ps_schedules = %u\n", ++ htt_stats_buf->num_ps_schedules); ++ len += scnprintf(buf + len, buf_len - len, "sched_cmds_pending = %u\n", ++ htt_stats_buf->sched_cmds_pending); ++ len += scnprintf(buf + len, buf_len - len, "num_tid_register = %u\n", ++ htt_stats_buf->num_tid_register); ++ len += scnprintf(buf + len, buf_len - len, "num_tid_unregister = %u\n", ++ htt_stats_buf->num_tid_unregister); ++ len += scnprintf(buf + len, buf_len - len, "num_qstats_queried = %u\n", ++ htt_stats_buf->num_qstats_queried); ++ len += scnprintf(buf + len, buf_len - len, "qstats_update_pending = %u\n", ++ htt_stats_buf->qstats_update_pending); ++ len += scnprintf(buf + len, buf_len - len, "last_qstats_query_timestamp = %u\n", ++ htt_stats_buf->last_qstats_query_timestamp); ++ len += scnprintf(buf + len, buf_len - len, "num_tqm_cmdq_full = %u\n", ++ htt_stats_buf->num_tqm_cmdq_full); ++ len += scnprintf(buf + len, buf_len - len, "num_de_sched_algo_trigger = %u\n", ++ htt_stats_buf->num_de_sched_algo_trigger); ++ len += scnprintf(buf + len, buf_len - len, "num_rt_sched_algo_trigger = %u\n", ++ htt_stats_buf->num_rt_sched_algo_trigger); ++ len += scnprintf(buf + len, buf_len - len, "num_tqm_sched_algo_trigger = %u\n", ++ htt_stats_buf->num_tqm_sched_algo_trigger); ++ len += scnprintf(buf + len, buf_len - len, "notify_sched = %u\n\n", ++ htt_stats_buf->notify_sched); ++ len += scnprintf(buf + len, buf_len - len, "dur_based_sendn_term = %u\n\n", ++ htt_stats_buf->dur_based_sendn_term); + + if (len >= buf_len) + buf[buf_len - 1] = 0; +@@ -1963,11 +1959,11 @@ static inline void htt_print_stats_tx_sc + u32 len = stats_req->buf_len; + u32 buf_len = ATH11K_HTT_STATS_BUF_SIZE; + +- len += HTT_DBG_OUT(buf + len, buf_len - len, "HTT_STATS_TX_SCHED_CMN_TLV:"); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "mac_id = %u", +- htt_stats_buf->mac_id__word & 0xFF); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "current_timestamp = %u\n", +- htt_stats_buf->current_timestamp); ++ len += scnprintf(buf + len, buf_len - len, "HTT_STATS_TX_SCHED_CMN_TLV:\n"); ++ len += scnprintf(buf + len, buf_len - len, "mac_id = %u\n", ++ htt_stats_buf->mac_id__word & 0xFF); ++ len += scnprintf(buf + len, buf_len - len, "current_timestamp = %u\n\n", ++ htt_stats_buf->current_timestamp); + + if (len >= buf_len) + buf[buf_len - 1] = 0; +@@ -1990,12 +1986,12 @@ htt_print_tx_tqm_gen_mpdu_stats_tlv_v(co + u16 num_elements = min_t(u16, (tag_len >> 2), + HTT_TX_TQM_MAX_LIST_MPDU_END_REASON); + +- len += HTT_DBG_OUT(buf + len, buf_len - len, "HTT_TX_TQM_GEN_MPDU_STATS_TLV_V:"); ++ len += scnprintf(buf + len, buf_len - len, "HTT_TX_TQM_GEN_MPDU_STATS_TLV_V:\n"); + + PRINT_ARRAY_TO_BUF(gen_mpdu_end_reason, htt_stats_buf->gen_mpdu_end_reason, + num_elements); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "gen_mpdu_end_reason = %s\n", +- gen_mpdu_end_reason); ++ len += scnprintf(buf + len, buf_len - len, "gen_mpdu_end_reason = %s\n\n", ++ gen_mpdu_end_reason); + + if (len >= buf_len) + buf[buf_len - 1] = 0; +@@ -2017,13 +2013,13 @@ htt_print_tx_tqm_list_mpdu_stats_tlv_v(c + char list_mpdu_end_reason[HTT_MAX_STRING_LEN] = {0}; + u16 num_elems = min_t(u16, (tag_len >> 2), HTT_TX_TQM_MAX_LIST_MPDU_END_REASON); + +- len += HTT_DBG_OUT(buf + len, buf_len - len, +- "HTT_TX_TQM_LIST_MPDU_STATS_TLV_V:"); ++ len += scnprintf(buf + len, buf_len - len, ++ "HTT_TX_TQM_LIST_MPDU_STATS_TLV_V:\n"); + + PRINT_ARRAY_TO_BUF(list_mpdu_end_reason, htt_stats_buf->list_mpdu_end_reason, + num_elems); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "list_mpdu_end_reason = %s\n", +- list_mpdu_end_reason); ++ len += scnprintf(buf + len, buf_len - len, "list_mpdu_end_reason = %s\n\n", ++ list_mpdu_end_reason); + if (len >= buf_len) + buf[buf_len - 1] = 0; + else +@@ -2045,12 +2041,12 @@ htt_print_tx_tqm_list_mpdu_cnt_tlv_v(con + u16 num_elems = min_t(u16, (tag_len >> 2), + HTT_TX_TQM_MAX_LIST_MPDU_CNT_HISTOGRAM_BINS); + +- len += HTT_DBG_OUT(buf + len, buf_len - len, "HTT_TX_TQM_LIST_MPDU_CNT_TLV_V:"); ++ len += scnprintf(buf + len, buf_len - len, "HTT_TX_TQM_LIST_MPDU_CNT_TLV_V:\n"); + + PRINT_ARRAY_TO_BUF(list_mpdu_cnt_hist, htt_stats_buf->list_mpdu_cnt_hist, + num_elems); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "list_mpdu_cnt_hist = %s\n", +- list_mpdu_cnt_hist); ++ len += scnprintf(buf + len, buf_len - len, "list_mpdu_cnt_hist = %s\n\n", ++ list_mpdu_cnt_hist); + + if (len >= buf_len) + buf[buf_len - 1] = 0; +@@ -2069,69 +2065,69 @@ htt_print_tx_tqm_pdev_stats_tlv_v(const + u32 len = stats_req->buf_len; + u32 buf_len = ATH11K_HTT_STATS_BUF_SIZE; + +- len += HTT_DBG_OUT(buf + len, buf_len - len, "HTT_TX_TQM_PDEV_STATS_TLV_V:"); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "msdu_count = %u", +- htt_stats_buf->msdu_count); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "mpdu_count = %u", +- htt_stats_buf->mpdu_count); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "remove_msdu = %u", +- htt_stats_buf->remove_msdu); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "remove_mpdu = %u", +- htt_stats_buf->remove_mpdu); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "remove_msdu_ttl = %u", +- htt_stats_buf->remove_msdu_ttl); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "send_bar = %u", +- htt_stats_buf->send_bar); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "bar_sync = %u", +- htt_stats_buf->bar_sync); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "notify_mpdu = %u", +- htt_stats_buf->notify_mpdu); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "sync_cmd = %u", +- htt_stats_buf->sync_cmd); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "write_cmd = %u", +- htt_stats_buf->write_cmd); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "hwsch_trigger = %u", +- htt_stats_buf->hwsch_trigger); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "ack_tlv_proc = %u", +- htt_stats_buf->ack_tlv_proc); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "gen_mpdu_cmd = %u", +- htt_stats_buf->gen_mpdu_cmd); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "gen_list_cmd = %u", +- htt_stats_buf->gen_list_cmd); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "remove_mpdu_cmd = %u", +- htt_stats_buf->remove_mpdu_cmd); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "remove_mpdu_tried_cmd = %u", +- htt_stats_buf->remove_mpdu_tried_cmd); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "mpdu_queue_stats_cmd = %u", +- htt_stats_buf->mpdu_queue_stats_cmd); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "mpdu_head_info_cmd = %u", +- htt_stats_buf->mpdu_head_info_cmd); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "msdu_flow_stats_cmd = %u", +- htt_stats_buf->msdu_flow_stats_cmd); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "remove_msdu_cmd = %u", +- htt_stats_buf->remove_msdu_cmd); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "remove_msdu_ttl_cmd = %u", +- htt_stats_buf->remove_msdu_ttl_cmd); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "flush_cache_cmd = %u", +- htt_stats_buf->flush_cache_cmd); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "update_mpduq_cmd = %u", +- htt_stats_buf->update_mpduq_cmd); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "enqueue = %u", +- htt_stats_buf->enqueue); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "enqueue_notify = %u", +- htt_stats_buf->enqueue_notify); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "notify_mpdu_at_head = %u", +- htt_stats_buf->notify_mpdu_at_head); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "notify_mpdu_state_valid = %u", +- htt_stats_buf->notify_mpdu_state_valid); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "sched_udp_notify1 = %u", +- htt_stats_buf->sched_udp_notify1); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "sched_udp_notify2 = %u", +- htt_stats_buf->sched_udp_notify2); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "sched_nonudp_notify1 = %u", +- htt_stats_buf->sched_nonudp_notify1); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "sched_nonudp_notify2 = %u\n", +- htt_stats_buf->sched_nonudp_notify2); ++ len += scnprintf(buf + len, buf_len - len, "HTT_TX_TQM_PDEV_STATS_TLV_V:\n"); ++ len += scnprintf(buf + len, buf_len - len, "msdu_count = %u\n", ++ htt_stats_buf->msdu_count); ++ len += scnprintf(buf + len, buf_len - len, "mpdu_count = %u\n", ++ htt_stats_buf->mpdu_count); ++ len += scnprintf(buf + len, buf_len - len, "remove_msdu = %u\n", ++ htt_stats_buf->remove_msdu); ++ len += scnprintf(buf + len, buf_len - len, "remove_mpdu = %u\n", ++ htt_stats_buf->remove_mpdu); ++ len += scnprintf(buf + len, buf_len - len, "remove_msdu_ttl = %u\n", ++ htt_stats_buf->remove_msdu_ttl); ++ len += scnprintf(buf + len, buf_len - len, "send_bar = %u\n", ++ htt_stats_buf->send_bar); ++ len += scnprintf(buf + len, buf_len - len, "bar_sync = %u\n", ++ htt_stats_buf->bar_sync); ++ len += scnprintf(buf + len, buf_len - len, "notify_mpdu = %u\n", ++ htt_stats_buf->notify_mpdu); ++ len += scnprintf(buf + len, buf_len - len, "sync_cmd = %u\n", ++ htt_stats_buf->sync_cmd); ++ len += scnprintf(buf + len, buf_len - len, "write_cmd = %u\n", ++ htt_stats_buf->write_cmd); ++ len += scnprintf(buf + len, buf_len - len, "hwsch_trigger = %u\n", ++ htt_stats_buf->hwsch_trigger); ++ len += scnprintf(buf + len, buf_len - len, "ack_tlv_proc = %u\n", ++ htt_stats_buf->ack_tlv_proc); ++ len += scnprintf(buf + len, buf_len - len, "gen_mpdu_cmd = %u\n", ++ htt_stats_buf->gen_mpdu_cmd); ++ len += scnprintf(buf + len, buf_len - len, "gen_list_cmd = %u\n", ++ htt_stats_buf->gen_list_cmd); ++ len += scnprintf(buf + len, buf_len - len, "remove_mpdu_cmd = %u\n", ++ htt_stats_buf->remove_mpdu_cmd); ++ len += scnprintf(buf + len, buf_len - len, "remove_mpdu_tried_cmd = %u\n", ++ htt_stats_buf->remove_mpdu_tried_cmd); ++ len += scnprintf(buf + len, buf_len - len, "mpdu_queue_stats_cmd = %u\n", ++ htt_stats_buf->mpdu_queue_stats_cmd); ++ len += scnprintf(buf + len, buf_len - len, "mpdu_head_info_cmd = %u\n", ++ htt_stats_buf->mpdu_head_info_cmd); ++ len += scnprintf(buf + len, buf_len - len, "msdu_flow_stats_cmd = %u\n", ++ htt_stats_buf->msdu_flow_stats_cmd); ++ len += scnprintf(buf + len, buf_len - len, "remove_msdu_cmd = %u\n", ++ htt_stats_buf->remove_msdu_cmd); ++ len += scnprintf(buf + len, buf_len - len, "remove_msdu_ttl_cmd = %u\n", ++ htt_stats_buf->remove_msdu_ttl_cmd); ++ len += scnprintf(buf + len, buf_len - len, "flush_cache_cmd = %u\n", ++ htt_stats_buf->flush_cache_cmd); ++ len += scnprintf(buf + len, buf_len - len, "update_mpduq_cmd = %u\n", ++ htt_stats_buf->update_mpduq_cmd); ++ len += scnprintf(buf + len, buf_len - len, "enqueue = %u\n", ++ htt_stats_buf->enqueue); ++ len += scnprintf(buf + len, buf_len - len, "enqueue_notify = %u\n", ++ htt_stats_buf->enqueue_notify); ++ len += scnprintf(buf + len, buf_len - len, "notify_mpdu_at_head = %u\n", ++ htt_stats_buf->notify_mpdu_at_head); ++ len += scnprintf(buf + len, buf_len - len, "notify_mpdu_state_valid = %u\n", ++ htt_stats_buf->notify_mpdu_state_valid); ++ len += scnprintf(buf + len, buf_len - len, "sched_udp_notify1 = %u\n", ++ htt_stats_buf->sched_udp_notify1); ++ len += scnprintf(buf + len, buf_len - len, "sched_udp_notify2 = %u\n", ++ htt_stats_buf->sched_udp_notify2); ++ len += scnprintf(buf + len, buf_len - len, "sched_nonudp_notify1 = %u\n", ++ htt_stats_buf->sched_nonudp_notify1); ++ len += scnprintf(buf + len, buf_len - len, "sched_nonudp_notify2 = %u\n\n", ++ htt_stats_buf->sched_nonudp_notify2); + + if (len >= buf_len) + buf[buf_len - 1] = 0; +@@ -2149,23 +2145,23 @@ static inline void htt_print_tx_tqm_cmn_ + u32 len = stats_req->buf_len; + u32 buf_len = ATH11K_HTT_STATS_BUF_SIZE; + +- len += HTT_DBG_OUT(buf + len, buf_len - len, "HTT_TX_TQM_CMN_STATS_TLV:"); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "mac_id = %u", +- htt_stats_buf->mac_id__word & 0xFF); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "max_cmdq_id = %u", +- htt_stats_buf->max_cmdq_id); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "list_mpdu_cnt_hist_intvl = %u", +- htt_stats_buf->list_mpdu_cnt_hist_intvl); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "add_msdu = %u", +- htt_stats_buf->add_msdu); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "q_empty = %u", +- htt_stats_buf->q_empty); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "q_not_empty = %u", +- htt_stats_buf->q_not_empty); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "drop_notification = %u", +- htt_stats_buf->drop_notification); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "desc_threshold = %u\n", +- htt_stats_buf->desc_threshold); ++ len += scnprintf(buf + len, buf_len - len, "HTT_TX_TQM_CMN_STATS_TLV:\n"); ++ len += scnprintf(buf + len, buf_len - len, "mac_id = %u\n", ++ htt_stats_buf->mac_id__word & 0xFF); ++ len += scnprintf(buf + len, buf_len - len, "max_cmdq_id = %u\n", ++ htt_stats_buf->max_cmdq_id); ++ len += scnprintf(buf + len, buf_len - len, "list_mpdu_cnt_hist_intvl = %u\n", ++ htt_stats_buf->list_mpdu_cnt_hist_intvl); ++ len += scnprintf(buf + len, buf_len - len, "add_msdu = %u\n", ++ htt_stats_buf->add_msdu); ++ len += scnprintf(buf + len, buf_len - len, "q_empty = %u\n", ++ htt_stats_buf->q_empty); ++ len += scnprintf(buf + len, buf_len - len, "q_not_empty = %u\n", ++ htt_stats_buf->q_not_empty); ++ len += scnprintf(buf + len, buf_len - len, "drop_notification = %u\n", ++ htt_stats_buf->drop_notification); ++ len += scnprintf(buf + len, buf_len - len, "desc_threshold = %u\n\n", ++ htt_stats_buf->desc_threshold); + + if (len >= buf_len) + buf[buf_len - 1] = 0; +@@ -2183,13 +2179,13 @@ static inline void htt_print_tx_tqm_erro + u32 len = stats_req->buf_len; + u32 buf_len = ATH11K_HTT_STATS_BUF_SIZE; + +- len += HTT_DBG_OUT(buf + len, buf_len - len, "HTT_TX_TQM_ERROR_STATS_TLV:"); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "q_empty_failure = %u", +- htt_stats_buf->q_empty_failure); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "q_not_empty_failure = %u", +- htt_stats_buf->q_not_empty_failure); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "add_msdu_failure = %u\n", +- htt_stats_buf->add_msdu_failure); ++ len += scnprintf(buf + len, buf_len - len, "HTT_TX_TQM_ERROR_STATS_TLV:\n"); ++ len += scnprintf(buf + len, buf_len - len, "q_empty_failure = %u\n", ++ htt_stats_buf->q_empty_failure); ++ len += scnprintf(buf + len, buf_len - len, "q_not_empty_failure = %u\n", ++ htt_stats_buf->q_not_empty_failure); ++ len += scnprintf(buf + len, buf_len - len, "add_msdu_failure = %u\n\n", ++ htt_stats_buf->add_msdu_failure); + + if (len >= buf_len) + buf[buf_len - 1] = 0; +@@ -2207,33 +2203,33 @@ static inline void htt_print_tx_tqm_cmdq + u32 len = stats_req->buf_len; + u32 buf_len = ATH11K_HTT_STATS_BUF_SIZE; + +- len += HTT_DBG_OUT(buf + len, buf_len - len, "HTT_TX_TQM_CMDQ_STATUS_TLV:"); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "mac_id = %u", +- htt_stats_buf->mac_id__cmdq_id__word & 0xFF); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "cmdq_id = %u\n", +- (htt_stats_buf->mac_id__cmdq_id__word & 0xFF00) >> 8); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "sync_cmd = %u", +- htt_stats_buf->sync_cmd); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "write_cmd = %u", +- htt_stats_buf->write_cmd); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "gen_mpdu_cmd = %u", +- htt_stats_buf->gen_mpdu_cmd); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "mpdu_queue_stats_cmd = %u", +- htt_stats_buf->mpdu_queue_stats_cmd); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "mpdu_head_info_cmd = %u", +- htt_stats_buf->mpdu_head_info_cmd); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "msdu_flow_stats_cmd = %u", +- htt_stats_buf->msdu_flow_stats_cmd); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "remove_mpdu_cmd = %u", +- htt_stats_buf->remove_mpdu_cmd); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "remove_msdu_cmd = %u", +- htt_stats_buf->remove_msdu_cmd); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "flush_cache_cmd = %u", +- htt_stats_buf->flush_cache_cmd); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "update_mpduq_cmd = %u", +- htt_stats_buf->update_mpduq_cmd); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "update_msduq_cmd = %u\n", +- htt_stats_buf->update_msduq_cmd); ++ len += scnprintf(buf + len, buf_len - len, "HTT_TX_TQM_CMDQ_STATUS_TLV:\n"); ++ len += scnprintf(buf + len, buf_len - len, "mac_id = %u\n", ++ htt_stats_buf->mac_id__cmdq_id__word & 0xFF); ++ len += scnprintf(buf + len, buf_len - len, "cmdq_id = %u\n\n", ++ (htt_stats_buf->mac_id__cmdq_id__word & 0xFF00) >> 8); ++ len += scnprintf(buf + len, buf_len - len, "sync_cmd = %u\n", ++ htt_stats_buf->sync_cmd); ++ len += scnprintf(buf + len, buf_len - len, "write_cmd = %u\n", ++ htt_stats_buf->write_cmd); ++ len += scnprintf(buf + len, buf_len - len, "gen_mpdu_cmd = %u\n", ++ htt_stats_buf->gen_mpdu_cmd); ++ len += scnprintf(buf + len, buf_len - len, "mpdu_queue_stats_cmd = %u\n", ++ htt_stats_buf->mpdu_queue_stats_cmd); ++ len += scnprintf(buf + len, buf_len - len, "mpdu_head_info_cmd = %u\n", ++ htt_stats_buf->mpdu_head_info_cmd); ++ len += scnprintf(buf + len, buf_len - len, "msdu_flow_stats_cmd = %u\n", ++ htt_stats_buf->msdu_flow_stats_cmd); ++ len += scnprintf(buf + len, buf_len - len, "remove_mpdu_cmd = %u\n", ++ htt_stats_buf->remove_mpdu_cmd); ++ len += scnprintf(buf + len, buf_len - len, "remove_msdu_cmd = %u\n", ++ htt_stats_buf->remove_msdu_cmd); ++ len += scnprintf(buf + len, buf_len - len, "flush_cache_cmd = %u\n", ++ htt_stats_buf->flush_cache_cmd); ++ len += scnprintf(buf + len, buf_len - len, "update_mpduq_cmd = %u\n", ++ htt_stats_buf->update_mpduq_cmd); ++ len += scnprintf(buf + len, buf_len - len, "update_msduq_cmd = %u\n\n", ++ htt_stats_buf->update_msduq_cmd); + + if (len >= buf_len) + buf[buf_len - 1] = 0; +@@ -2252,20 +2248,20 @@ htt_print_tx_de_eapol_packets_stats_tlv( + u32 len = stats_req->buf_len; + u32 buf_len = ATH11K_HTT_STATS_BUF_SIZE; + +- len += HTT_DBG_OUT(buf + len, buf_len - len, +- "HTT_TX_DE_EAPOL_PACKETS_STATS_TLV:"); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "m1_packets = %u", +- htt_stats_buf->m1_packets); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "m2_packets = %u", +- htt_stats_buf->m2_packets); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "m3_packets = %u", +- htt_stats_buf->m3_packets); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "m4_packets = %u", +- htt_stats_buf->m4_packets); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "g1_packets = %u", +- htt_stats_buf->g1_packets); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "g2_packets = %u\n", +- htt_stats_buf->g2_packets); ++ len += scnprintf(buf + len, buf_len - len, ++ "HTT_TX_DE_EAPOL_PACKETS_STATS_TLV:\n"); ++ len += scnprintf(buf + len, buf_len - len, "m1_packets = %u\n", ++ htt_stats_buf->m1_packets); ++ len += scnprintf(buf + len, buf_len - len, "m2_packets = %u\n", ++ htt_stats_buf->m2_packets); ++ len += scnprintf(buf + len, buf_len - len, "m3_packets = %u\n", ++ htt_stats_buf->m3_packets); ++ len += scnprintf(buf + len, buf_len - len, "m4_packets = %u\n", ++ htt_stats_buf->m4_packets); ++ len += scnprintf(buf + len, buf_len - len, "g1_packets = %u\n", ++ htt_stats_buf->g1_packets); ++ len += scnprintf(buf + len, buf_len - len, "g2_packets = %u\n\n", ++ htt_stats_buf->g2_packets); + + if (len >= buf_len) + buf[buf_len - 1] = 0; +@@ -2284,34 +2280,34 @@ htt_print_tx_de_classify_failed_stats_tl + u32 len = stats_req->buf_len; + u32 buf_len = ATH11K_HTT_STATS_BUF_SIZE; + +- len += HTT_DBG_OUT(buf + len, buf_len - len, +- "HTT_TX_DE_CLASSIFY_FAILED_STATS_TLV:"); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "ap_bss_peer_not_found = %u", +- htt_stats_buf->ap_bss_peer_not_found); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "ap_bcast_mcast_no_peer = %u", +- htt_stats_buf->ap_bcast_mcast_no_peer); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "sta_delete_in_progress = %u", +- htt_stats_buf->sta_delete_in_progress); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "ibss_no_bss_peer = %u", +- htt_stats_buf->ibss_no_bss_peer); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "invalid_vdev_type = %u", +- htt_stats_buf->invalid_vdev_type); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "invalid_ast_peer_entry = %u", +- htt_stats_buf->invalid_ast_peer_entry); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "peer_entry_invalid = %u", +- htt_stats_buf->peer_entry_invalid); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "ethertype_not_ip = %u", +- htt_stats_buf->ethertype_not_ip); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "eapol_lookup_failed = %u", +- htt_stats_buf->eapol_lookup_failed); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "qpeer_not_allow_data = %u", +- htt_stats_buf->qpeer_not_allow_data); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "fse_tid_override = %u", +- htt_stats_buf->fse_tid_override); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "ipv6_jumbogram_zero_length = %u", +- htt_stats_buf->ipv6_jumbogram_zero_length); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "qos_to_non_qos_in_prog = %u\n", +- htt_stats_buf->qos_to_non_qos_in_prog); ++ len += scnprintf(buf + len, buf_len - len, ++ "HTT_TX_DE_CLASSIFY_FAILED_STATS_TLV:\n"); ++ len += scnprintf(buf + len, buf_len - len, "ap_bss_peer_not_found = %u\n", ++ htt_stats_buf->ap_bss_peer_not_found); ++ len += scnprintf(buf + len, buf_len - len, "ap_bcast_mcast_no_peer = %u\n", ++ htt_stats_buf->ap_bcast_mcast_no_peer); ++ len += scnprintf(buf + len, buf_len - len, "sta_delete_in_progress = %u\n", ++ htt_stats_buf->sta_delete_in_progress); ++ len += scnprintf(buf + len, buf_len - len, "ibss_no_bss_peer = %u\n", ++ htt_stats_buf->ibss_no_bss_peer); ++ len += scnprintf(buf + len, buf_len - len, "invalid_vdev_type = %u\n", ++ htt_stats_buf->invalid_vdev_type); ++ len += scnprintf(buf + len, buf_len - len, "invalid_ast_peer_entry = %u\n", ++ htt_stats_buf->invalid_ast_peer_entry); ++ len += scnprintf(buf + len, buf_len - len, "peer_entry_invalid = %u\n", ++ htt_stats_buf->peer_entry_invalid); ++ len += scnprintf(buf + len, buf_len - len, "ethertype_not_ip = %u\n", ++ htt_stats_buf->ethertype_not_ip); ++ len += scnprintf(buf + len, buf_len - len, "eapol_lookup_failed = %u\n", ++ htt_stats_buf->eapol_lookup_failed); ++ len += scnprintf(buf + len, buf_len - len, "qpeer_not_allow_data = %u\n", ++ htt_stats_buf->qpeer_not_allow_data); ++ len += scnprintf(buf + len, buf_len - len, "fse_tid_override = %u\n", ++ htt_stats_buf->fse_tid_override); ++ len += scnprintf(buf + len, buf_len - len, "ipv6_jumbogram_zero_length = %u\n", ++ htt_stats_buf->ipv6_jumbogram_zero_length); ++ len += scnprintf(buf + len, buf_len - len, "qos_to_non_qos_in_prog = %u\n\n", ++ htt_stats_buf->qos_to_non_qos_in_prog); + + if (len >= buf_len) + buf[buf_len - 1] = 0; +@@ -2330,73 +2326,73 @@ htt_print_tx_de_classify_stats_tlv(const + u32 len = stats_req->buf_len; + u32 buf_len = ATH11K_HTT_STATS_BUF_SIZE; + +- len += HTT_DBG_OUT(buf + len, buf_len - len, "HTT_TX_DE_CLASSIFY_STATS_TLV:"); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "arp_packets = %u", +- htt_stats_buf->arp_packets); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "igmp_packets = %u", +- htt_stats_buf->igmp_packets); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "dhcp_packets = %u", +- htt_stats_buf->dhcp_packets); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "host_inspected = %u", +- htt_stats_buf->host_inspected); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "htt_included = %u", +- htt_stats_buf->htt_included); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "htt_valid_mcs = %u", +- htt_stats_buf->htt_valid_mcs); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "htt_valid_nss = %u", +- htt_stats_buf->htt_valid_nss); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "htt_valid_preamble_type = %u", +- htt_stats_buf->htt_valid_preamble_type); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "htt_valid_chainmask = %u", +- htt_stats_buf->htt_valid_chainmask); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "htt_valid_guard_interval = %u", +- htt_stats_buf->htt_valid_guard_interval); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "htt_valid_retries = %u", +- htt_stats_buf->htt_valid_retries); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "htt_valid_bw_info = %u", +- htt_stats_buf->htt_valid_bw_info); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "htt_valid_power = %u", +- htt_stats_buf->htt_valid_power); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "htt_valid_key_flags = 0x%x", +- htt_stats_buf->htt_valid_key_flags); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "htt_valid_no_encryption = %u", +- htt_stats_buf->htt_valid_no_encryption); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "fse_entry_count = %u", +- htt_stats_buf->fse_entry_count); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "fse_priority_be = %u", +- htt_stats_buf->fse_priority_be); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "fse_priority_high = %u", +- htt_stats_buf->fse_priority_high); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "fse_priority_low = %u", +- htt_stats_buf->fse_priority_low); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "fse_traffic_ptrn_be = %u", +- htt_stats_buf->fse_traffic_ptrn_be); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "fse_traffic_ptrn_over_sub = %u", +- htt_stats_buf->fse_traffic_ptrn_over_sub); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "fse_traffic_ptrn_bursty = %u", +- htt_stats_buf->fse_traffic_ptrn_bursty); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "fse_traffic_ptrn_interactive = %u", +- htt_stats_buf->fse_traffic_ptrn_interactive); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "fse_traffic_ptrn_periodic = %u", +- htt_stats_buf->fse_traffic_ptrn_periodic); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "fse_hwqueue_alloc = %u", +- htt_stats_buf->fse_hwqueue_alloc); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "fse_hwqueue_created = %u", +- htt_stats_buf->fse_hwqueue_created); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "fse_hwqueue_send_to_host = %u", +- htt_stats_buf->fse_hwqueue_send_to_host); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "mcast_entry = %u", +- htt_stats_buf->mcast_entry); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "bcast_entry = %u", +- htt_stats_buf->bcast_entry); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "htt_update_peer_cache = %u", +- htt_stats_buf->htt_update_peer_cache); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "htt_learning_frame = %u", +- htt_stats_buf->htt_learning_frame); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "fse_invalid_peer = %u", +- htt_stats_buf->fse_invalid_peer); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "mec_notify = %u\n", +- htt_stats_buf->mec_notify); ++ len += scnprintf(buf + len, buf_len - len, "HTT_TX_DE_CLASSIFY_STATS_TLV:\n"); ++ len += scnprintf(buf + len, buf_len - len, "arp_packets = %u\n", ++ htt_stats_buf->arp_packets); ++ len += scnprintf(buf + len, buf_len - len, "igmp_packets = %u\n", ++ htt_stats_buf->igmp_packets); ++ len += scnprintf(buf + len, buf_len - len, "dhcp_packets = %u\n", ++ htt_stats_buf->dhcp_packets); ++ len += scnprintf(buf + len, buf_len - len, "host_inspected = %u\n", ++ htt_stats_buf->host_inspected); ++ len += scnprintf(buf + len, buf_len - len, "htt_included = %u\n", ++ htt_stats_buf->htt_included); ++ len += scnprintf(buf + len, buf_len - len, "htt_valid_mcs = %u\n", ++ htt_stats_buf->htt_valid_mcs); ++ len += scnprintf(buf + len, buf_len - len, "htt_valid_nss = %u\n", ++ htt_stats_buf->htt_valid_nss); ++ len += scnprintf(buf + len, buf_len - len, "htt_valid_preamble_type = %u\n", ++ htt_stats_buf->htt_valid_preamble_type); ++ len += scnprintf(buf + len, buf_len - len, "htt_valid_chainmask = %u\n", ++ htt_stats_buf->htt_valid_chainmask); ++ len += scnprintf(buf + len, buf_len - len, "htt_valid_guard_interval = %u\n", ++ htt_stats_buf->htt_valid_guard_interval); ++ len += scnprintf(buf + len, buf_len - len, "htt_valid_retries = %u\n", ++ htt_stats_buf->htt_valid_retries); ++ len += scnprintf(buf + len, buf_len - len, "htt_valid_bw_info = %u\n", ++ htt_stats_buf->htt_valid_bw_info); ++ len += scnprintf(buf + len, buf_len - len, "htt_valid_power = %u\n", ++ htt_stats_buf->htt_valid_power); ++ len += scnprintf(buf + len, buf_len - len, "htt_valid_key_flags = 0x%x\n", ++ htt_stats_buf->htt_valid_key_flags); ++ len += scnprintf(buf + len, buf_len - len, "htt_valid_no_encryption = %u\n", ++ htt_stats_buf->htt_valid_no_encryption); ++ len += scnprintf(buf + len, buf_len - len, "fse_entry_count = %u\n", ++ htt_stats_buf->fse_entry_count); ++ len += scnprintf(buf + len, buf_len - len, "fse_priority_be = %u\n", ++ htt_stats_buf->fse_priority_be); ++ len += scnprintf(buf + len, buf_len - len, "fse_priority_high = %u\n", ++ htt_stats_buf->fse_priority_high); ++ len += scnprintf(buf + len, buf_len - len, "fse_priority_low = %u\n", ++ htt_stats_buf->fse_priority_low); ++ len += scnprintf(buf + len, buf_len - len, "fse_traffic_ptrn_be = %u\n", ++ htt_stats_buf->fse_traffic_ptrn_be); ++ len += scnprintf(buf + len, buf_len - len, "fse_traffic_ptrn_over_sub = %u\n", ++ htt_stats_buf->fse_traffic_ptrn_over_sub); ++ len += scnprintf(buf + len, buf_len - len, "fse_traffic_ptrn_bursty = %u\n", ++ htt_stats_buf->fse_traffic_ptrn_bursty); ++ len += scnprintf(buf + len, buf_len - len, "fse_traffic_ptrn_interactive = %u\n", ++ htt_stats_buf->fse_traffic_ptrn_interactive); ++ len += scnprintf(buf + len, buf_len - len, "fse_traffic_ptrn_periodic = %u\n", ++ htt_stats_buf->fse_traffic_ptrn_periodic); ++ len += scnprintf(buf + len, buf_len - len, "fse_hwqueue_alloc = %u\n", ++ htt_stats_buf->fse_hwqueue_alloc); ++ len += scnprintf(buf + len, buf_len - len, "fse_hwqueue_created = %u\n", ++ htt_stats_buf->fse_hwqueue_created); ++ len += scnprintf(buf + len, buf_len - len, "fse_hwqueue_send_to_host = %u\n", ++ htt_stats_buf->fse_hwqueue_send_to_host); ++ len += scnprintf(buf + len, buf_len - len, "mcast_entry = %u\n", ++ htt_stats_buf->mcast_entry); ++ len += scnprintf(buf + len, buf_len - len, "bcast_entry = %u\n", ++ htt_stats_buf->bcast_entry); ++ len += scnprintf(buf + len, buf_len - len, "htt_update_peer_cache = %u\n", ++ htt_stats_buf->htt_update_peer_cache); ++ len += scnprintf(buf + len, buf_len - len, "htt_learning_frame = %u\n", ++ htt_stats_buf->htt_learning_frame); ++ len += scnprintf(buf + len, buf_len - len, "fse_invalid_peer = %u\n", ++ htt_stats_buf->fse_invalid_peer); ++ len += scnprintf(buf + len, buf_len - len, "mec_notify = %u\n\n", ++ htt_stats_buf->mec_notify); + + if (len >= buf_len) + buf[buf_len - 1] = 0; +@@ -2415,24 +2411,24 @@ htt_print_tx_de_classify_status_stats_tl + u32 len = stats_req->buf_len; + u32 buf_len = ATH11K_HTT_STATS_BUF_SIZE; + +- len += HTT_DBG_OUT(buf + len, buf_len - len, +- "HTT_TX_DE_CLASSIFY_STATUS_STATS_TLV:"); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "eok = %u", +- htt_stats_buf->eok); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "classify_done = %u", +- htt_stats_buf->classify_done); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "lookup_failed = %u", +- htt_stats_buf->lookup_failed); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "send_host_dhcp = %u", +- htt_stats_buf->send_host_dhcp); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "send_host_mcast = %u", +- htt_stats_buf->send_host_mcast); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "send_host_unknown_dest = %u", +- htt_stats_buf->send_host_unknown_dest); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "send_host = %u", +- htt_stats_buf->send_host); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "status_invalid = %u\n", +- htt_stats_buf->status_invalid); ++ len += scnprintf(buf + len, buf_len - len, ++ "HTT_TX_DE_CLASSIFY_STATUS_STATS_TLV:\n"); ++ len += scnprintf(buf + len, buf_len - len, "eok = %u\n", ++ htt_stats_buf->eok); ++ len += scnprintf(buf + len, buf_len - len, "classify_done = %u\n", ++ htt_stats_buf->classify_done); ++ len += scnprintf(buf + len, buf_len - len, "lookup_failed = %u\n", ++ htt_stats_buf->lookup_failed); ++ len += scnprintf(buf + len, buf_len - len, "send_host_dhcp = %u\n", ++ htt_stats_buf->send_host_dhcp); ++ len += scnprintf(buf + len, buf_len - len, "send_host_mcast = %u\n", ++ htt_stats_buf->send_host_mcast); ++ len += scnprintf(buf + len, buf_len - len, "send_host_unknown_dest = %u\n", ++ htt_stats_buf->send_host_unknown_dest); ++ len += scnprintf(buf + len, buf_len - len, "send_host = %u\n", ++ htt_stats_buf->send_host); ++ len += scnprintf(buf + len, buf_len - len, "status_invalid = %u\n\n", ++ htt_stats_buf->status_invalid); + + if (len >= buf_len) + buf[buf_len - 1] = 0; +@@ -2451,14 +2447,14 @@ htt_print_tx_de_enqueue_packets_stats_tl + u32 len = stats_req->buf_len; + u32 buf_len = ATH11K_HTT_STATS_BUF_SIZE; + +- len += HTT_DBG_OUT(buf + len, buf_len - len, +- "HTT_TX_DE_ENQUEUE_PACKETS_STATS_TLV:"); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "enqueued_pkts = %u", +- htt_stats_buf->enqueued_pkts); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "to_tqm = %u", +- htt_stats_buf->to_tqm); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "to_tqm_bypass = %u\n", +- htt_stats_buf->to_tqm_bypass); ++ len += scnprintf(buf + len, buf_len - len, ++ "HTT_TX_DE_ENQUEUE_PACKETS_STATS_TLV:\n"); ++ len += scnprintf(buf + len, buf_len - len, "enqueued_pkts = %u\n", ++ htt_stats_buf->enqueued_pkts); ++ len += scnprintf(buf + len, buf_len - len, "to_tqm = %u\n", ++ htt_stats_buf->to_tqm); ++ len += scnprintf(buf + len, buf_len - len, "to_tqm_bypass = %u\n\n", ++ htt_stats_buf->to_tqm_bypass); + + if (len >= buf_len) + buf[buf_len - 1] = 0; +@@ -2477,14 +2473,14 @@ htt_print_tx_de_enqueue_discard_stats_tl + u32 len = stats_req->buf_len; + u32 buf_len = ATH11K_HTT_STATS_BUF_SIZE; + +- len += HTT_DBG_OUT(buf + len, buf_len - len, +- "HTT_TX_DE_ENQUEUE_DISCARD_STATS_TLV:"); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "discarded_pkts = %u", +- htt_stats_buf->discarded_pkts); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "local_frames = %u", +- htt_stats_buf->local_frames); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "is_ext_msdu = %u\n", +- htt_stats_buf->is_ext_msdu); ++ len += scnprintf(buf + len, buf_len - len, ++ "HTT_TX_DE_ENQUEUE_DISCARD_STATS_TLV:\n"); ++ len += scnprintf(buf + len, buf_len - len, "discarded_pkts = %u\n", ++ htt_stats_buf->discarded_pkts); ++ len += scnprintf(buf + len, buf_len - len, "local_frames = %u\n", ++ htt_stats_buf->local_frames); ++ len += scnprintf(buf + len, buf_len - len, "is_ext_msdu = %u\n\n", ++ htt_stats_buf->is_ext_msdu); + + if (len >= buf_len) + buf[buf_len - 1] = 0; +@@ -2502,17 +2498,17 @@ static inline void htt_print_tx_de_compl + u32 len = stats_req->buf_len; + u32 buf_len = ATH11K_HTT_STATS_BUF_SIZE; + +- len += HTT_DBG_OUT(buf + len, buf_len - len, "HTT_TX_DE_COMPL_STATS_TLV:"); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "tcl_dummy_frame = %u", +- htt_stats_buf->tcl_dummy_frame); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "tqm_dummy_frame = %u", +- htt_stats_buf->tqm_dummy_frame); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "tqm_notify_frame = %u", +- htt_stats_buf->tqm_notify_frame); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "fw2wbm_enq = %u", +- htt_stats_buf->fw2wbm_enq); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "tqm_bypass_frame = %u\n", +- htt_stats_buf->tqm_bypass_frame); ++ len += scnprintf(buf + len, buf_len - len, "HTT_TX_DE_COMPL_STATS_TLV:\n"); ++ len += scnprintf(buf + len, buf_len - len, "tcl_dummy_frame = %u\n", ++ htt_stats_buf->tcl_dummy_frame); ++ len += scnprintf(buf + len, buf_len - len, "tqm_dummy_frame = %u\n", ++ htt_stats_buf->tqm_dummy_frame); ++ len += scnprintf(buf + len, buf_len - len, "tqm_notify_frame = %u\n", ++ htt_stats_buf->tqm_notify_frame); ++ len += scnprintf(buf + len, buf_len - len, "fw2wbm_enq = %u\n", ++ htt_stats_buf->fw2wbm_enq); ++ len += scnprintf(buf + len, buf_len - len, "tqm_bypass_frame = %u\n\n", ++ htt_stats_buf->tqm_bypass_frame); + + if (len >= buf_len) + buf[buf_len - 1] = 0; +@@ -2535,19 +2531,19 @@ htt_print_tx_de_fw2wbm_ring_full_hist_tl + u16 num_elements = tag_len >> 2; + u32 required_buffer_size = HTT_MAX_PRINT_CHAR_PER_ELEM * num_elements; + +- len += HTT_DBG_OUT(buf + len, buf_len - len, +- "HTT_TX_DE_FW2WBM_RING_FULL_HIST_TLV"); ++ len += scnprintf(buf + len, buf_len - len, ++ "HTT_TX_DE_FW2WBM_RING_FULL_HIST_TLV"); + + if (required_buffer_size < HTT_MAX_STRING_LEN) { + PRINT_ARRAY_TO_BUF(fw2wbm_ring_full_hist, + htt_stats_buf->fw2wbm_ring_full_hist, + num_elements); +- len += HTT_DBG_OUT(buf + len, buf_len - len, +- "fw2wbm_ring_full_hist = %s\n", +- fw2wbm_ring_full_hist); ++ len += scnprintf(buf + len, buf_len - len, ++ "fw2wbm_ring_full_hist = %s\n\n", ++ fw2wbm_ring_full_hist); + } else { +- len += HTT_DBG_OUT(buf + len, buf_len - len, +- "INSUFFICIENT PRINT BUFFER "); ++ len += scnprintf(buf + len, buf_len - len, ++ "INSUFFICIENT PRINT BUFFER\n"); + } + + if (len >= buf_len) +@@ -2566,21 +2562,21 @@ htt_print_tx_de_cmn_stats_tlv(const void + u32 len = stats_req->buf_len; + u32 buf_len = ATH11K_HTT_STATS_BUF_SIZE; + +- len += HTT_DBG_OUT(buf + len, buf_len - len, "HTT_TX_DE_CMN_STATS_TLV:"); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "mac_id = %u", +- htt_stats_buf->mac_id__word & 0xFF); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "tcl2fw_entry_count = %u", +- htt_stats_buf->tcl2fw_entry_count); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "not_to_fw = %u", +- htt_stats_buf->not_to_fw); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "invalid_pdev_vdev_peer = %u", +- htt_stats_buf->invalid_pdev_vdev_peer); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "tcl_res_invalid_addrx = %u", +- htt_stats_buf->tcl_res_invalid_addrx); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "wbm2fw_entry_count = %u", +- htt_stats_buf->wbm2fw_entry_count); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "invalid_pdev = %u\n", +- htt_stats_buf->invalid_pdev); ++ len += scnprintf(buf + len, buf_len - len, "HTT_TX_DE_CMN_STATS_TLV:\n"); ++ len += scnprintf(buf + len, buf_len - len, "mac_id = %u\n", ++ htt_stats_buf->mac_id__word & 0xFF); ++ len += scnprintf(buf + len, buf_len - len, "tcl2fw_entry_count = %u\n", ++ htt_stats_buf->tcl2fw_entry_count); ++ len += scnprintf(buf + len, buf_len - len, "not_to_fw = %u\n", ++ htt_stats_buf->not_to_fw); ++ len += scnprintf(buf + len, buf_len - len, "invalid_pdev_vdev_peer = %u\n", ++ htt_stats_buf->invalid_pdev_vdev_peer); ++ len += scnprintf(buf + len, buf_len - len, "tcl_res_invalid_addrx = %u\n", ++ htt_stats_buf->tcl_res_invalid_addrx); ++ len += scnprintf(buf + len, buf_len - len, "wbm2fw_entry_count = %u\n", ++ htt_stats_buf->wbm2fw_entry_count); ++ len += scnprintf(buf + len, buf_len - len, "invalid_pdev = %u\n\n", ++ htt_stats_buf->invalid_pdev); + + if (len >= buf_len) + buf[buf_len - 1] = 0; +@@ -2600,49 +2596,49 @@ static inline void htt_print_ring_if_sta + char low_wm_hit_count[HTT_MAX_STRING_LEN] = {0}; + char high_wm_hit_count[HTT_MAX_STRING_LEN] = {0}; + +- len += HTT_DBG_OUT(buf + len, buf_len - len, "HTT_RING_IF_STATS_TLV:"); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "base_addr = %u", +- htt_stats_buf->base_addr); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "elem_size = %u", +- htt_stats_buf->elem_size); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "num_elems = %u", +- htt_stats_buf->num_elems__prefetch_tail_idx & 0xFFFF); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "prefetch_tail_idx = %u", +- (htt_stats_buf->num_elems__prefetch_tail_idx & +- 0xFFFF0000) >> 16); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "head_idx = %u", +- htt_stats_buf->head_idx__tail_idx & 0xFFFF); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "tail_idx = %u", +- (htt_stats_buf->head_idx__tail_idx & 0xFFFF0000) >> 16); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "shadow_head_idx = %u", +- htt_stats_buf->shadow_head_idx__shadow_tail_idx & 0xFFFF); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "shadow_tail_idx = %u", +- (htt_stats_buf->shadow_head_idx__shadow_tail_idx & +- 0xFFFF0000) >> 16); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "num_tail_incr = %u", +- htt_stats_buf->num_tail_incr); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "lwm_thresh = %u", +- htt_stats_buf->lwm_thresh__hwm_thresh & 0xFFFF); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "hwm_thresh = %u", +- (htt_stats_buf->lwm_thresh__hwm_thresh & 0xFFFF0000) >> 16); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "overrun_hit_count = %u", +- htt_stats_buf->overrun_hit_count); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "underrun_hit_count = %u", +- htt_stats_buf->underrun_hit_count); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "prod_blockwait_count = %u", +- htt_stats_buf->prod_blockwait_count); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "cons_blockwait_count = %u", +- htt_stats_buf->cons_blockwait_count); ++ len += scnprintf(buf + len, buf_len - len, "HTT_RING_IF_STATS_TLV:\n"); ++ len += scnprintf(buf + len, buf_len - len, "base_addr = %u\n", ++ htt_stats_buf->base_addr); ++ len += scnprintf(buf + len, buf_len - len, "elem_size = %u\n", ++ htt_stats_buf->elem_size); ++ len += scnprintf(buf + len, buf_len - len, "num_elems = %u\n", ++ htt_stats_buf->num_elems__prefetch_tail_idx & 0xFFFF); ++ len += scnprintf(buf + len, buf_len - len, "prefetch_tail_idx = %u\n", ++ (htt_stats_buf->num_elems__prefetch_tail_idx & ++ 0xFFFF0000) >> 16); ++ len += scnprintf(buf + len, buf_len - len, "head_idx = %u\n", ++ htt_stats_buf->head_idx__tail_idx & 0xFFFF); ++ len += scnprintf(buf + len, buf_len - len, "tail_idx = %u\n", ++ (htt_stats_buf->head_idx__tail_idx & 0xFFFF0000) >> 16); ++ len += scnprintf(buf + len, buf_len - len, "shadow_head_idx = %u\n", ++ htt_stats_buf->shadow_head_idx__shadow_tail_idx & 0xFFFF); ++ len += scnprintf(buf + len, buf_len - len, "shadow_tail_idx = %u\n", ++ (htt_stats_buf->shadow_head_idx__shadow_tail_idx & ++ 0xFFFF0000) >> 16); ++ len += scnprintf(buf + len, buf_len - len, "num_tail_incr = %u\n", ++ htt_stats_buf->num_tail_incr); ++ len += scnprintf(buf + len, buf_len - len, "lwm_thresh = %u\n", ++ htt_stats_buf->lwm_thresh__hwm_thresh & 0xFFFF); ++ len += scnprintf(buf + len, buf_len - len, "hwm_thresh = %u\n", ++ (htt_stats_buf->lwm_thresh__hwm_thresh & 0xFFFF0000) >> 16); ++ len += scnprintf(buf + len, buf_len - len, "overrun_hit_count = %u\n", ++ htt_stats_buf->overrun_hit_count); ++ len += scnprintf(buf + len, buf_len - len, "underrun_hit_count = %u\n", ++ htt_stats_buf->underrun_hit_count); ++ len += scnprintf(buf + len, buf_len - len, "prod_blockwait_count = %u\n", ++ htt_stats_buf->prod_blockwait_count); ++ len += scnprintf(buf + len, buf_len - len, "cons_blockwait_count = %u\n", ++ htt_stats_buf->cons_blockwait_count); + + PRINT_ARRAY_TO_BUF(low_wm_hit_count, htt_stats_buf->low_wm_hit_count, + HTT_STATS_LOW_WM_BINS); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "low_wm_hit_count = %s ", +- low_wm_hit_count); ++ len += scnprintf(buf + len, buf_len - len, "low_wm_hit_count = %s\n", ++ low_wm_hit_count); + + PRINT_ARRAY_TO_BUF(high_wm_hit_count, htt_stats_buf->high_wm_hit_count, + HTT_STATS_HIGH_WM_BINS); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "high_wm_hit_count = %s\n", +- high_wm_hit_count); ++ len += scnprintf(buf + len, buf_len - len, "high_wm_hit_count = %s\n\n", ++ high_wm_hit_count); + + if (len >= buf_len) + buf[buf_len - 1] = 0; +@@ -2660,11 +2656,11 @@ static inline void htt_print_ring_if_cmn + u32 len = stats_req->buf_len; + u32 buf_len = ATH11K_HTT_STATS_BUF_SIZE; + +- len += HTT_DBG_OUT(buf + len, buf_len - len, "HTT_RING_IF_CMN_TLV:"); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "mac_id = %u", +- htt_stats_buf->mac_id__word & 0xFF); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "num_records = %u\n", +- htt_stats_buf->num_records); ++ len += scnprintf(buf + len, buf_len - len, "HTT_RING_IF_CMN_TLV:\n"); ++ len += scnprintf(buf + len, buf_len - len, "mac_id = %u\n", ++ htt_stats_buf->mac_id__word & 0xFF); ++ len += scnprintf(buf + len, buf_len - len, "num_records = %u\n\n", ++ htt_stats_buf->num_records); + + if (len >= buf_len) + buf[buf_len - 1] = 0; +@@ -2685,13 +2681,13 @@ static inline void htt_print_sfm_client_ + char dwords_used_by_user_n[HTT_MAX_STRING_LEN] = {0}; + u16 num_elems = tag_len >> 2; + +- len += HTT_DBG_OUT(buf + len, buf_len - len, "HTT_SFM_CLIENT_USER_TLV_V:"); ++ len += scnprintf(buf + len, buf_len - len, "HTT_SFM_CLIENT_USER_TLV_V:\n"); + + PRINT_ARRAY_TO_BUF(dwords_used_by_user_n, + htt_stats_buf->dwords_used_by_user_n, + num_elems); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "dwords_used_by_user_n = %s\n", +- dwords_used_by_user_n); ++ len += scnprintf(buf + len, buf_len - len, "dwords_used_by_user_n = %s\n\n", ++ dwords_used_by_user_n); + + if (len >= buf_len) + buf[buf_len - 1] = 0; +@@ -2709,21 +2705,21 @@ static inline void htt_print_sfm_client_ + u32 len = stats_req->buf_len; + u32 buf_len = ATH11K_HTT_STATS_BUF_SIZE; + +- len += HTT_DBG_OUT(buf + len, buf_len - len, "HTT_SFM_CLIENT_TLV:"); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "client_id = %u", +- htt_stats_buf->client_id); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "buf_min = %u", +- htt_stats_buf->buf_min); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "buf_max = %u", +- htt_stats_buf->buf_max); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "buf_busy = %u", +- htt_stats_buf->buf_busy); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "buf_alloc = %u", +- htt_stats_buf->buf_alloc); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "buf_avail = %u", +- htt_stats_buf->buf_avail); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "num_users = %u\n", +- htt_stats_buf->num_users); ++ len += scnprintf(buf + len, buf_len - len, "HTT_SFM_CLIENT_TLV:\n"); ++ len += scnprintf(buf + len, buf_len - len, "client_id = %u\n", ++ htt_stats_buf->client_id); ++ len += scnprintf(buf + len, buf_len - len, "buf_min = %u\n", ++ htt_stats_buf->buf_min); ++ len += scnprintf(buf + len, buf_len - len, "buf_max = %u\n", ++ htt_stats_buf->buf_max); ++ len += scnprintf(buf + len, buf_len - len, "buf_busy = %u\n", ++ htt_stats_buf->buf_busy); ++ len += scnprintf(buf + len, buf_len - len, "buf_alloc = %u\n", ++ htt_stats_buf->buf_alloc); ++ len += scnprintf(buf + len, buf_len - len, "buf_avail = %u\n", ++ htt_stats_buf->buf_avail); ++ len += scnprintf(buf + len, buf_len - len, "num_users = %u\n\n", ++ htt_stats_buf->num_users); + + if (len >= buf_len) + buf[buf_len - 1] = 0; +@@ -2741,17 +2737,17 @@ static inline void htt_print_sfm_cmn_tlv + u32 len = stats_req->buf_len; + u32 buf_len = ATH11K_HTT_STATS_BUF_SIZE; + +- len += HTT_DBG_OUT(buf + len, buf_len - len, "HTT_SFM_CMN_TLV:"); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "mac_id = %u", +- htt_stats_buf->mac_id__word & 0xFF); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "buf_total = %u", +- htt_stats_buf->buf_total); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "mem_empty = %u", +- htt_stats_buf->mem_empty); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "deallocate_bufs = %u", +- htt_stats_buf->deallocate_bufs); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "num_records = %u\n", +- htt_stats_buf->num_records); ++ len += scnprintf(buf + len, buf_len - len, "HTT_SFM_CMN_TLV:\n"); ++ len += scnprintf(buf + len, buf_len - len, "mac_id = %u\n", ++ htt_stats_buf->mac_id__word & 0xFF); ++ len += scnprintf(buf + len, buf_len - len, "buf_total = %u\n", ++ htt_stats_buf->buf_total); ++ len += scnprintf(buf + len, buf_len - len, "mem_empty = %u\n", ++ htt_stats_buf->mem_empty); ++ len += scnprintf(buf + len, buf_len - len, "deallocate_bufs = %u\n", ++ htt_stats_buf->deallocate_bufs); ++ len += scnprintf(buf + len, buf_len - len, "num_records = %u\n\n", ++ htt_stats_buf->num_records); + + if (len >= buf_len) + buf[buf_len - 1] = 0; +@@ -2769,42 +2765,42 @@ static inline void htt_print_sring_stats + u32 len = stats_req->buf_len; + u32 buf_len = ATH11K_HTT_STATS_BUF_SIZE; + +- len += HTT_DBG_OUT(buf + len, buf_len - len, "HTT_SRING_STATS_TLV:"); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "mac_id = %u", +- htt_stats_buf->mac_id__ring_id__arena__ep & 0xFF); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "ring_id = %u", +- (htt_stats_buf->mac_id__ring_id__arena__ep & 0xFF00) >> 8); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "arena = %u", +- (htt_stats_buf->mac_id__ring_id__arena__ep & 0xFF0000) >> 16); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "ep = %u", +- (htt_stats_buf->mac_id__ring_id__arena__ep & 0x1000000) >> 24); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "base_addr_lsb = 0x%x", +- htt_stats_buf->base_addr_lsb); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "base_addr_msb = 0x%x", +- htt_stats_buf->base_addr_msb); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "ring_size = %u", +- htt_stats_buf->ring_size); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "elem_size = %u", +- htt_stats_buf->elem_size); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "num_avail_words = %u", +- htt_stats_buf->num_avail_words__num_valid_words & 0xFFFF); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "num_valid_words = %u", +- (htt_stats_buf->num_avail_words__num_valid_words & +- 0xFFFF0000) >> 16); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "head_ptr = %u", +- htt_stats_buf->head_ptr__tail_ptr & 0xFFFF); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "tail_ptr = %u", +- (htt_stats_buf->head_ptr__tail_ptr & 0xFFFF0000) >> 16); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "consumer_empty = %u", +- htt_stats_buf->consumer_empty__producer_full & 0xFFFF); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "producer_full = %u", +- (htt_stats_buf->consumer_empty__producer_full & +- 0xFFFF0000) >> 16); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "prefetch_count = %u", +- htt_stats_buf->prefetch_count__internal_tail_ptr & 0xFFFF); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "internal_tail_ptr = %u\n", +- (htt_stats_buf->prefetch_count__internal_tail_ptr & +- 0xFFFF0000) >> 16); ++ len += scnprintf(buf + len, buf_len - len, "HTT_SRING_STATS_TLV:\n"); ++ len += scnprintf(buf + len, buf_len - len, "mac_id = %u\n", ++ htt_stats_buf->mac_id__ring_id__arena__ep & 0xFF); ++ len += scnprintf(buf + len, buf_len - len, "ring_id = %u\n", ++ (htt_stats_buf->mac_id__ring_id__arena__ep & 0xFF00) >> 8); ++ len += scnprintf(buf + len, buf_len - len, "arena = %u\n", ++ (htt_stats_buf->mac_id__ring_id__arena__ep & 0xFF0000) >> 16); ++ len += scnprintf(buf + len, buf_len - len, "ep = %u\n", ++ (htt_stats_buf->mac_id__ring_id__arena__ep & 0x1000000) >> 24); ++ len += scnprintf(buf + len, buf_len - len, "base_addr_lsb = 0x%x\n", ++ htt_stats_buf->base_addr_lsb); ++ len += scnprintf(buf + len, buf_len - len, "base_addr_msb = 0x%x\n", ++ htt_stats_buf->base_addr_msb); ++ len += scnprintf(buf + len, buf_len - len, "ring_size = %u\n", ++ htt_stats_buf->ring_size); ++ len += scnprintf(buf + len, buf_len - len, "elem_size = %u\n", ++ htt_stats_buf->elem_size); ++ len += scnprintf(buf + len, buf_len - len, "num_avail_words = %u\n", ++ htt_stats_buf->num_avail_words__num_valid_words & 0xFFFF); ++ len += scnprintf(buf + len, buf_len - len, "num_valid_words = %u\n", ++ (htt_stats_buf->num_avail_words__num_valid_words & ++ 0xFFFF0000) >> 16); ++ len += scnprintf(buf + len, buf_len - len, "head_ptr = %u\n", ++ htt_stats_buf->head_ptr__tail_ptr & 0xFFFF); ++ len += scnprintf(buf + len, buf_len - len, "tail_ptr = %u\n", ++ (htt_stats_buf->head_ptr__tail_ptr & 0xFFFF0000) >> 16); ++ len += scnprintf(buf + len, buf_len - len, "consumer_empty = %u\n", ++ htt_stats_buf->consumer_empty__producer_full & 0xFFFF); ++ len += scnprintf(buf + len, buf_len - len, "producer_full = %u\n", ++ (htt_stats_buf->consumer_empty__producer_full & ++ 0xFFFF0000) >> 16); ++ len += scnprintf(buf + len, buf_len - len, "prefetch_count = %u\n", ++ htt_stats_buf->prefetch_count__internal_tail_ptr & 0xFFFF); ++ len += scnprintf(buf + len, buf_len - len, "internal_tail_ptr = %u\n\n", ++ (htt_stats_buf->prefetch_count__internal_tail_ptr & ++ 0xFFFF0000) >> 16); + + if (len >= buf_len) + buf[buf_len - 1] = 0; +@@ -2822,9 +2818,9 @@ static inline void htt_print_sring_cmn_t + u32 len = stats_req->buf_len; + u32 buf_len = ATH11K_HTT_STATS_BUF_SIZE; + +- len += HTT_DBG_OUT(buf + len, buf_len - len, "HTT_SRING_CMN_TLV:"); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "num_records = %u\n", +- htt_stats_buf->num_records); ++ len += scnprintf(buf + len, buf_len - len, "HTT_SRING_CMN_TLV:\n"); ++ len += scnprintf(buf + len, buf_len - len, "num_records = %u\n\n", ++ htt_stats_buf->num_records); + + if (len >= buf_len) + buf[buf_len - 1] = 0; +@@ -2851,156 +2847,156 @@ static inline void htt_print_tx_pdev_rat + goto fail; + } + +- len += HTT_DBG_OUT(buf + len, buf_len - len, "HTT_TX_PDEV_RATE_STATS_TLV:"); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "mac_id = %u", +- htt_stats_buf->mac_id__word & 0xFF); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "tx_ldpc = %u", +- htt_stats_buf->tx_ldpc); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "ac_mu_mimo_tx_ldpc = %u", +- htt_stats_buf->ac_mu_mimo_tx_ldpc); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "ax_mu_mimo_tx_ldpc = %u", +- htt_stats_buf->ax_mu_mimo_tx_ldpc); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "ofdma_tx_ldpc = %u", +- htt_stats_buf->ofdma_tx_ldpc); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "rts_cnt = %u", +- htt_stats_buf->rts_cnt); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "rts_success = %u", +- htt_stats_buf->rts_success); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "ack_rssi = %u", +- htt_stats_buf->ack_rssi); +- +- len += HTT_DBG_OUT(buf + len, buf_len - len, +- "Legacy CCK Rates: 1 Mbps: %u, 2 Mbps: %u, 5.5 Mbps: %u, 11 Mbps: %u", +- htt_stats_buf->tx_legacy_cck_rate[0], +- htt_stats_buf->tx_legacy_cck_rate[1], +- htt_stats_buf->tx_legacy_cck_rate[2], +- htt_stats_buf->tx_legacy_cck_rate[3]); +- +- len += HTT_DBG_OUT(buf + len, buf_len - len, +- "Legacy OFDM Rates: 6 Mbps: %u, 9 Mbps: %u, 12 Mbps: %u, 18 Mbps: %u\n" +- " 24 Mbps: %u, 36 Mbps: %u, 48 Mbps: %u, 54 Mbps: %u", +- htt_stats_buf->tx_legacy_ofdm_rate[0], +- htt_stats_buf->tx_legacy_ofdm_rate[1], +- htt_stats_buf->tx_legacy_ofdm_rate[2], +- htt_stats_buf->tx_legacy_ofdm_rate[3], +- htt_stats_buf->tx_legacy_ofdm_rate[4], +- htt_stats_buf->tx_legacy_ofdm_rate[5], +- htt_stats_buf->tx_legacy_ofdm_rate[6], +- htt_stats_buf->tx_legacy_ofdm_rate[7]); ++ len += scnprintf(buf + len, buf_len - len, "HTT_TX_PDEV_RATE_STATS_TLV:\n"); ++ len += scnprintf(buf + len, buf_len - len, "mac_id = %u\n", ++ htt_stats_buf->mac_id__word & 0xFF); ++ len += scnprintf(buf + len, buf_len - len, "tx_ldpc = %u\n", ++ htt_stats_buf->tx_ldpc); ++ len += scnprintf(buf + len, buf_len - len, "ac_mu_mimo_tx_ldpc = %u\n", ++ htt_stats_buf->ac_mu_mimo_tx_ldpc); ++ len += scnprintf(buf + len, buf_len - len, "ax_mu_mimo_tx_ldpc = %u\n", ++ htt_stats_buf->ax_mu_mimo_tx_ldpc); ++ len += scnprintf(buf + len, buf_len - len, "ofdma_tx_ldpc = %u\n", ++ htt_stats_buf->ofdma_tx_ldpc); ++ len += scnprintf(buf + len, buf_len - len, "rts_cnt = %u\n", ++ htt_stats_buf->rts_cnt); ++ len += scnprintf(buf + len, buf_len - len, "rts_success = %u\n", ++ htt_stats_buf->rts_success); ++ len += scnprintf(buf + len, buf_len - len, "ack_rssi = %u\n", ++ htt_stats_buf->ack_rssi); ++ ++ len += scnprintf(buf + len, buf_len - len, ++ "Legacy CCK Rates: 1 Mbps: %u, 2 Mbps: %u, 5.5 Mbps: %u, 11 Mbps: %u\n", ++ htt_stats_buf->tx_legacy_cck_rate[0], ++ htt_stats_buf->tx_legacy_cck_rate[1], ++ htt_stats_buf->tx_legacy_cck_rate[2], ++ htt_stats_buf->tx_legacy_cck_rate[3]); ++ ++ len += scnprintf(buf + len, buf_len - len, ++ "Legacy OFDM Rates: 6 Mbps: %u, 9 Mbps: %u, 12 Mbps: %u, 18 Mbps: %u\n" ++ " 24 Mbps: %u, 36 Mbps: %u, 48 Mbps: %u, 54 Mbps: %u\n", ++ htt_stats_buf->tx_legacy_ofdm_rate[0], ++ htt_stats_buf->tx_legacy_ofdm_rate[1], ++ htt_stats_buf->tx_legacy_ofdm_rate[2], ++ htt_stats_buf->tx_legacy_ofdm_rate[3], ++ htt_stats_buf->tx_legacy_ofdm_rate[4], ++ htt_stats_buf->tx_legacy_ofdm_rate[5], ++ htt_stats_buf->tx_legacy_ofdm_rate[6], ++ htt_stats_buf->tx_legacy_ofdm_rate[7]); + + memset(str_buf, 0x0, HTT_MAX_STRING_LEN); + PRINT_ARRAY_TO_BUF(str_buf, htt_stats_buf->tx_mcs, + HTT_TX_PDEV_STATS_NUM_MCS_COUNTERS); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "tx_mcs = %s ", str_buf); ++ len += scnprintf(buf + len, buf_len - len, "tx_mcs = %s\n", str_buf); + + memset(str_buf, 0x0, HTT_MAX_STRING_LEN); + PRINT_ARRAY_TO_BUF(str_buf, htt_stats_buf->ac_mu_mimo_tx_mcs, + HTT_TX_PDEV_STATS_NUM_MCS_COUNTERS); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "ac_mu_mimo_tx_mcs = %s ", str_buf); ++ len += scnprintf(buf + len, buf_len - len, "ac_mu_mimo_tx_mcs = %s\n", str_buf); + + memset(str_buf, 0x0, HTT_MAX_STRING_LEN); + PRINT_ARRAY_TO_BUF(str_buf, htt_stats_buf->ax_mu_mimo_tx_mcs, + HTT_TX_PDEV_STATS_NUM_MCS_COUNTERS); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "ax_mu_mimo_tx_mcs = %s ", str_buf); ++ len += scnprintf(buf + len, buf_len - len, "ax_mu_mimo_tx_mcs = %s\n", str_buf); + + memset(str_buf, 0x0, HTT_MAX_STRING_LEN); + PRINT_ARRAY_TO_BUF(str_buf, htt_stats_buf->ofdma_tx_mcs, + HTT_TX_PDEV_STATS_NUM_MCS_COUNTERS); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "ofdma_tx_mcs = %s ", str_buf); ++ len += scnprintf(buf + len, buf_len - len, "ofdma_tx_mcs = %s\n", str_buf); + + memset(str_buf, 0x0, HTT_MAX_STRING_LEN); + PRINT_ARRAY_TO_BUF(str_buf, htt_stats_buf->tx_nss, + HTT_TX_PDEV_STATS_NUM_SPATIAL_STREAMS); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "tx_nss = %s ", str_buf); ++ len += scnprintf(buf + len, buf_len - len, "tx_nss = %s\n", str_buf); + + memset(str_buf, 0x0, HTT_MAX_STRING_LEN); + PRINT_ARRAY_TO_BUF(str_buf, htt_stats_buf->ac_mu_mimo_tx_nss, + HTT_TX_PDEV_STATS_NUM_SPATIAL_STREAMS); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "ac_mu_mimo_tx_nss = %s ", str_buf); ++ len += scnprintf(buf + len, buf_len - len, "ac_mu_mimo_tx_nss = %s\n", str_buf); + + memset(str_buf, 0x0, HTT_MAX_STRING_LEN); + PRINT_ARRAY_TO_BUF(str_buf, htt_stats_buf->ax_mu_mimo_tx_nss, + HTT_TX_PDEV_STATS_NUM_SPATIAL_STREAMS); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "ax_mu_mimo_tx_nss = %s ", str_buf); ++ len += scnprintf(buf + len, buf_len - len, "ax_mu_mimo_tx_nss = %s\n", str_buf); + + memset(str_buf, 0x0, HTT_MAX_STRING_LEN); + PRINT_ARRAY_TO_BUF(str_buf, htt_stats_buf->ofdma_tx_nss, + HTT_TX_PDEV_STATS_NUM_SPATIAL_STREAMS); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "ofdma_tx_nss = %s ", str_buf); ++ len += scnprintf(buf + len, buf_len - len, "ofdma_tx_nss = %s\n", str_buf); + + memset(str_buf, 0x0, HTT_MAX_STRING_LEN); + PRINT_ARRAY_TO_BUF(str_buf, htt_stats_buf->tx_bw, + HTT_TX_PDEV_STATS_NUM_BW_COUNTERS); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "tx_bw = %s ", str_buf); ++ len += scnprintf(buf + len, buf_len - len, "tx_bw = %s\n", str_buf); + + memset(str_buf, 0x0, HTT_MAX_STRING_LEN); + PRINT_ARRAY_TO_BUF(str_buf, htt_stats_buf->ac_mu_mimo_tx_bw, + HTT_TX_PDEV_STATS_NUM_BW_COUNTERS); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "ac_mu_mimo_tx_bw = %s ", str_buf); ++ len += scnprintf(buf + len, buf_len - len, "ac_mu_mimo_tx_bw = %s\n", str_buf); + + memset(str_buf, 0x0, HTT_MAX_STRING_LEN); + PRINT_ARRAY_TO_BUF(str_buf, htt_stats_buf->ax_mu_mimo_tx_bw, + HTT_TX_PDEV_STATS_NUM_BW_COUNTERS); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "ax_mu_mimo_tx_bw = %s ", str_buf); ++ len += scnprintf(buf + len, buf_len - len, "ax_mu_mimo_tx_bw = %s\n", str_buf); + + memset(str_buf, 0x0, HTT_MAX_STRING_LEN); + PRINT_ARRAY_TO_BUF(str_buf, htt_stats_buf->ofdma_tx_bw, + HTT_TX_PDEV_STATS_NUM_BW_COUNTERS); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "ofdma_tx_bw = %s ", str_buf); ++ len += scnprintf(buf + len, buf_len - len, "ofdma_tx_bw = %s\n", str_buf); + + memset(str_buf, 0x0, HTT_MAX_STRING_LEN); + PRINT_ARRAY_TO_BUF(str_buf, htt_stats_buf->tx_stbc, + HTT_TX_PDEV_STATS_NUM_MCS_COUNTERS); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "tx_stbc = %s ", str_buf); ++ len += scnprintf(buf + len, buf_len - len, "tx_stbc = %s\n", str_buf); + + memset(str_buf, 0x0, HTT_MAX_STRING_LEN); + PRINT_ARRAY_TO_BUF(str_buf, htt_stats_buf->tx_pream, + HTT_TX_PDEV_STATS_NUM_PREAMBLE_TYPES); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "tx_pream = %s ", str_buf); ++ len += scnprintf(buf + len, buf_len - len, "tx_pream = %s\n", str_buf); + +- len += HTT_DBG_OUT(buf + len, buf_len - len, "HE LTF: 1x: %u, 2x: %u, 4x: %u", +- htt_stats_buf->tx_he_ltf[1], +- htt_stats_buf->tx_he_ltf[2], +- htt_stats_buf->tx_he_ltf[3]); ++ len += scnprintf(buf + len, buf_len - len, "HE LTF: 1x: %u, 2x: %u, 4x: %u\n", ++ htt_stats_buf->tx_he_ltf[1], ++ htt_stats_buf->tx_he_ltf[2], ++ htt_stats_buf->tx_he_ltf[3]); + + /* SU GI Stats */ + for (j = 0; j < HTT_TX_PDEV_STATS_NUM_GI_COUNTERS; j++) { + PRINT_ARRAY_TO_BUF(tx_gi[j], htt_stats_buf->tx_gi[j], + HTT_TX_PDEV_STATS_NUM_MCS_COUNTERS); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "tx_gi[%u] = %s ", +- j, tx_gi[j]); ++ len += scnprintf(buf + len, buf_len - len, "tx_gi[%u] = %s\n", ++ j, tx_gi[j]); + } + + /* AC MU-MIMO GI Stats */ + for (j = 0; j < HTT_TX_PDEV_STATS_NUM_GI_COUNTERS; j++) { + PRINT_ARRAY_TO_BUF(tx_gi[j], htt_stats_buf->ac_mu_mimo_tx_gi[j], + HTT_TX_PDEV_STATS_NUM_MCS_COUNTERS); +- len += HTT_DBG_OUT(buf + len, buf_len - len, +- "ac_mu_mimo_tx_gi[%u] = %s ", +- j, tx_gi[j]); ++ len += scnprintf(buf + len, buf_len - len, ++ "ac_mu_mimo_tx_gi[%u] = %s\n", ++ j, tx_gi[j]); + } + + /* AX MU-MIMO GI Stats */ + for (j = 0; j < HTT_TX_PDEV_STATS_NUM_GI_COUNTERS; j++) { + PRINT_ARRAY_TO_BUF(tx_gi[j], htt_stats_buf->ax_mu_mimo_tx_gi[j], + HTT_TX_PDEV_STATS_NUM_MCS_COUNTERS); +- len += HTT_DBG_OUT(buf + len, buf_len - len, +- "ax_mu_mimo_tx_gi[%u] = %s ", +- j, tx_gi[j]); ++ len += scnprintf(buf + len, buf_len - len, ++ "ax_mu_mimo_tx_gi[%u] = %s\n", ++ j, tx_gi[j]); + } + + /* DL OFDMA GI Stats */ + for (j = 0; j < HTT_TX_PDEV_STATS_NUM_GI_COUNTERS; j++) { + PRINT_ARRAY_TO_BUF(tx_gi[j], htt_stats_buf->ofdma_tx_gi[j], + HTT_TX_PDEV_STATS_NUM_MCS_COUNTERS); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "ofdma_tx_gi[%u] = %s ", +- j, tx_gi[j]); ++ len += scnprintf(buf + len, buf_len - len, "ofdma_tx_gi[%u] = %s\n", ++ j, tx_gi[j]); + } + + memset(str_buf, 0x0, HTT_MAX_STRING_LEN); + PRINT_ARRAY_TO_BUF(str_buf, htt_stats_buf->tx_dcm, + HTT_TX_PDEV_STATS_NUM_DCM_COUNTERS); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "tx_dcm = %s\n", str_buf); ++ len += scnprintf(buf + len, buf_len - len, "tx_dcm = %s\n\n", str_buf); + + if (len >= buf_len) + buf[buf_len - 1] = 0; +@@ -3045,202 +3041,202 @@ static inline void htt_print_rx_pdev_rat + goto fail; + } + +- len += HTT_DBG_OUT(buf + len, buf_len - len, "HTT_RX_PDEV_RATE_STATS_TLV:"); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "mac_id = %u", +- htt_stats_buf->mac_id__word & 0xFF); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "nsts = %u", +- htt_stats_buf->nsts); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "rx_ldpc = %u", +- htt_stats_buf->rx_ldpc); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "rts_cnt = %u", +- htt_stats_buf->rts_cnt); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "rssi_mgmt = %u", +- htt_stats_buf->rssi_mgmt); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "rssi_data = %u", +- htt_stats_buf->rssi_data); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "rssi_comb = %u", +- htt_stats_buf->rssi_comb); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "rssi_in_dbm = %d", +- htt_stats_buf->rssi_in_dbm); ++ len += scnprintf(buf + len, buf_len - len, "HTT_RX_PDEV_RATE_STATS_TLV:\n"); ++ len += scnprintf(buf + len, buf_len - len, "mac_id = %u\n", ++ htt_stats_buf->mac_id__word & 0xFF); ++ len += scnprintf(buf + len, buf_len - len, "nsts = %u\n", ++ htt_stats_buf->nsts); ++ len += scnprintf(buf + len, buf_len - len, "rx_ldpc = %u\n", ++ htt_stats_buf->rx_ldpc); ++ len += scnprintf(buf + len, buf_len - len, "rts_cnt = %u\n", ++ htt_stats_buf->rts_cnt); ++ len += scnprintf(buf + len, buf_len - len, "rssi_mgmt = %u\n", ++ htt_stats_buf->rssi_mgmt); ++ len += scnprintf(buf + len, buf_len - len, "rssi_data = %u\n", ++ htt_stats_buf->rssi_data); ++ len += scnprintf(buf + len, buf_len - len, "rssi_comb = %u\n", ++ htt_stats_buf->rssi_comb); ++ len += scnprintf(buf + len, buf_len - len, "rssi_in_dbm = %d\n", ++ htt_stats_buf->rssi_in_dbm); + + memset(str_buf, 0x0, HTT_MAX_STRING_LEN); + PRINT_ARRAY_TO_BUF(str_buf, htt_stats_buf->rx_mcs, + HTT_RX_PDEV_STATS_NUM_MCS_COUNTERS); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "rx_mcs = %s ", str_buf); ++ len += scnprintf(buf + len, buf_len - len, "rx_mcs = %s\n", str_buf); + + memset(str_buf, 0x0, HTT_MAX_STRING_LEN); + PRINT_ARRAY_TO_BUF(str_buf, htt_stats_buf->rx_nss, + HTT_RX_PDEV_STATS_NUM_SPATIAL_STREAMS); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "rx_nss = %s ", str_buf); ++ len += scnprintf(buf + len, buf_len - len, "rx_nss = %s\n", str_buf); + + memset(str_buf, 0x0, HTT_MAX_STRING_LEN); + PRINT_ARRAY_TO_BUF(str_buf, htt_stats_buf->rx_dcm, + HTT_RX_PDEV_STATS_NUM_DCM_COUNTERS); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "rx_dcm = %s ", str_buf); ++ len += scnprintf(buf + len, buf_len - len, "rx_dcm = %s\n", str_buf); + + memset(str_buf, 0x0, HTT_MAX_STRING_LEN); + PRINT_ARRAY_TO_BUF(str_buf, htt_stats_buf->rx_stbc, + HTT_RX_PDEV_STATS_NUM_MCS_COUNTERS); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "rx_stbc = %s ", str_buf); ++ len += scnprintf(buf + len, buf_len - len, "rx_stbc = %s\n", str_buf); + + memset(str_buf, 0x0, HTT_MAX_STRING_LEN); + PRINT_ARRAY_TO_BUF(str_buf, htt_stats_buf->rx_bw, + HTT_RX_PDEV_STATS_NUM_BW_COUNTERS); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "rx_bw = %s ", str_buf); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "rx_evm_nss_count = %u", +- htt_stats_buf->nss_count); ++ len += scnprintf(buf + len, buf_len - len, "rx_bw = %s\n", str_buf); ++ len += scnprintf(buf + len, buf_len - len, "rx_evm_nss_count = %u\n", ++ htt_stats_buf->nss_count); + +- len += HTT_DBG_OUT(buf + len, buf_len - len, "rx_evm_pilot_count = %u", +- htt_stats_buf->pilot_count); ++ len += scnprintf(buf + len, buf_len - len, "rx_evm_pilot_count = %u\n", ++ htt_stats_buf->pilot_count); + + for (j = 0; j < HTT_RX_PDEV_STATS_NUM_SPATIAL_STREAMS; j++) { + index = 0; + + for (i = 0; i < HTT_RX_PDEV_STATS_RXEVM_MAX_PILOTS_PER_NSS; i++) + index += scnprintf(&rx_pilot_evm_db[j][index], +- HTT_MAX_STRING_LEN - index, +- " %u:%d,", +- i, +- htt_stats_buf->rx_pilot_evm_db[j][i]); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "pilot_evm_dB[%u] = %s ", +- j, rx_pilot_evm_db[j]); ++ HTT_MAX_STRING_LEN - index, ++ " %u:%d,", ++ i, ++ htt_stats_buf->rx_pilot_evm_db[j][i]); ++ len += scnprintf(buf + len, buf_len - len, "pilot_evm_dB[%u] = %s\n", ++ j, rx_pilot_evm_db[j]); + } + + index = 0; + memset(str_buf, 0x0, HTT_MAX_STRING_LEN); + for (i = 0; i < HTT_RX_PDEV_STATS_NUM_SPATIAL_STREAMS; i++) + index += scnprintf(&str_buf[index], +- HTT_MAX_STRING_LEN - index, +- " %u:%d,", i, htt_stats_buf->rx_pilot_evm_db_mean[i]); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "pilot_evm_dB_mean = %s ", str_buf); ++ HTT_MAX_STRING_LEN - index, ++ " %u:%d,", i, htt_stats_buf->rx_pilot_evm_db_mean[i]); ++ len += scnprintf(buf + len, buf_len - len, "pilot_evm_dB_mean = %s\n", str_buf); + + for (j = 0; j < HTT_RX_PDEV_STATS_NUM_SPATIAL_STREAMS; j++) { + PRINT_ARRAY_TO_BUF(rssi_chain[j], htt_stats_buf->rssi_chain[j], + HTT_RX_PDEV_STATS_NUM_BW_COUNTERS); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "rssi_chain[%u] = %s ", +- j, rssi_chain[j]); ++ len += scnprintf(buf + len, buf_len - len, "rssi_chain[%u] = %s\n", ++ j, rssi_chain[j]); + } + + for (j = 0; j < HTT_RX_PDEV_STATS_NUM_GI_COUNTERS; j++) { + PRINT_ARRAY_TO_BUF(rx_gi[j], htt_stats_buf->rx_gi[j], + HTT_RX_PDEV_STATS_NUM_MCS_COUNTERS); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "rx_gi[%u] = %s ", +- j, rx_gi[j]); ++ len += scnprintf(buf + len, buf_len - len, "rx_gi[%u] = %s\n", ++ j, rx_gi[j]); + } + + memset(str_buf, 0x0, HTT_MAX_STRING_LEN); + PRINT_ARRAY_TO_BUF(str_buf, htt_stats_buf->rx_pream, + HTT_RX_PDEV_STATS_NUM_PREAMBLE_TYPES); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "rx_pream = %s", str_buf); ++ len += scnprintf(buf + len, buf_len - len, "rx_pream = %s\n", str_buf); + +- len += HTT_DBG_OUT(buf + len, buf_len - len, "rx_11ax_su_ext = %u", +- htt_stats_buf->rx_11ax_su_ext); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "rx_11ac_mumimo = %u", +- htt_stats_buf->rx_11ac_mumimo); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "rx_11ax_mumimo = %u", +- htt_stats_buf->rx_11ax_mumimo); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "rx_11ax_ofdma = %u", +- htt_stats_buf->rx_11ax_ofdma); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "txbf = %u", +- htt_stats_buf->txbf); ++ len += scnprintf(buf + len, buf_len - len, "rx_11ax_su_ext = %u\n", ++ htt_stats_buf->rx_11ax_su_ext); ++ len += scnprintf(buf + len, buf_len - len, "rx_11ac_mumimo = %u\n", ++ htt_stats_buf->rx_11ac_mumimo); ++ len += scnprintf(buf + len, buf_len - len, "rx_11ax_mumimo = %u\n", ++ htt_stats_buf->rx_11ax_mumimo); ++ len += scnprintf(buf + len, buf_len - len, "rx_11ax_ofdma = %u\n", ++ htt_stats_buf->rx_11ax_ofdma); ++ len += scnprintf(buf + len, buf_len - len, "txbf = %u\n", ++ htt_stats_buf->txbf); + + memset(str_buf, 0x0, HTT_MAX_STRING_LEN); + PRINT_ARRAY_TO_BUF(str_buf, htt_stats_buf->rx_legacy_cck_rate, + HTT_RX_PDEV_STATS_NUM_LEGACY_CCK_STATS); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "rx_legacy_cck_rate = %s ", +- str_buf); ++ len += scnprintf(buf + len, buf_len - len, "rx_legacy_cck_rate = %s\n", ++ str_buf); + + memset(str_buf, 0x0, HTT_MAX_STRING_LEN); + PRINT_ARRAY_TO_BUF(str_buf, htt_stats_buf->rx_legacy_ofdm_rate, + HTT_RX_PDEV_STATS_NUM_LEGACY_OFDM_STATS); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "rx_legacy_ofdm_rate = %s ", +- str_buf); ++ len += scnprintf(buf + len, buf_len - len, "rx_legacy_ofdm_rate = %s\n", ++ str_buf); + +- len += HTT_DBG_OUT(buf + len, buf_len - len, "rx_active_dur_us_low = %u", +- htt_stats_buf->rx_active_dur_us_low); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "rx_active_dur_us_high = %u", +- htt_stats_buf->rx_active_dur_us_high); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "rx_11ax_ul_ofdma = %u", +- htt_stats_buf->rx_11ax_ul_ofdma); ++ len += scnprintf(buf + len, buf_len - len, "rx_active_dur_us_low = %u\n", ++ htt_stats_buf->rx_active_dur_us_low); ++ len += scnprintf(buf + len, buf_len - len, "rx_active_dur_us_high = %u\n", ++ htt_stats_buf->rx_active_dur_us_high); ++ len += scnprintf(buf + len, buf_len - len, "rx_11ax_ul_ofdma = %u\n", ++ htt_stats_buf->rx_11ax_ul_ofdma); + + memset(str_buf, 0x0, HTT_MAX_STRING_LEN); + PRINT_ARRAY_TO_BUF(str_buf, htt_stats_buf->ul_ofdma_rx_mcs, + HTT_RX_PDEV_STATS_NUM_MCS_COUNTERS); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "ul_ofdma_rx_mcs = %s ", str_buf); ++ len += scnprintf(buf + len, buf_len - len, "ul_ofdma_rx_mcs = %s\n", str_buf); + + for (j = 0; j < HTT_RX_PDEV_STATS_NUM_GI_COUNTERS; j++) { + PRINT_ARRAY_TO_BUF(rx_gi[j], htt_stats_buf->ul_ofdma_rx_gi[j], + HTT_RX_PDEV_STATS_NUM_MCS_COUNTERS); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "ul_ofdma_rx_gi[%u] = %s ", +- j, rx_gi[j]); ++ len += scnprintf(buf + len, buf_len - len, "ul_ofdma_rx_gi[%u] = %s\n", ++ j, rx_gi[j]); + } + + memset(str_buf, 0x0, HTT_MAX_STRING_LEN); + PRINT_ARRAY_TO_BUF(str_buf, htt_stats_buf->ul_ofdma_rx_nss, + HTT_RX_PDEV_STATS_NUM_SPATIAL_STREAMS); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "ul_ofdma_rx_nss = %s ", str_buf); ++ len += scnprintf(buf + len, buf_len - len, "ul_ofdma_rx_nss = %s\n", str_buf); + + memset(str_buf, 0x0, HTT_MAX_STRING_LEN); + PRINT_ARRAY_TO_BUF(str_buf, htt_stats_buf->ul_ofdma_rx_bw, + HTT_RX_PDEV_STATS_NUM_BW_COUNTERS); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "ul_ofdma_rx_bw = %s ", str_buf); ++ len += scnprintf(buf + len, buf_len - len, "ul_ofdma_rx_bw = %s\n", str_buf); + +- len += HTT_DBG_OUT(buf + len, buf_len - len, "ul_ofdma_rx_stbc = %u", ++ len += scnprintf(buf + len, buf_len - len, "ul_ofdma_rx_stbc = %u\n", + htt_stats_buf->ul_ofdma_rx_stbc); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "ul_ofdma_rx_ldpc = %u", ++ len += scnprintf(buf + len, buf_len - len, "ul_ofdma_rx_ldpc = %u\n", + htt_stats_buf->ul_ofdma_rx_ldpc); + + memset(str_buf, 0x0, HTT_MAX_STRING_LEN); + PRINT_ARRAY_TO_BUF(str_buf, htt_stats_buf->rx_ulofdma_non_data_ppdu, + HTT_RX_PDEV_MAX_OFDMA_NUM_USER); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "rx_ulofdma_non_data_ppdu = %s ", +- str_buf); ++ len += scnprintf(buf + len, buf_len - len, "rx_ulofdma_non_data_ppdu = %s\n", ++ str_buf); + + memset(str_buf, 0x0, HTT_MAX_STRING_LEN); + PRINT_ARRAY_TO_BUF(str_buf, htt_stats_buf->rx_ulofdma_data_ppdu, + HTT_RX_PDEV_MAX_OFDMA_NUM_USER); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "rx_ulofdma_data_ppdu = %s ", ++ len += scnprintf(buf + len, buf_len - len, "rx_ulofdma_data_ppdu = %s\n", + str_buf); + + memset(str_buf, 0x0, HTT_MAX_STRING_LEN); + PRINT_ARRAY_TO_BUF(str_buf, htt_stats_buf->rx_ulofdma_mpdu_ok, + HTT_RX_PDEV_MAX_OFDMA_NUM_USER); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "rx_ulofdma_mpdu_ok = %s ", str_buf); ++ len += scnprintf(buf + len, buf_len - len, "rx_ulofdma_mpdu_ok = %s\n", str_buf); + + memset(str_buf, 0x0, HTT_MAX_STRING_LEN); + PRINT_ARRAY_TO_BUF(str_buf, htt_stats_buf->rx_ulofdma_mpdu_fail, + HTT_RX_PDEV_MAX_OFDMA_NUM_USER); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "rx_ulofdma_mpdu_fail = %s", +- str_buf); ++ len += scnprintf(buf + len, buf_len - len, "rx_ulofdma_mpdu_fail = %s\n", ++ str_buf); + + for (j = 0; j < HTT_RX_PDEV_STATS_NUM_SPATIAL_STREAMS; j++) { + index = 0; + memset(str_buf, 0x0, HTT_MAX_STRING_LEN); + for (i = 0; i < HTT_RX_PDEV_MAX_OFDMA_NUM_USER; i++) + index += scnprintf(&str_buf[index], +- HTT_MAX_STRING_LEN - index, +- " %u:%d,", +- i, htt_stats_buf->rx_ul_fd_rssi[j][i]); +- len += HTT_DBG_OUT(buf + len, buf_len - len, +- "rx_ul_fd_rssi: nss[%u] = %s", j, str_buf); ++ HTT_MAX_STRING_LEN - index, ++ " %u:%d,", ++ i, htt_stats_buf->rx_ul_fd_rssi[j][i]); ++ len += scnprintf(buf + len, buf_len - len, ++ "rx_ul_fd_rssi: nss[%u] = %s\n", j, str_buf); + } + +- len += HTT_DBG_OUT(buf + len, buf_len - len, "per_chain_rssi_pkt_type = %#x", +- htt_stats_buf->per_chain_rssi_pkt_type); ++ len += scnprintf(buf + len, buf_len - len, "per_chain_rssi_pkt_type = %#x\n", ++ htt_stats_buf->per_chain_rssi_pkt_type); + + for (j = 0; j < HTT_RX_PDEV_STATS_NUM_SPATIAL_STREAMS; j++) { + index = 0; + memset(str_buf, 0x0, HTT_MAX_STRING_LEN); + for (i = 0; i < HTT_RX_PDEV_STATS_NUM_BW_COUNTERS; i++) + index += scnprintf(&str_buf[index], +- HTT_MAX_STRING_LEN - index, +- " %u:%d,", +- i, +- htt_stats_buf->rx_per_chain_rssi_in_dbm[j][i]); +- len += HTT_DBG_OUT(buf + len, buf_len - len, +- "rx_per_chain_rssi_in_dbm[%u] = %s ", j, str_buf); ++ HTT_MAX_STRING_LEN - index, ++ " %u:%d,", ++ i, ++ htt_stats_buf->rx_per_chain_rssi_in_dbm[j][i]); ++ len += scnprintf(buf + len, buf_len - len, ++ "rx_per_chain_rssi_in_dbm[%u] = %s\n", j, str_buf); + } +- len += HTT_DBG_OUT(buf + len, buf_len - len, "\n"); ++ len += scnprintf(buf + len, buf_len - len, "\n"); + + if (len >= buf_len) + buf[buf_len - 1] = 0; +@@ -3268,34 +3264,34 @@ static inline void htt_print_rx_soc_fw_s + u32 len = stats_req->buf_len; + u32 buf_len = ATH11K_HTT_STATS_BUF_SIZE; + +- len += HTT_DBG_OUT(buf + len, buf_len - len, "HTT_RX_SOC_FW_STATS_TLV:"); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "fw_reo_ring_data_msdu = %u", +- htt_stats_buf->fw_reo_ring_data_msdu); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "fw_to_host_data_msdu_bcmc = %u", +- htt_stats_buf->fw_to_host_data_msdu_bcmc); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "fw_to_host_data_msdu_uc = %u", +- htt_stats_buf->fw_to_host_data_msdu_uc); +- len += HTT_DBG_OUT(buf + len, buf_len - len, +- "ofld_remote_data_buf_recycle_cnt = %u", +- htt_stats_buf->ofld_remote_data_buf_recycle_cnt); +- len += HTT_DBG_OUT(buf + len, buf_len - len, +- "ofld_remote_free_buf_indication_cnt = %u", +- htt_stats_buf->ofld_remote_free_buf_indication_cnt); +- len += HTT_DBG_OUT(buf + len, buf_len - len, +- "ofld_buf_to_host_data_msdu_uc = %u", +- htt_stats_buf->ofld_buf_to_host_data_msdu_uc); +- len += HTT_DBG_OUT(buf + len, buf_len - len, +- "reo_fw_ring_to_host_data_msdu_uc = %u", +- htt_stats_buf->reo_fw_ring_to_host_data_msdu_uc); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "wbm_sw_ring_reap = %u", +- htt_stats_buf->wbm_sw_ring_reap); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "wbm_forward_to_host_cnt = %u", +- htt_stats_buf->wbm_forward_to_host_cnt); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "wbm_target_recycle_cnt = %u", +- htt_stats_buf->wbm_target_recycle_cnt); +- len += HTT_DBG_OUT(buf + len, buf_len - len, +- "target_refill_ring_recycle_cnt = %u", +- htt_stats_buf->target_refill_ring_recycle_cnt); ++ len += scnprintf(buf + len, buf_len - len, "HTT_RX_SOC_FW_STATS_TLV:\n"); ++ len += scnprintf(buf + len, buf_len - len, "fw_reo_ring_data_msdu = %u\n", ++ htt_stats_buf->fw_reo_ring_data_msdu); ++ len += scnprintf(buf + len, buf_len - len, "fw_to_host_data_msdu_bcmc = %u\n", ++ htt_stats_buf->fw_to_host_data_msdu_bcmc); ++ len += scnprintf(buf + len, buf_len - len, "fw_to_host_data_msdu_uc = %u\n", ++ htt_stats_buf->fw_to_host_data_msdu_uc); ++ len += scnprintf(buf + len, buf_len - len, ++ "ofld_remote_data_buf_recycle_cnt = %u\n", ++ htt_stats_buf->ofld_remote_data_buf_recycle_cnt); ++ len += scnprintf(buf + len, buf_len - len, ++ "ofld_remote_free_buf_indication_cnt = %u\n", ++ htt_stats_buf->ofld_remote_free_buf_indication_cnt); ++ len += scnprintf(buf + len, buf_len - len, ++ "ofld_buf_to_host_data_msdu_uc = %u\n", ++ htt_stats_buf->ofld_buf_to_host_data_msdu_uc); ++ len += scnprintf(buf + len, buf_len - len, ++ "reo_fw_ring_to_host_data_msdu_uc = %u\n", ++ htt_stats_buf->reo_fw_ring_to_host_data_msdu_uc); ++ len += scnprintf(buf + len, buf_len - len, "wbm_sw_ring_reap = %u\n", ++ htt_stats_buf->wbm_sw_ring_reap); ++ len += scnprintf(buf + len, buf_len - len, "wbm_forward_to_host_cnt = %u\n", ++ htt_stats_buf->wbm_forward_to_host_cnt); ++ len += scnprintf(buf + len, buf_len - len, "wbm_target_recycle_cnt = %u\n", ++ htt_stats_buf->wbm_target_recycle_cnt); ++ len += scnprintf(buf + len, buf_len - len, ++ "target_refill_ring_recycle_cnt = %u\n", ++ htt_stats_buf->target_refill_ring_recycle_cnt); + + if (len >= buf_len) + buf[buf_len - 1] = 0; +@@ -3317,14 +3313,14 @@ htt_print_rx_soc_fw_refill_ring_empty_tl + char refill_ring_empty_cnt[HTT_MAX_STRING_LEN] = {0}; + u16 num_elems = min_t(u16, (tag_len >> 2), HTT_RX_STATS_REFILL_MAX_RING); + +- len += HTT_DBG_OUT(buf + len, buf_len - len, +- "HTT_RX_SOC_FW_REFILL_RING_EMPTY_TLV_V:"); ++ len += scnprintf(buf + len, buf_len - len, ++ "HTT_RX_SOC_FW_REFILL_RING_EMPTY_TLV_V:\n"); + + PRINT_ARRAY_TO_BUF(refill_ring_empty_cnt, + htt_stats_buf->refill_ring_empty_cnt, + num_elems); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "refill_ring_empty_cnt = %s\n", +- refill_ring_empty_cnt); ++ len += scnprintf(buf + len, buf_len - len, "refill_ring_empty_cnt = %s\n\n", ++ refill_ring_empty_cnt); + + if (len >= buf_len) + buf[buf_len - 1] = 0; +@@ -3347,14 +3343,14 @@ htt_print_rx_soc_fw_refill_ring_num_rxdm + char rxdma_err_cnt[HTT_MAX_STRING_LEN] = {0}; + u16 num_elems = min_t(u16, (tag_len >> 2), HTT_RX_RXDMA_MAX_ERR_CODE); + +- len += HTT_DBG_OUT(buf + len, buf_len - len, +- "HTT_RX_SOC_FW_REFILL_RING_NUM_RXDMA_ERR_TLV_V:"); ++ len += scnprintf(buf + len, buf_len - len, ++ "HTT_RX_SOC_FW_REFILL_RING_NUM_RXDMA_ERR_TLV_V:\n"); + + PRINT_ARRAY_TO_BUF(rxdma_err_cnt, + htt_stats_buf->rxdma_err, + num_elems); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "rxdma_err = %s\n", +- rxdma_err_cnt); ++ len += scnprintf(buf + len, buf_len - len, "rxdma_err = %s\n\n", ++ rxdma_err_cnt); + + if (len >= buf_len) + buf[buf_len - 1] = 0; +@@ -3376,14 +3372,14 @@ htt_print_rx_soc_fw_refill_ring_num_reo_ + char reo_err_cnt[HTT_MAX_STRING_LEN] = {0}; + u16 num_elems = min_t(u16, (tag_len >> 2), HTT_RX_REO_MAX_ERR_CODE); + +- len += HTT_DBG_OUT(buf + len, buf_len - len, +- "HTT_RX_SOC_FW_REFILL_RING_NUM_REO_ERR_TLV_V:"); ++ len += scnprintf(buf + len, buf_len - len, ++ "HTT_RX_SOC_FW_REFILL_RING_NUM_REO_ERR_TLV_V:\n"); + + PRINT_ARRAY_TO_BUF(reo_err_cnt, + htt_stats_buf->reo_err, + num_elems); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "reo_err = %s\n", +- reo_err_cnt); ++ len += scnprintf(buf + len, buf_len - len, "reo_err = %s\n\n", ++ reo_err_cnt); + + if (len >= buf_len) + buf[buf_len - 1] = 0; +@@ -3402,27 +3398,27 @@ htt_print_rx_reo_debug_stats_tlv_v(const + u32 len = stats_req->buf_len; + u32 buf_len = ATH11K_HTT_STATS_BUF_SIZE; + +- len += HTT_DBG_OUT(buf + len, buf_len - len, "HTT_RX_REO_RESOURCE_STATS_TLV:"); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "sample_id = %u", +- htt_stats_buf->sample_id); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "total_max = %u", +- htt_stats_buf->total_max); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "total_avg = %u", +- htt_stats_buf->total_avg); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "total_sample = %u", +- htt_stats_buf->total_sample); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "non_zeros_avg = %u", +- htt_stats_buf->non_zeros_avg); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "non_zeros_sample = %u", +- htt_stats_buf->non_zeros_sample); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "last_non_zeros_max = %u", +- htt_stats_buf->last_non_zeros_max); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "last_non_zeros_min %u", +- htt_stats_buf->last_non_zeros_min); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "last_non_zeros_avg %u", +- htt_stats_buf->last_non_zeros_avg); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "last_non_zeros_sample %u\n", +- htt_stats_buf->last_non_zeros_sample); ++ len += scnprintf(buf + len, buf_len - len, "HTT_RX_REO_RESOURCE_STATS_TLV:\n"); ++ len += scnprintf(buf + len, buf_len - len, "sample_id = %u\n", ++ htt_stats_buf->sample_id); ++ len += scnprintf(buf + len, buf_len - len, "total_max = %u\n", ++ htt_stats_buf->total_max); ++ len += scnprintf(buf + len, buf_len - len, "total_avg = %u\n", ++ htt_stats_buf->total_avg); ++ len += scnprintf(buf + len, buf_len - len, "total_sample = %u\n", ++ htt_stats_buf->total_sample); ++ len += scnprintf(buf + len, buf_len - len, "non_zeros_avg = %u\n", ++ htt_stats_buf->non_zeros_avg); ++ len += scnprintf(buf + len, buf_len - len, "non_zeros_sample = %u\n", ++ htt_stats_buf->non_zeros_sample); ++ len += scnprintf(buf + len, buf_len - len, "last_non_zeros_max = %u\n", ++ htt_stats_buf->last_non_zeros_max); ++ len += scnprintf(buf + len, buf_len - len, "last_non_zeros_min %u\n", ++ htt_stats_buf->last_non_zeros_min); ++ len += scnprintf(buf + len, buf_len - len, "last_non_zeros_avg %u\n", ++ htt_stats_buf->last_non_zeros_avg); ++ len += scnprintf(buf + len, buf_len - len, "last_non_zeros_sample %u\n\n", ++ htt_stats_buf->last_non_zeros_sample); + + if (len >= buf_len) + buf[buf_len - 1] = 0; +@@ -3444,14 +3440,14 @@ htt_print_rx_soc_fw_refill_ring_num_refi + char refill_ring_num_refill[HTT_MAX_STRING_LEN] = {0}; + u16 num_elems = min_t(u16, (tag_len >> 2), HTT_RX_STATS_REFILL_MAX_RING); + +- len += HTT_DBG_OUT(buf + len, buf_len - len, +- "HTT_RX_SOC_FW_REFILL_RING_NUM_REFILL_TLV_V:"); ++ len += scnprintf(buf + len, buf_len - len, ++ "HTT_RX_SOC_FW_REFILL_RING_NUM_REFILL_TLV_V:\n"); + + PRINT_ARRAY_TO_BUF(refill_ring_num_refill, + htt_stats_buf->refill_ring_num_refill, + num_elems); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "refill_ring_num_refill = %s\n", +- refill_ring_num_refill); ++ len += scnprintf(buf + len, buf_len - len, "refill_ring_num_refill = %s\n\n", ++ refill_ring_num_refill); + + if (len >= buf_len) + buf[buf_len - 1] = 0; +@@ -3471,110 +3467,110 @@ static inline void htt_print_rx_pdev_fw_ + char fw_ring_mgmt_subtype[HTT_MAX_STRING_LEN] = {0}; + char fw_ring_ctrl_subtype[HTT_MAX_STRING_LEN] = {0}; + +- len += HTT_DBG_OUT(buf + len, buf_len - len, "HTT_RX_PDEV_FW_STATS_TLV:"); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "mac_id = %u", +- htt_stats_buf->mac_id__word & 0xFF); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "ppdu_recvd = %u", +- htt_stats_buf->ppdu_recvd); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "mpdu_cnt_fcs_ok = %u", +- htt_stats_buf->mpdu_cnt_fcs_ok); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "mpdu_cnt_fcs_err = %u", +- htt_stats_buf->mpdu_cnt_fcs_err); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "tcp_msdu_cnt = %u", +- htt_stats_buf->tcp_msdu_cnt); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "tcp_ack_msdu_cnt = %u", +- htt_stats_buf->tcp_ack_msdu_cnt); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "udp_msdu_cnt = %u", +- htt_stats_buf->udp_msdu_cnt); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "other_msdu_cnt = %u", +- htt_stats_buf->other_msdu_cnt); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "fw_ring_mpdu_ind = %u", +- htt_stats_buf->fw_ring_mpdu_ind); ++ len += scnprintf(buf + len, buf_len - len, "HTT_RX_PDEV_FW_STATS_TLV:\n"); ++ len += scnprintf(buf + len, buf_len - len, "mac_id = %u\n", ++ htt_stats_buf->mac_id__word & 0xFF); ++ len += scnprintf(buf + len, buf_len - len, "ppdu_recvd = %u\n", ++ htt_stats_buf->ppdu_recvd); ++ len += scnprintf(buf + len, buf_len - len, "mpdu_cnt_fcs_ok = %u\n", ++ htt_stats_buf->mpdu_cnt_fcs_ok); ++ len += scnprintf(buf + len, buf_len - len, "mpdu_cnt_fcs_err = %u\n", ++ htt_stats_buf->mpdu_cnt_fcs_err); ++ len += scnprintf(buf + len, buf_len - len, "tcp_msdu_cnt = %u\n", ++ htt_stats_buf->tcp_msdu_cnt); ++ len += scnprintf(buf + len, buf_len - len, "tcp_ack_msdu_cnt = %u\n", ++ htt_stats_buf->tcp_ack_msdu_cnt); ++ len += scnprintf(buf + len, buf_len - len, "udp_msdu_cnt = %u\n", ++ htt_stats_buf->udp_msdu_cnt); ++ len += scnprintf(buf + len, buf_len - len, "other_msdu_cnt = %u\n", ++ htt_stats_buf->other_msdu_cnt); ++ len += scnprintf(buf + len, buf_len - len, "fw_ring_mpdu_ind = %u\n", ++ htt_stats_buf->fw_ring_mpdu_ind); + + PRINT_ARRAY_TO_BUF(fw_ring_mgmt_subtype, + htt_stats_buf->fw_ring_mgmt_subtype, + HTT_STATS_SUBTYPE_MAX); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "fw_ring_mgmt_subtype = %s ", +- fw_ring_mgmt_subtype); ++ len += scnprintf(buf + len, buf_len - len, "fw_ring_mgmt_subtype = %s\n", ++ fw_ring_mgmt_subtype); + + PRINT_ARRAY_TO_BUF(fw_ring_ctrl_subtype, + htt_stats_buf->fw_ring_ctrl_subtype, + HTT_STATS_SUBTYPE_MAX); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "fw_ring_ctrl_subtype = %s ", +- fw_ring_ctrl_subtype); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "fw_ring_mcast_data_msdu = %u", +- htt_stats_buf->fw_ring_mcast_data_msdu); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "fw_ring_bcast_data_msdu = %u", +- htt_stats_buf->fw_ring_bcast_data_msdu); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "fw_ring_ucast_data_msdu = %u", +- htt_stats_buf->fw_ring_ucast_data_msdu); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "fw_ring_null_data_msdu = %u", +- htt_stats_buf->fw_ring_null_data_msdu); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "fw_ring_mpdu_drop = %u", +- htt_stats_buf->fw_ring_mpdu_drop); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "ofld_local_data_ind_cnt = %u", +- htt_stats_buf->ofld_local_data_ind_cnt); +- len += HTT_DBG_OUT(buf + len, buf_len - len, +- "ofld_local_data_buf_recycle_cnt = %u", +- htt_stats_buf->ofld_local_data_buf_recycle_cnt); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "drx_local_data_ind_cnt = %u", +- htt_stats_buf->drx_local_data_ind_cnt); +- len += HTT_DBG_OUT(buf + len, buf_len - len, +- "drx_local_data_buf_recycle_cnt = %u", +- htt_stats_buf->drx_local_data_buf_recycle_cnt); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "local_nondata_ind_cnt = %u", +- htt_stats_buf->local_nondata_ind_cnt); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "local_nondata_buf_recycle_cnt = %u", +- htt_stats_buf->local_nondata_buf_recycle_cnt); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "fw_status_buf_ring_refill_cnt = %u", +- htt_stats_buf->fw_status_buf_ring_refill_cnt); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "fw_status_buf_ring_empty_cnt = %u", +- htt_stats_buf->fw_status_buf_ring_empty_cnt); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "fw_pkt_buf_ring_refill_cnt = %u", +- htt_stats_buf->fw_pkt_buf_ring_refill_cnt); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "fw_pkt_buf_ring_empty_cnt = %u", +- htt_stats_buf->fw_pkt_buf_ring_empty_cnt); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "fw_link_buf_ring_refill_cnt = %u", +- htt_stats_buf->fw_link_buf_ring_refill_cnt); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "fw_link_buf_ring_empty_cnt = %u", +- htt_stats_buf->fw_link_buf_ring_empty_cnt); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "host_pkt_buf_ring_refill_cnt = %u", +- htt_stats_buf->host_pkt_buf_ring_refill_cnt); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "host_pkt_buf_ring_empty_cnt = %u", +- htt_stats_buf->host_pkt_buf_ring_empty_cnt); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "mon_pkt_buf_ring_refill_cnt = %u", +- htt_stats_buf->mon_pkt_buf_ring_refill_cnt); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "mon_pkt_buf_ring_empty_cnt = %u", +- htt_stats_buf->mon_pkt_buf_ring_empty_cnt); +- len += HTT_DBG_OUT(buf + len, buf_len - len, +- "mon_status_buf_ring_refill_cnt = %u", +- htt_stats_buf->mon_status_buf_ring_refill_cnt); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "mon_status_buf_ring_empty_cnt = %u", +- htt_stats_buf->mon_status_buf_ring_empty_cnt); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "mon_desc_buf_ring_refill_cnt = %u", +- htt_stats_buf->mon_desc_buf_ring_refill_cnt); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "mon_desc_buf_ring_empty_cnt = %u", +- htt_stats_buf->mon_desc_buf_ring_empty_cnt); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "mon_dest_ring_update_cnt = %u", +- htt_stats_buf->mon_dest_ring_update_cnt); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "mon_dest_ring_full_cnt = %u", +- htt_stats_buf->mon_dest_ring_full_cnt); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "rx_suspend_cnt = %u", +- htt_stats_buf->rx_suspend_cnt); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "rx_suspend_fail_cnt = %u", +- htt_stats_buf->rx_suspend_fail_cnt); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "rx_resume_cnt = %u", +- htt_stats_buf->rx_resume_cnt); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "rx_resume_fail_cnt = %u", +- htt_stats_buf->rx_resume_fail_cnt); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "rx_ring_switch_cnt = %u", +- htt_stats_buf->rx_ring_switch_cnt); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "rx_ring_restore_cnt = %u", +- htt_stats_buf->rx_ring_restore_cnt); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "rx_flush_cnt = %u", +- htt_stats_buf->rx_flush_cnt); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "rx_recovery_reset_cnt = %u\n", +- htt_stats_buf->rx_recovery_reset_cnt); ++ len += scnprintf(buf + len, buf_len - len, "fw_ring_ctrl_subtype = %s\n", ++ fw_ring_ctrl_subtype); ++ len += scnprintf(buf + len, buf_len - len, "fw_ring_mcast_data_msdu = %u\n", ++ htt_stats_buf->fw_ring_mcast_data_msdu); ++ len += scnprintf(buf + len, buf_len - len, "fw_ring_bcast_data_msdu = %u\n", ++ htt_stats_buf->fw_ring_bcast_data_msdu); ++ len += scnprintf(buf + len, buf_len - len, "fw_ring_ucast_data_msdu = %u\n", ++ htt_stats_buf->fw_ring_ucast_data_msdu); ++ len += scnprintf(buf + len, buf_len - len, "fw_ring_null_data_msdu = %u\n", ++ htt_stats_buf->fw_ring_null_data_msdu); ++ len += scnprintf(buf + len, buf_len - len, "fw_ring_mpdu_drop = %u\n", ++ htt_stats_buf->fw_ring_mpdu_drop); ++ len += scnprintf(buf + len, buf_len - len, "ofld_local_data_ind_cnt = %u\n", ++ htt_stats_buf->ofld_local_data_ind_cnt); ++ len += scnprintf(buf + len, buf_len - len, ++ "ofld_local_data_buf_recycle_cnt = %u\n", ++ htt_stats_buf->ofld_local_data_buf_recycle_cnt); ++ len += scnprintf(buf + len, buf_len - len, "drx_local_data_ind_cnt = %u\n", ++ htt_stats_buf->drx_local_data_ind_cnt); ++ len += scnprintf(buf + len, buf_len - len, ++ "drx_local_data_buf_recycle_cnt = %u\n", ++ htt_stats_buf->drx_local_data_buf_recycle_cnt); ++ len += scnprintf(buf + len, buf_len - len, "local_nondata_ind_cnt = %u\n", ++ htt_stats_buf->local_nondata_ind_cnt); ++ len += scnprintf(buf + len, buf_len - len, "local_nondata_buf_recycle_cnt = %u\n", ++ htt_stats_buf->local_nondata_buf_recycle_cnt); ++ len += scnprintf(buf + len, buf_len - len, "fw_status_buf_ring_refill_cnt = %u\n", ++ htt_stats_buf->fw_status_buf_ring_refill_cnt); ++ len += scnprintf(buf + len, buf_len - len, "fw_status_buf_ring_empty_cnt = %u\n", ++ htt_stats_buf->fw_status_buf_ring_empty_cnt); ++ len += scnprintf(buf + len, buf_len - len, "fw_pkt_buf_ring_refill_cnt = %u\n", ++ htt_stats_buf->fw_pkt_buf_ring_refill_cnt); ++ len += scnprintf(buf + len, buf_len - len, "fw_pkt_buf_ring_empty_cnt = %u\n", ++ htt_stats_buf->fw_pkt_buf_ring_empty_cnt); ++ len += scnprintf(buf + len, buf_len - len, "fw_link_buf_ring_refill_cnt = %u\n", ++ htt_stats_buf->fw_link_buf_ring_refill_cnt); ++ len += scnprintf(buf + len, buf_len - len, "fw_link_buf_ring_empty_cnt = %u\n", ++ htt_stats_buf->fw_link_buf_ring_empty_cnt); ++ len += scnprintf(buf + len, buf_len - len, "host_pkt_buf_ring_refill_cnt = %u\n", ++ htt_stats_buf->host_pkt_buf_ring_refill_cnt); ++ len += scnprintf(buf + len, buf_len - len, "host_pkt_buf_ring_empty_cnt = %u\n", ++ htt_stats_buf->host_pkt_buf_ring_empty_cnt); ++ len += scnprintf(buf + len, buf_len - len, "mon_pkt_buf_ring_refill_cnt = %u\n", ++ htt_stats_buf->mon_pkt_buf_ring_refill_cnt); ++ len += scnprintf(buf + len, buf_len - len, "mon_pkt_buf_ring_empty_cnt = %u\n", ++ htt_stats_buf->mon_pkt_buf_ring_empty_cnt); ++ len += scnprintf(buf + len, buf_len - len, ++ "mon_status_buf_ring_refill_cnt = %u\n", ++ htt_stats_buf->mon_status_buf_ring_refill_cnt); ++ len += scnprintf(buf + len, buf_len - len, "mon_status_buf_ring_empty_cnt = %u\n", ++ htt_stats_buf->mon_status_buf_ring_empty_cnt); ++ len += scnprintf(buf + len, buf_len - len, "mon_desc_buf_ring_refill_cnt = %u\n", ++ htt_stats_buf->mon_desc_buf_ring_refill_cnt); ++ len += scnprintf(buf + len, buf_len - len, "mon_desc_buf_ring_empty_cnt = %u\n", ++ htt_stats_buf->mon_desc_buf_ring_empty_cnt); ++ len += scnprintf(buf + len, buf_len - len, "mon_dest_ring_update_cnt = %u\n", ++ htt_stats_buf->mon_dest_ring_update_cnt); ++ len += scnprintf(buf + len, buf_len - len, "mon_dest_ring_full_cnt = %u\n", ++ htt_stats_buf->mon_dest_ring_full_cnt); ++ len += scnprintf(buf + len, buf_len - len, "rx_suspend_cnt = %u\n", ++ htt_stats_buf->rx_suspend_cnt); ++ len += scnprintf(buf + len, buf_len - len, "rx_suspend_fail_cnt = %u\n", ++ htt_stats_buf->rx_suspend_fail_cnt); ++ len += scnprintf(buf + len, buf_len - len, "rx_resume_cnt = %u\n", ++ htt_stats_buf->rx_resume_cnt); ++ len += scnprintf(buf + len, buf_len - len, "rx_resume_fail_cnt = %u\n", ++ htt_stats_buf->rx_resume_fail_cnt); ++ len += scnprintf(buf + len, buf_len - len, "rx_ring_switch_cnt = %u\n", ++ htt_stats_buf->rx_ring_switch_cnt); ++ len += scnprintf(buf + len, buf_len - len, "rx_ring_restore_cnt = %u\n", ++ htt_stats_buf->rx_ring_restore_cnt); ++ len += scnprintf(buf + len, buf_len - len, "rx_flush_cnt = %u\n", ++ htt_stats_buf->rx_flush_cnt); ++ len += scnprintf(buf + len, buf_len - len, "rx_recovery_reset_cnt = %u\n\n", ++ htt_stats_buf->rx_recovery_reset_cnt); + + if (len >= buf_len) + buf[buf_len - 1] = 0; +@@ -3594,14 +3590,14 @@ htt_print_rx_pdev_fw_ring_mpdu_err_tlv_v + u32 buf_len = ATH11K_HTT_STATS_BUF_SIZE; + char fw_ring_mpdu_err[HTT_MAX_STRING_LEN] = {0}; + +- len += HTT_DBG_OUT(buf + len, buf_len - len, +- "HTT_RX_PDEV_FW_RING_MPDU_ERR_TLV_V:"); ++ len += scnprintf(buf + len, buf_len - len, ++ "HTT_RX_PDEV_FW_RING_MPDU_ERR_TLV_V:\n"); + + PRINT_ARRAY_TO_BUF(fw_ring_mpdu_err, + htt_stats_buf->fw_ring_mpdu_err, + HTT_RX_STATS_RXDMA_MAX_ERR); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "fw_ring_mpdu_err = %s\n", +- fw_ring_mpdu_err); ++ len += scnprintf(buf + len, buf_len - len, "fw_ring_mpdu_err = %s\n\n", ++ fw_ring_mpdu_err); + + if (len >= buf_len) + buf[buf_len - 1] = 0; +@@ -3623,12 +3619,12 @@ htt_print_rx_pdev_fw_mpdu_drop_tlv_v(con + char fw_mpdu_drop[HTT_MAX_STRING_LEN] = {0}; + u16 num_elems = min_t(u16, (tag_len >> 2), HTT_RX_STATS_FW_DROP_REASON_MAX); + +- len += HTT_DBG_OUT(buf + len, buf_len - len, "HTT_RX_PDEV_FW_MPDU_DROP_TLV_V:"); ++ len += scnprintf(buf + len, buf_len - len, "HTT_RX_PDEV_FW_MPDU_DROP_TLV_V:\n"); + + PRINT_ARRAY_TO_BUF(fw_mpdu_drop, + htt_stats_buf->fw_mpdu_drop, + num_elems); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "fw_mpdu_drop = %s\n", fw_mpdu_drop); ++ len += scnprintf(buf + len, buf_len - len, "fw_mpdu_drop = %s\n\n", fw_mpdu_drop); + + if (len >= buf_len) + buf[buf_len - 1] = 0; +@@ -3648,16 +3644,16 @@ htt_print_rx_pdev_fw_stats_phy_err_tlv(c + u32 buf_len = ATH11K_HTT_STATS_BUF_SIZE; + char phy_errs[HTT_MAX_STRING_LEN] = {0}; + +- len += HTT_DBG_OUT(buf + len, buf_len - len, "HTT_RX_PDEV_FW_STATS_PHY_ERR_TLV:"); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "mac_id__word = %u", +- htt_stats_buf->mac_id__word); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "total_phy_err_nct = %u", +- htt_stats_buf->total_phy_err_cnt); ++ len += scnprintf(buf + len, buf_len - len, "HTT_RX_PDEV_FW_STATS_PHY_ERR_TLV:\n"); ++ len += scnprintf(buf + len, buf_len - len, "mac_id__word = %u\n", ++ htt_stats_buf->mac_id__word); ++ len += scnprintf(buf + len, buf_len - len, "total_phy_err_nct = %u\n", ++ htt_stats_buf->total_phy_err_cnt); + + PRINT_ARRAY_TO_BUF(phy_errs, + htt_stats_buf->phy_err, + HTT_STATS_PHY_ERR_MAX); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "phy_errs = %s\n", phy_errs); ++ len += scnprintf(buf + len, buf_len - len, "phy_errs = %s\n\n", phy_errs); + + if (len >= buf_len) + buf[buf_len - 1] = 0; +@@ -3676,20 +3672,20 @@ htt_print_pdev_cca_stats_hist_tlv(const + u32 len = stats_req->buf_len; + u32 buf_len = ATH11K_HTT_STATS_BUF_SIZE; + +- len += HTT_DBG_OUT(buf + len, buf_len - len, "\nHTT_PDEV_CCA_STATS_HIST_TLV:"); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "chan_num = %u", +- htt_stats_buf->chan_num); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "num_records = %u", +- htt_stats_buf->num_records); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "valid_cca_counters_bitmap = 0x%x", +- htt_stats_buf->valid_cca_counters_bitmap); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "collection_interval = %u\n", +- htt_stats_buf->collection_interval); +- +- len += HTT_DBG_OUT(buf + len, buf_len - len, +- "HTT_PDEV_STATS_CCA_COUNTERS_TLV:(in usec)"); +- len += HTT_DBG_OUT(buf + len, buf_len - len, +- "| tx_frame| rx_frame| rx_clear| my_rx_frame| cnt| med_rx_idle| med_tx_idle_global| cca_obss|"); ++ len += scnprintf(buf + len, buf_len - len, "\nHTT_PDEV_CCA_STATS_HIST_TLV:\n"); ++ len += scnprintf(buf + len, buf_len - len, "chan_num = %u\n", ++ htt_stats_buf->chan_num); ++ len += scnprintf(buf + len, buf_len - len, "num_records = %u\n", ++ htt_stats_buf->num_records); ++ len += scnprintf(buf + len, buf_len - len, "valid_cca_counters_bitmap = 0x%x\n", ++ htt_stats_buf->valid_cca_counters_bitmap); ++ len += scnprintf(buf + len, buf_len - len, "collection_interval = %u\n\n", ++ htt_stats_buf->collection_interval); ++ ++ len += scnprintf(buf + len, buf_len - len, ++ "HTT_PDEV_STATS_CCA_COUNTERS_TLV:(in usec)\n"); ++ len += scnprintf(buf + len, buf_len - len, ++ "| tx_frame| rx_frame| rx_clear| my_rx_frame| cnt| med_rx_idle| med_tx_idle_global| cca_obss|\n"); + + if (len >= buf_len) + buf[buf_len - 1] = 0; +@@ -3708,16 +3704,16 @@ htt_print_pdev_stats_cca_counters_tlv(co + u32 len = stats_req->buf_len; + u32 buf_len = ATH11K_HTT_STATS_BUF_SIZE; + +- len += HTT_DBG_OUT(buf + len, buf_len - len, +- "|%10u| %10u| %10u| %11u| %10u| %11u| %18u| %10u|", +- htt_stats_buf->tx_frame_usec, +- htt_stats_buf->rx_frame_usec, +- htt_stats_buf->rx_clear_usec, +- htt_stats_buf->my_rx_frame_usec, +- htt_stats_buf->usec_cnt, +- htt_stats_buf->med_rx_idle_usec, +- htt_stats_buf->med_tx_idle_global_usec, +- htt_stats_buf->cca_obss_usec); ++ len += scnprintf(buf + len, buf_len - len, ++ "|%10u| %10u| %10u| %11u| %10u| %11u| %18u| %10u|\n", ++ htt_stats_buf->tx_frame_usec, ++ htt_stats_buf->rx_frame_usec, ++ htt_stats_buf->rx_clear_usec, ++ htt_stats_buf->my_rx_frame_usec, ++ htt_stats_buf->usec_cnt, ++ htt_stats_buf->med_rx_idle_usec, ++ htt_stats_buf->med_tx_idle_global_usec, ++ htt_stats_buf->cca_obss_usec); + + if (len >= buf_len) + buf[buf_len - 1] = 0; +@@ -3735,32 +3731,32 @@ static inline void htt_print_hw_stats_wh + u32 len = stats_req->buf_len; + u32 buf_len = ATH11K_HTT_STATS_BUF_SIZE; + +- len += HTT_DBG_OUT(buf + len, buf_len - len, "HTT_HW_STATS_WHAL_TX_TLV:"); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "mac_id = %u", +- htt_stats_buf->mac_id__word & 0xFF); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "last_unpause_ppdu_id = %u", +- htt_stats_buf->last_unpause_ppdu_id); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "hwsch_unpause_wait_tqm_write = %u", +- htt_stats_buf->hwsch_unpause_wait_tqm_write); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "hwsch_dummy_tlv_skipped = %u", +- htt_stats_buf->hwsch_dummy_tlv_skipped); +- len += HTT_DBG_OUT(buf + len, buf_len - len, +- "hwsch_misaligned_offset_received = %u", +- htt_stats_buf->hwsch_misaligned_offset_received); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "hwsch_reset_count = %u", +- htt_stats_buf->hwsch_reset_count); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "hwsch_dev_reset_war = %u", +- htt_stats_buf->hwsch_dev_reset_war); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "hwsch_delayed_pause = %u", +- htt_stats_buf->hwsch_delayed_pause); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "hwsch_long_delayed_pause = %u", +- htt_stats_buf->hwsch_long_delayed_pause); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "sch_rx_ppdu_no_response = %u", +- htt_stats_buf->sch_rx_ppdu_no_response); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "sch_selfgen_response = %u", +- htt_stats_buf->sch_selfgen_response); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "sch_rx_sifs_resp_trigger= %u\n", +- htt_stats_buf->sch_rx_sifs_resp_trigger); ++ len += scnprintf(buf + len, buf_len - len, "HTT_HW_STATS_WHAL_TX_TLV:\n"); ++ len += scnprintf(buf + len, buf_len - len, "mac_id = %u\n", ++ htt_stats_buf->mac_id__word & 0xFF); ++ len += scnprintf(buf + len, buf_len - len, "last_unpause_ppdu_id = %u\n", ++ htt_stats_buf->last_unpause_ppdu_id); ++ len += scnprintf(buf + len, buf_len - len, "hwsch_unpause_wait_tqm_write = %u\n", ++ htt_stats_buf->hwsch_unpause_wait_tqm_write); ++ len += scnprintf(buf + len, buf_len - len, "hwsch_dummy_tlv_skipped = %u\n", ++ htt_stats_buf->hwsch_dummy_tlv_skipped); ++ len += scnprintf(buf + len, buf_len - len, ++ "hwsch_misaligned_offset_received = %u\n", ++ htt_stats_buf->hwsch_misaligned_offset_received); ++ len += scnprintf(buf + len, buf_len - len, "hwsch_reset_count = %u\n", ++ htt_stats_buf->hwsch_reset_count); ++ len += scnprintf(buf + len, buf_len - len, "hwsch_dev_reset_war = %u\n", ++ htt_stats_buf->hwsch_dev_reset_war); ++ len += scnprintf(buf + len, buf_len - len, "hwsch_delayed_pause = %u\n", ++ htt_stats_buf->hwsch_delayed_pause); ++ len += scnprintf(buf + len, buf_len - len, "hwsch_long_delayed_pause = %u\n", ++ htt_stats_buf->hwsch_long_delayed_pause); ++ len += scnprintf(buf + len, buf_len - len, "sch_rx_ppdu_no_response = %u\n", ++ htt_stats_buf->sch_rx_ppdu_no_response); ++ len += scnprintf(buf + len, buf_len - len, "sch_selfgen_response = %u\n", ++ htt_stats_buf->sch_selfgen_response); ++ len += scnprintf(buf + len, buf_len - len, "sch_rx_sifs_resp_trigger= %u\n\n", ++ htt_stats_buf->sch_rx_sifs_resp_trigger); + + if (len >= buf_len) + buf[buf_len - 1] = 0; +@@ -3779,11 +3775,11 @@ htt_print_pdev_stats_twt_sessions_tlv(co + u32 len = stats_req->buf_len; + u32 buf_len = ATH11K_HTT_STATS_BUF_SIZE; + +- len += HTT_DBG_OUT(buf + len, buf_len - len, "HTT_PDEV_STATS_TWT_SESSIONS_TLV:"); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "pdev_id = %u", +- htt_stats_buf->pdev_id); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "num_sessions = %u\n", +- htt_stats_buf->num_sessions); ++ len += scnprintf(buf + len, buf_len - len, "HTT_PDEV_STATS_TWT_SESSIONS_TLV:\n"); ++ len += scnprintf(buf + len, buf_len - len, "pdev_id = %u\n", ++ htt_stats_buf->pdev_id); ++ len += scnprintf(buf + len, buf_len - len, "num_sessions = %u\n\n", ++ htt_stats_buf->num_sessions); + + if (len >= buf_len) + buf[buf_len - 1] = 0; +@@ -3802,27 +3798,27 @@ htt_print_pdev_stats_twt_session_tlv(con + u32 len = stats_req->buf_len; + u32 buf_len = ATH11K_HTT_STATS_BUF_SIZE; + +- len += HTT_DBG_OUT(buf + len, buf_len - len, "HTT_PDEV_STATS_TWT_SESSION_TLV:"); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "vdev_id = %u", +- htt_stats_buf->vdev_id); +- len += HTT_DBG_OUT(buf + len, buf_len - len, +- "peer_mac = %02x:%02x:%02x:%02x:%02x:%02x", +- htt_stats_buf->peer_mac.mac_addr_l32 & 0xFF, +- (htt_stats_buf->peer_mac.mac_addr_l32 & 0xFF00) >> 8, +- (htt_stats_buf->peer_mac.mac_addr_l32 & 0xFF0000) >> 16, +- (htt_stats_buf->peer_mac.mac_addr_l32 & 0xFF000000) >> 24, +- (htt_stats_buf->peer_mac.mac_addr_h16 & 0xFF), +- (htt_stats_buf->peer_mac.mac_addr_h16 & 0xFF00) >> 8); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "flow_id_flags = %u", +- htt_stats_buf->flow_id_flags); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "dialog_id = %u", +- htt_stats_buf->dialog_id); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "wake_dura_us = %u", +- htt_stats_buf->wake_dura_us); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "wake_intvl_us = %u", +- htt_stats_buf->wake_intvl_us); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "sp_offset_us = %u\n", +- htt_stats_buf->sp_offset_us); ++ len += scnprintf(buf + len, buf_len - len, "HTT_PDEV_STATS_TWT_SESSION_TLV:\n"); ++ len += scnprintf(buf + len, buf_len - len, "vdev_id = %u\n", ++ htt_stats_buf->vdev_id); ++ len += scnprintf(buf + len, buf_len - len, ++ "peer_mac = %02x:%02x:%02x:%02x:%02x:%02x\n", ++ htt_stats_buf->peer_mac.mac_addr_l32 & 0xFF, ++ (htt_stats_buf->peer_mac.mac_addr_l32 & 0xFF00) >> 8, ++ (htt_stats_buf->peer_mac.mac_addr_l32 & 0xFF0000) >> 16, ++ (htt_stats_buf->peer_mac.mac_addr_l32 & 0xFF000000) >> 24, ++ (htt_stats_buf->peer_mac.mac_addr_h16 & 0xFF), ++ (htt_stats_buf->peer_mac.mac_addr_h16 & 0xFF00) >> 8); ++ len += scnprintf(buf + len, buf_len - len, "flow_id_flags = %u\n", ++ htt_stats_buf->flow_id_flags); ++ len += scnprintf(buf + len, buf_len - len, "dialog_id = %u\n", ++ htt_stats_buf->dialog_id); ++ len += scnprintf(buf + len, buf_len - len, "wake_dura_us = %u\n", ++ htt_stats_buf->wake_dura_us); ++ len += scnprintf(buf + len, buf_len - len, "wake_intvl_us = %u\n", ++ htt_stats_buf->wake_intvl_us); ++ len += scnprintf(buf + len, buf_len - len, "sp_offset_us = %u\n\n", ++ htt_stats_buf->sp_offset_us); + + if (len >= buf_len) + buf[buf_len - 1] = 0; +@@ -3841,21 +3837,21 @@ htt_print_pdev_obss_pd_stats_tlv_v(const + u32 len = stats_req->buf_len; + u32 buf_len = ATH11K_HTT_STATS_BUF_SIZE; + +- len += HTT_DBG_OUT(buf + len, buf_len - len, "OBSS Tx success PPDU = %u", ++ len += scnprintf(buf + len, buf_len - len, "OBSS Tx success PPDU = %u\n", + htt_stats_buf->num_obss_tx_ppdu_success); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "OBSS Tx failures PPDU = %u\n", ++ len += scnprintf(buf + len, buf_len - len, "OBSS Tx failures PPDU = %u\n", + htt_stats_buf->num_obss_tx_ppdu_failure); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "Non-SRG Opportunities = %u\n", ++ len += scnprintf(buf + len, buf_len - len, "Non-SRG Opportunities = %u\n", + htt_stats_buf->num_non_srg_opportunities); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "Non-SRG tried PPDU = %u\n", ++ len += scnprintf(buf + len, buf_len - len, "Non-SRG tried PPDU = %u\n", + htt_stats_buf->num_non_srg_ppdu_tried); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "Non-SRG success PPDU = %u\n", ++ len += scnprintf(buf + len, buf_len - len, "Non-SRG success PPDU = %u\n", + htt_stats_buf->num_non_srg_ppdu_success); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "SRG Opportunities = %u\n", ++ len += scnprintf(buf + len, buf_len - len, "SRG Opportunities = %u\n", + htt_stats_buf->num_srg_opportunities); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "SRG tried PPDU = %u\n", ++ len += scnprintf(buf + len, buf_len - len, "SRG tried PPDU = %u\n", + htt_stats_buf->num_srg_ppdu_tried); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "SRG success PPDU = %u\n", ++ len += scnprintf(buf + len, buf_len - len, "SRG success PPDU = %u\n\n", + htt_stats_buf->num_srg_ppdu_success); + + if (len >= buf_len) +@@ -3878,25 +3874,25 @@ static inline void htt_print_backpressur + u32 len = stats_req->buf_len; + u32 buf_len = ATH11K_HTT_STATS_BUF_SIZE; + +- len += HTT_DBG_OUT(buf + len, buf_len - len, "pdev_id = %u", +- htt_stats_buf->pdev_id); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "current_head_idx = %u", +- htt_stats_buf->current_head_idx); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "current_tail_idx = %u", +- htt_stats_buf->current_tail_idx); +- len += HTT_DBG_OUT(buf + len, buf_len - len, "num_htt_msgs_sent = %u", +- htt_stats_buf->num_htt_msgs_sent); +- len += HTT_DBG_OUT(buf + len, buf_len - len, +- "backpressure_time_ms = %u", +- htt_stats_buf->backpressure_time_ms); ++ len += scnprintf(buf + len, buf_len - len, "pdev_id = %u\n", ++ htt_stats_buf->pdev_id); ++ len += scnprintf(buf + len, buf_len - len, "current_head_idx = %u\n", ++ htt_stats_buf->current_head_idx); ++ len += scnprintf(buf + len, buf_len - len, "current_tail_idx = %u\n", ++ htt_stats_buf->current_tail_idx); ++ len += scnprintf(buf + len, buf_len - len, "num_htt_msgs_sent = %u\n", ++ htt_stats_buf->num_htt_msgs_sent); ++ len += scnprintf(buf + len, buf_len - len, ++ "backpressure_time_ms = %u\n", ++ htt_stats_buf->backpressure_time_ms); + + for (i = 0; i < 5; i++) +- len += HTT_DBG_OUT(buf + len, buf_len - len, +- "backpressure_hist_%u = %u", +- i + 1, htt_stats_buf->backpressure_hist[i]); ++ len += scnprintf(buf + len, buf_len - len, ++ "backpressure_hist_%u = %u\n", ++ i + 1, htt_stats_buf->backpressure_hist[i]); + +- len += HTT_DBG_OUT(buf + len, buf_len - len, +- "============================"); ++ len += scnprintf(buf + len, buf_len - len, ++ "============================\n"); + + if (len >= buf_len) { + buf[buf_len - 1] = 0; diff --git a/package/kernel/mac80211/patches/ath11k/0045-ath11k-Remove-htt-stats-fixed-size-array-usage.patch b/package/kernel/mac80211/patches/ath11k/0045-ath11k-Remove-htt-stats-fixed-size-array-usage.patch new file mode 100644 index 000000000..40a197022 --- /dev/null +++ b/package/kernel/mac80211/patches/ath11k/0045-ath11k-Remove-htt-stats-fixed-size-array-usage.patch @@ -0,0 +1,1451 @@ +From 74327bab6781a34d96ff4c0a7c59bb032fab1650 Mon Sep 17 00:00:00 2001 +From: Seevalamuthu Mariappan +Date: Tue, 28 Sep 2021 14:00:45 +0300 +Subject: [PATCH 045/120] ath11k: Remove htt stats fixed size array usage + +To support the HTT Stats DebugFS interface a single large buffer that +contains the stats must be provided to the DebugFS infrastructure. +In the current code, for each class of stats, the stats are first +formatted in a local on-stack buffer, and then the local buffer is +copied to the large DebugFS buffer. + +This logic has a problem when, for a given class, the formatted +stats exceed the size of the on-stack buffer. When this occurs the +stats for this class is truncated. In addition, this logic is +inefficient since it introduces an unnecessary memory copy. + +To address these issues, update the logic to no longer use a local +on-stack buffer, and instead write the formatted data directly into +the large DebugFS buffer. + +Tested-on: IPQ8074 hw2.0 AHB WLAN.HK.2.5.0.1-01105-QCAHKSWPL_SILICONZ-1 + +Signed-off-by: Seevalamuthu Mariappan +Signed-off-by: Jouni Malinen +Signed-off-by: Kalle Valo +Link: https://lore.kernel.org/r/20210913223148.208026-4-jouni@codeaurora.org +--- + .../wireless/ath/ath11k/debugfs_htt_stats.c | 838 ++++++------------ + 1 file changed, 264 insertions(+), 574 deletions(-) + +--- a/drivers/net/wireless/ath/ath11k/debugfs_htt_stats.c ++++ b/drivers/net/wireless/ath/ath11k/debugfs_htt_stats.c +@@ -10,20 +10,28 @@ + #include "debug.h" + #include "debugfs_htt_stats.h" + +-#define HTT_MAX_STRING_LEN 256 + #define HTT_MAX_PRINT_CHAR_PER_ELEM 15 + + #define HTT_TLV_HDR_LEN 4 + +-#define PRINT_ARRAY_TO_BUF(out, arr, len) \ ++#define PRINT_ARRAY_TO_BUF(out, buflen, arr, str, len, newline) \ + do { \ +- int index = 0; u8 i; \ ++ int index = 0; u8 i; const char *str_val = str; \ ++ const char *new_line = newline; \ ++ if (str_val) { \ ++ index += scnprintf((out + buflen), \ ++ (ATH11K_HTT_STATS_BUF_SIZE - buflen), \ ++ "%s = ", str_val); \ ++ } \ + for (i = 0; i < len; i++) { \ +- index += scnprintf(out + index, HTT_MAX_STRING_LEN - index, \ +- " %u:%u,", i, arr[i]); \ +- if (index < 0 || index >= HTT_MAX_STRING_LEN) \ +- break; \ ++ index += scnprintf((out + buflen) + index, \ ++ (ATH11K_HTT_STATS_BUF_SIZE - buflen) - index, \ ++ " %u:%u,", i, arr[i]); \ + } \ ++ index += scnprintf((out + buflen) + index, \ ++ (ATH11K_HTT_STATS_BUF_SIZE - buflen) - index, \ ++ "%s", new_line); \ ++ buflen += index; \ + } while (0) + + static inline void htt_print_stats_string_tlv(const void *tag_buf, +@@ -35,22 +43,20 @@ static inline void htt_print_stats_strin + u32 len = stats_req->buf_len; + u32 buf_len = ATH11K_HTT_STATS_BUF_SIZE; + u8 i; +- u16 index = 0; +- char data[HTT_MAX_STRING_LEN] = {0}; + + tag_len = tag_len >> 2; + + len += scnprintf(buf + len, buf_len - len, "HTT_STATS_STRING_TLV:\n"); + ++ len += scnprintf(buf + len, buf_len - len, ++ "data = "); + for (i = 0; i < tag_len; i++) { +- index += scnprintf(&data[index], +- HTT_MAX_STRING_LEN - index, +- "%.*s", 4, (char *)&(htt_stats_buf->data[i])); +- if (index >= HTT_MAX_STRING_LEN) +- break; ++ len += scnprintf(buf + len, ++ buf_len - len, ++ "%.*s", 4, (char *)&(htt_stats_buf->data[i])); + } +- +- len += scnprintf(buf + len, buf_len - len, "data = %s\n\n", data); ++ /* New lines are added for better display */ ++ len += scnprintf(buf + len, buf_len - len, "\n\n"); + + if (len >= buf_len) + buf[buf_len - 1] = 0; +@@ -187,13 +193,12 @@ htt_print_tx_pdev_stats_urrn_tlv_v(const + u8 *buf = stats_req->buf; + u32 len = stats_req->buf_len; + u32 buf_len = ATH11K_HTT_STATS_BUF_SIZE; +- char urrn_stats[HTT_MAX_STRING_LEN] = {0}; + u16 num_elems = min_t(u16, (tag_len >> 2), HTT_TX_PDEV_MAX_URRN_STATS); + + len += scnprintf(buf + len, buf_len - len, "HTT_TX_PDEV_STATS_URRN_TLV_V:\n"); + +- PRINT_ARRAY_TO_BUF(urrn_stats, htt_stats_buf->urrn_stats, num_elems); +- len += scnprintf(buf + len, buf_len - len, "urrn_stats = %s\n\n", urrn_stats); ++ PRINT_ARRAY_TO_BUF(buf, len, htt_stats_buf->urrn_stats, "urrn_stats", ++ num_elems, "\n\n"); + + if (len >= buf_len) + buf[buf_len - 1] = 0; +@@ -212,13 +217,12 @@ htt_print_tx_pdev_stats_flush_tlv_v(cons + u8 *buf = stats_req->buf; + u32 len = stats_req->buf_len; + u32 buf_len = ATH11K_HTT_STATS_BUF_SIZE; +- char flush_errs[HTT_MAX_STRING_LEN] = {0}; + u16 num_elems = min_t(u16, (tag_len >> 2), HTT_TX_PDEV_MAX_FLUSH_REASON_STATS); + + len += scnprintf(buf + len, buf_len - len, "HTT_TX_PDEV_STATS_FLUSH_TLV_V:\n"); + +- PRINT_ARRAY_TO_BUF(flush_errs, htt_stats_buf->flush_errs, num_elems); +- len += scnprintf(buf + len, buf_len - len, "flush_errs = %s\n\n", flush_errs); ++ PRINT_ARRAY_TO_BUF(buf, len, htt_stats_buf->flush_errs, "flush_errs", ++ num_elems, "\n\n"); + + if (len >= buf_len) + buf[buf_len - 1] = 0; +@@ -237,14 +241,12 @@ htt_print_tx_pdev_stats_sifs_tlv_v(const + u8 *buf = stats_req->buf; + u32 len = stats_req->buf_len; + u32 buf_len = ATH11K_HTT_STATS_BUF_SIZE; +- char sifs_status[HTT_MAX_STRING_LEN] = {0}; + u16 num_elems = min_t(u16, (tag_len >> 2), HTT_TX_PDEV_MAX_SIFS_BURST_STATS); + + len += scnprintf(buf + len, buf_len - len, "HTT_TX_PDEV_STATS_SIFS_TLV_V:\n"); + +- PRINT_ARRAY_TO_BUF(sifs_status, htt_stats_buf->sifs_status, num_elems); +- len += scnprintf(buf + len, buf_len - len, "sifs_status = %s\n\n", +- sifs_status); ++ PRINT_ARRAY_TO_BUF(buf, len, htt_stats_buf->sifs_status, "sifs_status", ++ num_elems, "\n\n"); + + if (len >= buf_len) + buf[buf_len - 1] = 0; +@@ -263,13 +265,12 @@ htt_print_tx_pdev_stats_phy_err_tlv_v(co + u8 *buf = stats_req->buf; + u32 len = stats_req->buf_len; + u32 buf_len = ATH11K_HTT_STATS_BUF_SIZE; +- char phy_errs[HTT_MAX_STRING_LEN] = {0}; + u16 num_elems = min_t(u16, (tag_len >> 2), HTT_TX_PDEV_MAX_PHY_ERR_STATS); + + len += scnprintf(buf + len, buf_len - len, "HTT_TX_PDEV_STATS_PHY_ERR_TLV_V:\n"); + +- PRINT_ARRAY_TO_BUF(phy_errs, htt_stats_buf->phy_errs, num_elems); +- len += scnprintf(buf + len, buf_len - len, "phy_errs = %s\n\n", phy_errs); ++ PRINT_ARRAY_TO_BUF(buf, len, htt_stats_buf->phy_errs, "phy_errs", ++ num_elems, "\n\n"); + + if (len >= buf_len) + buf[buf_len - 1] = 0; +@@ -288,15 +289,13 @@ htt_print_tx_pdev_stats_sifs_hist_tlv_v( + u8 *buf = stats_req->buf; + u32 len = stats_req->buf_len; + u32 buf_len = ATH11K_HTT_STATS_BUF_SIZE; +- char sifs_hist_status[HTT_MAX_STRING_LEN] = {0}; + u16 num_elems = min_t(u16, (tag_len >> 2), HTT_TX_PDEV_MAX_SIFS_BURST_HIST_STATS); + + len += scnprintf(buf + len, buf_len - len, + "HTT_TX_PDEV_STATS_SIFS_HIST_TLV_V:\n"); + +- PRINT_ARRAY_TO_BUF(sifs_hist_status, htt_stats_buf->sifs_hist_status, num_elems); +- len += scnprintf(buf + len, buf_len - len, "sifs_hist_status = %s\n\n", +- sifs_hist_status); ++ PRINT_ARRAY_TO_BUF(buf, len, htt_stats_buf->sifs_hist_status, ++ "sifs_hist_status", num_elems, "\n\n"); + + if (len >= buf_len) + buf[buf_len - 1] = 0; +@@ -350,25 +349,15 @@ htt_print_tx_pdev_stats_tried_mpdu_cnt_h + u8 *buf = stats_req->buf; + u32 len = stats_req->buf_len; + u32 buf_len = ATH11K_HTT_STATS_BUF_SIZE; +- char tried_mpdu_cnt_hist[HTT_MAX_STRING_LEN] = {0}; + u32 num_elements = ((tag_len - sizeof(htt_stats_buf->hist_bin_size)) >> 2); +- u32 required_buffer_size = HTT_MAX_PRINT_CHAR_PER_ELEM * num_elements; + + len += scnprintf(buf + len, buf_len - len, + "HTT_TX_PDEV_STATS_TRIED_MPDU_CNT_HIST_TLV_V:\n"); + len += scnprintf(buf + len, buf_len - len, "TRIED_MPDU_CNT_HIST_BIN_SIZE : %u\n", + htt_stats_buf->hist_bin_size); + +- if (required_buffer_size < HTT_MAX_STRING_LEN) { +- PRINT_ARRAY_TO_BUF(tried_mpdu_cnt_hist, +- htt_stats_buf->tried_mpdu_cnt_hist, +- num_elements); +- len += scnprintf(buf + len, buf_len - len, "tried_mpdu_cnt_hist = %s\n\n", +- tried_mpdu_cnt_hist); +- } else { +- len += scnprintf(buf + len, buf_len - len, +- "INSUFFICIENT PRINT BUFFER\n\n"); +- } ++ PRINT_ARRAY_TO_BUF(buf, len, htt_stats_buf->tried_mpdu_cnt_hist, ++ "tried_mpdu_cnt_hist", num_elements, "\n\n"); + + if (len >= buf_len) + buf[buf_len - 1] = 0; +@@ -659,14 +648,12 @@ static inline void htt_print_counter_tlv + u8 *buf = stats_req->buf; + u32 len = stats_req->buf_len; + u32 buf_len = ATH11K_HTT_STATS_BUF_SIZE; +- char counter_name[HTT_MAX_STRING_LEN] = {0}; + + len += scnprintf(buf + len, buf_len - len, "HTT_COUNTER_TLV:\n"); + +- PRINT_ARRAY_TO_BUF(counter_name, +- htt_stats_buf->counter_name, +- HTT_MAX_COUNTER_NAME); +- len += scnprintf(buf + len, buf_len - len, "counter_name = %s\n", counter_name); ++ PRINT_ARRAY_TO_BUF(buf, len, htt_stats_buf->counter_name, ++ "counter_name", ++ HTT_MAX_COUNTER_NAME, "\n"); + len += scnprintf(buf + len, buf_len - len, "count = %u\n\n", + htt_stats_buf->count); + +@@ -771,16 +758,8 @@ static inline void htt_print_tx_peer_rat + u8 *buf = stats_req->buf; + u32 len = stats_req->buf_len; + u32 buf_len = ATH11K_HTT_STATS_BUF_SIZE; +- char str_buf[HTT_MAX_STRING_LEN] = {0}; +- char *tx_gi[HTT_TX_PEER_STATS_NUM_GI_COUNTERS] = {NULL}; + u8 j; + +- for (j = 0; j < HTT_TX_PEER_STATS_NUM_GI_COUNTERS; j++) { +- tx_gi[j] = kmalloc(HTT_MAX_STRING_LEN, GFP_ATOMIC); +- if (!tx_gi[j]) +- goto fail; +- } +- + len += scnprintf(buf + len, buf_len - len, "HTT_TX_PEER_RATE_STATS_TLV:\n"); + len += scnprintf(buf + len, buf_len - len, "tx_ldpc = %u\n", + htt_stats_buf->tx_ldpc); +@@ -789,56 +768,30 @@ static inline void htt_print_tx_peer_rat + len += scnprintf(buf + len, buf_len - len, "ack_rssi = %u\n", + htt_stats_buf->ack_rssi); + +- memset(str_buf, 0x0, HTT_MAX_STRING_LEN); +- PRINT_ARRAY_TO_BUF(str_buf, htt_stats_buf->tx_mcs, +- HTT_TX_PDEV_STATS_NUM_MCS_COUNTERS); +- len += scnprintf(buf + len, buf_len - len, "tx_mcs = %s\n", str_buf); +- +- memset(str_buf, 0x0, HTT_MAX_STRING_LEN); +- PRINT_ARRAY_TO_BUF(str_buf, htt_stats_buf->tx_su_mcs, +- HTT_TX_PDEV_STATS_NUM_MCS_COUNTERS); +- len += scnprintf(buf + len, buf_len - len, "tx_su_mcs = %s\n", str_buf); +- +- memset(str_buf, 0x0, HTT_MAX_STRING_LEN); +- PRINT_ARRAY_TO_BUF(str_buf, htt_stats_buf->tx_mu_mcs, +- HTT_TX_PDEV_STATS_NUM_MCS_COUNTERS); +- len += scnprintf(buf + len, buf_len - len, "tx_mu_mcs = %s\n", str_buf); +- +- memset(str_buf, 0x0, HTT_MAX_STRING_LEN); +- PRINT_ARRAY_TO_BUF(str_buf, +- htt_stats_buf->tx_nss, +- HTT_TX_PDEV_STATS_NUM_SPATIAL_STREAMS); +- len += scnprintf(buf + len, buf_len - len, "tx_nss = %s\n", str_buf); +- +- memset(str_buf, 0x0, HTT_MAX_STRING_LEN); +- PRINT_ARRAY_TO_BUF(str_buf, +- htt_stats_buf->tx_bw, +- HTT_TX_PDEV_STATS_NUM_BW_COUNTERS); +- len += scnprintf(buf + len, buf_len - len, "tx_bw = %s\n", str_buf); +- +- memset(str_buf, 0x0, HTT_MAX_STRING_LEN); +- PRINT_ARRAY_TO_BUF(str_buf, htt_stats_buf->tx_stbc, +- HTT_TX_PDEV_STATS_NUM_MCS_COUNTERS); +- len += scnprintf(buf + len, buf_len - len, "tx_stbc = %s\n", str_buf); +- +- memset(str_buf, 0x0, HTT_MAX_STRING_LEN); +- PRINT_ARRAY_TO_BUF(str_buf, htt_stats_buf->tx_pream, +- HTT_TX_PDEV_STATS_NUM_PREAMBLE_TYPES); +- len += scnprintf(buf + len, buf_len - len, "tx_pream = %s\n", str_buf); ++ PRINT_ARRAY_TO_BUF(buf, len, htt_stats_buf->tx_mcs, "tx_mcs", ++ HTT_TX_PDEV_STATS_NUM_MCS_COUNTERS, "\n"); ++ PRINT_ARRAY_TO_BUF(buf, len, htt_stats_buf->tx_su_mcs, "tx_su_mcs", ++ HTT_TX_PDEV_STATS_NUM_MCS_COUNTERS, "\n"); ++ PRINT_ARRAY_TO_BUF(buf, len, htt_stats_buf->tx_mu_mcs, "tx_mu_mcs", ++ HTT_TX_PDEV_STATS_NUM_MCS_COUNTERS, "\n"); ++ PRINT_ARRAY_TO_BUF(buf, len, htt_stats_buf->tx_nss, "tx_nss", ++ HTT_TX_PDEV_STATS_NUM_SPATIAL_STREAMS, "\n"); ++ PRINT_ARRAY_TO_BUF(buf, len, htt_stats_buf->tx_bw, "tx_bw", ++ HTT_TX_PDEV_STATS_NUM_BW_COUNTERS, "\n"); ++ PRINT_ARRAY_TO_BUF(buf, len, htt_stats_buf->tx_stbc, "tx_stbc", ++ HTT_TX_PDEV_STATS_NUM_MCS_COUNTERS, "\n"); ++ PRINT_ARRAY_TO_BUF(buf, len, htt_stats_buf->tx_pream, "tx_pream", ++ HTT_TX_PDEV_STATS_NUM_PREAMBLE_TYPES, "\n"); + + for (j = 0; j < HTT_TX_PEER_STATS_NUM_GI_COUNTERS; j++) { +- PRINT_ARRAY_TO_BUF(tx_gi[j], +- htt_stats_buf->tx_gi[j], +- HTT_TX_PEER_STATS_NUM_MCS_COUNTERS); +- len += scnprintf(buf + len, buf_len - len, "tx_gi[%u] = %s\n", +- j, tx_gi[j]); ++ len += scnprintf(buf + len, buf_len - len, ++ "tx_gi[%u] = ", j); ++ PRINT_ARRAY_TO_BUF(buf, len, htt_stats_buf->tx_gi[j], NULL, ++ HTT_TX_PEER_STATS_NUM_MCS_COUNTERS, "\n"); + } + +- memset(str_buf, 0x0, HTT_MAX_STRING_LEN); +- PRINT_ARRAY_TO_BUF(str_buf, +- htt_stats_buf->tx_dcm, +- HTT_TX_PDEV_STATS_NUM_DCM_COUNTERS); +- len += scnprintf(buf + len, buf_len - len, "tx_dcm = %s\n\n", str_buf); ++ PRINT_ARRAY_TO_BUF(buf, len, htt_stats_buf->tx_dcm, "tx_dcm", ++ HTT_TX_PDEV_STATS_NUM_DCM_COUNTERS, "\n\n"); + + if (len >= buf_len) + buf[buf_len - 1] = 0; +@@ -847,9 +800,6 @@ static inline void htt_print_tx_peer_rat + + stats_req->buf_len = len; + +-fail: +- for (j = 0; j < HTT_TX_PEER_STATS_NUM_GI_COUNTERS; j++) +- kfree(tx_gi[j]); + } + + static inline void htt_print_rx_peer_rate_stats_tlv(const void *tag_buf, +@@ -860,21 +810,6 @@ static inline void htt_print_rx_peer_rat + u32 len = stats_req->buf_len; + u32 buf_len = ATH11K_HTT_STATS_BUF_SIZE; + u8 j; +- char *rssi_chain[HTT_RX_PEER_STATS_NUM_SPATIAL_STREAMS] = {NULL}; +- char *rx_gi[HTT_RX_PEER_STATS_NUM_GI_COUNTERS] = {NULL}; +- char str_buf[HTT_MAX_STRING_LEN] = {0}; +- +- for (j = 0; j < HTT_RX_PEER_STATS_NUM_SPATIAL_STREAMS; j++) { +- rssi_chain[j] = kmalloc(HTT_MAX_STRING_LEN, GFP_ATOMIC); +- if (!rssi_chain[j]) +- goto fail; +- } +- +- for (j = 0; j < HTT_RX_PEER_STATS_NUM_GI_COUNTERS; j++) { +- rx_gi[j] = kmalloc(HTT_MAX_STRING_LEN, GFP_ATOMIC); +- if (!rx_gi[j]) +- goto fail; +- } + + len += scnprintf(buf + len, buf_len - len, "HTT_RX_PEER_RATE_STATS_TLV:\n"); + len += scnprintf(buf + len, buf_len - len, "nsts = %u\n", +@@ -890,49 +825,33 @@ static inline void htt_print_rx_peer_rat + len += scnprintf(buf + len, buf_len - len, "rssi_comb = %u\n", + htt_stats_buf->rssi_comb); + +- memset(str_buf, 0x0, HTT_MAX_STRING_LEN); +- PRINT_ARRAY_TO_BUF(str_buf, htt_stats_buf->rx_mcs, +- HTT_RX_PDEV_STATS_NUM_MCS_COUNTERS); +- len += scnprintf(buf + len, buf_len - len, "rx_mcs = %s\n", str_buf); +- +- memset(str_buf, 0x0, HTT_MAX_STRING_LEN); +- PRINT_ARRAY_TO_BUF(str_buf, htt_stats_buf->rx_nss, +- HTT_RX_PDEV_STATS_NUM_SPATIAL_STREAMS); +- len += scnprintf(buf + len, buf_len - len, "rx_nss = %s\n", str_buf); +- +- memset(str_buf, 0x0, HTT_MAX_STRING_LEN); +- PRINT_ARRAY_TO_BUF(str_buf, htt_stats_buf->rx_dcm, +- HTT_RX_PDEV_STATS_NUM_DCM_COUNTERS); +- len += scnprintf(buf + len, buf_len - len, "rx_dcm = %s\n", str_buf); +- +- memset(str_buf, 0x0, HTT_MAX_STRING_LEN); +- PRINT_ARRAY_TO_BUF(str_buf, htt_stats_buf->rx_stbc, +- HTT_RX_PDEV_STATS_NUM_MCS_COUNTERS); +- len += scnprintf(buf + len, buf_len - len, "rx_stbc = %s\n", str_buf); +- +- memset(str_buf, 0x0, HTT_MAX_STRING_LEN); +- PRINT_ARRAY_TO_BUF(str_buf, htt_stats_buf->rx_bw, +- HTT_RX_PDEV_STATS_NUM_BW_COUNTERS); +- len += scnprintf(buf + len, buf_len - len, "rx_bw = %s\n", str_buf); ++ PRINT_ARRAY_TO_BUF(buf, len, htt_stats_buf->rx_mcs, "rx_mcs", ++ HTT_RX_PDEV_STATS_NUM_MCS_COUNTERS, "\n"); ++ PRINT_ARRAY_TO_BUF(buf, len, htt_stats_buf->rx_nss, "rx_nss", ++ HTT_RX_PDEV_STATS_NUM_SPATIAL_STREAMS, "\n"); ++ PRINT_ARRAY_TO_BUF(buf, len, htt_stats_buf->rx_dcm, "rx_dcm", ++ HTT_RX_PDEV_STATS_NUM_DCM_COUNTERS, "\n"); ++ PRINT_ARRAY_TO_BUF(buf, len, htt_stats_buf->rx_stbc, "rx_stbc", ++ HTT_RX_PDEV_STATS_NUM_MCS_COUNTERS, "\n"); ++ PRINT_ARRAY_TO_BUF(buf, len, htt_stats_buf->rx_bw, "rx_bw", ++ HTT_RX_PDEV_STATS_NUM_BW_COUNTERS, "\n"); + + for (j = 0; j < HTT_RX_PEER_STATS_NUM_SPATIAL_STREAMS; j++) { +- PRINT_ARRAY_TO_BUF(rssi_chain[j], htt_stats_buf->rssi_chain[j], +- HTT_RX_PEER_STATS_NUM_BW_COUNTERS); +- len += scnprintf(buf + len, buf_len - len, "rssi_chain[%u] = %s\n", +- j, rssi_chain[j]); ++ len += scnprintf(buf + len, (buf_len - len), ++ "rssi_chain[%u] = ", j); ++ PRINT_ARRAY_TO_BUF(buf, len, htt_stats_buf->rssi_chain[j], NULL, ++ HTT_RX_PEER_STATS_NUM_BW_COUNTERS, "\n"); + } + + for (j = 0; j < HTT_RX_PEER_STATS_NUM_GI_COUNTERS; j++) { +- PRINT_ARRAY_TO_BUF(rx_gi[j], htt_stats_buf->rx_gi[j], +- HTT_RX_PDEV_STATS_NUM_MCS_COUNTERS); +- len += scnprintf(buf + len, buf_len - len, "rx_gi[%u] = %s\n", +- j, rx_gi[j]); ++ len += scnprintf(buf + len, (buf_len - len), ++ "rx_gi[%u] = ", j); ++ PRINT_ARRAY_TO_BUF(buf, len, htt_stats_buf->rx_gi[j], NULL, ++ HTT_RX_PDEV_STATS_NUM_MCS_COUNTERS, "\n"); + } + +- memset(str_buf, 0x0, HTT_MAX_STRING_LEN); +- PRINT_ARRAY_TO_BUF(str_buf, htt_stats_buf->rx_pream, +- HTT_RX_PDEV_STATS_NUM_PREAMBLE_TYPES); +- len += scnprintf(buf + len, buf_len - len, "rx_pream = %s\n\n", str_buf); ++ PRINT_ARRAY_TO_BUF(buf, len, htt_stats_buf->rx_pream, "rx_pream", ++ HTT_RX_PDEV_STATS_NUM_PREAMBLE_TYPES, "\n"); + + if (len >= buf_len) + buf[buf_len - 1] = 0; +@@ -940,13 +859,6 @@ static inline void htt_print_rx_peer_rat + buf[len] = 0; + + stats_req->buf_len = len; +- +-fail: +- for (j = 0; j < HTT_RX_PEER_STATS_NUM_SPATIAL_STREAMS; j++) +- kfree(rssi_chain[j]); +- +- for (j = 0; j < HTT_RX_PEER_STATS_NUM_GI_COUNTERS; j++) +- kfree(rx_gi[j]); + } + + static inline void +@@ -1104,17 +1016,14 @@ htt_print_tx_hwq_difs_latency_stats_tlv_ + u32 len = stats_req->buf_len; + u32 buf_len = ATH11K_HTT_STATS_BUF_SIZE; + u16 data_len = min_t(u16, (tag_len >> 2), HTT_TX_HWQ_MAX_DIFS_LATENCY_BINS); +- char difs_latency_hist[HTT_MAX_STRING_LEN] = {0}; + + len += scnprintf(buf + len, buf_len - len, + "HTT_TX_HWQ_DIFS_LATENCY_STATS_TLV_V:\n"); + len += scnprintf(buf + len, buf_len - len, "hist_intvl = %u\n", + htt_stats_buf->hist_intvl); + +- PRINT_ARRAY_TO_BUF(difs_latency_hist, htt_stats_buf->difs_latency_hist, +- data_len); +- len += scnprintf(buf + len, buf_len - len, "difs_latency_hist = %s\n\n", +- difs_latency_hist); ++ PRINT_ARRAY_TO_BUF(buf, len, htt_stats_buf->difs_latency_hist, ++ "difs_latency_hist", data_len, "\n\n"); + + if (len >= buf_len) + buf[buf_len - 1] = 0; +@@ -1134,16 +1043,14 @@ htt_print_tx_hwq_cmd_result_stats_tlv_v( + u32 len = stats_req->buf_len; + u32 buf_len = ATH11K_HTT_STATS_BUF_SIZE; + u16 data_len; +- char cmd_result[HTT_MAX_STRING_LEN] = {0}; + + data_len = min_t(u16, (tag_len >> 2), HTT_TX_HWQ_MAX_CMD_RESULT_STATS); + + len += scnprintf(buf + len, buf_len - len, + "HTT_TX_HWQ_CMD_RESULT_STATS_TLV_V:\n"); + +- PRINT_ARRAY_TO_BUF(cmd_result, htt_stats_buf->cmd_result, data_len); +- +- len += scnprintf(buf + len, buf_len - len, "cmd_result = %s\n\n", cmd_result); ++ PRINT_ARRAY_TO_BUF(buf, len, htt_stats_buf->cmd_result, "cmd_result", ++ data_len, "\n\n"); + + if (len >= buf_len) + buf[buf_len - 1] = 0; +@@ -1163,15 +1070,13 @@ htt_print_tx_hwq_cmd_stall_stats_tlv_v(c + u32 len = stats_req->buf_len; + u32 buf_len = ATH11K_HTT_STATS_BUF_SIZE; + u16 num_elems; +- char cmd_stall_status[HTT_MAX_STRING_LEN] = {0}; + + num_elems = min_t(u16, (tag_len >> 2), HTT_TX_HWQ_MAX_CMD_STALL_STATS); + + len += scnprintf(buf + len, buf_len - len, "HTT_TX_HWQ_CMD_STALL_STATS_TLV_V:\n"); + +- PRINT_ARRAY_TO_BUF(cmd_stall_status, htt_stats_buf->cmd_stall_status, num_elems); +- len += scnprintf(buf + len, buf_len - len, "cmd_stall_status = %s\n\n", +- cmd_stall_status); ++ PRINT_ARRAY_TO_BUF(buf, len, htt_stats_buf->cmd_stall_status, ++ "cmd_stall_status", num_elems, "\n\n"); + + if (len >= buf_len) + buf[buf_len - 1] = 0; +@@ -1191,15 +1096,14 @@ htt_print_tx_hwq_fes_result_stats_tlv_v( + u32 len = stats_req->buf_len; + u32 buf_len = ATH11K_HTT_STATS_BUF_SIZE; + u16 num_elems; +- char fes_result[HTT_MAX_STRING_LEN] = {0}; + + num_elems = min_t(u16, (tag_len >> 2), HTT_TX_HWQ_MAX_FES_RESULT_STATS); + + len += scnprintf(buf + len, buf_len - len, + "HTT_TX_HWQ_FES_RESULT_STATS_TLV_V:\n"); + +- PRINT_ARRAY_TO_BUF(fes_result, htt_stats_buf->fes_result, num_elems); +- len += scnprintf(buf + len, buf_len - len, "fes_result = %s\n\n", fes_result); ++ PRINT_ARRAY_TO_BUF(buf, len, htt_stats_buf->fes_result, "fes_result", ++ num_elems, "\n\n"); + + if (len >= buf_len) + buf[buf_len - 1] = 0; +@@ -1218,27 +1122,16 @@ htt_print_tx_hwq_tried_mpdu_cnt_hist_tlv + u8 *buf = stats_req->buf; + u32 len = stats_req->buf_len; + u32 buf_len = ATH11K_HTT_STATS_BUF_SIZE; +- char tried_mpdu_cnt_hist[HTT_MAX_STRING_LEN] = {0}; + u32 num_elements = ((tag_len - + sizeof(htt_stats_buf->hist_bin_size)) >> 2); +- u32 required_buffer_size = HTT_MAX_PRINT_CHAR_PER_ELEM * num_elements; + + len += scnprintf(buf + len, buf_len - len, + "HTT_TX_HWQ_TRIED_MPDU_CNT_HIST_TLV_V:\n"); + len += scnprintf(buf + len, buf_len - len, "TRIED_MPDU_CNT_HIST_BIN_SIZE : %u\n", + htt_stats_buf->hist_bin_size); + +- if (required_buffer_size < HTT_MAX_STRING_LEN) { +- PRINT_ARRAY_TO_BUF(tried_mpdu_cnt_hist, +- htt_stats_buf->tried_mpdu_cnt_hist, +- num_elements); +- len += scnprintf(buf + len, buf_len - len, +- "tried_mpdu_cnt_hist = %s\n\n", +- tried_mpdu_cnt_hist); +- } else { +- len += scnprintf(buf + len, buf_len - len, +- "INSUFFICIENT PRINT BUFFER\n"); +- } ++ PRINT_ARRAY_TO_BUF(buf, len, htt_stats_buf->tried_mpdu_cnt_hist, ++ "tried_mpdu_cnt_hist", num_elements, "\n\n"); + + if (len >= buf_len) + buf[buf_len - 1] = 0; +@@ -1257,23 +1150,14 @@ htt_print_tx_hwq_txop_used_cnt_hist_tlv_ + u8 *buf = stats_req->buf; + u32 len = stats_req->buf_len; + u32 buf_len = ATH11K_HTT_STATS_BUF_SIZE; +- char txop_used_cnt_hist[HTT_MAX_STRING_LEN] = {0}; + u32 num_elements = tag_len >> 2; +- u32 required_buffer_size = HTT_MAX_PRINT_CHAR_PER_ELEM * num_elements; + + len += scnprintf(buf + len, buf_len - len, + "HTT_TX_HWQ_TXOP_USED_CNT_HIST_TLV_V:\n"); + +- if (required_buffer_size < HTT_MAX_STRING_LEN) { +- PRINT_ARRAY_TO_BUF(txop_used_cnt_hist, +- htt_stats_buf->txop_used_cnt_hist, +- num_elements); +- len += scnprintf(buf + len, buf_len - len, "txop_used_cnt_hist = %s\n\n", +- txop_used_cnt_hist); +- } else { +- len += scnprintf(buf + len, buf_len - len, +- "INSUFFICIENT PRINT BUFFER\n"); +- } ++ PRINT_ARRAY_TO_BUF(buf, len, htt_stats_buf->txop_used_cnt_hist, ++ "txop_used_cnt_hist", num_elements, "\n\n"); ++ + if (len >= buf_len) + buf[buf_len - 1] = 0; + else +@@ -1781,15 +1665,12 @@ htt_print_sched_txq_cmd_posted_tlv_v(con + u8 *buf = stats_req->buf; + u32 len = stats_req->buf_len; + u32 buf_len = ATH11K_HTT_STATS_BUF_SIZE; +- char sched_cmd_posted[HTT_MAX_STRING_LEN] = {0}; + u16 num_elements = min_t(u16, (tag_len >> 2), HTT_TX_PDEV_SCHED_TX_MODE_MAX); + + len += scnprintf(buf + len, buf_len - len, "HTT_SCHED_TXQ_CMD_POSTED_TLV_V:\n"); + +- PRINT_ARRAY_TO_BUF(sched_cmd_posted, htt_stats_buf->sched_cmd_posted, +- num_elements); +- len += scnprintf(buf + len, buf_len - len, "sched_cmd_posted = %s\n\n", +- sched_cmd_posted); ++ PRINT_ARRAY_TO_BUF(buf, len, htt_stats_buf->sched_cmd_posted, ++ "sched_cmd_posted", num_elements, "\n\n"); + + if (len >= buf_len) + buf[buf_len - 1] = 0; +@@ -1808,15 +1689,12 @@ htt_print_sched_txq_cmd_reaped_tlv_v(con + u8 *buf = stats_req->buf; + u32 len = stats_req->buf_len; + u32 buf_len = ATH11K_HTT_STATS_BUF_SIZE; +- char sched_cmd_reaped[HTT_MAX_STRING_LEN] = {0}; + u16 num_elements = min_t(u16, (tag_len >> 2), HTT_TX_PDEV_SCHED_TX_MODE_MAX); + + len += scnprintf(buf + len, buf_len - len, "HTT_SCHED_TXQ_CMD_REAPED_TLV_V:\n"); + +- PRINT_ARRAY_TO_BUF(sched_cmd_reaped, htt_stats_buf->sched_cmd_reaped, +- num_elements); +- len += scnprintf(buf + len, buf_len - len, "sched_cmd_reaped = %s\n\n", +- sched_cmd_reaped); ++ PRINT_ARRAY_TO_BUF(buf, len, htt_stats_buf->sched_cmd_reaped, ++ "sched_cmd_reaped", num_elements, "\n\n"); + + if (len >= buf_len) + buf[buf_len - 1] = 0; +@@ -1835,7 +1713,6 @@ htt_print_sched_txq_sched_order_su_tlv_v + u8 *buf = stats_req->buf; + u32 len = stats_req->buf_len; + u32 buf_len = ATH11K_HTT_STATS_BUF_SIZE; +- char sched_order_su[HTT_MAX_STRING_LEN] = {0}; + /* each entry is u32, i.e. 4 bytes */ + u32 sched_order_su_num_entries = + min_t(u32, (tag_len >> 2), HTT_TX_PDEV_NUM_SCHED_ORDER_LOG); +@@ -1843,10 +1720,8 @@ htt_print_sched_txq_sched_order_su_tlv_v + len += scnprintf(buf + len, buf_len - len, + "HTT_SCHED_TXQ_SCHED_ORDER_SU_TLV_V:\n"); + +- PRINT_ARRAY_TO_BUF(sched_order_su, htt_stats_buf->sched_order_su, +- sched_order_su_num_entries); +- len += scnprintf(buf + len, buf_len - len, "sched_order_su = %s\n\n", +- sched_order_su); ++ PRINT_ARRAY_TO_BUF(buf, len, htt_stats_buf->sched_order_su, "sched_order_su", ++ sched_order_su_num_entries, "\n\n"); + + if (len >= buf_len) + buf[buf_len - 1] = 0; +@@ -1865,17 +1740,15 @@ htt_print_sched_txq_sched_ineligibility_ + u8 *buf = stats_req->buf; + u32 len = stats_req->buf_len; + u32 buf_len = ATH11K_HTT_STATS_BUF_SIZE; +- char sched_ineligibility[HTT_MAX_STRING_LEN] = {0}; + /* each entry is u32, i.e. 4 bytes */ + u32 sched_ineligibility_num_entries = tag_len >> 2; + + len += scnprintf(buf + len, buf_len - len, + "HTT_SCHED_TXQ_SCHED_INELIGIBILITY_V:\n"); + +- PRINT_ARRAY_TO_BUF(sched_ineligibility, htt_stats_buf->sched_ineligibility, +- sched_ineligibility_num_entries); +- len += scnprintf(buf + len, buf_len - len, "sched_ineligibility = %s\n\n", +- sched_ineligibility); ++ PRINT_ARRAY_TO_BUF(buf, len, htt_stats_buf->sched_ineligibility, ++ "sched_ineligibility", sched_ineligibility_num_entries, ++ "\n\n"); + + if (len >= buf_len) + buf[buf_len - 1] = 0; +@@ -1982,16 +1855,13 @@ htt_print_tx_tqm_gen_mpdu_stats_tlv_v(co + u8 *buf = stats_req->buf; + u32 len = stats_req->buf_len; + u32 buf_len = ATH11K_HTT_STATS_BUF_SIZE; +- char gen_mpdu_end_reason[HTT_MAX_STRING_LEN] = {0}; + u16 num_elements = min_t(u16, (tag_len >> 2), + HTT_TX_TQM_MAX_LIST_MPDU_END_REASON); + + len += scnprintf(buf + len, buf_len - len, "HTT_TX_TQM_GEN_MPDU_STATS_TLV_V:\n"); + +- PRINT_ARRAY_TO_BUF(gen_mpdu_end_reason, htt_stats_buf->gen_mpdu_end_reason, +- num_elements); +- len += scnprintf(buf + len, buf_len - len, "gen_mpdu_end_reason = %s\n\n", +- gen_mpdu_end_reason); ++ PRINT_ARRAY_TO_BUF(buf, len, htt_stats_buf->gen_mpdu_end_reason, ++ "gen_mpdu_end_reason", num_elements, "\n\n"); + + if (len >= buf_len) + buf[buf_len - 1] = 0; +@@ -2010,16 +1880,14 @@ htt_print_tx_tqm_list_mpdu_stats_tlv_v(c + u8 *buf = stats_req->buf; + u32 len = stats_req->buf_len; + u32 buf_len = ATH11K_HTT_STATS_BUF_SIZE; +- char list_mpdu_end_reason[HTT_MAX_STRING_LEN] = {0}; + u16 num_elems = min_t(u16, (tag_len >> 2), HTT_TX_TQM_MAX_LIST_MPDU_END_REASON); + + len += scnprintf(buf + len, buf_len - len, + "HTT_TX_TQM_LIST_MPDU_STATS_TLV_V:\n"); + +- PRINT_ARRAY_TO_BUF(list_mpdu_end_reason, htt_stats_buf->list_mpdu_end_reason, +- num_elems); +- len += scnprintf(buf + len, buf_len - len, "list_mpdu_end_reason = %s\n\n", +- list_mpdu_end_reason); ++ PRINT_ARRAY_TO_BUF(buf, len, htt_stats_buf->list_mpdu_end_reason, ++ "list_mpdu_end_reason", num_elems, "\n\n"); ++ + if (len >= buf_len) + buf[buf_len - 1] = 0; + else +@@ -2037,16 +1905,13 @@ htt_print_tx_tqm_list_mpdu_cnt_tlv_v(con + u8 *buf = stats_req->buf; + u32 len = stats_req->buf_len; + u32 buf_len = ATH11K_HTT_STATS_BUF_SIZE; +- char list_mpdu_cnt_hist[HTT_MAX_STRING_LEN] = {0}; + u16 num_elems = min_t(u16, (tag_len >> 2), + HTT_TX_TQM_MAX_LIST_MPDU_CNT_HISTOGRAM_BINS); + + len += scnprintf(buf + len, buf_len - len, "HTT_TX_TQM_LIST_MPDU_CNT_TLV_V:\n"); + +- PRINT_ARRAY_TO_BUF(list_mpdu_cnt_hist, htt_stats_buf->list_mpdu_cnt_hist, +- num_elems); +- len += scnprintf(buf + len, buf_len - len, "list_mpdu_cnt_hist = %s\n\n", +- list_mpdu_cnt_hist); ++ PRINT_ARRAY_TO_BUF(buf, len, htt_stats_buf->list_mpdu_cnt_hist, ++ "list_mpdu_cnt_hist", num_elems, "\n\n"); + + if (len >= buf_len) + buf[buf_len - 1] = 0; +@@ -2527,24 +2392,13 @@ htt_print_tx_de_fw2wbm_ring_full_hist_tl + u8 *buf = stats_req->buf; + u32 len = stats_req->buf_len; + u32 buf_len = ATH11K_HTT_STATS_BUF_SIZE; +- char fw2wbm_ring_full_hist[HTT_MAX_STRING_LEN] = {0}; + u16 num_elements = tag_len >> 2; +- u32 required_buffer_size = HTT_MAX_PRINT_CHAR_PER_ELEM * num_elements; + + len += scnprintf(buf + len, buf_len - len, + "HTT_TX_DE_FW2WBM_RING_FULL_HIST_TLV"); + +- if (required_buffer_size < HTT_MAX_STRING_LEN) { +- PRINT_ARRAY_TO_BUF(fw2wbm_ring_full_hist, +- htt_stats_buf->fw2wbm_ring_full_hist, +- num_elements); +- len += scnprintf(buf + len, buf_len - len, +- "fw2wbm_ring_full_hist = %s\n\n", +- fw2wbm_ring_full_hist); +- } else { +- len += scnprintf(buf + len, buf_len - len, +- "INSUFFICIENT PRINT BUFFER\n"); +- } ++ PRINT_ARRAY_TO_BUF(buf, len, htt_stats_buf->fw2wbm_ring_full_hist, ++ "fw2wbm_ring_full_hist", num_elements, "\n\n"); + + if (len >= buf_len) + buf[buf_len - 1] = 0; +@@ -2593,8 +2447,6 @@ static inline void htt_print_ring_if_sta + u8 *buf = stats_req->buf; + u32 len = stats_req->buf_len; + u32 buf_len = ATH11K_HTT_STATS_BUF_SIZE; +- char low_wm_hit_count[HTT_MAX_STRING_LEN] = {0}; +- char high_wm_hit_count[HTT_MAX_STRING_LEN] = {0}; + + len += scnprintf(buf + len, buf_len - len, "HTT_RING_IF_STATS_TLV:\n"); + len += scnprintf(buf + len, buf_len - len, "base_addr = %u\n", +@@ -2630,15 +2482,10 @@ static inline void htt_print_ring_if_sta + len += scnprintf(buf + len, buf_len - len, "cons_blockwait_count = %u\n", + htt_stats_buf->cons_blockwait_count); + +- PRINT_ARRAY_TO_BUF(low_wm_hit_count, htt_stats_buf->low_wm_hit_count, +- HTT_STATS_LOW_WM_BINS); +- len += scnprintf(buf + len, buf_len - len, "low_wm_hit_count = %s\n", +- low_wm_hit_count); +- +- PRINT_ARRAY_TO_BUF(high_wm_hit_count, htt_stats_buf->high_wm_hit_count, +- HTT_STATS_HIGH_WM_BINS); +- len += scnprintf(buf + len, buf_len - len, "high_wm_hit_count = %s\n\n", +- high_wm_hit_count); ++ PRINT_ARRAY_TO_BUF(buf, len, htt_stats_buf->low_wm_hit_count, ++ "low_wm_hit_count", HTT_STATS_LOW_WM_BINS, "\n"); ++ PRINT_ARRAY_TO_BUF(buf, len, htt_stats_buf->high_wm_hit_count, ++ "high_wm_hit_count", HTT_STATS_HIGH_WM_BINS, "\n\n"); + + if (len >= buf_len) + buf[buf_len - 1] = 0; +@@ -2678,16 +2525,12 @@ static inline void htt_print_sfm_client_ + u8 *buf = stats_req->buf; + u32 len = stats_req->buf_len; + u32 buf_len = ATH11K_HTT_STATS_BUF_SIZE; +- char dwords_used_by_user_n[HTT_MAX_STRING_LEN] = {0}; + u16 num_elems = tag_len >> 2; + + len += scnprintf(buf + len, buf_len - len, "HTT_SFM_CLIENT_USER_TLV_V:\n"); + +- PRINT_ARRAY_TO_BUF(dwords_used_by_user_n, +- htt_stats_buf->dwords_used_by_user_n, +- num_elems); +- len += scnprintf(buf + len, buf_len - len, "dwords_used_by_user_n = %s\n\n", +- dwords_used_by_user_n); ++ PRINT_ARRAY_TO_BUF(buf, len, htt_stats_buf->dwords_used_by_user_n, ++ "dwords_used_by_user_n", num_elems, "\n\n"); + + if (len >= buf_len) + buf[buf_len - 1] = 0; +@@ -2838,14 +2681,6 @@ static inline void htt_print_tx_pdev_rat + u32 len = stats_req->buf_len; + u32 buf_len = ATH11K_HTT_STATS_BUF_SIZE; + u8 j; +- char str_buf[HTT_MAX_STRING_LEN] = {0}; +- char *tx_gi[HTT_TX_PEER_STATS_NUM_GI_COUNTERS] = {NULL}; +- +- for (j = 0; j < HTT_TX_PEER_STATS_NUM_GI_COUNTERS; j++) { +- tx_gi[j] = kmalloc(HTT_MAX_STRING_LEN, GFP_ATOMIC); +- if (!tx_gi[j]) +- goto fail; +- } + + len += scnprintf(buf + len, buf_len - len, "HTT_TX_PDEV_RATE_STATS_TLV:\n"); + len += scnprintf(buf + len, buf_len - len, "mac_id = %u\n", +@@ -2884,75 +2719,37 @@ static inline void htt_print_tx_pdev_rat + htt_stats_buf->tx_legacy_ofdm_rate[6], + htt_stats_buf->tx_legacy_ofdm_rate[7]); + +- memset(str_buf, 0x0, HTT_MAX_STRING_LEN); +- PRINT_ARRAY_TO_BUF(str_buf, htt_stats_buf->tx_mcs, +- HTT_TX_PDEV_STATS_NUM_MCS_COUNTERS); +- len += scnprintf(buf + len, buf_len - len, "tx_mcs = %s\n", str_buf); +- +- memset(str_buf, 0x0, HTT_MAX_STRING_LEN); +- PRINT_ARRAY_TO_BUF(str_buf, htt_stats_buf->ac_mu_mimo_tx_mcs, +- HTT_TX_PDEV_STATS_NUM_MCS_COUNTERS); +- len += scnprintf(buf + len, buf_len - len, "ac_mu_mimo_tx_mcs = %s\n", str_buf); +- +- memset(str_buf, 0x0, HTT_MAX_STRING_LEN); +- PRINT_ARRAY_TO_BUF(str_buf, htt_stats_buf->ax_mu_mimo_tx_mcs, +- HTT_TX_PDEV_STATS_NUM_MCS_COUNTERS); +- len += scnprintf(buf + len, buf_len - len, "ax_mu_mimo_tx_mcs = %s\n", str_buf); +- +- memset(str_buf, 0x0, HTT_MAX_STRING_LEN); +- PRINT_ARRAY_TO_BUF(str_buf, htt_stats_buf->ofdma_tx_mcs, +- HTT_TX_PDEV_STATS_NUM_MCS_COUNTERS); +- len += scnprintf(buf + len, buf_len - len, "ofdma_tx_mcs = %s\n", str_buf); +- +- memset(str_buf, 0x0, HTT_MAX_STRING_LEN); +- PRINT_ARRAY_TO_BUF(str_buf, htt_stats_buf->tx_nss, +- HTT_TX_PDEV_STATS_NUM_SPATIAL_STREAMS); +- len += scnprintf(buf + len, buf_len - len, "tx_nss = %s\n", str_buf); +- +- memset(str_buf, 0x0, HTT_MAX_STRING_LEN); +- PRINT_ARRAY_TO_BUF(str_buf, htt_stats_buf->ac_mu_mimo_tx_nss, +- HTT_TX_PDEV_STATS_NUM_SPATIAL_STREAMS); +- len += scnprintf(buf + len, buf_len - len, "ac_mu_mimo_tx_nss = %s\n", str_buf); +- +- memset(str_buf, 0x0, HTT_MAX_STRING_LEN); +- PRINT_ARRAY_TO_BUF(str_buf, htt_stats_buf->ax_mu_mimo_tx_nss, +- HTT_TX_PDEV_STATS_NUM_SPATIAL_STREAMS); +- len += scnprintf(buf + len, buf_len - len, "ax_mu_mimo_tx_nss = %s\n", str_buf); +- +- memset(str_buf, 0x0, HTT_MAX_STRING_LEN); +- PRINT_ARRAY_TO_BUF(str_buf, htt_stats_buf->ofdma_tx_nss, +- HTT_TX_PDEV_STATS_NUM_SPATIAL_STREAMS); +- len += scnprintf(buf + len, buf_len - len, "ofdma_tx_nss = %s\n", str_buf); +- +- memset(str_buf, 0x0, HTT_MAX_STRING_LEN); +- PRINT_ARRAY_TO_BUF(str_buf, htt_stats_buf->tx_bw, +- HTT_TX_PDEV_STATS_NUM_BW_COUNTERS); +- len += scnprintf(buf + len, buf_len - len, "tx_bw = %s\n", str_buf); +- +- memset(str_buf, 0x0, HTT_MAX_STRING_LEN); +- PRINT_ARRAY_TO_BUF(str_buf, htt_stats_buf->ac_mu_mimo_tx_bw, +- HTT_TX_PDEV_STATS_NUM_BW_COUNTERS); +- len += scnprintf(buf + len, buf_len - len, "ac_mu_mimo_tx_bw = %s\n", str_buf); +- +- memset(str_buf, 0x0, HTT_MAX_STRING_LEN); +- PRINT_ARRAY_TO_BUF(str_buf, htt_stats_buf->ax_mu_mimo_tx_bw, +- HTT_TX_PDEV_STATS_NUM_BW_COUNTERS); +- len += scnprintf(buf + len, buf_len - len, "ax_mu_mimo_tx_bw = %s\n", str_buf); +- +- memset(str_buf, 0x0, HTT_MAX_STRING_LEN); +- PRINT_ARRAY_TO_BUF(str_buf, htt_stats_buf->ofdma_tx_bw, +- HTT_TX_PDEV_STATS_NUM_BW_COUNTERS); +- len += scnprintf(buf + len, buf_len - len, "ofdma_tx_bw = %s\n", str_buf); +- +- memset(str_buf, 0x0, HTT_MAX_STRING_LEN); +- PRINT_ARRAY_TO_BUF(str_buf, htt_stats_buf->tx_stbc, +- HTT_TX_PDEV_STATS_NUM_MCS_COUNTERS); +- len += scnprintf(buf + len, buf_len - len, "tx_stbc = %s\n", str_buf); +- +- memset(str_buf, 0x0, HTT_MAX_STRING_LEN); +- PRINT_ARRAY_TO_BUF(str_buf, htt_stats_buf->tx_pream, +- HTT_TX_PDEV_STATS_NUM_PREAMBLE_TYPES); +- len += scnprintf(buf + len, buf_len - len, "tx_pream = %s\n", str_buf); ++ PRINT_ARRAY_TO_BUF(buf, len, htt_stats_buf->tx_mcs, "tx_mcs", ++ HTT_TX_PDEV_STATS_NUM_MCS_COUNTERS, "\n"); ++ PRINT_ARRAY_TO_BUF(buf, len, htt_stats_buf->ac_mu_mimo_tx_mcs, ++ "ac_mu_mimo_tx_mcs", HTT_TX_PDEV_STATS_NUM_MCS_COUNTERS, "\n"); ++ PRINT_ARRAY_TO_BUF(buf, len, htt_stats_buf->ax_mu_mimo_tx_mcs, ++ "ax_mu_mimo_tx_mcs", HTT_TX_PDEV_STATS_NUM_MCS_COUNTERS, "\n"); ++ PRINT_ARRAY_TO_BUF(buf, len, htt_stats_buf->ofdma_tx_mcs, "ofdma_tx_mcs", ++ HTT_TX_PDEV_STATS_NUM_MCS_COUNTERS, "\n"); ++ PRINT_ARRAY_TO_BUF(buf, len, htt_stats_buf->tx_nss, "tx_nss", ++ HTT_TX_PDEV_STATS_NUM_SPATIAL_STREAMS, "\n"); ++ PRINT_ARRAY_TO_BUF(buf, len, htt_stats_buf->ac_mu_mimo_tx_nss, ++ "ac_mu_mimo_tx_nss", ++ HTT_TX_PDEV_STATS_NUM_SPATIAL_STREAMS, "\n"); ++ PRINT_ARRAY_TO_BUF(buf, len, htt_stats_buf->ax_mu_mimo_tx_nss, ++ "ax_mu_mimo_tx_nss", ++ HTT_TX_PDEV_STATS_NUM_SPATIAL_STREAMS, "\n"); ++ PRINT_ARRAY_TO_BUF(buf, len, htt_stats_buf->ofdma_tx_nss, "ofdma_tx_nss", ++ HTT_TX_PDEV_STATS_NUM_SPATIAL_STREAMS, "\n"); ++ PRINT_ARRAY_TO_BUF(buf, len, htt_stats_buf->tx_bw, "tx_bw", ++ HTT_TX_PDEV_STATS_NUM_BW_COUNTERS, "\n"); ++ PRINT_ARRAY_TO_BUF(buf, len, htt_stats_buf->ac_mu_mimo_tx_bw, ++ "ac_mu_mimo_tx_bw", HTT_TX_PDEV_STATS_NUM_BW_COUNTERS, "\n"); ++ PRINT_ARRAY_TO_BUF(buf, len, htt_stats_buf->ax_mu_mimo_tx_bw, ++ "ax_mu_mimo_tx_bw", ++ HTT_TX_PDEV_STATS_NUM_BW_COUNTERS, "\n"); ++ PRINT_ARRAY_TO_BUF(buf, len, htt_stats_buf->ofdma_tx_bw, "ofdma_tx_bw", ++ HTT_TX_PDEV_STATS_NUM_BW_COUNTERS, "\n"); ++ PRINT_ARRAY_TO_BUF(buf, len, htt_stats_buf->tx_stbc, "tx_stbc", ++ HTT_TX_PDEV_STATS_NUM_MCS_COUNTERS, "\n"); ++ PRINT_ARRAY_TO_BUF(buf, len, htt_stats_buf->tx_pream, "tx_pream", ++ HTT_TX_PDEV_STATS_NUM_PREAMBLE_TYPES, "\n"); + + len += scnprintf(buf + len, buf_len - len, "HE LTF: 1x: %u, 2x: %u, 4x: %u\n", + htt_stats_buf->tx_he_ltf[1], +@@ -2961,42 +2758,38 @@ static inline void htt_print_tx_pdev_rat + + /* SU GI Stats */ + for (j = 0; j < HTT_TX_PDEV_STATS_NUM_GI_COUNTERS; j++) { +- PRINT_ARRAY_TO_BUF(tx_gi[j], htt_stats_buf->tx_gi[j], +- HTT_TX_PDEV_STATS_NUM_MCS_COUNTERS); +- len += scnprintf(buf + len, buf_len - len, "tx_gi[%u] = %s\n", +- j, tx_gi[j]); ++ len += scnprintf(buf + len, (buf_len - len), ++ "tx_gi[%u] = ", j); ++ PRINT_ARRAY_TO_BUF(buf, len, htt_stats_buf->tx_gi[j], NULL, ++ HTT_TX_PDEV_STATS_NUM_MCS_COUNTERS, "\n"); + } + + /* AC MU-MIMO GI Stats */ + for (j = 0; j < HTT_TX_PDEV_STATS_NUM_GI_COUNTERS; j++) { +- PRINT_ARRAY_TO_BUF(tx_gi[j], htt_stats_buf->ac_mu_mimo_tx_gi[j], +- HTT_TX_PDEV_STATS_NUM_MCS_COUNTERS); +- len += scnprintf(buf + len, buf_len - len, +- "ac_mu_mimo_tx_gi[%u] = %s\n", +- j, tx_gi[j]); ++ len += scnprintf(buf + len, (buf_len - len), ++ "ac_mu_mimo_tx_gi[%u] = ", j); ++ PRINT_ARRAY_TO_BUF(buf, len, htt_stats_buf->ac_mu_mimo_tx_gi[j], ++ NULL, HTT_TX_PDEV_STATS_NUM_MCS_COUNTERS, "\n"); + } + + /* AX MU-MIMO GI Stats */ + for (j = 0; j < HTT_TX_PDEV_STATS_NUM_GI_COUNTERS; j++) { +- PRINT_ARRAY_TO_BUF(tx_gi[j], htt_stats_buf->ax_mu_mimo_tx_gi[j], +- HTT_TX_PDEV_STATS_NUM_MCS_COUNTERS); +- len += scnprintf(buf + len, buf_len - len, +- "ax_mu_mimo_tx_gi[%u] = %s\n", +- j, tx_gi[j]); ++ len += scnprintf(buf + len, (buf_len - len), ++ "ax_mu_mimo_tx_gi[%u] = ", j); ++ PRINT_ARRAY_TO_BUF(buf, len, htt_stats_buf->ax_mu_mimo_tx_gi[j], ++ NULL, HTT_TX_PDEV_STATS_NUM_MCS_COUNTERS, "\n"); + } + + /* DL OFDMA GI Stats */ + for (j = 0; j < HTT_TX_PDEV_STATS_NUM_GI_COUNTERS; j++) { +- PRINT_ARRAY_TO_BUF(tx_gi[j], htt_stats_buf->ofdma_tx_gi[j], +- HTT_TX_PDEV_STATS_NUM_MCS_COUNTERS); +- len += scnprintf(buf + len, buf_len - len, "ofdma_tx_gi[%u] = %s\n", +- j, tx_gi[j]); ++ len += scnprintf(buf + len, (buf_len - len), ++ "ofdma_tx_gi[%u] = ", j); ++ PRINT_ARRAY_TO_BUF(buf, len, htt_stats_buf->ofdma_tx_gi[j], NULL, ++ HTT_TX_PDEV_STATS_NUM_MCS_COUNTERS, "\n"); + } + +- memset(str_buf, 0x0, HTT_MAX_STRING_LEN); +- PRINT_ARRAY_TO_BUF(str_buf, htt_stats_buf->tx_dcm, +- HTT_TX_PDEV_STATS_NUM_DCM_COUNTERS); +- len += scnprintf(buf + len, buf_len - len, "tx_dcm = %s\n\n", str_buf); ++ PRINT_ARRAY_TO_BUF(buf, len, htt_stats_buf->tx_dcm, "tx_dcm", ++ HTT_TX_PDEV_STATS_NUM_DCM_COUNTERS, "\n\n"); + + if (len >= buf_len) + buf[buf_len - 1] = 0; +@@ -3004,9 +2797,6 @@ static inline void htt_print_tx_pdev_rat + buf[len] = 0; + + stats_req->buf_len = len; +-fail: +- for (j = 0; j < HTT_TX_PEER_STATS_NUM_GI_COUNTERS; j++) +- kfree(tx_gi[j]); + } + + static inline void htt_print_rx_pdev_rate_stats_tlv(const void *tag_buf, +@@ -3017,29 +2807,6 @@ static inline void htt_print_rx_pdev_rat + u32 len = stats_req->buf_len; + u32 buf_len = ATH11K_HTT_STATS_BUF_SIZE; + u8 i, j; +- u16 index = 0; +- char *rssi_chain[HTT_RX_PDEV_STATS_NUM_SPATIAL_STREAMS] = {NULL}; +- char *rx_gi[HTT_RX_PDEV_STATS_NUM_GI_COUNTERS] = {NULL}; +- char str_buf[HTT_MAX_STRING_LEN] = {0}; +- char *rx_pilot_evm_db[HTT_RX_PDEV_STATS_NUM_SPATIAL_STREAMS] = {NULL}; +- +- for (j = 0; j < HTT_RX_PDEV_STATS_NUM_SPATIAL_STREAMS; j++) { +- rssi_chain[j] = kmalloc(HTT_MAX_STRING_LEN, GFP_ATOMIC); +- if (!rssi_chain[j]) +- goto fail; +- } +- +- for (j = 0; j < HTT_RX_PDEV_STATS_NUM_GI_COUNTERS; j++) { +- rx_gi[j] = kmalloc(HTT_MAX_STRING_LEN, GFP_ATOMIC); +- if (!rx_gi[j]) +- goto fail; +- } +- +- for (j = 0; j < HTT_RX_PDEV_STATS_NUM_SPATIAL_STREAMS; j++) { +- rx_pilot_evm_db[j] = kmalloc(HTT_MAX_STRING_LEN, GFP_ATOMIC); +- if (!rx_pilot_evm_db[j]) +- goto fail; +- } + + len += scnprintf(buf + len, buf_len - len, "HTT_RX_PDEV_RATE_STATS_TLV:\n"); + len += scnprintf(buf + len, buf_len - len, "mac_id = %u\n", +@@ -3059,30 +2826,17 @@ static inline void htt_print_rx_pdev_rat + len += scnprintf(buf + len, buf_len - len, "rssi_in_dbm = %d\n", + htt_stats_buf->rssi_in_dbm); + +- memset(str_buf, 0x0, HTT_MAX_STRING_LEN); +- PRINT_ARRAY_TO_BUF(str_buf, htt_stats_buf->rx_mcs, +- HTT_RX_PDEV_STATS_NUM_MCS_COUNTERS); +- len += scnprintf(buf + len, buf_len - len, "rx_mcs = %s\n", str_buf); +- +- memset(str_buf, 0x0, HTT_MAX_STRING_LEN); +- PRINT_ARRAY_TO_BUF(str_buf, htt_stats_buf->rx_nss, +- HTT_RX_PDEV_STATS_NUM_SPATIAL_STREAMS); +- len += scnprintf(buf + len, buf_len - len, "rx_nss = %s\n", str_buf); +- +- memset(str_buf, 0x0, HTT_MAX_STRING_LEN); +- PRINT_ARRAY_TO_BUF(str_buf, htt_stats_buf->rx_dcm, +- HTT_RX_PDEV_STATS_NUM_DCM_COUNTERS); +- len += scnprintf(buf + len, buf_len - len, "rx_dcm = %s\n", str_buf); +- +- memset(str_buf, 0x0, HTT_MAX_STRING_LEN); +- PRINT_ARRAY_TO_BUF(str_buf, htt_stats_buf->rx_stbc, +- HTT_RX_PDEV_STATS_NUM_MCS_COUNTERS); +- len += scnprintf(buf + len, buf_len - len, "rx_stbc = %s\n", str_buf); +- +- memset(str_buf, 0x0, HTT_MAX_STRING_LEN); +- PRINT_ARRAY_TO_BUF(str_buf, htt_stats_buf->rx_bw, +- HTT_RX_PDEV_STATS_NUM_BW_COUNTERS); +- len += scnprintf(buf + len, buf_len - len, "rx_bw = %s\n", str_buf); ++ PRINT_ARRAY_TO_BUF(buf, len, htt_stats_buf->rx_mcs, "rx_mcs", ++ HTT_RX_PDEV_STATS_NUM_MCS_COUNTERS, "\n"); ++ PRINT_ARRAY_TO_BUF(buf, len, htt_stats_buf->rx_nss, "rx_nss", ++ HTT_RX_PDEV_STATS_NUM_SPATIAL_STREAMS, "\n"); ++ PRINT_ARRAY_TO_BUF(buf, len, htt_stats_buf->rx_dcm, "rx_dcm", ++ HTT_RX_PDEV_STATS_NUM_DCM_COUNTERS, "\n"); ++ PRINT_ARRAY_TO_BUF(buf, len, htt_stats_buf->rx_stbc, "rx_stbc", ++ HTT_RX_PDEV_STATS_NUM_MCS_COUNTERS, "\n"); ++ PRINT_ARRAY_TO_BUF(buf, len, htt_stats_buf->rx_bw, "rx_bw", ++ HTT_RX_PDEV_STATS_NUM_BW_COUNTERS, "\n"); ++ + len += scnprintf(buf + len, buf_len - len, "rx_evm_nss_count = %u\n", + htt_stats_buf->nss_count); + +@@ -3090,44 +2844,43 @@ static inline void htt_print_rx_pdev_rat + htt_stats_buf->pilot_count); + + for (j = 0; j < HTT_RX_PDEV_STATS_NUM_SPATIAL_STREAMS; j++) { +- index = 0; + ++ len += scnprintf(buf + len, buf_len - len, ++ "pilot_evm_db[%u] = ", j); + for (i = 0; i < HTT_RX_PDEV_STATS_RXEVM_MAX_PILOTS_PER_NSS; i++) +- index += scnprintf(&rx_pilot_evm_db[j][index], +- HTT_MAX_STRING_LEN - index, +- " %u:%d,", +- i, +- htt_stats_buf->rx_pilot_evm_db[j][i]); +- len += scnprintf(buf + len, buf_len - len, "pilot_evm_dB[%u] = %s\n", +- j, rx_pilot_evm_db[j]); ++ len += scnprintf(buf + len, ++ buf_len - len, ++ " %u:%d,", ++ i, ++ htt_stats_buf->rx_pilot_evm_db[j][i]); ++ len += scnprintf(buf + len, buf_len - len, "\n"); + } + +- index = 0; +- memset(str_buf, 0x0, HTT_MAX_STRING_LEN); ++ len += scnprintf(buf + len, buf_len - len, ++ "pilot_evm_db_mean = "); + for (i = 0; i < HTT_RX_PDEV_STATS_NUM_SPATIAL_STREAMS; i++) +- index += scnprintf(&str_buf[index], +- HTT_MAX_STRING_LEN - index, +- " %u:%d,", i, htt_stats_buf->rx_pilot_evm_db_mean[i]); +- len += scnprintf(buf + len, buf_len - len, "pilot_evm_dB_mean = %s\n", str_buf); ++ len += scnprintf(buf + len, ++ buf_len - len, ++ " %u:%d,", i, ++ htt_stats_buf->rx_pilot_evm_db_mean[i]); ++ len += scnprintf(buf + len, buf_len - len, "\n"); + + for (j = 0; j < HTT_RX_PDEV_STATS_NUM_SPATIAL_STREAMS; j++) { +- PRINT_ARRAY_TO_BUF(rssi_chain[j], htt_stats_buf->rssi_chain[j], +- HTT_RX_PDEV_STATS_NUM_BW_COUNTERS); +- len += scnprintf(buf + len, buf_len - len, "rssi_chain[%u] = %s\n", +- j, rssi_chain[j]); ++ len += scnprintf(buf + len, buf_len - len, ++ "rssi_chain[%u] = ", j); ++ PRINT_ARRAY_TO_BUF(buf, len, htt_stats_buf->rssi_chain[j], NULL, ++ HTT_RX_PDEV_STATS_NUM_BW_COUNTERS, "\n"); + } + + for (j = 0; j < HTT_RX_PDEV_STATS_NUM_GI_COUNTERS; j++) { +- PRINT_ARRAY_TO_BUF(rx_gi[j], htt_stats_buf->rx_gi[j], +- HTT_RX_PDEV_STATS_NUM_MCS_COUNTERS); +- len += scnprintf(buf + len, buf_len - len, "rx_gi[%u] = %s\n", +- j, rx_gi[j]); ++ len += scnprintf(buf + len, buf_len - len, ++ "rx_gi[%u] = ", j); ++ PRINT_ARRAY_TO_BUF(buf, len, htt_stats_buf->rx_gi[j], NULL, ++ HTT_RX_PDEV_STATS_NUM_MCS_COUNTERS, "\n"); + } + +- memset(str_buf, 0x0, HTT_MAX_STRING_LEN); +- PRINT_ARRAY_TO_BUF(str_buf, htt_stats_buf->rx_pream, +- HTT_RX_PDEV_STATS_NUM_PREAMBLE_TYPES); +- len += scnprintf(buf + len, buf_len - len, "rx_pream = %s\n", str_buf); ++ PRINT_ARRAY_TO_BUF(buf, len, htt_stats_buf->rx_pream, "rx_pream", ++ HTT_RX_PDEV_STATS_NUM_PREAMBLE_TYPES, "\n"); + + len += scnprintf(buf + len, buf_len - len, "rx_11ax_su_ext = %u\n", + htt_stats_buf->rx_11ax_su_ext); +@@ -3140,17 +2893,13 @@ static inline void htt_print_rx_pdev_rat + len += scnprintf(buf + len, buf_len - len, "txbf = %u\n", + htt_stats_buf->txbf); + +- memset(str_buf, 0x0, HTT_MAX_STRING_LEN); +- PRINT_ARRAY_TO_BUF(str_buf, htt_stats_buf->rx_legacy_cck_rate, +- HTT_RX_PDEV_STATS_NUM_LEGACY_CCK_STATS); +- len += scnprintf(buf + len, buf_len - len, "rx_legacy_cck_rate = %s\n", +- str_buf); +- +- memset(str_buf, 0x0, HTT_MAX_STRING_LEN); +- PRINT_ARRAY_TO_BUF(str_buf, htt_stats_buf->rx_legacy_ofdm_rate, +- HTT_RX_PDEV_STATS_NUM_LEGACY_OFDM_STATS); +- len += scnprintf(buf + len, buf_len - len, "rx_legacy_ofdm_rate = %s\n", +- str_buf); ++ PRINT_ARRAY_TO_BUF(buf, len, htt_stats_buf->rx_legacy_cck_rate, ++ "rx_legacy_cck_rate", ++ HTT_RX_PDEV_STATS_NUM_LEGACY_CCK_STATS, "\n"); ++ ++ PRINT_ARRAY_TO_BUF(buf, len, htt_stats_buf->rx_legacy_ofdm_rate, ++ "rx_legacy_ofdm_rate", ++ HTT_RX_PDEV_STATS_NUM_LEGACY_OFDM_STATS, "\n"); + + len += scnprintf(buf + len, buf_len - len, "rx_active_dur_us_low = %u\n", + htt_stats_buf->rx_active_dur_us_low); +@@ -3159,82 +2908,66 @@ static inline void htt_print_rx_pdev_rat + len += scnprintf(buf + len, buf_len - len, "rx_11ax_ul_ofdma = %u\n", + htt_stats_buf->rx_11ax_ul_ofdma); + +- memset(str_buf, 0x0, HTT_MAX_STRING_LEN); +- PRINT_ARRAY_TO_BUF(str_buf, htt_stats_buf->ul_ofdma_rx_mcs, +- HTT_RX_PDEV_STATS_NUM_MCS_COUNTERS); +- len += scnprintf(buf + len, buf_len - len, "ul_ofdma_rx_mcs = %s\n", str_buf); ++ PRINT_ARRAY_TO_BUF(buf, len, htt_stats_buf->ul_ofdma_rx_mcs, ++ "ul_ofdma_rx_mcs", ++ HTT_RX_PDEV_STATS_NUM_MCS_COUNTERS, "\n"); + + for (j = 0; j < HTT_RX_PDEV_STATS_NUM_GI_COUNTERS; j++) { +- PRINT_ARRAY_TO_BUF(rx_gi[j], htt_stats_buf->ul_ofdma_rx_gi[j], +- HTT_RX_PDEV_STATS_NUM_MCS_COUNTERS); +- len += scnprintf(buf + len, buf_len - len, "ul_ofdma_rx_gi[%u] = %s\n", +- j, rx_gi[j]); ++ len += scnprintf(buf + len, buf_len - len, ++ "ul_ofdma_rx_gi[%u] = ", j); ++ PRINT_ARRAY_TO_BUF(buf, len, htt_stats_buf->ul_ofdma_rx_gi[j], NULL, ++ HTT_RX_PDEV_STATS_NUM_MCS_COUNTERS, "\n"); + } + +- memset(str_buf, 0x0, HTT_MAX_STRING_LEN); +- PRINT_ARRAY_TO_BUF(str_buf, htt_stats_buf->ul_ofdma_rx_nss, +- HTT_RX_PDEV_STATS_NUM_SPATIAL_STREAMS); +- len += scnprintf(buf + len, buf_len - len, "ul_ofdma_rx_nss = %s\n", str_buf); +- +- memset(str_buf, 0x0, HTT_MAX_STRING_LEN); +- PRINT_ARRAY_TO_BUF(str_buf, htt_stats_buf->ul_ofdma_rx_bw, +- HTT_RX_PDEV_STATS_NUM_BW_COUNTERS); +- len += scnprintf(buf + len, buf_len - len, "ul_ofdma_rx_bw = %s\n", str_buf); ++ PRINT_ARRAY_TO_BUF(buf, len, htt_stats_buf->ul_ofdma_rx_nss, ++ "ul_ofdma_rx_nss", ++ HTT_RX_PDEV_STATS_NUM_SPATIAL_STREAMS, "\n"); ++ ++ PRINT_ARRAY_TO_BUF(buf, len, htt_stats_buf->ul_ofdma_rx_bw, "ul_ofdma_rx_bw", ++ HTT_RX_PDEV_STATS_NUM_BW_COUNTERS, "\n"); + + len += scnprintf(buf + len, buf_len - len, "ul_ofdma_rx_stbc = %u\n", + htt_stats_buf->ul_ofdma_rx_stbc); + len += scnprintf(buf + len, buf_len - len, "ul_ofdma_rx_ldpc = %u\n", + htt_stats_buf->ul_ofdma_rx_ldpc); + +- memset(str_buf, 0x0, HTT_MAX_STRING_LEN); +- PRINT_ARRAY_TO_BUF(str_buf, htt_stats_buf->rx_ulofdma_non_data_ppdu, +- HTT_RX_PDEV_MAX_OFDMA_NUM_USER); +- len += scnprintf(buf + len, buf_len - len, "rx_ulofdma_non_data_ppdu = %s\n", +- str_buf); +- +- memset(str_buf, 0x0, HTT_MAX_STRING_LEN); +- PRINT_ARRAY_TO_BUF(str_buf, htt_stats_buf->rx_ulofdma_data_ppdu, +- HTT_RX_PDEV_MAX_OFDMA_NUM_USER); +- len += scnprintf(buf + len, buf_len - len, "rx_ulofdma_data_ppdu = %s\n", +- str_buf); +- +- memset(str_buf, 0x0, HTT_MAX_STRING_LEN); +- PRINT_ARRAY_TO_BUF(str_buf, htt_stats_buf->rx_ulofdma_mpdu_ok, +- HTT_RX_PDEV_MAX_OFDMA_NUM_USER); +- len += scnprintf(buf + len, buf_len - len, "rx_ulofdma_mpdu_ok = %s\n", str_buf); +- +- memset(str_buf, 0x0, HTT_MAX_STRING_LEN); +- PRINT_ARRAY_TO_BUF(str_buf, htt_stats_buf->rx_ulofdma_mpdu_fail, +- HTT_RX_PDEV_MAX_OFDMA_NUM_USER); +- len += scnprintf(buf + len, buf_len - len, "rx_ulofdma_mpdu_fail = %s\n", +- str_buf); ++ PRINT_ARRAY_TO_BUF(buf, len, htt_stats_buf->rx_ulofdma_non_data_ppdu, ++ "rx_ulofdma_non_data_ppdu", ++ HTT_RX_PDEV_MAX_OFDMA_NUM_USER, "\n"); ++ ++ PRINT_ARRAY_TO_BUF(buf, len, htt_stats_buf->rx_ulofdma_data_ppdu, ++ "rx_ulofdma_data_ppdu", HTT_RX_PDEV_MAX_OFDMA_NUM_USER, "\n"); ++ ++ PRINT_ARRAY_TO_BUF(buf, len, htt_stats_buf->rx_ulofdma_mpdu_ok, ++ "rx_ulofdma_mpdu_ok", HTT_RX_PDEV_MAX_OFDMA_NUM_USER, "\n"); ++ ++ PRINT_ARRAY_TO_BUF(buf, len, htt_stats_buf->rx_ulofdma_mpdu_fail, ++ "rx_ulofdma_mpdu_fail", HTT_RX_PDEV_MAX_OFDMA_NUM_USER, "\n"); + + for (j = 0; j < HTT_RX_PDEV_STATS_NUM_SPATIAL_STREAMS; j++) { +- index = 0; +- memset(str_buf, 0x0, HTT_MAX_STRING_LEN); +- for (i = 0; i < HTT_RX_PDEV_MAX_OFDMA_NUM_USER; i++) +- index += scnprintf(&str_buf[index], +- HTT_MAX_STRING_LEN - index, +- " %u:%d,", +- i, htt_stats_buf->rx_ul_fd_rssi[j][i]); + len += scnprintf(buf + len, buf_len - len, +- "rx_ul_fd_rssi: nss[%u] = %s\n", j, str_buf); ++ "rx_ul_fd_rssi: nss[%u] = ", j); ++ for (i = 0; i < HTT_RX_PDEV_MAX_OFDMA_NUM_USER; i++) ++ len += scnprintf(buf + len, ++ buf_len - len, ++ " %u:%d,", ++ i, htt_stats_buf->rx_ul_fd_rssi[j][i]); ++ len += scnprintf(buf + len, buf_len - len, "\n"); + } + + len += scnprintf(buf + len, buf_len - len, "per_chain_rssi_pkt_type = %#x\n", + htt_stats_buf->per_chain_rssi_pkt_type); + + for (j = 0; j < HTT_RX_PDEV_STATS_NUM_SPATIAL_STREAMS; j++) { +- index = 0; +- memset(str_buf, 0x0, HTT_MAX_STRING_LEN); +- for (i = 0; i < HTT_RX_PDEV_STATS_NUM_BW_COUNTERS; i++) +- index += scnprintf(&str_buf[index], +- HTT_MAX_STRING_LEN - index, +- " %u:%d,", +- i, +- htt_stats_buf->rx_per_chain_rssi_in_dbm[j][i]); + len += scnprintf(buf + len, buf_len - len, +- "rx_per_chain_rssi_in_dbm[%u] = %s\n", j, str_buf); ++ "rx_per_chain_rssi_in_dbm[%u] = ", j); ++ for (i = 0; i < HTT_RX_PDEV_STATS_NUM_BW_COUNTERS; i++) ++ len += scnprintf(buf + len, ++ buf_len - len, ++ " %u:%d,", ++ i, ++ htt_stats_buf->rx_per_chain_rssi_in_dbm[j][i]); ++ len += scnprintf(buf + len, buf_len - len, "\n"); + } + len += scnprintf(buf + len, buf_len - len, "\n"); + +@@ -3244,16 +2977,6 @@ static inline void htt_print_rx_pdev_rat + buf[len] = 0; + + stats_req->buf_len = len; +- +-fail: +- for (j = 0; j < HTT_RX_PDEV_STATS_NUM_SPATIAL_STREAMS; j++) +- kfree(rssi_chain[j]); +- +- for (j = 0; j < HTT_RX_PDEV_STATS_NUM_SPATIAL_STREAMS; j++) +- kfree(rx_pilot_evm_db[j]); +- +- for (i = 0; i < HTT_RX_PDEV_STATS_NUM_GI_COUNTERS; i++) +- kfree(rx_gi[i]); + } + + static inline void htt_print_rx_soc_fw_stats_tlv(const void *tag_buf, +@@ -3310,17 +3033,13 @@ htt_print_rx_soc_fw_refill_ring_empty_tl + u8 *buf = stats_req->buf; + u32 len = stats_req->buf_len; + u32 buf_len = ATH11K_HTT_STATS_BUF_SIZE; +- char refill_ring_empty_cnt[HTT_MAX_STRING_LEN] = {0}; + u16 num_elems = min_t(u16, (tag_len >> 2), HTT_RX_STATS_REFILL_MAX_RING); + + len += scnprintf(buf + len, buf_len - len, + "HTT_RX_SOC_FW_REFILL_RING_EMPTY_TLV_V:\n"); + +- PRINT_ARRAY_TO_BUF(refill_ring_empty_cnt, +- htt_stats_buf->refill_ring_empty_cnt, +- num_elems); +- len += scnprintf(buf + len, buf_len - len, "refill_ring_empty_cnt = %s\n\n", +- refill_ring_empty_cnt); ++ PRINT_ARRAY_TO_BUF(buf, len, htt_stats_buf->refill_ring_empty_cnt, ++ "refill_ring_empty_cnt", num_elems, "\n\n"); + + if (len >= buf_len) + buf[buf_len - 1] = 0; +@@ -3340,17 +3059,13 @@ htt_print_rx_soc_fw_refill_ring_num_rxdm + u8 *buf = stats_req->buf; + u32 len = stats_req->buf_len; + u32 buf_len = ATH11K_HTT_STATS_BUF_SIZE; +- char rxdma_err_cnt[HTT_MAX_STRING_LEN] = {0}; + u16 num_elems = min_t(u16, (tag_len >> 2), HTT_RX_RXDMA_MAX_ERR_CODE); + + len += scnprintf(buf + len, buf_len - len, + "HTT_RX_SOC_FW_REFILL_RING_NUM_RXDMA_ERR_TLV_V:\n"); + +- PRINT_ARRAY_TO_BUF(rxdma_err_cnt, +- htt_stats_buf->rxdma_err, +- num_elems); +- len += scnprintf(buf + len, buf_len - len, "rxdma_err = %s\n\n", +- rxdma_err_cnt); ++ PRINT_ARRAY_TO_BUF(buf, len, htt_stats_buf->rxdma_err, "rxdma_err", ++ num_elems, "\n\n"); + + if (len >= buf_len) + buf[buf_len - 1] = 0; +@@ -3369,17 +3084,13 @@ htt_print_rx_soc_fw_refill_ring_num_reo_ + u8 *buf = stats_req->buf; + u32 len = stats_req->buf_len; + u32 buf_len = ATH11K_HTT_STATS_BUF_SIZE; +- char reo_err_cnt[HTT_MAX_STRING_LEN] = {0}; + u16 num_elems = min_t(u16, (tag_len >> 2), HTT_RX_REO_MAX_ERR_CODE); + + len += scnprintf(buf + len, buf_len - len, + "HTT_RX_SOC_FW_REFILL_RING_NUM_REO_ERR_TLV_V:\n"); + +- PRINT_ARRAY_TO_BUF(reo_err_cnt, +- htt_stats_buf->reo_err, +- num_elems); +- len += scnprintf(buf + len, buf_len - len, "reo_err = %s\n\n", +- reo_err_cnt); ++ PRINT_ARRAY_TO_BUF(buf, len, htt_stats_buf->reo_err, "reo_err", ++ num_elems, "\n\n"); + + if (len >= buf_len) + buf[buf_len - 1] = 0; +@@ -3437,17 +3148,13 @@ htt_print_rx_soc_fw_refill_ring_num_refi + u8 *buf = stats_req->buf; + u32 len = stats_req->buf_len; + u32 buf_len = ATH11K_HTT_STATS_BUF_SIZE; +- char refill_ring_num_refill[HTT_MAX_STRING_LEN] = {0}; + u16 num_elems = min_t(u16, (tag_len >> 2), HTT_RX_STATS_REFILL_MAX_RING); + + len += scnprintf(buf + len, buf_len - len, + "HTT_RX_SOC_FW_REFILL_RING_NUM_REFILL_TLV_V:\n"); + +- PRINT_ARRAY_TO_BUF(refill_ring_num_refill, +- htt_stats_buf->refill_ring_num_refill, +- num_elems); +- len += scnprintf(buf + len, buf_len - len, "refill_ring_num_refill = %s\n\n", +- refill_ring_num_refill); ++ PRINT_ARRAY_TO_BUF(buf, len, htt_stats_buf->refill_ring_num_refill, ++ "refill_ring_num_refill", num_elems, "\n\n"); + + if (len >= buf_len) + buf[buf_len - 1] = 0; +@@ -3464,8 +3171,6 @@ static inline void htt_print_rx_pdev_fw_ + u8 *buf = stats_req->buf; + u32 len = stats_req->buf_len; + u32 buf_len = ATH11K_HTT_STATS_BUF_SIZE; +- char fw_ring_mgmt_subtype[HTT_MAX_STRING_LEN] = {0}; +- char fw_ring_ctrl_subtype[HTT_MAX_STRING_LEN] = {0}; + + len += scnprintf(buf + len, buf_len - len, "HTT_RX_PDEV_FW_STATS_TLV:\n"); + len += scnprintf(buf + len, buf_len - len, "mac_id = %u\n", +@@ -3487,17 +3192,12 @@ static inline void htt_print_rx_pdev_fw_ + len += scnprintf(buf + len, buf_len - len, "fw_ring_mpdu_ind = %u\n", + htt_stats_buf->fw_ring_mpdu_ind); + +- PRINT_ARRAY_TO_BUF(fw_ring_mgmt_subtype, +- htt_stats_buf->fw_ring_mgmt_subtype, +- HTT_STATS_SUBTYPE_MAX); +- len += scnprintf(buf + len, buf_len - len, "fw_ring_mgmt_subtype = %s\n", +- fw_ring_mgmt_subtype); +- +- PRINT_ARRAY_TO_BUF(fw_ring_ctrl_subtype, +- htt_stats_buf->fw_ring_ctrl_subtype, +- HTT_STATS_SUBTYPE_MAX); +- len += scnprintf(buf + len, buf_len - len, "fw_ring_ctrl_subtype = %s\n", +- fw_ring_ctrl_subtype); ++ PRINT_ARRAY_TO_BUF(buf, len, htt_stats_buf->fw_ring_mgmt_subtype, ++ "fw_ring_mgmt_subtype", HTT_STATS_SUBTYPE_MAX, "\n"); ++ ++ PRINT_ARRAY_TO_BUF(buf, len, htt_stats_buf->fw_ring_ctrl_subtype, ++ "fw_ring_ctrl_subtype", HTT_STATS_SUBTYPE_MAX, "\n"); ++ + len += scnprintf(buf + len, buf_len - len, "fw_ring_mcast_data_msdu = %u\n", + htt_stats_buf->fw_ring_mcast_data_msdu); + len += scnprintf(buf + len, buf_len - len, "fw_ring_bcast_data_msdu = %u\n", +@@ -3588,16 +3288,12 @@ htt_print_rx_pdev_fw_ring_mpdu_err_tlv_v + u8 *buf = stats_req->buf; + u32 len = stats_req->buf_len; + u32 buf_len = ATH11K_HTT_STATS_BUF_SIZE; +- char fw_ring_mpdu_err[HTT_MAX_STRING_LEN] = {0}; + + len += scnprintf(buf + len, buf_len - len, + "HTT_RX_PDEV_FW_RING_MPDU_ERR_TLV_V:\n"); + +- PRINT_ARRAY_TO_BUF(fw_ring_mpdu_err, +- htt_stats_buf->fw_ring_mpdu_err, +- HTT_RX_STATS_RXDMA_MAX_ERR); +- len += scnprintf(buf + len, buf_len - len, "fw_ring_mpdu_err = %s\n\n", +- fw_ring_mpdu_err); ++ PRINT_ARRAY_TO_BUF(buf, len, htt_stats_buf->fw_ring_mpdu_err, ++ "fw_ring_mpdu_err", HTT_RX_STATS_RXDMA_MAX_ERR, "\n"); + + if (len >= buf_len) + buf[buf_len - 1] = 0; +@@ -3616,15 +3312,12 @@ htt_print_rx_pdev_fw_mpdu_drop_tlv_v(con + u8 *buf = stats_req->buf; + u32 len = stats_req->buf_len; + u32 buf_len = ATH11K_HTT_STATS_BUF_SIZE; +- char fw_mpdu_drop[HTT_MAX_STRING_LEN] = {0}; + u16 num_elems = min_t(u16, (tag_len >> 2), HTT_RX_STATS_FW_DROP_REASON_MAX); + + len += scnprintf(buf + len, buf_len - len, "HTT_RX_PDEV_FW_MPDU_DROP_TLV_V:\n"); + +- PRINT_ARRAY_TO_BUF(fw_mpdu_drop, +- htt_stats_buf->fw_mpdu_drop, +- num_elems); +- len += scnprintf(buf + len, buf_len - len, "fw_mpdu_drop = %s\n\n", fw_mpdu_drop); ++ PRINT_ARRAY_TO_BUF(buf, len, htt_stats_buf->fw_mpdu_drop, "fw_mpdu_drop", ++ num_elems, "\n\n"); + + if (len >= buf_len) + buf[buf_len - 1] = 0; +@@ -3642,7 +3335,6 @@ htt_print_rx_pdev_fw_stats_phy_err_tlv(c + u8 *buf = stats_req->buf; + u32 len = stats_req->buf_len; + u32 buf_len = ATH11K_HTT_STATS_BUF_SIZE; +- char phy_errs[HTT_MAX_STRING_LEN] = {0}; + + len += scnprintf(buf + len, buf_len - len, "HTT_RX_PDEV_FW_STATS_PHY_ERR_TLV:\n"); + len += scnprintf(buf + len, buf_len - len, "mac_id__word = %u\n", +@@ -3650,10 +3342,8 @@ htt_print_rx_pdev_fw_stats_phy_err_tlv(c + len += scnprintf(buf + len, buf_len - len, "total_phy_err_nct = %u\n", + htt_stats_buf->total_phy_err_cnt); + +- PRINT_ARRAY_TO_BUF(phy_errs, +- htt_stats_buf->phy_err, +- HTT_STATS_PHY_ERR_MAX); +- len += scnprintf(buf + len, buf_len - len, "phy_errs = %s\n\n", phy_errs); ++ PRINT_ARRAY_TO_BUF(buf, len, htt_stats_buf->phy_err, "phy_errs", ++ HTT_STATS_PHY_ERR_MAX, "\n\n"); + + if (len >= buf_len) + buf[buf_len - 1] = 0; diff --git a/package/kernel/mac80211/patches/ath11k/0046-ath11k-Change-masking-and-shifting-in-htt-stats.patch b/package/kernel/mac80211/patches/ath11k/0046-ath11k-Change-masking-and-shifting-in-htt-stats.patch new file mode 100644 index 000000000..4ebb1021f --- /dev/null +++ b/package/kernel/mac80211/patches/ath11k/0046-ath11k-Change-masking-and-shifting-in-htt-stats.patch @@ -0,0 +1,683 @@ +From 6ed731829cf862dc1f73bbd063662d8a6c78a5b7 Mon Sep 17 00:00:00 2001 +From: Seevalamuthu Mariappan +Date: Tue, 28 Sep 2021 14:00:45 +0300 +Subject: [PATCH 046/120] ath11k: Change masking and shifting in htt stats + +In debugfs_htt_stats.c, masking and shifting is done to get +stats values. Instead use GENMASK and FIELD_GET to improve +code readability and maintenance. + +Tested-on: IPQ8074 hw2.0 AHB WLAN.HK.2.5.0.1-01105-QCAHKSWPL_SILICONZ-1 + +Signed-off-by: Seevalamuthu Mariappan +Signed-off-by: Jouni Malinen +Signed-off-by: Kalle Valo +Link: https://lore.kernel.org/r/20210913223148.208026-5-jouni@codeaurora.org +--- + .../wireless/ath/ath11k/debugfs_htt_stats.c | 318 ++++++++++-------- + .../wireless/ath/ath11k/debugfs_htt_stats.h | 54 +++ + drivers/net/wireless/ath/ath11k/dp.h | 7 + + 3 files changed, 243 insertions(+), 136 deletions(-) + +--- a/drivers/net/wireless/ath/ath11k/debugfs_htt_stats.c ++++ b/drivers/net/wireless/ath/ath11k/debugfs_htt_stats.c +@@ -75,8 +75,8 @@ static inline void htt_print_tx_pdev_sta + u32 buf_len = ATH11K_HTT_STATS_BUF_SIZE; + + len += scnprintf(buf + len, buf_len - len, "HTT_TX_PDEV_STATS_CMN_TLV:\n"); +- len += scnprintf(buf + len, buf_len - len, "mac_id = %u\n", +- htt_stats_buf->mac_id__word & 0xFF); ++ len += scnprintf(buf + len, buf_len - len, "mac_id = %lu\n", ++ FIELD_GET(HTT_STATS_MAC_ID, htt_stats_buf->mac_id__word)); + len += scnprintf(buf + len, buf_len - len, "hw_queued = %u\n", + htt_stats_buf->hw_queued); + len += scnprintf(buf + len, buf_len - len, "hw_reaped = %u\n", +@@ -428,8 +428,8 @@ static inline void htt_print_hw_stats_pd + u32 buf_len = ATH11K_HTT_STATS_BUF_SIZE; + + len += scnprintf(buf + len, buf_len - len, "HTT_HW_STATS_PDEV_ERRS_TLV:\n"); +- len += scnprintf(buf + len, buf_len - len, "mac_id = %u\n", +- htt_stats_buf->mac_id__word & 0xFF); ++ len += scnprintf(buf + len, buf_len - len, "mac_id = %lu\n", ++ FIELD_GET(HTT_STATS_MAC_ID, htt_stats_buf->mac_id__word)); + len += scnprintf(buf + len, buf_len - len, "tx_abort = %u\n", + htt_stats_buf->tx_abort); + len += scnprintf(buf + len, buf_len - len, "tx_abort_fail_count = %u\n", +@@ -480,13 +480,15 @@ static inline void htt_print_msdu_flow_s + htt_stats_buf->cur_msdu_count_in_flowq); + len += scnprintf(buf + len, buf_len - len, "sw_peer_id = %u\n", + htt_stats_buf->sw_peer_id); +- len += scnprintf(buf + len, buf_len - len, "tx_flow_no = %u\n", +- htt_stats_buf->tx_flow_no__tid_num__drop_rule & 0xFFFF); +- len += scnprintf(buf + len, buf_len - len, "tid_num = %u\n", +- (htt_stats_buf->tx_flow_no__tid_num__drop_rule & 0xF0000) >> 16); +- len += scnprintf(buf + len, buf_len - len, "drop_rule = %u\n", +- (htt_stats_buf->tx_flow_no__tid_num__drop_rule & 0x100000) >> +- 20); ++ len += scnprintf(buf + len, buf_len - len, "tx_flow_no = %lu\n", ++ FIELD_GET(HTT_MSDU_FLOW_STATS_TX_FLOW_NO, ++ htt_stats_buf->tx_flow_no__tid_num__drop_rule)); ++ len += scnprintf(buf + len, buf_len - len, "tid_num = %lu\n", ++ FIELD_GET(HTT_MSDU_FLOW_STATS_TID_NUM, ++ htt_stats_buf->tx_flow_no__tid_num__drop_rule)); ++ len += scnprintf(buf + len, buf_len - len, "drop_rule = %lu\n", ++ FIELD_GET(HTT_MSDU_FLOW_STATS_DROP_RULE, ++ htt_stats_buf->tx_flow_no__tid_num__drop_rule)); + len += scnprintf(buf + len, buf_len - len, "last_cycle_enqueue_count = %u\n", + htt_stats_buf->last_cycle_enqueue_count); + len += scnprintf(buf + len, buf_len - len, "last_cycle_dequeue_count = %u\n", +@@ -516,15 +518,18 @@ static inline void htt_print_tx_tid_stat + len += scnprintf(buf + len, buf_len - len, "HTT_TX_TID_STATS_TLV:\n"); + memcpy(tid_name, &(htt_stats_buf->tid_name[0]), MAX_HTT_TID_NAME); + len += scnprintf(buf + len, buf_len - len, "tid_name = %s\n", tid_name); +- len += scnprintf(buf + len, buf_len - len, "sw_peer_id = %u\n", +- htt_stats_buf->sw_peer_id__tid_num & 0xFFFF); +- len += scnprintf(buf + len, buf_len - len, "tid_num = %u\n", +- (htt_stats_buf->sw_peer_id__tid_num & 0xFFFF0000) >> 16); +- len += scnprintf(buf + len, buf_len - len, "num_sched_pending = %u\n", +- htt_stats_buf->num_sched_pending__num_ppdu_in_hwq & 0xFF); +- len += scnprintf(buf + len, buf_len - len, "num_ppdu_in_hwq = %u\n", +- (htt_stats_buf->num_sched_pending__num_ppdu_in_hwq & +- 0xFF00) >> 8); ++ len += scnprintf(buf + len, buf_len - len, "sw_peer_id = %lu\n", ++ FIELD_GET(HTT_TX_TID_STATS_SW_PEER_ID, ++ htt_stats_buf->sw_peer_id__tid_num)); ++ len += scnprintf(buf + len, buf_len - len, "tid_num = %lu\n", ++ FIELD_GET(HTT_TX_TID_STATS_TID_NUM, ++ htt_stats_buf->sw_peer_id__tid_num)); ++ len += scnprintf(buf + len, buf_len - len, "num_sched_pending = %lu\n", ++ FIELD_GET(HTT_TX_TID_STATS_NUM_SCHED_PENDING, ++ htt_stats_buf->num_sched_pending__num_ppdu_in_hwq)); ++ len += scnprintf(buf + len, buf_len - len, "num_ppdu_in_hwq = %lu\n", ++ FIELD_GET(HTT_TX_TID_STATS_NUM_PPDU_IN_HWQ, ++ htt_stats_buf->num_sched_pending__num_ppdu_in_hwq)); + len += scnprintf(buf + len, buf_len - len, "tid_flags = 0x%x\n", + htt_stats_buf->tid_flags); + len += scnprintf(buf + len, buf_len - len, "hw_queued = %u\n", +@@ -566,15 +571,18 @@ static inline void htt_print_tx_tid_stat + len += scnprintf(buf + len, buf_len - len, "HTT_TX_TID_STATS_V1_TLV:\n"); + memcpy(tid_name, &(htt_stats_buf->tid_name[0]), MAX_HTT_TID_NAME); + len += scnprintf(buf + len, buf_len - len, "tid_name = %s\n", tid_name); +- len += scnprintf(buf + len, buf_len - len, "sw_peer_id = %u\n", +- htt_stats_buf->sw_peer_id__tid_num & 0xFFFF); +- len += scnprintf(buf + len, buf_len - len, "tid_num = %u\n", +- (htt_stats_buf->sw_peer_id__tid_num & 0xFFFF0000) >> 16); +- len += scnprintf(buf + len, buf_len - len, "num_sched_pending = %u\n", +- htt_stats_buf->num_sched_pending__num_ppdu_in_hwq & 0xFF); +- len += scnprintf(buf + len, buf_len - len, "num_ppdu_in_hwq = %u\n", +- (htt_stats_buf->num_sched_pending__num_ppdu_in_hwq & +- 0xFF00) >> 8); ++ len += scnprintf(buf + len, buf_len - len, "sw_peer_id = %lu\n", ++ FIELD_GET(HTT_TX_TID_STATS_V1_SW_PEER_ID, ++ htt_stats_buf->sw_peer_id__tid_num)); ++ len += scnprintf(buf + len, buf_len - len, "tid_num = %lu\n", ++ FIELD_GET(HTT_TX_TID_STATS_V1_TID_NUM, ++ htt_stats_buf->sw_peer_id__tid_num)); ++ len += scnprintf(buf + len, buf_len - len, "num_sched_pending = %lu\n", ++ FIELD_GET(HTT_TX_TID_STATS_V1_NUM_SCHED_PENDING, ++ htt_stats_buf->num_sched_pending__num_ppdu_in_hwq)); ++ len += scnprintf(buf + len, buf_len - len, "num_ppdu_in_hwq = %lu\n", ++ FIELD_GET(HTT_TX_TID_STATS_V1_NUM_PPDU_IN_HWQ, ++ htt_stats_buf->num_sched_pending__num_ppdu_in_hwq)); + len += scnprintf(buf + len, buf_len - len, "tid_flags = 0x%x\n", + htt_stats_buf->tid_flags); + len += scnprintf(buf + len, buf_len - len, "max_qdepth_bytes = %u\n", +@@ -618,10 +626,12 @@ static inline void htt_print_rx_tid_stat + char tid_name[MAX_HTT_TID_NAME + 1] = {0}; + + len += scnprintf(buf + len, buf_len - len, "HTT_RX_TID_STATS_TLV:\n"); +- len += scnprintf(buf + len, buf_len - len, "sw_peer_id = %u\n", +- htt_stats_buf->sw_peer_id__tid_num & 0xFFFF); +- len += scnprintf(buf + len, buf_len - len, "tid_num = %u\n", +- (htt_stats_buf->sw_peer_id__tid_num & 0xFFFF0000) >> 16); ++ len += scnprintf(buf + len, buf_len - len, "sw_peer_id = %lu\n", ++ FIELD_GET(HTT_RX_TID_STATS_SW_PEER_ID, ++ htt_stats_buf->sw_peer_id__tid_num)); ++ len += scnprintf(buf + len, buf_len - len, "tid_num = %lu\n", ++ FIELD_GET(HTT_RX_TID_STATS_TID_NUM, ++ htt_stats_buf->sw_peer_id__tid_num)); + memcpy(tid_name, &(htt_stats_buf->tid_name[0]), MAX_HTT_TID_NAME); + len += scnprintf(buf + len, buf_len - len, "tid_name = %s\n", tid_name); + len += scnprintf(buf + len, buf_len - len, "dup_in_reorder = %u\n", +@@ -724,20 +734,29 @@ static inline void htt_print_peer_detail + htt_stats_buf->peer_type); + len += scnprintf(buf + len, buf_len - len, "sw_peer_id = %u\n", + htt_stats_buf->sw_peer_id); +- len += scnprintf(buf + len, buf_len - len, "vdev_id = %u\n", +- htt_stats_buf->vdev_pdev_ast_idx & 0xFF); +- len += scnprintf(buf + len, buf_len - len, "pdev_id = %u\n", +- (htt_stats_buf->vdev_pdev_ast_idx & 0xFF00) >> 8); +- len += scnprintf(buf + len, buf_len - len, "ast_idx = %u\n", +- (htt_stats_buf->vdev_pdev_ast_idx & 0xFFFF0000) >> 16); +- len += scnprintf(buf + len, buf_len - len, +- "mac_addr = %02x:%02x:%02x:%02x:%02x:%02x\n", +- htt_stats_buf->mac_addr.mac_addr_l32 & 0xFF, +- (htt_stats_buf->mac_addr.mac_addr_l32 & 0xFF00) >> 8, +- (htt_stats_buf->mac_addr.mac_addr_l32 & 0xFF0000) >> 16, +- (htt_stats_buf->mac_addr.mac_addr_l32 & 0xFF000000) >> 24, +- (htt_stats_buf->mac_addr.mac_addr_h16 & 0xFF), +- (htt_stats_buf->mac_addr.mac_addr_h16 & 0xFF00) >> 8); ++ len += scnprintf(buf + len, buf_len - len, "vdev_id = %lu\n", ++ FIELD_GET(HTT_PEER_DETAILS_VDEV_ID, ++ htt_stats_buf->vdev_pdev_ast_idx)); ++ len += scnprintf(buf + len, buf_len - len, "pdev_id = %lu\n", ++ FIELD_GET(HTT_PEER_DETAILS_PDEV_ID, ++ htt_stats_buf->vdev_pdev_ast_idx)); ++ len += scnprintf(buf + len, buf_len - len, "ast_idx = %lu\n", ++ FIELD_GET(HTT_PEER_DETAILS_AST_IDX, ++ htt_stats_buf->vdev_pdev_ast_idx)); ++ len += scnprintf(buf + len, buf_len - len, ++ "mac_addr = %02lx:%02lx:%02lx:%02lx:%02lx:%02lx\n", ++ FIELD_GET(HTT_MAC_ADDR_L32_0, ++ htt_stats_buf->mac_addr.mac_addr_l32), ++ FIELD_GET(HTT_MAC_ADDR_L32_1, ++ htt_stats_buf->mac_addr.mac_addr_l32), ++ FIELD_GET(HTT_MAC_ADDR_L32_2, ++ htt_stats_buf->mac_addr.mac_addr_l32), ++ FIELD_GET(HTT_MAC_ADDR_L32_3, ++ htt_stats_buf->mac_addr.mac_addr_l32), ++ FIELD_GET(HTT_MAC_ADDR_H16_0, ++ htt_stats_buf->mac_addr.mac_addr_h16), ++ FIELD_GET(HTT_MAC_ADDR_H16_1, ++ htt_stats_buf->mac_addr.mac_addr_h16)); + len += scnprintf(buf + len, buf_len - len, "peer_flags = 0x%x\n", + htt_stats_buf->peer_flags); + len += scnprintf(buf + len, buf_len - len, "qpeer_flags = 0x%x\n\n", +@@ -799,7 +818,6 @@ static inline void htt_print_tx_peer_rat + buf[len] = 0; + + stats_req->buf_len = len; +- + } + + static inline void htt_print_rx_peer_rate_stats_tlv(const void *tag_buf, +@@ -930,10 +948,12 @@ htt_print_tx_hwq_mu_mimo_cmn_stats_tlv(c + u32 buf_len = ATH11K_HTT_STATS_BUF_SIZE; + + len += scnprintf(buf + len, buf_len - len, "HTT_TX_HWQ_MU_MIMO_CMN_STATS_TLV:\n"); +- len += scnprintf(buf + len, buf_len - len, "mac_id = %u\n", +- htt_stats_buf->mac_id__hwq_id__word & 0xFF); +- len += scnprintf(buf + len, buf_len - len, "hwq_id = %u\n\n", +- (htt_stats_buf->mac_id__hwq_id__word & 0xFF00) >> 8); ++ len += scnprintf(buf + len, buf_len - len, "mac_id = %lu\n", ++ FIELD_GET(HTT_TX_HWQ_STATS_MAC_ID, ++ htt_stats_buf->mac_id__hwq_id__word)); ++ len += scnprintf(buf + len, buf_len - len, "hwq_id = %lu\n\n", ++ FIELD_GET(HTT_TX_HWQ_STATS_HWQ_ID, ++ htt_stats_buf->mac_id__hwq_id__word)); + + if (len >= buf_len) + buf[buf_len - 1] = 0; +@@ -953,10 +973,12 @@ htt_print_tx_hwq_stats_cmn_tlv(const voi + + /* TODO: HKDBG */ + len += scnprintf(buf + len, buf_len - len, "HTT_TX_HWQ_STATS_CMN_TLV:\n"); +- len += scnprintf(buf + len, buf_len - len, "mac_id = %u\n", +- htt_stats_buf->mac_id__hwq_id__word & 0xFF); +- len += scnprintf(buf + len, buf_len - len, "hwq_id = %u\n", +- (htt_stats_buf->mac_id__hwq_id__word & 0xFF00) >> 8); ++ len += scnprintf(buf + len, buf_len - len, "mac_id = %lu\n", ++ FIELD_GET(HTT_TX_HWQ_STATS_MAC_ID, ++ htt_stats_buf->mac_id__hwq_id__word)); ++ len += scnprintf(buf + len, buf_len - len, "hwq_id = %lu\n", ++ FIELD_GET(HTT_TX_HWQ_STATS_HWQ_ID, ++ htt_stats_buf->mac_id__hwq_id__word)); + len += scnprintf(buf + len, buf_len - len, "xretry = %u\n", + htt_stats_buf->xretry); + len += scnprintf(buf + len, buf_len - len, "underrun_cnt = %u\n", +@@ -1281,8 +1303,8 @@ htt_print_tx_selfgen_cmn_stats_tlv(const + u32 buf_len = ATH11K_HTT_STATS_BUF_SIZE; + + len += scnprintf(buf + len, buf_len - len, "HTT_TX_SELFGEN_CMN_STATS_TLV:\n"); +- len += scnprintf(buf + len, buf_len - len, "mac_id = %u\n", +- htt_stats_buf->mac_id__word & 0xFF); ++ len += scnprintf(buf + len, buf_len - len, "mac_id = %lu\n", ++ FIELD_GET(HTT_STATS_MAC_ID, htt_stats_buf->mac_id__word)); + len += scnprintf(buf + len, buf_len - len, "su_bar = %u\n", + htt_stats_buf->su_bar); + len += scnprintf(buf + len, buf_len - len, "rts = %u\n", +@@ -1769,10 +1791,12 @@ htt_print_tx_pdev_stats_sched_per_txq_tl + + len += scnprintf(buf + len, buf_len - len, + "HTT_TX_PDEV_STATS_SCHED_PER_TXQ_TLV:\n"); +- len += scnprintf(buf + len, buf_len - len, "mac_id = %u\n", +- htt_stats_buf->mac_id__txq_id__word & 0xFF); +- len += scnprintf(buf + len, buf_len - len, "txq_id = %u\n", +- (htt_stats_buf->mac_id__txq_id__word & 0xFF00) >> 8); ++ len += scnprintf(buf + len, buf_len - len, "mac_id = %lu\n", ++ FIELD_GET(HTT_TX_PDEV_STATS_SCHED_PER_TXQ_MAC_ID, ++ htt_stats_buf->mac_id__txq_id__word)); ++ len += scnprintf(buf + len, buf_len - len, "txq_id = %lu\n", ++ FIELD_GET(HTT_TX_PDEV_STATS_SCHED_PER_TXQ_ID, ++ htt_stats_buf->mac_id__txq_id__word)); + len += scnprintf(buf + len, buf_len - len, "sched_policy = %u\n", + htt_stats_buf->sched_policy); + len += scnprintf(buf + len, buf_len - len, +@@ -1833,8 +1857,8 @@ static inline void htt_print_stats_tx_sc + u32 buf_len = ATH11K_HTT_STATS_BUF_SIZE; + + len += scnprintf(buf + len, buf_len - len, "HTT_STATS_TX_SCHED_CMN_TLV:\n"); +- len += scnprintf(buf + len, buf_len - len, "mac_id = %u\n", +- htt_stats_buf->mac_id__word & 0xFF); ++ len += scnprintf(buf + len, buf_len - len, "mac_id = %lu\n", ++ FIELD_GET(HTT_STATS_MAC_ID, htt_stats_buf->mac_id__word)); + len += scnprintf(buf + len, buf_len - len, "current_timestamp = %u\n\n", + htt_stats_buf->current_timestamp); + +@@ -2011,8 +2035,8 @@ static inline void htt_print_tx_tqm_cmn_ + u32 buf_len = ATH11K_HTT_STATS_BUF_SIZE; + + len += scnprintf(buf + len, buf_len - len, "HTT_TX_TQM_CMN_STATS_TLV:\n"); +- len += scnprintf(buf + len, buf_len - len, "mac_id = %u\n", +- htt_stats_buf->mac_id__word & 0xFF); ++ len += scnprintf(buf + len, buf_len - len, "mac_id = %lu\n", ++ FIELD_GET(HTT_STATS_MAC_ID, htt_stats_buf->mac_id__word)); + len += scnprintf(buf + len, buf_len - len, "max_cmdq_id = %u\n", + htt_stats_buf->max_cmdq_id); + len += scnprintf(buf + len, buf_len - len, "list_mpdu_cnt_hist_intvl = %u\n", +@@ -2069,10 +2093,12 @@ static inline void htt_print_tx_tqm_cmdq + u32 buf_len = ATH11K_HTT_STATS_BUF_SIZE; + + len += scnprintf(buf + len, buf_len - len, "HTT_TX_TQM_CMDQ_STATUS_TLV:\n"); +- len += scnprintf(buf + len, buf_len - len, "mac_id = %u\n", +- htt_stats_buf->mac_id__cmdq_id__word & 0xFF); +- len += scnprintf(buf + len, buf_len - len, "cmdq_id = %u\n\n", +- (htt_stats_buf->mac_id__cmdq_id__word & 0xFF00) >> 8); ++ len += scnprintf(buf + len, buf_len - len, "mac_id = %lu\n", ++ FIELD_GET(HTT_TX_TQM_CMDQ_STATUS_MAC_ID, ++ htt_stats_buf->mac_id__cmdq_id__word)); ++ len += scnprintf(buf + len, buf_len - len, "cmdq_id = %lu\n\n", ++ FIELD_GET(HTT_TX_TQM_CMDQ_STATUS_CMDQ_ID, ++ htt_stats_buf->mac_id__cmdq_id__word)); + len += scnprintf(buf + len, buf_len - len, "sync_cmd = %u\n", + htt_stats_buf->sync_cmd); + len += scnprintf(buf + len, buf_len - len, "write_cmd = %u\n", +@@ -2417,8 +2443,8 @@ htt_print_tx_de_cmn_stats_tlv(const void + u32 buf_len = ATH11K_HTT_STATS_BUF_SIZE; + + len += scnprintf(buf + len, buf_len - len, "HTT_TX_DE_CMN_STATS_TLV:\n"); +- len += scnprintf(buf + len, buf_len - len, "mac_id = %u\n", +- htt_stats_buf->mac_id__word & 0xFF); ++ len += scnprintf(buf + len, buf_len - len, "mac_id = %lu\n", ++ FIELD_GET(HTT_STATS_MAC_ID, htt_stats_buf->mac_id__word)); + len += scnprintf(buf + len, buf_len - len, "tcl2fw_entry_count = %u\n", + htt_stats_buf->tcl2fw_entry_count); + len += scnprintf(buf + len, buf_len - len, "not_to_fw = %u\n", +@@ -2453,26 +2479,32 @@ static inline void htt_print_ring_if_sta + htt_stats_buf->base_addr); + len += scnprintf(buf + len, buf_len - len, "elem_size = %u\n", + htt_stats_buf->elem_size); +- len += scnprintf(buf + len, buf_len - len, "num_elems = %u\n", +- htt_stats_buf->num_elems__prefetch_tail_idx & 0xFFFF); +- len += scnprintf(buf + len, buf_len - len, "prefetch_tail_idx = %u\n", +- (htt_stats_buf->num_elems__prefetch_tail_idx & +- 0xFFFF0000) >> 16); +- len += scnprintf(buf + len, buf_len - len, "head_idx = %u\n", +- htt_stats_buf->head_idx__tail_idx & 0xFFFF); +- len += scnprintf(buf + len, buf_len - len, "tail_idx = %u\n", +- (htt_stats_buf->head_idx__tail_idx & 0xFFFF0000) >> 16); +- len += scnprintf(buf + len, buf_len - len, "shadow_head_idx = %u\n", +- htt_stats_buf->shadow_head_idx__shadow_tail_idx & 0xFFFF); +- len += scnprintf(buf + len, buf_len - len, "shadow_tail_idx = %u\n", +- (htt_stats_buf->shadow_head_idx__shadow_tail_idx & +- 0xFFFF0000) >> 16); ++ len += scnprintf(buf + len, buf_len - len, "num_elems = %lu\n", ++ FIELD_GET(HTT_RING_IF_STATS_NUM_ELEMS, ++ htt_stats_buf->num_elems__prefetch_tail_idx)); ++ len += scnprintf(buf + len, buf_len - len, "prefetch_tail_idx = %lu\n", ++ FIELD_GET(HTT_RING_IF_STATS_PREFETCH_TAIL_INDEX, ++ htt_stats_buf->num_elems__prefetch_tail_idx)); ++ len += scnprintf(buf + len, buf_len - len, "head_idx = %lu\n", ++ FIELD_GET(HTT_RING_IF_STATS_HEAD_IDX, ++ htt_stats_buf->head_idx__tail_idx)); ++ len += scnprintf(buf + len, buf_len - len, "tail_idx = %lu\n", ++ FIELD_GET(HTT_RING_IF_STATS_TAIL_IDX, ++ htt_stats_buf->head_idx__tail_idx)); ++ len += scnprintf(buf + len, buf_len - len, "shadow_head_idx = %lu\n", ++ FIELD_GET(HTT_RING_IF_STATS_SHADOW_HEAD_IDX, ++ htt_stats_buf->shadow_head_idx__shadow_tail_idx)); ++ len += scnprintf(buf + len, buf_len - len, "shadow_tail_idx = %lu\n", ++ FIELD_GET(HTT_RING_IF_STATS_SHADOW_TAIL_IDX, ++ htt_stats_buf->shadow_head_idx__shadow_tail_idx)); + len += scnprintf(buf + len, buf_len - len, "num_tail_incr = %u\n", + htt_stats_buf->num_tail_incr); +- len += scnprintf(buf + len, buf_len - len, "lwm_thresh = %u\n", +- htt_stats_buf->lwm_thresh__hwm_thresh & 0xFFFF); +- len += scnprintf(buf + len, buf_len - len, "hwm_thresh = %u\n", +- (htt_stats_buf->lwm_thresh__hwm_thresh & 0xFFFF0000) >> 16); ++ len += scnprintf(buf + len, buf_len - len, "lwm_thresh = %lu\n", ++ FIELD_GET(HTT_RING_IF_STATS_LWM_THRESH, ++ htt_stats_buf->lwm_thresh__hwm_thresh)); ++ len += scnprintf(buf + len, buf_len - len, "hwm_thresh = %lu\n", ++ FIELD_GET(HTT_RING_IF_STATS_HWM_THRESH, ++ htt_stats_buf->lwm_thresh__hwm_thresh)); + len += scnprintf(buf + len, buf_len - len, "overrun_hit_count = %u\n", + htt_stats_buf->overrun_hit_count); + len += scnprintf(buf + len, buf_len - len, "underrun_hit_count = %u\n", +@@ -2504,8 +2536,8 @@ static inline void htt_print_ring_if_cmn + u32 buf_len = ATH11K_HTT_STATS_BUF_SIZE; + + len += scnprintf(buf + len, buf_len - len, "HTT_RING_IF_CMN_TLV:\n"); +- len += scnprintf(buf + len, buf_len - len, "mac_id = %u\n", +- htt_stats_buf->mac_id__word & 0xFF); ++ len += scnprintf(buf + len, buf_len - len, "mac_id = %lu\n", ++ FIELD_GET(HTT_STATS_MAC_ID, htt_stats_buf->mac_id__word)); + len += scnprintf(buf + len, buf_len - len, "num_records = %u\n\n", + htt_stats_buf->num_records); + +@@ -2581,8 +2613,8 @@ static inline void htt_print_sfm_cmn_tlv + u32 buf_len = ATH11K_HTT_STATS_BUF_SIZE; + + len += scnprintf(buf + len, buf_len - len, "HTT_SFM_CMN_TLV:\n"); +- len += scnprintf(buf + len, buf_len - len, "mac_id = %u\n", +- htt_stats_buf->mac_id__word & 0xFF); ++ len += scnprintf(buf + len, buf_len - len, "mac_id = %lu\n", ++ FIELD_GET(HTT_STATS_MAC_ID, htt_stats_buf->mac_id__word)); + len += scnprintf(buf + len, buf_len - len, "buf_total = %u\n", + htt_stats_buf->buf_total); + len += scnprintf(buf + len, buf_len - len, "mem_empty = %u\n", +@@ -2609,14 +2641,18 @@ static inline void htt_print_sring_stats + u32 buf_len = ATH11K_HTT_STATS_BUF_SIZE; + + len += scnprintf(buf + len, buf_len - len, "HTT_SRING_STATS_TLV:\n"); +- len += scnprintf(buf + len, buf_len - len, "mac_id = %u\n", +- htt_stats_buf->mac_id__ring_id__arena__ep & 0xFF); +- len += scnprintf(buf + len, buf_len - len, "ring_id = %u\n", +- (htt_stats_buf->mac_id__ring_id__arena__ep & 0xFF00) >> 8); +- len += scnprintf(buf + len, buf_len - len, "arena = %u\n", +- (htt_stats_buf->mac_id__ring_id__arena__ep & 0xFF0000) >> 16); +- len += scnprintf(buf + len, buf_len - len, "ep = %u\n", +- (htt_stats_buf->mac_id__ring_id__arena__ep & 0x1000000) >> 24); ++ len += scnprintf(buf + len, buf_len - len, "mac_id = %lu\n", ++ FIELD_GET(HTT_SRING_STATS_MAC_ID, ++ htt_stats_buf->mac_id__ring_id__arena__ep)); ++ len += scnprintf(buf + len, buf_len - len, "ring_id = %lu\n", ++ FIELD_GET(HTT_SRING_STATS_RING_ID, ++ htt_stats_buf->mac_id__ring_id__arena__ep)); ++ len += scnprintf(buf + len, buf_len - len, "arena = %lu\n", ++ FIELD_GET(HTT_SRING_STATS_ARENA, ++ htt_stats_buf->mac_id__ring_id__arena__ep)); ++ len += scnprintf(buf + len, buf_len - len, "ep = %lu\n", ++ FIELD_GET(HTT_SRING_STATS_EP, ++ htt_stats_buf->mac_id__ring_id__arena__ep)); + len += scnprintf(buf + len, buf_len - len, "base_addr_lsb = 0x%x\n", + htt_stats_buf->base_addr_lsb); + len += scnprintf(buf + len, buf_len - len, "base_addr_msb = 0x%x\n", +@@ -2625,25 +2661,30 @@ static inline void htt_print_sring_stats + htt_stats_buf->ring_size); + len += scnprintf(buf + len, buf_len - len, "elem_size = %u\n", + htt_stats_buf->elem_size); +- len += scnprintf(buf + len, buf_len - len, "num_avail_words = %u\n", +- htt_stats_buf->num_avail_words__num_valid_words & 0xFFFF); +- len += scnprintf(buf + len, buf_len - len, "num_valid_words = %u\n", +- (htt_stats_buf->num_avail_words__num_valid_words & +- 0xFFFF0000) >> 16); +- len += scnprintf(buf + len, buf_len - len, "head_ptr = %u\n", +- htt_stats_buf->head_ptr__tail_ptr & 0xFFFF); +- len += scnprintf(buf + len, buf_len - len, "tail_ptr = %u\n", +- (htt_stats_buf->head_ptr__tail_ptr & 0xFFFF0000) >> 16); +- len += scnprintf(buf + len, buf_len - len, "consumer_empty = %u\n", +- htt_stats_buf->consumer_empty__producer_full & 0xFFFF); +- len += scnprintf(buf + len, buf_len - len, "producer_full = %u\n", +- (htt_stats_buf->consumer_empty__producer_full & +- 0xFFFF0000) >> 16); +- len += scnprintf(buf + len, buf_len - len, "prefetch_count = %u\n", +- htt_stats_buf->prefetch_count__internal_tail_ptr & 0xFFFF); +- len += scnprintf(buf + len, buf_len - len, "internal_tail_ptr = %u\n\n", +- (htt_stats_buf->prefetch_count__internal_tail_ptr & +- 0xFFFF0000) >> 16); ++ len += scnprintf(buf + len, buf_len - len, "num_avail_words = %lu\n", ++ FIELD_GET(HTT_SRING_STATS_NUM_AVAIL_WORDS, ++ htt_stats_buf->num_avail_words__num_valid_words)); ++ len += scnprintf(buf + len, buf_len - len, "num_valid_words = %lu\n", ++ FIELD_GET(HTT_SRING_STATS_NUM_VALID_WORDS, ++ htt_stats_buf->num_avail_words__num_valid_words)); ++ len += scnprintf(buf + len, buf_len - len, "head_ptr = %lu\n", ++ FIELD_GET(HTT_SRING_STATS_HEAD_PTR, ++ htt_stats_buf->head_ptr__tail_ptr)); ++ len += scnprintf(buf + len, buf_len - len, "tail_ptr = %lu\n", ++ FIELD_GET(HTT_SRING_STATS_TAIL_PTR, ++ htt_stats_buf->head_ptr__tail_ptr)); ++ len += scnprintf(buf + len, buf_len - len, "consumer_empty = %lu\n", ++ FIELD_GET(HTT_SRING_STATS_CONSUMER_EMPTY, ++ htt_stats_buf->consumer_empty__producer_full)); ++ len += scnprintf(buf + len, buf_len - len, "producer_full = %lu\n", ++ FIELD_GET(HTT_SRING_STATS_PRODUCER_FULL, ++ htt_stats_buf->consumer_empty__producer_full)); ++ len += scnprintf(buf + len, buf_len - len, "prefetch_count = %lu\n", ++ FIELD_GET(HTT_SRING_STATS_PREFETCH_COUNT, ++ htt_stats_buf->prefetch_count__internal_tail_ptr)); ++ len += scnprintf(buf + len, buf_len - len, "internal_tail_ptr = %lu\n\n", ++ FIELD_GET(HTT_SRING_STATS_INTERNAL_TAIL_PTR, ++ htt_stats_buf->prefetch_count__internal_tail_ptr)); + + if (len >= buf_len) + buf[buf_len - 1] = 0; +@@ -2683,8 +2724,8 @@ static inline void htt_print_tx_pdev_rat + u8 j; + + len += scnprintf(buf + len, buf_len - len, "HTT_TX_PDEV_RATE_STATS_TLV:\n"); +- len += scnprintf(buf + len, buf_len - len, "mac_id = %u\n", +- htt_stats_buf->mac_id__word & 0xFF); ++ len += scnprintf(buf + len, buf_len - len, "mac_id = %lu\n", ++ FIELD_GET(HTT_STATS_MAC_ID, htt_stats_buf->mac_id__word)); + len += scnprintf(buf + len, buf_len - len, "tx_ldpc = %u\n", + htt_stats_buf->tx_ldpc); + len += scnprintf(buf + len, buf_len - len, "ac_mu_mimo_tx_ldpc = %u\n", +@@ -2809,8 +2850,8 @@ static inline void htt_print_rx_pdev_rat + u8 i, j; + + len += scnprintf(buf + len, buf_len - len, "HTT_RX_PDEV_RATE_STATS_TLV:\n"); +- len += scnprintf(buf + len, buf_len - len, "mac_id = %u\n", +- htt_stats_buf->mac_id__word & 0xFF); ++ len += scnprintf(buf + len, buf_len - len, "mac_id = %lu\n", ++ FIELD_GET(HTT_STATS_MAC_ID, htt_stats_buf->mac_id__word)); + len += scnprintf(buf + len, buf_len - len, "nsts = %u\n", + htt_stats_buf->nsts); + len += scnprintf(buf + len, buf_len - len, "rx_ldpc = %u\n", +@@ -2844,7 +2885,6 @@ static inline void htt_print_rx_pdev_rat + htt_stats_buf->pilot_count); + + for (j = 0; j < HTT_RX_PDEV_STATS_NUM_SPATIAL_STREAMS; j++) { +- + len += scnprintf(buf + len, buf_len - len, + "pilot_evm_db[%u] = ", j); + for (i = 0; i < HTT_RX_PDEV_STATS_RXEVM_MAX_PILOTS_PER_NSS; i++) +@@ -3173,8 +3213,8 @@ static inline void htt_print_rx_pdev_fw_ + u32 buf_len = ATH11K_HTT_STATS_BUF_SIZE; + + len += scnprintf(buf + len, buf_len - len, "HTT_RX_PDEV_FW_STATS_TLV:\n"); +- len += scnprintf(buf + len, buf_len - len, "mac_id = %u\n", +- htt_stats_buf->mac_id__word & 0xFF); ++ len += scnprintf(buf + len, buf_len - len, "mac_id = %lu\n", ++ FIELD_GET(HTT_STATS_MAC_ID, htt_stats_buf->mac_id__word)); + len += scnprintf(buf + len, buf_len - len, "ppdu_recvd = %u\n", + htt_stats_buf->ppdu_recvd); + len += scnprintf(buf + len, buf_len - len, "mpdu_cnt_fcs_ok = %u\n", +@@ -3422,8 +3462,8 @@ static inline void htt_print_hw_stats_wh + u32 buf_len = ATH11K_HTT_STATS_BUF_SIZE; + + len += scnprintf(buf + len, buf_len - len, "HTT_HW_STATS_WHAL_TX_TLV:\n"); +- len += scnprintf(buf + len, buf_len - len, "mac_id = %u\n", +- htt_stats_buf->mac_id__word & 0xFF); ++ len += scnprintf(buf + len, buf_len - len, "mac_id = %lu\n", ++ FIELD_GET(HTT_STATS_MAC_ID, htt_stats_buf->mac_id__word)); + len += scnprintf(buf + len, buf_len - len, "last_unpause_ppdu_id = %u\n", + htt_stats_buf->last_unpause_ppdu_id); + len += scnprintf(buf + len, buf_len - len, "hwsch_unpause_wait_tqm_write = %u\n", +@@ -3492,13 +3532,19 @@ htt_print_pdev_stats_twt_session_tlv(con + len += scnprintf(buf + len, buf_len - len, "vdev_id = %u\n", + htt_stats_buf->vdev_id); + len += scnprintf(buf + len, buf_len - len, +- "peer_mac = %02x:%02x:%02x:%02x:%02x:%02x\n", +- htt_stats_buf->peer_mac.mac_addr_l32 & 0xFF, +- (htt_stats_buf->peer_mac.mac_addr_l32 & 0xFF00) >> 8, +- (htt_stats_buf->peer_mac.mac_addr_l32 & 0xFF0000) >> 16, +- (htt_stats_buf->peer_mac.mac_addr_l32 & 0xFF000000) >> 24, +- (htt_stats_buf->peer_mac.mac_addr_h16 & 0xFF), +- (htt_stats_buf->peer_mac.mac_addr_h16 & 0xFF00) >> 8); ++ "peer_mac = %02lx:%02lx:%02lx:%02lx:%02lx:%02lx\n", ++ FIELD_GET(HTT_MAC_ADDR_L32_0, ++ htt_stats_buf->peer_mac.mac_addr_l32), ++ FIELD_GET(HTT_MAC_ADDR_L32_1, ++ htt_stats_buf->peer_mac.mac_addr_l32), ++ FIELD_GET(HTT_MAC_ADDR_L32_2, ++ htt_stats_buf->peer_mac.mac_addr_l32), ++ FIELD_GET(HTT_MAC_ADDR_L32_3, ++ htt_stats_buf->peer_mac.mac_addr_l32), ++ FIELD_GET(HTT_MAC_ADDR_H16_0, ++ htt_stats_buf->peer_mac.mac_addr_h16), ++ FIELD_GET(HTT_MAC_ADDR_H16_1, ++ htt_stats_buf->peer_mac.mac_addr_h16)); + len += scnprintf(buf + len, buf_len - len, "flow_id_flags = %u\n", + htt_stats_buf->flow_id_flags); + len += scnprintf(buf + len, buf_len - len, "dialog_id = %u\n", +--- a/drivers/net/wireless/ath/ath11k/debugfs_htt_stats.h ++++ b/drivers/net/wireless/ath/ath11k/debugfs_htt_stats.h +@@ -137,6 +137,8 @@ struct htt_stats_string_tlv { + u32 data[0]; /* Can be variable length */ + } __packed; + ++#define HTT_STATS_MAC_ID GENMASK(7, 0) ++ + /* == TX PDEV STATS == */ + struct htt_tx_pdev_stats_cmn_tlv { + u32 mac_id__word; +@@ -290,6 +292,10 @@ struct htt_hw_stats_whal_tx_tlv { + }; + + /* ============ PEER STATS ============ */ ++#define HTT_MSDU_FLOW_STATS_TX_FLOW_NO GENMASK(15, 0) ++#define HTT_MSDU_FLOW_STATS_TID_NUM GENMASK(19, 16) ++#define HTT_MSDU_FLOW_STATS_DROP_RULE BIT(20) ++ + struct htt_msdu_flow_stats_tlv { + u32 last_update_timestamp; + u32 last_add_timestamp; +@@ -306,6 +312,11 @@ struct htt_msdu_flow_stats_tlv { + + #define MAX_HTT_TID_NAME 8 + ++#define HTT_TX_TID_STATS_SW_PEER_ID GENMASK(15, 0) ++#define HTT_TX_TID_STATS_TID_NUM GENMASK(31, 16) ++#define HTT_TX_TID_STATS_NUM_SCHED_PENDING GENMASK(7, 0) ++#define HTT_TX_TID_STATS_NUM_PPDU_IN_HWQ GENMASK(15, 8) ++ + /* Tidq stats */ + struct htt_tx_tid_stats_tlv { + /* Stored as little endian */ +@@ -326,6 +337,11 @@ struct htt_tx_tid_stats_tlv { + u32 tid_tx_airtime; + }; + ++#define HTT_TX_TID_STATS_V1_SW_PEER_ID GENMASK(15, 0) ++#define HTT_TX_TID_STATS_V1_TID_NUM GENMASK(31, 16) ++#define HTT_TX_TID_STATS_V1_NUM_SCHED_PENDING GENMASK(7, 0) ++#define HTT_TX_TID_STATS_V1_NUM_PPDU_IN_HWQ GENMASK(15, 8) ++ + /* Tidq stats */ + struct htt_tx_tid_stats_v1_tlv { + /* Stored as little endian */ +@@ -348,6 +364,9 @@ struct htt_tx_tid_stats_v1_tlv { + u32 sendn_frms_allowed; + }; + ++#define HTT_RX_TID_STATS_SW_PEER_ID GENMASK(15, 0) ++#define HTT_RX_TID_STATS_TID_NUM GENMASK(31, 16) ++ + struct htt_rx_tid_stats_tlv { + u32 sw_peer_id__tid_num; + u8 tid_name[MAX_HTT_TID_NAME]; +@@ -386,6 +405,10 @@ struct htt_peer_stats_cmn_tlv { + u32 inactive_time; + }; + ++#define HTT_PEER_DETAILS_VDEV_ID GENMASK(7, 0) ++#define HTT_PEER_DETAILS_PDEV_ID GENMASK(15, 8) ++#define HTT_PEER_DETAILS_AST_IDX GENMASK(31, 16) ++ + struct htt_peer_details_tlv { + u32 peer_type; + u32 sw_peer_id; +@@ -510,6 +533,9 @@ struct htt_tx_hwq_mu_mimo_mpdu_stats_tlv + u32 mu_mimo_ampdu_underrun_usr; + }; + ++#define HTT_TX_HWQ_STATS_MAC_ID GENMASK(7, 0) ++#define HTT_TX_HWQ_STATS_HWQ_ID GENMASK(15, 8) ++ + struct htt_tx_hwq_mu_mimo_cmn_stats_tlv { + u32 mac_id__hwq_id__word; + }; +@@ -789,6 +815,9 @@ struct htt_sched_txq_sched_ineligibility + u32 sched_ineligibility[0]; + }; + ++#define HTT_TX_PDEV_STATS_SCHED_PER_TXQ_MAC_ID GENMASK(7, 0) ++#define HTT_TX_PDEV_STATS_SCHED_PER_TXQ_ID GENMASK(15, 8) ++ + struct htt_tx_pdev_stats_sched_per_txq_tlv { + u32 mac_id__txq_id__word; + u32 sched_policy; +@@ -910,6 +939,9 @@ struct htt_tx_tqm_error_stats_tlv { + }; + + /* == TQM CMDQ stats == */ ++#define HTT_TX_TQM_CMDQ_STATUS_MAC_ID GENMASK(7, 0) ++#define HTT_TX_TQM_CMDQ_STATUS_CMDQ_ID GENMASK(15, 8) ++ + struct htt_tx_tqm_cmdq_status_tlv { + u32 mac_id__cmdq_id__word; + u32 sync_cmd; +@@ -1055,6 +1087,15 @@ struct htt_tx_de_cmn_stats_tlv { + #define HTT_STATS_LOW_WM_BINS 5 + #define HTT_STATS_HIGH_WM_BINS 5 + ++#define HTT_RING_IF_STATS_NUM_ELEMS GENMASK(15, 0) ++#define HTT_RING_IF_STATS_PREFETCH_TAIL_INDEX GENMASK(31, 16) ++#define HTT_RING_IF_STATS_HEAD_IDX GENMASK(15, 0) ++#define HTT_RING_IF_STATS_TAIL_IDX GENMASK(31, 16) ++#define HTT_RING_IF_STATS_SHADOW_HEAD_IDX GENMASK(15, 0) ++#define HTT_RING_IF_STATS_SHADOW_TAIL_IDX GENMASK(31, 16) ++#define HTT_RING_IF_STATS_LWM_THRESH GENMASK(15, 0) ++#define HTT_RING_IF_STATS_HWM_THRESH GENMASK(31, 16) ++ + struct htt_ring_if_stats_tlv { + u32 base_addr; /* DWORD aligned base memory address of the ring */ + u32 elem_size; +@@ -1117,6 +1158,19 @@ struct htt_sfm_cmn_tlv { + }; + + /* == SRNG STATS == */ ++#define HTT_SRING_STATS_MAC_ID GENMASK(7, 0) ++#define HTT_SRING_STATS_RING_ID GENMASK(15, 8) ++#define HTT_SRING_STATS_ARENA GENMASK(23, 16) ++#define HTT_SRING_STATS_EP BIT(24) ++#define HTT_SRING_STATS_NUM_AVAIL_WORDS GENMASK(15, 0) ++#define HTT_SRING_STATS_NUM_VALID_WORDS GENMASK(31, 16) ++#define HTT_SRING_STATS_HEAD_PTR GENMASK(15, 0) ++#define HTT_SRING_STATS_TAIL_PTR GENMASK(31, 16) ++#define HTT_SRING_STATS_CONSUMER_EMPTY GENMASK(15, 0) ++#define HTT_SRING_STATS_PRODUCER_FULL GENMASK(31, 16) ++#define HTT_SRING_STATS_PREFETCH_COUNT GENMASK(15, 0) ++#define HTT_SRING_STATS_INTERNAL_TAIL_PTR GENMASK(31, 16) ++ + struct htt_sring_stats_tlv { + u32 mac_id__ring_id__arena__ep; + u32 base_addr_lsb; /* DWORD aligned base memory address of the ring */ +--- a/drivers/net/wireless/ath/ath11k/dp.h ++++ b/drivers/net/wireless/ath/ath11k/dp.h +@@ -1593,6 +1593,13 @@ struct ath11k_htt_extd_stats_msg { + u8 data[0]; + } __packed; + ++#define HTT_MAC_ADDR_L32_0 GENMASK(7, 0) ++#define HTT_MAC_ADDR_L32_1 GENMASK(15, 8) ++#define HTT_MAC_ADDR_L32_2 GENMASK(23, 16) ++#define HTT_MAC_ADDR_L32_3 GENMASK(31, 24) ++#define HTT_MAC_ADDR_H16_0 GENMASK(7, 0) ++#define HTT_MAC_ADDR_H16_1 GENMASK(15, 8) ++ + struct htt_mac_addr { + u32 mac_addr_l32; + u32 mac_addr_h16; diff --git a/package/kernel/mac80211/patches/ath11k/0047-ath11k-add-HTT-stats-support-for-new-stats.patch b/package/kernel/mac80211/patches/ath11k/0047-ath11k-add-HTT-stats-support-for-new-stats.patch new file mode 100644 index 000000000..3b7310d37 --- /dev/null +++ b/package/kernel/mac80211/patches/ath11k/0047-ath11k-add-HTT-stats-support-for-new-stats.patch @@ -0,0 +1,677 @@ +From ac83b6034cfa3bec010c1e01d6e6b44673135afe Mon Sep 17 00:00:00 2001 +From: Venkateswara Naralasetty +Date: Tue, 28 Sep 2021 14:00:45 +0300 +Subject: [PATCH 047/120] ath11k: add HTT stats support for new stats + +Add HTT stats support for, + +29-ATH11K_DBG_HTT_EXT_STATS_PEER_CTRL_PATH_TXRX_STATS: +Used to dump the control path txrx stats for each connected peer. +Usage: +echo 29 > /sys/kernel/debug/ieee80211/phyx/ath11k/htt_stats_type +cat /sys/kernel/debug/ieee80211/phyx/netdev\:wlan0/stations/ +/htt_peer_stats. + +31-ATH11K_DBG_HTT_EXT_STATS_PDEV_TX_RATE_TXBF_STATS: +Used to dump the per pdev tx rate txbf stats. +Usage: +echo 31 > /sys/kernel/debug/ieee80211/phyx/ath11k/htt_stats_type +cat /sys/kernel/debug/ieee80211/phyx/ath11k/htt_stats + +32-ATH11k_DBG_HTT_EXT_STATS_TXBF_OFDMA: +Used to dump the TXBF ofdma stats for all ofdma users. +Usage: +echo 32 > /sys/kernel/debug/ieee80211/phyx/ath11k/htt_stats_type +cat /sys/kernel/debug/ieee80211/phyx/ath11k/htt_stats + +37-ATH11K_DBG_HTT_EXT_PHY_COUNTERS_AND_PHY_STATS: +Used to dump the mac and phy txrx counts and phy stats like per chain rssi +and ANI level. +Usage: +echo 37 > /sys/kernel/debug/ieee80211/phyx/ath11k/htt_stats_type +cat /sys/kernel/debug/ieee80211/phyx/ath11k/htt_stats + +Tested-on: IPQ8074 hw2.0 AHB WLAN.HK.2.5.0.1-00486-QCAHKSWPL_SILICONZ-1 + +Signed-off-by: Venkateswara Naralasetty +Signed-off-by: Jouni Malinen +Signed-off-by: Kalle Valo +Link: https://lore.kernel.org/r/20210913223148.208026-6-jouni@codeaurora.org +--- + drivers/net/wireless/ath/ath11k/debugfs.h | 4 + + .../wireless/ath/ath11k/debugfs_htt_stats.c | 368 +++++++++++++++++- + .../wireless/ath/ath11k/debugfs_htt_stats.h | 172 ++++++++ + drivers/net/wireless/ath/ath11k/debugfs_sta.c | 8 +- + 4 files changed, 548 insertions(+), 4 deletions(-) + +--- a/drivers/net/wireless/ath/ath11k/debugfs.h ++++ b/drivers/net/wireless/ath/ath11k/debugfs.h +@@ -38,6 +38,10 @@ enum ath11k_dbg_htt_ext_stats_type { + ATH11K_DBG_HTT_EXT_STATS_TX_SOUNDING_INFO = 22, + ATH11K_DBG_HTT_EXT_STATS_PDEV_OBSS_PD_STATS = 23, + ATH11K_DBG_HTT_EXT_STATS_RING_BACKPRESSURE_STATS = 24, ++ ATH11K_DBG_HTT_EXT_STATS_PEER_CTRL_PATH_TXRX_STATS = 29, ++ ATH11K_DBG_HTT_EXT_STATS_PDEV_TX_RATE_TXBF_STATS = 31, ++ ATH11K_DBG_HTT_EXT_STATS_TXBF_OFDMA = 32, ++ ATH11K_DBG_HTT_EXT_PHY_COUNTERS_AND_PHY_STATS = 37, + + /* keep this last */ + ATH11K_DBG_HTT_NUM_EXT_STATS, +--- a/drivers/net/wireless/ath/ath11k/debugfs_htt_stats.c ++++ b/drivers/net/wireless/ath/ath11k/debugfs_htt_stats.c +@@ -3639,6 +3639,334 @@ static inline void htt_print_backpressur + } + } + ++static inline ++void htt_print_pdev_tx_rate_txbf_stats_tlv(const void *tag_buf, ++ struct debug_htt_stats_req *stats_req) ++{ ++ const struct htt_pdev_txrate_txbf_stats_tlv *htt_stats_buf = tag_buf; ++ u8 *buf = stats_req->buf; ++ u32 len = stats_req->buf_len; ++ u32 buf_len = ATH11K_HTT_STATS_BUF_SIZE; ++ int i; ++ ++ len += scnprintf(buf + len, buf_len - len, ++ "HTT_STATS_PDEV_TX_RATE_TXBF_STATS:\n"); ++ ++ len += scnprintf(buf + len, buf_len - len, "tx_ol_mcs = "); ++ for (i = 0; i < HTT_TX_TXBF_RATE_STATS_NUM_MCS_COUNTERS; i++) ++ len += scnprintf(buf + len, buf_len - len, ++ "%d:%u,", i, htt_stats_buf->tx_su_ol_mcs[i]); ++ len--; ++ ++ len += scnprintf(buf + len, buf_len - len, "\ntx_ibf_mcs = "); ++ for (i = 0; i < HTT_TX_TXBF_RATE_STATS_NUM_MCS_COUNTERS; i++) ++ len += scnprintf(buf + len, buf_len - len, ++ "%d:%u,", i, htt_stats_buf->tx_su_ibf_mcs[i]); ++ len--; ++ ++ len += scnprintf(buf + len, buf_len - len, "\ntx_txbf_mcs ="); ++ for (i = 0; i < HTT_TX_TXBF_RATE_STATS_NUM_MCS_COUNTERS; i++) ++ len += scnprintf(buf + len, buf_len - len, ++ "%d:%u,", i, htt_stats_buf->tx_su_txbf_mcs[i]); ++ len--; ++ ++ len += scnprintf(buf + len, buf_len - len, "\ntx_ol_nss = "); ++ for (i = 0; i < HTT_TX_PDEV_STATS_NUM_SPATIAL_STREAMS; i++) ++ len += scnprintf(buf + len, buf_len - len, ++ "%d:%u,", i, htt_stats_buf->tx_su_ol_nss[i]); ++ len--; ++ ++ len += scnprintf(buf + len, buf_len - len, "\ntx_ibf_nss = "); ++ for (i = 0; i < HTT_TX_PDEV_STATS_NUM_SPATIAL_STREAMS; i++) ++ len += scnprintf(buf + len, buf_len - len, ++ "%d:%u,", i, htt_stats_buf->tx_su_ibf_nss[i]); ++ len--; ++ ++ len += scnprintf(buf + len, buf_len - len, "\ntx_txbf_nss = "); ++ for (i = 0; i < HTT_TX_PDEV_STATS_NUM_SPATIAL_STREAMS; i++) ++ len += scnprintf(buf + len, buf_len - len, ++ "%d:%u,", i, htt_stats_buf->tx_su_txbf_nss[i]); ++ len--; ++ ++ len += scnprintf(buf + len, buf_len - len, "\ntx_ol_bw = "); ++ for (i = 0; i < HTT_TX_TXBF_RATE_STATS_NUM_BW_COUNTERS; i++) ++ len += scnprintf(buf + len, buf_len - len, ++ "%d:%u,", i, htt_stats_buf->tx_su_ol_bw[i]); ++ len--; ++ ++ len += scnprintf(buf + len, buf_len - len, "\ntx_ibf_bw = "); ++ for (i = 0; i < HTT_TX_TXBF_RATE_STATS_NUM_BW_COUNTERS; i++) ++ len += scnprintf(buf + len, buf_len - len, ++ "%d:%u,", i, htt_stats_buf->tx_su_ibf_bw[i]); ++ len--; ++ ++ len += scnprintf(buf + len, buf_len - len, "\ntx_txbf_bw = "); ++ for (i = 0; i < HTT_TX_TXBF_RATE_STATS_NUM_BW_COUNTERS; i++) ++ len += scnprintf(buf + len, buf_len - len, ++ "%d:%u,", i, htt_stats_buf->tx_su_txbf_bw[i]); ++ len--; ++ ++ len += scnprintf(buf + len, buf_len - len, "\n"); ++ ++ stats_req->buf_len = len; ++} ++ ++static inline ++void htt_print_txbf_ofdma_ndpa_stats_tlv(const void *tag_buf, ++ struct debug_htt_stats_req *stats_req) ++{ ++ const struct htt_txbf_ofdma_ndpa_stats_tlv *htt_stats_buf = tag_buf; ++ u8 *buf = stats_req->buf; ++ u32 len = stats_req->buf_len; ++ u32 buf_len = ATH11K_HTT_STATS_BUF_SIZE; ++ int i; ++ ++ len += scnprintf(buf + len, buf_len - len, ++ "HTT_TXBF_OFDMA_NDPA_STATS_TLV:\n"); ++ ++ for (i = 0; i < HTT_TX_PDEV_STATS_NUM_OFDMA_USER_STATS; i++) { ++ len += scnprintf(buf + len, buf_len - len, ++ "ax_ofdma_ndpa_queued_user%d = %u\n", ++ i, htt_stats_buf->ax_ofdma_ndpa_queued[i]); ++ len += scnprintf(buf + len, buf_len - len, ++ "ax_ofdma_ndpa_tried_user%d = %u\n", ++ i, htt_stats_buf->ax_ofdma_ndpa_tried[i]); ++ len += scnprintf(buf + len, buf_len - len, ++ "ax_ofdma_ndpa_flushed_user%d = %u\n", ++ i, htt_stats_buf->ax_ofdma_ndpa_flushed[i]); ++ len += scnprintf(buf + len, buf_len - len, ++ "ax_ofdma_ndpa_err_user%d = %u\n", ++ i, htt_stats_buf->ax_ofdma_ndpa_err[i]); ++ len += scnprintf(buf + len, buf_len - len, "\n"); ++ } ++ ++ stats_req->buf_len = len; ++} ++ ++static inline ++void htt_print_txbf_ofdma_ndp_stats_tlv(const void *tag_buf, ++ struct debug_htt_stats_req *stats_req) ++{ ++ const struct htt_txbf_ofdma_ndp_stats_tlv *htt_stats_buf = tag_buf; ++ u8 *buf = stats_req->buf; ++ u32 len = stats_req->buf_len; ++ u32 buf_len = ATH11K_HTT_STATS_BUF_SIZE; ++ int i; ++ ++ len += scnprintf(buf + len, buf_len - len, ++ "HTT_TXBF_OFDMA_NDP_STATS_TLV:\n"); ++ ++ for (i = 0; i < HTT_TX_PDEV_STATS_NUM_OFDMA_USER_STATS; i++) { ++ len += scnprintf(buf + len, buf_len - len, ++ "ax_ofdma_ndp_queued_user%d = %u\n", ++ i, htt_stats_buf->ax_ofdma_ndp_queued[i]); ++ len += scnprintf(buf + len, buf_len - len, ++ "ax_ofdma_ndp_tried_user%d = %u\n", ++ i, htt_stats_buf->ax_ofdma_ndp_tried[i]); ++ len += scnprintf(buf + len, buf_len - len, ++ "ax_ofdma_ndp_flushed_user%d = %u\n", ++ i, htt_stats_buf->ax_ofdma_ndp_flushed[i]); ++ len += scnprintf(buf + len, buf_len - len, ++ "ax_ofdma_ndp_err_user%d = %u\n", ++ i, htt_stats_buf->ax_ofdma_ndp_err[i]); ++ len += scnprintf(buf + len, buf_len - len, "\n"); ++ } ++ ++ stats_req->buf_len = len; ++} ++ ++static inline ++void htt_print_txbf_ofdma_brp_stats_tlv(const void *tag_buf, ++ struct debug_htt_stats_req *stats_req) ++{ ++ const struct htt_txbf_ofdma_brp_stats_tlv *htt_stats_buf = tag_buf; ++ u8 *buf = stats_req->buf; ++ u32 len = stats_req->buf_len; ++ u32 buf_len = ATH11K_HTT_STATS_BUF_SIZE; ++ int i; ++ ++ len += scnprintf(buf + len, buf_len - len, ++ "HTT_TXBF_OFDMA_BRP_STATS_TLV:\n"); ++ ++ for (i = 0; i < HTT_TX_PDEV_STATS_NUM_OFDMA_USER_STATS; i++) { ++ len += scnprintf(buf + len, buf_len - len, ++ "ax_ofdma_brpoll_queued_user%d = %u\n", ++ i, htt_stats_buf->ax_ofdma_brpoll_queued[i]); ++ len += scnprintf(buf + len, buf_len - len, ++ "ax_ofdma_brpoll_tried_user%d = %u\n", ++ i, htt_stats_buf->ax_ofdma_brpoll_tried[i]); ++ len += scnprintf(buf + len, buf_len - len, ++ "ax_ofdma_brpoll_flushed_user%d = %u\n", ++ i, htt_stats_buf->ax_ofdma_brpoll_flushed[i]); ++ len += scnprintf(buf + len, buf_len - len, ++ "ax_ofdma_brp_err_user%d = %u\n", ++ i, htt_stats_buf->ax_ofdma_brp_err[i]); ++ len += scnprintf(buf + len, buf_len - len, ++ "ax_ofdma_brp_err_num_cbf_rcvd_user%d = %u\n", ++ i, htt_stats_buf->ax_ofdma_brp_err_num_cbf_rcvd[i]); ++ len += scnprintf(buf + len, buf_len - len, "\n"); ++ } ++ ++ stats_req->buf_len = len; ++} ++ ++static inline ++void htt_print_txbf_ofdma_steer_stats_tlv(const void *tag_buf, ++ struct debug_htt_stats_req *stats_req) ++{ ++ const struct htt_txbf_ofdma_steer_stats_tlv *htt_stats_buf = tag_buf; ++ u8 *buf = stats_req->buf; ++ u32 len = stats_req->buf_len; ++ u32 buf_len = ATH11K_HTT_STATS_BUF_SIZE; ++ int i; ++ ++ len += scnprintf(buf + len, buf_len - len, ++ "HTT_TXBF_OFDMA_STEER_STATS_TLV:\n"); ++ ++ for (i = 0; i < HTT_TX_PDEV_STATS_NUM_OFDMA_USER_STATS; i++) { ++ len += scnprintf(buf + len, buf_len - len, ++ "ax_ofdma_num_ppdu_steer_user%d = %u\n", ++ i, htt_stats_buf->ax_ofdma_num_ppdu_steer[i]); ++ len += scnprintf(buf + len, buf_len - len, ++ "ax_ofdma_num_ppdu_ol_user%d = %u\n", ++ i, htt_stats_buf->ax_ofdma_num_ppdu_ol[i]); ++ len += scnprintf(buf + len, buf_len - len, ++ "ax_ofdma_num_usrs_prefetch_user%d = %u\n", ++ i, htt_stats_buf->ax_ofdma_num_usrs_prefetch[i]); ++ len += scnprintf(buf + len, buf_len - len, ++ "ax_ofdma_num_usrs_sound_user%d = %u\n", ++ i, htt_stats_buf->ax_ofdma_num_usrs_sound[i]); ++ len += scnprintf(buf + len, buf_len - len, ++ "ax_ofdma_num_usrs_force_sound_user%d = %u\n", ++ i, htt_stats_buf->ax_ofdma_num_usrs_force_sound[i]); ++ len += scnprintf(buf + len, buf_len - len, "\n"); ++ } ++ ++ stats_req->buf_len = len; ++} ++ ++static inline ++void htt_print_phy_counters_tlv(const void *tag_buf, ++ struct debug_htt_stats_req *stats_req) ++{ ++ const struct htt_phy_counters_tlv *htt_stats_buf = tag_buf; ++ u8 *buf = stats_req->buf; ++ u32 len = stats_req->buf_len; ++ u32 buf_len = ATH11K_HTT_STATS_BUF_SIZE; ++ int i; ++ ++ len += scnprintf(buf + len, buf_len - len, "HTT_PHY_COUNTERS_TLV:\n"); ++ len += scnprintf(buf + len, buf_len - len, "rx_ofdma_timing_err_cnt = %u\n", ++ htt_stats_buf->rx_ofdma_timing_err_cnt); ++ len += scnprintf(buf + len, buf_len - len, "rx_cck_fail_cnt = %u\n", ++ htt_stats_buf->rx_cck_fail_cnt); ++ len += scnprintf(buf + len, buf_len - len, "mactx_abort_cnt = %u\n", ++ htt_stats_buf->mactx_abort_cnt); ++ len += scnprintf(buf + len, buf_len - len, "macrx_abort_cnt = %u\n", ++ htt_stats_buf->macrx_abort_cnt); ++ len += scnprintf(buf + len, buf_len - len, "phytx_abort_cnt = %u\n", ++ htt_stats_buf->phytx_abort_cnt); ++ len += scnprintf(buf + len, buf_len - len, "phyrx_abort_cnt = %u\n", ++ htt_stats_buf->phyrx_abort_cnt); ++ len += scnprintf(buf + len, buf_len - len, "phyrx_defer_abort_cnt = %u\n", ++ htt_stats_buf->phyrx_defer_abort_cnt); ++ len += scnprintf(buf + len, buf_len - len, "rx_gain_adj_lstf_event_cnt = %u\n", ++ htt_stats_buf->rx_gain_adj_lstf_event_cnt); ++ len += scnprintf(buf + len, buf_len - len, "rx_gain_adj_non_legacy_cnt = %u\n", ++ htt_stats_buf->rx_gain_adj_non_legacy_cnt); ++ ++ for (i = 0; i < HTT_MAX_RX_PKT_CNT; i++) ++ len += scnprintf(buf + len, buf_len - len, "rx_pkt_cnt[%d] = %u\n", ++ i, htt_stats_buf->rx_pkt_cnt[i]); ++ ++ for (i = 0; i < HTT_MAX_RX_PKT_CRC_PASS_CNT; i++) ++ len += scnprintf(buf + len, buf_len - len, ++ "rx_pkt_crc_pass_cnt[%d] = %u\n", ++ i, htt_stats_buf->rx_pkt_crc_pass_cnt[i]); ++ ++ for (i = 0; i < HTT_MAX_PER_BLK_ERR_CNT; i++) ++ len += scnprintf(buf + len, buf_len - len, ++ "per_blk_err_cnt[%d] = %u\n", ++ i, htt_stats_buf->per_blk_err_cnt[i]); ++ ++ for (i = 0; i < HTT_MAX_RX_OTA_ERR_CNT; i++) ++ len += scnprintf(buf + len, buf_len - len, ++ "rx_ota_err_cnt[%d] = %u\n", ++ i, htt_stats_buf->rx_ota_err_cnt[i]); ++ ++ stats_req->buf_len = len; ++} ++ ++static inline ++void htt_print_phy_stats_tlv(const void *tag_buf, ++ struct debug_htt_stats_req *stats_req) ++{ ++ const struct htt_phy_stats_tlv *htt_stats_buf = tag_buf; ++ u8 *buf = stats_req->buf; ++ u32 len = stats_req->buf_len; ++ u32 buf_len = ATH11K_HTT_STATS_BUF_SIZE; ++ int i; ++ ++ len += scnprintf(buf + len, buf_len - len, "HTT_PHY_STATS_TLV:\n"); ++ ++ for (i = 0; i < HTT_STATS_MAX_CHAINS; i++) ++ len += scnprintf(buf + len, buf_len - len, "nf_chain[%d] = %d\n", ++ i, htt_stats_buf->nf_chain[i]); ++ ++ len += scnprintf(buf + len, buf_len - len, "false_radar_cnt = %u\n", ++ htt_stats_buf->false_radar_cnt); ++ len += scnprintf(buf + len, buf_len - len, "radar_cs_cnt = %u\n", ++ htt_stats_buf->radar_cs_cnt); ++ len += scnprintf(buf + len, buf_len - len, "ani_level = %d\n", ++ htt_stats_buf->ani_level); ++ len += scnprintf(buf + len, buf_len - len, "fw_run_time = %u\n", ++ htt_stats_buf->fw_run_time); ++ ++ stats_req->buf_len = len; ++} ++ ++static inline ++void htt_print_peer_ctrl_path_txrx_stats_tlv(const void *tag_buf, ++ struct debug_htt_stats_req *stats_req) ++{ ++ const struct htt_peer_ctrl_path_txrx_stats_tlv *htt_stat_buf = tag_buf; ++ u8 *buf = stats_req->buf; ++ u32 len = stats_req->buf_len; ++ u32 buf_len = ATH11K_HTT_STATS_BUF_SIZE; ++ int i; ++ const char *mgmt_frm_type[ATH11K_STATS_MGMT_FRM_TYPE_MAX - 1] = { ++ "assoc_req", "assoc_resp", ++ "reassoc_req", "reassoc_resp", ++ "probe_req", "probe_resp", ++ "timing_advertisement", "reserved", ++ "beacon", "atim", "disassoc", ++ "auth", "deauth", "action", "action_no_ack"}; ++ ++ len += scnprintf(buf + len, buf_len - len, ++ "HTT_STATS_PEER_CTRL_PATH_TXRX_STATS_TAG:\n"); ++ len += scnprintf(buf + len, buf_len - len, ++ "peer_mac_addr = %02x:%02x:%02x:%02x:%02x:%02x\n", ++ htt_stat_buf->peer_mac_addr[0], htt_stat_buf->peer_mac_addr[1], ++ htt_stat_buf->peer_mac_addr[2], htt_stat_buf->peer_mac_addr[3], ++ htt_stat_buf->peer_mac_addr[4], htt_stat_buf->peer_mac_addr[5]); ++ ++ len += scnprintf(buf + len, buf_len - len, "peer_tx_mgmt_subtype:\n"); ++ for (i = 0; i < ATH11K_STATS_MGMT_FRM_TYPE_MAX - 1; i++) ++ len += scnprintf(buf + len, buf_len - len, "%s:%u\n", ++ mgmt_frm_type[i], ++ htt_stat_buf->peer_rx_mgmt_subtype[i]); ++ ++ len += scnprintf(buf + len, buf_len - len, "peer_rx_mgmt_subtype:\n"); ++ for (i = 0; i < ATH11K_STATS_MGMT_FRM_TYPE_MAX - 1; i++) ++ len += scnprintf(buf + len, buf_len - len, "%s:%u\n", ++ mgmt_frm_type[i], ++ htt_stat_buf->peer_rx_mgmt_subtype[i]); ++ ++ len += scnprintf(buf + len, buf_len - len, "\n"); ++ ++ stats_req->buf_len = len; ++} ++ + static int ath11k_dbg_htt_ext_stats_parse(struct ath11k_base *ab, + u16 tag, u16 len, const void *tag_buf, + void *user_data) +@@ -3990,6 +4318,30 @@ static int ath11k_dbg_htt_ext_stats_pars + case HTT_STATS_RING_BACKPRESSURE_STATS_TAG: + htt_print_backpressure_stats_tlv_v(tag_buf, user_data); + break; ++ case HTT_STATS_PDEV_TX_RATE_TXBF_STATS_TAG: ++ htt_print_pdev_tx_rate_txbf_stats_tlv(tag_buf, stats_req); ++ break; ++ case HTT_STATS_TXBF_OFDMA_NDPA_STATS_TAG: ++ htt_print_txbf_ofdma_ndpa_stats_tlv(tag_buf, stats_req); ++ break; ++ case HTT_STATS_TXBF_OFDMA_NDP_STATS_TAG: ++ htt_print_txbf_ofdma_ndp_stats_tlv(tag_buf, stats_req); ++ break; ++ case HTT_STATS_TXBF_OFDMA_BRP_STATS_TAG: ++ htt_print_txbf_ofdma_brp_stats_tlv(tag_buf, stats_req); ++ break; ++ case HTT_STATS_TXBF_OFDMA_STEER_STATS_TAG: ++ htt_print_txbf_ofdma_steer_stats_tlv(tag_buf, stats_req); ++ break; ++ case HTT_STATS_PHY_COUNTERS_TAG: ++ htt_print_phy_counters_tlv(tag_buf, stats_req); ++ break; ++ case HTT_STATS_PHY_STATS_TAG: ++ htt_print_phy_stats_tlv(tag_buf, stats_req); ++ break; ++ case HTT_STATS_PEER_CTRL_PATH_TXRX_STATS_TAG: ++ htt_print_peer_ctrl_path_txrx_stats_tlv(tag_buf, stats_req); ++ break; + default: + break; + } +@@ -4077,8 +4429,7 @@ static ssize_t ath11k_write_htt_stats_ty + if (type >= ATH11K_DBG_HTT_NUM_EXT_STATS) + return -E2BIG; + +- if (type == ATH11K_DBG_HTT_EXT_STATS_RESET || +- type == ATH11K_DBG_HTT_EXT_STATS_PEER_INFO) ++ if (type == ATH11K_DBG_HTT_EXT_STATS_RESET) + return -EPERM; + + ar->debug.htt_stats.type = type; +@@ -4139,6 +4490,15 @@ static int ath11k_prep_htt_stats_cfg_par + case ATH11K_DBG_HTT_EXT_STATS_TX_SOUNDING_INFO: + cfg_params->cfg0 = HTT_STAT_DEFAULT_CFG0_ACTIVE_VDEVS; + break; ++ case ATH11K_DBG_HTT_EXT_STATS_PEER_CTRL_PATH_TXRX_STATS: ++ cfg_params->cfg0 = HTT_STAT_PEER_INFO_MAC_ADDR; ++ cfg_params->cfg1 |= FIELD_PREP(GENMASK(7, 0), mac_addr[0]); ++ cfg_params->cfg1 |= FIELD_PREP(GENMASK(15, 8), mac_addr[1]); ++ cfg_params->cfg1 |= FIELD_PREP(GENMASK(23, 16), mac_addr[2]); ++ cfg_params->cfg1 |= FIELD_PREP(GENMASK(31, 24), mac_addr[3]); ++ cfg_params->cfg2 |= FIELD_PREP(GENMASK(7, 0), mac_addr[4]); ++ cfg_params->cfg2 |= FIELD_PREP(GENMASK(15, 8), mac_addr[5]); ++ break; + default: + break; + } +@@ -4196,7 +4556,9 @@ static int ath11k_open_htt_stats(struct + u8 type = ar->debug.htt_stats.type; + int ret; + +- if (type == ATH11K_DBG_HTT_EXT_STATS_RESET) ++ if (type == ATH11K_DBG_HTT_EXT_STATS_RESET || ++ type == ATH11K_DBG_HTT_EXT_STATS_PEER_INFO || ++ type == ATH11K_DBG_HTT_EXT_STATS_PEER_CTRL_PATH_TXRX_STATS) + return -EPERM; + + mutex_lock(&ar->conf_mutex); +--- a/drivers/net/wireless/ath/ath11k/debugfs_htt_stats.h ++++ b/drivers/net/wireless/ath/ath11k/debugfs_htt_stats.h +@@ -102,6 +102,14 @@ enum htt_tlv_tag_t { + HTT_STATS_PDEV_OBSS_PD_TAG = 88, + HTT_STATS_HW_WAR_TAG = 89, + HTT_STATS_RING_BACKPRESSURE_STATS_TAG = 90, ++ HTT_STATS_PEER_CTRL_PATH_TXRX_STATS_TAG = 101, ++ HTT_STATS_PDEV_TX_RATE_TXBF_STATS_TAG = 108, ++ HTT_STATS_TXBF_OFDMA_NDPA_STATS_TAG = 113, ++ HTT_STATS_TXBF_OFDMA_NDP_STATS_TAG = 114, ++ HTT_STATS_TXBF_OFDMA_BRP_STATS_TAG = 115, ++ HTT_STATS_TXBF_OFDMA_STEER_STATS_TAG = 116, ++ HTT_STATS_PHY_COUNTERS_TAG = 121, ++ HTT_STATS_PHY_STATS_TAG = 122, + + HTT_STATS_MAX_TAG, + }; +@@ -1750,6 +1758,170 @@ struct htt_ring_backpressure_stats_tlv { + u32 backpressure_hist[5]; + }; + ++#define HTT_TX_TXBF_RATE_STATS_NUM_MCS_COUNTERS 14 ++#define HTT_TX_TXBF_RATE_STATS_NUM_BW_COUNTERS 5 ++#define HTT_TX_PDEV_STATS_NUM_SPATIAL_STREAMS 8 ++ ++struct htt_pdev_txrate_txbf_stats_tlv { ++ /* SU TxBF TX MCS stats */ ++ u32 tx_su_txbf_mcs[HTT_TX_TXBF_RATE_STATS_NUM_MCS_COUNTERS]; ++ /* Implicit BF TX MCS stats */ ++ u32 tx_su_ibf_mcs[HTT_TX_TXBF_RATE_STATS_NUM_MCS_COUNTERS]; ++ /* Open loop TX MCS stats */ ++ u32 tx_su_ol_mcs[HTT_TX_TXBF_RATE_STATS_NUM_MCS_COUNTERS]; ++ /* SU TxBF TX NSS stats */ ++ u32 tx_su_txbf_nss[HTT_TX_PDEV_STATS_NUM_SPATIAL_STREAMS]; ++ /* Implicit BF TX NSS stats */ ++ u32 tx_su_ibf_nss[HTT_TX_PDEV_STATS_NUM_SPATIAL_STREAMS]; ++ /* Open loop TX NSS stats */ ++ u32 tx_su_ol_nss[HTT_TX_PDEV_STATS_NUM_SPATIAL_STREAMS]; ++ /* SU TxBF TX BW stats */ ++ u32 tx_su_txbf_bw[HTT_TX_TXBF_RATE_STATS_NUM_BW_COUNTERS]; ++ /* Implicit BF TX BW stats */ ++ u32 tx_su_ibf_bw[HTT_TX_TXBF_RATE_STATS_NUM_BW_COUNTERS]; ++ /* Open loop TX BW stats */ ++ u32 tx_su_ol_bw[HTT_TX_TXBF_RATE_STATS_NUM_BW_COUNTERS]; ++}; ++ ++struct htt_txbf_ofdma_ndpa_stats_tlv { ++ /* 11AX HE OFDMA NDPA frame queued to the HW */ ++ u32 ax_ofdma_ndpa_queued[HTT_TX_PDEV_STATS_NUM_OFDMA_USER_STATS]; ++ /* 11AX HE OFDMA NDPA frame sent over the air */ ++ u32 ax_ofdma_ndpa_tried[HTT_TX_PDEV_STATS_NUM_OFDMA_USER_STATS]; ++ /* 11AX HE OFDMA NDPA frame flushed by HW */ ++ u32 ax_ofdma_ndpa_flushed[HTT_TX_PDEV_STATS_NUM_OFDMA_USER_STATS]; ++ /* 11AX HE OFDMA NDPA frame completed with error(s) */ ++ u32 ax_ofdma_ndpa_err[HTT_TX_PDEV_STATS_NUM_OFDMA_USER_STATS]; ++}; ++ ++struct htt_txbf_ofdma_ndp_stats_tlv { ++ /* 11AX HE OFDMA NDP frame queued to the HW */ ++ u32 ax_ofdma_ndp_queued[HTT_TX_PDEV_STATS_NUM_OFDMA_USER_STATS]; ++ /* 11AX HE OFDMA NDPA frame sent over the air */ ++ u32 ax_ofdma_ndp_tried[HTT_TX_PDEV_STATS_NUM_OFDMA_USER_STATS]; ++ /* 11AX HE OFDMA NDPA frame flushed by HW */ ++ u32 ax_ofdma_ndp_flushed[HTT_TX_PDEV_STATS_NUM_OFDMA_USER_STATS]; ++ /* 11AX HE OFDMA NDPA frame completed with error(s) */ ++ u32 ax_ofdma_ndp_err[HTT_TX_PDEV_STATS_NUM_OFDMA_USER_STATS]; ++}; ++ ++struct htt_txbf_ofdma_brp_stats_tlv { ++ /* 11AX HE OFDMA MU BRPOLL frame queued to the HW */ ++ u32 ax_ofdma_brpoll_queued[HTT_TX_PDEV_STATS_NUM_OFDMA_USER_STATS]; ++ /* 11AX HE OFDMA MU BRPOLL frame sent over the air */ ++ u32 ax_ofdma_brpoll_tried[HTT_TX_PDEV_STATS_NUM_OFDMA_USER_STATS]; ++ /* 11AX HE OFDMA MU BRPOLL frame flushed by HW */ ++ u32 ax_ofdma_brpoll_flushed[HTT_TX_PDEV_STATS_NUM_OFDMA_USER_STATS]; ++ /* 11AX HE OFDMA MU BRPOLL frame completed with error(s) */ ++ u32 ax_ofdma_brp_err[HTT_TX_PDEV_STATS_NUM_OFDMA_USER_STATS]; ++ /* Number of CBF(s) received when 11AX HE OFDMA MU BRPOLL frame ++ * completed with error(s). ++ */ ++ u32 ax_ofdma_brp_err_num_cbf_rcvd[HTT_TX_PDEV_STATS_NUM_OFDMA_USER_STATS + 1]; ++}; ++ ++struct htt_txbf_ofdma_steer_stats_tlv { ++ /* 11AX HE OFDMA PPDUs that were sent over the air with steering (TXBF + OFDMA) */ ++ u32 ax_ofdma_num_ppdu_steer[HTT_TX_PDEV_STATS_NUM_OFDMA_USER_STATS]; ++ /* 11AX HE OFDMA PPDUs that were sent over the air in open loop */ ++ u32 ax_ofdma_num_ppdu_ol[HTT_TX_PDEV_STATS_NUM_OFDMA_USER_STATS]; ++ /* 11AX HE OFDMA number of users for which CBF prefetch was ++ * initiated to PHY HW during TX. ++ */ ++ u32 ax_ofdma_num_usrs_prefetch[HTT_TX_PDEV_STATS_NUM_OFDMA_USER_STATS]; ++ /* 11AX HE OFDMA number of users for which sounding was initiated during TX */ ++ u32 ax_ofdma_num_usrs_sound[HTT_TX_PDEV_STATS_NUM_OFDMA_USER_STATS]; ++ /* 11AX HE OFDMA number of users for which sounding was forced during TX */ ++ u32 ax_ofdma_num_usrs_force_sound[HTT_TX_PDEV_STATS_NUM_OFDMA_USER_STATS]; ++}; ++ ++#define HTT_MAX_RX_PKT_CNT 8 ++#define HTT_MAX_RX_PKT_CRC_PASS_CNT 8 ++#define HTT_MAX_PER_BLK_ERR_CNT 20 ++#define HTT_MAX_RX_OTA_ERR_CNT 14 ++#define HTT_STATS_MAX_CHAINS 8 ++#define ATH11K_STATS_MGMT_FRM_TYPE_MAX 16 ++ ++struct htt_phy_counters_tlv { ++ /* number of RXTD OFDMA OTA error counts except power surge and drop */ ++ u32 rx_ofdma_timing_err_cnt; ++ /* rx_cck_fail_cnt: ++ * number of cck error counts due to rx reception failure because of ++ * timing error in cck ++ */ ++ u32 rx_cck_fail_cnt; ++ /* number of times tx abort initiated by mac */ ++ u32 mactx_abort_cnt; ++ /* number of times rx abort initiated by mac */ ++ u32 macrx_abort_cnt; ++ /* number of times tx abort initiated by phy */ ++ u32 phytx_abort_cnt; ++ /* number of times rx abort initiated by phy */ ++ u32 phyrx_abort_cnt; ++ /* number of rx defered count initiated by phy */ ++ u32 phyrx_defer_abort_cnt; ++ /* number of sizing events generated at LSTF */ ++ u32 rx_gain_adj_lstf_event_cnt; ++ /* number of sizing events generated at non-legacy LTF */ ++ u32 rx_gain_adj_non_legacy_cnt; ++ /* rx_pkt_cnt - ++ * Received EOP (end-of-packet) count per packet type; ++ * [0] = 11a; [1] = 11b; [2] = 11n; [3] = 11ac; [4] = 11ax; [5] = GF ++ * [6-7]=RSVD ++ */ ++ u32 rx_pkt_cnt[HTT_MAX_RX_PKT_CNT]; ++ /* rx_pkt_crc_pass_cnt - ++ * Received EOP (end-of-packet) count per packet type; ++ * [0] = 11a; [1] = 11b; [2] = 11n; [3] = 11ac; [4] = 11ax; [5] = GF ++ * [6-7]=RSVD ++ */ ++ u32 rx_pkt_crc_pass_cnt[HTT_MAX_RX_PKT_CRC_PASS_CNT]; ++ /* per_blk_err_cnt - ++ * Error count per error source; ++ * [0] = unknown; [1] = LSIG; [2] = HTSIG; [3] = VHTSIG; [4] = HESIG; ++ * [5] = RXTD_OTA; [6] = RXTD_FATAL; [7] = DEMF; [8] = ROBE; ++ * [9] = PMI; [10] = TXFD; [11] = TXTD; [12] = PHYRF ++ * [13-19]=RSVD ++ */ ++ u32 per_blk_err_cnt[HTT_MAX_PER_BLK_ERR_CNT]; ++ /* rx_ota_err_cnt - ++ * RXTD OTA (over-the-air) error count per error reason; ++ * [0] = voting fail; [1] = weak det fail; [2] = strong sig fail; ++ * [3] = cck fail; [4] = power surge; [5] = power drop; ++ * [6] = btcf timing timeout error; [7] = btcf packet detect error; ++ * [8] = coarse timing timeout error ++ * [9-13]=RSVD ++ */ ++ u32 rx_ota_err_cnt[HTT_MAX_RX_OTA_ERR_CNT]; ++}; ++ ++struct htt_phy_stats_tlv { ++ /* per chain hw noise floor values in dBm */ ++ s32 nf_chain[HTT_STATS_MAX_CHAINS]; ++ /* number of false radars detected */ ++ u32 false_radar_cnt; ++ /* number of channel switches happened due to radar detection */ ++ u32 radar_cs_cnt; ++ /* ani_level - ++ * ANI level (noise interference) corresponds to the channel ++ * the desense levels range from -5 to 15 in dB units, ++ * higher values indicating more noise interference. ++ */ ++ s32 ani_level; ++ /* running time in minutes since FW boot */ ++ u32 fw_run_time; ++}; ++ ++struct htt_peer_ctrl_path_txrx_stats_tlv { ++ /* peer mac address */ ++ u8 peer_mac_addr[ETH_ALEN]; ++ u8 rsvd[2]; ++ /* Num of tx mgmt frames with subtype on peer level */ ++ u32 peer_tx_mgmt_subtype[ATH11K_STATS_MGMT_FRM_TYPE_MAX]; ++ /* Num of rx mgmt frames with subtype on peer level */ ++ u32 peer_rx_mgmt_subtype[ATH11K_STATS_MGMT_FRM_TYPE_MAX]; ++}; ++ + #ifdef CPTCFG_ATH11K_DEBUGFS + + void ath11k_debugfs_htt_stats_init(struct ath11k *ar); +--- a/drivers/net/wireless/ath/ath11k/debugfs_sta.c ++++ b/drivers/net/wireless/ath/ath11k/debugfs_sta.c +@@ -419,15 +419,21 @@ ath11k_dbg_sta_open_htt_peer_stats(struc + struct ath11k_sta *arsta = (struct ath11k_sta *)sta->drv_priv; + struct ath11k *ar = arsta->arvif->ar; + struct debug_htt_stats_req *stats_req; ++ int type = ar->debug.htt_stats.type; + int ret; + ++ if ((type != ATH11K_DBG_HTT_EXT_STATS_PEER_INFO && ++ type != ATH11K_DBG_HTT_EXT_STATS_PEER_CTRL_PATH_TXRX_STATS) || ++ type == ATH11K_DBG_HTT_EXT_STATS_RESET) ++ return -EPERM; ++ + stats_req = vzalloc(sizeof(*stats_req) + ATH11K_HTT_STATS_BUF_SIZE); + if (!stats_req) + return -ENOMEM; + + mutex_lock(&ar->conf_mutex); + ar->debug.htt_stats.stats_req = stats_req; +- stats_req->type = ATH11K_DBG_HTT_EXT_STATS_PEER_INFO; ++ stats_req->type = type; + memcpy(stats_req->peer_addr, sta->addr, ETH_ALEN); + ret = ath11k_debugfs_htt_stats_req(ar); + mutex_unlock(&ar->conf_mutex); diff --git a/package/kernel/mac80211/patches/ath11k/0049-ath11k-indicate-scan-complete-for-scan-canceled-when.patch b/package/kernel/mac80211/patches/ath11k/0049-ath11k-indicate-scan-complete-for-scan-canceled-when.patch new file mode 100644 index 000000000..b93b6b4ef --- /dev/null +++ b/package/kernel/mac80211/patches/ath11k/0049-ath11k-indicate-scan-complete-for-scan-canceled-when.patch @@ -0,0 +1,76 @@ +From c677d4b1bcc4f7330043d8f039f494557d720ed4 Mon Sep 17 00:00:00 2001 +From: Wen Gong +Date: Tue, 28 Sep 2021 14:00:45 +0300 +Subject: [PATCH 049/120] ath11k: indicate scan complete for scan canceled when + scan running + +ath11k prints "Received scan event for unknown vdev" when doing the +following test: +1. trigger scan +2. wait 0.2 second +3. iw reg set or 11d scan complete from firmware + +Reason: When iw reg set or 11d scan complete, the new country code will +be set to the firmware, and the new regdomain info indicated to ath11k, +then the new channel list will be sent to the firmware. The firmware +will cancel the current scan after receiving WMI_SCAN_CHAN_LIST_CMDID +which is used for the new channel list, and the state of ath11k is +ATH11K_SCAN_RUNNING, then ath11k_get_ar_on_scan_abort() returns NULL and +ath11k_scan_event() returns at this point and does not indicate scan +completion to mac80211. + +Indicate scan completion to mac80211 and get rid of the "Received scan +event for unknown vdev" print for the above case. + +Tested-on: WCN6855 hw2.0 PCI WLAN.HSP.1.1-01720.1-QCAHSPSWPL_V1_V2_SILICONZ_LITE-1 + +Signed-off-by: Wen Gong +Signed-off-by: Jouni Malinen +Signed-off-by: Kalle Valo +Link: https://lore.kernel.org/r/20210914164226.38843-2-jouni@codeaurora.org +--- + drivers/net/wireless/ath/ath11k/wmi.c | 18 ++++++++++++------ + 1 file changed, 12 insertions(+), 6 deletions(-) + +--- a/drivers/net/wireless/ath/ath11k/wmi.c ++++ b/drivers/net/wireless/ath/ath11k/wmi.c +@@ -6289,8 +6289,9 @@ exit: + rcu_read_unlock(); + } + +-static struct ath11k *ath11k_get_ar_on_scan_abort(struct ath11k_base *ab, +- u32 vdev_id) ++static struct ath11k *ath11k_get_ar_on_scan_state(struct ath11k_base *ab, ++ u32 vdev_id, ++ enum ath11k_scan_state state) + { + int i; + struct ath11k_pdev *pdev; +@@ -6302,7 +6303,7 @@ static struct ath11k *ath11k_get_ar_on_s + ar = pdev->ar; + + spin_lock_bh(&ar->data_lock); +- if (ar->scan.state == ATH11K_SCAN_ABORTING && ++ if (ar->scan.state == state && + ar->scan.vdev_id == vdev_id) { + spin_unlock_bh(&ar->data_lock); + return ar; +@@ -6332,10 +6333,15 @@ static void ath11k_scan_event(struct ath + * aborting scan's vdev id matches this event info. + */ + if (scan_ev.event_type == WMI_SCAN_EVENT_COMPLETED && +- scan_ev.reason == WMI_SCAN_REASON_CANCELLED) +- ar = ath11k_get_ar_on_scan_abort(ab, scan_ev.vdev_id); +- else ++ scan_ev.reason == WMI_SCAN_REASON_CANCELLED) { ++ ar = ath11k_get_ar_on_scan_state(ab, scan_ev.vdev_id, ++ ATH11K_SCAN_ABORTING); ++ if (!ar) ++ ar = ath11k_get_ar_on_scan_state(ab, scan_ev.vdev_id, ++ ATH11K_SCAN_RUNNING); ++ } else { + ar = ath11k_mac_get_ar_by_vdev_id(ab, scan_ev.vdev_id); ++ } + + if (!ar) { + ath11k_warn(ab, "Received scan event for unknown vdev"); diff --git a/package/kernel/mac80211/patches/ath11k/0050-ath11k-indicate-to-mac80211-scan-complete-with-abort.patch b/package/kernel/mac80211/patches/ath11k/0050-ath11k-indicate-to-mac80211-scan-complete-with-abort.patch new file mode 100644 index 000000000..a4865bccb --- /dev/null +++ b/package/kernel/mac80211/patches/ath11k/0050-ath11k-indicate-to-mac80211-scan-complete-with-abort.patch @@ -0,0 +1,71 @@ +From 62db14ea95b1017c53ebb8f724119ea4d90ecc07 Mon Sep 17 00:00:00 2001 +From: Wen Gong +Date: Tue, 28 Sep 2021 14:00:45 +0300 +Subject: [PATCH 050/120] ath11k: indicate to mac80211 scan complete with + aborted flag for ATH11K_SCAN_STARTING state + +Scan failure can not be recovered from when running a loop of the +following steps: +1. run scan: "iw wlan scan". +2. run command: echo assert > /sys/kernel/debug/ath11k/qca6490\ hw2.0/simulate_fw_crash + immediately after step 1. + +result: +scan failed and can not recover even when wlan recovery succeeds: +command failed: Device or resource busy (-16) + +reason: +When scan arrives, WMI_START_SCAN_CMDID is sent to the firmware and +function ath11k_mac_op_hw_scan() returns, then simulate_fw_crash arrives +and the scan started event does not arrive, and then it starts to do +recovery of wlan. __ath11k_mac_scan_finish() which is called from +ath11k_core_halt() is one step of recovery, it will not call +ieee80211_scan_completed() by logic currently because the scan state is +ATH11K_SCAN_STARTING. Thus it leads the scan not being completed in +mac80211, and leads all consecutive scans failing with -EBUSY in +nl80211_trigger_scan even after wlan recovery success. + +Indicate scan complete with aborted flag to mac80211 for +ATH11K_SCAN_STARTING to allow recovery from scan failed with "Device or +resource busy (-16)" after wlan recovery. + +Tested-on: WCN6855 hw2.0 PCI WLAN.HSP.1.1-01720.1-QCAHSPSWPL_V1_V2_SILICONZ_LITE-1 + +Signed-off-by: Wen Gong +Signed-off-by: Jouni Malinen +Signed-off-by: Kalle Valo +Link: https://lore.kernel.org/r/20210914164226.38843-3-jouni@codeaurora.org +--- + drivers/net/wireless/ath/ath11k/mac.c | 15 +++++++++------ + 1 file changed, 9 insertions(+), 6 deletions(-) + +--- a/drivers/net/wireless/ath/ath11k/mac.c ++++ b/drivers/net/wireless/ath/ath11k/mac.c +@@ -2982,18 +2982,21 @@ void __ath11k_mac_scan_finish(struct ath + break; + case ATH11K_SCAN_RUNNING: + case ATH11K_SCAN_ABORTING: ++ if (ar->scan.is_roc && ar->scan.roc_notify) ++ ieee80211_remain_on_channel_expired(ar->hw); ++ fallthrough; ++ case ATH11K_SCAN_STARTING: + if (!ar->scan.is_roc) { + struct cfg80211_scan_info info = { +- .aborted = (ar->scan.state == +- ATH11K_SCAN_ABORTING), ++ .aborted = ((ar->scan.state == ++ ATH11K_SCAN_ABORTING) || ++ (ar->scan.state == ++ ATH11K_SCAN_STARTING)), + }; + + ieee80211_scan_completed(ar->hw, &info); +- } else if (ar->scan.roc_notify) { +- ieee80211_remain_on_channel_expired(ar->hw); + } +- fallthrough; +- case ATH11K_SCAN_STARTING: ++ + ar->scan.state = ATH11K_SCAN_IDLE; + ar->scan_channel = NULL; + ar->scan.roc_freq = 0; diff --git a/package/kernel/mac80211/patches/ath11k/0051-ath11k-add-6-GHz-params-in-peer-assoc-command.patch b/package/kernel/mac80211/patches/ath11k/0051-ath11k-add-6-GHz-params-in-peer-assoc-command.patch new file mode 100644 index 000000000..7239b38a2 --- /dev/null +++ b/package/kernel/mac80211/patches/ath11k/0051-ath11k-add-6-GHz-params-in-peer-assoc-command.patch @@ -0,0 +1,94 @@ +From c3a7d7eb4c9853bb457b792cef42ddd4a029a914 Mon Sep 17 00:00:00 2001 +From: Pradeep Kumar Chitrapu +Date: Tue, 28 Sep 2021 14:00:46 +0300 +Subject: [PATCH 051/120] ath11k: add 6 GHz params in peer assoc command + +Currently A-MPDU aggregation parameters are not being configured +during peer association for 6 GHz band. Hence, extract these +parameters from station's capabilities received in association +request and send to firmware. Without this, A-MPDU aggregation +is not happening in 6 GHz band. + +Tested-on: QCN9074 hw1.0 PCI WLAN.HK.2.4.0.1-01386-QCAHKSWPL_SILICONZ-1 + +Signed-off-by: Pradeep Kumar Chitrapu +Signed-off-by: Jouni Malinen +Signed-off-by: Kalle Valo +Link: https://lore.kernel.org/r/20210913175510.193005-2-jouni@codeaurora.org +--- + drivers/net/wireless/ath/ath11k/mac.c | 50 ++++++++++++++++++++++++++- + 1 file changed, 49 insertions(+), 1 deletion(-) + +--- a/drivers/net/wireless/ath/ath11k/mac.c ++++ b/drivers/net/wireless/ath/ath11k/mac.c +@@ -2016,6 +2016,53 @@ static void ath11k_peer_assoc_h_he(struc + arg->peer_bw_rxnss_override); + } + ++static void ath11k_peer_assoc_h_he_6ghz(struct ath11k *ar, ++ struct ieee80211_vif *vif, ++ struct ieee80211_sta *sta, ++ struct peer_assoc_params *arg) ++{ ++ const struct ieee80211_sta_he_cap *he_cap = &sta->he_cap; ++ struct cfg80211_chan_def def; ++ enum nl80211_band band; ++ u8 ampdu_factor; ++ ++ if (WARN_ON(ath11k_mac_vif_chan(vif, &def))) ++ return; ++ ++ band = def.chan->band; ++ ++ if (!arg->he_flag || band != NL80211_BAND_6GHZ || !sta->he_6ghz_capa.capa) ++ return; ++ ++ if (sta->bandwidth == IEEE80211_STA_RX_BW_80) ++ arg->bw_80 = true; ++ ++ if (sta->bandwidth == IEEE80211_STA_RX_BW_160) ++ arg->bw_160 = true; ++ ++ arg->peer_he_caps_6ghz = le16_to_cpu(sta->he_6ghz_capa.capa); ++ arg->peer_mpdu_density = ++ ath11k_parse_mpdudensity(FIELD_GET(IEEE80211_HE_6GHZ_CAP_MIN_MPDU_START, ++ arg->peer_he_caps_6ghz)); ++ ++ /* From IEEE Std 802.11ax-2021 - Section 10.12.2: An HE STA shall be capable of ++ * receiving A-MPDU where the A-MPDU pre-EOF padding length is up to the value ++ * indicated by the Maximum A-MPDU Length Exponent Extension field in the HE ++ * Capabilities element and the Maximum A-MPDU Length Exponent field in HE 6 GHz ++ * Band Capabilities element in the 6 GHz band. ++ * ++ * Here, we are extracting the Max A-MPDU Exponent Extension from HE caps and ++ * factor is the Maximum A-MPDU Length Exponent from HE 6 GHZ Band capability. ++ */ ++ ampdu_factor = FIELD_GET(IEEE80211_HE_MAC_CAP3_MAX_AMPDU_LEN_EXP_MASK, ++ he_cap->he_cap_elem.mac_cap_info[3]) + ++ FIELD_GET(IEEE80211_HE_6GHZ_CAP_MAX_AMPDU_LEN_EXP, ++ arg->peer_he_caps_6ghz); ++ ++ arg->peer_max_mpdu = (1u << (IEEE80211_HE_6GHZ_MAX_AMPDU_FACTOR + ++ ampdu_factor)) - 1; ++} ++ + static void ath11k_peer_assoc_h_smps(struct ieee80211_sta *sta, + struct peer_assoc_params *arg) + { +@@ -2305,6 +2352,7 @@ static void ath11k_peer_assoc_prepare(st + ath11k_peer_assoc_h_ht(ar, vif, sta, arg); + ath11k_peer_assoc_h_vht(ar, vif, sta, arg); + ath11k_peer_assoc_h_he(ar, vif, sta, arg); ++ ath11k_peer_assoc_h_he_6ghz(ar, vif, sta, arg); + ath11k_peer_assoc_h_qos(ar, vif, sta, arg); + ath11k_peer_assoc_h_smps(sta, arg); + +@@ -7598,7 +7646,7 @@ static int __ath11k_mac_register(struct + if (cap->nss_ratio_enabled) + ieee80211_hw_set(ar->hw, SUPPORTS_VHT_EXT_NSS_BW); + +- if (ht_cap & WMI_HT_CAP_ENABLED) { ++ if ((ht_cap & WMI_HT_CAP_ENABLED) || ar->supports_6ghz) { + ieee80211_hw_set(ar->hw, AMPDU_AGGREGATION); + ieee80211_hw_set(ar->hw, TX_AMPDU_SETUP_IN_HW); + ieee80211_hw_set(ar->hw, SUPPORTS_REORDERING_BUFFER); diff --git a/package/kernel/mac80211/patches/ath11k/0052-ath11k-support-SMPS-configuration-for-6-GHz.patch b/package/kernel/mac80211/patches/ath11k/0052-ath11k-support-SMPS-configuration-for-6-GHz.patch new file mode 100644 index 000000000..127eaa551 --- /dev/null +++ b/package/kernel/mac80211/patches/ath11k/0052-ath11k-support-SMPS-configuration-for-6-GHz.patch @@ -0,0 +1,93 @@ +From 6f4d70308e5eb63c99702e93f7c0d8e55f360da2 Mon Sep 17 00:00:00 2001 +From: Pradeep Kumar Chitrapu +Date: Tue, 28 Sep 2021 14:00:46 +0300 +Subject: [PATCH 052/120] ath11k: support SMPS configuration for 6 GHz + +Parse SMPS configuration from IEs and configure. Without this, +SMPS is not enabled for 6 GHz band. + +Tested-on: QCN9074 hw1.0 PCI WLAN.HK.2.4.0.1-01386-QCAHKSWPL_SILICONZ-1 + +Signed-off-by: Pradeep Kumar Chitrapu +Signed-off-by: Jouni Malinen +Signed-off-by: Kalle Valo +Link: https://lore.kernel.org/r/20210913175510.193005-3-jouni@codeaurora.org +--- + drivers/net/wireless/ath/ath11k/mac.c | 31 ++++++++++++++++++--------- + 1 file changed, 21 insertions(+), 10 deletions(-) + +--- a/drivers/net/wireless/ath/ath11k/mac.c ++++ b/drivers/net/wireless/ath/ath11k/mac.c +@@ -2069,11 +2069,16 @@ static void ath11k_peer_assoc_h_smps(str + const struct ieee80211_sta_ht_cap *ht_cap = &sta->ht_cap; + int smps; + +- if (!ht_cap->ht_supported) ++ if (!ht_cap->ht_supported && !sta->he_6ghz_capa.capa) + return; + +- smps = ht_cap->cap & IEEE80211_HT_CAP_SM_PS; +- smps >>= IEEE80211_HT_CAP_SM_PS_SHIFT; ++ if (ht_cap->ht_supported) { ++ smps = ht_cap->cap & IEEE80211_HT_CAP_SM_PS; ++ smps >>= IEEE80211_HT_CAP_SM_PS_SHIFT; ++ } else { ++ smps = FIELD_GET(IEEE80211_HE_6GHZ_CAP_SM_PS, ++ le16_to_cpu(sta->he_6ghz_capa.capa)); ++ } + + switch (smps) { + case WLAN_HT_CAP_SM_PS_STATIC: +@@ -2361,15 +2366,20 @@ static void ath11k_peer_assoc_prepare(st + + static int ath11k_setup_peer_smps(struct ath11k *ar, struct ath11k_vif *arvif, + const u8 *addr, +- const struct ieee80211_sta_ht_cap *ht_cap) ++ const struct ieee80211_sta_ht_cap *ht_cap, ++ u16 he_6ghz_capa) + { + int smps; + +- if (!ht_cap->ht_supported) ++ if (!ht_cap->ht_supported && !he_6ghz_capa) + return 0; + +- smps = ht_cap->cap & IEEE80211_HT_CAP_SM_PS; +- smps >>= IEEE80211_HT_CAP_SM_PS_SHIFT; ++ if (ht_cap->ht_supported) { ++ smps = ht_cap->cap & IEEE80211_HT_CAP_SM_PS; ++ smps >>= IEEE80211_HT_CAP_SM_PS_SHIFT; ++ } else { ++ smps = FIELD_GET(IEEE80211_HE_6GHZ_CAP_SM_PS, he_6ghz_capa); ++ } + + if (smps >= ARRAY_SIZE(ath11k_smps_map)) + return -EINVAL; +@@ -2422,7 +2432,8 @@ static void ath11k_bss_assoc(struct ieee + } + + ret = ath11k_setup_peer_smps(ar, arvif, bss_conf->bssid, +- &ap_sta->ht_cap); ++ &ap_sta->ht_cap, ++ le16_to_cpu(ap_sta->he_6ghz_capa.capa)); + if (ret) { + ath11k_warn(ar->ab, "failed to setup peer SMPS for vdev %d: %d\n", + arvif->vdev_id, ret); +@@ -3714,7 +3725,7 @@ static int ath11k_station_assoc(struct a + return 0; + + ret = ath11k_setup_peer_smps(ar, arvif, sta->addr, +- &sta->ht_cap); ++ &sta->ht_cap, le16_to_cpu(sta->he_6ghz_capa.capa)); + if (ret) { + ath11k_warn(ar->ab, "failed to setup peer SMPS for vdev %d: %d\n", + arvif->vdev_id, ret); +@@ -7661,7 +7672,7 @@ static int __ath11k_mac_register(struct + * for each band for a dual band capable radio. It will be tricky to + * handle it when the ht capability different for each band. + */ +- if (ht_cap & WMI_HT_CAP_DYNAMIC_SMPS) ++ if (ht_cap & WMI_HT_CAP_DYNAMIC_SMPS || ar->supports_6ghz) + ar->hw->wiphy->features |= NL80211_FEATURE_DYNAMIC_SMPS; + + ar->hw->wiphy->max_scan_ssids = WLAN_SCAN_PARAMS_MAX_SSID; diff --git a/package/kernel/mac80211/patches/ath11k/0054-ath11k-Remove-unused-variable-in-ath11k_dp_rx_mon_me.patch b/package/kernel/mac80211/patches/ath11k/0054-ath11k-Remove-unused-variable-in-ath11k_dp_rx_mon_me.patch new file mode 100644 index 000000000..5962d02e5 --- /dev/null +++ b/package/kernel/mac80211/patches/ath11k/0054-ath11k-Remove-unused-variable-in-ath11k_dp_rx_mon_me.patch @@ -0,0 +1,70 @@ +From 7210b4b77fe47697890d2d3b2ce57ac9f767bffc Mon Sep 17 00:00:00 2001 +From: Tim Gardner +Date: Tue, 5 Oct 2021 16:55:54 +0300 +Subject: [PATCH 054/120] ath11k: Remove unused variable in + ath11k_dp_rx_mon_merg_msdus() + +Coverity complains that a constant variable guards dead code. In fact, +mpdu_buf is set NULL and never updated. + +4834err_merge_fail: + null: At condition mpdu_buf, the value of mpdu_buf must be NULL. + dead_error_condition: The condition mpdu_buf cannot be true. +CID 92162 (#1 of 1): 'Constant' variable guards dead code (DEADCODE) +dead_error_line: Execution cannot reach the expression decap_format != + DP_RX_DECAP_TYPE_RAW inside this statement: if (mpdu_buf && decap_forma.... +Local variable mpdu_buf is assigned only once, to a constant value, making it + effectively constant throughout its scope. If this is not the intent, examine + the logic to see if there is a missing assignment that would make mpdu_buf not + remain constant. +4835 if (mpdu_buf && decap_format != DP_RX_DECAP_TYPE_RAW) { + +Fix this by removing mpdu_buf and unreachable code. + +Cc: Kalle Valo +Cc: "David S. Miller" +Cc: Jakub Kicinski +Cc: ath11k@lists.infradead.org +Cc: linux-wireless@vger.kernel.org +Cc: netdev@vger.kernel.org +Cc: linux-kernel@vger.kernel.org +Signed-off-by: Tim Gardner +Signed-off-by: Kalle Valo +Link: https://lore.kernel.org/r/20210927150743.19816-1-tim.gardner@canonical.com +--- + drivers/net/wireless/ath/ath11k/dp_rx.c | 10 +--------- + 1 file changed, 1 insertion(+), 9 deletions(-) + +--- a/drivers/net/wireless/ath/ath11k/dp_rx.c ++++ b/drivers/net/wireless/ath/ath11k/dp_rx.c +@@ -4828,7 +4828,7 @@ ath11k_dp_rx_mon_merg_msdus(struct ath11 + struct ieee80211_rx_status *rxs) + { + struct ath11k_base *ab = ar->ab; +- struct sk_buff *msdu, *mpdu_buf, *prev_buf; ++ struct sk_buff *msdu, *prev_buf; + u32 wifi_hdr_len; + struct hal_rx_desc *rx_desc; + char *hdr_desc; +@@ -4836,8 +4836,6 @@ ath11k_dp_rx_mon_merg_msdus(struct ath11 + struct ieee80211_hdr_3addr *wh; + struct rx_attention *rx_attention; + +- mpdu_buf = NULL; +- + if (!head_msdu) + goto err_merge_fail; + +@@ -4920,12 +4918,6 @@ ath11k_dp_rx_mon_merg_msdus(struct ath11 + return head_msdu; + + err_merge_fail: +- if (mpdu_buf && decap_format != DP_RX_DECAP_TYPE_RAW) { +- ath11k_dbg(ab, ATH11K_DBG_DATA, +- "err_merge_fail mpdu_buf %pK", mpdu_buf); +- /* Free the head buffer */ +- dev_kfree_skb_any(mpdu_buf); +- } + return NULL; + } + diff --git a/package/kernel/mac80211/patches/ath11k/0055-ath11k-Fix-spelling-mistake-incompaitiblity-incompat.patch b/package/kernel/mac80211/patches/ath11k/0055-ath11k-Fix-spelling-mistake-incompaitiblity-incompat.patch new file mode 100644 index 000000000..1eb7c5463 --- /dev/null +++ b/package/kernel/mac80211/patches/ath11k/0055-ath11k-Fix-spelling-mistake-incompaitiblity-incompat.patch @@ -0,0 +1,26 @@ +From 567ec33a76c7d8e7fbd7a73c81dd16b9efc7ae6d Mon Sep 17 00:00:00 2001 +From: Colin Ian King +Date: Wed, 6 Oct 2021 09:32:17 +0100 +Subject: [PATCH 055/120] ath11k: Fix spelling mistake "incompaitiblity" -> + "incompatibility" + +There is a spelling mistake in an ath11k_warn message. Fix it. + +Signed-off-by: Colin Ian King +Signed-off-by: Kalle Valo +Link: https://lore.kernel.org/r/20211006083217.349596-1-colin.king@canonical.com +--- + drivers/net/wireless/ath/ath11k/mac.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +--- a/drivers/net/wireless/ath/ath11k/mac.c ++++ b/drivers/net/wireless/ath/ath11k/mac.c +@@ -7081,7 +7081,7 @@ ath11k_mac_op_set_bitrate_mask(struct ie + + if (!ath11k_mac_validate_vht_he_fixed_rate_settings(ar, band, mask)) + ath11k_warn(ar->ab, +- "could not update fixed rate settings to all peers due to mcs/nss incompaitiblity\n"); ++ "could not update fixed rate settings to all peers due to mcs/nss incompatibility\n"); + nss = min_t(u32, ar->num_tx_chains, + max(max(ath11k_mac_max_ht_nss(ht_mcs_mask), + ath11k_mac_max_vht_nss(vht_mcs_mask)), diff --git a/package/kernel/mac80211/patches/ath11k/0056-ath11k-fix-m68k-and-xtensa-build-failure-in-ath11k_p.patch b/package/kernel/mac80211/patches/ath11k/0056-ath11k-fix-m68k-and-xtensa-build-failure-in-ath11k_p.patch new file mode 100644 index 000000000..c94498dbc --- /dev/null +++ b/package/kernel/mac80211/patches/ath11k/0056-ath11k-fix-m68k-and-xtensa-build-failure-in-ath11k_p.patch @@ -0,0 +1,56 @@ +From 16bdce2ada5a4c3c91b7c4e81780d2de50bd6ab5 Mon Sep 17 00:00:00 2001 +From: Kalle Valo +Date: Fri, 8 Oct 2021 17:39:32 +0300 +Subject: [PATCH 056/120] ath11k: fix m68k and xtensa build failure in + ath11k_peer_assoc_h_smps() + +Stephen reported that ath11k was failing to build on m68k and xtensa: + +In file included from :0:0: +In function 'ath11k_peer_assoc_h_smps', + inlined from 'ath11k_peer_assoc_prepare' at drivers/net/wireless/ath/ath11k/mac.c:2362:2: +include/linux/compiler_types.h:317:38: error: call to '__compiletime_assert_650' declared with attribute error: FIELD_GET: type of reg too small for mask + _compiletime_assert(condition, msg, __compiletime_assert_, __COUNTER__) + ^ +include/linux/compiler_types.h:298:4: note: in definition of macro '__compiletime_assert' + prefix ## suffix(); \ + ^ +include/linux/compiler_types.h:317:2: note: in expansion of macro '_compiletime_assert' + _compiletime_assert(condition, msg, __compiletime_assert_, __COUNTER__) + ^ +include/linux/build_bug.h:39:37: note: in expansion of macro 'compiletime_assert' + #define BUILD_BUG_ON_MSG(cond, msg) compiletime_assert(!(cond), msg) + ^ +include/linux/bitfield.h:52:3: note: in expansion of macro 'BUILD_BUG_ON_MSG' + BUILD_BUG_ON_MSG((_mask) > (typeof(_reg))~0ull, \ + ^ +include/linux/bitfield.h:108:3: note: in expansion of macro '__BF_FIELD_CHECK' + __BF_FIELD_CHECK(_mask, _reg, 0U, "FIELD_GET: "); \ + ^ +drivers/net/wireless/ath/ath11k/mac.c:2079:10: note: in expansion of macro 'FIELD_GET' + smps = FIELD_GET(IEEE80211_HE_6GHZ_CAP_SM_PS, + +Fix the issue by using le16_get_bits() to specify the size explicitly. + +Fixes: 6f4d70308e5e ("ath11k: support SMPS configuration for 6 GHz") +Reported-by: Stephen Rothwell +Tested-by: Geert Uytterhoeven +Signed-off-by: Kalle Valo +Signed-off-by: David S. Miller +--- + drivers/net/wireless/ath/ath11k/mac.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +--- a/drivers/net/wireless/ath/ath11k/mac.c ++++ b/drivers/net/wireless/ath/ath11k/mac.c +@@ -2076,8 +2076,8 @@ static void ath11k_peer_assoc_h_smps(str + smps = ht_cap->cap & IEEE80211_HT_CAP_SM_PS; + smps >>= IEEE80211_HT_CAP_SM_PS_SHIFT; + } else { +- smps = FIELD_GET(IEEE80211_HE_6GHZ_CAP_SM_PS, +- le16_to_cpu(sta->he_6ghz_capa.capa)); ++ smps = le16_get_bits(sta->he_6ghz_capa.capa, ++ IEEE80211_HE_6GHZ_CAP_SM_PS); + } + + switch (smps) { diff --git a/package/kernel/mac80211/patches/ath11k/0057-ath11k-Remove-redundant-assignment-to-variable-fw_si.patch b/package/kernel/mac80211/patches/ath11k/0057-ath11k-Remove-redundant-assignment-to-variable-fw_si.patch new file mode 100644 index 000000000..f7b8998ad --- /dev/null +++ b/package/kernel/mac80211/patches/ath11k/0057-ath11k-Remove-redundant-assignment-to-variable-fw_si.patch @@ -0,0 +1,29 @@ +From 4f50bdfb4e5fc3d753c8cf94b94b43aaa2c49b95 Mon Sep 17 00:00:00 2001 +From: Colin Ian King +Date: Thu, 7 Oct 2021 18:16:24 +0300 +Subject: [PATCH 057/120] ath11k: Remove redundant assignment to variable + fw_size + +Variable fw_size is being assigned a value that is never read and +being re-assigned a new value in the next statement. The assignment +is redundant and can be removed. + +Addresses-Coverity: ("Unused value") +Fixes: 336e7b53c82f ("ath11k: clean up BDF download functions") +Signed-off-by: Colin Ian King +Signed-off-by: Kalle Valo +Link: https://lore.kernel.org/r/20211006105529.1011239-1-colin.king@canonical.com +--- + drivers/net/wireless/ath/ath11k/qmi.c | 1 - + 1 file changed, 1 deletion(-) + +--- a/drivers/net/wireless/ath/ath11k/qmi.c ++++ b/drivers/net/wireless/ath/ath11k/qmi.c +@@ -2135,7 +2135,6 @@ static int ath11k_qmi_load_bdf_qmi(struc + + ath11k_dbg(ab, ATH11K_DBG_QMI, "qmi bdf_type %d\n", bdf_type); + +- fw_size = bd.len; + fw_size = min_t(u32, ab->hw_params.fw.board_size, bd.len); + + ret = ath11k_qmi_load_file_target_mem(ab, bd.data, fw_size, bdf_type); diff --git a/package/kernel/mac80211/patches/ath11k/0058-ath11k-Use-kcalloc-instead-of-kzalloc.patch b/package/kernel/mac80211/patches/ath11k/0058-ath11k-Use-kcalloc-instead-of-kzalloc.patch new file mode 100644 index 000000000..fd41386e7 --- /dev/null +++ b/package/kernel/mac80211/patches/ath11k/0058-ath11k-Use-kcalloc-instead-of-kzalloc.patch @@ -0,0 +1,40 @@ +From ec4363384c3f110561dc5ee2e59adee02dbd9f73 Mon Sep 17 00:00:00 2001 +From: "Gustavo A. R. Silva" +Date: Thu, 7 Oct 2021 18:16:24 +0300 +Subject: [PATCH 058/120] ath11k: Use kcalloc() instead of kzalloc() + +Use 2-factor multiplication argument form kcalloc() instead +of kzalloc(). + +Link: https://github.com/KSPP/linux/issues/162 +Signed-off-by: Gustavo A. R. Silva +Signed-off-by: Kalle Valo +Link: https://lore.kernel.org/r/20211006181204.GA913553@embeddedor +--- + drivers/net/wireless/ath/ath11k/wmi.c | 8 ++++---- + 1 file changed, 4 insertions(+), 4 deletions(-) + +--- a/drivers/net/wireless/ath/ath11k/wmi.c ++++ b/drivers/net/wireless/ath/ath11k/wmi.c +@@ -4065,8 +4065,8 @@ static int ath11k_wmi_tlv_mac_phy_caps_p + + len = min_t(u16, len, sizeof(struct wmi_mac_phy_capabilities)); + if (!svc_rdy_ext->n_mac_phy_caps) { +- svc_rdy_ext->mac_phy_caps = kzalloc((svc_rdy_ext->tot_phy_id) * len, +- GFP_ATOMIC); ++ svc_rdy_ext->mac_phy_caps = kcalloc(svc_rdy_ext->tot_phy_id, ++ len, GFP_ATOMIC); + if (!svc_rdy_ext->mac_phy_caps) + return -ENOMEM; + } +@@ -4466,8 +4466,8 @@ static struct cur_reg_rule + struct cur_reg_rule *reg_rule_ptr; + u32 count; + +- reg_rule_ptr = kzalloc((num_reg_rules * sizeof(*reg_rule_ptr)), +- GFP_ATOMIC); ++ reg_rule_ptr = kcalloc(num_reg_rules, sizeof(*reg_rule_ptr), ++ GFP_ATOMIC); + + if (!reg_rule_ptr) + return NULL; diff --git a/package/kernel/mac80211/patches/ath11k/0059-ath11k-Handle-MSI-enablement-during-rmmod-and-SSR.patch b/package/kernel/mac80211/patches/ath11k/0059-ath11k-Handle-MSI-enablement-during-rmmod-and-SSR.patch new file mode 100644 index 000000000..633cc46c6 --- /dev/null +++ b/package/kernel/mac80211/patches/ath11k/0059-ath11k-Handle-MSI-enablement-during-rmmod-and-SSR.patch @@ -0,0 +1,139 @@ +From 96527d527b271d950367ad13e3de8b0673545622 Mon Sep 17 00:00:00 2001 +From: Baochen Qiang +Date: Mon, 11 Oct 2021 09:33:08 +0300 +Subject: [PATCH 059/120] ath11k: Handle MSI enablement during rmmod and SSR + +When doing "rmmod ath11k_pci", ath11k performs global SOC reset +and MHI reset, where 0 address access is captured by IOMMU. See +log below: + +... +[ 133.953860] ath11k_pci 0000:02:00.0: setting mhi state: DEINIT(1) +[ 133.959714] ath11k_pci 0000:02:00.0: AMD-Vi: Event logged [IO_PAGE_FAULT domain=0x000a address=0x0 flags=0x0020] +[ 133.973854] ath11k_pci 0000:02:00.0: MHISTATUS 0xff04 +[ 133.974095] ath11k_pci 0000:02:00.0: AMD-Vi: Event logged [IO_PAGE_FAULT domain=0x000a address=0x0 flags=0x0020] +... + +This issue is also observed in SSR process, cause a similar +sequence as above is performed. + +Such an invalid access occurs because, during rmmod or SSR, MSI +address is cleared but HW MSI functionality not disabled, thus HW +target is able to raise an MSI transaction with 0 as MSI address. + +So it can be fixed by simply disabling MSI before reset. For SSR, +since MSI functionality is still needed after target is brought +back, we need to reenable it. + +Also change naming of some interfaces related. + +Tested-on: QCA6390 hw2.0 PCI WLAN.HST.1.0.1-01740-QCAHSTSWPLZ_V2_TO_X86-1 +Tested-on: WCN6855 hw2.0 PCI WLAN.HSP.1.1-01720.1-QCAHSPSWPL_V1_V2_SILICONZ_LITE-1 + +Signed-off-by: Baochen Qiang +Signed-off-by: Jouni Malinen +Signed-off-by: Kalle Valo +Link: https://lore.kernel.org/r/20210913180246.193388-5-jouni@codeaurora.org +--- + drivers/net/wireless/ath/ath11k/pci.c | 41 +++++++++++++++++++++++---- + 1 file changed, 36 insertions(+), 5 deletions(-) + +--- a/drivers/net/wireless/ath/ath11k/pci.c ++++ b/drivers/net/wireless/ath/ath11k/pci.c +@@ -855,7 +855,32 @@ static void ath11k_pci_ce_irqs_enable(st + } + } + +-static int ath11k_pci_enable_msi(struct ath11k_pci *ab_pci) ++static void ath11k_pci_msi_config(struct ath11k_pci *ab_pci, bool enable) ++{ ++ struct pci_dev *dev = ab_pci->pdev; ++ u16 control; ++ ++ pci_read_config_word(dev, dev->msi_cap + PCI_MSI_FLAGS, &control); ++ ++ if (enable) ++ control |= PCI_MSI_FLAGS_ENABLE; ++ else ++ control &= ~PCI_MSI_FLAGS_ENABLE; ++ ++ pci_write_config_word(dev, dev->msi_cap + PCI_MSI_FLAGS, control); ++} ++ ++static void ath11k_pci_msi_enable(struct ath11k_pci *ab_pci) ++{ ++ ath11k_pci_msi_config(ab_pci, true); ++} ++ ++static void ath11k_pci_msi_disable(struct ath11k_pci *ab_pci) ++{ ++ ath11k_pci_msi_config(ab_pci, false); ++} ++ ++static int ath11k_pci_alloc_msi(struct ath11k_pci *ab_pci) + { + struct ath11k_base *ab = ab_pci->ab; + const struct ath11k_msi_config *msi_config = ab_pci->msi_config; +@@ -876,6 +901,7 @@ static int ath11k_pci_enable_msi(struct + else + return num_vectors; + } ++ ath11k_pci_msi_disable(ab_pci); + + msi_desc = irq_get_msi_desc(ab_pci->pdev->irq); + if (!msi_desc) { +@@ -898,7 +924,7 @@ free_msi_vector: + return ret; + } + +-static void ath11k_pci_disable_msi(struct ath11k_pci *ab_pci) ++static void ath11k_pci_free_msi(struct ath11k_pci *ab_pci) + { + pci_free_irq_vectors(ab_pci->pdev); + } +@@ -1019,6 +1045,8 @@ static int ath11k_pci_power_up(struct at + */ + ath11k_pci_aspm_disable(ab_pci); + ++ ath11k_pci_msi_enable(ab_pci); ++ + ret = ath11k_mhi_start(ab_pci); + if (ret) { + ath11k_err(ab, "failed to start mhi: %d\n", ret); +@@ -1039,6 +1067,9 @@ static void ath11k_pci_power_down(struct + ath11k_pci_aspm_restore(ab_pci); + + ath11k_pci_force_wake(ab_pci->ab); ++ ++ ath11k_pci_msi_disable(ab_pci); ++ + ath11k_mhi_stop(ab_pci); + clear_bit(ATH11K_PCI_FLAG_INIT_DONE, &ab_pci->flags); + ath11k_pci_sw_reset(ab_pci->ab, false); +@@ -1263,7 +1294,7 @@ static int ath11k_pci_probe(struct pci_d + goto err_pci_free_region; + } + +- ret = ath11k_pci_enable_msi(ab_pci); ++ ret = ath11k_pci_alloc_msi(ab_pci); + if (ret) { + ath11k_err(ab, "failed to enable msi: %d\n", ret); + goto err_pci_free_region; +@@ -1317,7 +1348,7 @@ err_mhi_unregister: + ath11k_mhi_unregister(ab_pci); + + err_pci_disable_msi: +- ath11k_pci_disable_msi(ab_pci); ++ ath11k_pci_free_msi(ab_pci); + + err_pci_free_region: + ath11k_pci_free_region(ab_pci); +@@ -1348,7 +1379,7 @@ qmi_fail: + ath11k_mhi_unregister(ab_pci); + + ath11k_pci_free_irq(ab); +- ath11k_pci_disable_msi(ab_pci); ++ ath11k_pci_free_msi(ab_pci); + ath11k_pci_free_region(ab_pci); + + ath11k_hal_srng_deinit(ab); diff --git a/package/kernel/mac80211/patches/ath11k/0060-ath11k-Change-number-of-TCL-rings-to-one-for-QCA6390.patch b/package/kernel/mac80211/patches/ath11k/0060-ath11k-Change-number-of-TCL-rings-to-one-for-QCA6390.patch new file mode 100644 index 000000000..806206561 --- /dev/null +++ b/package/kernel/mac80211/patches/ath11k/0060-ath11k-Change-number-of-TCL-rings-to-one-for-QCA6390.patch @@ -0,0 +1,241 @@ +From 31582373a4a8e888b29ed759d28330a1995f2162 Mon Sep 17 00:00:00 2001 +From: Baochen Qiang +Date: Mon, 11 Oct 2021 09:33:09 +0300 +Subject: [PATCH 060/120] ath11k: Change number of TCL rings to one for QCA6390 + +Some targets, QCA6390 for example, use only one TCL ring, it is better to +initialize only one ring and leave others untouched for such targets. + +This is a theoretical fix found during code review, no visible impact. + +Tested-on: QCA6390 hw2.0 PCI WLAN.HST.1.0.1-01740-QCAHSTSWPLZ_V2_TO_X86-1 + +Signed-off-by: Baochen Qiang +Signed-off-by: Jouni Malinen +Signed-off-by: Kalle Valo +Link: https://lore.kernel.org/r/20210914163726.38604-1-jouni@codeaurora.org +--- + drivers/net/wireless/ath/ath11k/core.c | 10 +++++----- + drivers/net/wireless/ath/ath11k/debugfs.c | 2 +- + drivers/net/wireless/ath/ath11k/dp.c | 10 +++++----- + drivers/net/wireless/ath/ath11k/dp.h | 1 + + drivers/net/wireless/ath/ath11k/dp_tx.c | 13 +++++-------- + drivers/net/wireless/ath/ath11k/hw.h | 2 +- + drivers/net/wireless/ath/ath11k/mac.c | 2 +- + 7 files changed, 19 insertions(+), 21 deletions(-) + +--- a/drivers/net/wireless/ath/ath11k/core.c ++++ b/drivers/net/wireless/ath/ath11k/core.c +@@ -58,7 +58,6 @@ static const struct ath11k_hw_params ath + .rx_mac_buf_ring = false, + .vdev_start_delay = false, + .htt_peer_map_v2 = true, +- .tcl_0_only = false, + + .spectral = { + .fft_sz = 2, +@@ -81,6 +80,7 @@ static const struct ath11k_hw_params ath + .supports_suspend = false, + .hal_desc_sz = sizeof(struct hal_rx_desc_ipq8074), + .fix_l1ss = true, ++ .max_tx_ring = DP_TCL_NUM_RING_MAX, + }, + { + .hw_rev = ATH11K_HW_IPQ6018_HW10, +@@ -109,7 +109,6 @@ static const struct ath11k_hw_params ath + .rx_mac_buf_ring = false, + .vdev_start_delay = false, + .htt_peer_map_v2 = true, +- .tcl_0_only = false, + + .spectral = { + .fft_sz = 4, +@@ -129,6 +128,7 @@ static const struct ath11k_hw_params ath + .supports_suspend = false, + .hal_desc_sz = sizeof(struct hal_rx_desc_ipq8074), + .fix_l1ss = true, ++ .max_tx_ring = DP_TCL_NUM_RING_MAX, + }, + { + .name = "qca6390 hw2.0", +@@ -157,7 +157,6 @@ static const struct ath11k_hw_params ath + .rx_mac_buf_ring = true, + .vdev_start_delay = true, + .htt_peer_map_v2 = false, +- .tcl_0_only = true, + + .spectral = { + .fft_sz = 0, +@@ -176,6 +175,7 @@ static const struct ath11k_hw_params ath + .supports_suspend = true, + .hal_desc_sz = sizeof(struct hal_rx_desc_ipq8074), + .fix_l1ss = true, ++ .max_tx_ring = DP_TCL_NUM_RING_MAX_QCA6390, + }, + { + .name = "qcn9074 hw1.0", +@@ -203,7 +203,6 @@ static const struct ath11k_hw_params ath + .rx_mac_buf_ring = false, + .vdev_start_delay = false, + .htt_peer_map_v2 = true, +- .tcl_0_only = false, + + .spectral = { + .fft_sz = 2, +@@ -223,6 +222,7 @@ static const struct ath11k_hw_params ath + .supports_suspend = false, + .hal_desc_sz = sizeof(struct hal_rx_desc_qcn9074), + .fix_l1ss = true, ++ .max_tx_ring = DP_TCL_NUM_RING_MAX, + }, + { + .name = "wcn6855 hw2.0", +@@ -251,7 +251,6 @@ static const struct ath11k_hw_params ath + .rx_mac_buf_ring = true, + .vdev_start_delay = true, + .htt_peer_map_v2 = false, +- .tcl_0_only = true, + + .spectral = { + .fft_sz = 0, +@@ -270,6 +269,7 @@ static const struct ath11k_hw_params ath + .supports_suspend = true, + .hal_desc_sz = sizeof(struct hal_rx_desc_wcn6855), + .fix_l1ss = false, ++ .max_tx_ring = DP_TCL_NUM_RING_MAX_QCA6390, + }, + }; + +--- a/drivers/net/wireless/ath/ath11k/debugfs.c ++++ b/drivers/net/wireless/ath/ath11k/debugfs.c +@@ -806,7 +806,7 @@ static ssize_t ath11k_debugfs_dump_soc_d + len += scnprintf(buf + len, size - len, "\nSOC TX STATS:\n"); + len += scnprintf(buf + len, size - len, "\nTCL Ring Full Failures:\n"); + +- for (i = 0; i < DP_TCL_NUM_RING_MAX; i++) ++ for (i = 0; i < ab->hw_params.max_tx_ring; i++) + len += scnprintf(buf + len, size - len, "ring%d: %u\n", + i, soc_stats->tx_err.desc_na[i]); + +--- a/drivers/net/wireless/ath/ath11k/dp.c ++++ b/drivers/net/wireless/ath/ath11k/dp.c +@@ -311,7 +311,7 @@ void ath11k_dp_stop_shadow_timers(struct + if (!ab->hw_params.supports_shadow_regs) + return; + +- for (i = 0; i < DP_TCL_NUM_RING_MAX; i++) ++ for (i = 0; i < ab->hw_params.max_tx_ring; i++) + ath11k_dp_shadow_stop_timer(ab, &ab->dp.tx_ring_timer[i]); + + ath11k_dp_shadow_stop_timer(ab, &ab->dp.reo_cmd_timer); +@@ -326,7 +326,7 @@ static void ath11k_dp_srng_common_cleanu + ath11k_dp_srng_cleanup(ab, &dp->wbm_desc_rel_ring); + ath11k_dp_srng_cleanup(ab, &dp->tcl_cmd_ring); + ath11k_dp_srng_cleanup(ab, &dp->tcl_status_ring); +- for (i = 0; i < DP_TCL_NUM_RING_MAX; i++) { ++ for (i = 0; i < ab->hw_params.max_tx_ring; i++) { + ath11k_dp_srng_cleanup(ab, &dp->tx_ring[i].tcl_data_ring); + ath11k_dp_srng_cleanup(ab, &dp->tx_ring[i].tcl_comp_ring); + } +@@ -366,7 +366,7 @@ static int ath11k_dp_srng_common_setup(s + goto err; + } + +- for (i = 0; i < DP_TCL_NUM_RING_MAX; i++) { ++ for (i = 0; i < ab->hw_params.max_tx_ring; i++) { + ret = ath11k_dp_srng_setup(ab, &dp->tx_ring[i].tcl_data_ring, + HAL_TCL_DATA, i, 0, + DP_TCL_DATA_RING_SIZE); +@@ -996,7 +996,7 @@ void ath11k_dp_free(struct ath11k_base * + + ath11k_dp_reo_cmd_list_cleanup(ab); + +- for (i = 0; i < DP_TCL_NUM_RING_MAX; i++) { ++ for (i = 0; i < ab->hw_params.max_tx_ring; i++) { + spin_lock_bh(&dp->tx_ring[i].tx_idr_lock); + idr_for_each(&dp->tx_ring[i].txbuf_idr, + ath11k_dp_tx_pending_cleanup, ab); +@@ -1046,7 +1046,7 @@ int ath11k_dp_alloc(struct ath11k_base * + + size = sizeof(struct hal_wbm_release_ring) * DP_TX_COMP_RING_SIZE; + +- for (i = 0; i < DP_TCL_NUM_RING_MAX; i++) { ++ for (i = 0; i < ab->hw_params.max_tx_ring; i++) { + idr_init(&dp->tx_ring[i].txbuf_idr); + spin_lock_init(&dp->tx_ring[i].tx_idr_lock); + dp->tx_ring[i].tcl_data_ring_id = i; +--- a/drivers/net/wireless/ath/ath11k/dp.h ++++ b/drivers/net/wireless/ath/ath11k/dp.h +@@ -170,6 +170,7 @@ struct ath11k_pdev_dp { + #define DP_BA_WIN_SZ_MAX 256 + + #define DP_TCL_NUM_RING_MAX 3 ++#define DP_TCL_NUM_RING_MAX_QCA6390 1 + + #define DP_IDLE_SCATTER_BUFS_MAX 16 + +--- a/drivers/net/wireless/ath/ath11k/dp_tx.c ++++ b/drivers/net/wireless/ath/ath11k/dp_tx.c +@@ -115,11 +115,8 @@ int ath11k_dp_tx(struct ath11k *ar, stru + + tcl_ring_sel: + tcl_ring_retry = false; +- /* For some chip, it can only use tcl0 to tx */ +- if (ar->ab->hw_params.tcl_0_only) +- ti.ring_id = 0; +- else +- ti.ring_id = ring_selector % DP_TCL_NUM_RING_MAX; ++ ++ ti.ring_id = ring_selector % ab->hw_params.max_tx_ring; + + ring_map |= BIT(ti.ring_id); + +@@ -131,7 +128,7 @@ tcl_ring_sel: + spin_unlock_bh(&tx_ring->tx_idr_lock); + + if (ret < 0) { +- if (ring_map == (BIT(DP_TCL_NUM_RING_MAX) - 1)) { ++ if (ring_map == (BIT(ab->hw_params.max_tx_ring) - 1)) { + atomic_inc(&ab->soc_stats.tx_err.misc_fail); + return -ENOSPC; + } +@@ -248,8 +245,8 @@ tcl_ring_sel: + * checking this ring earlier for each pkt tx. + * Restart ring selection if some rings are not checked yet. + */ +- if (ring_map != (BIT(DP_TCL_NUM_RING_MAX) - 1) && +- !ar->ab->hw_params.tcl_0_only) { ++ if (ring_map != (BIT(ab->hw_params.max_tx_ring) - 1) && ++ ab->hw_params.max_tx_ring > 1) { + tcl_ring_retry = true; + ring_selector++; + } +--- a/drivers/net/wireless/ath/ath11k/hw.h ++++ b/drivers/net/wireless/ath/ath11k/hw.h +@@ -152,7 +152,6 @@ struct ath11k_hw_params { + bool rx_mac_buf_ring; + bool vdev_start_delay; + bool htt_peer_map_v2; +- bool tcl_0_only; + + struct { + u8 fft_sz; +@@ -170,6 +169,7 @@ struct ath11k_hw_params { + bool supports_suspend; + u32 hal_desc_sz; + bool fix_l1ss; ++ u8 max_tx_ring; + }; + + struct ath11k_hw_ops { +--- a/drivers/net/wireless/ath/ath11k/mac.c ++++ b/drivers/net/wireless/ath/ath11k/mac.c +@@ -5797,7 +5797,7 @@ err_vdev_del: + idr_for_each(&ar->txmgmt_idr, + ath11k_mac_vif_txmgmt_idr_remove, vif); + +- for (i = 0; i < DP_TCL_NUM_RING_MAX; i++) { ++ for (i = 0; i < ab->hw_params.max_tx_ring; i++) { + spin_lock_bh(&ab->dp.tx_ring[i].tx_idr_lock); + idr_for_each(&ab->dp.tx_ring[i].txbuf_idr, + ath11k_mac_vif_unref, vif); diff --git a/package/kernel/mac80211/patches/ath11k/0061-ath11k-Identify-DFS-channel-when-sending-scan-channe.patch b/package/kernel/mac80211/patches/ath11k/0061-ath11k-Identify-DFS-channel-when-sending-scan-channe.patch new file mode 100644 index 000000000..c1a04ecbd --- /dev/null +++ b/package/kernel/mac80211/patches/ath11k/0061-ath11k-Identify-DFS-channel-when-sending-scan-channe.patch @@ -0,0 +1,33 @@ +From 8cd5c0847160aa9482d7f93ed63c4d72bad70cdf Mon Sep 17 00:00:00 2001 +From: Baochen Qiang +Date: Mon, 11 Oct 2021 18:18:00 +0300 +Subject: [PATCH 061/120] ath11k: Identify DFS channel when sending scan + channel list command + +WMI_CHAN_INFO_DFS flag should be set when configuring a DFS channel +included in scan channel list. Without it, firmware will not send a +probe request frame which is needed in connection to an AP configured +with hidden SSID/network_id. So fix this to allow probe request frames +to be sent in cases where a beacon frame has been seen on the channel +first. + +Tested-on: WCN6855 hw2.0 PCI WLAN.HSP.1.1-01720.1-QCAHSPSWPL_V1_V2_SILICONZ_LITE-1 + +Signed-off-by: Baochen Qiang +Signed-off-by: Kalle Valo +Link: https://lore.kernel.org/r/20211011054919.77071-1-bqiang@codeaurora.org +--- + drivers/net/wireless/ath/ath11k/wmi.c | 2 ++ + 1 file changed, 2 insertions(+) + +--- a/drivers/net/wireless/ath/ath11k/wmi.c ++++ b/drivers/net/wireless/ath/ath11k/wmi.c +@@ -2371,6 +2371,8 @@ int ath11k_wmi_send_scan_chan_list_cmd(s + chan_info->info |= WMI_CHAN_INFO_QUARTER_RATE; + if (tchan_info->psc_channel) + chan_info->info |= WMI_CHAN_INFO_PSC; ++ if (tchan_info->dfs_set) ++ chan_info->info |= WMI_CHAN_INFO_DFS; + + chan_info->info |= FIELD_PREP(WMI_CHAN_INFO_MODE, + tchan_info->phy_mode); diff --git a/package/kernel/mac80211/patches/ath11k/0062-ath11k-change-return-buffer-manager-for-QCA6390.patch b/package/kernel/mac80211/patches/ath11k/0062-ath11k-change-return-buffer-manager-for-QCA6390.patch new file mode 100644 index 000000000..99b31191b --- /dev/null +++ b/package/kernel/mac80211/patches/ath11k/0062-ath11k-change-return-buffer-manager-for-QCA6390.patch @@ -0,0 +1,299 @@ +From 734223d78428de3c7c7d7bc04daf258085780d90 Mon Sep 17 00:00:00 2001 +From: Baochen Qiang +Date: Wed, 20 Oct 2021 11:59:06 +0300 +Subject: [PATCH 062/120] ath11k: change return buffer manager for QCA6390 + +QCA6390 firmware uses HAL_RX_BUF_RBM_SW1_BM, not HAL_RX_BUF_RBM_SW3_BM. This is +needed to fix a case where an A-MSDU has an unexpected LLC/SNAP header in the +first subframe (CVE-2020-24588). + +Tested-on: QCA6390 hw2.0 PCI WLAN.HST.1.0.1-01740-QCAHSTSWPLZ_V2_TO_X86-1 + +Signed-off-by: Baochen Qiang +Signed-off-by: Jouni Malinen +Signed-off-by: Kalle Valo +Link: https://lore.kernel.org/r/20210914163726.38604-2-jouni@codeaurora.org +--- + drivers/net/wireless/ath/ath11k/core.c | 5 ++++ + drivers/net/wireless/ath/ath11k/dp.c | 4 +++- + drivers/net/wireless/ath/ath11k/dp_rx.c | 29 +++++++++++++++--------- + drivers/net/wireless/ath/ath11k/hal_rx.c | 6 +++-- + drivers/net/wireless/ath/ath11k/hw.c | 11 ++++++++- + drivers/net/wireless/ath/ath11k/hw.h | 9 ++++++++ + 6 files changed, 49 insertions(+), 15 deletions(-) + +--- a/drivers/net/wireless/ath/ath11k/core.c ++++ b/drivers/net/wireless/ath/ath11k/core.c +@@ -81,6 +81,7 @@ static const struct ath11k_hw_params ath + .hal_desc_sz = sizeof(struct hal_rx_desc_ipq8074), + .fix_l1ss = true, + .max_tx_ring = DP_TCL_NUM_RING_MAX, ++ .hal_params = &ath11k_hw_hal_params_ipq8074, + }, + { + .hw_rev = ATH11K_HW_IPQ6018_HW10, +@@ -129,6 +130,7 @@ static const struct ath11k_hw_params ath + .hal_desc_sz = sizeof(struct hal_rx_desc_ipq8074), + .fix_l1ss = true, + .max_tx_ring = DP_TCL_NUM_RING_MAX, ++ .hal_params = &ath11k_hw_hal_params_ipq8074, + }, + { + .name = "qca6390 hw2.0", +@@ -176,6 +178,7 @@ static const struct ath11k_hw_params ath + .hal_desc_sz = sizeof(struct hal_rx_desc_ipq8074), + .fix_l1ss = true, + .max_tx_ring = DP_TCL_NUM_RING_MAX_QCA6390, ++ .hal_params = &ath11k_hw_hal_params_qca6390, + }, + { + .name = "qcn9074 hw1.0", +@@ -223,6 +226,7 @@ static const struct ath11k_hw_params ath + .hal_desc_sz = sizeof(struct hal_rx_desc_qcn9074), + .fix_l1ss = true, + .max_tx_ring = DP_TCL_NUM_RING_MAX, ++ .hal_params = &ath11k_hw_hal_params_ipq8074, + }, + { + .name = "wcn6855 hw2.0", +@@ -270,6 +274,7 @@ static const struct ath11k_hw_params ath + .hal_desc_sz = sizeof(struct hal_rx_desc_wcn6855), + .fix_l1ss = false, + .max_tx_ring = DP_TCL_NUM_RING_MAX_QCA6390, ++ .hal_params = &ath11k_hw_hal_params_qca6390, + }, + }; + +--- a/drivers/net/wireless/ath/ath11k/dp.c ++++ b/drivers/net/wireless/ath/ath11k/dp.c +@@ -739,6 +739,7 @@ int ath11k_dp_service_srng(struct ath11k + int budget) + { + struct napi_struct *napi = &irq_grp->napi; ++ const struct ath11k_hw_hal_params *hal_params; + int grp_id = irq_grp->grp_id; + int work_done = 0; + int i = 0, j; +@@ -821,8 +822,9 @@ int ath11k_dp_service_srng(struct ath11k + struct ath11k_pdev_dp *dp = &ar->dp; + struct dp_rxdma_ring *rx_ring = &dp->rx_refill_buf_ring; + ++ hal_params = ab->hw_params.hal_params; + ath11k_dp_rxbufs_replenish(ab, id, rx_ring, 0, +- HAL_RX_BUF_RBM_SW3_BM); ++ hal_params->rx_buf_rbm); + } + } + } +--- a/drivers/net/wireless/ath/ath11k/dp_rx.c ++++ b/drivers/net/wireless/ath/ath11k/dp_rx.c +@@ -499,7 +499,7 @@ static int ath11k_dp_rxdma_ring_buf_setu + + rx_ring->bufs_max = num_entries; + ath11k_dp_rxbufs_replenish(ar->ab, dp->mac_id, rx_ring, num_entries, +- HAL_RX_BUF_RBM_SW3_BM); ++ ar->ab->hw_params.hal_params->rx_buf_rbm); + return 0; + } + +@@ -2756,7 +2756,7 @@ try_again: + rx_ring = &ar->dp.rx_refill_buf_ring; + + ath11k_dp_rxbufs_replenish(ab, i, rx_ring, num_buffs_reaped[i], +- HAL_RX_BUF_RBM_SW3_BM); ++ ab->hw_params.hal_params->rx_buf_rbm); + } + + ath11k_dp_rx_process_received_packets(ab, napi, &msdu_list, +@@ -2949,6 +2949,7 @@ static int ath11k_dp_rx_reap_mon_status_ + int *budget, struct sk_buff_head *skb_list) + { + struct ath11k *ar; ++ const struct ath11k_hw_hal_params *hal_params; + struct ath11k_pdev_dp *dp; + struct dp_rxdma_ring *rx_ring; + struct hal_srng *srng; +@@ -3019,8 +3020,9 @@ move_next: + &buf_id); + + if (!skb) { ++ hal_params = ab->hw_params.hal_params; + ath11k_hal_rx_buf_addr_info_set(rx_mon_status_desc, 0, 0, +- HAL_RX_BUF_RBM_SW3_BM); ++ hal_params->rx_buf_rbm); + num_buffs_reaped++; + break; + } +@@ -3030,7 +3032,8 @@ move_next: + FIELD_PREP(DP_RXDMA_BUF_COOKIE_BUF_ID, buf_id); + + ath11k_hal_rx_buf_addr_info_set(rx_mon_status_desc, rxcb->paddr, +- cookie, HAL_RX_BUF_RBM_SW3_BM); ++ cookie, ++ ab->hw_params.hal_params->rx_buf_rbm); + ath11k_hal_srng_src_get_next_entry(ab, srng); + num_buffs_reaped++; + } +@@ -3419,7 +3422,8 @@ static int ath11k_dp_rx_h_defrag_reo_rei + cookie = FIELD_PREP(DP_RXDMA_BUF_COOKIE_PDEV_ID, dp->mac_id) | + FIELD_PREP(DP_RXDMA_BUF_COOKIE_BUF_ID, buf_id); + +- ath11k_hal_rx_buf_addr_info_set(msdu0, paddr, cookie, HAL_RX_BUF_RBM_SW3_BM); ++ ath11k_hal_rx_buf_addr_info_set(msdu0, paddr, cookie, ++ ab->hw_params.hal_params->rx_buf_rbm); + + /* Fill mpdu details into reo entrace ring */ + srng = &ab->hal.srng_list[ab->dp.reo_reinject_ring.ring_id]; +@@ -3796,7 +3800,7 @@ int ath11k_dp_process_rx_err(struct ath1 + ath11k_hal_rx_msdu_link_info_get(link_desc_va, &num_msdus, msdu_cookies, + &rbm); + if (rbm != HAL_RX_BUF_RBM_WBM_IDLE_DESC_LIST && +- rbm != HAL_RX_BUF_RBM_SW3_BM) { ++ rbm != ab->hw_params.hal_params->rx_buf_rbm) { + ab->soc_stats.invalid_rbm++; + ath11k_warn(ab, "invalid return buffer manager %d\n", rbm); + ath11k_dp_rx_link_desc_return(ab, desc, +@@ -3852,7 +3856,7 @@ exit: + rx_ring = &ar->dp.rx_refill_buf_ring; + + ath11k_dp_rxbufs_replenish(ab, i, rx_ring, n_bufs_reaped[i], +- HAL_RX_BUF_RBM_SW3_BM); ++ ab->hw_params.hal_params->rx_buf_rbm); + } + + return tot_n_bufs_reaped; +@@ -4148,7 +4152,7 @@ int ath11k_dp_rx_process_wbm_err(struct + rx_ring = &ar->dp.rx_refill_buf_ring; + + ath11k_dp_rxbufs_replenish(ab, i, rx_ring, num_buffs_reaped[i], +- HAL_RX_BUF_RBM_SW3_BM); ++ ab->hw_params.hal_params->rx_buf_rbm); + } + + rcu_read_lock(); +@@ -4257,7 +4261,7 @@ int ath11k_dp_process_rxdma_err(struct a + + if (num_buf_freed) + ath11k_dp_rxbufs_replenish(ab, mac_id, rx_ring, num_buf_freed, +- HAL_RX_BUF_RBM_SW3_BM); ++ ab->hw_params.hal_params->rx_buf_rbm); + + return budget - quota; + } +@@ -4976,6 +4980,7 @@ static void ath11k_dp_rx_mon_dest_proces + { + struct ath11k_pdev_dp *dp = &ar->dp; + struct ath11k_mon_data *pmon = (struct ath11k_mon_data *)&dp->mon_data; ++ const struct ath11k_hw_hal_params *hal_params; + void *ring_entry; + void *mon_dst_srng; + u32 ppdu_id; +@@ -5039,16 +5044,18 @@ static void ath11k_dp_rx_mon_dest_proces + + if (rx_bufs_used) { + rx_mon_stats->dest_ppdu_done++; ++ hal_params = ar->ab->hw_params.hal_params; ++ + if (ar->ab->hw_params.rxdma1_enable) + ath11k_dp_rxbufs_replenish(ar->ab, dp->mac_id, + &dp->rxdma_mon_buf_ring, + rx_bufs_used, +- HAL_RX_BUF_RBM_SW3_BM); ++ hal_params->rx_buf_rbm); + else + ath11k_dp_rxbufs_replenish(ar->ab, dp->mac_id, + &dp->rx_refill_buf_ring, + rx_bufs_used, +- HAL_RX_BUF_RBM_SW3_BM); ++ hal_params->rx_buf_rbm); + } + } + +--- a/drivers/net/wireless/ath/ath11k/hal_rx.c ++++ b/drivers/net/wireless/ath/ath11k/hal_rx.c +@@ -356,6 +356,7 @@ int ath11k_hal_wbm_desc_parse_err(struct + struct hal_wbm_release_ring *wbm_desc = desc; + enum hal_wbm_rel_desc_type type; + enum hal_wbm_rel_src_module rel_src; ++ enum hal_rx_buf_return_buf_manager ret_buf_mgr; + + type = FIELD_GET(HAL_WBM_RELEASE_INFO0_DESC_TYPE, + wbm_desc->info0); +@@ -371,8 +372,9 @@ int ath11k_hal_wbm_desc_parse_err(struct + rel_src != HAL_WBM_REL_SRC_MODULE_REO) + return -EINVAL; + +- if (FIELD_GET(BUFFER_ADDR_INFO1_RET_BUF_MGR, +- wbm_desc->buf_addr_info.info1) != HAL_RX_BUF_RBM_SW3_BM) { ++ ret_buf_mgr = FIELD_GET(BUFFER_ADDR_INFO1_RET_BUF_MGR, ++ wbm_desc->buf_addr_info.info1); ++ if (ret_buf_mgr != ab->hw_params.hal_params->rx_buf_rbm) { + ab->soc_stats.invalid_rbm++; + return -EINVAL; + } +--- a/drivers/net/wireless/ath/ath11k/hw.c ++++ b/drivers/net/wireless/ath/ath11k/hw.c +@@ -7,10 +7,11 @@ + #include + #include + +-#include "hw.h" + #include "core.h" + #include "ce.h" + #include "hif.h" ++#include "hal.h" ++#include "hw.h" + + /* Map from pdev index to hw mac index */ + static u8 ath11k_hw_ipq8074_mac_from_pdev_id(int pdev_idx) +@@ -2124,3 +2125,11 @@ const struct ath11k_hw_regs wcn6855_regs + .pcie_qserdes_sysclk_en_sel = 0x01e0c0ac, + .pcie_pcs_osc_dtct_config_base = 0x01e0c628, + }; ++ ++const struct ath11k_hw_hal_params ath11k_hw_hal_params_ipq8074 = { ++ .rx_buf_rbm = HAL_RX_BUF_RBM_SW3_BM, ++}; ++ ++const struct ath11k_hw_hal_params ath11k_hw_hal_params_qca6390 = { ++ .rx_buf_rbm = HAL_RX_BUF_RBM_SW1_BM, ++}; +--- a/drivers/net/wireless/ath/ath11k/hw.h ++++ b/drivers/net/wireless/ath/ath11k/hw.h +@@ -6,6 +6,7 @@ + #ifndef ATH11K_HW_H + #define ATH11K_HW_H + ++#include "hal.h" + #include "wmi.h" + + /* Target configuration defines */ +@@ -119,6 +120,10 @@ struct ath11k_hw_ring_mask { + u8 host2rxdma[ATH11K_EXT_IRQ_GRP_NUM_MAX]; + }; + ++struct ath11k_hw_hal_params { ++ enum hal_rx_buf_return_buf_manager rx_buf_rbm; ++}; ++ + struct ath11k_hw_params { + const char *name; + u16 hw_rev; +@@ -170,6 +175,7 @@ struct ath11k_hw_params { + u32 hal_desc_sz; + bool fix_l1ss; + u8 max_tx_ring; ++ const struct ath11k_hw_hal_params *hal_params; + }; + + struct ath11k_hw_ops { +@@ -223,6 +229,9 @@ extern const struct ath11k_hw_ring_mask + extern const struct ath11k_hw_ring_mask ath11k_hw_ring_mask_qca6390; + extern const struct ath11k_hw_ring_mask ath11k_hw_ring_mask_qcn9074; + ++extern const struct ath11k_hw_hal_params ath11k_hw_hal_params_ipq8074; ++extern const struct ath11k_hw_hal_params ath11k_hw_hal_params_qca6390; ++ + static inline + int ath11k_hw_get_mac_from_pdev_id(struct ath11k_hw_params *hw, + int pdev_idx) diff --git a/package/kernel/mac80211/patches/ath11k/0063-ath11k-set-correct-NL80211_FEATURE_DYNAMIC_SMPS-for-.patch b/package/kernel/mac80211/patches/ath11k/0063-ath11k-set-correct-NL80211_FEATURE_DYNAMIC_SMPS-for-.patch new file mode 100644 index 000000000..86f5efddc --- /dev/null +++ b/package/kernel/mac80211/patches/ath11k/0063-ath11k-set-correct-NL80211_FEATURE_DYNAMIC_SMPS-for-.patch @@ -0,0 +1,94 @@ +From 82c434c103408842a87404e873992b7698b6df2b Mon Sep 17 00:00:00 2001 +From: Wen Gong +Date: Thu, 28 Oct 2021 10:46:28 +0300 +Subject: [PATCH 063/120] ath11k: set correct NL80211_FEATURE_DYNAMIC_SMPS for + WCN6855 + +Commit 6f4d70308e5e ("ath11k: support SMPS configuration for 6 GHz") changed +"if (ht_cap & WMI_HT_CAP_DYNAMIC_SMPS)" to "if (ht_cap & +WMI_HT_CAP_DYNAMIC_SMPS || ar->supports_6ghz)" which means +NL80211_FEATURE_DYNAMIC_SMPS is enabled for all chips which support 6 GHz. +However, WCN6855 supports 6 GHz but it does not support feature +NL80211_FEATURE_DYNAMIC_SMPS, and this can lead to MU-MIMO test failures for +WCN6855. + +Disable NL80211_FEATURE_DYNAMIC_SMPS for WCN6855 since its ht_cap does not +support WMI_HT_CAP_DYNAMIC_SMPS. Enable the feature only on QCN9074 as that's +the only other device supporting 6 GHz band. + +Tested-on: WCN6855 hw2.0 PCI WLAN.HSP.1.1-01720.1-QCAHSPSWPL_V1_V2_SILICONZ_LITE-1 + +Signed-off-by: Wen Gong +Signed-off-by: Jouni Malinen +Signed-off-by: Kalle Valo +Link: https://lore.kernel.org/r/20210914163726.38604-3-jouni@codeaurora.org +--- + drivers/net/wireless/ath/ath11k/core.c | 5 +++++ + drivers/net/wireless/ath/ath11k/hw.h | 1 + + drivers/net/wireless/ath/ath11k/mac.c | 3 ++- + 3 files changed, 8 insertions(+), 1 deletion(-) + +--- a/drivers/net/wireless/ath/ath11k/core.c ++++ b/drivers/net/wireless/ath/ath11k/core.c +@@ -82,6 +82,7 @@ static const struct ath11k_hw_params ath + .fix_l1ss = true, + .max_tx_ring = DP_TCL_NUM_RING_MAX, + .hal_params = &ath11k_hw_hal_params_ipq8074, ++ .supports_dynamic_smps_6ghz = false, + }, + { + .hw_rev = ATH11K_HW_IPQ6018_HW10, +@@ -131,6 +132,7 @@ static const struct ath11k_hw_params ath + .fix_l1ss = true, + .max_tx_ring = DP_TCL_NUM_RING_MAX, + .hal_params = &ath11k_hw_hal_params_ipq8074, ++ .supports_dynamic_smps_6ghz = false, + }, + { + .name = "qca6390 hw2.0", +@@ -179,6 +181,7 @@ static const struct ath11k_hw_params ath + .fix_l1ss = true, + .max_tx_ring = DP_TCL_NUM_RING_MAX_QCA6390, + .hal_params = &ath11k_hw_hal_params_qca6390, ++ .supports_dynamic_smps_6ghz = false, + }, + { + .name = "qcn9074 hw1.0", +@@ -227,6 +230,7 @@ static const struct ath11k_hw_params ath + .fix_l1ss = true, + .max_tx_ring = DP_TCL_NUM_RING_MAX, + .hal_params = &ath11k_hw_hal_params_ipq8074, ++ .supports_dynamic_smps_6ghz = true, + }, + { + .name = "wcn6855 hw2.0", +@@ -275,6 +279,7 @@ static const struct ath11k_hw_params ath + .fix_l1ss = false, + .max_tx_ring = DP_TCL_NUM_RING_MAX_QCA6390, + .hal_params = &ath11k_hw_hal_params_qca6390, ++ .supports_dynamic_smps_6ghz = false, + }, + }; + +--- a/drivers/net/wireless/ath/ath11k/hw.h ++++ b/drivers/net/wireless/ath/ath11k/hw.h +@@ -176,6 +176,7 @@ struct ath11k_hw_params { + bool fix_l1ss; + u8 max_tx_ring; + const struct ath11k_hw_hal_params *hal_params; ++ bool supports_dynamic_smps_6ghz; + }; + + struct ath11k_hw_ops { +--- a/drivers/net/wireless/ath/ath11k/mac.c ++++ b/drivers/net/wireless/ath/ath11k/mac.c +@@ -7672,7 +7672,8 @@ static int __ath11k_mac_register(struct + * for each band for a dual band capable radio. It will be tricky to + * handle it when the ht capability different for each band. + */ +- if (ht_cap & WMI_HT_CAP_DYNAMIC_SMPS || ar->supports_6ghz) ++ if (ht_cap & WMI_HT_CAP_DYNAMIC_SMPS || ++ (ar->supports_6ghz && ab->hw_params.supports_dynamic_smps_6ghz)) + ar->hw->wiphy->features |= NL80211_FEATURE_DYNAMIC_SMPS; + + ar->hw->wiphy->max_scan_ssids = WLAN_SCAN_PARAMS_MAX_SSID; diff --git a/package/kernel/mac80211/patches/ath11k/0064-ath11k-convert-ath11k_wmi_pdev_set_ps_mode-to-use-en.patch b/package/kernel/mac80211/patches/ath11k/0064-ath11k-convert-ath11k_wmi_pdev_set_ps_mode-to-use-en.patch new file mode 100644 index 000000000..faaa96275 --- /dev/null +++ b/package/kernel/mac80211/patches/ath11k/0064-ath11k-convert-ath11k_wmi_pdev_set_ps_mode-to-use-en.patch @@ -0,0 +1,73 @@ +From af3d89649bb69bd5be273cf6c001cd19c2604ca2 Mon Sep 17 00:00:00 2001 +From: Kalle Valo +Date: Mon, 8 Nov 2021 14:38:25 +0200 +Subject: [PATCH 064/120] ath11k: convert ath11k_wmi_pdev_set_ps_mode() to use + enum wmi_sta_ps_mode + +It's more descriptive to use the actual enum used by the firmware instead of a +boolean so change ath11k_wmi_pdev_set_ps_mode() to use a boolean. + +Tested-on: QCA6390 hw2.0 PCI WLAN.HST.1.0.1-01740-QCAHSTSWPLZ_V2_TO_X86-1 + +Signed-off-by: Kalle Valo +Link: https://lore.kernel.org/r/20211108123826.8463-1-kvalo@codeaurora.org +--- + drivers/net/wireless/ath/ath11k/mac.c | 3 ++- + drivers/net/wireless/ath/ath11k/wmi.c | 7 ++++--- + drivers/net/wireless/ath/ath11k/wmi.h | 3 ++- + 3 files changed, 8 insertions(+), 5 deletions(-) + +--- a/drivers/net/wireless/ath/ath11k/mac.c ++++ b/drivers/net/wireless/ath/ath11k/mac.c +@@ -5638,7 +5638,8 @@ static int ath11k_mac_op_add_interface(s + goto err_peer_del; + } + +- ret = ath11k_wmi_pdev_set_ps_mode(ar, arvif->vdev_id, false); ++ ret = ath11k_wmi_pdev_set_ps_mode(ar, arvif->vdev_id, ++ WMI_STA_PS_MODE_DISABLED); + if (ret) { + ath11k_warn(ar->ab, "failed to disable vdev %d ps mode: %d\n", + arvif->vdev_id, ret); +--- a/drivers/net/wireless/ath/ath11k/wmi.c ++++ b/drivers/net/wireless/ath/ath11k/wmi.c +@@ -1244,7 +1244,8 @@ int ath11k_wmi_pdev_set_param(struct ath + return ret; + } + +-int ath11k_wmi_pdev_set_ps_mode(struct ath11k *ar, int vdev_id, u32 enable) ++int ath11k_wmi_pdev_set_ps_mode(struct ath11k *ar, int vdev_id, ++ enum wmi_sta_ps_mode psmode) + { + struct ath11k_pdev_wmi *wmi = ar->wmi; + struct wmi_pdev_set_ps_mode_cmd *cmd; +@@ -1259,7 +1260,7 @@ int ath11k_wmi_pdev_set_ps_mode(struct a + cmd->tlv_header = FIELD_PREP(WMI_TLV_TAG, WMI_TAG_STA_POWERSAVE_MODE_CMD) | + FIELD_PREP(WMI_TLV_LEN, sizeof(*cmd) - TLV_HDR_SIZE); + cmd->vdev_id = vdev_id; +- cmd->sta_ps_mode = enable; ++ cmd->sta_ps_mode = psmode; + + ret = ath11k_wmi_cmd_send(wmi, skb, WMI_STA_POWERSAVE_MODE_CMDID); + if (ret) { +@@ -1269,7 +1270,7 @@ int ath11k_wmi_pdev_set_ps_mode(struct a + + ath11k_dbg(ar->ab, ATH11K_DBG_WMI, + "WMI vdev set psmode %d vdev id %d\n", +- enable, vdev_id); ++ psmode, vdev_id); + + return ret; + } +--- a/drivers/net/wireless/ath/ath11k/wmi.h ++++ b/drivers/net/wireless/ath/ath11k/wmi.h +@@ -5351,7 +5351,8 @@ int ath11k_wmi_set_peer_param(struct ath + u32 vdev_id, u32 param_id, u32 param_val); + int ath11k_wmi_pdev_set_param(struct ath11k *ar, u32 param_id, + u32 param_value, u8 pdev_id); +-int ath11k_wmi_pdev_set_ps_mode(struct ath11k *ar, int vdev_id, u32 enable); ++int ath11k_wmi_pdev_set_ps_mode(struct ath11k *ar, int vdev_id, ++ enum wmi_sta_ps_mode psmode); + int ath11k_wmi_wait_for_unified_ready(struct ath11k_base *ab); + int ath11k_wmi_cmd_init(struct ath11k_base *ab); + int ath11k_wmi_wait_for_service_ready(struct ath11k_base *ab); diff --git a/package/kernel/mac80211/patches/ath11k/0065-ath11k-enable-802.11-power-save-mode-in-station-mode.patch b/package/kernel/mac80211/patches/ath11k/0065-ath11k-enable-802.11-power-save-mode-in-station-mode.patch new file mode 100644 index 000000000..45ce607d0 --- /dev/null +++ b/package/kernel/mac80211/patches/ath11k/0065-ath11k-enable-802.11-power-save-mode-in-station-mode.patch @@ -0,0 +1,192 @@ +From b2beffa7d9a67b59b085616a27f1d10b1e80784f Mon Sep 17 00:00:00 2001 +From: Carl Huang +Date: Mon, 8 Nov 2021 14:38:26 +0200 +Subject: [PATCH 065/120] ath11k: enable 802.11 power save mode in station mode + +To reduce power consumption enable 802.11 power save mode in station mode. This +allows both radio and CPU to sleep more. + +Only enable the mode on QCA6390 and WCN6855, it's unknown how other hardware +families support this feature. + +To test that power save mode is running run "iw dev wls1 set power_save off", +check there is no NULL Data frame seen by a sniffer. And run "iw dev wls1 set power_save +on" and check there is a NULL Data frame in sniffer. + +Tested-on: QCA6390 hw2.0 PCI WLAN.HST.1.0.1-01740-QCAHSTSWPLZ_V2_TO_X86-1 + +Signed-off-by: Carl Huang +Signed-off-by: Kalle Valo +Link: https://lore.kernel.org/r/20211108123826.8463-2-kvalo@codeaurora.org +--- + drivers/net/wireless/ath/ath11k/core.c | 5 ++ + drivers/net/wireless/ath/ath11k/core.h | 1 + + drivers/net/wireless/ath/ath11k/hw.h | 1 + + drivers/net/wireless/ath/ath11k/mac.c | 87 ++++++++++++++++++++++++++ + 4 files changed, 94 insertions(+) + +--- a/drivers/net/wireless/ath/ath11k/core.c ++++ b/drivers/net/wireless/ath/ath11k/core.c +@@ -76,6 +76,7 @@ static const struct ath11k_hw_params ath + .supports_monitor = true, + .supports_shadow_regs = false, + .idle_ps = false, ++ .supports_sta_ps = false, + .cold_boot_calib = true, + .supports_suspend = false, + .hal_desc_sz = sizeof(struct hal_rx_desc_ipq8074), +@@ -126,6 +127,7 @@ static const struct ath11k_hw_params ath + .supports_monitor = true, + .supports_shadow_regs = false, + .idle_ps = false, ++ .supports_sta_ps = false, + .cold_boot_calib = true, + .supports_suspend = false, + .hal_desc_sz = sizeof(struct hal_rx_desc_ipq8074), +@@ -175,6 +177,7 @@ static const struct ath11k_hw_params ath + .supports_monitor = false, + .supports_shadow_regs = true, + .idle_ps = true, ++ .supports_sta_ps = true, + .cold_boot_calib = false, + .supports_suspend = true, + .hal_desc_sz = sizeof(struct hal_rx_desc_ipq8074), +@@ -224,6 +227,7 @@ static const struct ath11k_hw_params ath + .supports_monitor = true, + .supports_shadow_regs = false, + .idle_ps = false, ++ .supports_sta_ps = false, + .cold_boot_calib = false, + .supports_suspend = false, + .hal_desc_sz = sizeof(struct hal_rx_desc_qcn9074), +@@ -273,6 +277,7 @@ static const struct ath11k_hw_params ath + .supports_monitor = false, + .supports_shadow_regs = true, + .idle_ps = true, ++ .supports_sta_ps = true, + .cold_boot_calib = false, + .supports_suspend = true, + .hal_desc_sz = sizeof(struct hal_rx_desc_wcn6855), +--- a/drivers/net/wireless/ath/ath11k/core.h ++++ b/drivers/net/wireless/ath/ath11k/core.h +@@ -240,6 +240,7 @@ struct ath11k_vif { + bool is_started; + bool is_up; + bool spectral_enabled; ++ bool ps; + u32 aid; + u8 bssid[ETH_ALEN]; + struct cfg80211_bitrate_mask bitrate_mask; +--- a/drivers/net/wireless/ath/ath11k/hw.h ++++ b/drivers/net/wireless/ath/ath11k/hw.h +@@ -170,6 +170,7 @@ struct ath11k_hw_params { + bool supports_monitor; + bool supports_shadow_regs; + bool idle_ps; ++ bool supports_sta_ps; + bool cold_boot_calib; + bool supports_suspend; + u32 hal_desc_sz; +--- a/drivers/net/wireless/ath/ath11k/mac.c ++++ b/drivers/net/wireless/ath/ath11k/mac.c +@@ -1049,6 +1049,83 @@ static int ath11k_mac_monitor_stop(struc + return 0; + } + ++static int ath11k_mac_vif_setup_ps(struct ath11k_vif *arvif) ++{ ++ struct ath11k *ar = arvif->ar; ++ struct ieee80211_vif *vif = arvif->vif; ++ struct ieee80211_conf *conf = &ar->hw->conf; ++ enum wmi_sta_powersave_param param; ++ enum wmi_sta_ps_mode psmode; ++ int ret; ++ int timeout; ++ bool enable_ps; ++ ++ lockdep_assert_held(&arvif->ar->conf_mutex); ++ ++ if (arvif->vif->type != NL80211_IFTYPE_STATION) ++ return 0; ++ ++ enable_ps = arvif->ps; ++ ++ if (!arvif->is_started) { ++ /* mac80211 can update vif powersave state while disconnected. ++ * Firmware doesn't behave nicely and consumes more power than ++ * necessary if PS is disabled on a non-started vdev. Hence ++ * force-enable PS for non-running vdevs. ++ */ ++ psmode = WMI_STA_PS_MODE_ENABLED; ++ } else if (enable_ps) { ++ psmode = WMI_STA_PS_MODE_ENABLED; ++ param = WMI_STA_PS_PARAM_INACTIVITY_TIME; ++ ++ timeout = conf->dynamic_ps_timeout; ++ if (timeout == 0) { ++ /* firmware doesn't like 0 */ ++ timeout = ieee80211_tu_to_usec(vif->bss_conf.beacon_int) / 1000; ++ } ++ ++ ret = ath11k_wmi_set_sta_ps_param(ar, arvif->vdev_id, param, ++ timeout); ++ if (ret) { ++ ath11k_warn(ar->ab, "failed to set inactivity time for vdev %d: %i\n", ++ arvif->vdev_id, ret); ++ return ret; ++ } ++ } else { ++ psmode = WMI_STA_PS_MODE_DISABLED; ++ } ++ ++ ath11k_dbg(ar->ab, ATH11K_DBG_MAC, "mac vdev %d psmode %s\n", ++ arvif->vdev_id, psmode ? "enable" : "disable"); ++ ++ ret = ath11k_wmi_pdev_set_ps_mode(ar, arvif->vdev_id, psmode); ++ if (ret) { ++ ath11k_warn(ar->ab, "failed to set sta power save mode %d for vdev %d: %d\n", ++ psmode, arvif->vdev_id, ret); ++ return ret; ++ } ++ ++ return 0; ++} ++ ++static int ath11k_mac_config_ps(struct ath11k *ar) ++{ ++ struct ath11k_vif *arvif; ++ int ret = 0; ++ ++ lockdep_assert_held(&ar->conf_mutex); ++ ++ list_for_each_entry(arvif, &ar->arvifs, list) { ++ ret = ath11k_mac_vif_setup_ps(arvif); ++ if (ret) { ++ ath11k_warn(ar->ab, "failed to setup powersave: %d\n", ret); ++ break; ++ } ++ } ++ ++ return ret; ++} ++ + static int ath11k_mac_op_config(struct ieee80211_hw *hw, u32 changed) + { + struct ath11k *ar = hw->priv; +@@ -2942,6 +3019,16 @@ static void ath11k_mac_op_bss_info_chang + ath11k_mac_txpower_recalc(ar); + } + ++ if (changed & BSS_CHANGED_PS && ++ ar->ab->hw_params.supports_sta_ps) { ++ arvif->ps = vif->bss_conf.ps; ++ ++ ret = ath11k_mac_config_ps(ar); ++ if (ret) ++ ath11k_warn(ar->ab, "failed to setup ps on vdev %i: %d\n", ++ arvif->vdev_id, ret); ++ } ++ + if (changed & BSS_CHANGED_MCAST_RATE && + !ath11k_mac_vif_chan(arvif->vif, &def)) { + band = def.chan->band; diff --git a/package/kernel/mac80211/patches/ath11k/0066-ath11k-Send-PPDU_STATS_CFG-with-proper-pdev-mask-to-.patch b/package/kernel/mac80211/patches/ath11k/0066-ath11k-Send-PPDU_STATS_CFG-with-proper-pdev-mask-to-.patch new file mode 100644 index 000000000..5e47e5b8b --- /dev/null +++ b/package/kernel/mac80211/patches/ath11k/0066-ath11k-Send-PPDU_STATS_CFG-with-proper-pdev-mask-to-.patch @@ -0,0 +1,57 @@ +From 16a2c3d5406f95ef6139de52669c60a39443f5f7 Mon Sep 17 00:00:00 2001 +From: Rameshkumar Sundaram +Date: Wed, 10 Nov 2021 17:10:48 +0200 +Subject: [PATCH 066/120] ath11k: Send PPDU_STATS_CFG with proper pdev mask to + firmware + +HTT_PPDU_STATS_CFG_PDEV_ID bit mask for target FW PPDU stats request message +was set as bit 8 to 15. Bit 8 is reserved for soc stats and pdev id starts from +bit 9. Hence change the bitmask as bit 9 to 15 and fill the proper pdev id in +the request message. + +In commit 701e48a43e15 ("ath11k: add packet log support for QCA6390"), both +HTT_PPDU_STATS_CFG_PDEV_ID and pdev_mask were changed, but this pdev_mask +calculation is not valid for platforms which has multiple pdevs with 1 rxdma +per pdev, as this is writing same value(i.e. 2) for all pdevs. Hence fixed it +to consider pdev_idx as well, to make it compatible for both single and multi +pd cases. + +Tested on: IPQ8074 hw2.0 AHB WLAN.HK.2.5.0.1-01092-QCAHKSWPL_SILICONZ-1 +Tested on: IPQ6018 hw1.0 WLAN.HK.2.5.0.1-01067-QCAHKSWPL_SILICONZ-1 + +Fixes: 701e48a43e15 ("ath11k: add packet log support for QCA6390") + +Co-developed-by: Sathishkumar Muruganandam +Signed-off-by: Sathishkumar Muruganandam +Signed-off-by: Rameshkumar Sundaram +Signed-off-by: Jouni Malinen +Signed-off-by: Kalle Valo +Link: https://lore.kernel.org/r/20210721212029.142388-10-jouni@codeaurora.org +--- + drivers/net/wireless/ath/ath11k/dp.h | 3 ++- + drivers/net/wireless/ath/ath11k/dp_tx.c | 2 +- + 2 files changed, 3 insertions(+), 2 deletions(-) + +--- a/drivers/net/wireless/ath/ath11k/dp.h ++++ b/drivers/net/wireless/ath/ath11k/dp.h +@@ -517,7 +517,8 @@ struct htt_ppdu_stats_cfg_cmd { + } __packed; + + #define HTT_PPDU_STATS_CFG_MSG_TYPE GENMASK(7, 0) +-#define HTT_PPDU_STATS_CFG_PDEV_ID GENMASK(15, 8) ++#define HTT_PPDU_STATS_CFG_SOC_STATS BIT(8) ++#define HTT_PPDU_STATS_CFG_PDEV_ID GENMASK(15, 9) + #define HTT_PPDU_STATS_CFG_TLV_TYPE_BITMASK GENMASK(31, 16) + + enum htt_ppdu_stats_tag_type { +--- a/drivers/net/wireless/ath/ath11k/dp_tx.c ++++ b/drivers/net/wireless/ath/ath11k/dp_tx.c +@@ -903,7 +903,7 @@ int ath11k_dp_tx_htt_h2t_ppdu_stats_req( + cmd->msg = FIELD_PREP(HTT_PPDU_STATS_CFG_MSG_TYPE, + HTT_H2T_MSG_TYPE_PPDU_STATS_CFG); + +- pdev_mask = 1 << (i + 1); ++ pdev_mask = 1 << (ar->pdev_idx + i); + cmd->msg |= FIELD_PREP(HTT_PPDU_STATS_CFG_PDEV_ID, pdev_mask); + cmd->msg |= FIELD_PREP(HTT_PPDU_STATS_CFG_TLV_TYPE_BITMASK, mask); + diff --git a/package/kernel/mac80211/patches/ath11k/0067-ath11k-Clear-auth-flag-only-for-actual-association-i.patch b/package/kernel/mac80211/patches/ath11k/0067-ath11k-Clear-auth-flag-only-for-actual-association-i.patch new file mode 100644 index 000000000..739d9656f --- /dev/null +++ b/package/kernel/mac80211/patches/ath11k/0067-ath11k-Clear-auth-flag-only-for-actual-association-i.patch @@ -0,0 +1,72 @@ +From c802b6d7815d7c3f556efea28d0b79ef57ebcfd4 Mon Sep 17 00:00:00 2001 +From: Rameshkumar Sundaram +Date: Mon, 25 Oct 2021 21:33:06 +0530 +Subject: [PATCH 067/120] ath11k: Clear auth flag only for actual association + in security mode + +AUTH flag is needed when peer assoc command is sent from host in +security mode for non-assoc cases. Firmware will handle AUTH flag +when client is associating as AUTH flag will be set after key exchange. +For internally provided peer assoc commands from host, there won't be +any key exchange, so AUTH flag is expected to be set in host. + +Tested-on: QCN9074 hw1.0 PCI WLAN.HK.2.4.0.1-01838-QCAHKSWPL_SILICONZ-1 + +Co-developed-by: Lavanya Suresh +Signed-off-by: Lavanya Suresh +Signed-off-by: Rameshkumar Sundaram +Signed-off-by: Kalle Valo +Link: https://lore.kernel.org/r/1635177786-20854-1-git-send-email-quic_ramess@quicinc.com +--- + drivers/net/wireless/ath/ath11k/mac.c | 3 +++ + drivers/net/wireless/ath/ath11k/wmi.c | 2 +- + drivers/net/wireless/ath/ath11k/wmi.h | 1 + + 3 files changed, 5 insertions(+), 1 deletion(-) + +--- a/drivers/net/wireless/ath/ath11k/mac.c ++++ b/drivers/net/wireless/ath/ath11k/mac.c +@@ -2495,6 +2495,7 @@ static void ath11k_bss_assoc(struct ieee + + rcu_read_unlock(); + ++ peer_arg.is_assoc = true; + ret = ath11k_wmi_send_peer_assoc_cmd(ar, &peer_arg); + if (ret) { + ath11k_warn(ar->ab, "failed to run peer assoc for %pM vdev %i: %d\n", +@@ -3772,6 +3773,7 @@ static int ath11k_station_assoc(struct a + + ath11k_peer_assoc_prepare(ar, vif, sta, &peer_arg, reassoc); + ++ peer_arg.is_assoc = true; + ret = ath11k_wmi_send_peer_assoc_cmd(ar, &peer_arg); + if (ret) { + ath11k_warn(ar->ab, "failed to run peer assoc for STA %pM vdev %i: %d\n", +@@ -3983,6 +3985,7 @@ static void ath11k_sta_rc_update_wk(stru + ath11k_peer_assoc_prepare(ar, arvif->vif, sta, + &peer_arg, true); + ++ peer_arg.is_assoc = false; + err = ath11k_wmi_send_peer_assoc_cmd(ar, &peer_arg); + if (err) + ath11k_warn(ar->ab, "failed to run peer assoc for STA %pM vdev %i: %d\n", +--- a/drivers/net/wireless/ath/ath11k/wmi.c ++++ b/drivers/net/wireless/ath/ath11k/wmi.c +@@ -1763,7 +1763,7 @@ ath11k_wmi_copy_peer_flags(struct wmi_pe + cmd->peer_flags |= WMI_PEER_AUTH; + if (param->need_ptk_4_way) { + cmd->peer_flags |= WMI_PEER_NEED_PTK_4_WAY; +- if (!hw_crypto_disabled) ++ if (!hw_crypto_disabled && param->is_assoc) + cmd->peer_flags &= ~WMI_PEER_AUTH; + } + if (param->need_gtk_2_way) +--- a/drivers/net/wireless/ath/ath11k/wmi.h ++++ b/drivers/net/wireless/ath/ath11k/wmi.h +@@ -3617,6 +3617,7 @@ struct peer_assoc_params { + u32 peer_he_tx_mcs_set[WMI_HOST_MAX_HE_RATE_SET]; + bool twt_responder; + bool twt_requester; ++ bool is_assoc; + struct ath11k_ppe_threshold peer_ppet; + }; + diff --git a/package/kernel/mac80211/patches/ath11k/0068-ath11k-fix-fw-crash-due-to-peer-get-authorized-befor.patch b/package/kernel/mac80211/patches/ath11k/0068-ath11k-fix-fw-crash-due-to-peer-get-authorized-befor.patch new file mode 100644 index 000000000..bf769451d --- /dev/null +++ b/package/kernel/mac80211/patches/ath11k/0068-ath11k-fix-fw-crash-due-to-peer-get-authorized-befor.patch @@ -0,0 +1,114 @@ +From 85f36923be47b6990215ad444545a6a85133a0c6 Mon Sep 17 00:00:00 2001 +From: Karthikeyan Periyasamy +Date: Fri, 12 Nov 2021 10:03:40 +0200 +Subject: [PATCH 068/120] ath11k: fix fw crash due to peer get authorized + before key install + +Firmware expects host to authorize the peer after the successful key +install. But host authorize the peer before the key install, this trigger +the firmware assert which leads to Q6 crash. To avoid this Q6 crash, host +should authorize the peer after the key install. So introduce is_authorized +in peer object to identify that peer is authorize or not. When +IEEE80211_STA_CONTROL_PORT flag is unset, peer move to authorize state +before the vdev up. When the same flag is set then peer move to authorize +state after vdev up. So added authorise check in ath11k_bss_assoc() to +handle the earlier state transition case. Also added the WMI authorize +procedure in ath11k_mac_op_sta_state() to handle the non-earlier state +transition case. + +Tested-on: IPQ8074 hw2.0 AHB WLAN.HK.2.4.0.1-01492-QCAHKSWPL_SILICONZ-1 + +Signed-off-by: Karthikeyan Periyasamy +Signed-off-by: Kalle Valo +Link: https://lore.kernel.org/r/1636554200-12345-1-git-send-email-quic_periyasa@quicinc.com +--- + drivers/net/wireless/ath/ath11k/mac.c | 53 ++++++++++++++++++++++---- + drivers/net/wireless/ath/ath11k/peer.h | 1 + + 2 files changed, 47 insertions(+), 7 deletions(-) + +--- a/drivers/net/wireless/ath/ath11k/mac.c ++++ b/drivers/net/wireless/ath/ath11k/mac.c +@@ -2474,6 +2474,8 @@ static void ath11k_bss_assoc(struct ieee + struct ath11k_vif *arvif = (void *)vif->drv_priv; + struct peer_assoc_params peer_arg; + struct ieee80211_sta *ap_sta; ++ struct ath11k_peer *peer; ++ bool is_auth = false; + int ret; + + lockdep_assert_held(&ar->conf_mutex); +@@ -2536,13 +2538,22 @@ static void ath11k_bss_assoc(struct ieee + "mac vdev %d up (associated) bssid %pM aid %d\n", + arvif->vdev_id, bss_conf->bssid, bss_conf->aid); + +- /* Authorize BSS Peer */ +- ret = ath11k_wmi_set_peer_param(ar, arvif->bssid, +- arvif->vdev_id, +- WMI_PEER_AUTHORIZE, +- 1); +- if (ret) +- ath11k_warn(ar->ab, "Unable to authorize BSS peer: %d\n", ret); ++ spin_lock_bh(&ar->ab->base_lock); ++ ++ peer = ath11k_peer_find(ar->ab, arvif->vdev_id, arvif->bssid); ++ if (peer && peer->is_authorized) ++ is_auth = true; ++ ++ spin_unlock_bh(&ar->ab->base_lock); ++ ++ if (is_auth) { ++ ret = ath11k_wmi_set_peer_param(ar, arvif->bssid, ++ arvif->vdev_id, ++ WMI_PEER_AUTHORIZE, ++ 1); ++ if (ret) ++ ath11k_warn(ar->ab, "Unable to authorize BSS peer: %d\n", ret); ++ } + + ret = ath11k_wmi_send_obss_spr_cmd(ar, arvif->vdev_id, + &bss_conf->he_obss_pd); +@@ -4221,6 +4232,34 @@ static int ath11k_mac_op_sta_state(struc + ath11k_warn(ar->ab, "Failed to associate station: %pM\n", + sta->addr); + } else if (old_state == IEEE80211_STA_ASSOC && ++ new_state == IEEE80211_STA_AUTHORIZED) { ++ spin_lock_bh(&ar->ab->base_lock); ++ ++ peer = ath11k_peer_find(ar->ab, arvif->vdev_id, sta->addr); ++ if (peer) ++ peer->is_authorized = true; ++ ++ spin_unlock_bh(&ar->ab->base_lock); ++ ++ if (vif->type == NL80211_IFTYPE_STATION && arvif->is_up) { ++ ret = ath11k_wmi_set_peer_param(ar, sta->addr, ++ arvif->vdev_id, ++ WMI_PEER_AUTHORIZE, ++ 1); ++ if (ret) ++ ath11k_warn(ar->ab, "Unable to authorize peer %pM vdev %d: %d\n", ++ sta->addr, arvif->vdev_id, ret); ++ } ++ } else if (old_state == IEEE80211_STA_AUTHORIZED && ++ new_state == IEEE80211_STA_ASSOC) { ++ spin_lock_bh(&ar->ab->base_lock); ++ ++ peer = ath11k_peer_find(ar->ab, arvif->vdev_id, sta->addr); ++ if (peer) ++ peer->is_authorized = false; ++ ++ spin_unlock_bh(&ar->ab->base_lock); ++ } else if (old_state == IEEE80211_STA_ASSOC && + new_state == IEEE80211_STA_AUTH && + (vif->type == NL80211_IFTYPE_AP || + vif->type == NL80211_IFTYPE_MESH_POINT || +--- a/drivers/net/wireless/ath/ath11k/peer.h ++++ b/drivers/net/wireless/ath/ath11k/peer.h +@@ -28,6 +28,7 @@ struct ath11k_peer { + u8 ucast_keyidx; + u16 sec_type; + u16 sec_type_grp; ++ bool is_authorized; + }; + + void ath11k_peer_unmap_event(struct ath11k_base *ab, u16 peer_id); diff --git a/package/kernel/mac80211/patches/ath11k/0069-ath11k-fix-error-routine-when-fallback-of-add-interf.patch b/package/kernel/mac80211/patches/ath11k/0069-ath11k-fix-error-routine-when-fallback-of-add-interf.patch new file mode 100644 index 000000000..ee9e34f08 --- /dev/null +++ b/package/kernel/mac80211/patches/ath11k/0069-ath11k-fix-error-routine-when-fallback-of-add-interf.patch @@ -0,0 +1,60 @@ +From 4ea03443ecdac6920eb7aa3a9da2cd0b8cc6dfc8 Mon Sep 17 00:00:00 2001 +From: Karthikeyan Periyasamy +Date: Wed, 10 Nov 2021 21:05:57 +0530 +Subject: [PATCH 069/120] ath11k: fix error routine when fallback of add + interface fails + +When there is an error in add interface process from +ath11k_mac_set_kickout(), the code attempts to handle a +fallback for add_interface. When this fallback succeeds, the +driver returns zero rather than error code. This leads to +success for the non created VAP. In cleanup, driver gets +remove interface callback for the non created VAP and +proceeds to self peer delete request which leads to FW assert. +Since it was already deleted on the fallback of add interface, +return the actual error code instead of fallback return code. + +Tested-on: IPQ8074 hw2.0 AHB WLAN.HK.2.5.0.1-00729-QCAHKSWPL_SILICONZ-3 v2 + +Signed-off-by: Karthikeyan Periyasamy +Signed-off-by: Kalle Valo +Link: https://lore.kernel.org/r/1636558557-2874-1-git-send-email-quic_periyasa@quicinc.com +--- + drivers/net/wireless/ath/ath11k/mac.c | 14 +++++++------- + 1 file changed, 7 insertions(+), 7 deletions(-) + +--- a/drivers/net/wireless/ath/ath11k/mac.c ++++ b/drivers/net/wireless/ath/ath11k/mac.c +@@ -5613,7 +5613,7 @@ static int ath11k_mac_op_add_interface(s + u32 param_id, param_value; + u16 nss; + int i; +- int ret; ++ int ret, fbret; + int bit; + + vif->driver_flags |= IEEE80211_VIF_SUPPORTS_UAPSD; +@@ -5816,17 +5816,17 @@ err_peer_del: + if (arvif->vdev_type == WMI_VDEV_TYPE_AP) { + reinit_completion(&ar->peer_delete_done); + +- ret = ath11k_wmi_send_peer_delete_cmd(ar, vif->addr, +- arvif->vdev_id); +- if (ret) { ++ fbret = ath11k_wmi_send_peer_delete_cmd(ar, vif->addr, ++ arvif->vdev_id); ++ if (fbret) { + ath11k_warn(ar->ab, "failed to delete peer vdev_id %d addr %pM\n", + arvif->vdev_id, vif->addr); + goto err; + } + +- ret = ath11k_wait_for_peer_delete_done(ar, arvif->vdev_id, +- vif->addr); +- if (ret) ++ fbret = ath11k_wait_for_peer_delete_done(ar, arvif->vdev_id, ++ vif->addr); ++ if (fbret) + goto err; + + ar->num_peers--; diff --git a/package/kernel/mac80211/patches/ath11k/0070-ath11k-avoid-unnecessary-BH-disable-lock-in-STA-kick.patch b/package/kernel/mac80211/patches/ath11k/0070-ath11k-avoid-unnecessary-BH-disable-lock-in-STA-kick.patch new file mode 100644 index 000000000..5b678876b --- /dev/null +++ b/package/kernel/mac80211/patches/ath11k/0070-ath11k-avoid-unnecessary-BH-disable-lock-in-STA-kick.patch @@ -0,0 +1,57 @@ +From 4c375743c5fe1ef84d1dd7269dd12585957f403e Mon Sep 17 00:00:00 2001 +From: Karthikeyan Periyasamy +Date: Wed, 10 Nov 2021 21:36:28 +0530 +Subject: [PATCH 070/120] ath11k: avoid unnecessary BH disable lock in STA + kickout event + +In STA kickout event processing, the peer object is protected +under spin lock BH. Release this lock after picking up the vdev_id +from the peer object instead after ieee80211_report_low_ack(). +This will minimize the lock hold period which will improve +performance since base_lock is used across the data path. +This was found in code review. + +Tested-on: IPQ8074 hw2.0 AHB WLAN.HK.2.5.0.1-00729-QCAHKSWPL_SILICONZ-3 v2 + +Signed-off-by: Karthikeyan Periyasamy +Signed-off-by: Kalle Valo +Link: https://lore.kernel.org/r/1636560388-24955-1-git-send-email-quic_periyasa@quicinc.com +--- + drivers/net/wireless/ath/ath11k/wmi.c | 9 +++++++-- + 1 file changed, 7 insertions(+), 2 deletions(-) + +--- a/drivers/net/wireless/ath/ath11k/wmi.c ++++ b/drivers/net/wireless/ath/ath11k/wmi.c +@@ -6399,6 +6399,7 @@ static void ath11k_peer_sta_kickout_even + struct ieee80211_sta *sta; + struct ath11k_peer *peer; + struct ath11k *ar; ++ u32 vdev_id; + + if (ath11k_pull_peer_sta_kickout_ev(ab, skb, &arg) != 0) { + ath11k_warn(ab, "failed to extract peer sta kickout event"); +@@ -6414,10 +6415,15 @@ static void ath11k_peer_sta_kickout_even + if (!peer) { + ath11k_warn(ab, "peer not found %pM\n", + arg.mac_addr); ++ spin_unlock_bh(&ab->base_lock); + goto exit; + } + +- ar = ath11k_mac_get_ar_by_vdev_id(ab, peer->vdev_id); ++ vdev_id = peer->vdev_id; ++ ++ spin_unlock_bh(&ab->base_lock); ++ ++ ar = ath11k_mac_get_ar_by_vdev_id(ab, vdev_id); + if (!ar) { + ath11k_warn(ab, "invalid vdev id in peer sta kickout ev %d", + peer->vdev_id); +@@ -6438,7 +6444,6 @@ static void ath11k_peer_sta_kickout_even + ieee80211_report_low_ack(sta, 10); + + exit: +- spin_unlock_bh(&ab->base_lock); + rcu_read_unlock(); + } + diff --git a/package/kernel/mac80211/patches/ath11k/0071-ath11k-fix-DMA-memory-free-in-CE-pipe-cleanup.patch b/package/kernel/mac80211/patches/ath11k/0071-ath11k-fix-DMA-memory-free-in-CE-pipe-cleanup.patch new file mode 100644 index 000000000..6935ca196 --- /dev/null +++ b/package/kernel/mac80211/patches/ath11k/0071-ath11k-fix-DMA-memory-free-in-CE-pipe-cleanup.patch @@ -0,0 +1,74 @@ +From 31aeaf547d7e3b64ba5d5442dabc530bdb9e216e Mon Sep 17 00:00:00 2001 +From: Karthikeyan Periyasamy +Date: Wed, 10 Nov 2021 21:51:30 +0530 +Subject: [PATCH 071/120] ath11k: fix DMA memory free in CE pipe cleanup + +In CE pipe cleanup, DMA memory gets freed by the aligned address +(base_addr_owner_space) which is wrong. It needs to be freed +by the address (base_addr_owner_space_unaligned) returned by +dma_alloc. So free the dma memory by the proper address. +This was found in code review. + +Tested-on: IPQ8074 hw2.0 AHB WLAN.HK.2.5.0.1-00729-QCAHKSWPL_SILICONZ-3 v2 + +Signed-off-by: Karthikeyan Periyasamy +Signed-off-by: Kalle Valo +Link: https://lore.kernel.org/r/1636561290-18966-1-git-send-email-quic_periyasa@quicinc.com +--- + drivers/net/wireless/ath/ath11k/ce.c | 16 ++++++++++------ + 1 file changed, 10 insertions(+), 6 deletions(-) + +--- a/drivers/net/wireless/ath/ath11k/ce.c ++++ b/drivers/net/wireless/ath/ath11k/ce.c +@@ -953,6 +953,7 @@ int ath11k_ce_init_pipes(struct ath11k_b + void ath11k_ce_free_pipes(struct ath11k_base *ab) + { + struct ath11k_ce_pipe *pipe; ++ struct ath11k_ce_ring *ce_ring; + int desc_sz; + int i; + +@@ -964,22 +965,24 @@ void ath11k_ce_free_pipes(struct ath11k_ + + if (pipe->src_ring) { + desc_sz = ath11k_hal_ce_get_desc_size(HAL_CE_DESC_SRC); ++ ce_ring = pipe->src_ring; + dma_free_coherent(ab->dev, + pipe->src_ring->nentries * desc_sz + + CE_DESC_RING_ALIGN, +- pipe->src_ring->base_addr_owner_space, +- pipe->src_ring->base_addr_ce_space); ++ ce_ring->base_addr_owner_space_unaligned, ++ ce_ring->base_addr_ce_space_unaligned); + kfree(pipe->src_ring); + pipe->src_ring = NULL; + } + + if (pipe->dest_ring) { + desc_sz = ath11k_hal_ce_get_desc_size(HAL_CE_DESC_DST); ++ ce_ring = pipe->dest_ring; + dma_free_coherent(ab->dev, + pipe->dest_ring->nentries * desc_sz + + CE_DESC_RING_ALIGN, +- pipe->dest_ring->base_addr_owner_space, +- pipe->dest_ring->base_addr_ce_space); ++ ce_ring->base_addr_owner_space_unaligned, ++ ce_ring->base_addr_ce_space_unaligned); + kfree(pipe->dest_ring); + pipe->dest_ring = NULL; + } +@@ -987,11 +990,12 @@ void ath11k_ce_free_pipes(struct ath11k_ + if (pipe->status_ring) { + desc_sz = + ath11k_hal_ce_get_desc_size(HAL_CE_DESC_DST_STATUS); ++ ce_ring = pipe->status_ring; + dma_free_coherent(ab->dev, + pipe->status_ring->nentries * desc_sz + + CE_DESC_RING_ALIGN, +- pipe->status_ring->base_addr_owner_space, +- pipe->status_ring->base_addr_ce_space); ++ ce_ring->base_addr_owner_space_unaligned, ++ ce_ring->base_addr_ce_space_unaligned); + kfree(pipe->status_ring); + pipe->status_ring = NULL; + } diff --git a/package/kernel/mac80211/patches/ath11k/0072-ath11k-Fix-unused-but-set-parameter-error.patch b/package/kernel/mac80211/patches/ath11k/0072-ath11k-Fix-unused-but-set-parameter-error.patch new file mode 100644 index 000000000..64718079d --- /dev/null +++ b/package/kernel/mac80211/patches/ath11k/0072-ath11k-Fix-unused-but-set-parameter-error.patch @@ -0,0 +1,30 @@ +From 624e0a3170309eeb5b729f7a43c1ba3234325f02 Mon Sep 17 00:00:00 2001 +From: Seevalamuthu Mariappan +Date: Thu, 11 Nov 2021 11:22:47 +0530 +Subject: [PATCH 072/120] ath11k: Fix 'unused-but-set-parameter' error + +Below compilation error is reported when built with W=1, + +drivers/net/wireless/ath/ath11k/mac.c:5408:22: error: parameter 'changed_flags' set but not used [-Werror,-Wunused-but-set-parameter] + +changed_flags is set, but left unused. So, remove unnecessary set. +Compile tested only. + +Reported-by: kernel test robot +Signed-off-by: Seevalamuthu Mariappan +Signed-off-by: Kalle Valo +Link: https://lore.kernel.org/r/1636609967-5114-1-git-send-email-quic_seevalam@quicinc.com +--- + drivers/net/wireless/ath/ath11k/mac.c | 1 - + 1 file changed, 1 deletion(-) + +--- a/drivers/net/wireless/ath/ath11k/mac.c ++++ b/drivers/net/wireless/ath/ath11k/mac.c +@@ -5961,7 +5961,6 @@ static void ath11k_mac_op_configure_filt + + mutex_lock(&ar->conf_mutex); + +- changed_flags &= SUPPORTED_FILTERS; + *total_flags &= SUPPORTED_FILTERS; + ar->filter_flags = *total_flags; + diff --git a/package/kernel/mac80211/patches/ath11k/0073-ath11k-fix-firmware-crash-during-channel-switch.patch b/package/kernel/mac80211/patches/ath11k/0073-ath11k-fix-firmware-crash-during-channel-switch.patch new file mode 100644 index 000000000..3a13edf46 --- /dev/null +++ b/package/kernel/mac80211/patches/ath11k/0073-ath11k-fix-firmware-crash-during-channel-switch.patch @@ -0,0 +1,65 @@ +From f187fe8e3bc65cc4d7b0916947e2d6cd65d9cd3a Mon Sep 17 00:00:00 2001 +From: Venkateswara Naralasetty +Date: Thu, 11 Nov 2021 20:50:02 +0530 +Subject: [PATCH 073/120] ath11k: fix firmware crash during channel switch + +Currently the updated bandwidth for the peer will be configured +to the firmware after channel switch from the sta_rc_update_wk. +If the updated bandwidth is greater than the configured peer phymode +during the peer assoc may result firmware assert. + +For example, initially AP is in HE40 mode and the peer phymode is +configured as MODE_11AX_HE40 during peer assoc. Now user change the +channel width to HE80 then, the peer bandwidth will be updated as +HE80 to the firmware. + +This will trigger firmware assert due to peer bandwidth is greater than +the peer phymode. + +Fix this issue by sending peer assoc command before setting the updated +peer bandwith to firmware. + +Tested-on: QCN9074 hw1.0 PCI WLAN.HK.2.5.0.1-01100-QCAHKSWPL_SILICONZ-1 + +Signed-off-by: Venkateswara Naralasetty +Signed-off-by: Kalle Valo +Link: https://lore.kernel.org/r/1636644002-25446-1-git-send-email-quic_vnaralas@quicinc.com +--- + drivers/net/wireless/ath/ath11k/mac.c | 26 +++++++++++++++++++++----- + 1 file changed, 21 insertions(+), 5 deletions(-) + +--- a/drivers/net/wireless/ath/ath11k/mac.c ++++ b/drivers/net/wireless/ath/ath11k/mac.c +@@ -3924,11 +3924,27 @@ static void ath11k_sta_rc_update_wk(stru + ath11k_mac_max_he_nss(he_mcs_mask))); + + if (changed & IEEE80211_RC_BW_CHANGED) { +- err = ath11k_wmi_set_peer_param(ar, sta->addr, arvif->vdev_id, +- WMI_PEER_CHWIDTH, bw); +- if (err) +- ath11k_warn(ar->ab, "failed to update STA %pM peer bw %d: %d\n", +- sta->addr, bw, err); ++ /* Send peer assoc command before set peer bandwidth param to ++ * avoid the mismatch between the peer phymode and the peer ++ * bandwidth. ++ */ ++ ath11k_peer_assoc_prepare(ar, arvif->vif, sta, &peer_arg, true); ++ ++ peer_arg.is_assoc = false; ++ err = ath11k_wmi_send_peer_assoc_cmd(ar, &peer_arg); ++ if (err) { ++ ath11k_warn(ar->ab, "failed to send peer assoc for STA %pM vdev %i: %d\n", ++ sta->addr, arvif->vdev_id, err); ++ } else if (wait_for_completion_timeout(&ar->peer_assoc_done, 1 * HZ)) { ++ err = ath11k_wmi_set_peer_param(ar, sta->addr, arvif->vdev_id, ++ WMI_PEER_CHWIDTH, bw); ++ if (err) ++ ath11k_warn(ar->ab, "failed to update STA %pM peer bw %d: %d\n", ++ sta->addr, bw, err); ++ } else { ++ ath11k_warn(ar->ab, "failed to get peer assoc conf event for %pM vdev %i\n", ++ sta->addr, arvif->vdev_id); ++ } + } + + if (changed & IEEE80211_RC_NSS_CHANGED) { diff --git a/package/kernel/mac80211/patches/ath11k/0074-ath11k-disable-unused-CE8-interrupts-for-ipq8074.patch b/package/kernel/mac80211/patches/ath11k/0074-ath11k-disable-unused-CE8-interrupts-for-ipq8074.patch new file mode 100644 index 000000000..95de36d6a --- /dev/null +++ b/package/kernel/mac80211/patches/ath11k/0074-ath11k-disable-unused-CE8-interrupts-for-ipq8074.patch @@ -0,0 +1,38 @@ +From 2c5545bfa29dd5305fa770959890a23ea39b5e69 Mon Sep 17 00:00:00 2001 +From: P Praneesh +Date: Fri, 12 Nov 2021 11:01:18 +0200 +Subject: [PATCH 074/120] ath11k: disable unused CE8 interrupts for ipq8074 + +Host driver doesn't need to process CE8 interrupts (used +by target independently) + +The volume of interrupts is huge within short interval, + CPU0 CPU1 CPU2 CPU3 +14022188 0 0 0 GIC 71 Edge ce8 + +Hence disabling unused CE8 interrupt will improve CPU usage. + +Tested-on: QCN9074 hw1.0 PCI WLAN.HK.2.4.0.1.r2-00012-QCAHKSWPL_SILICONZ-1 +Tested-on: IPQ8074 hw2.0 AHB WLAN.HK.2.4.0.1-01695-QCAHKSWPL_SILICONZ-1 + +Co-developed-by: Sriram R +Signed-off-by: Sriram R +Signed-off-by: Jouni Malinen +Signed-off-by: P Praneesh +Signed-off-by: Kalle Valo +Link: https://lore.kernel.org/r/1630560820-21905-2-git-send-email-ppranees@codeaurora.org +--- + drivers/net/wireless/ath/ath11k/ce.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +--- a/drivers/net/wireless/ath/ath11k/ce.c ++++ b/drivers/net/wireless/ath/ath11k/ce.c +@@ -77,7 +77,7 @@ const struct ce_attr ath11k_host_ce_conf + + /* CE8: target autonomous hif_memcpy */ + { +- .flags = CE_ATTR_FLAGS, ++ .flags = CE_ATTR_FLAGS | CE_ATTR_DIS_INTR, + .src_nentries = 0, + .src_sz_max = 0, + .dest_nentries = 0, diff --git a/package/kernel/mac80211/patches/ath11k/0075-ath11k-allocate-dst-ring-descriptors-from-cacheable-.patch b/package/kernel/mac80211/patches/ath11k/0075-ath11k-allocate-dst-ring-descriptors-from-cacheable-.patch new file mode 100644 index 000000000..fa6c6a28e --- /dev/null +++ b/package/kernel/mac80211/patches/ath11k/0075-ath11k-allocate-dst-ring-descriptors-from-cacheable-.patch @@ -0,0 +1,228 @@ +From 6452f0a3d5651bb7edfd9c709e78973aaa4d3bfc Mon Sep 17 00:00:00 2001 +From: P Praneesh +Date: Fri, 12 Nov 2021 11:01:26 +0200 +Subject: [PATCH 075/120] ath11k: allocate dst ring descriptors from cacheable + memory + +tcl_data and reo_dst rings are currently being allocated using +dma_allocate_coherent() which is non cacheable. + +Allocating ring memory from cacheable memory area allows cached descriptor +access and prefetch next descriptors to optimize CPU usage during +descriptor processing on NAPI. Based on the hardware param we can enable +or disable this feature for the corresponding platform. + +Tested-on: QCN9074 hw1.0 PCI WLAN.HK.2.4.0.1.r2-00012-QCAHKSWPL_SILICONZ-1 +Tested-on: IPQ8074 hw2.0 AHB WLAN.HK.2.4.0.1-01695-QCAHKSWPL_SILICONZ-1 + +Co-developed-by: Pradeep Kumar Chitrapu +Signed-off-by: Pradeep Kumar Chitrapu +Co-developed-by: Sriram R +Signed-off-by: Sriram R +Signed-off-by: Jouni Malinen +Signed-off-by: P Praneesh +Signed-off-by: Kalle Valo +Link: https://lore.kernel.org/r/1630560820-21905-3-git-send-email-ppranees@codeaurora.org +--- + drivers/net/wireless/ath/ath11k/core.c | 5 ++++ + drivers/net/wireless/ath/ath11k/dp.c | 38 ++++++++++++++++++++++---- + drivers/net/wireless/ath/ath11k/dp.h | 1 + + drivers/net/wireless/ath/ath11k/hal.c | 28 +++++++++++++++++-- + drivers/net/wireless/ath/ath11k/hal.h | 1 + + drivers/net/wireless/ath/ath11k/hw.h | 1 + + 6 files changed, 67 insertions(+), 7 deletions(-) + +--- a/drivers/net/wireless/ath/ath11k/core.c ++++ b/drivers/net/wireless/ath/ath11k/core.c +@@ -84,6 +84,7 @@ static const struct ath11k_hw_params ath + .max_tx_ring = DP_TCL_NUM_RING_MAX, + .hal_params = &ath11k_hw_hal_params_ipq8074, + .supports_dynamic_smps_6ghz = false, ++ .alloc_cacheable_memory = true, + }, + { + .hw_rev = ATH11K_HW_IPQ6018_HW10, +@@ -135,6 +136,7 @@ static const struct ath11k_hw_params ath + .max_tx_ring = DP_TCL_NUM_RING_MAX, + .hal_params = &ath11k_hw_hal_params_ipq8074, + .supports_dynamic_smps_6ghz = false, ++ .alloc_cacheable_memory = true, + }, + { + .name = "qca6390 hw2.0", +@@ -185,6 +187,7 @@ static const struct ath11k_hw_params ath + .max_tx_ring = DP_TCL_NUM_RING_MAX_QCA6390, + .hal_params = &ath11k_hw_hal_params_qca6390, + .supports_dynamic_smps_6ghz = false, ++ .alloc_cacheable_memory = false, + }, + { + .name = "qcn9074 hw1.0", +@@ -235,6 +238,7 @@ static const struct ath11k_hw_params ath + .max_tx_ring = DP_TCL_NUM_RING_MAX, + .hal_params = &ath11k_hw_hal_params_ipq8074, + .supports_dynamic_smps_6ghz = true, ++ .alloc_cacheable_memory = true, + }, + { + .name = "wcn6855 hw2.0", +@@ -285,6 +289,7 @@ static const struct ath11k_hw_params ath + .max_tx_ring = DP_TCL_NUM_RING_MAX_QCA6390, + .hal_params = &ath11k_hw_hal_params_qca6390, + .supports_dynamic_smps_6ghz = false, ++ .alloc_cacheable_memory = false, + }, + }; + +--- a/drivers/net/wireless/ath/ath11k/dp.c ++++ b/drivers/net/wireless/ath/ath11k/dp.c +@@ -101,8 +101,11 @@ void ath11k_dp_srng_cleanup(struct ath11 + if (!ring->vaddr_unaligned) + return; + +- dma_free_coherent(ab->dev, ring->size, ring->vaddr_unaligned, +- ring->paddr_unaligned); ++ if (ring->cached) ++ kfree(ring->vaddr_unaligned); ++ else ++ dma_free_coherent(ab->dev, ring->size, ring->vaddr_unaligned, ++ ring->paddr_unaligned); + + ring->vaddr_unaligned = NULL; + } +@@ -222,6 +225,7 @@ int ath11k_dp_srng_setup(struct ath11k_b + int entry_sz = ath11k_hal_srng_get_entrysize(ab, type); + int max_entries = ath11k_hal_srng_get_max_entries(ab, type); + int ret; ++ bool cached = false; + + if (max_entries < 0 || entry_sz < 0) + return -EINVAL; +@@ -230,9 +234,28 @@ int ath11k_dp_srng_setup(struct ath11k_b + num_entries = max_entries; + + ring->size = (num_entries * entry_sz) + HAL_RING_BASE_ALIGN - 1; +- ring->vaddr_unaligned = dma_alloc_coherent(ab->dev, ring->size, +- &ring->paddr_unaligned, +- GFP_KERNEL); ++ ++ if (ab->hw_params.alloc_cacheable_memory) { ++ /* Allocate the reo dst and tx completion rings from cacheable memory */ ++ switch (type) { ++ case HAL_REO_DST: ++ cached = true; ++ break; ++ default: ++ cached = false; ++ } ++ ++ if (cached) { ++ ring->vaddr_unaligned = kzalloc(ring->size, GFP_KERNEL); ++ ring->paddr_unaligned = virt_to_phys(ring->vaddr_unaligned); ++ } ++ } ++ ++ if (!cached) ++ ring->vaddr_unaligned = dma_alloc_coherent(ab->dev, ring->size, ++ &ring->paddr_unaligned, ++ GFP_KERNEL); ++ + if (!ring->vaddr_unaligned) + return -ENOMEM; + +@@ -292,6 +315,11 @@ int ath11k_dp_srng_setup(struct ath11k_b + return -EINVAL; + } + ++ if (cached) { ++ params.flags |= HAL_SRNG_FLAGS_CACHED; ++ ring->cached = 1; ++ } ++ + ret = ath11k_hal_srng_setup(ab, type, ring_num, mac_id, ¶ms); + if (ret < 0) { + ath11k_warn(ab, "failed to setup srng: %d ring_id %d\n", +--- a/drivers/net/wireless/ath/ath11k/dp.h ++++ b/drivers/net/wireless/ath/ath11k/dp.h +@@ -64,6 +64,7 @@ struct dp_srng { + dma_addr_t paddr; + int size; + u32 ring_id; ++ u8 cached; + }; + + struct dp_rxdma_ring { +--- a/drivers/net/wireless/ath/ath11k/hal.c ++++ b/drivers/net/wireless/ath/ath11k/hal.c +@@ -627,6 +627,21 @@ u32 *ath11k_hal_srng_dst_peek(struct ath + return NULL; + } + ++static void ath11k_hal_srng_prefetch_desc(struct ath11k_base *ab, ++ struct hal_srng *srng) ++{ ++ u32 *desc; ++ ++ /* prefetch only if desc is available */ ++ desc = ath11k_hal_srng_dst_peek(ab, srng); ++ if (likely(desc)) { ++ dma_sync_single_for_cpu(ab->dev, virt_to_phys(desc), ++ (srng->entry_size * sizeof(u32)), ++ DMA_FROM_DEVICE); ++ prefetch(desc); ++ } ++} ++ + u32 *ath11k_hal_srng_dst_get_next_entry(struct ath11k_base *ab, + struct hal_srng *srng) + { +@@ -642,6 +657,10 @@ u32 *ath11k_hal_srng_dst_get_next_entry( + srng->u.dst_ring.tp = (srng->u.dst_ring.tp + srng->entry_size) % + srng->ring_size; + ++ /* Try to prefetch the next descriptor in the ring */ ++ if (srng->flags & HAL_SRNG_FLAGS_CACHED) ++ ath11k_hal_srng_prefetch_desc(ab, srng); ++ + return desc; + } + +@@ -775,11 +794,16 @@ void ath11k_hal_srng_access_begin(struct + { + lockdep_assert_held(&srng->lock); + +- if (srng->ring_dir == HAL_SRNG_DIR_SRC) ++ if (srng->ring_dir == HAL_SRNG_DIR_SRC) { + srng->u.src_ring.cached_tp = + *(volatile u32 *)srng->u.src_ring.tp_addr; +- else ++ } else { + srng->u.dst_ring.cached_hp = *srng->u.dst_ring.hp_addr; ++ ++ /* Try to prefetch the next descriptor in the ring */ ++ if (srng->flags & HAL_SRNG_FLAGS_CACHED) ++ ath11k_hal_srng_prefetch_desc(ab, srng); ++ } + } + + /* Update cached ring head/tail pointers to HW. ath11k_hal_srng_access_begin() +--- a/drivers/net/wireless/ath/ath11k/hal.h ++++ b/drivers/net/wireless/ath/ath11k/hal.h +@@ -513,6 +513,7 @@ enum hal_srng_dir { + #define HAL_SRNG_FLAGS_DATA_TLV_SWAP 0x00000020 + #define HAL_SRNG_FLAGS_LOW_THRESH_INTR_EN 0x00010000 + #define HAL_SRNG_FLAGS_MSI_INTR 0x00020000 ++#define HAL_SRNG_FLAGS_CACHED 0x20000000 + #define HAL_SRNG_FLAGS_LMAC_RING 0x80000000 + + #define HAL_SRNG_TLV_HDR_TAG GENMASK(9, 1) +--- a/drivers/net/wireless/ath/ath11k/hw.h ++++ b/drivers/net/wireless/ath/ath11k/hw.h +@@ -178,6 +178,7 @@ struct ath11k_hw_params { + u8 max_tx_ring; + const struct ath11k_hw_hal_params *hal_params; + bool supports_dynamic_smps_6ghz; ++ bool alloc_cacheable_memory; + }; + + struct ath11k_hw_ops { diff --git a/package/kernel/mac80211/patches/ath11k/0076-ath11k-modify-dp_rx-desc-access-wrapper-calls-inline.patch b/package/kernel/mac80211/patches/ath11k/0076-ath11k-modify-dp_rx-desc-access-wrapper-calls-inline.patch new file mode 100644 index 000000000..cacf6c6a1 --- /dev/null +++ b/package/kernel/mac80211/patches/ath11k/0076-ath11k-modify-dp_rx-desc-access-wrapper-calls-inline.patch @@ -0,0 +1,285 @@ +From 5e76fe03dbf9f9dbc4fd454283b02594226c0718 Mon Sep 17 00:00:00 2001 +From: P Praneesh +Date: Fri, 12 Nov 2021 11:02:03 +0200 +Subject: [PATCH 076/120] ath11k: modify dp_rx desc access wrapper calls inline + +In data path, to reduce the CPU cycles spending on descriptor access +wrapper function, changed those functions as static inline. + +Tested-on: QCN9074 hw1.0 PCI WLAN.HK.2.4.0.1.r2-00012-QCAHKSWPL_SILICONZ-1 +Tested-on: IPQ8074 hw2.0 AHB WLAN.HK.2.4.0.1-01695-QCAHKSWPL_SILICONZ-1 + +Co-developed-by: Sriram R +Signed-off-by: Sriram R +Signed-off-by: Jouni Malinen +Signed-off-by: P Praneesh +Signed-off-by: Kalle Valo +Link: https://lore.kernel.org/r/1630560820-21905-4-git-send-email-ppranees@codeaurora.org +--- + drivers/net/wireless/ath/ath11k/dp_rx.c | 114 ++++++++++++------------ + 1 file changed, 59 insertions(+), 55 deletions(-) + +--- a/drivers/net/wireless/ath/ath11k/dp_rx.c ++++ b/drivers/net/wireless/ath/ath11k/dp_rx.c +@@ -20,13 +20,15 @@ + + #define ATH11K_DP_RX_FRAGMENT_TIMEOUT_MS (2 * HZ) + +-static u8 *ath11k_dp_rx_h_80211_hdr(struct ath11k_base *ab, struct hal_rx_desc *desc) ++static inline ++u8 *ath11k_dp_rx_h_80211_hdr(struct ath11k_base *ab, struct hal_rx_desc *desc) + { + return ab->hw_params.hw_ops->rx_desc_get_hdr_status(desc); + } + +-static enum hal_encrypt_type ath11k_dp_rx_h_mpdu_start_enctype(struct ath11k_base *ab, +- struct hal_rx_desc *desc) ++static inline ++enum hal_encrypt_type ath11k_dp_rx_h_mpdu_start_enctype(struct ath11k_base *ab, ++ struct hal_rx_desc *desc) + { + if (!ab->hw_params.hw_ops->rx_desc_encrypt_valid(desc)) + return HAL_ENCRYPT_TYPE_OPEN; +@@ -34,32 +36,34 @@ static enum hal_encrypt_type ath11k_dp_r + return ab->hw_params.hw_ops->rx_desc_get_encrypt_type(desc); + } + +-static u8 ath11k_dp_rx_h_msdu_start_decap_type(struct ath11k_base *ab, +- struct hal_rx_desc *desc) ++static inline u8 ath11k_dp_rx_h_msdu_start_decap_type(struct ath11k_base *ab, ++ struct hal_rx_desc *desc) + { + return ab->hw_params.hw_ops->rx_desc_get_decap_type(desc); + } + +-static u8 ath11k_dp_rx_h_msdu_start_mesh_ctl_present(struct ath11k_base *ab, +- struct hal_rx_desc *desc) ++static inline ++u8 ath11k_dp_rx_h_msdu_start_mesh_ctl_present(struct ath11k_base *ab, ++ struct hal_rx_desc *desc) + { + return ab->hw_params.hw_ops->rx_desc_get_mesh_ctl(desc); + } + +-static bool ath11k_dp_rx_h_mpdu_start_seq_ctrl_valid(struct ath11k_base *ab, +- struct hal_rx_desc *desc) ++static inline ++bool ath11k_dp_rx_h_mpdu_start_seq_ctrl_valid(struct ath11k_base *ab, ++ struct hal_rx_desc *desc) + { + return ab->hw_params.hw_ops->rx_desc_get_mpdu_seq_ctl_vld(desc); + } + +-static bool ath11k_dp_rx_h_mpdu_start_fc_valid(struct ath11k_base *ab, +- struct hal_rx_desc *desc) ++static inline bool ath11k_dp_rx_h_mpdu_start_fc_valid(struct ath11k_base *ab, ++ struct hal_rx_desc *desc) + { + return ab->hw_params.hw_ops->rx_desc_get_mpdu_fc_valid(desc); + } + +-static bool ath11k_dp_rx_h_mpdu_start_more_frags(struct ath11k_base *ab, +- struct sk_buff *skb) ++static inline bool ath11k_dp_rx_h_mpdu_start_more_frags(struct ath11k_base *ab, ++ struct sk_buff *skb) + { + struct ieee80211_hdr *hdr; + +@@ -67,8 +71,8 @@ static bool ath11k_dp_rx_h_mpdu_start_mo + return ieee80211_has_morefrags(hdr->frame_control); + } + +-static u16 ath11k_dp_rx_h_mpdu_start_frag_no(struct ath11k_base *ab, +- struct sk_buff *skb) ++static inline u16 ath11k_dp_rx_h_mpdu_start_frag_no(struct ath11k_base *ab, ++ struct sk_buff *skb) + { + struct ieee80211_hdr *hdr; + +@@ -76,37 +80,37 @@ static u16 ath11k_dp_rx_h_mpdu_start_fra + return le16_to_cpu(hdr->seq_ctrl) & IEEE80211_SCTL_FRAG; + } + +-static u16 ath11k_dp_rx_h_mpdu_start_seq_no(struct ath11k_base *ab, +- struct hal_rx_desc *desc) ++static inline u16 ath11k_dp_rx_h_mpdu_start_seq_no(struct ath11k_base *ab, ++ struct hal_rx_desc *desc) + { + return ab->hw_params.hw_ops->rx_desc_get_mpdu_start_seq_no(desc); + } + +-static void *ath11k_dp_rx_get_attention(struct ath11k_base *ab, +- struct hal_rx_desc *desc) ++static inline void *ath11k_dp_rx_get_attention(struct ath11k_base *ab, ++ struct hal_rx_desc *desc) + { + return ab->hw_params.hw_ops->rx_desc_get_attention(desc); + } + +-static bool ath11k_dp_rx_h_attn_msdu_done(struct rx_attention *attn) ++static inline bool ath11k_dp_rx_h_attn_msdu_done(struct rx_attention *attn) + { + return !!FIELD_GET(RX_ATTENTION_INFO2_MSDU_DONE, + __le32_to_cpu(attn->info2)); + } + +-static bool ath11k_dp_rx_h_attn_l4_cksum_fail(struct rx_attention *attn) ++static inline bool ath11k_dp_rx_h_attn_l4_cksum_fail(struct rx_attention *attn) + { + return !!FIELD_GET(RX_ATTENTION_INFO1_TCP_UDP_CKSUM_FAIL, + __le32_to_cpu(attn->info1)); + } + +-static bool ath11k_dp_rx_h_attn_ip_cksum_fail(struct rx_attention *attn) ++static inline bool ath11k_dp_rx_h_attn_ip_cksum_fail(struct rx_attention *attn) + { + return !!FIELD_GET(RX_ATTENTION_INFO1_IP_CKSUM_FAIL, + __le32_to_cpu(attn->info1)); + } + +-static bool ath11k_dp_rx_h_attn_is_decrypted(struct rx_attention *attn) ++static inline bool ath11k_dp_rx_h_attn_is_decrypted(struct rx_attention *attn) + { + return (FIELD_GET(RX_ATTENTION_INFO2_DCRYPT_STATUS_CODE, + __le32_to_cpu(attn->info2)) == +@@ -154,68 +158,68 @@ static bool ath11k_dp_rx_h_attn_msdu_len + return errmap & DP_RX_MPDU_ERR_MSDU_LEN; + } + +-static u16 ath11k_dp_rx_h_msdu_start_msdu_len(struct ath11k_base *ab, +- struct hal_rx_desc *desc) ++static inline u16 ath11k_dp_rx_h_msdu_start_msdu_len(struct ath11k_base *ab, ++ struct hal_rx_desc *desc) + { + return ab->hw_params.hw_ops->rx_desc_get_msdu_len(desc); + } + +-static u8 ath11k_dp_rx_h_msdu_start_sgi(struct ath11k_base *ab, +- struct hal_rx_desc *desc) ++static inline u8 ath11k_dp_rx_h_msdu_start_sgi(struct ath11k_base *ab, ++ struct hal_rx_desc *desc) + { + return ab->hw_params.hw_ops->rx_desc_get_msdu_sgi(desc); + } + +-static u8 ath11k_dp_rx_h_msdu_start_rate_mcs(struct ath11k_base *ab, +- struct hal_rx_desc *desc) ++static inline u8 ath11k_dp_rx_h_msdu_start_rate_mcs(struct ath11k_base *ab, ++ struct hal_rx_desc *desc) + { + return ab->hw_params.hw_ops->rx_desc_get_msdu_rate_mcs(desc); + } + +-static u8 ath11k_dp_rx_h_msdu_start_rx_bw(struct ath11k_base *ab, +- struct hal_rx_desc *desc) ++static inline u8 ath11k_dp_rx_h_msdu_start_rx_bw(struct ath11k_base *ab, ++ struct hal_rx_desc *desc) + { + return ab->hw_params.hw_ops->rx_desc_get_msdu_rx_bw(desc); + } + +-static u32 ath11k_dp_rx_h_msdu_start_freq(struct ath11k_base *ab, +- struct hal_rx_desc *desc) ++static inline u32 ath11k_dp_rx_h_msdu_start_freq(struct ath11k_base *ab, ++ struct hal_rx_desc *desc) + { + return ab->hw_params.hw_ops->rx_desc_get_msdu_freq(desc); + } + +-static u8 ath11k_dp_rx_h_msdu_start_pkt_type(struct ath11k_base *ab, +- struct hal_rx_desc *desc) ++static inline u8 ath11k_dp_rx_h_msdu_start_pkt_type(struct ath11k_base *ab, ++ struct hal_rx_desc *desc) + { + return ab->hw_params.hw_ops->rx_desc_get_msdu_pkt_type(desc); + } + +-static u8 ath11k_dp_rx_h_msdu_start_nss(struct ath11k_base *ab, +- struct hal_rx_desc *desc) ++static inline u8 ath11k_dp_rx_h_msdu_start_nss(struct ath11k_base *ab, ++ struct hal_rx_desc *desc) + { + return hweight8(ab->hw_params.hw_ops->rx_desc_get_msdu_nss(desc)); + } + +-static u8 ath11k_dp_rx_h_mpdu_start_tid(struct ath11k_base *ab, +- struct hal_rx_desc *desc) ++static inline u8 ath11k_dp_rx_h_mpdu_start_tid(struct ath11k_base *ab, ++ struct hal_rx_desc *desc) + { + return ab->hw_params.hw_ops->rx_desc_get_mpdu_tid(desc); + } + +-static u16 ath11k_dp_rx_h_mpdu_start_peer_id(struct ath11k_base *ab, +- struct hal_rx_desc *desc) ++static inline u16 ath11k_dp_rx_h_mpdu_start_peer_id(struct ath11k_base *ab, ++ struct hal_rx_desc *desc) + { + return ab->hw_params.hw_ops->rx_desc_get_mpdu_peer_id(desc); + } + +-static u8 ath11k_dp_rx_h_msdu_end_l3pad(struct ath11k_base *ab, +- struct hal_rx_desc *desc) ++static inline u8 ath11k_dp_rx_h_msdu_end_l3pad(struct ath11k_base *ab, ++ struct hal_rx_desc *desc) + { + return ab->hw_params.hw_ops->rx_desc_get_l3_pad_bytes(desc); + } + +-static bool ath11k_dp_rx_h_msdu_end_first_msdu(struct ath11k_base *ab, +- struct hal_rx_desc *desc) ++static inline bool ath11k_dp_rx_h_msdu_end_first_msdu(struct ath11k_base *ab, ++ struct hal_rx_desc *desc) + { + return ab->hw_params.hw_ops->rx_desc_get_first_msdu(desc); + } +@@ -233,14 +237,14 @@ static void ath11k_dp_rx_desc_end_tlv_co + ab->hw_params.hw_ops->rx_desc_copy_attn_end_tlv(fdesc, ldesc); + } + +-static u32 ath11k_dp_rxdesc_get_mpdulen_err(struct rx_attention *attn) ++static inline u32 ath11k_dp_rxdesc_get_mpdulen_err(struct rx_attention *attn) + { + return FIELD_GET(RX_ATTENTION_INFO1_MPDU_LEN_ERR, + __le32_to_cpu(attn->info1)); + } + +-static u8 *ath11k_dp_rxdesc_get_80211hdr(struct ath11k_base *ab, +- struct hal_rx_desc *rx_desc) ++static inline u8 *ath11k_dp_rxdesc_get_80211hdr(struct ath11k_base *ab, ++ struct hal_rx_desc *rx_desc) + { + u8 *rx_pkt_hdr; + +@@ -249,8 +253,8 @@ static u8 *ath11k_dp_rxdesc_get_80211hdr + return rx_pkt_hdr; + } + +-static bool ath11k_dp_rxdesc_mpdu_valid(struct ath11k_base *ab, +- struct hal_rx_desc *rx_desc) ++static inline bool ath11k_dp_rxdesc_mpdu_valid(struct ath11k_base *ab, ++ struct hal_rx_desc *rx_desc) + { + u32 tlv_tag; + +@@ -259,15 +263,15 @@ static bool ath11k_dp_rxdesc_mpdu_valid( + return tlv_tag == HAL_RX_MPDU_START; + } + +-static u32 ath11k_dp_rxdesc_get_ppduid(struct ath11k_base *ab, +- struct hal_rx_desc *rx_desc) ++static inline u32 ath11k_dp_rxdesc_get_ppduid(struct ath11k_base *ab, ++ struct hal_rx_desc *rx_desc) + { + return ab->hw_params.hw_ops->rx_desc_get_mpdu_ppdu_id(rx_desc); + } + +-static void ath11k_dp_rxdesc_set_msdu_len(struct ath11k_base *ab, +- struct hal_rx_desc *desc, +- u16 len) ++static inline void ath11k_dp_rxdesc_set_msdu_len(struct ath11k_base *ab, ++ struct hal_rx_desc *desc, ++ u16 len) + { + ab->hw_params.hw_ops->rx_desc_set_msdu_len(desc, len); + } diff --git a/package/kernel/mac80211/patches/ath11k/0077-ath11k-avoid-additional-access-to-ath11k_hal_srng_ds.patch b/package/kernel/mac80211/patches/ath11k/0077-ath11k-avoid-additional-access-to-ath11k_hal_srng_ds.patch new file mode 100644 index 000000000..78b3b67e6 --- /dev/null +++ b/package/kernel/mac80211/patches/ath11k/0077-ath11k-avoid-additional-access-to-ath11k_hal_srng_ds.patch @@ -0,0 +1,55 @@ +From a1775e732eb90486519de3813b83a11b7fcee2d0 Mon Sep 17 00:00:00 2001 +From: P Praneesh +Date: Fri, 12 Nov 2021 11:02:12 +0200 +Subject: [PATCH 077/120] ath11k: avoid additional access to + ath11k_hal_srng_dst_num_free + +In ath11k_dp_process_rx(), after processing rx_desc from +ath11k_hal_srng_dst_get_next_entry(), ath11k_hal_srng_dst_num_free() +is accessed everytime because of done flag is not set. + +To avoid this additional access to ath11k_hal_srng_dst_num_free(), +increment total_msdu_reaped only when continuation is not set and +update done flag correspondingly. + +Tested-on: QCN9074 hw1.0 PCI WLAN.HK.2.4.0.1.r2-00012-QCAHKSWPL_SILICONZ-1 +Tested-on: IPQ8074 hw2.0 AHB WLAN.HK.2.4.0.1-01695-QCAHKSWPL_SILICONZ-1 + +Co-developed-by: Sriram R +Signed-off-by: Sriram R +Signed-off-by: Jouni Malinen +Signed-off-by: P Praneesh +Signed-off-by: Kalle Valo +Link: https://lore.kernel.org/r/1630560820-21905-5-git-send-email-ppranees@codeaurora.org +--- + drivers/net/wireless/ath/ath11k/dp_rx.c | 10 +++++++--- + 1 file changed, 7 insertions(+), 3 deletions(-) + +--- a/drivers/net/wireless/ath/ath11k/dp_rx.c ++++ b/drivers/net/wireless/ath/ath11k/dp_rx.c +@@ -2701,7 +2701,6 @@ try_again: + DMA_FROM_DEVICE); + + num_buffs_reaped[mac_id]++; +- total_msdu_reaped++; + + push_reason = FIELD_GET(HAL_REO_DEST_RING_INFO0_PUSH_REASON, + desc.info0); +@@ -2728,10 +2727,15 @@ try_again: + rxcb->mac_id = mac_id; + __skb_queue_tail(&msdu_list, msdu); + +- if (total_msdu_reaped >= quota && !rxcb->is_continuation) { ++ if (rxcb->is_continuation) { ++ done = false; ++ } else { ++ total_msdu_reaped++; + done = true; +- break; + } ++ ++ if (total_msdu_reaped >= budget) ++ break; + } + + /* Hw might have updated the head pointer after we cached it. diff --git a/package/kernel/mac80211/patches/ath11k/0078-ath11k-avoid-active-pdev-check-for-each-msdu.patch b/package/kernel/mac80211/patches/ath11k/0078-ath11k-avoid-active-pdev-check-for-each-msdu.patch new file mode 100644 index 000000000..91755c095 --- /dev/null +++ b/package/kernel/mac80211/patches/ath11k/0078-ath11k-avoid-active-pdev-check-for-each-msdu.patch @@ -0,0 +1,174 @@ +From c4d12cb37ea2e6c2b70880350d7bf1bbbd825c6c Mon Sep 17 00:00:00 2001 +From: P Praneesh +Date: Fri, 12 Nov 2021 11:02:18 +0200 +Subject: [PATCH 078/120] ath11k: avoid active pdev check for each msdu + +The Active Pdev and CAC check are done for each msdu in +ath11k_dp_rx_process_received_packets which is a overhead. +To avoid this overhead, collect all msdus in a per mac msdu +list and pass to function. + +Tested-on: QCN9074 hw1.0 PCI WLAN.HK.2.4.0.1.r2-00012-QCAHKSWPL_SILICONZ-1 +Tested-on: IPQ8074 hw2.0 AHB WLAN.HK.2.4.0.1-01695-QCAHKSWPL_SILICONZ-1 + +Co-developed-by: Sriram R +Signed-off-by: Sriram R +Signed-off-by: Jouni Malinen +Signed-off-by: P Praneesh +Signed-off-by: Kalle Valo +Link: https://lore.kernel.org/r/1630560820-21905-6-git-send-email-ppranees@codeaurora.org +--- + drivers/net/wireless/ath/ath11k/dp_rx.c | 70 ++++++++++++------------- + 1 file changed, 34 insertions(+), 36 deletions(-) + +--- a/drivers/net/wireless/ath/ath11k/dp_rx.c ++++ b/drivers/net/wireless/ath/ath11k/dp_rx.c +@@ -2600,13 +2600,11 @@ free_out: + static void ath11k_dp_rx_process_received_packets(struct ath11k_base *ab, + struct napi_struct *napi, + struct sk_buff_head *msdu_list, +- int *quota, int ring_id) ++ int *quota, int mac_id) + { +- struct ath11k_skb_rxcb *rxcb; + struct sk_buff *msdu; + struct ath11k *ar; + struct ieee80211_rx_status rx_status = {0}; +- u8 mac_id; + int ret; + + if (skb_queue_empty(msdu_list)) +@@ -2614,20 +2612,20 @@ static void ath11k_dp_rx_process_receive + + rcu_read_lock(); + +- while (*quota && (msdu = __skb_dequeue(msdu_list))) { +- rxcb = ATH11K_SKB_RXCB(msdu); +- mac_id = rxcb->mac_id; +- ar = ab->pdevs[mac_id].ar; +- if (!rcu_dereference(ab->pdevs_active[mac_id])) { +- dev_kfree_skb_any(msdu); +- continue; +- } ++ ar = ab->pdevs[mac_id].ar; ++ if (!rcu_dereference(ab->pdevs_active[mac_id])) { ++ __skb_queue_purge(msdu_list); ++ rcu_read_unlock(); ++ return; ++ } + +- if (test_bit(ATH11K_CAC_RUNNING, &ar->dev_flags)) { +- dev_kfree_skb_any(msdu); +- continue; +- } ++ if (test_bit(ATH11K_CAC_RUNNING, &ar->dev_flags)) { ++ __skb_queue_purge(msdu_list); ++ rcu_read_unlock(); ++ return; ++ } + ++ while ((msdu = __skb_dequeue(msdu_list))) { + ret = ath11k_dp_rx_process_msdu(ar, msdu, msdu_list, &rx_status); + if (ret) { + ath11k_dbg(ab, ATH11K_DBG_DATA, +@@ -2649,7 +2647,7 @@ int ath11k_dp_process_rx(struct ath11k_b + struct ath11k_dp *dp = &ab->dp; + struct dp_rxdma_ring *rx_ring; + int num_buffs_reaped[MAX_RADIOS] = {0}; +- struct sk_buff_head msdu_list; ++ struct sk_buff_head msdu_list[MAX_RADIOS]; + struct ath11k_skb_rxcb *rxcb; + int total_msdu_reaped = 0; + struct hal_srng *srng; +@@ -2658,10 +2656,13 @@ int ath11k_dp_process_rx(struct ath11k_b + bool done = false; + int buf_id, mac_id; + struct ath11k *ar; +- u32 *rx_desc; ++ struct hal_reo_dest_ring *desc; ++ enum hal_reo_dest_ring_push_reason push_reason; ++ u32 cookie; + int i; + +- __skb_queue_head_init(&msdu_list); ++ for (i = 0; i < MAX_RADIOS; i++) ++ __skb_queue_head_init(&msdu_list[i]); + + srng = &ab->hal.srng_list[dp->reo_dst_ring[ring_id].ring_id]; + +@@ -2670,13 +2671,11 @@ int ath11k_dp_process_rx(struct ath11k_b + ath11k_hal_srng_access_begin(ab, srng); + + try_again: +- while ((rx_desc = ath11k_hal_srng_dst_get_next_entry(ab, srng))) { +- struct hal_reo_dest_ring desc = *(struct hal_reo_dest_ring *)rx_desc; +- enum hal_reo_dest_ring_push_reason push_reason; +- u32 cookie; +- ++ while (likely(desc = ++ (struct hal_reo_dest_ring *)ath11k_hal_srng_dst_get_next_entry(ab, ++ srng))) { + cookie = FIELD_GET(BUFFER_ADDR_INFO1_SW_COOKIE, +- desc.buf_addr_info.info1); ++ desc->buf_addr_info.info1); + buf_id = FIELD_GET(DP_RXDMA_BUF_COOKIE_BUF_ID, + cookie); + mac_id = FIELD_GET(DP_RXDMA_BUF_COOKIE_PDEV_ID, cookie); +@@ -2703,7 +2702,7 @@ try_again: + num_buffs_reaped[mac_id]++; + + push_reason = FIELD_GET(HAL_REO_DEST_RING_INFO0_PUSH_REASON, +- desc.info0); ++ desc->info0); + if (push_reason != + HAL_REO_DEST_RING_PUSH_REASON_ROUTING_INSTRUCTION) { + dev_kfree_skb_any(msdu); +@@ -2711,21 +2710,21 @@ try_again: + continue; + } + +- rxcb->is_first_msdu = !!(desc.rx_msdu_info.info0 & ++ rxcb->is_first_msdu = !!(desc->rx_msdu_info.info0 & + RX_MSDU_DESC_INFO0_FIRST_MSDU_IN_MPDU); +- rxcb->is_last_msdu = !!(desc.rx_msdu_info.info0 & ++ rxcb->is_last_msdu = !!(desc->rx_msdu_info.info0 & + RX_MSDU_DESC_INFO0_LAST_MSDU_IN_MPDU); +- rxcb->is_continuation = !!(desc.rx_msdu_info.info0 & ++ rxcb->is_continuation = !!(desc->rx_msdu_info.info0 & + RX_MSDU_DESC_INFO0_MSDU_CONTINUATION); + rxcb->peer_id = FIELD_GET(RX_MPDU_DESC_META_DATA_PEER_ID, +- desc.rx_mpdu_info.meta_data); ++ desc->rx_mpdu_info.meta_data); + rxcb->seq_no = FIELD_GET(RX_MPDU_DESC_INFO0_SEQ_NUM, +- desc.rx_mpdu_info.info0); ++ desc->rx_mpdu_info.info0); + rxcb->tid = FIELD_GET(HAL_REO_DEST_RING_INFO0_RX_QUEUE_NUM, +- desc.info0); ++ desc->info0); + + rxcb->mac_id = mac_id; +- __skb_queue_tail(&msdu_list, msdu); ++ __skb_queue_tail(&msdu_list[mac_id], msdu); + + if (rxcb->is_continuation) { + done = false; +@@ -2760,16 +2759,15 @@ try_again: + if (!num_buffs_reaped[i]) + continue; + ++ ath11k_dp_rx_process_received_packets(ab, napi, &msdu_list[i], ++ "a, i); ++ + ar = ab->pdevs[i].ar; + rx_ring = &ar->dp.rx_refill_buf_ring; + + ath11k_dp_rxbufs_replenish(ab, i, rx_ring, num_buffs_reaped[i], + ab->hw_params.hal_params->rx_buf_rbm); + } +- +- ath11k_dp_rx_process_received_packets(ab, napi, &msdu_list, +- "a, ring_id); +- + exit: + return budget - quota; + } diff --git a/package/kernel/mac80211/patches/ath11k/0079-ath11k-remove-usage-quota-while-processing-rx-packet.patch b/package/kernel/mac80211/patches/ath11k/0079-ath11k-remove-usage-quota-while-processing-rx-packet.patch new file mode 100644 index 000000000..d03576068 --- /dev/null +++ b/package/kernel/mac80211/patches/ath11k/0079-ath11k-remove-usage-quota-while-processing-rx-packet.patch @@ -0,0 +1,70 @@ +From db2ecf9f0567a8f1a96f23a392cc5a30eaec4369 Mon Sep 17 00:00:00 2001 +From: P Praneesh +Date: Fri, 12 Nov 2021 11:02:24 +0200 +Subject: [PATCH 079/120] ath11k: remove usage quota while processing rx + packets + +The usage of quota variable inside ath11k_dp_rx_process_received_packets() +is redundant. Since we would queue only max packets to the list before +calling this function so it would never exceed quota. Hence removing +usage of quota variable. + +Tested-on: QCN9074 hw1.0 PCI WLAN.HK.2.4.0.1.r2-00012-QCAHKSWPL_SILICONZ-1 +Tested-on: IPQ8074 hw2.0 AHB WLAN.HK.2.4.0.1-01695-QCAHKSWPL_SILICONZ-1 + +Co-developed-by: Sriram R +Signed-off-by: Sriram R +Signed-off-by: Jouni Malinen +Signed-off-by: P Praneesh +Signed-off-by: Kalle Valo +Link: https://lore.kernel.org/r/1630560820-21905-7-git-send-email-ppranees@codeaurora.org +--- + drivers/net/wireless/ath/ath11k/dp_rx.c | 9 +++------ + 1 file changed, 3 insertions(+), 6 deletions(-) + +--- a/drivers/net/wireless/ath/ath11k/dp_rx.c ++++ b/drivers/net/wireless/ath/ath11k/dp_rx.c +@@ -2600,7 +2600,7 @@ free_out: + static void ath11k_dp_rx_process_received_packets(struct ath11k_base *ab, + struct napi_struct *napi, + struct sk_buff_head *msdu_list, +- int *quota, int mac_id) ++ int mac_id) + { + struct sk_buff *msdu; + struct ath11k *ar; +@@ -2635,7 +2635,6 @@ static void ath11k_dp_rx_process_receive + } + + ath11k_dp_rx_deliver_msdu(ar, napi, msdu, &rx_status); +- (*quota)--; + } + + rcu_read_unlock(); +@@ -2652,7 +2651,6 @@ int ath11k_dp_process_rx(struct ath11k_b + int total_msdu_reaped = 0; + struct hal_srng *srng; + struct sk_buff *msdu; +- int quota = budget; + bool done = false; + int buf_id, mac_id; + struct ath11k *ar; +@@ -2759,8 +2757,7 @@ try_again: + if (!num_buffs_reaped[i]) + continue; + +- ath11k_dp_rx_process_received_packets(ab, napi, &msdu_list[i], +- "a, i); ++ ath11k_dp_rx_process_received_packets(ab, napi, &msdu_list[i], i); + + ar = ab->pdevs[i].ar; + rx_ring = &ar->dp.rx_refill_buf_ring; +@@ -2769,7 +2766,7 @@ try_again: + ab->hw_params.hal_params->rx_buf_rbm); + } + exit: +- return budget - quota; ++ return total_msdu_reaped; + } + + static void ath11k_dp_rx_update_peer_stats(struct ath11k_sta *arsta, diff --git a/package/kernel/mac80211/patches/ath11k/0080-ath11k-add-branch-predictors-in-process_rx.patch b/package/kernel/mac80211/patches/ath11k/0080-ath11k-add-branch-predictors-in-process_rx.patch new file mode 100644 index 000000000..8c9721b8c --- /dev/null +++ b/package/kernel/mac80211/patches/ath11k/0080-ath11k-add-branch-predictors-in-process_rx.patch @@ -0,0 +1,102 @@ +From 400588039a17a460292eb974ebba5811b8cbdb91 Mon Sep 17 00:00:00 2001 +From: P Praneesh +Date: Fri, 12 Nov 2021 11:02:31 +0200 +Subject: [PATCH 080/120] ath11k: add branch predictors in process_rx + +In datapath, add branch predictors where required in the process rx(). +This protects high value rx path without having performance overhead. +Also while processing rx packets, the pointer that is returned by +rcu_dereference() is not dereferenced. so it is preferable to use +rcu_access_pointer() here. + +Tested-on: QCN9074 hw1.0 PCI WLAN.HK.2.4.0.1.r2-00012-QCAHKSWPL_SILICONZ-1 +Tested-on: IPQ8074 hw2.0 AHB WLAN.HK.2.4.0.1-01695-QCAHKSWPL_SILICONZ-1 + +Co-developed-by: Sriram R +Signed-off-by: Sriram R +Signed-off-by: Jouni Malinen +Signed-off-by: P Praneesh +Signed-off-by: Kalle Valo +Link: https://lore.kernel.org/r/1630560820-21905-8-git-send-email-ppranees@codeaurora.org +--- + drivers/net/wireless/ath/ath11k/dp_rx.c | 24 +++++++++--------------- + 1 file changed, 9 insertions(+), 15 deletions(-) + +--- a/drivers/net/wireless/ath/ath11k/dp_rx.c ++++ b/drivers/net/wireless/ath/ath11k/dp_rx.c +@@ -2610,24 +2610,20 @@ static void ath11k_dp_rx_process_receive + if (skb_queue_empty(msdu_list)) + return; + +- rcu_read_lock(); +- +- ar = ab->pdevs[mac_id].ar; +- if (!rcu_dereference(ab->pdevs_active[mac_id])) { ++ if (unlikely(!rcu_access_pointer(ab->pdevs_active[mac_id]))) { + __skb_queue_purge(msdu_list); +- rcu_read_unlock(); + return; + } + +- if (test_bit(ATH11K_CAC_RUNNING, &ar->dev_flags)) { ++ ar = ab->pdevs[mac_id].ar; ++ if (unlikely(test_bit(ATH11K_CAC_RUNNING, &ar->dev_flags))) { + __skb_queue_purge(msdu_list); +- rcu_read_unlock(); + return; + } + + while ((msdu = __skb_dequeue(msdu_list))) { + ret = ath11k_dp_rx_process_msdu(ar, msdu, msdu_list, &rx_status); +- if (ret) { ++ if (unlikely(ret)) { + ath11k_dbg(ab, ATH11K_DBG_DATA, + "Unable to process msdu %d", ret); + dev_kfree_skb_any(msdu); +@@ -2636,8 +2632,6 @@ static void ath11k_dp_rx_process_receive + + ath11k_dp_rx_deliver_msdu(ar, napi, msdu, &rx_status); + } +- +- rcu_read_unlock(); + } + + int ath11k_dp_process_rx(struct ath11k_base *ab, int ring_id, +@@ -2682,7 +2676,7 @@ try_again: + rx_ring = &ar->dp.rx_refill_buf_ring; + spin_lock_bh(&rx_ring->idr_lock); + msdu = idr_find(&rx_ring->bufs_idr, buf_id); +- if (!msdu) { ++ if (unlikely(!msdu)) { + ath11k_warn(ab, "frame rx with invalid buf_id %d\n", + buf_id); + spin_unlock_bh(&rx_ring->idr_lock); +@@ -2701,8 +2695,8 @@ try_again: + + push_reason = FIELD_GET(HAL_REO_DEST_RING_INFO0_PUSH_REASON, + desc->info0); +- if (push_reason != +- HAL_REO_DEST_RING_PUSH_REASON_ROUTING_INSTRUCTION) { ++ if (unlikely(push_reason != ++ HAL_REO_DEST_RING_PUSH_REASON_ROUTING_INSTRUCTION)) { + dev_kfree_skb_any(msdu); + ab->soc_stats.hal_reo_error[dp->reo_dst_ring[ring_id].ring_id]++; + continue; +@@ -2741,7 +2735,7 @@ try_again: + * head pointer so that we can reap complete MPDU in the current + * rx processing. + */ +- if (!done && ath11k_hal_srng_dst_num_free(ab, srng, true)) { ++ if (unlikely(!done && ath11k_hal_srng_dst_num_free(ab, srng, true))) { + ath11k_hal_srng_access_end(ab, srng); + goto try_again; + } +@@ -2750,7 +2744,7 @@ try_again: + + spin_unlock_bh(&srng->lock); + +- if (!total_msdu_reaped) ++ if (unlikely(!total_msdu_reaped)) + goto exit; + + for (i = 0; i < ab->num_radios; i++) { diff --git a/package/kernel/mac80211/patches/ath11k/0081-ath11k-allocate-HAL_WBM2SW_RELEASE-ring-from-cacheab.patch b/package/kernel/mac80211/patches/ath11k/0081-ath11k-allocate-HAL_WBM2SW_RELEASE-ring-from-cacheab.patch new file mode 100644 index 000000000..c18ee151b --- /dev/null +++ b/package/kernel/mac80211/patches/ath11k/0081-ath11k-allocate-HAL_WBM2SW_RELEASE-ring-from-cacheab.patch @@ -0,0 +1,32 @@ +From d0e2523bfa9cb391fe966b0b6948c7e438981361 Mon Sep 17 00:00:00 2001 +From: P Praneesh +Date: Fri, 12 Nov 2021 11:02:38 +0200 +Subject: [PATCH 081/120] ath11k: allocate HAL_WBM2SW_RELEASE ring from + cacheable memory + +Similar to REO destination ring, also allocate HAL_WBM2SW_RELEASE +from cacheable memory so that descriptors could be prefetched during +tx completion handling. + +Tested-on: IPQ8074 hw2.0 AHB WLAN.HK.2.4.0.1-01734-QCAHKSWPL_SILICONZ-1 v2 + +Co-developed-by: Sriram R +Signed-off-by: Sriram R +Signed-off-by: Jouni Malinen +Signed-off-by: P Praneesh +Signed-off-by: Kalle Valo +Link: https://lore.kernel.org/r/1630560820-21905-9-git-send-email-ppranees@codeaurora.org +--- + drivers/net/wireless/ath/ath11k/dp.c | 1 + + 1 file changed, 1 insertion(+) + +--- a/drivers/net/wireless/ath/ath11k/dp.c ++++ b/drivers/net/wireless/ath/ath11k/dp.c +@@ -239,6 +239,7 @@ int ath11k_dp_srng_setup(struct ath11k_b + /* Allocate the reo dst and tx completion rings from cacheable memory */ + switch (type) { + case HAL_REO_DST: ++ case HAL_WBM2SW_RELEASE: + cached = true; + break; + default: diff --git a/package/kernel/mac80211/patches/ath11k/0082-ath11k-remove-mod-operator-in-dst-ring-processing.patch b/package/kernel/mac80211/patches/ath11k/0082-ath11k-remove-mod-operator-in-dst-ring-processing.patch new file mode 100644 index 000000000..2ac4f55e9 --- /dev/null +++ b/package/kernel/mac80211/patches/ath11k/0082-ath11k-remove-mod-operator-in-dst-ring-processing.patch @@ -0,0 +1,36 @@ +From a8508bf7ced2e43f30b46333f09cbc79a1675616 Mon Sep 17 00:00:00 2001 +From: P Praneesh +Date: Fri, 12 Nov 2021 11:02:45 +0200 +Subject: [PATCH 082/120] ath11k: remove mod operator in dst ring processing + +Replace use of mod operator with a manual wrap around +to avoid additional cost of using mod operation. + +Tested-on: IPQ8074 hw2.0 AHB WLAN.HK.2.4.0.1-01734-QCAHKSWPL_SILICONZ-1 v2 + +Co-developed-by: Sriram R +Signed-off-by: Sriram R +Signed-off-by: Jouni Malinen +Signed-off-by: P Praneesh +Signed-off-by: Kalle Valo +Link: https://lore.kernel.org/r/1630560820-21905-10-git-send-email-ppranees@codeaurora.org +--- + drivers/net/wireless/ath/ath11k/hal.c | 7 +++++-- + 1 file changed, 5 insertions(+), 2 deletions(-) + +--- a/drivers/net/wireless/ath/ath11k/hal.c ++++ b/drivers/net/wireless/ath/ath11k/hal.c +@@ -654,8 +654,11 @@ u32 *ath11k_hal_srng_dst_get_next_entry( + + desc = srng->ring_base_vaddr + srng->u.dst_ring.tp; + +- srng->u.dst_ring.tp = (srng->u.dst_ring.tp + srng->entry_size) % +- srng->ring_size; ++ srng->u.dst_ring.tp += srng->entry_size; ++ ++ /* wrap around to start of ring*/ ++ if (srng->u.dst_ring.tp == srng->ring_size) ++ srng->u.dst_ring.tp = 0; + + /* Try to prefetch the next descriptor in the ring */ + if (srng->flags & HAL_SRNG_FLAGS_CACHED) diff --git a/package/kernel/mac80211/patches/ath11k/0083-ath11k-avoid-while-loop-in-ring-selection-of-tx-comp.patch b/package/kernel/mac80211/patches/ath11k/0083-ath11k-avoid-while-loop-in-ring-selection-of-tx-comp.patch new file mode 100644 index 000000000..a7ee498fc --- /dev/null +++ b/package/kernel/mac80211/patches/ath11k/0083-ath11k-avoid-while-loop-in-ring-selection-of-tx-comp.patch @@ -0,0 +1,43 @@ +From cbfbed495d3289d5a0bc7c614cea639008086cfe Mon Sep 17 00:00:00 2001 +From: P Praneesh +Date: Fri, 12 Nov 2021 11:05:58 +0200 +Subject: [PATCH 083/120] ath11k: avoid while loop in ring selection of tx + completion interrupt + +Currently while loop is used to find the tx completion ring number and +it is not required since the tx ring mask and the group id can be combined +to directly fetch the ring number. Hence remove the while loop +and directly get the ring number from tx mask and group id. + +Tested-on: IPQ8074 hw2.0 AHB WLAN.HK.2.4.0.1-01734-QCAHKSWPL_SILICONZ-1 v2 + +Co-developed-by: Sriram R +Signed-off-by: Sriram R +Signed-off-by: Jouni Malinen +Signed-off-by: P Praneesh +Signed-off-by: Kalle Valo +Link: https://lore.kernel.org/r/1630560820-21905-11-git-send-email-ppranees@codeaurora.org +--- + drivers/net/wireless/ath/ath11k/dp.c | 9 ++++----- + 1 file changed, 4 insertions(+), 5 deletions(-) + +--- a/drivers/net/wireless/ath/ath11k/dp.c ++++ b/drivers/net/wireless/ath/ath11k/dp.c +@@ -771,13 +771,12 @@ int ath11k_dp_service_srng(struct ath11k + const struct ath11k_hw_hal_params *hal_params; + int grp_id = irq_grp->grp_id; + int work_done = 0; +- int i = 0, j; ++ int i, j; + int tot_work_done = 0; + +- while (ab->hw_params.ring_mask->tx[grp_id] >> i) { +- if (ab->hw_params.ring_mask->tx[grp_id] & BIT(i)) +- ath11k_dp_tx_completion_handler(ab, i); +- i++; ++ if (ab->hw_params.ring_mask->tx[grp_id]) { ++ i = __fls(ab->hw_params.ring_mask->tx[grp_id]); ++ ath11k_dp_tx_completion_handler(ab, i); + } + + if (ab->hw_params.ring_mask->rx_err[grp_id]) { diff --git a/package/kernel/mac80211/patches/ath11k/0084-ath11k-add-branch-predictors-in-dp_tx-path.patch b/package/kernel/mac80211/patches/ath11k/0084-ath11k-add-branch-predictors-in-dp_tx-path.patch new file mode 100644 index 000000000..d86d464e2 --- /dev/null +++ b/package/kernel/mac80211/patches/ath11k/0084-ath11k-add-branch-predictors-in-dp_tx-path.patch @@ -0,0 +1,201 @@ +From bcef57ea400cc20a5389fa0e38d61063331558f8 Mon Sep 17 00:00:00 2001 +From: P Praneesh +Date: Fri, 12 Nov 2021 11:06:04 +0200 +Subject: [PATCH 084/120] ath11k: add branch predictors in dp_tx path + +Add branch prediction in dp_tx code path in tx and tx completion handlers. +Also in ath11k_dp_tx_complete_msdu , the pointer that is returned by +rcu_dereference() is not dereferenced. so it is preferable to use +rcu_access_pointer() here. + +Tested-on: IPQ8074 hw2.0 AHB WLAN.HK.2.4.0.1-01734-QCAHKSWPL_SILICONZ-1 v2 + +Co-developed-by: Sriram R +Signed-off-by: Sriram R +Signed-off-by: Jouni Malinen +Signed-off-by: P Praneesh +Signed-off-by: Kalle Valo +Link: https://lore.kernel.org/r/1630560820-21905-12-git-send-email-ppranees@codeaurora.org +--- + drivers/net/wireless/ath/ath11k/dp_tx.c | 52 ++++++++++++------------- + drivers/net/wireless/ath/ath11k/mac.c | 2 +- + 2 files changed, 25 insertions(+), 29 deletions(-) + +--- a/drivers/net/wireless/ath/ath11k/dp_tx.c ++++ b/drivers/net/wireless/ath/ath11k/dp_tx.c +@@ -95,11 +95,11 @@ int ath11k_dp_tx(struct ath11k *ar, stru + u8 ring_selector = 0, ring_map = 0; + bool tcl_ring_retry; + +- if (test_bit(ATH11K_FLAG_CRASH_FLUSH, &ar->ab->dev_flags)) ++ if (unlikely(test_bit(ATH11K_FLAG_CRASH_FLUSH, &ar->ab->dev_flags))) + return -ESHUTDOWN; + +- if (!(info->flags & IEEE80211_TX_CTL_HW_80211_ENCAP) && +- !ieee80211_is_data(hdr->frame_control)) ++ if (unlikely(!(info->flags & IEEE80211_TX_CTL_HW_80211_ENCAP) && ++ !ieee80211_is_data(hdr->frame_control))) + return -ENOTSUPP; + + pool_id = skb_get_queue_mapping(skb) & (ATH11K_HW_MAX_QUEUES - 1); +@@ -127,7 +127,7 @@ tcl_ring_sel: + DP_TX_IDR_SIZE - 1, GFP_ATOMIC); + spin_unlock_bh(&tx_ring->tx_idr_lock); + +- if (ret < 0) { ++ if (unlikely(ret < 0)) { + if (ring_map == (BIT(ab->hw_params.max_tx_ring) - 1)) { + atomic_inc(&ab->soc_stats.tx_err.misc_fail); + return -ENOSPC; +@@ -152,7 +152,7 @@ tcl_ring_sel: + ti.meta_data_flags = arvif->tcl_metadata; + } + +- if (ti.encap_type == HAL_TCL_ENCAP_TYPE_RAW) { ++ if (unlikely(ti.encap_type == HAL_TCL_ENCAP_TYPE_RAW)) { + if (skb_cb->flags & ATH11K_SKB_CIPHER_SET) { + ti.encrypt_type = + ath11k_dp_tx_get_encrypt_type(skb_cb->cipher); +@@ -173,8 +173,8 @@ tcl_ring_sel: + ti.bss_ast_idx = arvif->ast_idx; + ti.dscp_tid_tbl_idx = 0; + +- if (skb->ip_summed == CHECKSUM_PARTIAL && +- ti.encap_type != HAL_TCL_ENCAP_TYPE_RAW) { ++ if (likely(skb->ip_summed == CHECKSUM_PARTIAL && ++ ti.encap_type != HAL_TCL_ENCAP_TYPE_RAW)) { + ti.flags0 |= FIELD_PREP(HAL_TCL_DATA_CMD_INFO1_IP4_CKSUM_EN, 1) | + FIELD_PREP(HAL_TCL_DATA_CMD_INFO1_UDP4_CKSUM_EN, 1) | + FIELD_PREP(HAL_TCL_DATA_CMD_INFO1_UDP6_CKSUM_EN, 1) | +@@ -211,7 +211,7 @@ tcl_ring_sel: + } + + ti.paddr = dma_map_single(ab->dev, skb->data, skb->len, DMA_TO_DEVICE); +- if (dma_mapping_error(ab->dev, ti.paddr)) { ++ if (unlikely(dma_mapping_error(ab->dev, ti.paddr))) { + atomic_inc(&ab->soc_stats.tx_err.misc_fail); + ath11k_warn(ab, "failed to DMA map data Tx buffer\n"); + ret = -ENOMEM; +@@ -231,7 +231,7 @@ tcl_ring_sel: + ath11k_hal_srng_access_begin(ab, tcl_ring); + + hal_tcl_desc = (void *)ath11k_hal_srng_src_get_next_entry(ab, tcl_ring); +- if (!hal_tcl_desc) { ++ if (unlikely(!hal_tcl_desc)) { + /* NOTE: It is highly unlikely we'll be running out of tcl_ring + * desc because the desc is directly enqueued onto hw queue. + */ +@@ -245,7 +245,7 @@ tcl_ring_sel: + * checking this ring earlier for each pkt tx. + * Restart ring selection if some rings are not checked yet. + */ +- if (ring_map != (BIT(ab->hw_params.max_tx_ring) - 1) && ++ if (unlikely(ring_map != (BIT(ab->hw_params.max_tx_ring)) - 1) && + ab->hw_params.max_tx_ring > 1) { + tcl_ring_retry = true; + ring_selector++; +@@ -327,7 +327,7 @@ ath11k_dp_tx_htt_tx_complete_buf(struct + + spin_lock_bh(&tx_ring->tx_idr_lock); + msdu = idr_find(&tx_ring->txbuf_idr, ts->msdu_id); +- if (!msdu) { ++ if (unlikely(!msdu)) { + ath11k_warn(ab, "htt tx completion for unknown msdu_id %d\n", + ts->msdu_id); + spin_unlock_bh(&tx_ring->tx_idr_lock); +@@ -435,16 +435,14 @@ static void ath11k_dp_tx_complete_msdu(s + + dma_unmap_single(ab->dev, skb_cb->paddr, msdu->len, DMA_TO_DEVICE); + +- rcu_read_lock(); +- +- if (!rcu_dereference(ab->pdevs_active[ar->pdev_idx])) { ++ if (unlikely(!rcu_access_pointer(ab->pdevs_active[ar->pdev_idx]))) { + dev_kfree_skb_any(msdu); +- goto exit; ++ return; + } + +- if (!skb_cb->vif) { ++ if (unlikely(!skb_cb->vif)) { + dev_kfree_skb_any(msdu); +- goto exit; ++ return; + } + + info = IEEE80211_SKB_CB(msdu); +@@ -465,7 +463,7 @@ static void ath11k_dp_tx_complete_msdu(s + (info->flags & IEEE80211_TX_CTL_NO_ACK)) + info->flags |= IEEE80211_TX_STAT_NOACK_TRANSMITTED; + +- if (ath11k_debugfs_is_extd_tx_stats_enabled(ar)) { ++ if (unlikely(ath11k_debugfs_is_extd_tx_stats_enabled(ar))) { + if (ts->flags & HAL_TX_STATUS_FLAGS_FIRST_MSDU) { + if (ar->last_ppdu_id == 0) { + ar->last_ppdu_id = ts->ppdu_id; +@@ -494,9 +492,6 @@ static void ath11k_dp_tx_complete_msdu(s + */ + + ieee80211_tx_status(ar->hw, msdu); +- +-exit: +- rcu_read_unlock(); + } + + static inline void ath11k_dp_tx_status_parse(struct ath11k_base *ab, +@@ -505,11 +500,11 @@ static inline void ath11k_dp_tx_status_p + { + ts->buf_rel_source = + FIELD_GET(HAL_WBM_RELEASE_INFO0_REL_SRC_MODULE, desc->info0); +- if (ts->buf_rel_source != HAL_WBM_REL_SRC_MODULE_FW && +- ts->buf_rel_source != HAL_WBM_REL_SRC_MODULE_TQM) ++ if (unlikely(ts->buf_rel_source != HAL_WBM_REL_SRC_MODULE_FW && ++ ts->buf_rel_source != HAL_WBM_REL_SRC_MODULE_TQM)) + return; + +- if (ts->buf_rel_source == HAL_WBM_REL_SRC_MODULE_FW) ++ if (unlikely(ts->buf_rel_source == HAL_WBM_REL_SRC_MODULE_FW)) + return; + + ts->status = FIELD_GET(HAL_WBM_RELEASE_INFO0_TQM_RELEASE_REASON, +@@ -556,8 +551,9 @@ void ath11k_dp_tx_completion_handler(str + ATH11K_TX_COMPL_NEXT(tx_ring->tx_status_head); + } + +- if ((ath11k_hal_srng_dst_peek(ab, status_ring) != NULL) && +- (ATH11K_TX_COMPL_NEXT(tx_ring->tx_status_head) == tx_ring->tx_status_tail)) { ++ if (unlikely((ath11k_hal_srng_dst_peek(ab, status_ring) != NULL) && ++ (ATH11K_TX_COMPL_NEXT(tx_ring->tx_status_head) == ++ tx_ring->tx_status_tail))) { + /* TODO: Process pending tx_status messages when kfifo_is_full() */ + ath11k_warn(ab, "Unable to process some of the tx_status ring desc because status_fifo is full\n"); + } +@@ -580,7 +576,7 @@ void ath11k_dp_tx_completion_handler(str + mac_id = FIELD_GET(DP_TX_DESC_ID_MAC_ID, desc_id); + msdu_id = FIELD_GET(DP_TX_DESC_ID_MSDU_ID, desc_id); + +- if (ts.buf_rel_source == HAL_WBM_REL_SRC_MODULE_FW) { ++ if (unlikely(ts.buf_rel_source == HAL_WBM_REL_SRC_MODULE_FW)) { + ath11k_dp_tx_process_htt_tx_complete(ab, + (void *)tx_status, + mac_id, msdu_id, +@@ -590,7 +586,7 @@ void ath11k_dp_tx_completion_handler(str + + spin_lock_bh(&tx_ring->tx_idr_lock); + msdu = idr_find(&tx_ring->txbuf_idr, msdu_id); +- if (!msdu) { ++ if (unlikely(!msdu)) { + ath11k_warn(ab, "tx completion for unknown msdu_id %d\n", + msdu_id); + spin_unlock_bh(&tx_ring->tx_idr_lock); +--- a/drivers/net/wireless/ath/ath11k/mac.c ++++ b/drivers/net/wireless/ath/ath11k/mac.c +@@ -5283,7 +5283,7 @@ static void ath11k_mac_op_tx(struct ieee + arsta = (struct ath11k_sta *)control->sta->drv_priv; + + ret = ath11k_dp_tx(ar, arvif, arsta, skb); +- if (ret) { ++ if (unlikely(ret)) { + ath11k_warn(ar->ab, "failed to transmit frame %d\n", ret); + ieee80211_free_txskb(ar->hw, skb); + } diff --git a/package/kernel/mac80211/patches/ath11k/0085-ath11k-avoid-unnecessary-lock-contention-in-tx_compl.patch b/package/kernel/mac80211/patches/ath11k/0085-ath11k-avoid-unnecessary-lock-contention-in-tx_compl.patch new file mode 100644 index 000000000..c38c0f563 --- /dev/null +++ b/package/kernel/mac80211/patches/ath11k/0085-ath11k-avoid-unnecessary-lock-contention-in-tx_compl.patch @@ -0,0 +1,102 @@ +From be8867cb47652418e488170785bd9ffbadae3f1f Mon Sep 17 00:00:00 2001 +From: P Praneesh +Date: Fri, 12 Nov 2021 11:06:11 +0200 +Subject: [PATCH 085/120] ath11k: avoid unnecessary lock contention in + tx_completion path + +Avoid unnecessary idr_find calls before the idr_remove calls. Because +idr_remove gives the valid ptr if id is valid otherwise return NULL ptr. +So removed the idr_find before idr_remove in tx completion path. Also no +need to disable the bottom half preempt if it is already in the +bottom half context, so modify the spin_lock_bh to spin_lock in the +data tx completion path. + +Tested-on: IPQ8074 hw2.0 AHB WLAN.HK.2.4.0.1-01734-QCAHKSWPL_SILICONZ-1 v2 + +Co-developed-by: Karthikeyan Periyasamy +Signed-off-by: Karthikeyan Periyasamy +Signed-off-by: Jouni Malinen +Signed-off-by: P Praneesh +Signed-off-by: Kalle Valo +Link: https://lore.kernel.org/r/1630560820-21905-13-git-send-email-ppranees@codeaurora.org +--- + drivers/net/wireless/ath/ath11k/dp_tx.c | 32 +++++++++++-------------- + 1 file changed, 14 insertions(+), 18 deletions(-) + +--- a/drivers/net/wireless/ath/ath11k/dp_tx.c ++++ b/drivers/net/wireless/ath/ath11k/dp_tx.c +@@ -293,20 +293,18 @@ static void ath11k_dp_tx_free_txbuf(stru + struct sk_buff *msdu; + struct ath11k_skb_cb *skb_cb; + +- spin_lock_bh(&tx_ring->tx_idr_lock); +- msdu = idr_find(&tx_ring->txbuf_idr, msdu_id); +- if (!msdu) { ++ spin_lock(&tx_ring->tx_idr_lock); ++ msdu = idr_remove(&tx_ring->txbuf_idr, msdu_id); ++ spin_unlock(&tx_ring->tx_idr_lock); ++ ++ if (unlikely(!msdu)) { + ath11k_warn(ab, "tx completion for unknown msdu_id %d\n", + msdu_id); +- spin_unlock_bh(&tx_ring->tx_idr_lock); + return; + } + + skb_cb = ATH11K_SKB_CB(msdu); + +- idr_remove(&tx_ring->txbuf_idr, msdu_id); +- spin_unlock_bh(&tx_ring->tx_idr_lock); +- + dma_unmap_single(ab->dev, skb_cb->paddr, msdu->len, DMA_TO_DEVICE); + dev_kfree_skb_any(msdu); + +@@ -325,12 +323,13 @@ ath11k_dp_tx_htt_tx_complete_buf(struct + struct ath11k_skb_cb *skb_cb; + struct ath11k *ar; + +- spin_lock_bh(&tx_ring->tx_idr_lock); +- msdu = idr_find(&tx_ring->txbuf_idr, ts->msdu_id); ++ spin_lock(&tx_ring->tx_idr_lock); ++ msdu = idr_remove(&tx_ring->txbuf_idr, ts->msdu_id); ++ spin_unlock(&tx_ring->tx_idr_lock); ++ + if (unlikely(!msdu)) { + ath11k_warn(ab, "htt tx completion for unknown msdu_id %d\n", + ts->msdu_id); +- spin_unlock_bh(&tx_ring->tx_idr_lock); + return; + } + +@@ -339,9 +338,6 @@ ath11k_dp_tx_htt_tx_complete_buf(struct + + ar = skb_cb->ar; + +- idr_remove(&tx_ring->txbuf_idr, ts->msdu_id); +- spin_unlock_bh(&tx_ring->tx_idr_lock); +- + if (atomic_dec_and_test(&ar->dp.num_tx_pending)) + wake_up(&ar->dp.tx_empty_waitq); + +@@ -584,16 +580,16 @@ void ath11k_dp_tx_completion_handler(str + continue; + } + +- spin_lock_bh(&tx_ring->tx_idr_lock); +- msdu = idr_find(&tx_ring->txbuf_idr, msdu_id); ++ spin_lock(&tx_ring->tx_idr_lock); ++ msdu = idr_remove(&tx_ring->txbuf_idr, msdu_id); + if (unlikely(!msdu)) { + ath11k_warn(ab, "tx completion for unknown msdu_id %d\n", + msdu_id); +- spin_unlock_bh(&tx_ring->tx_idr_lock); ++ spin_unlock(&tx_ring->tx_idr_lock); + continue; + } +- idr_remove(&tx_ring->txbuf_idr, msdu_id); +- spin_unlock_bh(&tx_ring->tx_idr_lock); ++ ++ spin_unlock(&tx_ring->tx_idr_lock); + + ar = ab->pdevs[mac_id].ar; + diff --git a/package/kernel/mac80211/patches/ath11k/0086-ath11k-enable-IEEE80211_VHT_EXT_NSS_BW_CAPABLE-if-NS.patch b/package/kernel/mac80211/patches/ath11k/0086-ath11k-enable-IEEE80211_VHT_EXT_NSS_BW_CAPABLE-if-NS.patch new file mode 100644 index 000000000..800a8f838 --- /dev/null +++ b/package/kernel/mac80211/patches/ath11k/0086-ath11k-enable-IEEE80211_VHT_EXT_NSS_BW_CAPABLE-if-NS.patch @@ -0,0 +1,48 @@ +From 78406044bdd0cc8987bc082b76867c63ab1c6af8 Mon Sep 17 00:00:00 2001 +From: Wen Gong +Date: Wed, 13 Oct 2021 03:37:04 -0400 +Subject: [PATCH 086/120] ath11k: enable IEEE80211_VHT_EXT_NSS_BW_CAPABLE if + NSS ratio enabled +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +When NSS ratio enabled reported by firmware, SUPPORTS_VHT_EXT_NSS_BW +is set in ath11k, meanwhile IEEE80211_VHT_EXT_NSS_BW_CAPABLE also +need to be set, otherwise it is invalid because spec in IEEE Std +802.11™‐2020 as below. + +Table 9-273-Supported VHT-MCS and NSS Set subfields, it has subfield +VHT Extended NSS BW Capable, its definition is: +Indicates whether the STA is capable of interpreting the Extended NSS +BW Support subfield of the VHT Capabilities Information field. + +dmesg have a message without this patch: + +ieee80211 phy0: copying sband (band 1) due to VHT EXT NSS BW flag + +It means mac80211 will set IEEE80211_VHT_EXT_NSS_BW_CAPABLE if ath11k not +set it in ieee80211_register_hw(). So it is better to set it in ath11k. + +Tested-on: WCN6855 hw2.0 PCI WLAN.HSP.1.1-01720.1-QCAHSPSWPL_V1_V2_SILICONZ_LITE-1 + +Signed-off-by: Wen Gong +Signed-off-by: Kalle Valo +Link: https://lore.kernel.org/r/20211013073704.15888-1-wgong@codeaurora.org +--- + drivers/net/wireless/ath/ath11k/mac.c | 4 ++++ + 1 file changed, 4 insertions(+) + +--- a/drivers/net/wireless/ath/ath11k/mac.c ++++ b/drivers/net/wireless/ath/ath11k/mac.c +@@ -4706,6 +4706,10 @@ ath11k_create_vht_cap(struct ath11k *ar, + vht_cap.vht_supported = 1; + vht_cap.cap = ar->pdev->cap.vht_cap; + ++ if (ar->pdev->cap.nss_ratio_enabled) ++ vht_cap.vht_mcs.tx_highest |= ++ cpu_to_le16(IEEE80211_VHT_EXT_NSS_BW_CAPABLE); ++ + ath11k_set_vht_txbf_cap(ar, &vht_cap.cap); + + rxmcs_map = 0; diff --git a/package/kernel/mac80211/patches/ath11k/0087-ath11k-remove-return-for-empty-tx-bitrate-in-mac_op_.patch b/package/kernel/mac80211/patches/ath11k/0087-ath11k-remove-return-for-empty-tx-bitrate-in-mac_op_.patch new file mode 100644 index 000000000..5a52481f3 --- /dev/null +++ b/package/kernel/mac80211/patches/ath11k/0087-ath11k-remove-return-for-empty-tx-bitrate-in-mac_op_.patch @@ -0,0 +1,66 @@ +From 1d795645e1eef97fe5d409e3dd5747a942f00e08 Mon Sep 17 00:00:00 2001 +From: Wen Gong +Date: Mon, 11 Oct 2021 04:49:57 -0400 +Subject: [PATCH 087/120] ath11k: remove return for empty tx bitrate in + mac_op_sta_statistics + +Currently in ath11k_mac_op_sta_statistics() there is the following +logic: + + if (!arsta->txrate.legacy && !arsta->txrate.nss) + return; + +Unfortunately if this condition is true then the function returns without +setting parameters that follow the txrate. To address this issue remove the +return and instead invert the logic to set the txrate logic if +(arsta->txrate.legacy || arsta->txrate.nss). + +The same was done also in ath10k in commit 1cd6ba8ae33e ("ath10k: remove return +for NL80211_STA_INFO_TX_BITRATE"). + +Tested-on: QCA6390 hw2.0 PCI WLAN.HST.1.0.1-01740-QCAHSTSWPLZ_V2_TO_X86-1 + +Signed-off-by: Wen Gong +Signed-off-by: Kalle Valo +Link: https://lore.kernel.org/r/20211011084957.31024-1-wgong@codeaurora.org +--- + drivers/net/wireless/ath/ath11k/mac.c | 29 +++++++++++++-------------- + 1 file changed, 14 insertions(+), 15 deletions(-) + +--- a/drivers/net/wireless/ath/ath11k/mac.c ++++ b/drivers/net/wireless/ath/ath11k/mac.c +@@ -7426,21 +7426,20 @@ static void ath11k_mac_op_sta_statistics + sinfo->tx_duration = arsta->tx_duration; + sinfo->filled |= BIT_ULL(NL80211_STA_INFO_TX_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; +- sinfo->txrate.he_gi = arsta->txrate.he_gi; +- sinfo->txrate.he_dcm = arsta->txrate.he_dcm; +- sinfo->txrate.he_ru_alloc = arsta->txrate.he_ru_alloc; ++ 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.he_gi = arsta->txrate.he_gi; ++ sinfo->txrate.he_dcm = arsta->txrate.he_dcm; ++ sinfo->txrate.he_ru_alloc = arsta->txrate.he_ru_alloc; ++ } ++ 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); + + /* TODO: Use real NF instead of default one. */ + sinfo->signal = arsta->rssi_comb + ATH11K_DEFAULT_NOISE_FLOOR; diff --git a/package/kernel/mac80211/patches/ath11k/0088-ath11k-fix-the-value-of-msecs_to_jiffies-in-ath11k_d.patch b/package/kernel/mac80211/patches/ath11k/0088-ath11k-fix-the-value-of-msecs_to_jiffies-in-ath11k_d.patch new file mode 100644 index 000000000..4c48cd3f6 --- /dev/null +++ b/package/kernel/mac80211/patches/ath11k/0088-ath11k-fix-the-value-of-msecs_to_jiffies-in-ath11k_d.patch @@ -0,0 +1,28 @@ +From c8f2d41bbff6794329d681d108a817366aed0ba7 Mon Sep 17 00:00:00 2001 +From: Wen Gong +Date: Mon, 25 Oct 2021 23:20:14 -0400 +Subject: [PATCH 088/120] ath11k: fix the value of msecs_to_jiffies in + ath11k_debugfs_fw_stats_request + +parameter of msecs_to_jiffies should be (3 * 1000) instead of (3 * HZ) + +Tested-on: QCA6390 hw2.0 PCI WLAN.HST.1.0.1-01740-QCAHSTSWPLZ_V2_TO_X86-1 + +Signed-off-by: Wen Gong +Signed-off-by: Kalle Valo +Link: https://lore.kernel.org/r/20211026032014.27010-1-quic_wgong@quicinc.com +--- + drivers/net/wireless/ath/ath11k/debugfs.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +--- a/drivers/net/wireless/ath/ath11k/debugfs.c ++++ b/drivers/net/wireless/ath/ath11k/debugfs.c +@@ -195,7 +195,7 @@ static int ath11k_debugfs_fw_stats_reque + * received 'update stats' event, we keep a 3 seconds timeout in case, + * fw_stats_done is not marked yet + */ +- timeout = jiffies + msecs_to_jiffies(3 * HZ); ++ timeout = jiffies + msecs_to_jiffies(3 * 1000); + + ath11k_debugfs_fw_stats_reset(ar); + diff --git a/package/kernel/mac80211/patches/ath11k/0089-ath11k-move-peer-delete-after-vdev-stop-of-station-f.patch b/package/kernel/mac80211/patches/ath11k/0089-ath11k-move-peer-delete-after-vdev-stop-of-station-f.patch new file mode 100644 index 000000000..3f103c4eb --- /dev/null +++ b/package/kernel/mac80211/patches/ath11k/0089-ath11k-move-peer-delete-after-vdev-stop-of-station-f.patch @@ -0,0 +1,89 @@ +From b4a0f54156ac7720de1750b6ea06657c91c52163 Mon Sep 17 00:00:00 2001 +From: Wen Gong +Date: Wed, 27 Oct 2021 05:38:25 -0400 +Subject: [PATCH 089/120] ath11k: move peer delete after vdev stop of station + for QCA6390 and WCN6855 + +When station connect to AP, the wmi command sequence is: + +peer_create->vdev_start->vdev_up + +and sequence of station disconnect fo AP is: + +peer_delete->vdev_down->vdev_stop + +The sequence of disconnect is not opposite of connect, it caused firmware +crash when it handle wmi vdev stop cmd when the AP is support TWT of +802.11 ax, because firmware need access the bss peer for vdev stop cmd. + +[ 390.438564] ath11k_pci 0000:05:00.0: wmi cmd send 0x6001 ret 0 +[ 390.438567] ath11k_pci 0000:05:00.0: WMI peer create vdev_id 0 peer_addr c4:04:15:3b:e0:39 +[ 390.472724] ath11k_pci 0000:05:00.0: mac vdev 0 start center_freq 2437 phymode 11ax-he20-2g +[ 390.472731] ath11k_pci 0000:05:00.0: wmi cmd send 0x5003 ret 0 +[ 390.560849] ath11k_pci 0000:05:00.0: wmi cmd send 0x5005 ret 0 +[ 390.560850] ath11k_pci 0000:05:00.0: WMI mgmt vdev up id 0x0 assoc id 1 bssid c4:04:15:3b:e0:39 + +[ 399.432896] ath11k_pci 0000:05:00.0: WMI peer delete vdev_id 0 peer_addr c4:04:15:3b:e0:39 +[ 399.432902] ath11k_pci 0000:05:00.0: wmi cmd send 0x6002 ret 0 +[ 399.441380] ath11k_pci 0000:05:00.0: wmi cmd send 0x5007 ret 0 +[ 399.441381] ath11k_pci 0000:05:00.0: WMI vdev down id 0x0 +[ 399.454681] ath11k_pci 0000:05:00.0: wmi cmd send 0x5006 ret 0 +[ 399.454682] ath11k_pci 0000:05:00.0: WMI vdev stop id 0x0 + +The opposite sequence of disconnect should be: + +vdev_down->vdev_stop->peer_delete + +This patch change the sequence of disconnect for station as above +opposite sequence for QCA6390, firmware not crash again with this patch. + +Tested-on: QCA6390 hw2.0 PCI WLAN.HST.1.0.1-01740-QCAHSTSWPLZ_V2_TO_X86-1 + +Signed-off-by: Wen Gong +Signed-off-by: Kalle Valo +Link: https://lore.kernel.org/r/20211027093825.12167-1-quic_wgong@quicinc.com +--- + drivers/net/wireless/ath/ath11k/mac.c | 18 ++++++++++++++++++ + 1 file changed, 18 insertions(+) + +--- a/drivers/net/wireless/ath/ath11k/mac.c ++++ b/drivers/net/wireless/ath/ath11k/mac.c +@@ -4212,6 +4212,10 @@ static int ath11k_mac_op_sta_state(struc + new_state == IEEE80211_STA_NOTEXIST)) { + ath11k_dp_peer_cleanup(ar, arvif->vdev_id, sta->addr); + ++ if (ar->ab->hw_params.vdev_start_delay && ++ vif->type == NL80211_IFTYPE_STATION) ++ goto free; ++ + ret = ath11k_peer_delete(ar, arvif->vdev_id, sta->addr); + if (ret) + ath11k_warn(ar->ab, "Failed to delete peer: %pM for VDEV: %d\n", +@@ -4233,6 +4237,7 @@ static int ath11k_mac_op_sta_state(struc + } + spin_unlock_bh(&ar->ab->base_lock); + ++free: + kfree(arsta->tx_stats); + arsta->tx_stats = NULL; + +@@ -6617,6 +6622,19 @@ ath11k_mac_op_unassign_vif_chanctx(struc + arvif->is_started = false; + + if (ab->hw_params.vdev_start_delay && ++ arvif->vdev_type == WMI_VDEV_TYPE_STA) { ++ ret = ath11k_peer_delete(ar, arvif->vdev_id, arvif->bssid); ++ if (ret) ++ ath11k_warn(ar->ab, ++ "failed to delete peer %pM for vdev %d: %d\n", ++ arvif->bssid, arvif->vdev_id, ret); ++ else ++ ath11k_dbg(ar->ab, ATH11K_DBG_MAC, ++ "mac removed peer %pM vdev %d after vdev stop\n", ++ arvif->bssid, arvif->vdev_id); ++ } ++ ++ if (ab->hw_params.vdev_start_delay && + arvif->vdev_type == WMI_VDEV_TYPE_MONITOR) + ath11k_wmi_vdev_down(ar, arvif->vdev_id); + diff --git a/package/kernel/mac80211/patches/ath11k/0090-ath11k-fix-FCS_ERR-flag-in-radio-tap-header.patch b/package/kernel/mac80211/patches/ath11k/0090-ath11k-fix-FCS_ERR-flag-in-radio-tap-header.patch new file mode 100644 index 000000000..f966564e0 --- /dev/null +++ b/package/kernel/mac80211/patches/ath11k/0090-ath11k-fix-FCS_ERR-flag-in-radio-tap-header.patch @@ -0,0 +1,73 @@ +From 787264893c69ed091a46335dfd0f50dabb457718 Mon Sep 17 00:00:00 2001 +From: P Praneesh +Date: Mon, 25 Oct 2021 17:44:20 +0530 +Subject: [PATCH 090/120] ath11k: fix FCS_ERR flag in radio tap header + +In radio tap header, BAD FCS flag is not updated properly because +driver failed to update FCS_ERR flag in monitor mode. + +In rx_desc, FCS_ERR information is available in rx_attention +structure and presence of this field indicates corresponding frame +failed FCS check. + +Tested-on: IPQ8074 hw2.0 AHB WLAN.HK.2.4.0.1-01695-QCAHKSWPL_SILICONZ-1 + +Signed-off-by: P Praneesh +Signed-off-by: Kalle Valo +Link: https://lore.kernel.org/r/1635164060-18423-1-git-send-email-quic_ppranees@quicinc.com +--- + drivers/net/wireless/ath/ath11k/dp_rx.c | 14 ++++++++++++-- + 1 file changed, 12 insertions(+), 2 deletions(-) + +--- a/drivers/net/wireless/ath/ath11k/dp_rx.c ++++ b/drivers/net/wireless/ath/ath11k/dp_rx.c +@@ -4826,7 +4826,7 @@ static struct sk_buff * + ath11k_dp_rx_mon_merg_msdus(struct ath11k *ar, + u32 mac_id, struct sk_buff *head_msdu, + struct sk_buff *last_msdu, +- struct ieee80211_rx_status *rxs) ++ struct ieee80211_rx_status *rxs, bool *fcs_err) + { + struct ath11k_base *ab = ar->ab; + struct sk_buff *msdu, *prev_buf; +@@ -4836,12 +4836,17 @@ ath11k_dp_rx_mon_merg_msdus(struct ath11 + u8 *dest, decap_format; + struct ieee80211_hdr_3addr *wh; + struct rx_attention *rx_attention; ++ u32 err_bitmap; + + if (!head_msdu) + goto err_merge_fail; + + rx_desc = (struct hal_rx_desc *)head_msdu->data; + rx_attention = ath11k_dp_rx_get_attention(ab, rx_desc); ++ err_bitmap = ath11k_dp_rx_h_attn_mpdu_err(rx_attention); ++ ++ if (err_bitmap & DP_RX_MPDU_ERR_FCS) ++ *fcs_err = true; + + if (ath11k_dp_rxdesc_get_mpdulen_err(rx_attention)) + return NULL; +@@ -4930,9 +4935,10 @@ static int ath11k_dp_rx_mon_deliver(stru + struct ath11k_pdev_dp *dp = &ar->dp; + struct sk_buff *mon_skb, *skb_next, *header; + struct ieee80211_rx_status *rxs = &dp->rx_status; ++ bool fcs_err = false; + + mon_skb = ath11k_dp_rx_mon_merg_msdus(ar, mac_id, head_msdu, +- tail_msdu, rxs); ++ tail_msdu, rxs, &fcs_err); + + if (!mon_skb) + goto mon_deliver_fail; +@@ -4940,6 +4946,10 @@ static int ath11k_dp_rx_mon_deliver(stru + header = mon_skb; + + rxs->flag = 0; ++ ++ if (fcs_err) ++ rxs->flag = RX_FLAG_FAILED_FCS_CRC; ++ + do { + skb_next = mon_skb->next; + if (!skb_next) diff --git a/package/kernel/mac80211/patches/ath11k/0091-ath11k-send-proper-txpower-and-maxregpower-values-to.patch b/package/kernel/mac80211/patches/ath11k/0091-ath11k-send-proper-txpower-and-maxregpower-values-to.patch new file mode 100644 index 000000000..2372ec485 --- /dev/null +++ b/package/kernel/mac80211/patches/ath11k/0091-ath11k-send-proper-txpower-and-maxregpower-values-to.patch @@ -0,0 +1,64 @@ +From 9212c1b9e80a869e732769a4fe7f82d392b219be Mon Sep 17 00:00:00 2001 +From: P Praneesh +Date: Mon, 25 Oct 2021 17:47:09 +0530 +Subject: [PATCH 091/120] ath11k: send proper txpower and maxregpower values to + firmware + +Set proper values for max_regpower, max_power, max_antenna_gain as it +is because firmware will convert power values to 0.5dbm steps by +multiplying it with 2. + +If txpower is not set, it will lead to cca stuck resulting in latency +issues for QCN9074. + +Tested-on: QCN9074 hw1.0 PCI WLAN.HK.2.4.0.1-01386-QCAHKSWPL_SILICONZ-1 + +Co-developed-by: Lavanya Suresh +Signed-off-by: Lavanya Suresh +Signed-off-by: P Praneesh +Signed-off-by: Kalle Valo +Link: https://lore.kernel.org/r/1635164229-22880-1-git-send-email-quic_ppranees@quicinc.com +--- + drivers/net/wireless/ath/ath11k/mac.c | 12 ++++++------ + drivers/net/wireless/ath/ath11k/wmi.c | 2 ++ + 2 files changed, 8 insertions(+), 6 deletions(-) + +--- a/drivers/net/wireless/ath/ath11k/mac.c ++++ b/drivers/net/wireless/ath/ath11k/mac.c +@@ -775,9 +775,9 @@ static int ath11k_mac_monitor_vdev_start + arg.channel.chan_radar = !!(channel->flags & IEEE80211_CHAN_RADAR); + + arg.channel.min_power = 0; +- arg.channel.max_power = channel->max_power * 2; +- arg.channel.max_reg_power = channel->max_reg_power * 2; +- arg.channel.max_antenna_gain = channel->max_antenna_gain * 2; ++ arg.channel.max_power = channel->max_power; ++ arg.channel.max_reg_power = channel->max_reg_power; ++ arg.channel.max_antenna_gain = channel->max_antenna_gain; + + arg.pref_tx_streams = ar->num_tx_chains; + arg.pref_rx_streams = ar->num_rx_chains; +@@ -6123,9 +6123,9 @@ ath11k_mac_vdev_start_restart(struct ath + ath11k_phymodes[chandef->chan->band][chandef->width]; + + arg.channel.min_power = 0; +- arg.channel.max_power = chandef->chan->max_power * 2; +- arg.channel.max_reg_power = chandef->chan->max_reg_power * 2; +- arg.channel.max_antenna_gain = chandef->chan->max_antenna_gain * 2; ++ arg.channel.max_power = chandef->chan->max_power; ++ arg.channel.max_reg_power = chandef->chan->max_reg_power; ++ arg.channel.max_antenna_gain = chandef->chan->max_antenna_gain; + + arg.pref_tx_streams = ar->num_tx_chains; + arg.pref_rx_streams = ar->num_rx_chains; +--- a/drivers/net/wireless/ath/ath11k/wmi.c ++++ b/drivers/net/wireless/ath/ath11k/wmi.c +@@ -2387,6 +2387,8 @@ int ath11k_wmi_send_scan_chan_list_cmd(s + tchan_info->reg_class_id); + *reg2 |= FIELD_PREP(WMI_CHAN_REG_INFO2_ANT_MAX, + tchan_info->antennamax); ++ *reg2 |= FIELD_PREP(WMI_CHAN_REG_INFO2_MAX_TX_PWR, ++ tchan_info->maxregpower); + + ath11k_dbg(ar->ab, ATH11K_DBG_WMI, + "WMI chan scan list chan[%d] = %u, chan_info->info %8x\n", diff --git a/package/kernel/mac80211/patches/ath11k/0092-ath11k-Increment-pending_mgmt_tx-count-before-tx-sen.patch b/package/kernel/mac80211/patches/ath11k/0092-ath11k-Increment-pending_mgmt_tx-count-before-tx-sen.patch new file mode 100644 index 000000000..94fa816d6 --- /dev/null +++ b/package/kernel/mac80211/patches/ath11k/0092-ath11k-Increment-pending_mgmt_tx-count-before-tx-sen.patch @@ -0,0 +1,44 @@ +From c0b0d2e87d91ce283c8766b4b3c2ec9ac90ebf96 Mon Sep 17 00:00:00 2001 +From: P Praneesh +Date: Mon, 25 Oct 2021 18:54:42 +0530 +Subject: [PATCH 092/120] ath11k: Increment pending_mgmt_tx count before tx + send invoke + +There is a race condition whereby the tx completion handler can be invoked +before the 'num_pending_mgmt_tx" count is incremented. If that occurs, we +could get warning trace indicating that 'num_pending_mgmt_tx' is 0 (because +it was not yet incremented). Ideally, this trace should be seen only if +mgmt tx has not happened but tx completion is received, and it is not +expected in this race condition. + +Tested-on: QCN9074 hw1.0 PCI WLAN.HK.2.4.0.1-01386-QCAHKSWPL_SILICONZ-1 + +Co-developed-by: Lavanya Suresh +Signed-off-by: Lavanya Suresh +Signed-off-by: P Praneesh +Signed-off-by: Kalle Valo +Link: https://lore.kernel.org/r/1635168282-8845-1-git-send-email-quic_ppranees@quicinc.com +--- + drivers/net/wireless/ath/ath11k/mac.c | 6 ++++-- + 1 file changed, 4 insertions(+), 2 deletions(-) + +--- a/drivers/net/wireless/ath/ath11k/mac.c ++++ b/drivers/net/wireless/ath/ath11k/mac.c +@@ -5202,13 +5202,15 @@ static void ath11k_mgmt_over_wmi_tx_work + arvif = ath11k_vif_to_arvif(skb_cb->vif); + if (ar->allocated_vdev_map & (1LL << arvif->vdev_id) && + arvif->is_started) { ++ atomic_inc(&ar->num_pending_mgmt_tx); + ret = ath11k_mac_mgmt_tx_wmi(ar, arvif, skb); + if (ret) { ++ if (atomic_dec_if_positive(&ar->num_pending_mgmt_tx) < 0) ++ WARN_ON_ONCE(1); ++ + ath11k_warn(ar->ab, "failed to tx mgmt frame, vdev_id %d :%d\n", + arvif->vdev_id, ret); + ieee80211_free_txskb(ar->hw, skb); +- } else { +- atomic_inc(&ar->num_pending_mgmt_tx); + } + } else { + ath11k_warn(ar->ab, diff --git a/package/kernel/mac80211/patches/ath11k/0093-ath11k-Fix-ETSI-regd-with-weather-radar-overlap.patch b/package/kernel/mac80211/patches/ath11k/0093-ath11k-Fix-ETSI-regd-with-weather-radar-overlap.patch new file mode 100644 index 000000000..eb9c73022 --- /dev/null +++ b/package/kernel/mac80211/patches/ath11k/0093-ath11k-Fix-ETSI-regd-with-weather-radar-overlap.patch @@ -0,0 +1,236 @@ +From 086c921a354089f209318501038d43c98d3f409f Mon Sep 17 00:00:00 2001 +From: Sven Eckelmann +Date: Mon, 15 Nov 2021 11:29:55 +0200 +Subject: [PATCH 093/120] ath11k: Fix ETSI regd with weather radar overlap + +Some ETSI countries have a small overlap in the wireless-regdb with an ETSI +channel (5590-5650). A good example is Australia: + + country AU: DFS-ETSI + (2400 - 2483.5 @ 40), (36) + (5150 - 5250 @ 80), (23), NO-OUTDOOR, AUTO-BW + (5250 - 5350 @ 80), (20), NO-OUTDOOR, AUTO-BW, DFS + (5470 - 5600 @ 80), (27), DFS + (5650 - 5730 @ 80), (27), DFS + (5730 - 5850 @ 80), (36) + (57000 - 66000 @ 2160), (43), NO-OUTDOOR + +If the firmware (or the BDF) is shipped with these rules then there is only +a 10 MHz overlap with the weather radar: + +* below: 5470 - 5590 +* weather radar: 5590 - 5600 +* above: (none for the rule "5470 - 5600 @ 80") + +There are several wrong assumption in the ath11k code: + +* there is always a valid range below the weather radar + (actually: there could be no range below the weather radar range OR range + could be smaller than 20 MHz) +* intersected range in the weather radar range is valid + (actually: the range could be smaller than 20 MHz) +* range above weather radar is either empty or valid + (actually: the range could be smaller than 20 MHz) + +These wrong assumption will lead in this example to a rule + + (5590 - 5600 @ 20), (N/A, 27), (600000 ms), DFS, AUTO-BW + +which is invalid according to is_valid_reg_rule() because the freq_diff is +only 10 MHz but the max_bandwidth is set to 20 MHz. Which results in a +rejection like: + + WARNING: at backports-20210222_001-4.4.60-b157d2276/net/wireless/reg.c:3984 + [...] + Call trace: + [] reg_get_max_bandwidth+0x300/0x3a8 [cfg80211] + [] regulatory_set_wiphy_regd_sync+0x3c/0x98 [cfg80211] + [] ath11k_regd_update+0x1a8/0x210 [ath11k] + [] ath11k_regd_update_work+0x18/0x20 [ath11k] + [] process_one_work+0x1f8/0x340 + [] worker_thread+0x25c/0x448 + [] kthread+0xd0/0xd8 + [] ret_from_fork+0x10/0x40 + ath11k c000000.wifi: failed to perform regd update : -22 + Invalid regulatory domain detected + +To avoid this, the algorithm has to be changed slightly. Instead of +splitting a rule which overlaps with the weather radar range into 3 pieces +and accepting the first two parts blindly, it must actually be checked for +each piece whether it is a valid range. And only if it is valid, add it to +the output array. + +When these checks are in place, the processed rules for AU would end up as + + country AU: DFS-ETSI + (2400 - 2483 @ 40), (N/A, 36), (N/A) + (5150 - 5250 @ 80), (6, 23), (N/A), NO-OUTDOOR, AUTO-BW + (5250 - 5350 @ 80), (6, 20), (0 ms), NO-OUTDOOR, DFS, AUTO-BW + (5470 - 5590 @ 80), (6, 27), (0 ms), DFS, AUTO-BW + (5650 - 5730 @ 80), (6, 27), (0 ms), DFS, AUTO-BW + (5730 - 5850 @ 80), (6, 36), (N/A), AUTO-BW + +and will be accepted by the wireless regulatory code. + +Fixes: d5c65159f289 ("ath11k: driver for Qualcomm IEEE 802.11ax devices") +Signed-off-by: Sven Eckelmann +Signed-off-by: Kalle Valo +Link: https://lore.kernel.org/r/20211112153116.1214421-1-sven@narfation.org +--- + drivers/net/wireless/ath/ath11k/reg.c | 103 ++++++++++++++------------ + 1 file changed, 56 insertions(+), 47 deletions(-) + +--- a/drivers/net/wireless/ath/ath11k/reg.c ++++ b/drivers/net/wireless/ath/ath11k/reg.c +@@ -456,6 +456,9 @@ ath11k_reg_adjust_bw(u16 start_freq, u16 + { + u16 bw; + ++ if (end_freq <= start_freq) ++ return 0; ++ + bw = end_freq - start_freq; + bw = min_t(u16, bw, max_bw); + +@@ -463,8 +466,10 @@ ath11k_reg_adjust_bw(u16 start_freq, u16 + bw = 80; + else if (bw >= 40 && bw < 80) + bw = 40; +- else if (bw < 40) ++ else if (bw >= 20 && bw < 40) + bw = 20; ++ else ++ bw = 0; + + return bw; + } +@@ -488,73 +493,77 @@ ath11k_reg_update_weather_radar_band(str + struct cur_reg_rule *reg_rule, + u8 *rule_idx, u32 flags, u16 max_bw) + { ++ u32 start_freq; + u32 end_freq; + u16 bw; + u8 i; + + i = *rule_idx; + ++ /* there might be situations when even the input rule must be dropped */ ++ i--; ++ ++ /* frequencies below weather radar */ + bw = ath11k_reg_adjust_bw(reg_rule->start_freq, + ETSI_WEATHER_RADAR_BAND_LOW, max_bw); ++ if (bw > 0) { ++ i++; + +- ath11k_reg_update_rule(regd->reg_rules + i, reg_rule->start_freq, +- ETSI_WEATHER_RADAR_BAND_LOW, bw, +- reg_rule->ant_gain, reg_rule->reg_power, +- flags); +- +- ath11k_dbg(ab, ATH11K_DBG_REG, +- "\t%d. (%d - %d @ %d) (%d, %d) (%d ms) (FLAGS %d)\n", +- i + 1, reg_rule->start_freq, ETSI_WEATHER_RADAR_BAND_LOW, +- bw, reg_rule->ant_gain, reg_rule->reg_power, +- regd->reg_rules[i].dfs_cac_ms, +- flags); +- +- if (reg_rule->end_freq > ETSI_WEATHER_RADAR_BAND_HIGH) +- end_freq = ETSI_WEATHER_RADAR_BAND_HIGH; +- else +- end_freq = reg_rule->end_freq; +- +- bw = ath11k_reg_adjust_bw(ETSI_WEATHER_RADAR_BAND_LOW, end_freq, +- max_bw); +- +- i++; ++ ath11k_reg_update_rule(regd->reg_rules + i, ++ reg_rule->start_freq, ++ ETSI_WEATHER_RADAR_BAND_LOW, bw, ++ reg_rule->ant_gain, reg_rule->reg_power, ++ flags); ++ ++ ath11k_dbg(ab, ATH11K_DBG_REG, ++ "\t%d. (%d - %d @ %d) (%d, %d) (%d ms) (FLAGS %d)\n", ++ i + 1, reg_rule->start_freq, ++ ETSI_WEATHER_RADAR_BAND_LOW, bw, reg_rule->ant_gain, ++ reg_rule->reg_power, regd->reg_rules[i].dfs_cac_ms, ++ flags); ++ } + +- ath11k_reg_update_rule(regd->reg_rules + i, +- ETSI_WEATHER_RADAR_BAND_LOW, end_freq, bw, +- reg_rule->ant_gain, reg_rule->reg_power, +- flags); +- +- regd->reg_rules[i].dfs_cac_ms = ETSI_WEATHER_RADAR_BAND_CAC_TIMEOUT; +- +- ath11k_dbg(ab, ATH11K_DBG_REG, +- "\t%d. (%d - %d @ %d) (%d, %d) (%d ms) (FLAGS %d)\n", +- i + 1, ETSI_WEATHER_RADAR_BAND_LOW, end_freq, +- bw, reg_rule->ant_gain, reg_rule->reg_power, +- regd->reg_rules[i].dfs_cac_ms, +- flags); +- +- if (end_freq == reg_rule->end_freq) { +- regd->n_reg_rules--; +- *rule_idx = i; +- return; ++ /* weather radar frequencies */ ++ start_freq = max_t(u32, reg_rule->start_freq, ++ ETSI_WEATHER_RADAR_BAND_LOW); ++ end_freq = min_t(u32, reg_rule->end_freq, ETSI_WEATHER_RADAR_BAND_HIGH); ++ ++ bw = ath11k_reg_adjust_bw(start_freq, end_freq, max_bw); ++ if (bw > 0) { ++ i++; ++ ++ ath11k_reg_update_rule(regd->reg_rules + i, start_freq, ++ end_freq, bw, reg_rule->ant_gain, ++ reg_rule->reg_power, flags); ++ ++ regd->reg_rules[i].dfs_cac_ms = ETSI_WEATHER_RADAR_BAND_CAC_TIMEOUT; ++ ++ ath11k_dbg(ab, ATH11K_DBG_REG, ++ "\t%d. (%d - %d @ %d) (%d, %d) (%d ms) (FLAGS %d)\n", ++ i + 1, start_freq, end_freq, bw, ++ reg_rule->ant_gain, reg_rule->reg_power, ++ regd->reg_rules[i].dfs_cac_ms, flags); + } + ++ /* frequencies above weather radar */ + bw = ath11k_reg_adjust_bw(ETSI_WEATHER_RADAR_BAND_HIGH, + reg_rule->end_freq, max_bw); ++ if (bw > 0) { ++ i++; + +- i++; +- +- ath11k_reg_update_rule(regd->reg_rules + i, ETSI_WEATHER_RADAR_BAND_HIGH, +- reg_rule->end_freq, bw, +- reg_rule->ant_gain, reg_rule->reg_power, +- flags); +- +- ath11k_dbg(ab, ATH11K_DBG_REG, +- "\t%d. (%d - %d @ %d) (%d, %d) (%d ms) (FLAGS %d)\n", +- i + 1, ETSI_WEATHER_RADAR_BAND_HIGH, reg_rule->end_freq, +- bw, reg_rule->ant_gain, reg_rule->reg_power, +- regd->reg_rules[i].dfs_cac_ms, +- flags); ++ ath11k_reg_update_rule(regd->reg_rules + i, ++ ETSI_WEATHER_RADAR_BAND_HIGH, ++ reg_rule->end_freq, bw, ++ reg_rule->ant_gain, reg_rule->reg_power, ++ flags); ++ ++ ath11k_dbg(ab, ATH11K_DBG_REG, ++ "\t%d. (%d - %d @ %d) (%d, %d) (%d ms) (FLAGS %d)\n", ++ i + 1, ETSI_WEATHER_RADAR_BAND_HIGH, ++ reg_rule->end_freq, bw, reg_rule->ant_gain, ++ reg_rule->reg_power, regd->reg_rules[i].dfs_cac_ms, ++ flags); ++ } + + *rule_idx = i; + } diff --git a/package/kernel/mac80211/patches/ath11k/0094-ath11k-Disabling-credit-flow-for-WMI-path.patch b/package/kernel/mac80211/patches/ath11k/0094-ath11k-Disabling-credit-flow-for-WMI-path.patch new file mode 100644 index 000000000..7ec7a68b1 --- /dev/null +++ b/package/kernel/mac80211/patches/ath11k/0094-ath11k-Disabling-credit-flow-for-WMI-path.patch @@ -0,0 +1,499 @@ +From f951380a6022440335f668f85296096ba13071ba Mon Sep 17 00:00:00 2001 +From: P Praneesh +Date: Mon, 15 Nov 2021 11:50:52 +0200 +Subject: [PATCH 094/120] ath11k: Disabling credit flow for WMI path + +Firmware credit flow control is enabled for WMI control services, +which expects available tokens should be acquired before sending a +command to the target. Also the token gets released when firmware +receives the command. + +This credit-based flow limits driver to send WMI command only +when the token available which is causing WMI commands to timeout and +return -EAGAIN, whereas firmware has enough capability to process the +WMI command. To fix this Tx starvation issue, introduce the ability to +disable the credit flow for the WMI path. + +The driver sends WMI configuration for disabling credit flow to firmware +by two ways. + 1. By using a global flag + (HTC_MSG_SETUP_COMPLETE_EX_ID msg type flags) + 2. By using a local flag + (ATH11K_HTC_CONN_FLAGS_DISABLE_CREDIT_FLOW_CTRL = 1 << 3) + +Ath11k uses both these configurations to disable credit flow for the +WMI path completely. + +Also added a hw_param member for credit flow control by which we can +enable or disable it based on per-target basis. Currently we are disabling +credit flow for IPQ8074, IPQ6018, and QCN9074 as recommended by firmware. + +Tested-on: IPQ8074 hw2.0 AHB WLAN.HK.2.4.0.1-01492-QCAHKSWPL_SILICONZ-1 +Tested-on: IPQ6018 hw1.0 AHB WLAN.HK.2.4.0.1-00330-QCAHKSWPL_SILICONZ-1 + +Co-developed-by: Pravas Kumar Panda +Signed-off-by: Pravas Kumar Panda +Signed-off-by: P Praneesh +Signed-off-by: Kalle Valo +Link: https://lore.kernel.org/r/1635156494-20059-1-git-send-email-quic_ppranees@quicinc.com +--- + drivers/net/wireless/ath/ath11k/ce.c | 37 +++++++++++--- + drivers/net/wireless/ath/ath11k/ce.h | 3 +- + drivers/net/wireless/ath/ath11k/core.c | 5 ++ + drivers/net/wireless/ath/ath11k/htc.c | 71 +++++++++++++++++++------- + drivers/net/wireless/ath/ath11k/htc.h | 9 ++-- + drivers/net/wireless/ath/ath11k/hw.h | 1 + + drivers/net/wireless/ath/ath11k/wmi.c | 54 +++++++++++++++++--- + drivers/net/wireless/ath/ath11k/wmi.h | 1 + + 8 files changed, 146 insertions(+), 35 deletions(-) + +--- a/drivers/net/wireless/ath/ath11k/ce.c ++++ b/drivers/net/wireless/ath/ath11k/ce.c +@@ -14,6 +14,7 @@ const struct ce_attr ath11k_host_ce_conf + .src_nentries = 16, + .src_sz_max = 2048, + .dest_nentries = 0, ++ .send_cb = ath11k_htc_tx_completion_handler, + }, + + /* CE1: target->host HTT + HTC control */ +@@ -40,6 +41,7 @@ const struct ce_attr ath11k_host_ce_conf + .src_nentries = 32, + .src_sz_max = 2048, + .dest_nentries = 0, ++ .send_cb = ath11k_htc_tx_completion_handler, + }, + + /* CE4: host->target HTT */ +@@ -73,6 +75,7 @@ const struct ce_attr ath11k_host_ce_conf + .src_nentries = 32, + .src_sz_max = 2048, + .dest_nentries = 0, ++ .send_cb = ath11k_htc_tx_completion_handler, + }, + + /* CE8: target autonomous hif_memcpy */ +@@ -89,6 +92,7 @@ const struct ce_attr ath11k_host_ce_conf + .src_nentries = 32, + .src_sz_max = 2048, + .dest_nentries = 0, ++ .send_cb = ath11k_htc_tx_completion_handler, + }, + + /* CE10: target->host HTT */ +@@ -142,6 +146,7 @@ const struct ce_attr ath11k_host_ce_conf + .src_nentries = 32, + .src_sz_max = 2048, + .dest_nentries = 0, ++ .send_cb = ath11k_htc_tx_completion_handler, + }, + + /* CE4: host->target HTT */ +@@ -175,6 +180,7 @@ const struct ce_attr ath11k_host_ce_conf + .src_nentries = 32, + .src_sz_max = 2048, + .dest_nentries = 0, ++ .send_cb = ath11k_htc_tx_completion_handler, + }, + + /* CE8: target autonomous hif_memcpy */ +@@ -220,6 +226,7 @@ const struct ce_attr ath11k_host_ce_conf + .src_nentries = 32, + .src_sz_max = 2048, + .dest_nentries = 0, ++ .send_cb = ath11k_htc_tx_completion_handler, + }, + + /* CE4: host->target HTT */ +@@ -489,18 +496,32 @@ err_unlock: + return skb; + } + +-static void ath11k_ce_send_done_cb(struct ath11k_ce_pipe *pipe) ++static void ath11k_ce_tx_process_cb(struct ath11k_ce_pipe *pipe) + { + struct ath11k_base *ab = pipe->ab; + struct sk_buff *skb; ++ struct sk_buff_head list; + ++ __skb_queue_head_init(&list); + while (!IS_ERR(skb = ath11k_ce_completed_send_next(pipe))) { + if (!skb) + continue; + + dma_unmap_single(ab->dev, ATH11K_SKB_CB(skb)->paddr, skb->len, + DMA_TO_DEVICE); +- dev_kfree_skb_any(skb); ++ ++ if ((!pipe->send_cb) || ab->hw_params.credit_flow) { ++ dev_kfree_skb_any(skb); ++ continue; ++ } ++ ++ __skb_queue_tail(&list, skb); ++ } ++ ++ while ((skb = __skb_dequeue(&list))) { ++ ath11k_dbg(ab, ATH11K_DBG_AHB, "tx ce pipe %d len %d\n", ++ pipe->pipe_num, skb->len); ++ pipe->send_cb(ab, skb); + } + } + +@@ -636,7 +657,7 @@ static int ath11k_ce_alloc_pipe(struct a + pipe->attr_flags = attr->flags; + + if (attr->src_nentries) { +- pipe->send_cb = ath11k_ce_send_done_cb; ++ pipe->send_cb = attr->send_cb; + nentries = roundup_pow_of_two(attr->src_nentries); + desc_sz = ath11k_hal_ce_get_desc_size(HAL_CE_DESC_SRC); + ring = ath11k_ce_alloc_ring(ab, nentries, desc_sz); +@@ -667,9 +688,10 @@ static int ath11k_ce_alloc_pipe(struct a + void ath11k_ce_per_engine_service(struct ath11k_base *ab, u16 ce_id) + { + struct ath11k_ce_pipe *pipe = &ab->ce.ce_pipe[ce_id]; ++ const struct ce_attr *attr = &ab->hw_params.host_ce_config[ce_id]; + +- if (pipe->send_cb) +- pipe->send_cb(pipe); ++ if (attr->src_nentries) ++ ath11k_ce_tx_process_cb(pipe); + + if (pipe->recv_cb) + ath11k_ce_recv_process_cb(pipe); +@@ -678,9 +700,10 @@ void ath11k_ce_per_engine_service(struct + void ath11k_ce_poll_send_completed(struct ath11k_base *ab, u8 pipe_id) + { + struct ath11k_ce_pipe *pipe = &ab->ce.ce_pipe[pipe_id]; ++ const struct ce_attr *attr = &ab->hw_params.host_ce_config[pipe_id]; + +- if ((pipe->attr_flags & CE_ATTR_DIS_INTR) && pipe->send_cb) +- pipe->send_cb(pipe); ++ if ((pipe->attr_flags & CE_ATTR_DIS_INTR) && attr->src_nentries) ++ ath11k_ce_tx_process_cb(pipe); + } + EXPORT_SYMBOL(ath11k_ce_per_engine_service); + +--- a/drivers/net/wireless/ath/ath11k/ce.h ++++ b/drivers/net/wireless/ath/ath11k/ce.h +@@ -101,6 +101,7 @@ struct ce_attr { + unsigned int dest_nentries; + + void (*recv_cb)(struct ath11k_base *, struct sk_buff *); ++ void (*send_cb)(struct ath11k_base *, struct sk_buff *); + }; + + #define CE_DESC_RING_ALIGN 8 +@@ -154,7 +155,7 @@ struct ath11k_ce_pipe { + unsigned int buf_sz; + unsigned int rx_buf_needed; + +- void (*send_cb)(struct ath11k_ce_pipe *); ++ void (*send_cb)(struct ath11k_base *, struct sk_buff *); + void (*recv_cb)(struct ath11k_base *, struct sk_buff *); + + struct tasklet_struct intr_tq; +--- a/drivers/net/wireless/ath/ath11k/core.c ++++ b/drivers/net/wireless/ath/ath11k/core.c +@@ -81,6 +81,7 @@ static const struct ath11k_hw_params ath + .supports_suspend = false, + .hal_desc_sz = sizeof(struct hal_rx_desc_ipq8074), + .fix_l1ss = true, ++ .credit_flow = false, + .max_tx_ring = DP_TCL_NUM_RING_MAX, + .hal_params = &ath11k_hw_hal_params_ipq8074, + .supports_dynamic_smps_6ghz = false, +@@ -133,6 +134,7 @@ static const struct ath11k_hw_params ath + .supports_suspend = false, + .hal_desc_sz = sizeof(struct hal_rx_desc_ipq8074), + .fix_l1ss = true, ++ .credit_flow = false, + .max_tx_ring = DP_TCL_NUM_RING_MAX, + .hal_params = &ath11k_hw_hal_params_ipq8074, + .supports_dynamic_smps_6ghz = false, +@@ -184,6 +186,7 @@ static const struct ath11k_hw_params ath + .supports_suspend = true, + .hal_desc_sz = sizeof(struct hal_rx_desc_ipq8074), + .fix_l1ss = true, ++ .credit_flow = true, + .max_tx_ring = DP_TCL_NUM_RING_MAX_QCA6390, + .hal_params = &ath11k_hw_hal_params_qca6390, + .supports_dynamic_smps_6ghz = false, +@@ -235,6 +238,7 @@ static const struct ath11k_hw_params ath + .supports_suspend = false, + .hal_desc_sz = sizeof(struct hal_rx_desc_qcn9074), + .fix_l1ss = true, ++ .credit_flow = false, + .max_tx_ring = DP_TCL_NUM_RING_MAX, + .hal_params = &ath11k_hw_hal_params_ipq8074, + .supports_dynamic_smps_6ghz = true, +@@ -286,6 +290,7 @@ static const struct ath11k_hw_params ath + .supports_suspend = true, + .hal_desc_sz = sizeof(struct hal_rx_desc_wcn6855), + .fix_l1ss = false, ++ .credit_flow = true, + .max_tx_ring = DP_TCL_NUM_RING_MAX_QCA6390, + .hal_params = &ath11k_hw_hal_params_qca6390, + .supports_dynamic_smps_6ghz = false, +--- a/drivers/net/wireless/ath/ath11k/htc.c ++++ b/drivers/net/wireless/ath/ath11k/htc.c +@@ -81,6 +81,8 @@ int ath11k_htc_send(struct ath11k_htc *h + struct ath11k_base *ab = htc->ab; + int credits = 0; + int ret; ++ bool credit_flow_enabled = (ab->hw_params.credit_flow && ++ ep->tx_credit_flow_enabled); + + if (eid >= ATH11K_HTC_EP_COUNT) { + ath11k_warn(ab, "Invalid endpoint id: %d\n", eid); +@@ -89,7 +91,7 @@ int ath11k_htc_send(struct ath11k_htc *h + + skb_push(skb, sizeof(struct ath11k_htc_hdr)); + +- if (ep->tx_credit_flow_enabled) { ++ if (credit_flow_enabled) { + credits = DIV_ROUND_UP(skb->len, htc->target_credit_size); + spin_lock_bh(&htc->tx_lock); + if (ep->tx_credits < credits) { +@@ -126,7 +128,7 @@ int ath11k_htc_send(struct ath11k_htc *h + err_unmap: + dma_unmap_single(dev, skb_cb->paddr, skb->len, DMA_TO_DEVICE); + err_credits: +- if (ep->tx_credit_flow_enabled) { ++ if (credit_flow_enabled) { + spin_lock_bh(&htc->tx_lock); + ep->tx_credits += credits; + ath11k_dbg(ab, ATH11K_DBG_HTC, +@@ -203,23 +205,25 @@ static int ath11k_htc_process_trailer(st + break; + } + +- switch (record->hdr.id) { +- case ATH11K_HTC_RECORD_CREDITS: +- len = sizeof(struct ath11k_htc_credit_report); +- if (record->hdr.len < len) { +- ath11k_warn(ab, "Credit report too long\n"); +- status = -EINVAL; ++ if (ab->hw_params.credit_flow) { ++ switch (record->hdr.id) { ++ case ATH11K_HTC_RECORD_CREDITS: ++ len = sizeof(struct ath11k_htc_credit_report); ++ if (record->hdr.len < len) { ++ ath11k_warn(ab, "Credit report too long\n"); ++ status = -EINVAL; ++ break; ++ } ++ ath11k_htc_process_credit_report(htc, ++ record->credit_report, ++ record->hdr.len, ++ src_eid); ++ break; ++ default: ++ ath11k_warn(ab, "Unhandled record: id:%d length:%d\n", ++ record->hdr.id, record->hdr.len); + break; + } +- ath11k_htc_process_credit_report(htc, +- record->credit_report, +- record->hdr.len, +- src_eid); +- break; +- default: +- ath11k_warn(ab, "Unhandled record: id:%d length:%d\n", +- record->hdr.id, record->hdr.len); +- break; + } + + if (status) +@@ -245,6 +249,29 @@ static void ath11k_htc_suspend_complete( + complete(&ab->htc_suspend); + } + ++void ath11k_htc_tx_completion_handler(struct ath11k_base *ab, ++ struct sk_buff *skb) ++{ ++ struct ath11k_htc *htc = &ab->htc; ++ struct ath11k_htc_ep *ep; ++ void (*ep_tx_complete)(struct ath11k_base *, struct sk_buff *); ++ u8 eid; ++ ++ eid = ATH11K_SKB_CB(skb)->eid; ++ if (eid >= ATH11K_HTC_EP_COUNT) ++ return; ++ ++ ep = &htc->endpoint[eid]; ++ spin_lock_bh(&htc->tx_lock); ++ ep_tx_complete = ep->ep_ops.ep_tx_complete; ++ spin_unlock_bh(&htc->tx_lock); ++ if (!ep_tx_complete) { ++ dev_kfree_skb_any(skb); ++ return; ++ } ++ ep_tx_complete(htc->ab, skb); ++} ++ + void ath11k_htc_rx_completion_handler(struct ath11k_base *ab, + struct sk_buff *skb) + { +@@ -607,6 +634,11 @@ int ath11k_htc_connect_service(struct at + disable_credit_flow_ctrl = true; + } + ++ if (!ab->hw_params.credit_flow) { ++ flags |= ATH11K_HTC_CONN_FLAGS_DISABLE_CREDIT_FLOW_CTRL; ++ disable_credit_flow_ctrl = true; ++ } ++ + req_msg->flags_len = FIELD_PREP(HTC_SVC_MSG_CONNECTIONFLAGS, flags); + req_msg->msg_svc_id |= FIELD_PREP(HTC_SVC_MSG_SERVICE_ID, + conn_req->service_id); +@@ -732,7 +764,10 @@ int ath11k_htc_start(struct ath11k_htc * + msg->msg_id = FIELD_PREP(HTC_MSG_MESSAGEID, + ATH11K_HTC_MSG_SETUP_COMPLETE_EX_ID); + +- ath11k_dbg(ab, ATH11K_DBG_HTC, "HTC is using TX credit flow control\n"); ++ if (ab->hw_params.credit_flow) ++ ath11k_dbg(ab, ATH11K_DBG_HTC, "HTC is using TX credit flow control\n"); ++ else ++ msg->flags |= ATH11K_GLOBAL_DISABLE_CREDIT_FLOW; + + status = ath11k_htc_send(htc, ATH11K_HTC_EP_0, skb); + if (status) { +--- a/drivers/net/wireless/ath/ath11k/htc.h ++++ b/drivers/net/wireless/ath/ath11k/htc.h +@@ -83,8 +83,8 @@ enum ath11k_htc_conn_flags { + ATH11K_HTC_CONN_FLAGS_THRESHOLD_LEVEL_ONE_HALF = 0x1, + ATH11K_HTC_CONN_FLAGS_THRESHOLD_LEVEL_THREE_FOURTHS = 0x2, + ATH11K_HTC_CONN_FLAGS_THRESHOLD_LEVEL_UNITY = 0x3, +- ATH11K_HTC_CONN_FLAGS_REDUCE_CREDIT_DRIBBLE = 1 << 2, +- ATH11K_HTC_CONN_FLAGS_DISABLE_CREDIT_FLOW_CTRL = 1 << 3 ++ ATH11K_HTC_CONN_FLAGS_REDUCE_CREDIT_DRIBBLE = 0x4, ++ ATH11K_HTC_CONN_FLAGS_DISABLE_CREDIT_FLOW_CTRL = 0x8, + }; + + enum ath11k_htc_conn_svc_status { +@@ -116,6 +116,8 @@ struct ath11k_htc_conn_svc_resp { + u32 svc_meta_pad; + } __packed; + ++#define ATH11K_GLOBAL_DISABLE_CREDIT_FLOW BIT(1) ++ + struct ath11k_htc_setup_complete_extended { + u32 msg_id; + u32 flags; +@@ -305,5 +307,6 @@ int ath11k_htc_send(struct ath11k_htc *h + struct sk_buff *ath11k_htc_alloc_skb(struct ath11k_base *ar, int size); + void ath11k_htc_rx_completion_handler(struct ath11k_base *ar, + struct sk_buff *skb); +- ++void ath11k_htc_tx_completion_handler(struct ath11k_base *ab, ++ struct sk_buff *skb); + #endif +--- a/drivers/net/wireless/ath/ath11k/hw.h ++++ b/drivers/net/wireless/ath/ath11k/hw.h +@@ -175,6 +175,7 @@ struct ath11k_hw_params { + bool supports_suspend; + u32 hal_desc_sz; + bool fix_l1ss; ++ bool credit_flow; + u8 max_tx_ring; + const struct ath11k_hw_hal_params *hal_params; + bool supports_dynamic_smps_6ghz; +--- a/drivers/net/wireless/ath/ath11k/wmi.c ++++ b/drivers/net/wireless/ath/ath11k/wmi.c +@@ -267,21 +267,39 @@ int ath11k_wmi_cmd_send(struct ath11k_pd + { + struct ath11k_wmi_base *wmi_sc = wmi->wmi_ab; + int ret = -EOPNOTSUPP; ++ struct ath11k_base *ab = wmi_sc->ab; + + might_sleep(); + +- wait_event_timeout(wmi_sc->tx_credits_wq, ({ +- ret = ath11k_wmi_cmd_send_nowait(wmi, skb, cmd_id); ++ if (ab->hw_params.credit_flow) { ++ wait_event_timeout(wmi_sc->tx_credits_wq, ({ ++ ret = ath11k_wmi_cmd_send_nowait(wmi, skb, cmd_id); ++ ++ if (ret && test_bit(ATH11K_FLAG_CRASH_FLUSH, ++ &wmi_sc->ab->dev_flags)) ++ ret = -ESHUTDOWN; ++ ++ (ret != -EAGAIN); ++ }), WMI_SEND_TIMEOUT_HZ); ++ } else { ++ wait_event_timeout(wmi->tx_ce_desc_wq, ({ ++ ret = ath11k_wmi_cmd_send_nowait(wmi, skb, cmd_id); + +- if (ret && test_bit(ATH11K_FLAG_CRASH_FLUSH, &wmi_sc->ab->dev_flags)) +- ret = -ESHUTDOWN; ++ if (ret && test_bit(ATH11K_FLAG_CRASH_FLUSH, ++ &wmi_sc->ab->dev_flags)) ++ ret = -ESHUTDOWN; + +- (ret != -EAGAIN); +- }), WMI_SEND_TIMEOUT_HZ); ++ (ret != -ENOBUFS); ++ }), WMI_SEND_TIMEOUT_HZ); ++ } + + if (ret == -EAGAIN) + ath11k_warn(wmi_sc->ab, "wmi command %d timeout\n", cmd_id); + ++ if (ret == -ENOBUFS) ++ ath11k_warn(wmi_sc->ab, "ce desc not available for wmi command %d\n", ++ cmd_id); ++ + return ret; + } + +@@ -5816,7 +5834,30 @@ static void ath11k_wmi_op_ep_tx_credits( + static void ath11k_wmi_htc_tx_complete(struct ath11k_base *ab, + struct sk_buff *skb) + { ++ struct ath11k_pdev_wmi *wmi = NULL; ++ u32 i; ++ u8 wmi_ep_count; ++ u8 eid; ++ ++ eid = ATH11K_SKB_CB(skb)->eid; + dev_kfree_skb(skb); ++ ++ if (eid >= ATH11K_HTC_EP_COUNT) ++ return; ++ ++ wmi_ep_count = ab->htc.wmi_ep_count; ++ if (wmi_ep_count > ab->hw_params.max_radios) ++ return; ++ ++ for (i = 0; i < ab->htc.wmi_ep_count; i++) { ++ if (ab->wmi_ab.wmi[i].eid == eid) { ++ wmi = &ab->wmi_ab.wmi[i]; ++ break; ++ } ++ } ++ ++ if (wmi) ++ wake_up(&wmi->tx_ce_desc_wq); + } + + static bool ath11k_reg_is_world_alpha(char *alpha) +@@ -7207,6 +7248,7 @@ static int ath11k_connect_pdev_htc_servi + ab->wmi_ab.wmi_endpoint_id[pdev_idx] = conn_resp.eid; + ab->wmi_ab.wmi[pdev_idx].eid = conn_resp.eid; + ab->wmi_ab.max_msg_len[pdev_idx] = conn_resp.max_msg_len; ++ init_waitqueue_head(&ab->wmi_ab.wmi[pdev_idx].tx_ce_desc_wq); + + return 0; + } +--- a/drivers/net/wireless/ath/ath11k/wmi.h ++++ b/drivers/net/wireless/ath/ath11k/wmi.h +@@ -2522,6 +2522,7 @@ struct ath11k_pdev_wmi { + enum ath11k_htc_ep_id eid; + const struct wmi_peer_flags_map *peer_flags; + u32 rx_decap_mode; ++ wait_queue_head_t tx_ce_desc_wq; + }; + + struct vdev_create_params { diff --git a/package/kernel/mac80211/patches/ath11k/0095-ath11k-use-cache-line-aligned-buffers-for-dbring.patch b/package/kernel/mac80211/patches/ath11k/0095-ath11k-use-cache-line-aligned-buffers-for-dbring.patch new file mode 100644 index 000000000..b1027665a --- /dev/null +++ b/package/kernel/mac80211/patches/ath11k/0095-ath11k-use-cache-line-aligned-buffers-for-dbring.patch @@ -0,0 +1,91 @@ +From bd77f6b1d7104cf6451399a7c67d08afecb9a7c7 Mon Sep 17 00:00:00 2001 +From: Rameshkumar Sundaram +Date: Tue, 2 Nov 2021 11:11:33 +0530 +Subject: [PATCH 095/120] ath11k: use cache line aligned buffers for dbring + +The DMA buffers of dbring which is used for spectral/cfr +starts at certain offset from original kmalloc() returned buffer. +This is not cache line aligned. +And also driver tries to access the data that is immediately before +this offset address (i.e. buff->paddr) after doing dma map. +This will cause cache line sharing issues and data corruption, +if CPU happen to write back cache after HW has dma'ed the data. + +Fix this by mapping a cache line aligned buffer to dma. + +Tested on: IPQ8074 hw2.0 AHB WLAN.HK.2.5.0.1-01100-QCAHKSWPL_SILICONZ-1 + +Signed-off-by: Rameshkumar Sundaram +Signed-off-by: Kalle Valo +Link: https://lore.kernel.org/r/1635831693-15962-1-git-send-email-quic_ramess@quicinc.com +--- + drivers/net/wireless/ath/ath11k/dbring.c | 16 ++++++++++++---- + drivers/net/wireless/ath/ath11k/dbring.h | 2 +- + 2 files changed, 13 insertions(+), 5 deletions(-) + +--- a/drivers/net/wireless/ath/ath11k/dbring.c ++++ b/drivers/net/wireless/ath/ath11k/dbring.c +@@ -87,17 +87,23 @@ static int ath11k_dbring_fill_bufs(struc + req_entries = min(num_free, ring->bufs_max); + num_remain = req_entries; + align = ring->buf_align; +- size = sizeof(*buff) + ring->buf_sz + align - 1; ++ size = ring->buf_sz + align - 1; + + while (num_remain > 0) { +- buff = kzalloc(size, GFP_ATOMIC); ++ buff = kzalloc(sizeof(*buff), GFP_ATOMIC); + if (!buff) + break; + ++ buff->payload = kzalloc(size, GFP_ATOMIC); ++ if (!buff->payload) { ++ kfree(buff); ++ break; ++ } + ret = ath11k_dbring_bufs_replenish(ar, ring, buff); + if (ret) { + ath11k_warn(ar->ab, "failed to replenish db ring num_remain %d req_ent %d\n", + num_remain, req_entries); ++ kfree(buff->payload); + kfree(buff); + break; + } +@@ -282,7 +288,7 @@ int ath11k_dbring_buffer_release_event(s + + srng = &ab->hal.srng_list[ring->refill_srng.ring_id]; + num_entry = ev->fixed.num_buf_release_entry; +- size = sizeof(*buff) + ring->buf_sz + ring->buf_align - 1; ++ size = ring->buf_sz + ring->buf_align - 1; + num_buff_reaped = 0; + + spin_lock_bh(&srng->lock); +@@ -319,7 +325,8 @@ int ath11k_dbring_buffer_release_event(s + ring->handler(ar, &handler_data); + } + +- memset(buff, 0, size); ++ buff->paddr = 0; ++ memset(buff->payload, 0, size); + ath11k_dbring_bufs_replenish(ar, ring, buff); + } + +@@ -346,6 +353,7 @@ void ath11k_dbring_buf_cleanup(struct at + idr_remove(&ring->bufs_idr, buf_id); + dma_unmap_single(ar->ab->dev, buff->paddr, + ring->buf_sz, DMA_FROM_DEVICE); ++ kfree(buff->payload); + kfree(buff); + } + +--- a/drivers/net/wireless/ath/ath11k/dbring.h ++++ b/drivers/net/wireless/ath/ath11k/dbring.h +@@ -13,7 +13,7 @@ + + struct ath11k_dbring_element { + dma_addr_t paddr; +- u8 payload[0]; ++ u8 *payload; + }; + + struct ath11k_dbring_data { diff --git a/package/kernel/mac80211/patches/ath11k/0096-ath11k-Add-missing-qmi_txn_cancel.patch b/package/kernel/mac80211/patches/ath11k/0096-ath11k-Add-missing-qmi_txn_cancel.patch new file mode 100644 index 000000000..98333bf3b --- /dev/null +++ b/package/kernel/mac80211/patches/ath11k/0096-ath11k-Add-missing-qmi_txn_cancel.patch @@ -0,0 +1,142 @@ +From 1ad6e4b00f29d017b196dda7ab96d1cfcbabd7d2 Mon Sep 17 00:00:00 2001 +From: Anilkumar Kolli +Date: Tue, 2 Nov 2021 18:22:38 +0530 +Subject: [PATCH 096/120] ath11k: Add missing qmi_txn_cancel() + +Currently many functions do not follow this guidance when +qmi_send_request() fails, therefore add missing +qmi_txn_cancel() in the qmi_send_request() error path. + +Also remove initialization on 'struct qmi_txn' +since qmi_tx_init() performs all necessary initialization. + +Tested-on: QCN9074 hw1.0 PCI WLAN.HK.2.4.0.1-01838-QCAHKSWPL_SILICONZ-1 + +Signed-off-by: Anilkumar Kolli +Signed-off-by: Kalle Valo +Link: https://lore.kernel.org/r/1635857558-21733-1-git-send-email-akolli@codeaurora.org +--- + drivers/net/wireless/ath/ath11k/qmi.c | 21 ++++++++++++++------- + 1 file changed, 14 insertions(+), 7 deletions(-) + +--- a/drivers/net/wireless/ath/ath11k/qmi.c ++++ b/drivers/net/wireless/ath/ath11k/qmi.c +@@ -1586,7 +1586,7 @@ static int ath11k_qmi_host_cap_send(stru + { + struct qmi_wlanfw_host_cap_req_msg_v01 req; + struct qmi_wlanfw_host_cap_resp_msg_v01 resp; +- struct qmi_txn txn = {}; ++ struct qmi_txn txn; + int ret = 0; + + memset(&req, 0, sizeof(req)); +@@ -1640,6 +1640,7 @@ static int ath11k_qmi_host_cap_send(stru + QMI_WLANFW_HOST_CAP_REQ_MSG_V01_MAX_LEN, + qmi_wlanfw_host_cap_req_msg_v01_ei, &req); + if (ret < 0) { ++ qmi_txn_cancel(&txn); + ath11k_warn(ab, "failed to send host capability request: %d\n", ret); + goto out; + } +@@ -1705,6 +1706,7 @@ static int ath11k_qmi_fw_ind_register_se + QMI_WLANFW_IND_REGISTER_REQ_MSG_V01_MAX_LEN, + qmi_wlanfw_ind_register_req_msg_v01_ei, req); + if (ret < 0) { ++ qmi_txn_cancel(&txn); + ath11k_warn(ab, "failed to send indication register request: %d\n", + ret); + goto out; +@@ -1734,7 +1736,7 @@ static int ath11k_qmi_respond_fw_mem_req + { + struct qmi_wlanfw_respond_mem_req_msg_v01 *req; + struct qmi_wlanfw_respond_mem_resp_msg_v01 resp; +- struct qmi_txn txn = {}; ++ struct qmi_txn txn; + int ret = 0, i; + bool delayed; + +@@ -1783,6 +1785,7 @@ static int ath11k_qmi_respond_fw_mem_req + QMI_WLANFW_RESPOND_MEM_REQ_MSG_V01_MAX_LEN, + qmi_wlanfw_respond_mem_req_msg_v01_ei, req); + if (ret < 0) { ++ qmi_txn_cancel(&txn); + ath11k_warn(ab, "failed to respond qmi memory request: %d\n", + ret); + goto out; +@@ -1911,7 +1914,7 @@ static int ath11k_qmi_request_target_cap + { + struct qmi_wlanfw_cap_req_msg_v01 req; + struct qmi_wlanfw_cap_resp_msg_v01 resp; +- struct qmi_txn txn = {}; ++ struct qmi_txn txn; + int ret = 0; + int r; + +@@ -1930,6 +1933,7 @@ static int ath11k_qmi_request_target_cap + QMI_WLANFW_CAP_REQ_MSG_V01_MAX_LEN, + qmi_wlanfw_cap_req_msg_v01_ei, &req); + if (ret < 0) { ++ qmi_txn_cancel(&txn); + ath11k_warn(ab, "failed to send qmi cap request: %d\n", + ret); + goto out; +@@ -2000,7 +2004,7 @@ static int ath11k_qmi_load_file_target_m + { + struct qmi_wlanfw_bdf_download_req_msg_v01 *req; + struct qmi_wlanfw_bdf_download_resp_msg_v01 resp; +- struct qmi_txn txn = {}; ++ struct qmi_txn txn; + const u8 *temp = data; + void __iomem *bdf_addr = NULL; + int ret; +@@ -2245,7 +2249,7 @@ static int ath11k_qmi_wlanfw_m3_info_sen + struct m3_mem_region *m3_mem = &ab->qmi.m3_mem; + struct qmi_wlanfw_m3_info_req_msg_v01 req; + struct qmi_wlanfw_m3_info_resp_msg_v01 resp; +- struct qmi_txn txn = {}; ++ struct qmi_txn txn; + int ret = 0; + + memset(&req, 0, sizeof(req)); +@@ -2277,6 +2281,7 @@ static int ath11k_qmi_wlanfw_m3_info_sen + QMI_WLANFW_M3_INFO_REQ_MSG_V01_MAX_MSG_LEN, + qmi_wlanfw_m3_info_req_msg_v01_ei, &req); + if (ret < 0) { ++ qmi_txn_cancel(&txn); + ath11k_warn(ab, "failed to send m3 information request: %d\n", + ret); + goto out; +@@ -2303,7 +2308,7 @@ static int ath11k_qmi_wlanfw_mode_send(s + { + struct qmi_wlanfw_wlan_mode_req_msg_v01 req; + struct qmi_wlanfw_wlan_mode_resp_msg_v01 resp; +- struct qmi_txn txn = {}; ++ struct qmi_txn txn; + int ret = 0; + + memset(&req, 0, sizeof(req)); +@@ -2325,6 +2330,7 @@ static int ath11k_qmi_wlanfw_mode_send(s + QMI_WLANFW_WLAN_MODE_REQ_MSG_V01_MAX_LEN, + qmi_wlanfw_wlan_mode_req_msg_v01_ei, &req); + if (ret < 0) { ++ qmi_txn_cancel(&txn); + ath11k_warn(ab, "failed to send wlan mode request (mode %d): %d\n", + mode, ret); + goto out; +@@ -2358,7 +2364,7 @@ static int ath11k_qmi_wlanfw_wlan_cfg_se + struct qmi_wlanfw_wlan_cfg_resp_msg_v01 resp; + struct ce_pipe_config *ce_cfg; + struct service_to_pipe *svc_cfg; +- struct qmi_txn txn = {}; ++ struct qmi_txn txn; + int ret = 0, pipe_num; + + ce_cfg = (struct ce_pipe_config *)ab->qmi.ce_cfg.tgt_ce; +@@ -2419,6 +2425,7 @@ static int ath11k_qmi_wlanfw_wlan_cfg_se + QMI_WLANFW_WLAN_CFG_REQ_MSG_V01_MAX_LEN, + qmi_wlanfw_wlan_cfg_req_msg_v01_ei, req); + if (ret < 0) { ++ qmi_txn_cancel(&txn); + ath11k_warn(ab, "failed to send wlan config request: %d\n", + ret); + goto out; diff --git a/package/kernel/mac80211/patches/ath11k/0097-ath11k-add-trace-log-support.patch b/package/kernel/mac80211/patches/ath11k/0097-ath11k-add-trace-log-support.patch new file mode 100644 index 000000000..29f7453f1 --- /dev/null +++ b/package/kernel/mac80211/patches/ath11k/0097-ath11k-add-trace-log-support.patch @@ -0,0 +1,309 @@ +From fb12305aff12e735e599c79514dde5dac40f5a59 Mon Sep 17 00:00:00 2001 +From: Venkateswara Naralasetty +Date: Tue, 9 Nov 2021 12:05:55 +0530 +Subject: [PATCH 097/120] ath11k: add trace log support + +This change is to add trace log support for, + * WMI events + * WMI commands + * ath11k_dbg messages + * ath11k_dbg_dump messages + * ath11k_log_info messages + * ath11k_log_warn messages + * ath11k_log_err messages + +Tested-on: IPQ8074 hw2.0 AHB WLAN.HK.2.5.0.1-00652-QCAHKSWPL_SILICONZ-1 + +Signed-off-by: Venkateswara Naralasetty +Signed-off-by: Kalle Valo +Link: https://lore.kernel.org/r/1636439755-30419-1-git-send-email-quic_vnaralas@quicinc.com +--- + drivers/net/wireless/ath/ath11k/debug.c | 12 +- + drivers/net/wireless/ath/ath11k/debug.h | 3 +- + drivers/net/wireless/ath/ath11k/trace.c | 1 + + drivers/net/wireless/ath/ath11k/trace.h | 172 ++++++++++++++++++++++++ + drivers/net/wireless/ath/ath11k/wmi.c | 4 + + 5 files changed, 187 insertions(+), 5 deletions(-) + +--- a/drivers/net/wireless/ath/ath11k/debug.c ++++ b/drivers/net/wireless/ath/ath11k/debug.c +@@ -17,7 +17,7 @@ void ath11k_info(struct ath11k_base *ab, + va_start(args, fmt); + vaf.va = &args; + dev_info(ab->dev, "%pV", &vaf); +- /* TODO: Trace the log */ ++ trace_ath11k_log_info(ab, &vaf); + va_end(args); + } + EXPORT_SYMBOL(ath11k_info); +@@ -32,7 +32,7 @@ void ath11k_err(struct ath11k_base *ab, + va_start(args, fmt); + vaf.va = &args; + dev_err(ab->dev, "%pV", &vaf); +- /* TODO: Trace the log */ ++ trace_ath11k_log_err(ab, &vaf); + va_end(args); + } + EXPORT_SYMBOL(ath11k_err); +@@ -47,7 +47,7 @@ void ath11k_warn(struct ath11k_base *ab, + va_start(args, fmt); + vaf.va = &args; + dev_warn_ratelimited(ab->dev, "%pV", &vaf); +- /* TODO: Trace the log */ ++ trace_ath11k_log_warn(ab, &vaf); + va_end(args); + } + EXPORT_SYMBOL(ath11k_warn); +@@ -68,7 +68,7 @@ void __ath11k_dbg(struct ath11k_base *ab + if (ath11k_debug_mask & mask) + dev_printk(KERN_DEBUG, ab->dev, "%pV", &vaf); + +- /* TODO: trace log */ ++ trace_ath11k_log_dbg(ab, mask, &vaf); + + va_end(args); + } +@@ -100,6 +100,10 @@ void ath11k_dbg_dump(struct ath11k_base + dev_printk(KERN_DEBUG, ab->dev, "%s\n", linebuf); + } + } ++ ++ /* tracing code doesn't like null strings */ ++ trace_ath11k_log_dbg_dump(ab, msg ? msg : "", prefix ? prefix : "", ++ buf, len); + } + EXPORT_SYMBOL(ath11k_dbg_dump); + +--- a/drivers/net/wireless/ath/ath11k/debug.h ++++ b/drivers/net/wireless/ath/ath11k/debug.h +@@ -60,7 +60,8 @@ static inline void ath11k_dbg_dump(struc + + #define ath11k_dbg(ar, dbg_mask, fmt, ...) \ + do { \ +- if (ath11k_debug_mask & dbg_mask) \ ++ if ((ath11k_debug_mask & dbg_mask) || \ ++ trace_ath11k_log_dbg_enabled()) \ + __ath11k_dbg(ar, dbg_mask, fmt, ##__VA_ARGS__); \ + } while (0) + +--- a/drivers/net/wireless/ath/ath11k/trace.c ++++ b/drivers/net/wireless/ath/ath11k/trace.c +@@ -7,3 +7,4 @@ + + #define CREATE_TRACE_POINTS + #include "trace.h" ++EXPORT_SYMBOL(__tracepoint_ath11k_log_dbg); +--- a/drivers/net/wireless/ath/ath11k/trace.h ++++ b/drivers/net/wireless/ath/ath11k/trace.h +@@ -14,12 +14,24 @@ + #if !defined(CPTCFG_ATH11K_TRACING) + #undef TRACE_EVENT + #define TRACE_EVENT(name, proto, ...) \ ++static inline void trace_ ## name(proto) {} \ ++static inline bool trace_##name##_enabled(void) \ ++{ \ ++ return false; \ ++} ++ ++#undef DECLARE_EVENT_CLASS ++#define DECLARE_EVENT_CLASS(...) ++#undef DEFINE_EVENT ++#define DEFINE_EVENT(evt_class, name, proto, ...) \ + static inline void trace_ ## name(proto) {} + #endif /* !CPTCFG_ATH11K_TRACING || __CHECKER__ */ + + #undef TRACE_SYSTEM + #define TRACE_SYSTEM ath11k + ++#define ATH11K_MSG_MAX 400 ++ + TRACE_EVENT(ath11k_htt_pktlog, + TP_PROTO(struct ath11k *ar, const void *buf, u16 buf_len, + u32 pktlog_checksum), +@@ -108,6 +120,166 @@ TRACE_EVENT(ath11k_htt_rxdesc, + ) + ); + ++DECLARE_EVENT_CLASS(ath11k_log_event, ++ TP_PROTO(struct ath11k_base *ab, struct va_format *vaf), ++ TP_ARGS(ab, vaf), ++ TP_STRUCT__entry( ++ __string(device, dev_name(ab->dev)) ++ __string(driver, dev_driver_string(ab->dev)) ++ __dynamic_array(char, msg, ATH11K_MSG_MAX) ++ ), ++ TP_fast_assign( ++ __assign_str(device, dev_name(ab->dev)); ++ __assign_str(driver, dev_driver_string(ab->dev)); ++ WARN_ON_ONCE(vsnprintf(__get_dynamic_array(msg), ++ ATH11K_MSG_MAX, ++ vaf->fmt, ++ *vaf->va) >= ATH11K_MSG_MAX); ++ ), ++ TP_printk( ++ "%s %s %s", ++ __get_str(driver), ++ __get_str(device), ++ __get_str(msg) ++ ) ++); ++ ++DEFINE_EVENT(ath11k_log_event, ath11k_log_err, ++ TP_PROTO(struct ath11k_base *ab, struct va_format *vaf), ++ TP_ARGS(ab, vaf) ++); ++ ++DEFINE_EVENT(ath11k_log_event, ath11k_log_warn, ++ TP_PROTO(struct ath11k_base *ab, struct va_format *vaf), ++ TP_ARGS(ab, vaf) ++); ++ ++DEFINE_EVENT(ath11k_log_event, ath11k_log_info, ++ TP_PROTO(struct ath11k_base *ab, struct va_format *vaf), ++ TP_ARGS(ab, vaf) ++); ++ ++TRACE_EVENT(ath11k_wmi_cmd, ++ TP_PROTO(struct ath11k_base *ab, int id, const void *buf, size_t buf_len), ++ ++ TP_ARGS(ab, id, buf, buf_len), ++ ++ TP_STRUCT__entry( ++ __string(device, dev_name(ab->dev)) ++ __string(driver, dev_driver_string(ab->dev)) ++ __field(unsigned int, id) ++ __field(size_t, buf_len) ++ __dynamic_array(u8, buf, buf_len) ++ ), ++ ++ TP_fast_assign( ++ __assign_str(device, dev_name(ab->dev)); ++ __assign_str(driver, dev_driver_string(ab->dev)); ++ __entry->id = id; ++ __entry->buf_len = buf_len; ++ memcpy(__get_dynamic_array(buf), buf, buf_len); ++ ), ++ ++ TP_printk( ++ "%s %s id %d len %zu", ++ __get_str(driver), ++ __get_str(device), ++ __entry->id, ++ __entry->buf_len ++ ) ++); ++ ++TRACE_EVENT(ath11k_wmi_event, ++ TP_PROTO(struct ath11k_base *ab, int id, const void *buf, size_t buf_len), ++ ++ TP_ARGS(ab, id, buf, buf_len), ++ ++ TP_STRUCT__entry( ++ __string(device, dev_name(ab->dev)) ++ __string(driver, dev_driver_string(ab->dev)) ++ __field(unsigned int, id) ++ __field(size_t, buf_len) ++ __dynamic_array(u8, buf, buf_len) ++ ), ++ ++ TP_fast_assign( ++ __assign_str(device, dev_name(ab->dev)); ++ __assign_str(driver, dev_driver_string(ab->dev)); ++ __entry->id = id; ++ __entry->buf_len = buf_len; ++ memcpy(__get_dynamic_array(buf), buf, buf_len); ++ ), ++ ++ TP_printk( ++ "%s %s id %d len %zu", ++ __get_str(driver), ++ __get_str(device), ++ __entry->id, ++ __entry->buf_len ++ ) ++); ++ ++TRACE_EVENT(ath11k_log_dbg, ++ TP_PROTO(struct ath11k_base *ab, unsigned int level, struct va_format *vaf), ++ ++ TP_ARGS(ab, level, vaf), ++ ++ TP_STRUCT__entry( ++ __string(device, dev_name(ab->dev)) ++ __string(driver, dev_driver_string(ab->dev)) ++ __field(unsigned int, level) ++ __dynamic_array(char, msg, ATH11K_MSG_MAX) ++ ), ++ ++ TP_fast_assign( ++ __assign_str(device, dev_name(ab->dev)); ++ __assign_str(driver, dev_driver_string(ab->dev)); ++ __entry->level = level; ++ WARN_ON_ONCE(vsnprintf(__get_dynamic_array(msg), ++ ATH11K_MSG_MAX, vaf->fmt, ++ *vaf->va) >= ATH11K_MSG_MAX); ++ ), ++ ++ TP_printk( ++ "%s %s %s", ++ __get_str(driver), ++ __get_str(device), ++ __get_str(msg) ++ ) ++); ++ ++TRACE_EVENT(ath11k_log_dbg_dump, ++ TP_PROTO(struct ath11k_base *ab, const char *msg, const char *prefix, ++ const void *buf, size_t buf_len), ++ ++ TP_ARGS(ab, msg, prefix, buf, buf_len), ++ ++ TP_STRUCT__entry( ++ __string(device, dev_name(ab->dev)) ++ __string(driver, dev_driver_string(ab->dev)) ++ __string(msg, msg) ++ __string(prefix, prefix) ++ __field(size_t, buf_len) ++ __dynamic_array(u8, buf, buf_len) ++ ), ++ ++ TP_fast_assign( ++ __assign_str(device, dev_name(ab->dev)); ++ __assign_str(driver, dev_driver_string(ab->dev)); ++ __assign_str(msg, msg); ++ __assign_str(prefix, prefix); ++ __entry->buf_len = buf_len; ++ memcpy(__get_dynamic_array(buf), buf, buf_len); ++ ), ++ ++ TP_printk( ++ "%s %s %s/%s\n", ++ __get_str(driver), ++ __get_str(device), ++ __get_str(prefix), ++ __get_str(msg) ++ ) ++); + #endif /* _TRACE_H_ || TRACE_HEADER_MULTI_READ*/ + + /* we don't want to use include/trace/events */ +--- a/drivers/net/wireless/ath/ath11k/wmi.c ++++ b/drivers/net/wireless/ath/ath11k/wmi.c +@@ -249,6 +249,8 @@ static int ath11k_wmi_cmd_send_nowait(st + cmd_hdr = (struct wmi_cmd_hdr *)skb->data; + cmd_hdr->cmd_id = cmd; + ++ trace_ath11k_wmi_cmd(ab, cmd_id, skb->data, skb->len); ++ + memset(skb_cb, 0, sizeof(*skb_cb)); + ret = ath11k_htc_send(&ab->htc, wmi->eid, skb); + +@@ -7103,6 +7105,8 @@ static void ath11k_wmi_tlv_op_rx(struct + cmd_hdr = (struct wmi_cmd_hdr *)skb->data; + id = FIELD_GET(WMI_CMD_HDR_CMD_ID, (cmd_hdr->cmd_id)); + ++ trace_ath11k_wmi_event(ab, id, skb->data, skb->len); ++ + if (skb_pull(skb, sizeof(struct wmi_cmd_hdr)) == NULL) + goto out; + diff --git a/package/kernel/mac80211/patches/ath11k/0098-ath11k-Fix-crash-caused-by-uninitialized-TX-ring.patch b/package/kernel/mac80211/patches/ath11k/0098-ath11k-Fix-crash-caused-by-uninitialized-TX-ring.patch new file mode 100644 index 000000000..86aa0adde --- /dev/null +++ b/package/kernel/mac80211/patches/ath11k/0098-ath11k-Fix-crash-caused-by-uninitialized-TX-ring.patch @@ -0,0 +1,70 @@ +From 273703ebdb01b6c5f1aaf4b98fb57b177609055c Mon Sep 17 00:00:00 2001 +From: Baochen Qiang +Date: Tue, 26 Oct 2021 09:16:05 +0800 +Subject: [PATCH 098/120] ath11k: Fix crash caused by uninitialized TX ring + +Commit 31582373a4a8 ("ath11k: Change number of TCL rings to one for +QCA6390") avoids initializing the other entries of dp->tx_ring cause +the corresponding TX rings on QCA6390/WCN6855 are not used, but leaves +those ring masks in ath11k_hw_ring_mask_qca6390.tx unchanged. Normally +this is OK because we will only get interrupts from the first TX ring +on these chips and thus only the first entry of dp->tx_ring is involved. + +In case of one MSI vector, all DP rings share the same IRQ. For each +interrupt, all rings have to be checked, which means the other entries +of dp->tx_ring are involved. However since they are not initialized, +system crashes. + +Fix this issue by simply removing those ring masks. + +crash stack: +[ 102.907438] BUG: kernel NULL pointer dereference, address: 0000000000000028 +[ 102.907447] #PF: supervisor read access in kernel mode +[ 102.907451] #PF: error_code(0x0000) - not-present page +[ 102.907453] PGD 1081f0067 P4D 1081f0067 PUD 1081f1067 PMD 0 +[ 102.907460] Oops: 0000 [#1] SMP DEBUG_PAGEALLOC NOPTI +[ 102.907465] CPU: 0 PID: 3511 Comm: apt-check Kdump: loaded Tainted: G E 5.15.0-rc4-wt-ath+ #20 +[ 102.907470] Hardware name: AMD Celadon-RN/Celadon-RN, BIOS RCD1005E 10/08/2020 +[ 102.907472] RIP: 0010:ath11k_dp_tx_completion_handler+0x201/0x830 [ath11k] +[ 102.907497] Code: 3c 24 4e 8d ac 37 10 04 00 00 4a 8d bc 37 68 04 00 00 48 89 3c 24 48 63 c8 89 83 84 18 00 00 48 c1 e1 05 48 03 8b 78 18 00 00 <8b> 51 08 89 d6 83 e6 07 89 74 24 24 83 fe 03 74 04 85 f6 75 63 41 +[ 102.907501] RSP: 0000:ffff9b7340003e08 EFLAGS: 00010202 +[ 102.907505] RAX: 0000000000000001 RBX: ffff8e21530c0100 RCX: 0000000000000020 +[ 102.907508] RDX: 0000000000000000 RSI: 00000000fffffe00 RDI: ffff8e21530c1938 +[ 102.907511] RBP: ffff8e21530c0000 R08: 0000000000000001 R09: 0000000000000000 +[ 102.907513] R10: ffff8e2145534c10 R11: 0000000000000001 R12: ffff8e21530c2938 +[ 102.907515] R13: ffff8e21530c18e0 R14: 0000000000000100 R15: ffff8e21530c2978 +[ 102.907518] FS: 00007f5d4297e740(0000) GS:ffff8e243d600000(0000) knlGS:0000000000000000 +[ 102.907521] CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033 +[ 102.907524] CR2: 0000000000000028 CR3: 00000001034ea000 CR4: 0000000000350ef0 +[ 102.907527] Call Trace: +[ 102.907531] +[ 102.907537] ath11k_dp_service_srng+0x5c/0x2f0 [ath11k] +[ 102.907556] ath11k_pci_ext_grp_napi_poll+0x21/0x70 [ath11k_pci] +[ 102.907562] __napi_poll+0x2c/0x160 +[ 102.907570] net_rx_action+0x251/0x310 +[ 102.907576] __do_softirq+0x107/0x2fc +[ 102.907585] irq_exit_rcu+0x74/0x90 +[ 102.907593] common_interrupt+0x83/0xa0 +[ 102.907600] +[ 102.907601] asm_common_interrupt+0x1e/0x40 + +Tested-on: WCN6855 hw2.0 PCI WLAN.HSP.1.1-01720.1-QCAHSPSWPL_V1_V2_SILICONZ_LITE-1 + +Signed-off-by: Baochen Qiang +Signed-off-by: Kalle Valo +Link: https://lore.kernel.org/r/20211026011605.58615-1-quic_bqiang@quicinc.com +--- + drivers/net/wireless/ath/ath11k/hw.c | 2 -- + 1 file changed, 2 deletions(-) + +--- a/drivers/net/wireless/ath/ath11k/hw.c ++++ b/drivers/net/wireless/ath/ath11k/hw.c +@@ -1061,8 +1061,6 @@ const struct ath11k_hw_ring_mask ath11k_ + const struct ath11k_hw_ring_mask ath11k_hw_ring_mask_qca6390 = { + .tx = { + ATH11K_TX_RING_MASK_0, +- ATH11K_TX_RING_MASK_1, +- ATH11K_TX_RING_MASK_2, + }, + .rx_mon_status = { + 0, 0, 0, 0, diff --git a/package/kernel/mac80211/patches/ath11k/0099-ath11k-add-string-type-to-search-board-data-in-board.patch b/package/kernel/mac80211/patches/ath11k/0099-ath11k-add-string-type-to-search-board-data-in-board.patch new file mode 100644 index 000000000..f8078e472 --- /dev/null +++ b/package/kernel/mac80211/patches/ath11k/0099-ath11k-add-string-type-to-search-board-data-in-board.patch @@ -0,0 +1,130 @@ +From fc95d10ac41d75c14a81afcc8722333d8b2cf80f Mon Sep 17 00:00:00 2001 +From: Wen Gong +Date: Mon, 15 Nov 2021 11:29:55 +0200 +Subject: [PATCH 099/120] ath11k: add string type to search board data in + board-2.bin for WCN6855 + +Currently ath11k only support string type with bus, chip id and board id +such as "bus=ahb,qmi-chip-id=1,qmi-board-id=4" for ahb bus chip and +"bus=pci,qmi-chip-id=0,qmi-board-id=255" for PCIe bus chip in +board-2.bin. For WCN6855, it is not enough to distinguish all different +chips. + +This is to add a new string type which include bus, chip id, board id, +vendor, device, subsystem-vendor and subsystem-device for WCN6855. + +ath11k will first load board-2.bin and search in it for the board data +with the above parameters, if matched one board data, then download it +to firmware, if not matched any one, then ath11k will download the file +board.bin to firmware. + +Tested-on: WCN6855 hw2.0 PCI WLAN.HSP.1.1-01720.1-QCAHSPSWPL_V1_V2_SILICONZ_LITE-1 + +Signed-off-by: Wen Gong +Signed-off-by: Jouni Malinen +Signed-off-by: Kalle Valo +Link: https://lore.kernel.org/r/20211111065340.20187-1-quic_wgong@quicinc.com +--- + drivers/net/wireless/ath/ath11k/core.c | 27 ++++++++++++++++++++------ + drivers/net/wireless/ath/ath11k/core.h | 13 +++++++++++++ + drivers/net/wireless/ath/ath11k/pci.c | 10 ++++++++++ + 3 files changed, 44 insertions(+), 6 deletions(-) + +--- a/drivers/net/wireless/ath/ath11k/core.c ++++ b/drivers/net/wireless/ath/ath11k/core.c +@@ -412,11 +412,26 @@ static int ath11k_core_create_board_name + scnprintf(variant, sizeof(variant), ",variant=%s", + ab->qmi.target.bdf_ext); + +- scnprintf(name, name_len, +- "bus=%s,qmi-chip-id=%d,qmi-board-id=%d%s", +- ath11k_bus_str(ab->hif.bus), +- ab->qmi.target.chip_id, +- ab->qmi.target.board_id, variant); ++ switch (ab->id.bdf_search) { ++ case ATH11K_BDF_SEARCH_BUS_AND_BOARD: ++ scnprintf(name, name_len, ++ "bus=%s,vendor=%04x,device=%04x,subsystem-vendor=%04x,subsystem-device=%04x,qmi-chip-id=%d,qmi-board-id=%d%s", ++ ath11k_bus_str(ab->hif.bus), ++ ab->id.vendor, ab->id.device, ++ ab->id.subsystem_vendor, ++ ab->id.subsystem_device, ++ ab->qmi.target.chip_id, ++ ab->qmi.target.board_id, ++ variant); ++ break; ++ default: ++ scnprintf(name, name_len, ++ "bus=%s,qmi-chip-id=%d,qmi-board-id=%d%s", ++ ath11k_bus_str(ab->hif.bus), ++ ab->qmi.target.chip_id, ++ ab->qmi.target.board_id, variant); ++ break; ++ } + + ath11k_dbg(ab, ATH11K_DBG_BOOT, "boot using board name '%s'\n", name); + +@@ -653,7 +668,7 @@ static int ath11k_core_fetch_board_data_ + return 0; + } + +-#define BOARD_NAME_SIZE 100 ++#define BOARD_NAME_SIZE 200 + int ath11k_core_fetch_bdf(struct ath11k_base *ab, struct ath11k_board_data *bd) + { + char boardname[BOARD_NAME_SIZE]; +--- a/drivers/net/wireless/ath/ath11k/core.h ++++ b/drivers/net/wireless/ath/ath11k/core.h +@@ -47,6 +47,11 @@ enum ath11k_supported_bw { + ATH11K_BW_160 = 3, + }; + ++enum ath11k_bdf_search { ++ ATH11K_BDF_SEARCH_DEFAULT, ++ ATH11K_BDF_SEARCH_BUS_AND_BOARD, ++}; ++ + enum wme_ac { + WME_AC_BE, + WME_AC_BK, +@@ -760,6 +765,14 @@ struct ath11k_base { + + struct completion htc_suspend; + ++ struct { ++ enum ath11k_bdf_search bdf_search; ++ u32 vendor; ++ u32 device; ++ u32 subsystem_vendor; ++ u32 subsystem_device; ++ } id; ++ + /* must be last */ + u8 drv_priv[0] __aligned(sizeof(void *)); + }; +--- a/drivers/net/wireless/ath/ath11k/pci.c ++++ b/drivers/net/wireless/ath/ath11k/pci.c +@@ -1251,6 +1251,15 @@ static int ath11k_pci_probe(struct pci_d + goto err_free_core; + } + ++ ath11k_dbg(ab, ATH11K_DBG_BOOT, "pci probe %04x:%04x %04x:%04x\n", ++ pdev->vendor, pdev->device, ++ pdev->subsystem_vendor, pdev->subsystem_device); ++ ++ ab->id.vendor = pdev->vendor; ++ ab->id.device = pdev->device; ++ ab->id.subsystem_vendor = pdev->subsystem_vendor; ++ ab->id.subsystem_device = pdev->subsystem_device; ++ + switch (pci_dev->device) { + case QCA6390_DEVICE_ID: + ath11k_pci_read_hw_version(ab, &soc_hw_version_major, +@@ -1273,6 +1282,7 @@ static int ath11k_pci_probe(struct pci_d + ab->hw_rev = ATH11K_HW_QCN9074_HW10; + break; + case WCN6855_DEVICE_ID: ++ ab->id.bdf_search = ATH11K_BDF_SEARCH_BUS_AND_BOARD; + ath11k_pci_read_hw_version(ab, &soc_hw_version_major, + &soc_hw_version_minor); + switch (soc_hw_version_major) { diff --git a/package/kernel/mac80211/patches/ath11k/0100-ath11k-add-support-for-BSS-color-change.patch b/package/kernel/mac80211/patches/ath11k/0100-ath11k-add-support-for-BSS-color-change.patch new file mode 100644 index 000000000..7a18a0ac5 --- /dev/null +++ b/package/kernel/mac80211/patches/ath11k/0100-ath11k-add-support-for-BSS-color-change.patch @@ -0,0 +1,308 @@ +From 886433a984254c6d2c2074688dc8f48c40b1c070 Mon Sep 17 00:00:00 2001 +From: John Crispin +Date: Mon, 25 Oct 2021 21:40:54 +0530 +Subject: [PATCH 100/120] ath11k: add support for BSS color change + +Whenever the MAC detects a color collision, or any of +its associated stations detects one, the firmware will +send out an event. Add the code to parse and handle +this event and pass the data up to mac80211. + +The firmware does not provide an offload feature such +as the one used for CSA. The color change process is +hence triggered via the beacon offload tx completion +events sent out by firmware. + +BSS color feature is enabled depending on service flag +advertised by firmware, based on which color change +functionality is invoked. + +Tested-on: IPQ8074 hw2.0 AHB WLAN.HK.2.5.0.1-00680-QCAHKSWPL_SILICONZ-1 + +Signed-off-by: John Crispin +Co-developed-by: Lavanya Suresh +Signed-off-by: Lavanya Suresh +Signed-off-by: Rameshkumar Sundaram +Signed-off-by: Kalle Valo +Link: https://lore.kernel.org/r/1635178254-17732-1-git-send-email-quic_ramess@quicinc.com +--- + drivers/net/wireless/ath/ath11k/core.h | 2 + + drivers/net/wireless/ath/ath11k/mac.c | 57 +++++++++++++++++-- + drivers/net/wireless/ath/ath11k/mac.h | 1 + + drivers/net/wireless/ath/ath11k/wmi.c | 78 +++++++++++++++++++++++++- + drivers/net/wireless/ath/ath11k/wmi.h | 15 +++++ + 5 files changed, 147 insertions(+), 6 deletions(-) + +--- a/drivers/net/wireless/ath/ath11k/core.h ++++ b/drivers/net/wireless/ath/ath11k/core.h +@@ -255,6 +255,8 @@ struct ath11k_vif { + int txpower; + bool rsnie_present; + bool wpaie_present; ++ bool bcca_zero_sent; ++ bool do_not_send_tmpl; + struct ieee80211_chanctx_conf chanctx; + }; + +--- a/drivers/net/wireless/ath/ath11k/mac.c ++++ b/drivers/net/wireless/ath/ath11k/mac.c +@@ -1231,6 +1231,26 @@ static int ath11k_mac_setup_bcn_tmpl(str + return ret; + } + ++void ath11k_mac_bcn_tx_event(struct ath11k_vif *arvif) ++{ ++ struct ieee80211_vif *vif = arvif->vif; ++ ++ if (!vif->color_change_active && !arvif->bcca_zero_sent) ++ return; ++ ++ if (vif->color_change_active && ieee80211_beacon_cntdwn_is_complete(vif)) { ++ arvif->bcca_zero_sent = true; ++ ieee80211_color_change_finish(vif); ++ return; ++ } ++ ++ arvif->bcca_zero_sent = false; ++ ++ if (vif->color_change_active) ++ ieee80211_beacon_update_cntdwn(vif); ++ ath11k_mac_setup_bcn_tmpl(arvif); ++} ++ + static void ath11k_control_beaconing(struct ath11k_vif *arvif, + struct ieee80211_bss_conf *info) + { +@@ -2894,10 +2914,17 @@ static void ath11k_mac_op_bss_info_chang + "Set staggered beacon mode for VDEV: %d\n", + arvif->vdev_id); + +- ret = ath11k_mac_setup_bcn_tmpl(arvif); +- if (ret) +- ath11k_warn(ar->ab, "failed to update bcn template: %d\n", +- ret); ++ if (!arvif->do_not_send_tmpl || !arvif->bcca_zero_sent) { ++ ret = ath11k_mac_setup_bcn_tmpl(arvif); ++ if (ret) ++ ath11k_warn(ar->ab, "failed to update bcn template: %d\n", ++ ret); ++ } ++ ++ if (arvif->bcca_zero_sent) ++ arvif->do_not_send_tmpl = true; ++ else ++ arvif->do_not_send_tmpl = false; + } + + if (changed & (BSS_CHANGED_BEACON_INFO | BSS_CHANGED_BEACON)) { +@@ -3108,6 +3135,25 @@ static void ath11k_mac_op_bss_info_chang + if (ret) + ath11k_warn(ar->ab, "failed to set bss color collision on vdev %i: %d\n", + arvif->vdev_id, ret); ++ ++ param_id = WMI_VDEV_PARAM_BSS_COLOR; ++ if (info->he_bss_color.enabled) ++ param_value = info->he_bss_color.color << ++ IEEE80211_HE_OPERATION_BSS_COLOR_OFFSET; ++ else ++ param_value = IEEE80211_HE_OPERATION_BSS_COLOR_DISABLED; ++ ++ ret = ath11k_wmi_vdev_set_param_cmd(ar, arvif->vdev_id, ++ param_id, ++ param_value); ++ if (ret) ++ ath11k_warn(ar->ab, ++ "failed to set bss color param on vdev %i: %d\n", ++ arvif->vdev_id, ret); ++ ++ ath11k_dbg(ar->ab, ATH11K_DBG_MAC, ++ "bss color param 0x%x set on vdev %i\n", ++ param_value, arvif->vdev_id); + } else if (vif->type == NL80211_IFTYPE_STATION) { + ret = ath11k_wmi_send_bss_color_change_enable_cmd(ar, + arvif->vdev_id, +@@ -7872,6 +7918,9 @@ static int __ath11k_mac_register(struct + + wiphy_ext_feature_set(ar->hw->wiphy, NL80211_EXT_FEATURE_CQM_RSSI_LIST); + wiphy_ext_feature_set(ar->hw->wiphy, NL80211_EXT_FEATURE_STA_TX_PWR); ++ if (test_bit(WMI_TLV_SERVICE_BSS_COLOR_OFFLOAD, ar->ab->wmi_ab.svc_map)) ++ wiphy_ext_feature_set(ar->hw->wiphy, ++ NL80211_EXT_FEATURE_BSS_COLOR); + + ar->hw->wiphy->cipher_suites = cipher_suites; + ar->hw->wiphy->n_cipher_suites = ARRAY_SIZE(cipher_suites); +--- a/drivers/net/wireless/ath/ath11k/mac.h ++++ b/drivers/net/wireless/ath/ath11k/mac.h +@@ -155,4 +155,5 @@ enum ath11k_supported_bw ath11k_mac_mac8 + enum hal_encrypt_type ath11k_dp_tx_get_encrypt_type(u32 cipher); + void ath11k_mac_handle_beacon(struct ath11k *ar, struct sk_buff *skb); + void ath11k_mac_handle_beacon_miss(struct ath11k *ar, u32 vdev_id); ++void ath11k_mac_bcn_tx_event(struct ath11k_vif *arvif); + #endif +--- a/drivers/net/wireless/ath/ath11k/wmi.c ++++ b/drivers/net/wireless/ath/ath11k/wmi.c +@@ -128,6 +128,8 @@ static const struct wmi_tlv_policy wmi_t + .min_len = sizeof(struct wmi_probe_resp_tx_status_event) }, + [WMI_TAG_VDEV_DELETE_RESP_EVENT] = { + .min_len = sizeof(struct wmi_vdev_delete_resp_event) }, ++ [WMI_TAG_OBSS_COLOR_COLLISION_EVT] = { ++ .min_len = sizeof(struct wmi_obss_color_collision_event) }, + }; + + #define PRIMAP(_hw_mode_) \ +@@ -1633,6 +1635,15 @@ int ath11k_wmi_bcn_tmpl(struct ath11k *a + void *ptr; + int ret, len; + size_t aligned_len = roundup(bcn->len, 4); ++ struct ieee80211_vif *vif; ++ struct ath11k_vif *arvif = ath11k_mac_get_arvif(ar, vdev_id); ++ ++ if (!arvif) { ++ ath11k_warn(ar->ab, "failed to find arvif with vdev id %d\n", vdev_id); ++ return -EINVAL; ++ } ++ ++ vif = arvif->vif; + + len = sizeof(*cmd) + sizeof(*bcn_prb_info) + TLV_HDR_SIZE + aligned_len; + +@@ -1645,8 +1656,12 @@ int ath11k_wmi_bcn_tmpl(struct ath11k *a + FIELD_PREP(WMI_TLV_LEN, sizeof(*cmd) - TLV_HDR_SIZE); + cmd->vdev_id = vdev_id; + cmd->tim_ie_offset = offs->tim_offset; +- cmd->csa_switch_count_offset = offs->cntdwn_counter_offs[0]; +- cmd->ext_csa_switch_count_offset = offs->cntdwn_counter_offs[1]; ++ ++ if (vif->csa_active) { ++ cmd->csa_switch_count_offset = offs->cntdwn_counter_offs[0]; ++ cmd->ext_csa_switch_count_offset = offs->cntdwn_counter_offs[1]; ++ } ++ + cmd->buf_len = bcn->len; + + ptr = skb->data + sizeof(*cmd); +@@ -3451,6 +3466,53 @@ int ath11k_wmi_fils_discovery(struct ath + } + + static void ++ath11k_wmi_obss_color_collision_event(struct ath11k_base *ab, struct sk_buff *skb) ++{ ++ const void **tb; ++ const struct wmi_obss_color_collision_event *ev; ++ struct ath11k_vif *arvif; ++ int ret; ++ ++ tb = ath11k_wmi_tlv_parse_alloc(ab, skb->data, skb->len, GFP_ATOMIC); ++ if (IS_ERR(tb)) { ++ ret = PTR_ERR(tb); ++ ath11k_warn(ab, "failed to parse tlv: %d\n", ret); ++ return; ++ } ++ ++ ev = tb[WMI_TAG_OBSS_COLOR_COLLISION_EVT]; ++ if (!ev) { ++ ath11k_warn(ab, "failed to fetch obss color collision ev"); ++ goto exit; ++ } ++ ++ arvif = ath11k_mac_get_arvif_by_vdev_id(ab, ev->vdev_id); ++ if (!arvif) { ++ ath11k_warn(ab, "failed to find arvif with vedv id %d in obss_color_collision_event\n", ++ ev->vdev_id); ++ goto exit; ++ } ++ ++ switch (ev->evt_type) { ++ case WMI_BSS_COLOR_COLLISION_DETECTION: ++ ieeee80211_obss_color_collision_notify(arvif->vif, ev->obss_color_bitmap); ++ ath11k_dbg(ab, ATH11K_DBG_WMI, ++ "OBSS color collision detected vdev:%d, event:%d, bitmap:%08llx\n", ++ ev->vdev_id, ev->evt_type, ev->obss_color_bitmap); ++ break; ++ case WMI_BSS_COLOR_COLLISION_DISABLE: ++ case WMI_BSS_COLOR_FREE_SLOT_TIMER_EXPIRY: ++ case WMI_BSS_COLOR_FREE_SLOT_AVAILABLE: ++ break; ++ default: ++ ath11k_warn(ab, "received unknown obss color collision detetction event\n"); ++ } ++ ++exit: ++ kfree(tb); ++} ++ ++static void + ath11k_fill_band_to_mac_param(struct ath11k_base *soc, + struct wmi_host_pdev_band_to_mac *band_to_mac) + { +@@ -6157,6 +6219,7 @@ static void ath11k_vdev_start_resp_event + + static void ath11k_bcn_tx_status_event(struct ath11k_base *ab, struct sk_buff *skb) + { ++ struct ath11k_vif *arvif; + u32 vdev_id, tx_status; + + if (ath11k_pull_bcn_tx_status_ev(ab, skb->data, skb->len, +@@ -6164,6 +6227,14 @@ static void ath11k_bcn_tx_status_event(s + ath11k_warn(ab, "failed to extract bcn tx status"); + return; + } ++ ++ arvif = ath11k_mac_get_arvif_by_vdev_id(ab, vdev_id); ++ if (!arvif) { ++ ath11k_warn(ab, "invalid vdev id %d in bcn_tx_status", ++ vdev_id); ++ return; ++ } ++ ath11k_mac_bcn_tx_event(arvif); + } + + static void ath11k_vdev_stopped_event(struct ath11k_base *ab, struct sk_buff *skb) +@@ -7191,6 +7262,9 @@ static void ath11k_wmi_tlv_op_rx(struct + case WMI_OFFLOAD_PROB_RESP_TX_STATUS_EVENTID: + ath11k_probe_resp_tx_status_event(ab, skb); + break; ++ case WMI_OBSS_COLOR_COLLISION_DETECTION_EVENTID: ++ ath11k_wmi_obss_color_collision_event(ab, skb); ++ break; + /* add Unsupported events here */ + case WMI_TBTTOFFSET_EXT_UPDATE_EVENTID: + case WMI_PEER_OPER_MODE_CHANGE_EVENTID: +--- a/drivers/net/wireless/ath/ath11k/wmi.h ++++ b/drivers/net/wireless/ath/ath11k/wmi.h +@@ -774,6 +774,8 @@ enum wmi_tlv_event_id { + WMI_MDNS_STATS_EVENTID = WMI_TLV_CMD(WMI_GRP_MDNS_OFL), + WMI_SAP_OFL_ADD_STA_EVENTID = WMI_TLV_CMD(WMI_GRP_SAP_OFL), + WMI_SAP_OFL_DEL_STA_EVENTID, ++ WMI_OBSS_COLOR_COLLISION_DETECTION_EVENTID = ++ WMI_EVT_GRP_START_ID(WMI_GRP_OBSS_OFL), + WMI_OCB_SET_CONFIG_RESP_EVENTID = WMI_TLV_CMD(WMI_GRP_OCB), + WMI_OCB_GET_TSF_TIMER_RESP_EVENTID, + WMI_DCC_GET_STATS_RESP_EVENTID, +@@ -4916,6 +4918,13 @@ struct wmi_pdev_obss_pd_bitmap_cmd { + #define ATH11K_BSS_COLOR_COLLISION_DETECTION_STA_PERIOD_MS 10000 + #define ATH11K_BSS_COLOR_COLLISION_DETECTION_AP_PERIOD_MS 5000 + ++enum wmi_bss_color_collision { ++ WMI_BSS_COLOR_COLLISION_DISABLE = 0, ++ WMI_BSS_COLOR_COLLISION_DETECTION, ++ WMI_BSS_COLOR_FREE_SLOT_TIMER_EXPIRY, ++ WMI_BSS_COLOR_FREE_SLOT_AVAILABLE, ++}; ++ + struct wmi_obss_color_collision_cfg_params_cmd { + u32 tlv_header; + u32 vdev_id; +@@ -4933,6 +4942,12 @@ struct wmi_bss_color_change_enable_param + u32 enable; + } __packed; + ++struct wmi_obss_color_collision_event { ++ u32 vdev_id; ++ u32 evt_type; ++ u64 obss_color_bitmap; ++} __packed; ++ + #define ATH11K_IPV4_TH_SEED_SIZE 5 + #define ATH11K_IPV6_TH_SEED_SIZE 11 + diff --git a/package/kernel/mac80211/patches/ath11k/0101-ath11k-clear-the-keys-properly-via-DISABLE_KEY.patch b/package/kernel/mac80211/patches/ath11k/0101-ath11k-clear-the-keys-properly-via-DISABLE_KEY.patch new file mode 100644 index 000000000..659fc68ff --- /dev/null +++ b/package/kernel/mac80211/patches/ath11k/0101-ath11k-clear-the-keys-properly-via-DISABLE_KEY.patch @@ -0,0 +1,52 @@ +From 436a4e88659842a7cf634d7cc088c8f2cc94ebf5 Mon Sep 17 00:00:00 2001 +From: Karthikeyan Kathirvel +Date: Mon, 15 Nov 2021 11:04:40 +0100 +Subject: [PATCH 101/120] ath11k: clear the keys properly via DISABLE_KEY + +DISABLE_KEY sets the key_len to 0, firmware will not delete the keys if +key_len is 0. Changing from security mode to open mode will cause mcast +to be still encrypted without vdev restart. + +Set the proper key_len for DISABLE_KEY cmd to clear the keys in +firmware. + +Tested-on: IPQ6018 hw1.0 AHB WLAN.HK.2.5.0.1-01100-QCAHKSWPL_SILICONZ-1 + +Fixes: d5c65159f289 ("ath11k: driver for Qualcomm IEEE 802.11ax devices") +Reported-by: Sven Eckelmann +Signed-off-by: Karthikeyan Kathirvel +[sven@narfation.org: split into separate patches, clean up commit message] +Signed-off-by: Sven Eckelmann + +Signed-off-by: Kalle Valo +Link: https://lore.kernel.org/r/20211115100441.33771-1-sven@narfation.org +--- + drivers/net/wireless/ath/ath11k/mac.c | 4 +--- + drivers/net/wireless/ath/ath11k/wmi.c | 3 ++- + 2 files changed, 3 insertions(+), 4 deletions(-) + +--- a/drivers/net/wireless/ath/ath11k/mac.c ++++ b/drivers/net/wireless/ath/ath11k/mac.c +@@ -3461,9 +3461,7 @@ static int ath11k_install_key(struct ath + return 0; + + if (cmd == DISABLE_KEY) { +- /* TODO: Check if FW expects value other than NONE for del */ +- /* arg.key_cipher = WMI_CIPHER_NONE; */ +- arg.key_len = 0; ++ arg.key_cipher = WMI_CIPHER_NONE; + arg.key_data = NULL; + goto install; + } +--- a/drivers/net/wireless/ath/ath11k/wmi.c ++++ b/drivers/net/wireless/ath/ath11k/wmi.c +@@ -1725,7 +1725,8 @@ int ath11k_wmi_vdev_install_key(struct a + tlv = (struct wmi_tlv *)(skb->data + sizeof(*cmd)); + tlv->header = FIELD_PREP(WMI_TLV_TAG, WMI_TAG_ARRAY_BYTE) | + FIELD_PREP(WMI_TLV_LEN, key_len_aligned); +- memcpy(tlv->value, (u8 *)arg->key_data, key_len_aligned); ++ if (arg->key_data) ++ memcpy(tlv->value, (u8 *)arg->key_data, key_len_aligned); + + ret = ath11k_wmi_cmd_send(wmi, skb, WMI_VDEV_INSTALL_KEY_CMDID); + if (ret) { diff --git a/package/kernel/mac80211/patches/ath11k/0102-ath11k-reset-RSN-WPA-present-state-for-open-BSS.patch b/package/kernel/mac80211/patches/ath11k/0102-ath11k-reset-RSN-WPA-present-state-for-open-BSS.patch new file mode 100644 index 000000000..92eeb7c5d --- /dev/null +++ b/package/kernel/mac80211/patches/ath11k/0102-ath11k-reset-RSN-WPA-present-state-for-open-BSS.patch @@ -0,0 +1,49 @@ +From 64bc3aa02ae78b1fcb1b850e0eb1f0622002bfaa Mon Sep 17 00:00:00 2001 +From: Karthikeyan Kathirvel +Date: Mon, 15 Nov 2021 11:04:41 +0100 +Subject: [PATCH 102/120] ath11k: reset RSN/WPA present state for open BSS + +The ath11k driver is caching the information about RSN/WPA IE in the +configured beacon template. The cached information is used during +associations to figure out whether 4-way PKT/2-way GTK peer flags need to +be set or not. + +But the code never cleared the state when no such IE was found. This can +for example happen when moving from an WPA/RSN to an open setup. The +(seemingly connected) peer was then not able to communicate over the +link because the firmware assumed a different (encryption enabled) state +for the peer. + +Tested-on: IPQ6018 hw1.0 AHB WLAN.HK.2.5.0.1-01100-QCAHKSWPL_SILICONZ-1 + +Fixes: 01e34233c645 ("ath11k: fix wmi peer flags in peer assoc command") +Cc: Venkateswara Naralasetty +Reported-by: Sven Eckelmann +Signed-off-by: Karthikeyan Kathirvel +[sven@narfation.org: split into separate patches, clean up commit message] +Signed-off-by: Sven Eckelmann + +Signed-off-by: Kalle Valo +Link: https://lore.kernel.org/r/20211115100441.33771-2-sven@narfation.org +--- + drivers/net/wireless/ath/ath11k/mac.c | 4 ++++ + 1 file changed, 4 insertions(+) + +--- a/drivers/net/wireless/ath/ath11k/mac.c ++++ b/drivers/net/wireless/ath/ath11k/mac.c +@@ -1214,11 +1214,15 @@ static int ath11k_mac_setup_bcn_tmpl(str + + if (cfg80211_find_ie(WLAN_EID_RSN, ies, (skb_tail_pointer(bcn) - ies))) + arvif->rsnie_present = true; ++ else ++ arvif->rsnie_present = false; + + if (cfg80211_find_vendor_ie(WLAN_OUI_MICROSOFT, + WLAN_OUI_TYPE_MICROSOFT_WPA, + ies, (skb_tail_pointer(bcn) - ies))) + arvif->wpaie_present = true; ++ else ++ arvif->wpaie_present = false; + + ret = ath11k_wmi_bcn_tmpl(ar, arvif->vdev_id, &offs, bcn); + diff --git a/package/kernel/mac80211/patches/ath11k/0103-ath11k-add-hw_param-for-wakeup_mhi.patch b/package/kernel/mac80211/patches/ath11k/0103-ath11k-add-hw_param-for-wakeup_mhi.patch new file mode 100644 index 000000000..44248426c --- /dev/null +++ b/package/kernel/mac80211/patches/ath11k/0103-ath11k-add-hw_param-for-wakeup_mhi.patch @@ -0,0 +1,137 @@ +From 081e2d6476e30399433b509684d5da4d1844e430 Mon Sep 17 00:00:00 2001 +From: Seevalamuthu Mariappan +Date: Wed, 17 Nov 2021 09:39:41 +0200 +Subject: [PATCH 103/120] ath11k: add hw_param for wakeup_mhi + +Wakeup mhi is needed before pci_read/write only for QCA6390 and WCN6855. Since +wakeup & release mhi is enabled for all hardwares, below mhi assert is seen in +QCN9074 when doing 'rmmod ath11k_pci': + + Kernel panic - not syncing: dev_wake != 0 + CPU: 2 PID: 13535 Comm: procd Not tainted 4.4.60 #1 + Hardware name: Generic DT based system + [<80316dac>] (unwind_backtrace) from [<80313700>] (show_stack+0x10/0x14) + [<80313700>] (show_stack) from [<805135dc>] (dump_stack+0x7c/0x9c) + [<805135dc>] (dump_stack) from [<8032136c>] (panic+0x84/0x1f8) + [<8032136c>] (panic) from [<80549b24>] (mhi_pm_disable_transition+0x3b8/0x5b8) + [<80549b24>] (mhi_pm_disable_transition) from [<80549ddc>] (mhi_power_down+0xb8/0x100) + [<80549ddc>] (mhi_power_down) from [<7f5242b0>] (ath11k_mhi_op_status_cb+0x284/0x3ac [ath11k_pci]) + [E][__mhi_device_get_sync] Did not enter M0 state, cur_state:RESET pm_state:SHUTDOWN Process + [E][__mhi_device_get_sync] Did not enter M0 state, cur_state:RESET pm_state:SHUTDOWN Process + [E][__mhi_device_get_sync] Did not enter M0 state, cur_state:RESET pm_state:SHUTDOWN Process + [<7f5242b0>] (ath11k_mhi_op_status_cb [ath11k_pci]) from [<7f524878>] (ath11k_mhi_stop+0x10/0x20 [ath11k_pci]) + [<7f524878>] (ath11k_mhi_stop [ath11k_pci]) from [<7f525b94>] (ath11k_pci_power_down+0x54/0x90 [ath11k_pci]) + [<7f525b94>] (ath11k_pci_power_down [ath11k_pci]) from [<8056b2a8>] (pci_device_shutdown+0x30/0x44) + [<8056b2a8>] (pci_device_shutdown) from [<805cfa0c>] (device_shutdown+0x124/0x174) + [<805cfa0c>] (device_shutdown) from [<8033aaa4>] (kernel_restart+0xc/0x50) + [<8033aaa4>] (kernel_restart) from [<8033ada8>] (SyS_reboot+0x178/0x1ec) + [<8033ada8>] (SyS_reboot) from [<80301b80>] (ret_fast_syscall+0x0/0x34) + +Hence, disable wakeup/release mhi using hw_param for other hardwares. + +Tested-on: QCN9074 hw1.0 PCI WLAN.HK.2.5.0.1-01060-QCAHKSWPL_SILICONZ-1 + +Fixes: a05bd8513335 ("ath11k: read and write registers below unwindowed address") +Signed-off-by: Seevalamuthu Mariappan +Signed-off-by: Kalle Valo +Link: https://lore.kernel.org/r/1636702019-26142-1-git-send-email-quic_seevalam@quicinc.com +--- + drivers/net/wireless/ath/ath11k/core.c | 5 +++++ + drivers/net/wireless/ath/ath11k/hw.h | 1 + + drivers/net/wireless/ath/ath11k/pci.c | 12 ++++++++---- + 3 files changed, 14 insertions(+), 4 deletions(-) + +--- a/drivers/net/wireless/ath/ath11k/core.c ++++ b/drivers/net/wireless/ath/ath11k/core.c +@@ -86,6 +86,7 @@ static const struct ath11k_hw_params ath + .hal_params = &ath11k_hw_hal_params_ipq8074, + .supports_dynamic_smps_6ghz = false, + .alloc_cacheable_memory = true, ++ .wakeup_mhi = false, + }, + { + .hw_rev = ATH11K_HW_IPQ6018_HW10, +@@ -139,6 +140,7 @@ static const struct ath11k_hw_params ath + .hal_params = &ath11k_hw_hal_params_ipq8074, + .supports_dynamic_smps_6ghz = false, + .alloc_cacheable_memory = true, ++ .wakeup_mhi = false, + }, + { + .name = "qca6390 hw2.0", +@@ -191,6 +193,7 @@ static const struct ath11k_hw_params ath + .hal_params = &ath11k_hw_hal_params_qca6390, + .supports_dynamic_smps_6ghz = false, + .alloc_cacheable_memory = false, ++ .wakeup_mhi = true, + }, + { + .name = "qcn9074 hw1.0", +@@ -243,6 +246,7 @@ static const struct ath11k_hw_params ath + .hal_params = &ath11k_hw_hal_params_ipq8074, + .supports_dynamic_smps_6ghz = true, + .alloc_cacheable_memory = true, ++ .wakeup_mhi = false, + }, + { + .name = "wcn6855 hw2.0", +@@ -295,6 +299,7 @@ static const struct ath11k_hw_params ath + .hal_params = &ath11k_hw_hal_params_qca6390, + .supports_dynamic_smps_6ghz = false, + .alloc_cacheable_memory = false, ++ .wakeup_mhi = true, + }, + }; + +--- a/drivers/net/wireless/ath/ath11k/hw.h ++++ b/drivers/net/wireless/ath/ath11k/hw.h +@@ -180,6 +180,7 @@ struct ath11k_hw_params { + const struct ath11k_hw_hal_params *hal_params; + bool supports_dynamic_smps_6ghz; + bool alloc_cacheable_memory; ++ bool wakeup_mhi; + }; + + struct ath11k_hw_ops { +--- a/drivers/net/wireless/ath/ath11k/pci.c ++++ b/drivers/net/wireless/ath/ath11k/pci.c +@@ -182,7 +182,8 @@ void ath11k_pci_write32(struct ath11k_ba + /* for offset beyond BAR + 4K - 32, may + * need to wakeup MHI to access. + */ +- if (test_bit(ATH11K_PCI_FLAG_INIT_DONE, &ab_pci->flags) && ++ if (ab->hw_params.wakeup_mhi && ++ test_bit(ATH11K_PCI_FLAG_INIT_DONE, &ab_pci->flags) && + offset >= ACCESS_ALWAYS_OFF) + mhi_device_get_sync(ab_pci->mhi_ctrl->mhi_dev); + +@@ -206,7 +207,8 @@ void ath11k_pci_write32(struct ath11k_ba + } + } + +- if (test_bit(ATH11K_PCI_FLAG_INIT_DONE, &ab_pci->flags) && ++ if (ab->hw_params.wakeup_mhi && ++ test_bit(ATH11K_PCI_FLAG_INIT_DONE, &ab_pci->flags) && + offset >= ACCESS_ALWAYS_OFF) + mhi_device_put(ab_pci->mhi_ctrl->mhi_dev); + } +@@ -219,7 +221,8 @@ u32 ath11k_pci_read32(struct ath11k_base + /* for offset beyond BAR + 4K - 32, may + * need to wakeup MHI to access. + */ +- if (test_bit(ATH11K_PCI_FLAG_INIT_DONE, &ab_pci->flags) && ++ if (ab->hw_params.wakeup_mhi && ++ test_bit(ATH11K_PCI_FLAG_INIT_DONE, &ab_pci->flags) && + offset >= ACCESS_ALWAYS_OFF) + mhi_device_get_sync(ab_pci->mhi_ctrl->mhi_dev); + +@@ -243,7 +246,8 @@ u32 ath11k_pci_read32(struct ath11k_base + } + } + +- if (test_bit(ATH11K_PCI_FLAG_INIT_DONE, &ab_pci->flags) && ++ if (ab->hw_params.wakeup_mhi && ++ test_bit(ATH11K_PCI_FLAG_INIT_DONE, &ab_pci->flags) && + offset >= ACCESS_ALWAYS_OFF) + mhi_device_put(ab_pci->mhi_ctrl->mhi_dev); + diff --git a/package/kernel/mac80211/patches/ath11k/0104-ath11k-get-msi_data-again-after-request_irq-is-calle.patch b/package/kernel/mac80211/patches/ath11k/0104-ath11k-get-msi_data-again-after-request_irq-is-calle.patch new file mode 100644 index 000000000..ddbf0ee4d --- /dev/null +++ b/package/kernel/mac80211/patches/ath11k/0104-ath11k-get-msi_data-again-after-request_irq-is-calle.patch @@ -0,0 +1,77 @@ +From 87b4072d7ef818e368b0f4162a1af2fb4727f51c Mon Sep 17 00:00:00 2001 +From: Carl Huang +Date: Fri, 19 Nov 2021 15:36:26 +0200 +Subject: [PATCH 104/120] ath11k: get msi_data again after request_irq is + called + +The reservation mode of interrupts in kernel assigns a dummy vector +when the interrupt is allocated and assigns a real vector when the +request_irq is called. The reservation mode helps to ease vector +pressure when devices with a large amount of queues/interrupts +are initialized, but only a minimal subset of those queues/interrupts +is actually used. + +So on reservation mode, the msi_data may change after request_irq +is called, so ath11k reads msi_data again after request_irq is called, +and then the correct msi_data is programmed into QCA6390 hardware +components. Without this change, spurious interrupt occurs in case of +one MSI vector. When VT-d in BIOS is enabled and ath11k can get 32 MSI +vectors, ath11k always get the same msi_data before and after request_irq, +that's why this change is only required when one MSI vector is to be +supported. + +Tested-on: QCA6390 hw2.0 PCI WLAN.HST.1.0.1-01740-QCAHSTSWPLZ_V2_TO_X86-1 + +Signed-off-by: Carl Huang +Signed-off-by: Kalle Valo +Link: https://lore.kernel.org/r/20211026041636.5008-1-bqiang@codeaurora.org +--- + drivers/net/wireless/ath/ath11k/pci.c | 30 +++++++++++++++++++++++++++ + 1 file changed, 30 insertions(+) + +--- a/drivers/net/wireless/ath/ath11k/pci.c ++++ b/drivers/net/wireless/ath/ath11k/pci.c +@@ -933,6 +933,25 @@ static void ath11k_pci_free_msi(struct a + pci_free_irq_vectors(ab_pci->pdev); + } + ++static int ath11k_pci_config_msi_data(struct ath11k_pci *ab_pci) ++{ ++ struct msi_desc *msi_desc; ++ ++ msi_desc = irq_get_msi_desc(ab_pci->pdev->irq); ++ if (!msi_desc) { ++ ath11k_err(ab_pci->ab, "msi_desc is NULL!\n"); ++ pci_free_irq_vectors(ab_pci->pdev); ++ return -EINVAL; ++ } ++ ++ ab_pci->msi_ep_base_data = msi_desc->msg.data; ++ ++ ath11k_dbg(ab_pci->ab, ATH11K_DBG_PCI, "pci after request_irq msi_ep_base_data %d\n", ++ ab_pci->msi_ep_base_data); ++ ++ return 0; ++} ++ + static int ath11k_pci_claim(struct ath11k_pci *ab_pci, struct pci_dev *pdev) + { + struct ath11k_base *ab = ab_pci->ab; +@@ -1342,6 +1361,17 @@ static int ath11k_pci_probe(struct pci_d + goto err_ce_free; + } + ++ /* kernel may allocate a dummy vector before request_irq and ++ * then allocate a real vector when request_irq is called. ++ * So get msi_data here again to avoid spurious interrupt ++ * as msi_data will configured to srngs. ++ */ ++ ret = ath11k_pci_config_msi_data(ab_pci); ++ if (ret) { ++ ath11k_err(ab, "failed to config msi_data: %d\n", ret); ++ goto err_free_irq; ++ } ++ + ret = ath11k_core_init(ab); + if (ret) { + ath11k_err(ab, "failed to init core: %d\n", ret); diff --git a/package/kernel/mac80211/patches/ath11k/0105-ath11k-add-CE-and-ext-IRQ-flag-to-indicate-irq_handl.patch b/package/kernel/mac80211/patches/ath11k/0105-ath11k-add-CE-and-ext-IRQ-flag-to-indicate-irq_handl.patch new file mode 100644 index 000000000..d45c1fb5b --- /dev/null +++ b/package/kernel/mac80211/patches/ath11k/0105-ath11k-add-CE-and-ext-IRQ-flag-to-indicate-irq_handl.patch @@ -0,0 +1,93 @@ +From 01279bcd01d965b6526d575e036841778d8e3c4e Mon Sep 17 00:00:00 2001 +From: Carl Huang +Date: Fri, 19 Nov 2021 15:36:26 +0200 +Subject: [PATCH 105/120] ath11k: add CE and ext IRQ flag to indicate + irq_handler + +This change adds two flags to indicate whether IRQ handler for CE +and DP can be called. This is because in one MSI vector case, +interrupt is not disabled in hif_stop and hif_irq_disable. Otherwise, +MHI interrupt is disabled too. + +Tested-on: QCA6390 hw2.0 PCI WLAN.HST.1.0.1-01740-QCAHSTSWPLZ_V2_TO_X86-1 + +Signed-off-by: Carl Huang +Signed-off-by: Kalle Valo +Signed-off-by: Baochen Qiang +Link: https://lore.kernel.org/r/20211026041646.5060-1-bqiang@codeaurora.org +--- + drivers/net/wireless/ath/ath11k/core.h | 2 ++ + drivers/net/wireless/ath/ath11k/pci.c | 16 ++++++++++++++++ + 2 files changed, 18 insertions(+) + +--- a/drivers/net/wireless/ath/ath11k/core.h ++++ b/drivers/net/wireless/ath/ath11k/core.h +@@ -199,6 +199,8 @@ enum ath11k_dev_flags { + ATH11K_FLAG_REGISTERED, + ATH11K_FLAG_QMI_FAIL, + ATH11K_FLAG_HTC_SUSPEND_COMPLETE, ++ ATH11K_FLAG_CE_IRQ_ENABLED, ++ ATH11K_FLAG_EXT_IRQ_ENABLED, + }; + + enum ath11k_monitor_flags { +--- a/drivers/net/wireless/ath/ath11k/pci.c ++++ b/drivers/net/wireless/ath/ath11k/pci.c +@@ -578,6 +578,8 @@ static void ath11k_pci_ce_irqs_disable(s + { + int i; + ++ clear_bit(ATH11K_FLAG_CE_IRQ_ENABLED, &ab->dev_flags); ++ + for (i = 0; i < ab->hw_params.ce_count; i++) { + if (ath11k_ce_get_attr_flags(ab, i) & CE_ATTR_DIS_INTR) + continue; +@@ -611,6 +613,10 @@ static void ath11k_pci_ce_tasklet(struct + static irqreturn_t ath11k_pci_ce_interrupt_handler(int irq, void *arg) + { + struct ath11k_ce_pipe *ce_pipe = arg; ++ struct ath11k_base *ab = ce_pipe->ab; ++ ++ if (!test_bit(ATH11K_FLAG_CE_IRQ_ENABLED, &ab->dev_flags)) ++ return IRQ_HANDLED; + + /* last interrupt received for this CE */ + ce_pipe->timestamp = jiffies; +@@ -633,6 +639,8 @@ static void __ath11k_pci_ext_irq_disable + { + int i; + ++ clear_bit(ATH11K_FLAG_EXT_IRQ_ENABLED, &sc->dev_flags); ++ + for (i = 0; i < ATH11K_EXT_IRQ_GRP_NUM_MAX; i++) { + struct ath11k_ext_irq_grp *irq_grp = &sc->ext_irq_grp[i]; + +@@ -655,6 +663,8 @@ static void ath11k_pci_ext_irq_enable(st + { + int i; + ++ set_bit(ATH11K_FLAG_EXT_IRQ_ENABLED, &ab->dev_flags); ++ + for (i = 0; i < ATH11K_EXT_IRQ_GRP_NUM_MAX; i++) { + struct ath11k_ext_irq_grp *irq_grp = &ab->ext_irq_grp[i]; + +@@ -706,6 +716,10 @@ static int ath11k_pci_ext_grp_napi_poll( + static irqreturn_t ath11k_pci_ext_interrupt_handler(int irq, void *arg) + { + struct ath11k_ext_irq_grp *irq_grp = arg; ++ struct ath11k_base *ab = irq_grp->ab; ++ ++ if (!test_bit(ATH11K_FLAG_EXT_IRQ_ENABLED, &ab->dev_flags)) ++ return IRQ_HANDLED; + + ath11k_dbg(irq_grp->ab, ATH11K_DBG_PCI, "ext irq:%d\n", irq); + +@@ -852,6 +866,8 @@ static void ath11k_pci_ce_irqs_enable(st + { + int i; + ++ set_bit(ATH11K_FLAG_CE_IRQ_ENABLED, &ab->dev_flags); ++ + for (i = 0; i < ab->hw_params.ce_count; i++) { + if (ath11k_ce_get_attr_flags(ab, i) & CE_ATTR_DIS_INTR) + continue; diff --git a/package/kernel/mac80211/patches/ath11k/0106-ath11k-use-ATH11K_PCI_IRQ_DP_OFFSET-for-DP-IRQ.patch b/package/kernel/mac80211/patches/ath11k/0106-ath11k-use-ATH11K_PCI_IRQ_DP_OFFSET-for-DP-IRQ.patch new file mode 100644 index 000000000..be28b5f59 --- /dev/null +++ b/package/kernel/mac80211/patches/ath11k/0106-ath11k-use-ATH11K_PCI_IRQ_DP_OFFSET-for-DP-IRQ.patch @@ -0,0 +1,50 @@ +From 4ab4693f327ad015c4637ae42dc53c8471aed9c8 Mon Sep 17 00:00:00 2001 +From: Carl Huang +Date: Fri, 19 Nov 2021 15:36:26 +0200 +Subject: [PATCH 106/120] ath11k: use ATH11K_PCI_IRQ_DP_OFFSET for DP IRQ + +Like ATH11K_PCI_IRQ_CE0_OFFSET, define ATH11K_PCI_IRQ_DP_OFFSET for +DP to save the IRQ instead of base_vector from MSI config. + +Tested-on: QCA6390 hw2.0 PCI WLAN.HST.1.0.1-01740-QCAHSTSWPLZ_V2_TO_X86-1 + +Signed-off-by: Carl Huang +Signed-off-by: Kalle Valo +Signed-off-by: Baochen Qiang +Link: https://lore.kernel.org/r/20211026041655.5112-1-bqiang@codeaurora.org +--- + drivers/net/wireless/ath/ath11k/pci.c | 8 ++++---- + 1 file changed, 4 insertions(+), 4 deletions(-) + +--- a/drivers/net/wireless/ath/ath11k/pci.c ++++ b/drivers/net/wireless/ath/ath11k/pci.c +@@ -16,7 +16,8 @@ + #define ATH11K_PCI_BAR_NUM 0 + #define ATH11K_PCI_DMA_MASK 32 + +-#define ATH11K_PCI_IRQ_CE0_OFFSET 3 ++#define ATH11K_PCI_IRQ_CE0_OFFSET 3 ++#define ATH11K_PCI_IRQ_DP_OFFSET 14 + + #define WINDOW_ENABLE_BIT 0x40000000 + #define WINDOW_REG_ADDRESS 0x310c +@@ -736,9 +737,8 @@ static irqreturn_t ath11k_pci_ext_interr + static int ath11k_pci_ext_irq_config(struct ath11k_base *ab) + { + int i, j, ret, num_vectors = 0; +- u32 user_base_data = 0, base_vector = 0, base_idx; ++ u32 user_base_data = 0, base_vector = 0; + +- base_idx = ATH11K_PCI_IRQ_CE0_OFFSET + CE_COUNT_MAX; + ret = ath11k_pci_get_user_msi_assignment(ath11k_pci_priv(ab), "DP", + &num_vectors, + &user_base_data, +@@ -768,7 +768,7 @@ static int ath11k_pci_ext_irq_config(str + } + + irq_grp->num_irq = num_irq; +- irq_grp->irqs[0] = base_idx + i; ++ irq_grp->irqs[0] = ATH11K_PCI_IRQ_DP_OFFSET + i; + + for (j = 0; j < irq_grp->num_irq; j++) { + int irq_idx = irq_grp->irqs[j]; diff --git a/package/kernel/mac80211/patches/ath11k/0107-ath11k-refactor-multiple-MSI-vector-implementation.patch b/package/kernel/mac80211/patches/ath11k/0107-ath11k-refactor-multiple-MSI-vector-implementation.patch new file mode 100644 index 000000000..1529089cf --- /dev/null +++ b/package/kernel/mac80211/patches/ath11k/0107-ath11k-refactor-multiple-MSI-vector-implementation.patch @@ -0,0 +1,173 @@ +From c41a6700b276ddf6ef93dcb43baca51ea0c4c7c1 Mon Sep 17 00:00:00 2001 +From: Carl Huang +Date: Fri, 19 Nov 2021 15:36:26 +0200 +Subject: [PATCH 107/120] ath11k: refactor multiple MSI vector implementation + +This is to prepare for one MSI vector support. IRQ enable and disable +of CE and DP are done only in case of multiple MSI vectors. + +Tested-on: QCA6390 hw2.0 PCI WLAN.HST.1.0.1-01740-QCAHSTSWPLZ_V2_TO_X86-1 + +Signed-off-by: Carl Huang +Signed-off-by: Kalle Valo +Signed-off-by: Baochen Qiang +Link: https://lore.kernel.org/r/20211026041705.5167-1-bqiang@codeaurora.org +--- + drivers/net/wireless/ath/ath11k/pci.c | 48 ++++++++++++++++++++++----- + drivers/net/wireless/ath/ath11k/pci.h | 3 ++ + 2 files changed, 43 insertions(+), 8 deletions(-) + +--- a/drivers/net/wireless/ath/ath11k/pci.c ++++ b/drivers/net/wireless/ath/ath11k/pci.c +@@ -486,11 +486,11 @@ int ath11k_pci_get_user_msi_assignment(s + for (idx = 0; idx < msi_config->total_users; idx++) { + if (strcmp(user_name, msi_config->users[idx].name) == 0) { + *num_vectors = msi_config->users[idx].num_vectors; +- *user_base_data = msi_config->users[idx].base_vector +- + ab_pci->msi_ep_base_data; +- *base_vector = msi_config->users[idx].base_vector; ++ *base_vector = msi_config->users[idx].base_vector; ++ *user_base_data = *base_vector + ab_pci->msi_ep_base_data; + +- ath11k_dbg(ab, ATH11K_DBG_PCI, "Assign MSI to user: %s, num_vectors: %d, user_base_data: %u, base_vector: %u\n", ++ ath11k_dbg(ab, ATH11K_DBG_PCI, ++ "Assign MSI to user: %s, num_vectors: %d, user_base_data: %u, base_vector: %u\n", + user_name, *num_vectors, *user_base_data, + *base_vector); + +@@ -561,16 +561,30 @@ static void ath11k_pci_free_irq(struct a + + static void ath11k_pci_ce_irq_enable(struct ath11k_base *ab, u16 ce_id) + { ++ struct ath11k_pci *ab_pci = ath11k_pci_priv(ab); + u32 irq_idx; + ++ /* In case of one MSI vector, we handle irq enable/disable in a ++ * uniform way since we only have one irq ++ */ ++ if (!test_bit(ATH11K_PCI_FLAG_MULTI_MSI_VECTORS, &ab_pci->flags)) ++ return; ++ + irq_idx = ATH11K_PCI_IRQ_CE0_OFFSET + ce_id; + enable_irq(ab->irq_num[irq_idx]); + } + + static void ath11k_pci_ce_irq_disable(struct ath11k_base *ab, u16 ce_id) + { ++ struct ath11k_pci *ab_pci = ath11k_pci_priv(ab); + u32 irq_idx; + ++ /* In case of one MSI vector, we handle irq enable/disable in a ++ * uniform way since we only have one irq ++ */ ++ if (!test_bit(ATH11K_PCI_FLAG_MULTI_MSI_VECTORS, &ab_pci->flags)) ++ return; ++ + irq_idx = ATH11K_PCI_IRQ_CE0_OFFSET + ce_id; + disable_irq_nosync(ab->irq_num[irq_idx]); + } +@@ -630,8 +644,15 @@ static irqreturn_t ath11k_pci_ce_interru + + static void ath11k_pci_ext_grp_disable(struct ath11k_ext_irq_grp *irq_grp) + { ++ struct ath11k_pci *ab_pci = ath11k_pci_priv(irq_grp->ab); + int i; + ++ /* In case of one MSI vector, we handle irq enable/disable ++ * in a uniform way since we only have one irq ++ */ ++ if (!test_bit(ATH11K_PCI_FLAG_MULTI_MSI_VECTORS, &ab_pci->flags)) ++ return; ++ + for (i = 0; i < irq_grp->num_irq; i++) + disable_irq_nosync(irq_grp->ab->irq_num[irq_grp->irqs[i]]); + } +@@ -654,8 +675,15 @@ static void __ath11k_pci_ext_irq_disable + + static void ath11k_pci_ext_grp_enable(struct ath11k_ext_irq_grp *irq_grp) + { ++ struct ath11k_pci *ab_pci = ath11k_pci_priv(irq_grp->ab); + int i; + ++ /* In case of one MSI vector, we handle irq enable/disable in a ++ * uniform way since we only have one irq ++ */ ++ if (!test_bit(ATH11K_PCI_FLAG_MULTI_MSI_VECTORS, &ab_pci->flags)) ++ return; ++ + for (i = 0; i < irq_grp->num_irq; i++) + enable_irq(irq_grp->ab->irq_num[irq_grp->irqs[i]]); + } +@@ -736,6 +764,7 @@ static irqreturn_t ath11k_pci_ext_interr + + static int ath11k_pci_ext_irq_config(struct ath11k_base *ab) + { ++ struct ath11k_pci *ab_pci = ath11k_pci_priv(ab); + int i, j, ret, num_vectors = 0; + u32 user_base_data = 0, base_vector = 0; + +@@ -782,16 +811,15 @@ static int ath11k_pci_ext_irq_config(str + + irq_set_status_flags(irq, IRQ_DISABLE_UNLAZY); + ret = request_irq(irq, ath11k_pci_ext_interrupt_handler, +- IRQF_SHARED, ++ ab_pci->irq_flags, + "DP_EXT_IRQ", irq_grp); + if (ret) { + ath11k_err(ab, "failed request irq %d: %d\n", + vector, ret); + return ret; + } +- +- disable_irq_nosync(ab->irq_num[irq_idx]); + } ++ ath11k_pci_ext_grp_disable(irq_grp); + } + + return 0; +@@ -799,6 +827,7 @@ static int ath11k_pci_ext_irq_config(str + + static int ath11k_pci_config_irq(struct ath11k_base *ab) + { ++ struct ath11k_pci *ab_pci = ath11k_pci_priv(ab); + struct ath11k_ce_pipe *ce_pipe; + u32 msi_data_start; + u32 msi_data_count, msi_data_idx; +@@ -826,7 +855,7 @@ static int ath11k_pci_config_irq(struct + tasklet_setup(&ce_pipe->intr_tq, ath11k_pci_ce_tasklet); + + ret = request_irq(irq, ath11k_pci_ce_interrupt_handler, +- IRQF_SHARED, irq_name[irq_idx], ++ ab_pci->irq_flags, irq_name[irq_idx], + ce_pipe); + if (ret) { + ath11k_err(ab, "failed to request irq %d: %d\n", +@@ -920,6 +949,9 @@ static int ath11k_pci_alloc_msi(struct a + return -EINVAL; + else + return num_vectors; ++ } else { ++ set_bit(ATH11K_PCI_FLAG_MULTI_MSI_VECTORS, &ab_pci->flags); ++ ab_pci->irq_flags = IRQF_SHARED; + } + ath11k_pci_msi_disable(ab_pci); + +--- a/drivers/net/wireless/ath/ath11k/pci.h ++++ b/drivers/net/wireless/ath/ath11k/pci.h +@@ -68,6 +68,7 @@ enum ath11k_pci_flags { + ATH11K_PCI_FLAG_INIT_DONE, + ATH11K_PCI_FLAG_IS_MSI_64, + ATH11K_PCI_ASPM_RESTORE, ++ ATH11K_PCI_FLAG_MULTI_MSI_VECTORS, + }; + + struct ath11k_pci { +@@ -87,6 +88,8 @@ struct ath11k_pci { + /* enum ath11k_pci_flags */ + unsigned long flags; + u16 link_ctl; ++ ++ unsigned long irq_flags; + }; + + static inline struct ath11k_pci *ath11k_pci_priv(struct ath11k_base *ab) diff --git a/package/kernel/mac80211/patches/ath11k/0108-ath11k-add-support-one-MSI-vector.patch b/package/kernel/mac80211/patches/ath11k/0108-ath11k-add-support-one-MSI-vector.patch new file mode 100644 index 000000000..230d8d228 --- /dev/null +++ b/package/kernel/mac80211/patches/ath11k/0108-ath11k-add-support-one-MSI-vector.patch @@ -0,0 +1,195 @@ +From ac6e73483f7b4b5bde23b14fc3aaafc8341ae0c7 Mon Sep 17 00:00:00 2001 +From: Carl Huang +Date: Fri, 19 Nov 2021 15:36:26 +0200 +Subject: [PATCH 108/120] ath11k: add support one MSI vector + +On some platforms it's not possible to allocate 32 MSI vectors for various +reasons, be it kernel configuration, VT-d disabled, buggy BIOS etc. So +ath11k was not able to use QCA6390 PCI devices on those platforms. Add +support for one MSI vector to solve that. + +In case of one MSI vector, interrupt migration needs to be disabled. This +is because when interrupt migration happens, the msi_data may change. +However, msi_data is already programmed to rings during initial phase and +ath11k has no way to know that msi_data is changed during run time and +reprogram again. + +In case of one MSI vector, MHI subsystem should not use IRQF_NO_SUSPEND +as QCA6390 doesn't set this flag too. Ath11k doesn't need to leave +IRQ enabled in suspend state. + +Tested-on: QCA6390 hw2.0 PCI WLAN.HST.1.0.1-01740-QCAHSTSWPLZ_V2_TO_X86-1 + +Signed-off-by: Carl Huang +Signed-off-by: Kalle Valo +Signed-off-by: Baochen Qiang +Link: https://lore.kernel.org/r/20211026041714.5219-1-bqiang@codeaurora.org +--- + drivers/net/wireless/ath/ath11k/mhi.c | 14 ++++++-- + drivers/net/wireless/ath/ath11k/pci.c | 52 ++++++++++++++++++++------- + 2 files changed, 51 insertions(+), 15 deletions(-) + +--- a/drivers/net/wireless/ath/ath11k/mhi.c ++++ b/drivers/net/wireless/ath/ath11k/mhi.c +@@ -248,6 +248,7 @@ static int ath11k_mhi_get_msi(struct ath + u32 user_base_data, base_vector; + int ret, num_vectors, i; + int *irq; ++ unsigned int msi_data; + + ret = ath11k_pci_get_user_msi_assignment(ab_pci, + "MHI", &num_vectors, +@@ -262,9 +263,15 @@ static int ath11k_mhi_get_msi(struct ath + if (!irq) + return -ENOMEM; + +- for (i = 0; i < num_vectors; i++) ++ for (i = 0; i < num_vectors; i++) { ++ msi_data = base_vector; ++ ++ if (test_bit(ATH11K_PCI_FLAG_MULTI_MSI_VECTORS, &ab_pci->flags)) ++ msi_data += i; ++ + irq[i] = ath11k_pci_get_msi_irq(ab->dev, +- base_vector + i); ++ msi_data); ++ } + + ab_pci->mhi_ctrl->irq = irq; + ab_pci->mhi_ctrl->nr_irqs = num_vectors; +@@ -341,6 +348,9 @@ int ath11k_mhi_register(struct ath11k_pc + return ret; + } + ++ if (!test_bit(ATH11K_PCI_FLAG_MULTI_MSI_VECTORS, &ab_pci->flags)) ++ mhi_ctrl->irq_flags = IRQF_SHARED | IRQF_NOBALANCING; ++ + mhi_ctrl->iova_start = 0; + mhi_ctrl->iova_stop = 0xffffffff; + mhi_ctrl->sbl_size = SZ_512K; +--- a/drivers/net/wireless/ath/ath11k/pci.c ++++ b/drivers/net/wireless/ath/ath11k/pci.c +@@ -77,6 +77,17 @@ static const struct ath11k_msi_config at + }, + }; + ++static const struct ath11k_msi_config msi_config_one_msi = { ++ .total_vectors = 1, ++ .total_users = 4, ++ .users = (struct ath11k_msi_user[]) { ++ { .name = "MHI", .num_vectors = 3, .base_vector = 0 }, ++ { .name = "CE", .num_vectors = 1, .base_vector = 0 }, ++ { .name = "WAKE", .num_vectors = 1, .base_vector = 0 }, ++ { .name = "DP", .num_vectors = 1, .base_vector = 0 }, ++ }, ++}; ++ + static const char *irq_name[ATH11K_IRQ_NUM_MAX] = { + "bhi", + "mhi-er0", +@@ -619,16 +630,18 @@ static void ath11k_pci_sync_ce_irqs(stru + static void ath11k_pci_ce_tasklet(struct tasklet_struct *t) + { + struct ath11k_ce_pipe *ce_pipe = from_tasklet(ce_pipe, t, intr_tq); ++ int irq_idx = ATH11K_PCI_IRQ_CE0_OFFSET + ce_pipe->pipe_num; + + ath11k_ce_per_engine_service(ce_pipe->ab, ce_pipe->pipe_num); + +- ath11k_pci_ce_irq_enable(ce_pipe->ab, ce_pipe->pipe_num); ++ enable_irq(ce_pipe->ab->irq_num[irq_idx]); + } + + static irqreturn_t ath11k_pci_ce_interrupt_handler(int irq, void *arg) + { + struct ath11k_ce_pipe *ce_pipe = arg; + struct ath11k_base *ab = ce_pipe->ab; ++ int irq_idx = ATH11K_PCI_IRQ_CE0_OFFSET + ce_pipe->pipe_num; + + if (!test_bit(ATH11K_FLAG_CE_IRQ_ENABLED, &ab->dev_flags)) + return IRQ_HANDLED; +@@ -636,7 +649,8 @@ static irqreturn_t ath11k_pci_ce_interru + /* last interrupt received for this CE */ + ce_pipe->timestamp = jiffies; + +- ath11k_pci_ce_irq_disable(ce_pipe->ab, ce_pipe->pipe_num); ++ disable_irq_nosync(ab->irq_num[irq_idx]); ++ + tasklet_schedule(&ce_pipe->intr_tq); + + return IRQ_HANDLED; +@@ -729,11 +743,13 @@ static int ath11k_pci_ext_grp_napi_poll( + napi); + struct ath11k_base *ab = irq_grp->ab; + int work_done; ++ int i; + + work_done = ath11k_dp_service_srng(ab, irq_grp, budget); + if (work_done < budget) { + napi_complete_done(napi, work_done); +- ath11k_pci_ext_grp_enable(irq_grp); ++ for (i = 0; i < irq_grp->num_irq; i++) ++ enable_irq(irq_grp->ab->irq_num[irq_grp->irqs[i]]); + } + + if (work_done > budget) +@@ -746,6 +762,7 @@ static irqreturn_t ath11k_pci_ext_interr + { + struct ath11k_ext_irq_grp *irq_grp = arg; + struct ath11k_base *ab = irq_grp->ab; ++ int i; + + if (!test_bit(ATH11K_FLAG_EXT_IRQ_ENABLED, &ab->dev_flags)) + return IRQ_HANDLED; +@@ -755,7 +772,8 @@ static irqreturn_t ath11k_pci_ext_interr + /* last interrupt received for this group */ + irq_grp->timestamp = jiffies; + +- ath11k_pci_ext_grp_disable(irq_grp); ++ for (i = 0; i < irq_grp->num_irq; i++) ++ disable_irq_nosync(irq_grp->ab->irq_num[irq_grp->irqs[i]]); + + napi_schedule(&irq_grp->napi); + +@@ -941,18 +959,25 @@ static int ath11k_pci_alloc_msi(struct a + msi_config->total_vectors, + msi_config->total_vectors, + PCI_IRQ_MSI); +- if (num_vectors != msi_config->total_vectors) { +- ath11k_err(ab, "failed to get %d MSI vectors, only %d available", +- msi_config->total_vectors, num_vectors); +- +- if (num_vectors >= 0) +- return -EINVAL; +- else +- return num_vectors; +- } else { ++ if (num_vectors == msi_config->total_vectors) { + set_bit(ATH11K_PCI_FLAG_MULTI_MSI_VECTORS, &ab_pci->flags); + ab_pci->irq_flags = IRQF_SHARED; ++ } else { ++ num_vectors = pci_alloc_irq_vectors(ab_pci->pdev, ++ 1, ++ 1, ++ PCI_IRQ_MSI); ++ if (num_vectors < 0) { ++ ret = -EINVAL; ++ goto reset_msi_config; ++ } ++ clear_bit(ATH11K_PCI_FLAG_MULTI_MSI_VECTORS, &ab_pci->flags); ++ ab_pci->msi_config = &msi_config_one_msi; ++ ab_pci->irq_flags = IRQF_SHARED | IRQF_NOBALANCING; ++ ath11k_dbg(ab, ATH11K_DBG_PCI, "request MSI one vector\n"); + } ++ ath11k_info(ab, "MSI vectors: %d\n", num_vectors); ++ + ath11k_pci_msi_disable(ab_pci); + + msi_desc = irq_get_msi_desc(ab_pci->pdev->irq); +@@ -973,6 +998,7 @@ static int ath11k_pci_alloc_msi(struct a + free_msi_vector: + pci_free_irq_vectors(ab_pci->pdev); + ++reset_msi_config: + return ret; + } + diff --git a/package/kernel/mac80211/patches/ath11k/0109-ath11k-do-not-restore-ASPM-in-case-of-single-MSI-vec.patch b/package/kernel/mac80211/patches/ath11k/0109-ath11k-do-not-restore-ASPM-in-case-of-single-MSI-vec.patch new file mode 100644 index 000000000..bdb259cf4 --- /dev/null +++ b/package/kernel/mac80211/patches/ath11k/0109-ath11k-do-not-restore-ASPM-in-case-of-single-MSI-vec.patch @@ -0,0 +1,42 @@ +From 915a081ff307d61d6551d6c16b542e03775353c4 Mon Sep 17 00:00:00 2001 +From: Carl Huang +Date: Fri, 19 Nov 2021 15:36:26 +0200 +Subject: [PATCH 109/120] ath11k: do not restore ASPM in case of single MSI + vector + +Current code enables ASPM by default, it allows MHI to enter M2 state. +In case of one MSI vector, system hang is observed if ath11k does MHI +register reading in this state. The issue was reported on Dell XPS 13 +9310 but is seen also on XPS 15 and XPS 17 laptops. + +The workaround here is to prevent MHI from entering M2 state, this can +be done by disabling ASPM if only one MSI vector is used. When using 32 +vectors ASPM is enabled as before. + +Tested-on: QCA6390 hw2.0 PCI WLAN.HST.1.0.1-01740-QCAHSTSWPLZ_V2_TO_X86-1 + +Signed-off-by: Carl Huang +Signed-off-by: Kalle Valo +Signed-off-by: Baochen Qiang +Link: https://lore.kernel.org/r/20211026041722.5271-1-bqiang@codeaurora.org +--- + drivers/net/wireless/ath/ath11k/pci.c | 8 +++++++- + 1 file changed, 7 insertions(+), 1 deletion(-) + +--- a/drivers/net/wireless/ath/ath11k/pci.c ++++ b/drivers/net/wireless/ath/ath11k/pci.c +@@ -1223,7 +1223,13 @@ static int ath11k_pci_start(struct ath11 + + set_bit(ATH11K_PCI_FLAG_INIT_DONE, &ab_pci->flags); + +- ath11k_pci_aspm_restore(ab_pci); ++ /* TODO: for now don't restore ASPM in case of single MSI ++ * vector as MHI register reading in M2 causes system hang. ++ */ ++ if (test_bit(ATH11K_PCI_FLAG_MULTI_MSI_VECTORS, &ab_pci->flags)) ++ ath11k_pci_aspm_restore(ab_pci); ++ else ++ ath11k_info(ab, "leaving PCI ASPM disabled to avoid MHI M2 problems\n"); + + ath11k_pci_ce_irqs_enable(ab); + ath11k_ce_rx_post_buf(ab); diff --git a/package/kernel/mac80211/patches/ath11k/0110-ath11k-Set-IRQ-affinity-to-CPU0-in-case-of-one-MSI-v.patch b/package/kernel/mac80211/patches/ath11k/0110-ath11k-Set-IRQ-affinity-to-CPU0-in-case-of-one-MSI-v.patch new file mode 100644 index 000000000..f84723669 --- /dev/null +++ b/package/kernel/mac80211/patches/ath11k/0110-ath11k-Set-IRQ-affinity-to-CPU0-in-case-of-one-MSI-v.patch @@ -0,0 +1,90 @@ +From e94b07493da31705c3fdd0b2854f0cffe1dacb3c Mon Sep 17 00:00:00 2001 +From: Baochen Qiang +Date: Fri, 19 Nov 2021 15:36:26 +0200 +Subject: [PATCH 110/120] ath11k: Set IRQ affinity to CPU0 in case of one MSI + vector + +With VT-d disabled on Intel platform, ath11k gets only one MSI +vector. In that case, ath11k does not free IRQ when doing suspend, +hence the kernel has to migrate it to CPU0 (if it was affine to +other CPUs) and allocates a new MSI vector. However, ath11k has +no chance to reconfig it to HW srngs during this phase, thus +ath11k fails to resume. + +This issue can be fixed by setting IRQ affinity to CPU0 before +request_irq is called. With such affinity, migration will not +happen and thus the vector keeps unchanged during suspend/resume. + +Tested-on: QCA6390 hw2.0 PCI WLAN.HST.1.0.1-01740-QCAHSTSWPLZ_V2_TO_X86-1 + +Signed-off-by: Baochen Qiang +Signed-off-by: Kalle Valo +Link: https://lore.kernel.org/r/20211026041732.5323-1-bqiang@codeaurora.org +--- + drivers/net/wireless/ath/ath11k/pci.c | 25 +++++++++++++++++++++++-- + 1 file changed, 23 insertions(+), 2 deletions(-) + +--- a/drivers/net/wireless/ath/ath11k/pci.c ++++ b/drivers/net/wireless/ath/ath11k/pci.c +@@ -843,6 +843,15 @@ static int ath11k_pci_ext_irq_config(str + return 0; + } + ++static int ath11k_pci_set_irq_affinity_hint(struct ath11k_pci *ab_pci, ++ const struct cpumask *m) ++{ ++ if (test_bit(ATH11K_PCI_FLAG_MULTI_MSI_VECTORS, &ab_pci->flags)) ++ return 0; ++ ++ return irq_set_affinity_hint(ab_pci->pdev->irq, m); ++} ++ + static int ath11k_pci_config_irq(struct ath11k_base *ab) + { + struct ath11k_pci *ab_pci = ath11k_pci_priv(ab); +@@ -859,6 +868,12 @@ static int ath11k_pci_config_irq(struct + if (ret) + return ret; + ++ ret = ath11k_pci_set_irq_affinity_hint(ab_pci, cpumask_of(0)); ++ if (ret) { ++ ath11k_err(ab, "failed to set irq affinity %d\n", ret); ++ return ret; ++ } ++ + /* Configure CE irqs */ + for (i = 0, msi_data_idx = 0; i < ab->hw_params.ce_count; i++) { + if (ath11k_ce_get_attr_flags(ab, i) & CE_ATTR_DIS_INTR) +@@ -878,7 +893,7 @@ static int ath11k_pci_config_irq(struct + if (ret) { + ath11k_err(ab, "failed to request irq %d: %d\n", + irq_idx, ret); +- return ret; ++ goto err_irq_affinity_cleanup; + } + + ab->irq_num[irq_idx] = irq; +@@ -889,9 +904,13 @@ static int ath11k_pci_config_irq(struct + + ret = ath11k_pci_ext_irq_config(ab); + if (ret) +- return ret; ++ goto err_irq_affinity_cleanup; + + return 0; ++ ++err_irq_affinity_cleanup: ++ ath11k_pci_set_irq_affinity_hint(ab_pci, NULL); ++ return ret; + } + + static void ath11k_pci_init_qmi_ce_config(struct ath11k_base *ab) +@@ -1488,6 +1507,8 @@ static void ath11k_pci_remove(struct pci + struct ath11k_base *ab = pci_get_drvdata(pdev); + struct ath11k_pci *ab_pci = ath11k_pci_priv(ab); + ++ ath11k_pci_set_irq_affinity_hint(ab_pci, NULL); ++ + if (test_bit(ATH11K_FLAG_QMI_FAIL, &ab->dev_flags)) { + ath11k_pci_power_down(ab); + ath11k_debugfs_soc_destroy(ab); diff --git a/package/kernel/mac80211/patches/ath11k/0111-ath11k-change-to-treat-alpha-code-na-as-world-wide-r.patch b/package/kernel/mac80211/patches/ath11k/0111-ath11k-change-to-treat-alpha-code-na-as-world-wide-r.patch new file mode 100644 index 000000000..6895c5266 --- /dev/null +++ b/package/kernel/mac80211/patches/ath11k/0111-ath11k-change-to-treat-alpha-code-na-as-world-wide-r.patch @@ -0,0 +1,36 @@ +From f8108250e331b8f0273c53afb9e2db5068e59b2e Mon Sep 17 00:00:00 2001 +From: Wen Gong +Date: Mon, 22 Nov 2021 13:13:57 +0200 +Subject: [PATCH 111/120] ath11k: change to treat alpha code na as world wide + regdomain + +Some firmware versions for WCN6855 report the default regdomain with +alpha code "na" by default when load as a world wide regdomain, ath11k +should treat it as a world wide alpha code. + +Tested-on: WCN6855 hw2.0 PCI WLAN.HSP.1.1-01720.1-QCAHSPSWPL_V1_V2_SILICONZ_LITE-1 + +Signed-off-by: Wen Gong +Signed-off-by: Kalle Valo +Link: https://lore.kernel.org/r/20211118094848.7776-1-quic_wgong@quicinc.com +--- + drivers/net/wireless/ath/ath11k/wmi.c | 8 +++++++- + 1 file changed, 7 insertions(+), 1 deletion(-) + +--- a/drivers/net/wireless/ath/ath11k/wmi.c ++++ b/drivers/net/wireless/ath/ath11k/wmi.c +@@ -5927,7 +5927,13 @@ static void ath11k_wmi_htc_tx_complete(s + + static bool ath11k_reg_is_world_alpha(char *alpha) + { +- return alpha[0] == '0' && alpha[1] == '0'; ++ if (alpha[0] == '0' && alpha[1] == '0') ++ return true; ++ ++ if (alpha[0] == 'n' && alpha[1] == 'a') ++ return true; ++ ++ return false; + } + + static int ath11k_reg_chan_list_event(struct ath11k_base *ab, struct sk_buff *skb) diff --git a/package/kernel/mac80211/patches/ath11k/0112-ath11k-calculate-the-correct-NSS-of-peer-for-HE-capa.patch b/package/kernel/mac80211/patches/ath11k/0112-ath11k-calculate-the-correct-NSS-of-peer-for-HE-capa.patch new file mode 100644 index 000000000..580417307 --- /dev/null +++ b/package/kernel/mac80211/patches/ath11k/0112-ath11k-calculate-the-correct-NSS-of-peer-for-HE-capa.patch @@ -0,0 +1,81 @@ +From 3db26ecf7114370e451e296e33a0af3303d32819 Mon Sep 17 00:00:00 2001 +From: Wen Gong +Date: Mon, 22 Nov 2021 13:13:57 +0200 +Subject: [PATCH 112/120] ath11k: calculate the correct NSS of peer for HE + capabilities + +When connected to 6G mode AP, it does not have VHT/HT capabilities, +so the NSS is not set, then it is 1 by default. + +This patch is to calculate the NSS with supported HE-MCS and NSS set +of HE capabilities. + +Tested-on: WCN6855 hw2.0 PCI WLAN.HSP.1.1-01280-QCAHSPSWPL_V1_V2_SILICONZ_LITE-1 + +Signed-off-by: Wen Gong +Signed-off-by: Kalle Valo +Link: https://lore.kernel.org/r/20211118095453.8030-1-quic_wgong@quicinc.com +--- + drivers/net/wireless/ath/ath11k/mac.c | 37 ++++++++++++++++++++++++++- + 1 file changed, 36 insertions(+), 1 deletion(-) + +--- a/drivers/net/wireless/ath/ath11k/mac.c ++++ b/drivers/net/wireless/ath/ath11k/mac.c +@@ -1920,7 +1920,6 @@ static void ath11k_peer_assoc_h_he(struc + struct ath11k_vif *arvif = (void *)vif->drv_priv; + struct cfg80211_chan_def def; + const struct ieee80211_sta_he_cap *he_cap = &sta->he_cap; +- u8 ampdu_factor; + enum nl80211_band band; + u16 *he_mcs_mask; + u8 max_nss, he_mcs; +@@ -1928,6 +1927,9 @@ static void ath11k_peer_assoc_h_he(struc + int i, he_nss, nss_idx; + bool user_rate_valid = true; + u32 rx_nss, tx_nss, nss_160; ++ u8 ampdu_factor, rx_mcs_80, rx_mcs_160; ++ u16 mcs_160_map, mcs_80_map; ++ bool support_160; + + if (WARN_ON(ath11k_mac_vif_chan(vif, &def))) + return; +@@ -1942,6 +1944,39 @@ static void ath11k_peer_assoc_h_he(struc + return; + + arg->he_flag = true; ++ support_160 = !!(he_cap->he_cap_elem.phy_cap_info[0] & ++ IEEE80211_HE_PHY_CAP0_CHANNEL_WIDTH_SET_160MHZ_IN_5G); ++ ++ /* Supported HE-MCS and NSS Set of peer he_cap is intersection with self he_cp */ ++ mcs_160_map = le16_to_cpu(he_cap->he_mcs_nss_supp.rx_mcs_160); ++ mcs_80_map = le16_to_cpu(he_cap->he_mcs_nss_supp.rx_mcs_80); ++ ++ if (support_160) { ++ for (i = 7; i >= 0; i--) { ++ u8 mcs_160 = (mcs_160_map >> (2 * i)) & 3; ++ ++ if (mcs_160 != IEEE80211_VHT_MCS_NOT_SUPPORTED) { ++ rx_mcs_160 = i + 1; ++ break; ++ } ++ } ++ } ++ ++ for (i = 7; i >= 0; i--) { ++ u8 mcs_80 = (mcs_80_map >> (2 * i)) & 3; ++ ++ if (mcs_80 != IEEE80211_VHT_MCS_NOT_SUPPORTED) { ++ rx_mcs_80 = i + 1; ++ break; ++ } ++ } ++ ++ if (support_160) ++ max_nss = min(rx_mcs_80, rx_mcs_160); ++ else ++ max_nss = rx_mcs_80; ++ ++ arg->peer_nss = min(sta->rx_nss, max_nss); + + memcpy_and_pad(&arg->peer_he_cap_macinfo, + sizeof(arg->peer_he_cap_macinfo), diff --git a/package/kernel/mac80211/patches/ath11k/0113-ath11k-fix-read-fail-for-htt_stats-and-htt_peer_stat.patch b/package/kernel/mac80211/patches/ath11k/0113-ath11k-fix-read-fail-for-htt_stats-and-htt_peer_stat.patch new file mode 100644 index 000000000..53b4f3a6c --- /dev/null +++ b/package/kernel/mac80211/patches/ath11k/0113-ath11k-fix-read-fail-for-htt_stats-and-htt_peer_stat.patch @@ -0,0 +1,206 @@ +From 1370634054d4e1e4794057b06ac651b6366ce97d Mon Sep 17 00:00:00 2001 +From: Wen Gong +Date: Mon, 22 Nov 2021 13:13:58 +0200 +Subject: [PATCH 113/120] ath11k: fix read fail for htt_stats and + htt_peer_stats for single pdev + +The pdev id is set to 0 for single pdev configured hardware, the real +pdev id is not 0 in firmware, for example, its pdev id is 1 for 5G/6G +phy and 2 for 2G band phy. For HTT_H2T_MSG_TYPE_EXT_STATS_CFG message, +firmware parse the pdev_mask to its pdev id, ath11k set it to 0 for +single pdev, it is not correct, need set it with the real pdev id of +firmware. + +Save the real pdev id report by firmware and set it correctly. + +Below commands run success with this patch: +cat /sys/kernel/debug/ieee80211/phy0/ath11k/htt_stats +cat /sys/kernel/debug/ieee80211/phy0/netdev\:wls1/stations/00\:03\:7f\:75\:59\:85/htt_peer_stats + +Tested-on: QCA6390 hw2.0 PCI WLAN.HST.1.0.1-01740-QCAHSTSWPLZ_V2_TO_X86-1 + +Signed-off-by: Wen Gong +Signed-off-by: Kalle Valo +Link: https://lore.kernel.org/r/20211118095700.8149-1-quic_wgong@quicinc.com +--- + drivers/net/wireless/ath/ath11k/core.h | 5 ++ + drivers/net/wireless/ath/ath11k/dp_tx.c | 9 +++- + drivers/net/wireless/ath/ath11k/mac.c | 61 +++++++++++++++++++++++++ + drivers/net/wireless/ath/ath11k/mac.h | 4 ++ + drivers/net/wireless/ath/ath11k/wmi.c | 6 +++ + drivers/net/wireless/ath/ath11k/wmi.h | 4 +- + 6 files changed, 86 insertions(+), 3 deletions(-) + +--- a/drivers/net/wireless/ath/ath11k/core.h ++++ b/drivers/net/wireless/ath/ath11k/core.h +@@ -713,6 +713,11 @@ struct ath11k_base { + /* Protects data like peers */ + spinlock_t base_lock; + struct ath11k_pdev pdevs[MAX_RADIOS]; ++ struct { ++ enum WMI_HOST_WLAN_BAND supported_bands; ++ u32 pdev_id; ++ } target_pdev_ids[MAX_RADIOS]; ++ u8 target_pdev_count; + struct ath11k_pdev __rcu *pdevs_active[MAX_RADIOS]; + struct ath11k_hal_reg_capabilities_ext hal_reg_cap[MAX_RADIOS]; + unsigned long long free_vdev_map; +--- a/drivers/net/wireless/ath/ath11k/dp_tx.c ++++ b/drivers/net/wireless/ath/ath11k/dp_tx.c +@@ -9,6 +9,7 @@ + #include "debugfs_sta.h" + #include "hw.h" + #include "peer.h" ++#include "mac.h" + + static enum hal_tcl_encap_type + ath11k_dp_tx_get_encap_type(struct ath11k_vif *arvif, struct sk_buff *skb) +@@ -985,6 +986,7 @@ ath11k_dp_tx_htt_h2t_ext_stats_req(struc + struct ath11k_dp *dp = &ab->dp; + struct sk_buff *skb; + struct htt_ext_stats_cfg_cmd *cmd; ++ u32 pdev_id; + int len = sizeof(*cmd); + int ret; + +@@ -998,7 +1000,12 @@ ath11k_dp_tx_htt_h2t_ext_stats_req(struc + memset(cmd, 0, sizeof(*cmd)); + cmd->hdr.msg_type = HTT_H2T_MSG_TYPE_EXT_STATS_CFG; + +- cmd->hdr.pdev_mask = 1 << ar->pdev->pdev_id; ++ if (ab->hw_params.single_pdev_only) ++ pdev_id = ath11k_mac_get_target_pdev_id(ar); ++ else ++ pdev_id = ar->pdev->pdev_id; ++ ++ cmd->hdr.pdev_mask = 1 << pdev_id; + + cmd->hdr.stats_type = type; + cmd->cfg_param0 = cfg_params->cfg0; +--- a/drivers/net/wireless/ath/ath11k/mac.c ++++ b/drivers/net/wireless/ath/ath11k/mac.c +@@ -553,6 +553,67 @@ struct ath11k *ath11k_mac_get_ar_by_pdev + return NULL; + } + ++struct ath11k_vif *ath11k_mac_get_vif_up(struct ath11k_base *ab) ++{ ++ struct ath11k *ar; ++ struct ath11k_pdev *pdev; ++ struct ath11k_vif *arvif; ++ int i; ++ ++ for (i = 0; i < ab->num_radios; i++) { ++ pdev = &ab->pdevs[i]; ++ ar = pdev->ar; ++ list_for_each_entry(arvif, &ar->arvifs, list) { ++ if (arvif->is_up) ++ return arvif; ++ } ++ } ++ ++ return NULL; ++} ++ ++static bool ath11k_mac_band_match(enum nl80211_band band1, enum WMI_HOST_WLAN_BAND band2) ++{ ++ return (((band1 == NL80211_BAND_2GHZ) && (band2 & WMI_HOST_WLAN_2G_CAP)) || ++ (((band1 == NL80211_BAND_5GHZ) || (band1 == NL80211_BAND_6GHZ)) && ++ (band2 & WMI_HOST_WLAN_5G_CAP))); ++} ++ ++u8 ath11k_mac_get_target_pdev_id_from_vif(struct ath11k_vif *arvif) ++{ ++ struct ath11k *ar = arvif->ar; ++ struct ath11k_base *ab = ar->ab; ++ struct ieee80211_vif *vif = arvif->vif; ++ struct cfg80211_chan_def def; ++ enum nl80211_band band; ++ u8 pdev_id = ab->target_pdev_ids[0].pdev_id; ++ int i; ++ ++ if (WARN_ON(ath11k_mac_vif_chan(vif, &def))) ++ return pdev_id; ++ ++ band = def.chan->band; ++ ++ for (i = 0; i < ab->target_pdev_count; i++) { ++ if (ath11k_mac_band_match(band, ab->target_pdev_ids[i].supported_bands)) ++ return ab->target_pdev_ids[i].pdev_id; ++ } ++ ++ return pdev_id; ++} ++ ++u8 ath11k_mac_get_target_pdev_id(struct ath11k *ar) ++{ ++ struct ath11k_vif *arvif; ++ ++ arvif = ath11k_mac_get_vif_up(ar->ab); ++ ++ if (arvif) ++ return ath11k_mac_get_target_pdev_id_from_vif(arvif); ++ else ++ return ar->ab->target_pdev_ids[0].pdev_id; ++} ++ + static void ath11k_pdev_caps_update(struct ath11k *ar) + { + struct ath11k_base *ab = ar->ab; +--- a/drivers/net/wireless/ath/ath11k/mac.h ++++ b/drivers/net/wireless/ath/ath11k/mac.h +@@ -144,6 +144,10 @@ void ath11k_mac_scan_finish(struct ath11 + struct ath11k_vif *ath11k_mac_get_arvif(struct ath11k *ar, u32 vdev_id); + struct ath11k_vif *ath11k_mac_get_arvif_by_vdev_id(struct ath11k_base *ab, + u32 vdev_id); ++u8 ath11k_mac_get_target_pdev_id(struct ath11k *ar); ++u8 ath11k_mac_get_target_pdev_id_from_vif(struct ath11k_vif *arvif); ++struct ath11k_vif *ath11k_mac_get_vif_up(struct ath11k_base *ab); ++ + struct ath11k *ath11k_mac_get_ar_by_vdev_id(struct ath11k_base *ab, u32 vdev_id); + struct ath11k *ath11k_mac_get_ar_by_pdev_id(struct ath11k_base *ab, u32 pdev_id); + +--- a/drivers/net/wireless/ath/ath11k/wmi.c ++++ b/drivers/net/wireless/ath/ath11k/wmi.c +@@ -337,6 +337,7 @@ ath11k_pull_mac_phy_cap_svc_ready_ext(st + struct ath11k_pdev *pdev) + { + struct wmi_mac_phy_capabilities *mac_phy_caps; ++ struct ath11k_base *ab = wmi_handle->wmi_ab->ab; + struct ath11k_band_cap *cap_band; + struct ath11k_pdev_cap *pdev_cap = &pdev->cap; + u32 phy_map; +@@ -368,6 +369,10 @@ ath11k_pull_mac_phy_cap_svc_ready_ext(st + pdev->pdev_id = mac_phy_caps->pdev_id; + pdev_cap->supported_bands |= mac_phy_caps->supported_bands; + pdev_cap->ampdu_density = mac_phy_caps->ampdu_density; ++ ab->target_pdev_ids[ab->target_pdev_count].supported_bands = ++ mac_phy_caps->supported_bands; ++ ab->target_pdev_ids[ab->target_pdev_count].pdev_id = mac_phy_caps->pdev_id; ++ ab->target_pdev_count++; + + /* Take non-zero tx/rx chainmask. If tx/rx chainmask differs from + * band to band for a single radio, need to see how this should be +@@ -4230,6 +4235,7 @@ static int ath11k_wmi_tlv_ext_soc_hal_re + svc_rdy_ext->param.num_phy = svc_rdy_ext->soc_hal_reg_caps->num_phy; + + soc->num_radios = 0; ++ soc->target_pdev_count = 0; + phy_id_map = svc_rdy_ext->pref_hw_mode_caps.phy_id_map; + + while (phy_id_map && soc->num_radios < MAX_RADIOS) { +--- a/drivers/net/wireless/ath/ath11k/wmi.h ++++ b/drivers/net/wireless/ath/ath11k/wmi.h +@@ -113,10 +113,10 @@ enum wmi_host_hw_mode_priority { + WMI_HOST_HW_MODE_MAX_PRI + }; + +-enum { ++enum WMI_HOST_WLAN_BAND { + WMI_HOST_WLAN_2G_CAP = 0x1, + WMI_HOST_WLAN_5G_CAP = 0x2, +- WMI_HOST_WLAN_2G_5G_CAP = 0x3, ++ WMI_HOST_WLAN_2G_5G_CAP = WMI_HOST_WLAN_2G_CAP | WMI_HOST_WLAN_5G_CAP, + }; + + /* Parameters used for WMI_VDEV_PARAM_AUTORATE_MISC_CFG command. diff --git a/package/kernel/mac80211/patches/ath11k/0114-ath11k-skip-sending-vdev-down-for-channel-switch.patch b/package/kernel/mac80211/patches/ath11k/0114-ath11k-skip-sending-vdev-down-for-channel-switch.patch new file mode 100644 index 000000000..8947552e7 --- /dev/null +++ b/package/kernel/mac80211/patches/ath11k/0114-ath11k-skip-sending-vdev-down-for-channel-switch.patch @@ -0,0 +1,68 @@ +From a4146249a33381f41f6d15eaa1797d7ba1820a31 Mon Sep 17 00:00:00 2001 +From: Wen Gong +Date: Mon, 22 Nov 2021 13:13:58 +0200 +Subject: [PATCH 114/120] ath11k: skip sending vdev down for channel switch + +The ath11k driver currently sends vdev down to the firmware before +updating the channel context, which is followed by a vdev restart +command. + +Sending vdev down is not required before sending a vdev restart, +because the firmware internally does vdev down when ath11k sends +a vdev restart command. + +Firmware will happen crash while channel switch without this change. + +Hence skip the vdev down command sending when updating the channel +context and then fix the firmware crash issue. + +Tested-on: QCA6390 hw2.0 PCI WLAN.HST.1.0.1-01740-QCAHSTSWPLZ_V2_TO_X86-1 + +Signed-off-by: Wen Gong +Signed-off-by: Kalle Valo +Link: https://lore.kernel.org/r/20211118095901.8271-1-quic_wgong@quicinc.com +--- + drivers/net/wireless/ath/ath11k/mac.c | 32 +-------------------------- + 1 file changed, 1 insertion(+), 31 deletions(-) + +--- a/drivers/net/wireless/ath/ath11k/mac.c ++++ b/drivers/net/wireless/ath/ath11k/mac.c +@@ -6459,37 +6459,7 @@ ath11k_mac_update_vif_chan(struct ath11k + + lockdep_assert_held(&ar->conf_mutex); + +- for (i = 0; i < n_vifs; i++) { +- arvif = (void *)vifs[i].vif->drv_priv; +- +- if (vifs[i].vif->type == NL80211_IFTYPE_MONITOR) +- monitor_vif = true; +- +- ath11k_dbg(ab, ATH11K_DBG_MAC, +- "mac chanctx switch vdev_id %i freq %u->%u width %d->%d\n", +- arvif->vdev_id, +- vifs[i].old_ctx->def.chan->center_freq, +- vifs[i].new_ctx->def.chan->center_freq, +- vifs[i].old_ctx->def.width, +- vifs[i].new_ctx->def.width); +- +- if (WARN_ON(!arvif->is_started)) +- continue; +- +- if (WARN_ON(!arvif->is_up)) +- continue; +- +- ret = ath11k_wmi_vdev_down(ar, arvif->vdev_id); +- if (ret) { +- ath11k_warn(ab, "failed to down vdev %d: %d\n", +- arvif->vdev_id, ret); +- continue; +- } +- +- ar->num_started_vdevs--; +- } +- +- /* All relevant vdevs are downed and associated channel resources ++ /* Associated channel resources of all relevant vdevs + * should be available for the channel switch now. + */ + diff --git a/package/kernel/mac80211/patches/ath11k/0115-ath11k-add-read-variant-from-SMBIOS-for-download-boa.patch b/package/kernel/mac80211/patches/ath11k/0115-ath11k-add-read-variant-from-SMBIOS-for-download-boa.patch new file mode 100644 index 000000000..7956d1492 --- /dev/null +++ b/package/kernel/mac80211/patches/ath11k/0115-ath11k-add-read-variant-from-SMBIOS-for-download-boa.patch @@ -0,0 +1,158 @@ +From 46e46db313a2bf3c48cac4eb8bdb613b762f301b Mon Sep 17 00:00:00 2001 +From: Wen Gong +Date: Mon, 22 Nov 2021 13:13:58 +0200 +Subject: [PATCH 115/120] ath11k: add read variant from SMBIOS for download + board data + +This is to read variant from SMBIOS such as read from DT, the variant +string will be used to one part of string which used to search board +data from board-2.bin. + +Tested-on: WCN6855 hw2.0 PCI WLAN.HSP.1.1-01720.1-QCAHSPSWPL_V1_V2_SILICONZ_LITE-1 + +Signed-off-by: Wen Gong +Signed-off-by: Kalle Valo +Link: https://lore.kernel.org/r/20211118100033.8384-1-quic_wgong@quicinc.com +--- + drivers/net/wireless/ath/ath11k/core.c | 79 ++++++++++++++++++++++++++ + drivers/net/wireless/ath/ath11k/core.h | 13 +++++ + drivers/net/wireless/ath/ath11k/qmi.c | 4 ++ + 3 files changed, 96 insertions(+) + +--- a/drivers/net/wireless/ath/ath11k/core.c ++++ b/drivers/net/wireless/ath/ath11k/core.c +@@ -8,6 +8,9 @@ + #include + #include + #include ++#include ++#include ++ + #include "core.h" + #include "dp_tx.h" + #include "dp_rx.h" +@@ -384,6 +387,82 @@ int ath11k_core_resume(struct ath11k_bas + } + EXPORT_SYMBOL(ath11k_core_resume); + ++static void ath11k_core_check_bdfext(const struct dmi_header *hdr, void *data) ++{ ++ struct ath11k_base *ab = data; ++ const char *bdf_ext; ++ const char *magic = ATH11K_SMBIOS_BDF_EXT_MAGIC; ++ u8 bdf_enabled; ++ int i; ++ size_t len; ++ ++ if (ab->qmi.target.bdf_ext[0] != '\0') ++ return; ++ ++ if (hdr->type != ATH11K_SMBIOS_BDF_EXT_TYPE) ++ return; ++ ++ if (hdr->length != ATH11K_SMBIOS_BDF_EXT_LENGTH) { ++ ath11k_dbg(ab, ATH11K_DBG_BOOT, ++ "wrong smbios bdf ext type length (%d).\n", ++ hdr->length); ++ return; ++ } ++ ++ bdf_enabled = *((u8 *)hdr + ATH11K_SMBIOS_BDF_EXT_OFFSET); ++ if (!bdf_enabled) { ++ ath11k_dbg(ab, ATH11K_DBG_BOOT, "bdf variant name not found.\n"); ++ return; ++ } ++ ++ /* Only one string exists (per spec) */ ++ bdf_ext = (char *)hdr + hdr->length; ++ ++ if (memcmp(bdf_ext, magic, strlen(magic)) != 0) { ++ ath11k_dbg(ab, ATH11K_DBG_BOOT, ++ "bdf variant magic does not match.\n"); ++ return; ++ } ++ ++ len = strlen(bdf_ext); ++ for (i = 0; i < len; i++) { ++ if (!isascii(bdf_ext[i]) || !isprint(bdf_ext[i])) { ++ ath11k_dbg(ab, ATH11K_DBG_BOOT, ++ "bdf variant name contains non ascii chars.\n"); ++ return; ++ } ++ } ++ ++ /* Copy extension name without magic prefix */ ++ if (strscpy(ab->qmi.target.bdf_ext, bdf_ext + strlen(magic), ++ sizeof(ab->qmi.target.bdf_ext)) < 0) { ++ ath11k_dbg(ab, ATH11K_DBG_BOOT, ++ "bdf variant string is longer than the buffer can accommodate (variant: %s)\n", ++ bdf_ext); ++ return; ++ } ++ ++ ath11k_dbg(ab, ATH11K_DBG_BOOT, ++ "found and validated bdf variant smbios_type 0x%x bdf %s\n", ++ ATH11K_SMBIOS_BDF_EXT_TYPE, bdf_ext); ++} ++ ++int ath11k_core_check_smbios(struct ath11k_base *ab) ++{ ++ int ret; ++ ++ ab->qmi.target.bdf_ext[0] = '\0'; ++ ++ ret = dmi_walk(ath11k_core_check_bdfext, ab); ++ if (ret) ++ return ret; ++ ++ if (ab->qmi.target.bdf_ext[0] == '\0') ++ return -ENODATA; ++ ++ return 0; ++} ++ + int ath11k_core_check_dt(struct ath11k_base *ab) + { + size_t max_len = sizeof(ab->qmi.target.bdf_ext); +--- a/drivers/net/wireless/ath/ath11k/core.h ++++ b/drivers/net/wireless/ath/ath11k/core.h +@@ -938,6 +938,18 @@ struct ath11k_fw_stats_bcn { + u32 tx_bcn_outage_cnt; + }; + ++/* SMBIOS type containing Board Data File Name Extension */ ++#define ATH11K_SMBIOS_BDF_EXT_TYPE 0xF8 ++ ++/* SMBIOS type structure length (excluding strings-set) */ ++#define ATH11K_SMBIOS_BDF_EXT_LENGTH 0x9 ++ ++/* Offset pointing to Board Data File Name Extension */ ++#define ATH11K_SMBIOS_BDF_EXT_OFFSET 0x8 ++ ++/* The magic used by QCA spec */ ++#define ATH11K_SMBIOS_BDF_EXT_MAGIC "BDF_" ++ + extern const struct ce_pipe_config ath11k_target_ce_config_wlan_ipq8074[]; + extern const struct service_to_pipe ath11k_target_service_to_ce_map_wlan_ipq8074[]; + extern const struct service_to_pipe ath11k_target_service_to_ce_map_wlan_ipq6018[]; +@@ -959,6 +971,7 @@ int ath11k_core_fetch_bdf(struct ath11k_ + struct ath11k_board_data *bd); + void ath11k_core_free_bdf(struct ath11k_base *ab, struct ath11k_board_data *bd); + int ath11k_core_check_dt(struct ath11k_base *ath11k); ++int ath11k_core_check_smbios(struct ath11k_base *ab); + + void ath11k_core_halt(struct ath11k *ar); + int ath11k_core_resume(struct ath11k_base *ab); +--- a/drivers/net/wireless/ath/ath11k/qmi.c ++++ b/drivers/net/wireless/ath/ath11k/qmi.c +@@ -1991,6 +1991,10 @@ static int ath11k_qmi_request_target_cap + ab->qmi.target.fw_build_timestamp, + ab->qmi.target.fw_build_id); + ++ r = ath11k_core_check_smbios(ab); ++ if (r) ++ ath11k_dbg(ab, ATH11K_DBG_QMI, "SMBIOS bdf variant name not set.\n"); ++ + r = ath11k_core_check_dt(ab); + if (r) + ath11k_dbg(ab, ATH11K_DBG_QMI, "DT bdf variant name not set.\n"); diff --git a/package/kernel/mac80211/patches/ath11k/0116-ath11k-Fix-mon-status-ring-rx-tlv-processing.patch b/package/kernel/mac80211/patches/ath11k/0116-ath11k-Fix-mon-status-ring-rx-tlv-processing.patch new file mode 100644 index 000000000..6c8fb867a --- /dev/null +++ b/package/kernel/mac80211/patches/ath11k/0116-ath11k-Fix-mon-status-ring-rx-tlv-processing.patch @@ -0,0 +1,65 @@ +From 09f16f7390f302937409738d6cb6ce99b265f455 Mon Sep 17 00:00:00 2001 +From: Anilkumar Kolli +Date: Mon, 22 Nov 2021 13:13:58 +0200 +Subject: [PATCH 116/120] ath11k: Fix mon status ring rx tlv processing + +In HE monitor capture, HAL_TLV_STATUS_PPDU_DONE is received +on processing multiple skb. Do not clear the ppdu_info +till the HAL_TLV_STATUS_PPDU_DONE is received. + +This fixes below warning and packet drops in monitor mode. + "Rate marked as an HE rate but data is invalid: MCS: 6, NSS: 0" + WARNING: at + PC is at ieee80211_rx_napi+0x624/0x840 [mac80211] + +Tested-on: IPQ8074 hw2.0 AHB WLAN.HK.2.4.0.1-01693-QCAHKSWPL_SILICONZ-1 + +Signed-off-by: Anilkumar Kolli +Signed-off-by: Kalle Valo +Link: https://lore.kernel.org/r/1637249433-10316-1-git-send-email-akolli@codeaurora.org +--- + drivers/net/wireless/ath/ath11k/dp_rx.c | 14 +++++++------- + 1 file changed, 7 insertions(+), 7 deletions(-) + +--- a/drivers/net/wireless/ath/ath11k/dp_rx.c ++++ b/drivers/net/wireless/ath/ath11k/dp_rx.c +@@ -3061,10 +3061,10 @@ int ath11k_dp_rx_process_mon_status(stru + if (!num_buffs_reaped) + goto exit; + +- while ((skb = __skb_dequeue(&skb_list))) { +- memset(&ppdu_info, 0, sizeof(ppdu_info)); +- ppdu_info.peer_id = HAL_INVALID_PEERID; ++ memset(&ppdu_info, 0, sizeof(ppdu_info)); ++ ppdu_info.peer_id = HAL_INVALID_PEERID; + ++ while ((skb = __skb_dequeue(&skb_list))) { + if (ath11k_debugfs_is_pktlog_lite_mode_enabled(ar)) { + log_type = ATH11K_PKTLOG_TYPE_LITE_RX; + rx_buf_sz = DP_RX_BUFFER_SIZE_LITE; +@@ -3092,10 +3092,7 @@ int ath11k_dp_rx_process_mon_status(stru + ath11k_dbg(ab, ATH11K_DBG_DATA, + "failed to find the peer with peer_id %d\n", + ppdu_info.peer_id); +- spin_unlock_bh(&ab->base_lock); +- rcu_read_unlock(); +- dev_kfree_skb_any(skb); +- continue; ++ goto next_skb; + } + + arsta = (struct ath11k_sta *)peer->sta->drv_priv; +@@ -3104,10 +3101,13 @@ int ath11k_dp_rx_process_mon_status(stru + if (ath11k_debugfs_is_pktlog_peer_valid(ar, peer->addr)) + trace_ath11k_htt_rxdesc(ar, skb->data, log_type, rx_buf_sz); + ++next_skb: + spin_unlock_bh(&ab->base_lock); + rcu_read_unlock(); + + dev_kfree_skb_any(skb); ++ memset(&ppdu_info, 0, sizeof(ppdu_info)); ++ ppdu_info.peer_id = HAL_INVALID_PEERID; + } + exit: + return num_buffs_reaped; diff --git a/package/kernel/mac80211/patches/ath11k/0117-Revert-ath11k-add-read-variant-from-SMBIOS-for-downl.patch b/package/kernel/mac80211/patches/ath11k/0117-Revert-ath11k-add-read-variant-from-SMBIOS-for-downl.patch new file mode 100644 index 000000000..40cd1e07d --- /dev/null +++ b/package/kernel/mac80211/patches/ath11k/0117-Revert-ath11k-add-read-variant-from-SMBIOS-for-downl.patch @@ -0,0 +1,168 @@ +From 72f4124347724e3b8aa434f6bc4a2cd69f7bb336 Mon Sep 17 00:00:00 2001 +From: Kalle Valo +Date: Wed, 24 Nov 2021 11:43:16 +0200 +Subject: [PATCH 117/120] Revert "ath11k: add read variant from SMBIOS for + download board data" +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +This reverts commit 46e46db313a2bf3c48cac4eb8bdb613b762f301b. Mark reported +that it breaks QCA6390 hw2.0 on Dell XPS 13 9310: + +[    5.537034] ath11k_pci 0000:72:00.0: chip_id 0x0 chip_family 0xb board_id 0xff soc_id 0xffffffff +[    5.537038] ath11k_pci 0000:72:00.0: fw_version 0x101c06cc fw_build_timestamp 2020-06-24 19:50 fw_build_id +[    5.537236] ath11k_pci 0000:72:00.0: failed to fetch board data for bus=pci,qmi-chip-id=0,qmi-board-id=255,variant=DE_1901 from ath11k/QCA6390/hw2.0/board-2.bin +[    5.537255] ath11k_pci 0000:72:00.0: failed to fetch board-2.bin or board.bin from QCA6390/hw2.0 +[    5.537257] ath11k_pci 0000:72:00.0: qmi failed to fetch board file: -2 +[    5.537258] ath11k_pci 0000:72:00.0: failed to load board data file: -2 + +So we need to back to the drawing board and implement it so that backwards +compatiblity is not broken. + +Reported-by: Mark Herbert +Signed-off-by: Kalle Valo +Link: https://lore.kernel.org/r/20211124094316.9096-1-kvalo@codeaurora.org +--- + drivers/net/wireless/ath/ath11k/core.c | 79 -------------------------- + drivers/net/wireless/ath/ath11k/core.h | 13 ----- + drivers/net/wireless/ath/ath11k/qmi.c | 4 -- + 3 files changed, 96 deletions(-) + +--- a/drivers/net/wireless/ath/ath11k/core.c ++++ b/drivers/net/wireless/ath/ath11k/core.c +@@ -8,9 +8,6 @@ + #include + #include + #include +-#include +-#include +- + #include "core.h" + #include "dp_tx.h" + #include "dp_rx.h" +@@ -387,82 +384,6 @@ int ath11k_core_resume(struct ath11k_bas + } + EXPORT_SYMBOL(ath11k_core_resume); + +-static void ath11k_core_check_bdfext(const struct dmi_header *hdr, void *data) +-{ +- struct ath11k_base *ab = data; +- const char *bdf_ext; +- const char *magic = ATH11K_SMBIOS_BDF_EXT_MAGIC; +- u8 bdf_enabled; +- int i; +- size_t len; +- +- if (ab->qmi.target.bdf_ext[0] != '\0') +- return; +- +- if (hdr->type != ATH11K_SMBIOS_BDF_EXT_TYPE) +- return; +- +- if (hdr->length != ATH11K_SMBIOS_BDF_EXT_LENGTH) { +- ath11k_dbg(ab, ATH11K_DBG_BOOT, +- "wrong smbios bdf ext type length (%d).\n", +- hdr->length); +- return; +- } +- +- bdf_enabled = *((u8 *)hdr + ATH11K_SMBIOS_BDF_EXT_OFFSET); +- if (!bdf_enabled) { +- ath11k_dbg(ab, ATH11K_DBG_BOOT, "bdf variant name not found.\n"); +- return; +- } +- +- /* Only one string exists (per spec) */ +- bdf_ext = (char *)hdr + hdr->length; +- +- if (memcmp(bdf_ext, magic, strlen(magic)) != 0) { +- ath11k_dbg(ab, ATH11K_DBG_BOOT, +- "bdf variant magic does not match.\n"); +- return; +- } +- +- len = strlen(bdf_ext); +- for (i = 0; i < len; i++) { +- if (!isascii(bdf_ext[i]) || !isprint(bdf_ext[i])) { +- ath11k_dbg(ab, ATH11K_DBG_BOOT, +- "bdf variant name contains non ascii chars.\n"); +- return; +- } +- } +- +- /* Copy extension name without magic prefix */ +- if (strscpy(ab->qmi.target.bdf_ext, bdf_ext + strlen(magic), +- sizeof(ab->qmi.target.bdf_ext)) < 0) { +- ath11k_dbg(ab, ATH11K_DBG_BOOT, +- "bdf variant string is longer than the buffer can accommodate (variant: %s)\n", +- bdf_ext); +- return; +- } +- +- ath11k_dbg(ab, ATH11K_DBG_BOOT, +- "found and validated bdf variant smbios_type 0x%x bdf %s\n", +- ATH11K_SMBIOS_BDF_EXT_TYPE, bdf_ext); +-} +- +-int ath11k_core_check_smbios(struct ath11k_base *ab) +-{ +- int ret; +- +- ab->qmi.target.bdf_ext[0] = '\0'; +- +- ret = dmi_walk(ath11k_core_check_bdfext, ab); +- if (ret) +- return ret; +- +- if (ab->qmi.target.bdf_ext[0] == '\0') +- return -ENODATA; +- +- return 0; +-} +- + int ath11k_core_check_dt(struct ath11k_base *ab) + { + size_t max_len = sizeof(ab->qmi.target.bdf_ext); +--- a/drivers/net/wireless/ath/ath11k/core.h ++++ b/drivers/net/wireless/ath/ath11k/core.h +@@ -938,18 +938,6 @@ struct ath11k_fw_stats_bcn { + u32 tx_bcn_outage_cnt; + }; + +-/* SMBIOS type containing Board Data File Name Extension */ +-#define ATH11K_SMBIOS_BDF_EXT_TYPE 0xF8 +- +-/* SMBIOS type structure length (excluding strings-set) */ +-#define ATH11K_SMBIOS_BDF_EXT_LENGTH 0x9 +- +-/* Offset pointing to Board Data File Name Extension */ +-#define ATH11K_SMBIOS_BDF_EXT_OFFSET 0x8 +- +-/* The magic used by QCA spec */ +-#define ATH11K_SMBIOS_BDF_EXT_MAGIC "BDF_" +- + extern const struct ce_pipe_config ath11k_target_ce_config_wlan_ipq8074[]; + extern const struct service_to_pipe ath11k_target_service_to_ce_map_wlan_ipq8074[]; + extern const struct service_to_pipe ath11k_target_service_to_ce_map_wlan_ipq6018[]; +@@ -971,7 +959,6 @@ int ath11k_core_fetch_bdf(struct ath11k_ + struct ath11k_board_data *bd); + void ath11k_core_free_bdf(struct ath11k_base *ab, struct ath11k_board_data *bd); + int ath11k_core_check_dt(struct ath11k_base *ath11k); +-int ath11k_core_check_smbios(struct ath11k_base *ab); + + void ath11k_core_halt(struct ath11k *ar); + int ath11k_core_resume(struct ath11k_base *ab); +--- a/drivers/net/wireless/ath/ath11k/qmi.c ++++ b/drivers/net/wireless/ath/ath11k/qmi.c +@@ -1991,10 +1991,6 @@ static int ath11k_qmi_request_target_cap + ab->qmi.target.fw_build_timestamp, + ab->qmi.target.fw_build_id); + +- r = ath11k_core_check_smbios(ab); +- if (r) +- ath11k_dbg(ab, ATH11K_DBG_QMI, "SMBIOS bdf variant name not set.\n"); +- + r = ath11k_core_check_dt(ab); + if (r) + ath11k_dbg(ab, ATH11K_DBG_QMI, "DT bdf variant name not set.\n"); diff --git a/package/kernel/mac80211/patches/ath11k/0118-ath11k-Fix-spelling-mistake-detetction-detection.patch b/package/kernel/mac80211/patches/ath11k/0118-ath11k-Fix-spelling-mistake-detetction-detection.patch new file mode 100644 index 000000000..bbfdcf4e0 --- /dev/null +++ b/package/kernel/mac80211/patches/ath11k/0118-ath11k-Fix-spelling-mistake-detetction-detection.patch @@ -0,0 +1,26 @@ +From c27506cc7733261bafd7a97e7990407eef433d32 Mon Sep 17 00:00:00 2001 +From: Colin Ian King +Date: Tue, 23 Nov 2021 09:04:31 +0000 +Subject: [PATCH 118/120] ath11k: Fix spelling mistake "detetction" -> + "detection" + +There is a spelling mistake in an ath11k_warn message. Fix it. + +Signed-off-by: Colin Ian King +Signed-off-by: Kalle Valo +Link: https://lore.kernel.org/r/20211123090431.165103-1-colin.i.king@gmail.com +--- + drivers/net/wireless/ath/ath11k/wmi.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +--- a/drivers/net/wireless/ath/ath11k/wmi.c ++++ b/drivers/net/wireless/ath/ath11k/wmi.c +@@ -3511,7 +3511,7 @@ ath11k_wmi_obss_color_collision_event(st + case WMI_BSS_COLOR_FREE_SLOT_AVAILABLE: + break; + default: +- ath11k_warn(ab, "received unknown obss color collision detetction event\n"); ++ ath11k_warn(ab, "received unknown obss color collision detection event\n"); + } + + exit: diff --git a/package/kernel/mac80211/patches/ath11k/0120-ath11k-Use-host-CE-parameters-for-CE-interrupts-conf.patch b/package/kernel/mac80211/patches/ath11k/0120-ath11k-Use-host-CE-parameters-for-CE-interrupts-conf.patch new file mode 100644 index 000000000..9eaf1b2cf --- /dev/null +++ b/package/kernel/mac80211/patches/ath11k/0120-ath11k-Use-host-CE-parameters-for-CE-interrupts-conf.patch @@ -0,0 +1,69 @@ +From b689f091aafd1a874b2f88137934276ab0fca480 Mon Sep 17 00:00:00 2001 +From: Anilkumar Kolli +Date: Wed, 24 Nov 2021 19:11:31 +0200 +Subject: [PATCH 120/120] ath11k: Use host CE parameters for CE interrupts + configuration + +CE interrupt configuration uses host ce parameters to assign/free +interrupts. Use host ce parameters to enable/disable interrupts. +This patch fixes below BUG, + +BUG: KASAN: global-out-of-bounds in 0xffffffbffdfb035c at addr +ffffffbffde6eeac + Read of size 4 by task kworker/u8:2/132 + Address belongs to variable ath11k_core_qmi_firmware_ready+0x1b0/0x5bc [ath11k] + +OOB is due to ath11k_ahb_ce_irqs_enable() iterates ce_count(which is 12) +times and accessing 12th element in target_ce_config +(which has only 11 elements) from ath11k_ahb_ce_irq_enable(). + +With this change host ce configs are used to enable/disable interrupts. + +Tested-on: IPQ8074 hw2.0 AHB WLAN.HK.2.5.0.1-00471-QCAHKSWPL_SILICONZ-1 + +Fixes: 967c1d1131fa ("ath11k: move target ce configs to hw_params") +Signed-off-by: Anilkumar Kolli +Signed-off-by: Kalle Valo +Link: https://lore.kernel.org/r/1637249558-12793-1-git-send-email-akolli@codeaurora.org +--- + drivers/net/wireless/ath/ath11k/ahb.c | 16 ++++++++-------- + 1 file changed, 8 insertions(+), 8 deletions(-) + +--- a/drivers/net/wireless/ath/ath11k/ahb.c ++++ b/drivers/net/wireless/ath/ath11k/ahb.c +@@ -206,13 +206,13 @@ static void ath11k_ahb_clearbit32(struct + + static void ath11k_ahb_ce_irq_enable(struct ath11k_base *ab, u16 ce_id) + { +- const struct ce_pipe_config *ce_config; ++ const struct ce_attr *ce_attr; + +- ce_config = &ab->hw_params.target_ce_config[ce_id]; +- if (__le32_to_cpu(ce_config->pipedir) & PIPEDIR_OUT) ++ ce_attr = &ab->hw_params.host_ce_config[ce_id]; ++ if (ce_attr->src_nentries) + ath11k_ahb_setbit32(ab, ce_id, CE_HOST_IE_ADDRESS); + +- if (__le32_to_cpu(ce_config->pipedir) & PIPEDIR_IN) { ++ if (ce_attr->dest_nentries) { + ath11k_ahb_setbit32(ab, ce_id, CE_HOST_IE_2_ADDRESS); + ath11k_ahb_setbit32(ab, ce_id + CE_HOST_IE_3_SHIFT, + CE_HOST_IE_3_ADDRESS); +@@ -221,13 +221,13 @@ static void ath11k_ahb_ce_irq_enable(str + + static void ath11k_ahb_ce_irq_disable(struct ath11k_base *ab, u16 ce_id) + { +- const struct ce_pipe_config *ce_config; ++ const struct ce_attr *ce_attr; + +- ce_config = &ab->hw_params.target_ce_config[ce_id]; +- if (__le32_to_cpu(ce_config->pipedir) & PIPEDIR_OUT) ++ ce_attr = &ab->hw_params.host_ce_config[ce_id]; ++ if (ce_attr->src_nentries) + ath11k_ahb_clearbit32(ab, ce_id, CE_HOST_IE_ADDRESS); + +- if (__le32_to_cpu(ce_config->pipedir) & PIPEDIR_IN) { ++ if (ce_attr->dest_nentries) { + ath11k_ahb_clearbit32(ab, ce_id, CE_HOST_IE_2_ADDRESS); + ath11k_ahb_clearbit32(ab, ce_id + CE_HOST_IE_3_SHIFT, + CE_HOST_IE_3_ADDRESS); diff --git a/package/kernel/mac80211/patches/ath11k/0121-ath11k-Avoid-NULL-ptr-access-during-mgmt-tx-cleanup.patch b/package/kernel/mac80211/patches/ath11k/0121-ath11k-Avoid-NULL-ptr-access-during-mgmt-tx-cleanup.patch new file mode 100644 index 000000000..7267fd034 --- /dev/null +++ b/package/kernel/mac80211/patches/ath11k/0121-ath11k-Avoid-NULL-ptr-access-during-mgmt-tx-cleanup.patch @@ -0,0 +1,109 @@ +From a93789ae541c7d5c1c2a4942013adb6bcc5e2848 Mon Sep 17 00:00:00 2001 +From: Sriram R +Date: Thu, 25 Nov 2021 15:00:14 +0530 +Subject: [PATCH] ath11k: Avoid NULL ptr access during mgmt tx cleanup + +Currently 'ar' reference is not added in skb_cb during +WMI mgmt tx. Though this is generally not used during tx completion +callbacks, on interface removal the remaining idr cleanup callback +uses the ar ptr from skb_cb from mgmt txmgmt_idr. Hence +fill them during tx call for proper usage. + +Also free the skb which is missing currently in these +callbacks. + +Crash_info: + +[19282.489476] Unable to handle kernel NULL pointer dereference at virtual address 00000000 +[19282.489515] pgd = 91eb8000 +[19282.496702] [00000000] *pgd=00000000 +[19282.502524] Internal error: Oops: 5 [#1] PREEMPT SMP ARM +[19282.783728] PC is at ath11k_mac_vif_txmgmt_idr_remove+0x28/0xd8 [ath11k] +[19282.789170] LR is at idr_for_each+0xa0/0xc8 + +Tested-on: IPQ8074 hw2.0 AHB WLAN.HK.2.5.0.1-00729-QCAHKSWPL_SILICONZ-3 v2 +Signed-off-by: Sriram R +Signed-off-by: Kalle Valo +Link: https://lore.kernel.org/r/1637832614-13831-1-git-send-email-quic_srirrama@quicinc.com +--- + drivers/net/wireless/ath/ath11k/mac.c | 35 +++++++++++++++------------ + 1 file changed, 20 insertions(+), 15 deletions(-) + +--- a/drivers/net/wireless/ath/ath11k/mac.c ++++ b/drivers/net/wireless/ath/ath11k/mac.c +@@ -1,6 +1,7 @@ + // SPDX-License-Identifier: BSD-3-Clause-Clear + /* + * Copyright (c) 2018-2019 The Linux Foundation. All rights reserved. ++ * Copyright (c) 2021 Qualcomm Innovation Center, Inc. All rights reserved. + */ + + #include +@@ -5224,23 +5225,32 @@ static int __ath11k_set_antenna(struct a + return 0; + } + +-int ath11k_mac_tx_mgmt_pending_free(int buf_id, void *skb, void *ctx) ++static void ath11k_mac_tx_mgmt_free(struct ath11k *ar, int buf_id) + { +- struct sk_buff *msdu = skb; ++ struct sk_buff *msdu; + struct ieee80211_tx_info *info; +- struct ath11k *ar = ctx; +- struct ath11k_base *ab = ar->ab; + + spin_lock_bh(&ar->txmgmt_idr_lock); +- idr_remove(&ar->txmgmt_idr, buf_id); ++ msdu = idr_remove(&ar->txmgmt_idr, buf_id); + spin_unlock_bh(&ar->txmgmt_idr_lock); +- dma_unmap_single(ab->dev, ATH11K_SKB_CB(msdu)->paddr, msdu->len, ++ ++ if (!msdu) ++ return; ++ ++ dma_unmap_single(ar->ab->dev, ATH11K_SKB_CB(msdu)->paddr, msdu->len, + DMA_TO_DEVICE); + + info = IEEE80211_SKB_CB(msdu); + memset(&info->status, 0, sizeof(info->status)); + + ieee80211_free_txskb(ar->hw, msdu); ++} ++ ++int ath11k_mac_tx_mgmt_pending_free(int buf_id, void *skb, void *ctx) ++{ ++ struct ath11k *ar = ctx; ++ ++ ath11k_mac_tx_mgmt_free(ar, buf_id); + + return 0; + } +@@ -5249,17 +5259,10 @@ static int ath11k_mac_vif_txmgmt_idr_rem + { + struct ieee80211_vif *vif = ctx; + struct ath11k_skb_cb *skb_cb = ATH11K_SKB_CB((struct sk_buff *)skb); +- struct sk_buff *msdu = skb; + struct ath11k *ar = skb_cb->ar; +- struct ath11k_base *ab = ar->ab; + +- if (skb_cb->vif == vif) { +- spin_lock_bh(&ar->txmgmt_idr_lock); +- idr_remove(&ar->txmgmt_idr, buf_id); +- spin_unlock_bh(&ar->txmgmt_idr_lock); +- dma_unmap_single(ab->dev, skb_cb->paddr, msdu->len, +- DMA_TO_DEVICE); +- } ++ if (skb_cb->vif == vif) ++ ath11k_mac_tx_mgmt_free(ar, buf_id); + + return 0; + } +@@ -5274,6 +5277,8 @@ static int ath11k_mac_mgmt_tx_wmi(struct + int buf_id; + int ret; + ++ ATH11K_SKB_CB(skb)->ar = ar; ++ + spin_lock_bh(&ar->txmgmt_idr_lock); + buf_id = idr_alloc(&ar->txmgmt_idr, skb, 0, + ATH11K_TX_MGMT_NUM_PENDING_MAX, GFP_ATOMIC); diff --git a/package/kernel/mac80211/patches/ath11k/0122-ath11k-add-support-for-WCN6855-hw2.1.patch b/package/kernel/mac80211/patches/ath11k/0122-ath11k-add-support-for-WCN6855-hw2.1.patch new file mode 100644 index 000000000..3aa43ad50 --- /dev/null +++ b/package/kernel/mac80211/patches/ath11k/0122-ath11k-add-support-for-WCN6855-hw2.1.patch @@ -0,0 +1,152 @@ +From d1147a316b53df9cb0152e415ec41dcb6ea62c1c Mon Sep 17 00:00:00 2001 +From: Baochen Qiang +Date: Mon, 29 Nov 2021 10:56:12 +0800 +Subject: [PATCH] ath11k: add support for WCN6855 hw2.1 + +Ath11k fails to probe WCN6855 hw2.1 chip: + +[ 6.983821] ath11k_pci 0000:06:00.0: enabling device (0000 -> 0002) +[ 6.983841] ath11k_pci 0000:06:00.0: Unsupported WCN6855 SOC hardware version: 18 17 + +This is caused by the wrong bit mask setting of hardware major version: +for QCA6390/QCN6855, it should be BIT8-11, not BIT8-16, so change the +definition to GENMASK(11, 8). + +Also, add a separate entry for WCN6855 hw2.1 in ath11k_hw_params. + +Please note that currently WCN6855 hw2.1 shares the same firmwares +as hw2.0, so users of this chip need to create a symlink as below: + + ln -s hw2.0 hw2.1 + +Tested-on: WCN6855 hw2.1 PCI WLAN.HSP.1.1-01720.1-QCAHSPSWPL_V1_V2_SILICONZ_LITE-1 +Tested-on: WCN6855 hw2.0 PCI WLAN.HSP.1.1-01720.1-QCAHSPSWPL_V1_V2_SILICONZ_LITE-1 +Tested-on: QCA6390 hw2.0 PCI WLAN.HST.1.0.1-01740-QCAHSTSWPLZ_V2_TO_X86-1 + +Fixes: 18ac1665e785 ("ath11k: pci: check TCSR_SOC_HW_VERSION") +Signed-off-by: Baochen Qiang +Signed-off-by: Kalle Valo +Link: https://lore.kernel.org/r/20211129025613.21594-1-quic_bqiang@quicinc.com +--- + drivers/net/wireless/ath/ath11k/core.c | 53 ++++++++++++++++++++++++++ + drivers/net/wireless/ath/ath11k/core.h | 1 + + drivers/net/wireless/ath/ath11k/mhi.c | 1 + + drivers/net/wireless/ath/ath11k/pci.c | 16 +++++++- + 4 files changed, 69 insertions(+), 2 deletions(-) + +--- a/drivers/net/wireless/ath/ath11k/core.c ++++ b/drivers/net/wireless/ath/ath11k/core.c +@@ -301,6 +301,59 @@ static const struct ath11k_hw_params ath + .alloc_cacheable_memory = false, + .wakeup_mhi = true, + }, ++ { ++ .name = "wcn6855 hw2.1", ++ .hw_rev = ATH11K_HW_WCN6855_HW21, ++ .fw = { ++ .dir = "WCN6855/hw2.1", ++ .board_size = 256 * 1024, ++ .cal_offset = 128 * 1024, ++ }, ++ .max_radios = 3, ++ .bdf_addr = 0x4B0C0000, ++ .hw_ops = &wcn6855_ops, ++ .ring_mask = &ath11k_hw_ring_mask_qca6390, ++ .internal_sleep_clock = true, ++ .regs = &wcn6855_regs, ++ .qmi_service_ins_id = ATH11K_QMI_WLFW_SERVICE_INS_ID_V01_QCA6390, ++ .host_ce_config = ath11k_host_ce_config_qca6390, ++ .ce_count = 9, ++ .target_ce_config = ath11k_target_ce_config_wlan_qca6390, ++ .target_ce_count = 9, ++ .svc_to_ce_map = ath11k_target_service_to_ce_map_wlan_qca6390, ++ .svc_to_ce_map_len = 14, ++ .single_pdev_only = true, ++ .rxdma1_enable = false, ++ .num_rxmda_per_pdev = 2, ++ .rx_mac_buf_ring = true, ++ .vdev_start_delay = true, ++ .htt_peer_map_v2 = false, ++ ++ .spectral = { ++ .fft_sz = 0, ++ .fft_pad_sz = 0, ++ .summary_pad_sz = 0, ++ .fft_hdr_len = 0, ++ .max_fft_bins = 0, ++ }, ++ ++ .interface_modes = BIT(NL80211_IFTYPE_STATION) | ++ BIT(NL80211_IFTYPE_AP), ++ .supports_monitor = false, ++ .supports_shadow_regs = true, ++ .idle_ps = true, ++ .supports_sta_ps = true, ++ .cold_boot_calib = false, ++ .supports_suspend = true, ++ .hal_desc_sz = sizeof(struct hal_rx_desc_wcn6855), ++ .fix_l1ss = false, ++ .credit_flow = true, ++ .max_tx_ring = DP_TCL_NUM_RING_MAX_QCA6390, ++ .hal_params = &ath11k_hw_hal_params_qca6390, ++ .supports_dynamic_smps_6ghz = false, ++ .alloc_cacheable_memory = false, ++ .wakeup_mhi = true, ++ }, + }; + + int ath11k_core_suspend(struct ath11k_base *ab) +--- a/drivers/net/wireless/ath/ath11k/core.h ++++ b/drivers/net/wireless/ath/ath11k/core.h +@@ -117,6 +117,7 @@ enum ath11k_hw_rev { + ATH11K_HW_IPQ6018_HW10, + ATH11K_HW_QCN9074_HW10, + ATH11K_HW_WCN6855_HW20, ++ ATH11K_HW_WCN6855_HW21, + }; + + enum ath11k_firmware_mode { +--- a/drivers/net/wireless/ath/ath11k/mhi.c ++++ b/drivers/net/wireless/ath/ath11k/mhi.c +@@ -368,6 +368,7 @@ int ath11k_mhi_register(struct ath11k_pc + break; + case ATH11K_HW_QCA6390_HW20: + case ATH11K_HW_WCN6855_HW20: ++ case ATH11K_HW_WCN6855_HW21: + ath11k_mhi_config = &ath11k_mhi_config_qca6390; + break; + default: +--- a/drivers/net/wireless/ath/ath11k/pci.c ++++ b/drivers/net/wireless/ath/ath11k/pci.c +@@ -26,7 +26,7 @@ + #define WINDOW_RANGE_MASK GENMASK(18, 0) + + #define TCSR_SOC_HW_VERSION 0x0224 +-#define TCSR_SOC_HW_VERSION_MAJOR_MASK GENMASK(16, 8) ++#define TCSR_SOC_HW_VERSION_MAJOR_MASK GENMASK(11, 8) + #define TCSR_SOC_HW_VERSION_MINOR_MASK GENMASK(7, 0) + + /* BAR0 + 4k is always accessible, and no +@@ -1409,9 +1409,21 @@ static int ath11k_pci_probe(struct pci_d + &soc_hw_version_minor); + switch (soc_hw_version_major) { + case 2: +- ab->hw_rev = ATH11K_HW_WCN6855_HW20; ++ switch (soc_hw_version_minor) { ++ case 0x00: ++ case 0x01: ++ ab->hw_rev = ATH11K_HW_WCN6855_HW20; ++ break; ++ case 0x10: ++ case 0x11: ++ ab->hw_rev = ATH11K_HW_WCN6855_HW21; ++ break; ++ default: ++ goto unsupported_wcn6855_soc; ++ } + break; + default: ++unsupported_wcn6855_soc: + dev_err(&pdev->dev, "Unsupported WCN6855 SOC hardware version: %d %d\n", + soc_hw_version_major, soc_hw_version_minor); + ret = -EOPNOTSUPP; diff --git a/package/kernel/mac80211/patches/ath11k/0123-ath11k-Fix-QMI-file-type-enum-value.patch b/package/kernel/mac80211/patches/ath11k/0123-ath11k-Fix-QMI-file-type-enum-value.patch new file mode 100644 index 000000000..3d1b5bfd0 --- /dev/null +++ b/package/kernel/mac80211/patches/ath11k/0123-ath11k-Fix-QMI-file-type-enum-value.patch @@ -0,0 +1,32 @@ +From 18ae1ab04525507ae5528245a6df004cacd0d39a Mon Sep 17 00:00:00 2001 +From: Seevalamuthu Mariappan +Date: Mon, 29 Nov 2021 16:15:54 +0530 +Subject: [PATCH] ath11k: Fix QMI file type enum value + +bdf_type for caldata in QMI_WLANFW_BDF_DOWNLOAD_REQ_V01 is wrongly +sent as 1. But, expected bdf_type value for caldata and EEPROM is 2 and 3 +respectively. It leads to firmware crash. Fix ath11k_qmi_file_type enum +values. + +Tested-on: QCN9074 hw1.0 PCI WLAN.HK.2.5.0.1-01100-QCAHKSWPL_SILICONZ-1 +Tested-on: IPQ8074 hw2.0 AHB WLAN.HK.2.4.0.1-00192-QCAHKSWPL_SILICONZ-1 + +Fixes: 336e7b53c82f ("ath11k: clean up BDF download functions") +Signed-off-by: Seevalamuthu Mariappan +Signed-off-by: Kalle Valo +Link: https://lore.kernel.org/r/1638182754-18408-1-git-send-email-quic_seevalam@quicinc.com +--- + drivers/net/wireless/ath/ath11k/qmi.h | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +--- a/drivers/net/wireless/ath/ath11k/qmi.h ++++ b/drivers/net/wireless/ath/ath11k/qmi.h +@@ -41,7 +41,7 @@ struct ath11k_base; + + enum ath11k_qmi_file_type { + ATH11K_QMI_FILE_TYPE_BDF_GOLDEN, +- ATH11K_QMI_FILE_TYPE_CALDATA, ++ ATH11K_QMI_FILE_TYPE_CALDATA = 2, + ATH11K_QMI_FILE_TYPE_EEPROM, + ATH11K_QMI_MAX_FILE_TYPE, + }; diff --git a/package/kernel/mac80211/patches/ath11k/0124-ath11k-change-to-use-dynamic-memory-for-channel-list.patch b/package/kernel/mac80211/patches/ath11k/0124-ath11k-change-to-use-dynamic-memory-for-channel-list.patch new file mode 100644 index 000000000..11399d333 --- /dev/null +++ b/package/kernel/mac80211/patches/ath11k/0124-ath11k-change-to-use-dynamic-memory-for-channel-list.patch @@ -0,0 +1,66 @@ +From cea7f78d85f3f6ba05f43754600426b0e84abbbd Mon Sep 17 00:00:00 2001 +From: Wen Gong +Date: Mon, 29 Nov 2021 06:09:39 -0500 +Subject: [PATCH] ath11k: change to use dynamic memory for channel list of scan + +Currently there are about 60 channels for 6 GHz, then the size of +chan_list in struct scan_req_params which is 40 is not enough to +fill all the channel list of 6 GHz. + +Use dynamic memory to save the channel list of scan. + +Tested-on: WCN6855 hw2.0 PCI WLAN.HSP.1.1-01720.1-QCAHSPSWPL_V1_V2_SILICONZ_LITE-1 + +Signed-off-by: Wen Gong +Signed-off-by: Kalle Valo +Link: https://lore.kernel.org/r/20211129110939.15711-1-quic_wgong@quicinc.com +--- + drivers/net/wireless/ath/ath11k/mac.c | 10 ++++++++++ + drivers/net/wireless/ath/ath11k/wmi.h | 3 +-- + 2 files changed, 11 insertions(+), 2 deletions(-) + +--- a/drivers/net/wireless/ath/ath11k/mac.c ++++ b/drivers/net/wireless/ath/ath11k/mac.c +@@ -3501,6 +3501,14 @@ static int ath11k_mac_op_hw_scan(struct + + if (req->n_channels) { + arg.num_chan = req->n_channels; ++ arg.chan_list = kcalloc(arg.num_chan, sizeof(*arg.chan_list), ++ GFP_KERNEL); ++ ++ if (!arg.chan_list) { ++ ret = -ENOMEM; ++ goto exit; ++ } ++ + for (i = 0; i < arg.num_chan; i++) + arg.chan_list[i] = req->channels[i]->center_freq; + } +@@ -3519,6 +3527,8 @@ static int ath11k_mac_op_hw_scan(struct + ATH11K_MAC_SCAN_TIMEOUT_MSECS)); + + exit: ++ kfree(arg.chan_list); ++ + if (req->ie_len) + kfree(arg.extraie.ptr); + +--- a/drivers/net/wireless/ath/ath11k/wmi.h ++++ b/drivers/net/wireless/ath/ath11k/wmi.h +@@ -3082,7 +3082,6 @@ enum scan_dwelltime_adaptive_mode { + + #define WLAN_SCAN_MAX_NUM_SSID 10 + #define WLAN_SCAN_MAX_NUM_BSSID 10 +-#define WLAN_SCAN_MAX_NUM_CHANNELS 40 + + #define WLAN_SSID_MAX_LEN 32 + +@@ -3303,7 +3302,7 @@ struct scan_req_params { + u32 num_bssid; + u32 num_ssids; + u32 n_probes; +- u32 chan_list[WLAN_SCAN_MAX_NUM_CHANNELS]; ++ u32 *chan_list; + u32 notify_scan_events; + struct wlan_ssid ssid[WLAN_SCAN_MAX_NUM_SSID]; + struct wmi_mac_addr bssid_list[WLAN_SCAN_MAX_NUM_BSSID]; diff --git a/package/kernel/mac80211/patches/ath11k/0125-ath11k-avoid-deadlock-by-change-ieee80211_queue_work.patch b/package/kernel/mac80211/patches/ath11k/0125-ath11k-avoid-deadlock-by-change-ieee80211_queue_work.patch new file mode 100644 index 000000000..28796600a --- /dev/null +++ b/package/kernel/mac80211/patches/ath11k/0125-ath11k-avoid-deadlock-by-change-ieee80211_queue_work.patch @@ -0,0 +1,195 @@ +From ed05c7cf1286d7e31e7623bce55ff135723591bf Mon Sep 17 00:00:00 2001 +From: Wen Gong +Date: Tue, 7 Dec 2021 17:23:36 +0200 +Subject: [PATCH] ath11k: avoid deadlock by change ieee80211_queue_work for + regd_update_work + +When enable debug config, it print below warning while shut down wlan +interface shuh as run "ifconfig wlan0 down". + +The reason is because ar->regd_update_work is ran once, and it is will +call wiphy_lock(ar->hw->wiphy) in function ath11k_regd_update() which +is running in workqueue of ieee80211_local queued by ieee80211_queue_work(). +Another thread from "ifconfig wlan0 down" will also accuqire the lock +by wiphy_lock(sdata->local->hw.wiphy) in function ieee80211_stop(), and +then it call ieee80211_stop_device() to flush_workqueue(local->workqueue), +this will wait the workqueue of ieee80211_local finished. Then deadlock +will happen easily if the two thread run meanwhile. + +Below warning disappeared after this change. + +[ 914.088798] ath11k_pci 0000:05:00.0: mac remove interface (vdev 0) +[ 914.088806] ath11k_pci 0000:05:00.0: mac stop 11d scan +[ 914.088810] ath11k_pci 0000:05:00.0: mac stop 11d vdev id 0 +[ 914.088827] ath11k_pci 0000:05:00.0: htc ep 2 consumed 1 credits (total 0) +[ 914.088841] ath11k_pci 0000:05:00.0: send 11d scan stop vdev id 0 +[ 914.088849] ath11k_pci 0000:05:00.0: htc insufficient credits ep 2 required 1 available 0 +[ 914.088856] ath11k_pci 0000:05:00.0: htc insufficient credits ep 2 required 1 available 0 +[ 914.096434] ath11k_pci 0000:05:00.0: rx ce pipe 2 len 16 +[ 914.096442] ath11k_pci 0000:05:00.0: htc ep 2 got 1 credits (total 1) +[ 914.096481] ath11k_pci 0000:05:00.0: htc ep 2 consumed 1 credits (total 0) +[ 914.096491] ath11k_pci 0000:05:00.0: WMI vdev delete id 0 +[ 914.111598] ath11k_pci 0000:05:00.0: rx ce pipe 2 len 16 +[ 914.111628] ath11k_pci 0000:05:00.0: htc ep 2 got 1 credits (total 1) +[ 914.114659] ath11k_pci 0000:05:00.0: rx ce pipe 2 len 20 +[ 914.114742] ath11k_pci 0000:05:00.0: htc rx completion ep 2 skb pK-error +[ 914.115977] ath11k_pci 0000:05:00.0: vdev delete resp for vdev id 0 +[ 914.116685] ath11k_pci 0000:05:00.0: vdev 00:03:7f:29:61:11 deleted, vdev_id 0 + +[ 914.117583] ====================================================== +[ 914.117592] WARNING: possible circular locking dependency detected +[ 914.117600] 5.16.0-rc1-wt-ath+ #1 Tainted: G OE +[ 914.117611] ------------------------------------------------------ +[ 914.117618] ifconfig/2805 is trying to acquire lock: +[ 914.117628] ffff9c00a62bb548 ((wq_completion)phy0){+.+.}-{0:0}, at: flush_workqueue+0x87/0x470 +[ 914.117674] + but task is already holding lock: +[ 914.117682] ffff9c00baea07d0 (&rdev->wiphy.mtx){+.+.}-{4:4}, at: ieee80211_stop+0x38/0x180 [mac80211] +[ 914.117872] + which lock already depends on the new lock. + +[ 914.117880] + the existing dependency chain (in reverse order) is: +[ 914.117888] + -> #3 (&rdev->wiphy.mtx){+.+.}-{4:4}: +[ 914.117910] __mutex_lock+0xa0/0x9c0 +[ 914.117930] mutex_lock_nested+0x1b/0x20 +[ 914.117944] reg_process_self_managed_hints+0x3a/0xb0 [cfg80211] +[ 914.118093] wiphy_regulatory_register+0x47/0x80 [cfg80211] +[ 914.118229] wiphy_register+0x84f/0x9c0 [cfg80211] +[ 914.118353] ieee80211_register_hw+0x6b1/0xd90 [mac80211] +[ 914.118486] ath11k_mac_register+0x6af/0xb60 [ath11k] +[ 914.118550] ath11k_core_qmi_firmware_ready+0x383/0x4a0 [ath11k] +[ 914.118598] ath11k_qmi_driver_event_work+0x347/0x4a0 [ath11k] +[ 914.118656] process_one_work+0x228/0x670 +[ 914.118669] worker_thread+0x4d/0x440 +[ 914.118680] kthread+0x16d/0x1b0 +[ 914.118697] ret_from_fork+0x22/0x30 +[ 914.118714] + -> #2 (rtnl_mutex){+.+.}-{4:4}: +[ 914.118736] __mutex_lock+0xa0/0x9c0 +[ 914.118751] mutex_lock_nested+0x1b/0x20 +[ 914.118767] rtnl_lock+0x17/0x20 +[ 914.118783] ath11k_regd_update+0x15a/0x260 [ath11k] +[ 914.118841] ath11k_regd_update_work+0x15/0x20 [ath11k] +[ 914.118897] process_one_work+0x228/0x670 +[ 914.118909] worker_thread+0x4d/0x440 +[ 914.118920] kthread+0x16d/0x1b0 +[ 914.118934] ret_from_fork+0x22/0x30 +[ 914.118948] + -> #1 ((work_completion)(&ar->regd_update_work)){+.+.}-{0:0}: +[ 914.118972] process_one_work+0x1fa/0x670 +[ 914.118984] worker_thread+0x4d/0x440 +[ 914.118996] kthread+0x16d/0x1b0 +[ 914.119010] ret_from_fork+0x22/0x30 +[ 914.119023] + -> #0 ((wq_completion)phy0){+.+.}-{0:0}: +[ 914.119045] __lock_acquire+0x146d/0x1cf0 +[ 914.119057] lock_acquire+0x19b/0x360 +[ 914.119067] flush_workqueue+0xae/0x470 +[ 914.119084] ieee80211_stop_device+0x3b/0x50 [mac80211] +[ 914.119260] ieee80211_do_stop+0x5d7/0x830 [mac80211] +[ 914.119409] ieee80211_stop+0x45/0x180 [mac80211] +[ 914.119557] __dev_close_many+0xb3/0x120 +[ 914.119573] __dev_change_flags+0xc3/0x1d0 +[ 914.119590] dev_change_flags+0x29/0x70 +[ 914.119605] devinet_ioctl+0x653/0x810 +[ 914.119620] inet_ioctl+0x193/0x1e0 +[ 914.119631] sock_do_ioctl+0x4d/0xf0 +[ 914.119649] sock_ioctl+0x262/0x340 +[ 914.119665] __x64_sys_ioctl+0x96/0xd0 +[ 914.119678] do_syscall_64+0x3d/0xd0 +[ 914.119694] entry_SYSCALL_64_after_hwframe+0x44/0xae +[ 914.119709] + other info that might help us debug this: + +[ 914.119717] Chain exists of: + (wq_completion)phy0 --> rtnl_mutex --> &rdev->wiphy.mtx + +[ 914.119745] Possible unsafe locking scenario: + +[ 914.119752] CPU0 CPU1 +[ 914.119758] ---- ---- +[ 914.119765] lock(&rdev->wiphy.mtx); +[ 914.119778] lock(rtnl_mutex); +[ 914.119792] lock(&rdev->wiphy.mtx); +[ 914.119807] lock((wq_completion)phy0); +[ 914.119819] + *** DEADLOCK *** + +[ 914.119827] 2 locks held by ifconfig/2805: +[ 914.119837] #0: ffffffffba3dc010 (rtnl_mutex){+.+.}-{4:4}, at: rtnl_lock+0x17/0x20 +[ 914.119872] #1: ffff9c00baea07d0 (&rdev->wiphy.mtx){+.+.}-{4:4}, at: ieee80211_stop+0x38/0x180 [mac80211] +[ 914.120039] + stack backtrace: +[ 914.120048] CPU: 0 PID: 2805 Comm: ifconfig Tainted: G OE 5.16.0-rc1-wt-ath+ #1 +[ 914.120064] Hardware name: LENOVO 418065C/418065C, BIOS 83ET63WW (1.33 ) 07/29/2011 +[ 914.120074] Call Trace: +[ 914.120084] +[ 914.120094] dump_stack_lvl+0x73/0xa4 +[ 914.120119] dump_stack+0x10/0x12 +[ 914.120135] print_circular_bug.isra.44+0x221/0x2e0 +[ 914.120165] check_noncircular+0x106/0x150 +[ 914.120203] __lock_acquire+0x146d/0x1cf0 +[ 914.120215] ? __lock_acquire+0x146d/0x1cf0 +[ 914.120245] lock_acquire+0x19b/0x360 +[ 914.120259] ? flush_workqueue+0x87/0x470 +[ 914.120286] ? lockdep_init_map_type+0x6b/0x250 +[ 914.120310] flush_workqueue+0xae/0x470 +[ 914.120327] ? flush_workqueue+0x87/0x470 +[ 914.120344] ? lockdep_hardirqs_on+0xd7/0x150 +[ 914.120391] ieee80211_stop_device+0x3b/0x50 [mac80211] +[ 914.120565] ? ieee80211_stop_device+0x3b/0x50 [mac80211] +[ 914.120736] ieee80211_do_stop+0x5d7/0x830 [mac80211] +[ 914.120906] ieee80211_stop+0x45/0x180 [mac80211] +[ 914.121060] __dev_close_many+0xb3/0x120 +[ 914.121081] __dev_change_flags+0xc3/0x1d0 +[ 914.121109] dev_change_flags+0x29/0x70 +[ 914.121131] devinet_ioctl+0x653/0x810 +[ 914.121149] ? __might_fault+0x77/0x80 +[ 914.121179] inet_ioctl+0x193/0x1e0 +[ 914.121194] ? inet_ioctl+0x193/0x1e0 +[ 914.121218] ? __might_fault+0x77/0x80 +[ 914.121238] ? _copy_to_user+0x68/0x80 +[ 914.121266] sock_do_ioctl+0x4d/0xf0 +[ 914.121283] ? inet_stream_connect+0x60/0x60 +[ 914.121297] ? sock_do_ioctl+0x4d/0xf0 +[ 914.121329] sock_ioctl+0x262/0x340 +[ 914.121347] ? sock_ioctl+0x262/0x340 +[ 914.121362] ? exit_to_user_mode_prepare+0x13b/0x280 +[ 914.121388] ? syscall_enter_from_user_mode+0x20/0x50 +[ 914.121416] __x64_sys_ioctl+0x96/0xd0 +[ 914.121430] ? br_ioctl_call+0x90/0x90 +[ 914.121445] ? __x64_sys_ioctl+0x96/0xd0 +[ 914.121465] do_syscall_64+0x3d/0xd0 +[ 914.121482] entry_SYSCALL_64_after_hwframe+0x44/0xae +[ 914.121497] RIP: 0033:0x7f0ed051737b +[ 914.121513] Code: 0f 1e fa 48 8b 05 15 3b 0d 00 64 c7 00 26 00 00 00 48 c7 c0 ff ff ff ff c3 66 0f 1f 44 00 00 f3 0f 1e fa b8 10 00 00 00 0f 05 <48> 3d 01 f0 ff ff 73 01 c3 48 8b 0d e5 3a 0d 00 f7 d8 64 89 01 48 +[ 914.121527] RSP: 002b:00007fff7be38b98 EFLAGS: 00000202 ORIG_RAX: 0000000000000010 +[ 914.121544] RAX: ffffffffffffffda RBX: 00007fff7be38ba0 RCX: 00007f0ed051737b +[ 914.121555] RDX: 00007fff7be38ba0 RSI: 0000000000008914 RDI: 0000000000000004 +[ 914.121566] RBP: 00007fff7be38c60 R08: 000000000000000a R09: 0000000000000001 +[ 914.121576] R10: 0000000000000000 R11: 0000000000000202 R12: 00000000fffffffe +[ 914.121586] R13: 0000000000000004 R14: 0000000000000000 R15: 0000000000000000 +[ 914.121620] + +Tested-on: WCN6855 hw2.0 PCI WLAN.HSP.1.1-01720.1-QCAHSPSWPL_V1_V2_SILICONZ_LITE-1 + +Signed-off-by: Wen Gong +Signed-off-by: Kalle Valo +Link: https://lore.kernel.org/r/20211201071745.17746-2-quic_wgong@quicinc.com +--- + drivers/net/wireless/ath/ath11k/wmi.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +--- a/drivers/net/wireless/ath/ath11k/wmi.c ++++ b/drivers/net/wireless/ath/ath11k/wmi.c +@@ -6032,7 +6032,7 @@ static int ath11k_reg_chan_list_event(st + ar = ab->pdevs[pdev_idx].ar; + kfree(ab->new_regd[pdev_idx]); + ab->new_regd[pdev_idx] = regd; +- ieee80211_queue_work(ar->hw, &ar->regd_update_work); ++ queue_work(ab->workqueue, &ar->regd_update_work); + } else { + /* This regd would be applied during mac registration and is + * held constant throughout for regd intersection purpose diff --git a/package/kernel/mac80211/patches/ath11k/0126-ath11k-add-configure-country-code-for-QCA6390-and-WC.patch b/package/kernel/mac80211/patches/ath11k/0126-ath11k-add-configure-country-code-for-QCA6390-and-WC.patch new file mode 100644 index 000000000..3d8a60ca5 --- /dev/null +++ b/package/kernel/mac80211/patches/ath11k/0126-ath11k-add-configure-country-code-for-QCA6390-and-WC.patch @@ -0,0 +1,92 @@ +From 0b05ddad8e4bd56bda42b9dc491c1b127720f063 Mon Sep 17 00:00:00 2001 +From: Wen Gong +Date: Tue, 7 Dec 2021 17:23:36 +0200 +Subject: [PATCH] ath11k: add configure country code for QCA6390 and WCN6855 + +Add handler to send WMI_SET_CURRENT_COUNTRY_CMDID to firmware which +is used for QCA6390 and WCN6855. + +Tested-on: WCN6855 hw2.0 PCI WLAN.HSP.1.1-01720.1-QCAHSPSWPL_V1_V2_SILICONZ_LITE-1 +Tested-on: QCA6390 hw2.0 PCI WLAN.HST.1.0.1-01740-QCAHSTSWPLZ_V2_TO_X86-1 + +Signed-off-by: Wen Gong +Signed-off-by: Kalle Valo +Link: https://lore.kernel.org/r/20211201071745.17746-3-quic_wgong@quicinc.com +--- + drivers/net/wireless/ath/ath11k/wmi.c | 36 +++++++++++++++++++++++++++ + drivers/net/wireless/ath/ath11k/wmi.h | 12 +++++++++ + 2 files changed, 48 insertions(+) + +--- a/drivers/net/wireless/ath/ath11k/wmi.c ++++ b/drivers/net/wireless/ath/ath11k/wmi.c +@@ -2798,6 +2798,42 @@ out: + return ret; + } + ++int ath11k_wmi_send_set_current_country_cmd(struct ath11k *ar, ++ struct wmi_set_current_country_params *param) ++{ ++ struct ath11k_pdev_wmi *wmi = ar->wmi; ++ struct wmi_set_current_country_cmd *cmd; ++ struct sk_buff *skb; ++ int ret; ++ ++ skb = ath11k_wmi_alloc_skb(wmi->wmi_ab, sizeof(*cmd)); ++ if (!skb) ++ return -ENOMEM; ++ ++ cmd = (struct wmi_set_current_country_cmd *)skb->data; ++ cmd->tlv_header = ++ FIELD_PREP(WMI_TLV_TAG, WMI_TAG_SET_CURRENT_COUNTRY_CMD) | ++ FIELD_PREP(WMI_TLV_LEN, sizeof(*cmd) - TLV_HDR_SIZE); ++ ++ cmd->pdev_id = ar->pdev->pdev_id; ++ memcpy(&cmd->new_alpha2, ¶m->alpha2, 3); ++ ret = ath11k_wmi_cmd_send(wmi, skb, WMI_SET_CURRENT_COUNTRY_CMDID); ++ ++ ath11k_dbg(ar->ab, ATH11K_DBG_WMI, ++ "set current country pdev id %d alpha2 %c%c\n", ++ ar->pdev->pdev_id, ++ param->alpha2[0], ++ param->alpha2[1]); ++ ++ if (ret) { ++ ath11k_warn(ar->ab, ++ "failed to send WMI_SET_CURRENT_COUNTRY_CMDID: %d\n", ret); ++ dev_kfree_skb(skb); ++ } ++ ++ return ret; ++} ++ + int + ath11k_wmi_send_thermal_mitigation_param_cmd(struct ath11k *ar, + struct thermal_mitigation_params *param) +--- a/drivers/net/wireless/ath/ath11k/wmi.h ++++ b/drivers/net/wireless/ath/ath11k/wmi.h +@@ -3769,6 +3769,16 @@ struct stats_request_params { + u32 pdev_id; + }; + ++struct wmi_set_current_country_params { ++ u8 alpha2[3]; ++}; ++ ++struct wmi_set_current_country_cmd { ++ u32 tlv_header; ++ u32 pdev_id; ++ u32 new_alpha2; ++} __packed; ++ + enum set_init_cc_type { + WMI_COUNTRY_INFO_TYPE_ALPHA, + WMI_COUNTRY_INFO_TYPE_COUNTRY_CODE, +@@ -5432,6 +5442,8 @@ int ath11k_wmi_delba_send(struct ath11k + u32 tid, u32 initiator, u32 reason); + int ath11k_wmi_send_bcn_offload_control_cmd(struct ath11k *ar, + u32 vdev_id, u32 bcn_ctrl_op); ++int ath11k_wmi_send_set_current_country_cmd(struct ath11k *ar, ++ struct wmi_set_current_country_params *param); + int + ath11k_wmi_send_init_country_cmd(struct ath11k *ar, + struct wmi_init_country_params init_cc_param); diff --git a/package/kernel/mac80211/patches/ath11k/0127-ath11k-add-11d-scan-offload-support.patch b/package/kernel/mac80211/patches/ath11k/0127-ath11k-add-11d-scan-offload-support.patch new file mode 100644 index 000000000..8cf2feeea --- /dev/null +++ b/package/kernel/mac80211/patches/ath11k/0127-ath11k-add-11d-scan-offload-support.patch @@ -0,0 +1,600 @@ +From 9dcf6808b253a72b2c90eed179863bf5fab7d68c Mon Sep 17 00:00:00 2001 +From: Wen Gong +Date: Tue, 7 Dec 2021 17:23:36 +0200 +Subject: [PATCH] ath11k: add 11d scan offload support + +Add handler for WMI_11D_NEW_COUNTRY_EVENTID, WMI_11D_SCAN_START_CMDID, +WMI_11D_SCAN_STOP_CMDID. + +After vdev create for STATION, send WMI_11D_SCAN_START_CMDID to firmware +and wait firmware complete it, the scan from mac80211 also need to wait +the 11d scan finished, and send WMI_11D_SCAN_STOP_CMDID to firmware +before vdev delete for STATION. + +Tested-on: QCA6390 hw2.0 PCI WLAN.HST.1.0.1-01230-QCAHSTSWPLZ_V2_TO_X86-1 + +Signed-off-by: Wen Gong +Signed-off-by: Kalle Valo +Link: https://lore.kernel.org/r/20211201071745.17746-4-quic_wgong@quicinc.com +--- + drivers/net/wireless/ath/ath11k/core.c | 31 +++++ + drivers/net/wireless/ath/ath11k/core.h | 9 ++ + drivers/net/wireless/ath/ath11k/mac.c | 163 ++++++++++++++++++++++++- + drivers/net/wireless/ath/ath11k/mac.h | 7 ++ + drivers/net/wireless/ath/ath11k/reg.c | 15 +++ + drivers/net/wireless/ath/ath11k/wmi.c | 109 +++++++++++++++++ + drivers/net/wireless/ath/ath11k/wmi.h | 27 ++++ + 7 files changed, 360 insertions(+), 1 deletion(-) + +--- a/drivers/net/wireless/ath/ath11k/core.c ++++ b/drivers/net/wireless/ath/ath11k/core.c +@@ -1096,6 +1096,7 @@ void ath11k_core_halt(struct ath11k *ar) + ath11k_mac_peer_cleanup_all(ar); + cancel_delayed_work_sync(&ar->scan.timeout); + cancel_work_sync(&ar->regd_update_work); ++ cancel_work_sync(&ab->update_11d_work); + + rcu_assign_pointer(ab->pdevs_active[ar->pdev_idx], NULL); + synchronize_rcu(); +@@ -1103,6 +1104,34 @@ void ath11k_core_halt(struct ath11k *ar) + idr_init(&ar->txmgmt_idr); + } + ++static void ath11k_update_11d(struct work_struct *work) ++{ ++ struct ath11k_base *ab = container_of(work, struct ath11k_base, update_11d_work); ++ struct ath11k *ar; ++ struct ath11k_pdev *pdev; ++ struct wmi_set_current_country_params set_current_param = {}; ++ int ret, i; ++ ++ spin_lock_bh(&ab->base_lock); ++ memcpy(&set_current_param.alpha2, &ab->new_alpha2, 2); ++ spin_unlock_bh(&ab->base_lock); ++ ++ ath11k_dbg(ab, ATH11K_DBG_WMI, "update 11d new cc %c%c\n", ++ set_current_param.alpha2[0], ++ set_current_param.alpha2[1]); ++ ++ for (i = 0; i < ab->num_radios; i++) { ++ pdev = &ab->pdevs[i]; ++ ar = pdev->ar; ++ ++ ret = ath11k_wmi_send_set_current_country_cmd(ar, &set_current_param); ++ if (ret) ++ ath11k_warn(ar->ab, ++ "pdev id %d failed set current country code: %d\n", ++ i, ret); ++ } ++} ++ + static void ath11k_core_restart(struct work_struct *work) + { + struct ath11k_base *ab = container_of(work, struct ath11k_base, restart_work); +@@ -1272,12 +1301,14 @@ struct ath11k_base *ath11k_core_alloc(st + + mutex_init(&ab->core_lock); + spin_lock_init(&ab->base_lock); ++ mutex_init(&ab->vdev_id_11d_lock); + + INIT_LIST_HEAD(&ab->peers); + init_waitqueue_head(&ab->peer_mapping_wq); + init_waitqueue_head(&ab->wmi_ab.tx_credits_wq); + init_waitqueue_head(&ab->qmi.cold_boot_waitq); + INIT_WORK(&ab->restart_work, ath11k_core_restart); ++ INIT_WORK(&ab->update_11d_work, ath11k_update_11d); + timer_setup(&ab->rx_replenish_retry, ath11k_ce_rx_replenish_retry, 0); + init_completion(&ab->htc_suspend); + init_completion(&ab->wow.wakeup_completed); +--- a/drivers/net/wireless/ath/ath11k/core.h ++++ b/drivers/net/wireless/ath/ath11k/core.h +@@ -588,6 +588,11 @@ struct ath11k { + #endif + bool dfs_block_radar_events; + struct ath11k_thermal thermal; ++ u32 vdev_id_11d_scan; ++ struct completion finish_11d_scan; ++ struct completion finish_11d_ch_list; ++ bool pending_11d; ++ bool regdom_set_by_user; + }; + + struct ath11k_band_cap { +@@ -762,6 +767,8 @@ struct ath11k_base { + struct completion driver_recovery; + struct workqueue_struct *workqueue; + struct work_struct restart_work; ++ struct work_struct update_11d_work; ++ u8 new_alpha2[3]; + struct { + /* protected by data_lock */ + u32 fw_crash_counter; +@@ -771,6 +778,8 @@ struct ath11k_base { + struct ath11k_dbring_cap *db_caps; + u32 num_db_cap; + ++ /* To synchronize 11d scan vdev id */ ++ struct mutex vdev_id_11d_lock; + struct timer_list mon_reap_timer; + + struct completion htc_suspend; +--- a/drivers/net/wireless/ath/ath11k/mac.c ++++ b/drivers/net/wireless/ath/ath11k/mac.c +@@ -2681,6 +2681,8 @@ static void ath11k_bss_assoc(struct ieee + if (ret) + ath11k_warn(ar->ab, "failed to set vdev %i OBSS PD parameters: %d\n", + arvif->vdev_id, ret); ++ ++ ath11k_mac_11d_scan_stop_all(ar->ab); + } + + static void ath11k_bss_disassoc(struct ieee80211_hw *hw, +@@ -3410,6 +3412,7 @@ static int ath11k_start_scan(struct ath1 + struct scan_req_params *arg) + { + int ret; ++ unsigned long timeout = 1 * HZ; + + lockdep_assert_held(&ar->conf_mutex); + +@@ -3420,7 +3423,14 @@ static int ath11k_start_scan(struct ath1 + if (ret) + return ret; + +- ret = wait_for_completion_timeout(&ar->scan.started, 1 * HZ); ++ if (test_bit(WMI_TLV_SERVICE_11D_OFFLOAD, ar->ab->wmi_ab.svc_map)) { ++ timeout = 5 * HZ; ++ ++ if (ar->supports_6ghz) ++ timeout += 5 * HZ; ++ } ++ ++ ret = wait_for_completion_timeout(&ar->scan.started, timeout); + if (ret == 0) { + ret = ath11k_scan_stop(ar); + if (ret) +@@ -3477,6 +3487,26 @@ static int ath11k_mac_op_hw_scan(struct + if (ret) + goto exit; + ++ /* Currently the pending_11d=true only happened 1 time while ++ * wlan interface up in ath11k_mac_11d_scan_start(), it is called by ++ * ath11k_mac_op_add_interface(), after wlan interface up, ++ * pending_11d=false always. ++ * If remove below wait, it always happened scan fail and lead connect ++ * fail while wlan interface up, because it has a 11d scan which is running ++ * in firmware, and lead this scan failed. ++ */ ++ if (ar->pending_11d) { ++ long time_left; ++ unsigned long timeout = 5 * HZ; ++ ++ if (ar->supports_6ghz) ++ timeout += 5 * HZ; ++ ++ time_left = wait_for_completion_timeout(&ar->finish_11d_ch_list, timeout); ++ ath11k_dbg(ar->ab, ATH11K_DBG_MAC, ++ "mac wait 11d channel list time left %ld\n", time_left); ++ } ++ + memset(&arg, 0, sizeof(arg)); + ath11k_wmi_start_scan_init(ar, &arg); + arg.vdev_id = arvif->vdev_id; +@@ -5635,6 +5665,7 @@ static void ath11k_mac_op_stop(struct ie + + cancel_delayed_work_sync(&ar->scan.timeout); + cancel_work_sync(&ar->regd_update_work); ++ cancel_work_sync(&ar->ab->update_11d_work); + + spin_lock_bh(&ar->data_lock); + list_for_each_entry_safe(ppdu_stats, tmp, &ar->ppdu_stats_info, list) { +@@ -5788,6 +5819,122 @@ static void ath11k_mac_op_update_vif_off + } + } + ++static bool ath11k_mac_vif_ap_active_any(struct ath11k_base *ab) ++{ ++ struct ath11k *ar; ++ struct ath11k_pdev *pdev; ++ struct ath11k_vif *arvif; ++ int i; ++ ++ for (i = 0; i < ab->num_radios; i++) { ++ pdev = &ab->pdevs[i]; ++ ar = pdev->ar; ++ list_for_each_entry(arvif, &ar->arvifs, list) { ++ if (arvif->is_up && arvif->vdev_type == WMI_VDEV_TYPE_AP) ++ return true; ++ } ++ } ++ return false; ++} ++ ++void ath11k_mac_11d_scan_start(struct ath11k *ar, u32 vdev_id, bool wait) ++{ ++ struct wmi_11d_scan_start_params param; ++ int ret; ++ ++ mutex_lock(&ar->ab->vdev_id_11d_lock); ++ ++ ath11k_dbg(ar->ab, ATH11K_DBG_MAC, "mac vdev id for 11d scan %d\n", ++ ar->vdev_id_11d_scan); ++ ++ if (ar->regdom_set_by_user) ++ goto fin; ++ ++ if (ar->vdev_id_11d_scan != ATH11K_11D_INVALID_VDEV_ID) ++ goto fin; ++ ++ if (!test_bit(WMI_TLV_SERVICE_11D_OFFLOAD, ar->ab->wmi_ab.svc_map)) ++ goto fin; ++ ++ if (ath11k_mac_vif_ap_active_any(ar->ab)) ++ goto fin; ++ ++ param.vdev_id = vdev_id; ++ param.start_interval_msec = 0; ++ param.scan_period_msec = ATH11K_SCAN_11D_INTERVAL; ++ ++ ath11k_dbg(ar->ab, ATH11K_DBG_MAC, "mac start 11d scan\n"); ++ ++ if (wait) ++ reinit_completion(&ar->finish_11d_scan); ++ ++ ret = ath11k_wmi_send_11d_scan_start_cmd(ar, ¶m); ++ if (ret) { ++ ath11k_warn(ar->ab, "failed to start 11d scan vdev %d ret: %d\n", ++ vdev_id, ret); ++ } else { ++ ar->vdev_id_11d_scan = vdev_id; ++ if (wait) { ++ ar->pending_11d = true; ++ ret = wait_for_completion_timeout(&ar->finish_11d_scan, ++ 5 * HZ); ++ ath11k_dbg(ar->ab, ATH11K_DBG_MAC, ++ "mac 11d scan left time %d\n", ret); ++ ++ if (!ret) ++ ar->pending_11d = false; ++ } ++ } ++ ++fin: ++ mutex_unlock(&ar->ab->vdev_id_11d_lock); ++} ++ ++void ath11k_mac_11d_scan_stop(struct ath11k *ar) ++{ ++ int ret; ++ u32 vdev_id; ++ ++ if (!test_bit(WMI_TLV_SERVICE_11D_OFFLOAD, ar->ab->wmi_ab.svc_map)) ++ return; ++ ++ ath11k_dbg(ar->ab, ATH11K_DBG_MAC, "mac stop 11d scan\n"); ++ ++ mutex_lock(&ar->ab->vdev_id_11d_lock); ++ ++ ath11k_dbg(ar->ab, ATH11K_DBG_MAC, "mac stop 11d vdev id %d\n", ++ ar->vdev_id_11d_scan); ++ ++ if (ar->vdev_id_11d_scan != ATH11K_11D_INVALID_VDEV_ID) { ++ vdev_id = ar->vdev_id_11d_scan; ++ ++ ret = ath11k_wmi_send_11d_scan_stop_cmd(ar, vdev_id); ++ if (ret) ++ ath11k_warn(ar->ab, ++ "failed to stopt 11d scan vdev %d ret: %d\n", ++ vdev_id, ret); ++ else ++ ar->vdev_id_11d_scan = ATH11K_11D_INVALID_VDEV_ID; ++ } ++ mutex_unlock(&ar->ab->vdev_id_11d_lock); ++} ++ ++void ath11k_mac_11d_scan_stop_all(struct ath11k_base *ab) ++{ ++ struct ath11k *ar; ++ struct ath11k_pdev *pdev; ++ int i; ++ ++ ath11k_dbg(ab, ATH11K_DBG_MAC, "mac stop soc 11d scan\n"); ++ ++ for (i = 0; i < ab->num_radios; i++) { ++ pdev = &ab->pdevs[i]; ++ ar = pdev->ar; ++ ++ ath11k_mac_11d_scan_stop(ar); ++ } ++} ++ + static int ath11k_mac_op_add_interface(struct ieee80211_hw *hw, + struct ieee80211_vif *vif) + { +@@ -5921,6 +6068,8 @@ static int ath11k_mac_op_add_interface(s + arvif->vdev_id, ret); + goto err_peer_del; + } ++ ++ ath11k_mac_11d_scan_stop_all(ar->ab); + break; + case WMI_VDEV_TYPE_STA: + param_id = WMI_STA_PS_PARAM_RX_WAKE_POLICY; +@@ -5960,6 +6109,9 @@ static int ath11k_mac_op_add_interface(s + arvif->vdev_id, ret); + goto err_peer_del; + } ++ ++ ath11k_mac_11d_scan_start(ar, arvif->vdev_id, true); ++ + break; + case WMI_VDEV_TYPE_MONITOR: + set_bit(ATH11K_FLAG_MONITOR_VDEV_CREATED, &ar->monitor_flags); +@@ -6061,6 +6213,9 @@ static void ath11k_mac_op_remove_interfa + ath11k_dbg(ab, ATH11K_DBG_MAC, "mac remove interface (vdev %d)\n", + arvif->vdev_id); + ++ if (arvif->vdev_type == WMI_VDEV_TYPE_STA) ++ ath11k_mac_11d_scan_stop(ar); ++ + if (arvif->vdev_type == WMI_VDEV_TYPE_AP) { + ret = ath11k_peer_delete(ar, arvif->vdev_id, vif->addr); + if (ret) +@@ -6779,6 +6934,9 @@ ath11k_mac_op_unassign_vif_chanctx(struc + ret); + } + ++ if (arvif->vdev_type == WMI_VDEV_TYPE_STA) ++ ath11k_mac_11d_scan_start(ar, arvif->vdev_id, false); ++ + mutex_unlock(&ar->conf_mutex); + } + +@@ -8180,6 +8338,9 @@ int ath11k_mac_allocate(struct ath11k_ba + + ar->monitor_vdev_id = -1; + clear_bit(ATH11K_FLAG_MONITOR_VDEV_CREATED, &ar->monitor_flags); ++ ar->vdev_id_11d_scan = ATH11K_11D_INVALID_VDEV_ID; ++ init_completion(&ar->finish_11d_scan); ++ init_completion(&ar->finish_11d_ch_list); + } + + return 0; +--- a/drivers/net/wireless/ath/ath11k/mac.h ++++ b/drivers/net/wireless/ath/ath11k/mac.h +@@ -127,6 +127,13 @@ struct ath11k_generic_iter { + + extern const struct htt_rx_ring_tlv_filter ath11k_mac_mon_status_filter_default; + ++#define ATH11K_SCAN_11D_INTERVAL 600000 ++#define ATH11K_11D_INVALID_VDEV_ID 0xFFFF ++ ++void ath11k_mac_11d_scan_start(struct ath11k *ar, u32 vdev_id, bool wait); ++void ath11k_mac_11d_scan_stop(struct ath11k *ar); ++void ath11k_mac_11d_scan_stop_all(struct ath11k_base *ab); ++ + void ath11k_mac_destroy(struct ath11k_base *ab); + void ath11k_mac_unregister(struct ath11k_base *ab); + int ath11k_mac_register(struct ath11k_base *ab); +--- a/drivers/net/wireless/ath/ath11k/reg.c ++++ b/drivers/net/wireless/ath/ath11k/reg.c +@@ -86,6 +86,9 @@ ath11k_reg_notifier(struct wiphy *wiphy, + if (ret) + ath11k_warn(ar->ab, + "INIT Country code set to fw failed : %d\n", ret); ++ ++ ath11k_mac_11d_scan_stop(ar); ++ ar->regdom_set_by_user = true; + } + + int ath11k_reg_update_chan_list(struct ath11k *ar) +@@ -179,6 +182,11 @@ int ath11k_reg_update_chan_list(struct a + ret = ath11k_wmi_send_scan_chan_list_cmd(ar, params); + kfree(params); + ++ if (ar->pending_11d) { ++ complete(&ar->finish_11d_ch_list); ++ ar->pending_11d = false; ++ } ++ + return ret; + } + +@@ -244,8 +252,15 @@ int ath11k_regd_update(struct ath11k *ar + goto err; + } + ++ if (ar->pending_11d) ++ complete(&ar->finish_11d_scan); ++ + rtnl_lock(); + wiphy_lock(ar->hw->wiphy); ++ ++ if (ar->pending_11d) ++ reinit_completion(&ar->finish_11d_ch_list); ++ + ret = regulatory_set_wiphy_regd_sync(ar->hw->wiphy, regd_copy); + wiphy_unlock(ar->hw->wiphy); + rtnl_unlock(); +--- a/drivers/net/wireless/ath/ath11k/wmi.c ++++ b/drivers/net/wireless/ath/ath11k/wmi.c +@@ -130,6 +130,8 @@ static const struct wmi_tlv_policy wmi_t + .min_len = sizeof(struct wmi_vdev_delete_resp_event) }, + [WMI_TAG_OBSS_COLOR_COLLISION_EVT] = { + .min_len = sizeof(struct wmi_obss_color_collision_event) }, ++ [WMI_TAG_11D_NEW_COUNTRY_EVENT] = { ++ .min_len = sizeof(struct wmi_11d_new_cc_ev) }, + }; + + #define PRIMAP(_hw_mode_) \ +@@ -2898,6 +2900,75 @@ ath11k_wmi_send_thermal_mitigation_param + return ret; + } + ++int ath11k_wmi_send_11d_scan_start_cmd(struct ath11k *ar, ++ struct wmi_11d_scan_start_params *param) ++{ ++ struct ath11k_pdev_wmi *wmi = ar->wmi; ++ struct wmi_11d_scan_start_cmd *cmd; ++ struct sk_buff *skb; ++ int ret; ++ ++ skb = ath11k_wmi_alloc_skb(wmi->wmi_ab, sizeof(*cmd)); ++ if (!skb) ++ return -ENOMEM; ++ ++ cmd = (struct wmi_11d_scan_start_cmd *)skb->data; ++ cmd->tlv_header = ++ FIELD_PREP(WMI_TLV_TAG, WMI_TAG_11D_SCAN_START_CMD) | ++ FIELD_PREP(WMI_TLV_LEN, sizeof(*cmd) - TLV_HDR_SIZE); ++ ++ cmd->vdev_id = param->vdev_id; ++ cmd->scan_period_msec = param->scan_period_msec; ++ cmd->start_interval_msec = param->start_interval_msec; ++ ret = ath11k_wmi_cmd_send(wmi, skb, WMI_11D_SCAN_START_CMDID); ++ ++ ath11k_dbg(ar->ab, ATH11K_DBG_WMI, ++ "send 11d scan start vdev id %d period %d ms internal %d ms\n", ++ cmd->vdev_id, ++ cmd->scan_period_msec, ++ cmd->start_interval_msec); ++ ++ if (ret) { ++ ath11k_warn(ar->ab, ++ "failed to send WMI_11D_SCAN_START_CMDID: %d\n", ret); ++ dev_kfree_skb(skb); ++ } ++ ++ return ret; ++} ++ ++int ath11k_wmi_send_11d_scan_stop_cmd(struct ath11k *ar, u32 vdev_id) ++{ ++ struct ath11k_pdev_wmi *wmi = ar->wmi; ++ struct wmi_11d_scan_stop_cmd *cmd; ++ struct sk_buff *skb; ++ int ret; ++ ++ skb = ath11k_wmi_alloc_skb(wmi->wmi_ab, sizeof(*cmd)); ++ if (!skb) ++ return -ENOMEM; ++ ++ cmd = (struct wmi_11d_scan_stop_cmd *)skb->data; ++ cmd->tlv_header = ++ FIELD_PREP(WMI_TLV_TAG, WMI_TAG_11D_SCAN_STOP_CMD) | ++ FIELD_PREP(WMI_TLV_LEN, sizeof(*cmd) - TLV_HDR_SIZE); ++ ++ cmd->vdev_id = vdev_id; ++ ret = ath11k_wmi_cmd_send(wmi, skb, WMI_11D_SCAN_STOP_CMDID); ++ ++ ath11k_dbg(ar->ab, ATH11K_DBG_WMI, ++ "send 11d scan stop vdev id %d\n", ++ cmd->vdev_id); ++ ++ if (ret) { ++ ath11k_warn(ar->ab, ++ "failed to send WMI_11D_SCAN_STOP_CMDID: %d\n", ret); ++ dev_kfree_skb(skb); ++ } ++ ++ return ret; ++} ++ + int ath11k_wmi_pdev_pktlog_enable(struct ath11k *ar, u32 pktlog_filter) + { + struct ath11k_pdev_wmi *wmi = ar->wmi; +@@ -5938,6 +6009,41 @@ static void ath11k_wmi_op_ep_tx_credits( + wake_up(&ab->wmi_ab.tx_credits_wq); + } + ++static int ath11k_reg_11d_new_cc_event(struct ath11k_base *ab, struct sk_buff *skb) ++{ ++ const struct wmi_11d_new_cc_ev *ev; ++ const void **tb; ++ int ret; ++ ++ tb = ath11k_wmi_tlv_parse_alloc(ab, skb->data, skb->len, GFP_ATOMIC); ++ if (IS_ERR(tb)) { ++ ret = PTR_ERR(tb); ++ ath11k_warn(ab, "failed to parse tlv: %d\n", ret); ++ return ret; ++ } ++ ++ ev = tb[WMI_TAG_11D_NEW_COUNTRY_EVENT]; ++ if (!ev) { ++ kfree(tb); ++ ath11k_warn(ab, "failed to fetch 11d new cc ev"); ++ return -EPROTO; ++ } ++ ++ spin_lock_bh(&ab->base_lock); ++ memcpy(&ab->new_alpha2, &ev->new_alpha2, 2); ++ spin_unlock_bh(&ab->base_lock); ++ ++ ath11k_dbg(ab, ATH11K_DBG_WMI, "wmi 11d new cc %c%c\n", ++ ab->new_alpha2[0], ++ ab->new_alpha2[1]); ++ ++ kfree(tb); ++ ++ queue_work(ab->workqueue, &ab->update_11d_work); ++ ++ return 0; ++} ++ + static void ath11k_wmi_htc_tx_complete(struct ath11k_base *ab, + struct sk_buff *skb) + { +@@ -7333,6 +7439,9 @@ static void ath11k_wmi_tlv_op_rx(struct + case WMI_WOW_WAKEUP_HOST_EVENTID: + ath11k_wmi_event_wow_wakeup_host(ab, skb); + break; ++ case WMI_11D_NEW_COUNTRY_EVENTID: ++ ath11k_reg_11d_new_cc_event(ab, skb); ++ break; + /* TODO: Add remaining events */ + default: + ath11k_dbg(ab, ATH11K_DBG_WMI, "Unknown eventid: 0x%x\n", id); +--- a/drivers/net/wireless/ath/ath11k/wmi.h ++++ b/drivers/net/wireless/ath/ath11k/wmi.h +@@ -3812,6 +3812,28 @@ struct wmi_init_country_cmd { + } cc_info; + } __packed; + ++struct wmi_11d_scan_start_params { ++ u32 vdev_id; ++ u32 scan_period_msec; ++ u32 start_interval_msec; ++}; ++ ++struct wmi_11d_scan_start_cmd { ++ u32 tlv_header; ++ u32 vdev_id; ++ u32 scan_period_msec; ++ u32 start_interval_msec; ++} __packed; ++ ++struct wmi_11d_scan_stop_cmd { ++ u32 tlv_header; ++ u32 vdev_id; ++} __packed; ++ ++struct wmi_11d_new_cc_ev { ++ u32 new_alpha2; ++} __packed; ++ + #define THERMAL_LEVELS 1 + struct tt_level_config { + u32 tmplwm; +@@ -5447,6 +5469,11 @@ int ath11k_wmi_send_set_current_country_ + int + ath11k_wmi_send_init_country_cmd(struct ath11k *ar, + struct wmi_init_country_params init_cc_param); ++ ++int ath11k_wmi_send_11d_scan_start_cmd(struct ath11k *ar, ++ struct wmi_11d_scan_start_params *param); ++int ath11k_wmi_send_11d_scan_stop_cmd(struct ath11k *ar, u32 vdev_id); ++ + int + ath11k_wmi_send_thermal_mitigation_param_cmd(struct ath11k *ar, + struct thermal_mitigation_params *param); diff --git a/package/kernel/mac80211/patches/ath11k/0128-ath11k-add-wait-operation-for-tx-management-packets-.patch b/package/kernel/mac80211/patches/ath11k/0128-ath11k-add-wait-operation-for-tx-management-packets-.patch new file mode 100644 index 000000000..7dad11011 --- /dev/null +++ b/package/kernel/mac80211/patches/ath11k/0128-ath11k-add-wait-operation-for-tx-management-packets-.patch @@ -0,0 +1,230 @@ +From dddaa64d0af37275314a656bd8f8e941799e2d61 Mon Sep 17 00:00:00 2001 +From: Wen Gong +Date: Thu, 2 Dec 2021 01:37:05 -0500 +Subject: [PATCH] ath11k: add wait operation for tx management packets for + flush from mac80211 + +In ath11k, tx of management packet is doing in a work queue. Sometimes +the workqueue does not finish tx immediately, then it lead after the next +step of vdev delete finished, it start to send the management packet to +firmware and lead firmware crash. + +ieee80211_set_disassoc() have logic of ieee80211_flush_queues() after +it send_deauth_disassoc() to ath11k, its purpose is make sure the +deauth was actually sent, so it need to change ath11k to match the +purpose of mac80211. + +To address these issue wait for tx mgmt as well as tx data packets. + +dmesg log of connect/disconnect to AP: +[ 307.522226] wls1: authenticate with 62:66:e4:e9:6a:a9 +[ 307.586565] wls1: send auth to 62:66:e4:e9:6a:a9 (try 1/3) +[ 307.586581] ath11k_pci 0000:05:00.0: mac tx mgmt frame, buf id 0 +[ 307.586922] ath11k_pci 0000:05:00.0: mac tx mgmt frame, vdev_id 0 +[ 307.590179] ath11k_pci 0000:05:00.0: wmi mgmt tx comp pending 0 desc id 0 +[ 307.590181] ath11k_pci 0000:05:00.0: mgmt tx compl ev pdev_id 2, desc_id 0, status 0 +[ 307.598699] wls1: authenticated +[ 307.599483] wls1: associate with 62:66:e4:e9:6a:a9 (try 1/3) +[ 307.599506] ath11k_pci 0000:05:00.0: mac tx mgmt frame, buf id 0 +[ 307.599519] ath11k_pci 0000:05:00.0: mac tx mgmt frame, vdev_id 0 +[ 307.603059] ath11k_pci 0000:05:00.0: wmi mgmt tx comp pending 0 desc id 0 +[ 307.603063] ath11k_pci 0000:05:00.0: mgmt tx compl ev pdev_id 2, desc_id 0, status 0 +[ 307.637105] wls1: associated +[ 317.365239] wls1: deauthenticating from 62:66:e4:e9:6a:a9 by local choice (Reason: 3=DEAUTH_LEAVING) +[ 317.368104] ath11k_pci 0000:05:00.0: mac tx mgmt frame, buf id 0 +[ 317.372622] ath11k_pci 0000:05:00.0: mac tx mgmt frame, vdev_id 0 +[ 317.378320] ath11k_pci 0000:05:00.0: wmi mgmt tx comp pending 0 desc id 0 +[ 317.378330] ath11k_pci 0000:05:00.0: mgmt tx compl ev pdev_id 2, desc_id 0, status 0 +[ 317.378359] ath11k_pci 0000:05:00.0: mac mgmt tx flush mgmt pending 0 +[ 317.421066] ath11k_pci 0000:05:00.0: mac mgmt tx flush mgmt pending 0 +[ 317.421427] ath11k_pci 0000:05:00.0: mac remove interface (vdev 0) + +Tested-on: QCA6390 hw2.0 PCI WLAN.HST.1.0.1-01230-QCAHSTSWPLZ_V2_TO_X86-1 +Tested-on: WCN6855 hw2.0 PCI WLAN.HSP.1.1-01720.1-QCAHSPSWPL_V1_V2_SILICONZ_LITE-1 + +Signed-off-by: Wen Gong +Signed-off-by: Kalle Valo +Link: https://lore.kernel.org/r/20211202063705.14321-1-quic_wgong@quicinc.com +--- + drivers/net/wireless/ath/ath11k/core.c | 1 + + drivers/net/wireless/ath/ath11k/core.h | 1 + + drivers/net/wireless/ath/ath11k/mac.c | 51 +++++++++++++++++++++----- + drivers/net/wireless/ath/ath11k/wmi.c | 12 +++++- + 4 files changed, 55 insertions(+), 10 deletions(-) + +--- a/drivers/net/wireless/ath/ath11k/core.c ++++ b/drivers/net/wireless/ath/ath11k/core.c +@@ -1165,6 +1165,7 @@ static void ath11k_core_restart(struct w + idr_for_each(&ar->txmgmt_idr, + ath11k_mac_tx_mgmt_pending_free, ar); + idr_destroy(&ar->txmgmt_idr); ++ wake_up(&ar->txmgmt_empty_waitq); + } + + wake_up(&ab->wmi_ab.tx_credits_wq); +--- a/drivers/net/wireless/ath/ath11k/core.h ++++ b/drivers/net/wireless/ath/ath11k/core.h +@@ -550,6 +550,7 @@ struct ath11k { + /* protects txmgmt_idr data */ + spinlock_t txmgmt_idr_lock; + atomic_t num_pending_mgmt_tx; ++ wait_queue_head_t txmgmt_empty_waitq; + + /* cycle count is reported twice for each visited channel during scan. + * access protected by data_lock +--- a/drivers/net/wireless/ath/ath11k/mac.c ++++ b/drivers/net/wireless/ath/ath11k/mac.c +@@ -5265,6 +5265,21 @@ static int __ath11k_set_antenna(struct a + return 0; + } + ++static void ath11k_mgmt_over_wmi_tx_drop(struct ath11k *ar, struct sk_buff *skb) ++{ ++ int num_mgmt; ++ ++ ieee80211_free_txskb(ar->hw, skb); ++ ++ num_mgmt = atomic_dec_if_positive(&ar->num_pending_mgmt_tx); ++ ++ if (num_mgmt < 0) ++ WARN_ON_ONCE(1); ++ ++ if (!num_mgmt) ++ wake_up(&ar->txmgmt_empty_waitq); ++} ++ + static void ath11k_mac_tx_mgmt_free(struct ath11k *ar, int buf_id) + { + struct sk_buff *msdu; +@@ -5283,7 +5298,7 @@ static void ath11k_mac_tx_mgmt_free(stru + info = IEEE80211_SKB_CB(msdu); + memset(&info->status, 0, sizeof(info->status)); + +- ieee80211_free_txskb(ar->hw, msdu); ++ ath11k_mgmt_over_wmi_tx_drop(ar, msdu); + } + + int ath11k_mac_tx_mgmt_pending_free(int buf_id, void *skb, void *ctx) +@@ -5323,6 +5338,10 @@ static int ath11k_mac_mgmt_tx_wmi(struct + buf_id = idr_alloc(&ar->txmgmt_idr, skb, 0, + ATH11K_TX_MGMT_NUM_PENDING_MAX, GFP_ATOMIC); + spin_unlock_bh(&ar->txmgmt_idr_lock); ++ ++ ath11k_dbg(ar->ab, ATH11K_DBG_MAC, ++ "mac tx mgmt frame, buf id %d\n", buf_id); ++ + if (buf_id < 0) + return -ENOSPC; + +@@ -5369,7 +5388,7 @@ static void ath11k_mgmt_over_wmi_tx_purg + struct sk_buff *skb; + + while ((skb = skb_dequeue(&ar->wmi_mgmt_tx_queue)) != NULL) +- ieee80211_free_txskb(ar->hw, skb); ++ ath11k_mgmt_over_wmi_tx_drop(ar, skb); + } + + static void ath11k_mgmt_over_wmi_tx_work(struct work_struct *work) +@@ -5384,29 +5403,29 @@ static void ath11k_mgmt_over_wmi_tx_work + skb_cb = ATH11K_SKB_CB(skb); + if (!skb_cb->vif) { + ath11k_warn(ar->ab, "no vif found for mgmt frame\n"); +- ieee80211_free_txskb(ar->hw, skb); ++ ath11k_mgmt_over_wmi_tx_drop(ar, skb); + continue; + } + + arvif = ath11k_vif_to_arvif(skb_cb->vif); + if (ar->allocated_vdev_map & (1LL << arvif->vdev_id) && + arvif->is_started) { +- atomic_inc(&ar->num_pending_mgmt_tx); + ret = ath11k_mac_mgmt_tx_wmi(ar, arvif, skb); + if (ret) { +- if (atomic_dec_if_positive(&ar->num_pending_mgmt_tx) < 0) +- WARN_ON_ONCE(1); +- + ath11k_warn(ar->ab, "failed to tx mgmt frame, vdev_id %d :%d\n", + arvif->vdev_id, ret); +- ieee80211_free_txskb(ar->hw, skb); ++ ath11k_mgmt_over_wmi_tx_drop(ar, skb); ++ } else { ++ ath11k_dbg(ar->ab, ATH11K_DBG_MAC, ++ "mac tx mgmt frame, vdev_id %d\n", ++ arvif->vdev_id); + } + } else { + ath11k_warn(ar->ab, + "dropping mgmt frame for vdev %d, is_started %d\n", + arvif->vdev_id, + arvif->is_started); +- ieee80211_free_txskb(ar->hw, skb); ++ ath11k_mgmt_over_wmi_tx_drop(ar, skb); + } + } + } +@@ -5437,6 +5456,7 @@ static int ath11k_mac_mgmt_tx(struct ath + } + + skb_queue_tail(q, skb); ++ atomic_inc(&ar->num_pending_mgmt_tx); + ieee80211_queue_work(ar->hw, &ar->wmi_mgmt_tx_work); + + return 0; +@@ -7023,6 +7043,17 @@ static void ath11k_mac_op_flush(struct i + ATH11K_FLUSH_TIMEOUT); + if (time_left == 0) + ath11k_warn(ar->ab, "failed to flush transmit queue %ld\n", time_left); ++ ++ time_left = wait_event_timeout(ar->txmgmt_empty_waitq, ++ (atomic_read(&ar->num_pending_mgmt_tx) == 0), ++ ATH11K_FLUSH_TIMEOUT); ++ if (time_left == 0) ++ ath11k_warn(ar->ab, "failed to flush mgmt transmit queue %ld\n", ++ time_left); ++ ++ ath11k_dbg(ar->ab, ATH11K_DBG_MAC, ++ "mac mgmt tx flush mgmt pending %d\n", ++ atomic_read(&ar->num_pending_mgmt_tx)); + } + + static int +@@ -8261,6 +8292,8 @@ int ath11k_mac_register(struct ath11k_ba + ret = __ath11k_mac_register(ar); + if (ret) + goto err_cleanup; ++ ++ init_waitqueue_head(&ar->txmgmt_empty_waitq); + } + + return 0; +--- a/drivers/net/wireless/ath/ath11k/wmi.c ++++ b/drivers/net/wireless/ath/ath11k/wmi.c +@@ -4980,6 +4980,7 @@ static int wmi_process_mgmt_tx_comp(stru + struct sk_buff *msdu; + struct ieee80211_tx_info *info; + struct ath11k_skb_cb *skb_cb; ++ int num_mgmt; + + spin_lock_bh(&ar->txmgmt_idr_lock); + msdu = idr_find(&ar->txmgmt_idr, desc_id); +@@ -5003,10 +5004,19 @@ static int wmi_process_mgmt_tx_comp(stru + + ieee80211_tx_status_irqsafe(ar->hw, msdu); + ++ num_mgmt = atomic_dec_if_positive(&ar->num_pending_mgmt_tx); ++ + /* WARN when we received this event without doing any mgmt tx */ +- if (atomic_dec_if_positive(&ar->num_pending_mgmt_tx) < 0) ++ if (num_mgmt < 0) + WARN_ON_ONCE(1); + ++ ath11k_dbg(ar->ab, ATH11K_DBG_WMI, ++ "wmi mgmt tx comp pending %d desc id %d\n", ++ num_mgmt, desc_id); ++ ++ if (!num_mgmt) ++ wake_up(&ar->txmgmt_empty_waitq); ++ + return 0; + } + diff --git a/package/kernel/mac80211/patches/ath11k/0129-ath11k-Fix-buffer-overflow-when-scanning-with-extrai.patch b/package/kernel/mac80211/patches/ath11k/0129-ath11k-Fix-buffer-overflow-when-scanning-with-extrai.patch new file mode 100644 index 000000000..dbe0f655d --- /dev/null +++ b/package/kernel/mac80211/patches/ath11k/0129-ath11k-Fix-buffer-overflow-when-scanning-with-extrai.patch @@ -0,0 +1,71 @@ +From a658c929ded7ea3aee324c8c2a9635a5e5a38e7f Mon Sep 17 00:00:00 2001 +From: Sven Eckelmann +Date: Wed, 8 Dec 2021 10:43:59 +0200 +Subject: [PATCH] ath11k: Fix buffer overflow when scanning with extraie + +If cfg80211 is providing extraie's for a scanning process then ath11k will +copy that over to the firmware. The extraie.len is a 32 bit value in struct +element_info and describes the amount of bytes for the vendor information +elements. + +The WMI_TLV packet is having a special WMI_TAG_ARRAY_BYTE section. This +section can have a (payload) length up to 65535 bytes because the +WMI_TLV_LEN can store up to 16 bits. The code was missing such a check and +could have created a scan request which cannot be parsed correctly by the +firmware. + +But the bigger problem was the allocation of the buffer. It has to align +the TLV sections by 4 bytes. But the code was using an u8 to store the +newly calculated length of this section (with alignment). And the new +calculated length was then used to allocate the skbuff. But the actual code +to copy in the data is using the extraie.len and not the calculated +"aligned" length. + +The length of extraie with IEEE80211_HW_SINGLE_SCAN_ON_ALL_BANDS enabled +was 264 bytes during tests with a QCA Milan card. But it only allocated 8 +bytes (264 bytes % 256) for it. As consequence, the code to memcpy the +extraie into the skb was then just overwriting data after skb->end. Things +like shinfo were therefore corrupted. This could usually be seen by a crash +in skb_zcopy_clear which tried to call a ubuf_info callback (using a bogus +address). + +Tested-on: WCN6855 hw2.0 PCI WLAN.HSP.1.1-02892.1-QCAHSPSWPL_V1_V2_SILICONZ_LITE-1 + +Cc: stable@vger.kernel.org +Fixes: d5c65159f289 ("ath11k: driver for Qualcomm IEEE 802.11ax devices") +Signed-off-by: Sven Eckelmann +Signed-off-by: Kalle Valo +Link: https://lore.kernel.org/r/20211207142913.1734635-1-sven@narfation.org +--- + drivers/net/wireless/ath/ath11k/wmi.c | 6 +++--- + 1 file changed, 3 insertions(+), 3 deletions(-) + +--- a/drivers/net/wireless/ath/ath11k/wmi.c ++++ b/drivers/net/wireless/ath/ath11k/wmi.c +@@ -2113,7 +2113,7 @@ int ath11k_wmi_send_scan_start_cmd(struc + void *ptr; + int i, ret, len; + u32 *tmp_ptr; +- u8 extraie_len_with_pad = 0; ++ u16 extraie_len_with_pad = 0; + struct hint_short_ssid *s_ssid = NULL; + struct hint_bssid *hint_bssid = NULL; + +@@ -2132,7 +2132,7 @@ int ath11k_wmi_send_scan_start_cmd(struc + len += sizeof(*bssid) * params->num_bssid; + + len += TLV_HDR_SIZE; +- if (params->extraie.len) ++ if (params->extraie.len && params->extraie.len <= 0xFFFF) + extraie_len_with_pad = + roundup(params->extraie.len, sizeof(u32)); + len += extraie_len_with_pad; +@@ -2239,7 +2239,7 @@ int ath11k_wmi_send_scan_start_cmd(struc + FIELD_PREP(WMI_TLV_LEN, len); + ptr += TLV_HDR_SIZE; + +- if (params->extraie.len) ++ if (extraie_len_with_pad) + memcpy(ptr, params->extraie.ptr, + params->extraie.len); + diff --git a/package/kernel/mac80211/patches/ath11k/0130-ath11k-enable-IEEE80211_HW_SINGLE_SCAN_ON_ALL_BANDS-.patch b/package/kernel/mac80211/patches/ath11k/0130-ath11k-enable-IEEE80211_HW_SINGLE_SCAN_ON_ALL_BANDS-.patch new file mode 100644 index 000000000..d0dfb12a5 --- /dev/null +++ b/package/kernel/mac80211/patches/ath11k/0130-ath11k-enable-IEEE80211_HW_SINGLE_SCAN_ON_ALL_BANDS-.patch @@ -0,0 +1,42 @@ +From 9f6da09a5f6ab94bca58395af56b883b3a79663a Mon Sep 17 00:00:00 2001 +From: Wen Gong +Date: Wed, 8 Dec 2021 10:43:59 +0200 +Subject: [PATCH] ath11k: enable IEEE80211_HW_SINGLE_SCAN_ON_ALL_BANDS for + WCN6855 + +Currently mac80211 will send 3 scan request for each scan of WCN6855, +they are 2.4 GHz/5 GHz/6 GHz band scan. Firmware of WCN6855 will +cache the RNR IE(Reduced Neighbor Report element) which exist in the +beacon of 2.4 GHz/5 GHz of the AP which is co-located with 6 GHz, +and then use the cache to scan in 6 GHz band scan if the 6 GHz scan +is in the same scan with the 2.4 GHz/5 GHz band, this will helpful to +search more AP of 6 GHz. Also it will decrease the time cost of scan +because firmware will use dual-band scan for the 2.4 GHz/5 GHz, it +means the 2.4 GHz and 5 GHz scans are doing simultaneously. + +Set the flag IEEE80211_HW_SINGLE_SCAN_ON_ALL_BANDS for WCN6855 since +it supports 2.4 GHz/5 GHz/6 GHz and it is single pdev which means +all the 2.4 GHz/5 GHz/6 GHz exist in the same wiphy/ieee80211_hw. + +Tested-on: WCN6855 hw2.0 PCI WLAN.HSP.1.1-01720.1-QCAHSPSWPL_V1_V2_SILICONZ_LITE-1 + +Tested-by: Sven Eckelmann +Signed-off-by: Wen Gong +Signed-off-by: Kalle Valo +Link: https://lore.kernel.org/r/20211129101309.2931-1-quic_wgong@quicinc.com +--- + drivers/net/wireless/ath/ath11k/mac.c | 3 +++ + 1 file changed, 3 insertions(+) + +--- a/drivers/net/wireless/ath/ath11k/mac.c ++++ b/drivers/net/wireless/ath/ath11k/mac.c +@@ -8119,6 +8119,9 @@ static int __ath11k_mac_register(struct + + ar->hw->wiphy->interface_modes = ab->hw_params.interface_modes; + ++ if (ab->hw_params.single_pdev_only && ar->supports_6ghz) ++ ieee80211_hw_set(ar->hw, SINGLE_SCAN_ON_ALL_BANDS); ++ + ieee80211_hw_set(ar->hw, SIGNAL_DBM); + ieee80211_hw_set(ar->hw, SUPPORTS_PS); + ieee80211_hw_set(ar->hw, SUPPORTS_DYNAMIC_PS); diff --git a/package/kernel/mac80211/patches/ath11k/0131-ath11k-Add-htt-cmd-to-enable-full-monitor-mode.patch b/package/kernel/mac80211/patches/ath11k/0131-ath11k-Add-htt-cmd-to-enable-full-monitor-mode.patch new file mode 100644 index 000000000..ccf8b9c1f --- /dev/null +++ b/package/kernel/mac80211/patches/ath11k/0131-ath11k-Add-htt-cmd-to-enable-full-monitor-mode.patch @@ -0,0 +1,189 @@ +From 5c1f74d24d92ce62264508df4c8acabb3127cd83 Mon Sep 17 00:00:00 2001 +From: Anilkumar Kolli +Date: Wed, 8 Dec 2021 10:44:00 +0200 +Subject: [PATCH] ath11k: Add htt cmd to enable full monitor mode + +A new hw_param full_monitor_mode is added to enable full +monitor support for QCN9074. +HTT_H2T_MSG_TYPE_RX_FULL_MONITOR_MODE cmd is sent to FW +to enable the full monitor mode. + +Tested-on: QCN9074 hw1.0 PCI WLAN.HK.2.4.0.1-01734-QCAHKSWPL_SILICONZ-1 + +Signed-off-by: Anilkumar Kolli +Signed-off-by: Kalle Valo +Link: https://lore.kernel.org/r/1638881695-22155-2-git-send-email-akolli@codeaurora.org +--- + drivers/net/wireless/ath/ath11k/core.c | 5 +++ + drivers/net/wireless/ath/ath11k/dp.h | 28 +++++++++++++++ + drivers/net/wireless/ath/ath11k/dp_tx.c | 48 +++++++++++++++++++++++++ + drivers/net/wireless/ath/ath11k/dp_tx.h | 2 ++ + drivers/net/wireless/ath/ath11k/hw.h | 1 + + 5 files changed, 84 insertions(+) + +--- a/drivers/net/wireless/ath/ath11k/core.c ++++ b/drivers/net/wireless/ath/ath11k/core.c +@@ -74,6 +74,7 @@ static const struct ath11k_hw_params ath + BIT(NL80211_IFTYPE_AP) | + BIT(NL80211_IFTYPE_MESH_POINT), + .supports_monitor = true, ++ .full_monitor_mode = false, + .supports_shadow_regs = false, + .idle_ps = false, + .supports_sta_ps = false, +@@ -128,6 +129,7 @@ static const struct ath11k_hw_params ath + BIT(NL80211_IFTYPE_AP) | + BIT(NL80211_IFTYPE_MESH_POINT), + .supports_monitor = true, ++ .full_monitor_mode = false, + .supports_shadow_regs = false, + .idle_ps = false, + .supports_sta_ps = false, +@@ -181,6 +183,7 @@ static const struct ath11k_hw_params ath + .interface_modes = BIT(NL80211_IFTYPE_STATION) | + BIT(NL80211_IFTYPE_AP), + .supports_monitor = false, ++ .full_monitor_mode = false, + .supports_shadow_regs = true, + .idle_ps = true, + .supports_sta_ps = true, +@@ -234,6 +237,7 @@ static const struct ath11k_hw_params ath + BIT(NL80211_IFTYPE_AP) | + BIT(NL80211_IFTYPE_MESH_POINT), + .supports_monitor = true, ++ .full_monitor_mode = true, + .supports_shadow_regs = false, + .idle_ps = false, + .supports_sta_ps = false, +@@ -287,6 +291,7 @@ static const struct ath11k_hw_params ath + .interface_modes = BIT(NL80211_IFTYPE_STATION) | + BIT(NL80211_IFTYPE_AP), + .supports_monitor = false, ++ .full_monitor_mode = false, + .supports_shadow_regs = true, + .idle_ps = true, + .supports_sta_ps = true, +--- a/drivers/net/wireless/ath/ath11k/dp.h ++++ b/drivers/net/wireless/ath/ath11k/dp.h +@@ -292,6 +292,7 @@ enum htt_h2t_msg_type { + HTT_H2T_MSG_TYPE_RX_RING_SELECTION_CFG = 0xc, + HTT_H2T_MSG_TYPE_EXT_STATS_CFG = 0x10, + HTT_H2T_MSG_TYPE_PPDU_STATS_CFG = 0x11, ++ HTT_H2T_MSG_TYPE_RX_FULL_MONITOR_MODE = 0x17, + }; + + #define HTT_VER_REQ_INFO_MSG_ID GENMASK(7, 0) +@@ -957,6 +958,33 @@ struct htt_rx_ring_tlv_filter { + u32 pkt_filter_flags3; /* DATA */ + }; + ++#define HTT_RX_FULL_MON_MODE_CFG_CMD_INFO0_MSG_TYPE GENMASK(7, 0) ++#define HTT_RX_FULL_MON_MODE_CFG_CMD_INFO0_PDEV_ID GENMASK(15, 8) ++ ++#define HTT_RX_FULL_MON_MODE_CFG_CMD_CFG_ENABLE BIT(0) ++#define HTT_RX_FULL_MON_MODE_CFG_CMD_CFG_ZERO_MPDUS_END BIT(1) ++#define HTT_RX_FULL_MON_MODE_CFG_CMD_CFG_NON_ZERO_MPDUS_END BIT(2) ++#define HTT_RX_FULL_MON_MODE_CFG_CMD_CFG_RELEASE_RING GENMASK(10, 3) ++ ++/** ++ * Enumeration for full monitor mode destination ring select ++ * 0 - REO destination ring select ++ * 1 - FW destination ring select ++ * 2 - SW destination ring select ++ * 3 - Release destination ring select ++ */ ++enum htt_rx_full_mon_release_ring { ++ HTT_RX_MON_RING_REO, ++ HTT_RX_MON_RING_FW, ++ HTT_RX_MON_RING_SW, ++ HTT_RX_MON_RING_RELEASE, ++}; ++ ++struct htt_rx_full_monitor_mode_cfg_cmd { ++ u32 info0; ++ u32 cfg; ++} __packed; ++ + /* HTT message target->host */ + + enum htt_t2h_msg_type { +--- a/drivers/net/wireless/ath/ath11k/dp_tx.c ++++ b/drivers/net/wireless/ath/ath11k/dp_tx.c +@@ -1033,6 +1033,15 @@ int ath11k_dp_tx_htt_monitor_mode_ring_c + struct htt_rx_ring_tlv_filter tlv_filter = {0}; + int ret = 0, ring_id = 0, i; + ++ if (ab->hw_params.full_monitor_mode) { ++ ret = ath11k_dp_tx_htt_rx_full_mon_setup(ab, ++ dp->mac_id, !reset); ++ if (ret < 0) { ++ ath11k_err(ab, "failed to setup full monitor %d\n", ret); ++ return ret; ++ } ++ } ++ + ring_id = dp->rxdma_mon_buf_ring.refill_buf_ring.ring_id; + + if (!reset) { +@@ -1098,3 +1107,42 @@ int ath11k_dp_tx_htt_monitor_mode_ring_c + + return ret; + } ++ ++int ath11k_dp_tx_htt_rx_full_mon_setup(struct ath11k_base *ab, int mac_id, ++ bool config) ++{ ++ struct htt_rx_full_monitor_mode_cfg_cmd *cmd; ++ struct sk_buff *skb; ++ int ret, len = sizeof(*cmd); ++ ++ skb = ath11k_htc_alloc_skb(ab, len); ++ if (!skb) ++ return -ENOMEM; ++ ++ skb_put(skb, len); ++ cmd = (struct htt_rx_full_monitor_mode_cfg_cmd *)skb->data; ++ memset(cmd, 0, sizeof(*cmd)); ++ cmd->info0 = FIELD_PREP(HTT_RX_FULL_MON_MODE_CFG_CMD_INFO0_MSG_TYPE, ++ HTT_H2T_MSG_TYPE_RX_FULL_MONITOR_MODE); ++ ++ cmd->info0 |= FIELD_PREP(HTT_RX_FULL_MON_MODE_CFG_CMD_INFO0_PDEV_ID, mac_id); ++ ++ cmd->cfg = HTT_RX_FULL_MON_MODE_CFG_CMD_CFG_ENABLE | ++ FIELD_PREP(HTT_RX_FULL_MON_MODE_CFG_CMD_CFG_RELEASE_RING, ++ HTT_RX_MON_RING_SW); ++ if (config) { ++ cmd->cfg |= HTT_RX_FULL_MON_MODE_CFG_CMD_CFG_ZERO_MPDUS_END | ++ HTT_RX_FULL_MON_MODE_CFG_CMD_CFG_NON_ZERO_MPDUS_END; ++ } ++ ++ ret = ath11k_htc_send(&ab->htc, ab->dp.eid, skb); ++ if (ret) ++ goto err_free; ++ ++ return 0; ++ ++err_free: ++ dev_kfree_skb_any(skb); ++ ++ return ret; ++} +--- a/drivers/net/wireless/ath/ath11k/dp_tx.h ++++ b/drivers/net/wireless/ath/ath11k/dp_tx.h +@@ -37,4 +37,6 @@ int ath11k_dp_tx_htt_rx_filter_setup(str + int rx_buf_size, + struct htt_rx_ring_tlv_filter *tlv_filter); + ++int ath11k_dp_tx_htt_rx_full_mon_setup(struct ath11k_base *ab, int mac_id, ++ bool config); + #endif +--- a/drivers/net/wireless/ath/ath11k/hw.h ++++ b/drivers/net/wireless/ath/ath11k/hw.h +@@ -168,6 +168,7 @@ struct ath11k_hw_params { + + u16 interface_modes; + bool supports_monitor; ++ bool full_monitor_mode; + bool supports_shadow_regs; + bool idle_ps; + bool supports_sta_ps; diff --git a/package/kernel/mac80211/patches/ath11k/0132-ath11k-add-software-monitor-ring-descriptor-for-full.patch b/package/kernel/mac80211/patches/ath11k/0132-ath11k-add-software-monitor-ring-descriptor-for-full.patch new file mode 100644 index 000000000..6db287bf2 --- /dev/null +++ b/package/kernel/mac80211/patches/ath11k/0132-ath11k-add-software-monitor-ring-descriptor-for-full.patch @@ -0,0 +1,131 @@ +From 88ee00d130f744854cdd91ad76a888d9e66996d1 Mon Sep 17 00:00:00 2001 +From: Anilkumar Kolli +Date: Wed, 8 Dec 2021 10:44:00 +0200 +Subject: [PATCH] ath11k: add software monitor ring descriptor for full monitor + +In full monitor mode, monitor destination ring is read in +software monitor ring descriptor format instead of +reo_entrance_ring format. Add new sw_mon_ring descriptor. + +Tested-on: QCN9074 hw1.0 PCI WLAN.HK.2.4.0.1-01734-QCAHKSWPL_SILICONZ-1 + +Signed-off-by: Anilkumar Kolli +Signed-off-by: Kalle Valo +Link: https://lore.kernel.org/r/1638881695-22155-3-git-send-email-akolli@codeaurora.org +--- + drivers/net/wireless/ath/ath11k/hal_desc.h | 19 ++++++++++ + drivers/net/wireless/ath/ath11k/hal_rx.c | 44 ++++++++++++++++++++++ + drivers/net/wireless/ath/ath11k/hal_rx.h | 17 +++++++++ + 3 files changed, 80 insertions(+) + +--- a/drivers/net/wireless/ath/ath11k/hal_desc.h ++++ b/drivers/net/wireless/ath/ath11k/hal_desc.h +@@ -858,6 +858,25 @@ struct hal_reo_entrance_ring { + * this ring has looped around the ring. + */ + ++#define HAL_SW_MON_RING_INFO0_RXDMA_PUSH_REASON GENMASK(1, 0) ++#define HAL_SW_MON_RING_INFO0_RXDMA_ERROR_CODE GENMASK(6, 2) ++#define HAL_SW_MON_RING_INFO0_MPDU_FRAG_NUMBER GENMASK(10, 7) ++#define HAL_SW_MON_RING_INFO0_FRAMELESS_BAR BIT(11) ++#define HAL_SW_MON_RING_INFO0_STATUS_BUF_CNT GENMASK(15, 12) ++#define HAL_SW_MON_RING_INFO0_END_OF_PPDU BIT(16) ++ ++#define HAL_SW_MON_RING_INFO1_PHY_PPDU_ID GENMASK(15, 0) ++#define HAL_SW_MON_RING_INFO1_RING_ID GENMASK(27, 20) ++#define HAL_SW_MON_RING_INFO1_LOOPING_COUNT GENMASK(31, 28) ++ ++struct hal_sw_monitor_ring { ++ struct ath11k_buffer_addr buf_addr_info; ++ struct rx_mpdu_desc rx_mpdu_info; ++ struct ath11k_buffer_addr status_buf_addr_info; ++ u32 info0; ++ u32 info1; ++} __packed; ++ + #define HAL_REO_CMD_HDR_INFO0_CMD_NUMBER GENMASK(15, 0) + #define HAL_REO_CMD_HDR_INFO0_STATUS_REQUIRED BIT(16) + +--- a/drivers/net/wireless/ath/ath11k/hal_rx.c ++++ b/drivers/net/wireless/ath/ath11k/hal_rx.c +@@ -1186,3 +1186,47 @@ void ath11k_hal_rx_reo_ent_buf_paddr_get + + *pp_buf_addr = (void *)buf_addr_info; + } ++ ++void ++ath11k_hal_rx_sw_mon_ring_buf_paddr_get(void *rx_desc, ++ struct hal_sw_mon_ring_entries *sw_mon_entries) ++{ ++ struct hal_sw_monitor_ring *sw_mon_ring = rx_desc; ++ struct ath11k_buffer_addr *buf_addr_info; ++ struct ath11k_buffer_addr *status_buf_addr_info; ++ struct rx_mpdu_desc *rx_mpdu_desc_info_details; ++ ++ rx_mpdu_desc_info_details = &sw_mon_ring->rx_mpdu_info; ++ ++ sw_mon_entries->msdu_cnt = FIELD_GET(RX_MPDU_DESC_INFO0_MSDU_COUNT, ++ rx_mpdu_desc_info_details->info0); ++ ++ buf_addr_info = &sw_mon_ring->buf_addr_info; ++ status_buf_addr_info = &sw_mon_ring->status_buf_addr_info; ++ ++ sw_mon_entries->mon_dst_paddr = (((u64)FIELD_GET(BUFFER_ADDR_INFO1_ADDR, ++ buf_addr_info->info1)) << 32) | ++ FIELD_GET(BUFFER_ADDR_INFO0_ADDR, ++ buf_addr_info->info0); ++ ++ sw_mon_entries->mon_status_paddr = ++ (((u64)FIELD_GET(BUFFER_ADDR_INFO1_ADDR, ++ status_buf_addr_info->info1)) << 32) | ++ FIELD_GET(BUFFER_ADDR_INFO0_ADDR, ++ status_buf_addr_info->info0); ++ ++ sw_mon_entries->mon_dst_sw_cookie = FIELD_GET(BUFFER_ADDR_INFO1_SW_COOKIE, ++ buf_addr_info->info1); ++ ++ sw_mon_entries->mon_status_sw_cookie = FIELD_GET(BUFFER_ADDR_INFO1_SW_COOKIE, ++ status_buf_addr_info->info1); ++ ++ sw_mon_entries->status_buf_count = FIELD_GET(HAL_SW_MON_RING_INFO0_STATUS_BUF_CNT, ++ sw_mon_ring->info0); ++ ++ sw_mon_entries->dst_buf_addr_info = buf_addr_info; ++ sw_mon_entries->status_buf_addr_info = status_buf_addr_info; ++ ++ sw_mon_entries->ppdu_id = ++ FIELD_GET(HAL_SW_MON_RING_INFO1_PHY_PPDU_ID, sw_mon_ring->info1); ++} +--- a/drivers/net/wireless/ath/ath11k/hal_rx.h ++++ b/drivers/net/wireless/ath/ath11k/hal_rx.h +@@ -77,6 +77,20 @@ enum hal_rx_mon_status { + HAL_RX_MON_STATUS_BUF_DONE, + }; + ++struct hal_sw_mon_ring_entries { ++ dma_addr_t mon_dst_paddr; ++ dma_addr_t mon_status_paddr; ++ u32 mon_dst_sw_cookie; ++ u32 mon_status_sw_cookie; ++ void *dst_buf_addr_info; ++ void *status_buf_addr_info; ++ u16 ppdu_id; ++ u8 status_buf_count; ++ u8 msdu_cnt; ++ bool end_of_ppdu; ++ bool drop_ppdu; ++}; ++ + struct hal_rx_mon_ppdu_info { + u32 ppdu_id; + u32 ppdu_ts; +@@ -331,6 +345,9 @@ void ath11k_hal_rx_reo_ent_buf_paddr_get + dma_addr_t *paddr, u32 *sw_cookie, + void **pp_buf_addr_info, u8 *rbm, + u32 *msdu_cnt); ++void ++ath11k_hal_rx_sw_mon_ring_buf_paddr_get(void *rx_desc, ++ struct hal_sw_mon_ring_entries *sw_mon_ent); + enum hal_rx_mon_status + ath11k_hal_rx_parse_mon_status(struct ath11k_base *ab, + struct hal_rx_mon_ppdu_info *ppdu_info, diff --git a/package/kernel/mac80211/patches/ath11k/0133-ath11k-Process-full-monitor-mode-rx-support.patch b/package/kernel/mac80211/patches/ath11k/0133-ath11k-Process-full-monitor-mode-rx-support.patch new file mode 100644 index 000000000..884a79564 --- /dev/null +++ b/package/kernel/mac80211/patches/ath11k/0133-ath11k-Process-full-monitor-mode-rx-support.patch @@ -0,0 +1,568 @@ +From 7e2ea2e947046834a450295dfd328adb70a9f864 Mon Sep 17 00:00:00 2001 +From: Anilkumar Kolli +Date: Wed, 8 Dec 2021 10:44:00 +0200 +Subject: [PATCH] ath11k: Process full monitor mode rx support + +In full monitor mode, monitor destination ring is read before monitor +status ring. mon_dst_ring has ppdu id, reap till the end of PPDU. Add +all the MPDUs to list. Start processing the status ring, if PPDU id in +status ring is lagging behind, reap the status ring, once the PPDU ID +matches, deliver the MSDU to upper layer. If status PPDU id leading, +reap the mon_dst_ring. + +The advantage with full monitor mode is hardware has status buffers +available for all the MPDUs in mon_dst_ring, which makes it possible +to deliver more frames to be seen on sniffer. + +Tested-on: QCN9074 hw1.0 PCI WLAN.HK.2.4.0.1-01734-QCAHKSWPL_SILICONZ-1 + +Signed-off-by: Anilkumar Kolli +Signed-off-by: Kalle Valo +Link: https://lore.kernel.org/r/1638881695-22155-4-git-send-email-akolli@codeaurora.org +--- + drivers/net/wireless/ath/ath11k/dp.c | 1 + + drivers/net/wireless/ath/ath11k/dp.h | 26 +- + drivers/net/wireless/ath/ath11k/dp_rx.c | 409 +++++++++++++++++++++++- + 3 files changed, 433 insertions(+), 3 deletions(-) + +--- a/drivers/net/wireless/ath/ath11k/dp.c ++++ b/drivers/net/wireless/ath/ath11k/dp.c +@@ -1051,6 +1051,7 @@ int ath11k_dp_alloc(struct ath11k_base * + + INIT_LIST_HEAD(&dp->reo_cmd_list); + INIT_LIST_HEAD(&dp->reo_cmd_cache_flush_list); ++ INIT_LIST_HEAD(&dp->dp_full_mon_mpdu_list); + spin_lock_init(&dp->reo_cmd_lock); + + dp->reo_cmd_cache_flush_count = 0; +--- a/drivers/net/wireless/ath/ath11k/dp.h ++++ b/drivers/net/wireless/ath/ath11k/dp.h +@@ -89,6 +89,19 @@ struct dp_tx_ring { + int tx_status_tail; + }; + ++enum dp_mon_status_buf_state { ++ /* PPDU id matches in dst ring and status ring */ ++ DP_MON_STATUS_MATCH, ++ /* status ring dma is not done */ ++ DP_MON_STATUS_NO_DMA, ++ /* status ring is lagging, reap status ring */ ++ DP_MON_STATUS_LAG, ++ /* status ring is leading, reap dst ring and drop */ ++ DP_MON_STATUS_LEAD, ++ /* replinish monitor status ring */ ++ DP_MON_STATUS_REPLINISH, ++}; ++ + struct ath11k_pdev_mon_stats { + u32 status_ppdu_state; + u32 status_ppdu_start; +@@ -104,6 +117,12 @@ struct ath11k_pdev_mon_stats { + u32 dup_mon_buf_cnt; + }; + ++struct dp_full_mon_mpdu { ++ struct list_head list; ++ struct sk_buff *head; ++ struct sk_buff *tail; ++}; ++ + struct dp_link_desc_bank { + void *vaddr_unaligned; + void *vaddr; +@@ -135,7 +154,11 @@ struct ath11k_mon_data { + u32 mon_last_buf_cookie; + u64 mon_last_linkdesc_paddr; + u16 chan_noise_floor; +- ++ bool hold_mon_dst_ring; ++ enum dp_mon_status_buf_state buf_state; ++ dma_addr_t mon_status_paddr; ++ struct dp_full_mon_mpdu *mon_mpdu; ++ struct hal_sw_mon_ring_entries sw_mon_entries; + struct ath11k_pdev_mon_stats rx_mon_stats; + /* lock for monitor data */ + spinlock_t mon_lock; +@@ -245,6 +268,7 @@ struct ath11k_dp { + struct hal_wbm_idle_scatter_list scatter_list[DP_IDLE_SCATTER_BUFS_MAX]; + struct list_head reo_cmd_list; + struct list_head reo_cmd_cache_flush_list; ++ struct list_head dp_full_mon_mpdu_list; + u32 reo_cmd_cache_flush_count; + /** + * protects access to below fields, +--- a/drivers/net/wireless/ath/ath11k/dp_rx.c ++++ b/drivers/net/wireless/ath/ath11k/dp_rx.c +@@ -2942,6 +2942,43 @@ fail_desc_get: + return req_entries - num_remain; + } + ++#define ATH11K_DP_RX_FULL_MON_PPDU_ID_WRAP 32535 ++ ++static void ++ath11k_dp_rx_mon_update_status_buf_state(struct ath11k_mon_data *pmon, ++ struct hal_tlv_hdr *tlv) ++{ ++ struct hal_rx_ppdu_start *ppdu_start; ++ u16 ppdu_id_diff, ppdu_id, tlv_len; ++ u8 *ptr; ++ ++ /* PPDU id is part of second tlv, move ptr to second tlv */ ++ tlv_len = FIELD_GET(HAL_TLV_HDR_LEN, tlv->tl); ++ ptr = (u8 *)tlv; ++ ptr += sizeof(*tlv) + tlv_len; ++ tlv = (struct hal_tlv_hdr *)ptr; ++ ++ if (FIELD_GET(HAL_TLV_HDR_TAG, tlv->tl) != HAL_RX_PPDU_START) ++ return; ++ ++ ptr += sizeof(*tlv); ++ ppdu_start = (struct hal_rx_ppdu_start *)ptr; ++ ppdu_id = FIELD_GET(HAL_RX_PPDU_START_INFO0_PPDU_ID, ++ __le32_to_cpu(ppdu_start->info0)); ++ ++ if (pmon->sw_mon_entries.ppdu_id < ppdu_id) { ++ pmon->buf_state = DP_MON_STATUS_LEAD; ++ ppdu_id_diff = ppdu_id - pmon->sw_mon_entries.ppdu_id; ++ if (ppdu_id_diff > ATH11K_DP_RX_FULL_MON_PPDU_ID_WRAP) ++ pmon->buf_state = DP_MON_STATUS_LAG; ++ } else if (pmon->sw_mon_entries.ppdu_id > ppdu_id) { ++ pmon->buf_state = DP_MON_STATUS_LAG; ++ ppdu_id_diff = pmon->sw_mon_entries.ppdu_id - ppdu_id; ++ if (ppdu_id_diff > ATH11K_DP_RX_FULL_MON_PPDU_ID_WRAP) ++ pmon->buf_state = DP_MON_STATUS_LEAD; ++ } ++} ++ + static int ath11k_dp_rx_reap_mon_status_ring(struct ath11k_base *ab, int mac_id, + int *budget, struct sk_buff_head *skb_list) + { +@@ -2949,6 +2986,7 @@ static int ath11k_dp_rx_reap_mon_status_ + const struct ath11k_hw_hal_params *hal_params; + struct ath11k_pdev_dp *dp; + struct dp_rxdma_ring *rx_ring; ++ struct ath11k_mon_data *pmon; + struct hal_srng *srng; + void *rx_mon_status_desc; + struct sk_buff *skb; +@@ -2962,6 +3000,7 @@ static int ath11k_dp_rx_reap_mon_status_ + + ar = ab->pdevs[ath11k_hw_mac_id_to_pdev_id(&ab->hw_params, mac_id)].ar; + dp = &ar->dp; ++ pmon = &dp->mon_data; + srng_id = ath11k_hw_mac_id_to_srng_id(&ab->hw_params, mac_id); + rx_ring = &dp->rx_mon_status_refill_ring[srng_id]; + +@@ -2974,8 +3013,10 @@ static int ath11k_dp_rx_reap_mon_status_ + *budget -= 1; + rx_mon_status_desc = + ath11k_hal_srng_src_peek(ab, srng); +- if (!rx_mon_status_desc) ++ if (!rx_mon_status_desc) { ++ pmon->buf_state = DP_MON_STATUS_REPLINISH; + break; ++ } + + ath11k_hal_rx_buf_addr_info_get(rx_mon_status_desc, &paddr, + &cookie, &rbm); +@@ -2988,6 +3029,7 @@ static int ath11k_dp_rx_reap_mon_status_ + ath11k_warn(ab, "rx monitor status with invalid buf_id %d\n", + buf_id); + spin_unlock_bh(&rx_ring->idr_lock); ++ pmon->buf_state = DP_MON_STATUS_REPLINISH; + goto move_next; + } + +@@ -3007,10 +3049,18 @@ static int ath11k_dp_rx_reap_mon_status_ + FIELD_GET(HAL_TLV_HDR_TAG, + tlv->tl)); + dev_kfree_skb_any(skb); ++ pmon->buf_state = DP_MON_STATUS_NO_DMA; + goto move_next; + } + ++ if (ab->hw_params.full_monitor_mode) { ++ ath11k_dp_rx_mon_update_status_buf_state(pmon, tlv); ++ if (paddr == pmon->mon_status_paddr) ++ pmon->buf_state = DP_MON_STATUS_MATCH; ++ } + __skb_queue_tail(skb_list, skb); ++ } else { ++ pmon->buf_state = DP_MON_STATUS_REPLINISH; + } + move_next: + skb = ath11k_dp_rx_alloc_mon_status_buf(ab, rx_ring, +@@ -5098,6 +5148,357 @@ static void ath11k_dp_rx_mon_status_proc + } + } + ++static u32 ++ath11k_dp_rx_full_mon_mpdu_pop(struct ath11k *ar, ++ void *ring_entry, struct sk_buff **head_msdu, ++ struct sk_buff **tail_msdu, ++ struct hal_sw_mon_ring_entries *sw_mon_entries) ++{ ++ struct ath11k_pdev_dp *dp = &ar->dp; ++ struct ath11k_mon_data *pmon = &dp->mon_data; ++ struct dp_rxdma_ring *rx_ring = &dp->rxdma_mon_buf_ring; ++ struct sk_buff *msdu = NULL, *last = NULL; ++ struct hal_sw_monitor_ring *sw_desc = ring_entry; ++ struct hal_rx_msdu_list msdu_list; ++ struct hal_rx_desc *rx_desc; ++ struct ath11k_skb_rxcb *rxcb; ++ void *rx_msdu_link_desc; ++ void *p_buf_addr_info, *p_last_buf_addr_info; ++ int buf_id, i = 0; ++ u32 rx_buf_size, rx_pkt_offset, l2_hdr_offset; ++ u32 rx_bufs_used = 0, msdu_cnt = 0; ++ u32 total_len = 0, frag_len = 0, sw_cookie; ++ u16 num_msdus = 0; ++ u8 rxdma_err, rbm; ++ bool is_frag, is_first_msdu; ++ bool drop_mpdu = false; ++ ++ ath11k_hal_rx_sw_mon_ring_buf_paddr_get(ring_entry, sw_mon_entries); ++ ++ sw_cookie = sw_mon_entries->mon_dst_sw_cookie; ++ sw_mon_entries->end_of_ppdu = false; ++ sw_mon_entries->drop_ppdu = false; ++ p_last_buf_addr_info = sw_mon_entries->dst_buf_addr_info; ++ msdu_cnt = sw_mon_entries->msdu_cnt; ++ ++ sw_mon_entries->end_of_ppdu = ++ FIELD_GET(HAL_SW_MON_RING_INFO0_END_OF_PPDU, sw_desc->info0); ++ if (sw_mon_entries->end_of_ppdu) ++ return rx_bufs_used; ++ ++ if (FIELD_GET(HAL_SW_MON_RING_INFO0_RXDMA_PUSH_REASON, ++ sw_desc->info0) == ++ HAL_REO_DEST_RING_PUSH_REASON_ERR_DETECTED) { ++ rxdma_err = ++ FIELD_GET(HAL_SW_MON_RING_INFO0_RXDMA_ERROR_CODE, ++ sw_desc->info0); ++ if (rxdma_err == HAL_REO_ENTR_RING_RXDMA_ECODE_FLUSH_REQUEST_ERR || ++ rxdma_err == HAL_REO_ENTR_RING_RXDMA_ECODE_MPDU_LEN_ERR || ++ rxdma_err == HAL_REO_ENTR_RING_RXDMA_ECODE_OVERFLOW_ERR) { ++ pmon->rx_mon_stats.dest_mpdu_drop++; ++ drop_mpdu = true; ++ } ++ } ++ ++ is_frag = false; ++ is_first_msdu = true; ++ ++ do { ++ rx_msdu_link_desc = ++ (u8 *)pmon->link_desc_banks[sw_cookie].vaddr + ++ (sw_mon_entries->mon_dst_paddr - ++ pmon->link_desc_banks[sw_cookie].paddr); ++ ++ ath11k_hal_rx_msdu_list_get(ar, rx_msdu_link_desc, &msdu_list, ++ &num_msdus); ++ ++ for (i = 0; i < num_msdus; i++) { ++ buf_id = FIELD_GET(DP_RXDMA_BUF_COOKIE_BUF_ID, ++ msdu_list.sw_cookie[i]); ++ ++ spin_lock_bh(&rx_ring->idr_lock); ++ msdu = idr_find(&rx_ring->bufs_idr, buf_id); ++ if (!msdu) { ++ ath11k_dbg(ar->ab, ATH11K_DBG_DATA, ++ "full mon msdu_pop: invalid buf_id %d\n", ++ buf_id); ++ spin_unlock_bh(&rx_ring->idr_lock); ++ break; ++ } ++ idr_remove(&rx_ring->bufs_idr, buf_id); ++ spin_unlock_bh(&rx_ring->idr_lock); ++ ++ rxcb = ATH11K_SKB_RXCB(msdu); ++ if (!rxcb->unmapped) { ++ dma_unmap_single(ar->ab->dev, rxcb->paddr, ++ msdu->len + ++ skb_tailroom(msdu), ++ DMA_FROM_DEVICE); ++ rxcb->unmapped = 1; ++ } ++ if (drop_mpdu) { ++ ath11k_dbg(ar->ab, ATH11K_DBG_DATA, ++ "full mon: i %d drop msdu %p *ppdu_id %x\n", ++ i, msdu, sw_mon_entries->ppdu_id); ++ dev_kfree_skb_any(msdu); ++ msdu_cnt--; ++ goto next_msdu; ++ } ++ ++ rx_desc = (struct hal_rx_desc *)msdu->data; ++ ++ rx_pkt_offset = sizeof(struct hal_rx_desc); ++ l2_hdr_offset = ath11k_dp_rx_h_msdu_end_l3pad(ar->ab, rx_desc); ++ ++ if (is_first_msdu) { ++ if (!ath11k_dp_rxdesc_mpdu_valid(ar->ab, rx_desc)) { ++ drop_mpdu = true; ++ dev_kfree_skb_any(msdu); ++ msdu = NULL; ++ goto next_msdu; ++ } ++ is_first_msdu = false; ++ } ++ ++ ath11k_dp_mon_get_buf_len(&msdu_list.msdu_info[i], ++ &is_frag, &total_len, ++ &frag_len, &msdu_cnt); ++ ++ rx_buf_size = rx_pkt_offset + l2_hdr_offset + frag_len; ++ ++ ath11k_dp_pkt_set_pktlen(msdu, rx_buf_size); ++ ++ if (!(*head_msdu)) ++ *head_msdu = msdu; ++ else if (last) ++ last->next = msdu; ++ ++ last = msdu; ++next_msdu: ++ rx_bufs_used++; ++ } ++ ++ ath11k_dp_rx_mon_next_link_desc_get(rx_msdu_link_desc, ++ &sw_mon_entries->mon_dst_paddr, ++ &sw_mon_entries->mon_dst_sw_cookie, ++ &rbm, ++ &p_buf_addr_info); ++ ++ if (ath11k_dp_rx_monitor_link_desc_return(ar, ++ p_last_buf_addr_info, ++ dp->mac_id)) ++ ath11k_dbg(ar->ab, ATH11K_DBG_DATA, ++ "full mon: dp_rx_monitor_link_desc_return failed\n"); ++ ++ p_last_buf_addr_info = p_buf_addr_info; ++ ++ } while (sw_mon_entries->mon_dst_paddr && msdu_cnt); ++ ++ if (last) ++ last->next = NULL; ++ ++ *tail_msdu = msdu; ++ ++ return rx_bufs_used; ++} ++ ++static int ath11k_dp_rx_full_mon_prepare_mpdu(struct ath11k_dp *dp, ++ struct dp_full_mon_mpdu *mon_mpdu, ++ struct sk_buff *head, ++ struct sk_buff *tail) ++{ ++ mon_mpdu = kzalloc(sizeof(*mon_mpdu), GFP_ATOMIC); ++ if (!mon_mpdu) ++ return -ENOMEM; ++ ++ list_add_tail(&mon_mpdu->list, &dp->dp_full_mon_mpdu_list); ++ mon_mpdu->head = head; ++ mon_mpdu->tail = tail; ++ ++ return 0; ++} ++ ++static void ath11k_dp_rx_full_mon_drop_ppdu(struct ath11k_dp *dp, ++ struct dp_full_mon_mpdu *mon_mpdu) ++{ ++ struct dp_full_mon_mpdu *tmp; ++ struct sk_buff *tmp_msdu, *skb_next; ++ ++ if (list_empty(&dp->dp_full_mon_mpdu_list)) ++ return; ++ ++ list_for_each_entry_safe(mon_mpdu, tmp, &dp->dp_full_mon_mpdu_list, list) { ++ list_del(&mon_mpdu->list); ++ ++ tmp_msdu = mon_mpdu->head; ++ while (tmp_msdu) { ++ skb_next = tmp_msdu->next; ++ dev_kfree_skb_any(tmp_msdu); ++ tmp_msdu = skb_next; ++ } ++ ++ kfree(mon_mpdu); ++ } ++} ++ ++static int ath11k_dp_rx_full_mon_deliver_ppdu(struct ath11k *ar, ++ int mac_id, ++ struct ath11k_mon_data *pmon, ++ struct napi_struct *napi) ++{ ++ struct ath11k_pdev_mon_stats *rx_mon_stats; ++ struct dp_full_mon_mpdu *tmp; ++ struct dp_full_mon_mpdu *mon_mpdu = pmon->mon_mpdu; ++ struct sk_buff *head_msdu, *tail_msdu; ++ struct ath11k_base *ab = ar->ab; ++ struct ath11k_dp *dp = &ab->dp; ++ int ret; ++ ++ rx_mon_stats = &pmon->rx_mon_stats; ++ ++ list_for_each_entry_safe(mon_mpdu, tmp, &dp->dp_full_mon_mpdu_list, list) { ++ list_del(&mon_mpdu->list); ++ head_msdu = mon_mpdu->head; ++ tail_msdu = mon_mpdu->tail; ++ if (head_msdu && tail_msdu) { ++ ret = ath11k_dp_rx_mon_deliver(ar, mac_id, head_msdu, ++ tail_msdu, napi); ++ rx_mon_stats->dest_mpdu_done++; ++ ath11k_dbg(ar->ab, ATH11K_DBG_DATA, "full mon: deliver ppdu\n"); ++ } ++ kfree(mon_mpdu); ++ } ++ ++ return ret; ++} ++ ++static int ++ath11k_dp_rx_process_full_mon_status_ring(struct ath11k_base *ab, int mac_id, ++ struct napi_struct *napi, int budget) ++{ ++ struct ath11k *ar = ab->pdevs[mac_id].ar; ++ struct ath11k_pdev_dp *dp = &ar->dp; ++ struct ath11k_mon_data *pmon = &dp->mon_data; ++ struct hal_sw_mon_ring_entries *sw_mon_entries; ++ int quota = 0, work = 0, count; ++ ++ sw_mon_entries = &pmon->sw_mon_entries; ++ ++ while (pmon->hold_mon_dst_ring) { ++ quota = ath11k_dp_rx_process_mon_status(ab, mac_id, ++ napi, 1); ++ if (pmon->buf_state == DP_MON_STATUS_MATCH) { ++ count = sw_mon_entries->status_buf_count; ++ if (count > 1) { ++ quota += ath11k_dp_rx_process_mon_status(ab, mac_id, ++ napi, count); ++ } ++ ++ ath11k_dp_rx_full_mon_deliver_ppdu(ar, dp->mac_id, ++ pmon, napi); ++ pmon->hold_mon_dst_ring = false; ++ } else if (!pmon->mon_status_paddr || ++ pmon->buf_state == DP_MON_STATUS_LEAD) { ++ sw_mon_entries->drop_ppdu = true; ++ pmon->hold_mon_dst_ring = false; ++ } ++ ++ if (!quota) ++ break; ++ ++ work += quota; ++ } ++ ++ if (sw_mon_entries->drop_ppdu) ++ ath11k_dp_rx_full_mon_drop_ppdu(&ab->dp, pmon->mon_mpdu); ++ ++ return work; ++} ++ ++static int ath11k_dp_full_mon_process_rx(struct ath11k_base *ab, int mac_id, ++ struct napi_struct *napi, int budget) ++{ ++ struct ath11k *ar = ab->pdevs[mac_id].ar; ++ struct ath11k_pdev_dp *dp = &ar->dp; ++ struct ath11k_mon_data *pmon = &dp->mon_data; ++ struct hal_sw_mon_ring_entries *sw_mon_entries; ++ struct ath11k_pdev_mon_stats *rx_mon_stats; ++ struct sk_buff *head_msdu, *tail_msdu; ++ void *mon_dst_srng = &ar->ab->hal.srng_list[dp->rxdma_mon_dst_ring.ring_id]; ++ void *ring_entry; ++ u32 rx_bufs_used = 0, mpdu_rx_bufs_used; ++ int quota = 0, ret; ++ bool break_dst_ring = false; ++ ++ spin_lock_bh(&pmon->mon_lock); ++ ++ sw_mon_entries = &pmon->sw_mon_entries; ++ rx_mon_stats = &pmon->rx_mon_stats; ++ ++ if (pmon->hold_mon_dst_ring) { ++ spin_unlock_bh(&pmon->mon_lock); ++ goto reap_status_ring; ++ } ++ ++ ath11k_hal_srng_access_begin(ar->ab, mon_dst_srng); ++ while ((ring_entry = ath11k_hal_srng_dst_peek(ar->ab, mon_dst_srng))) { ++ head_msdu = NULL; ++ tail_msdu = NULL; ++ ++ mpdu_rx_bufs_used = ath11k_dp_rx_full_mon_mpdu_pop(ar, ring_entry, ++ &head_msdu, ++ &tail_msdu, ++ sw_mon_entries); ++ rx_bufs_used += mpdu_rx_bufs_used; ++ ++ if (!sw_mon_entries->end_of_ppdu) { ++ if (head_msdu) { ++ ret = ath11k_dp_rx_full_mon_prepare_mpdu(&ab->dp, ++ pmon->mon_mpdu, ++ head_msdu, ++ tail_msdu); ++ if (ret) ++ break_dst_ring = true; ++ } ++ ++ goto next_entry; ++ } else { ++ if (!sw_mon_entries->ppdu_id && ++ !sw_mon_entries->mon_status_paddr) { ++ break_dst_ring = true; ++ goto next_entry; ++ } ++ } ++ ++ rx_mon_stats->dest_ppdu_done++; ++ pmon->mon_ppdu_status = DP_PPDU_STATUS_START; ++ pmon->buf_state = DP_MON_STATUS_LAG; ++ pmon->mon_status_paddr = sw_mon_entries->mon_status_paddr; ++ pmon->hold_mon_dst_ring = true; ++next_entry: ++ ring_entry = ath11k_hal_srng_dst_get_next_entry(ar->ab, ++ mon_dst_srng); ++ if (break_dst_ring) ++ break; ++ } ++ ++ ath11k_hal_srng_access_end(ar->ab, mon_dst_srng); ++ spin_unlock_bh(&pmon->mon_lock); ++ ++ if (rx_bufs_used) { ++ ath11k_dp_rxbufs_replenish(ar->ab, dp->mac_id, ++ &dp->rxdma_mon_buf_ring, ++ rx_bufs_used, ++ HAL_RX_BUF_RBM_SW3_BM); ++ } ++ ++reap_status_ring: ++ quota = ath11k_dp_rx_process_full_mon_status_ring(ab, mac_id, ++ napi, budget); ++ ++ return quota; ++} ++ + static int ath11k_dp_mon_process_rx(struct ath11k_base *ab, int mac_id, + struct napi_struct *napi, int budget) + { +@@ -5120,10 +5521,14 @@ int ath11k_dp_rx_process_mon_rings(struc + struct ath11k *ar = ath11k_ab_to_ar(ab, mac_id); + int ret = 0; + +- if (test_bit(ATH11K_FLAG_MONITOR_STARTED, &ar->monitor_flags)) ++ if (test_bit(ATH11K_FLAG_MONITOR_STARTED, &ar->monitor_flags) && ++ ab->hw_params.full_monitor_mode) ++ ret = ath11k_dp_full_mon_process_rx(ab, mac_id, napi, budget); ++ else if (test_bit(ATH11K_FLAG_MONITOR_STARTED, &ar->monitor_flags)) + ret = ath11k_dp_mon_process_rx(ab, mac_id, napi, budget); + else + ret = ath11k_dp_rx_process_mon_status(ab, mac_id, napi, budget); ++ + return ret; + } + diff --git a/package/kernel/mac80211/patches/ath11k/0134-ath11k-add-spectral-CFR-buffer-validation-support.patch b/package/kernel/mac80211/patches/ath11k/0134-ath11k-add-spectral-CFR-buffer-validation-support.patch new file mode 100644 index 000000000..ac37a3a0b --- /dev/null +++ b/package/kernel/mac80211/patches/ath11k/0134-ath11k-add-spectral-CFR-buffer-validation-support.patch @@ -0,0 +1,118 @@ +From d3d358efc553de4f9d803c889a2e91523ea90f19 Mon Sep 17 00:00:00 2001 +From: Venkateswara Naralasetty +Date: Wed, 8 Dec 2021 10:44:00 +0200 +Subject: [PATCH] ath11k: add spectral/CFR buffer validation support + +Currently there is no validation on the spectral/CFR report +over the db ring buffers from the hardware. Improper/incomplete +DMA by the target can result in invalid data received by host. +Due to this we may populate incorrect data to user space. + +This buffer validation support fix this issues by filling some +magic value in the buffer during buffer replenish and check for +the magic value in the buffer received by the target. If host +detect magic value in the received buffer it will drop the buffer. + +Tested-on: IPQ8074 WLAN.HK.2.4.0.1-01467-QCAHKSWPL_SILICONZ-1 + +Signed-off-by: Venkateswara Naralasetty +Signed-off-by: Kalle Valo +Link: https://lore.kernel.org/r/1637312901-10279-2-git-send-email-quic_vnaralas@quicinc.com +--- + drivers/net/wireless/ath/ath11k/dbring.c | 30 ++++++++++++++++++++++ + drivers/net/wireless/ath/ath11k/dbring.h | 2 ++ + drivers/net/wireless/ath/ath11k/spectral.c | 14 ++++++++++ + 3 files changed, 46 insertions(+) + +--- a/drivers/net/wireless/ath/ath11k/dbring.c ++++ b/drivers/net/wireless/ath/ath11k/dbring.c +@@ -6,6 +6,35 @@ + #include "core.h" + #include "debug.h" + ++#define ATH11K_DB_MAGIC_VALUE 0xdeadbeaf ++ ++int ath11k_dbring_validate_buffer(struct ath11k *ar, void *buffer, u32 size) ++{ ++ u32 *temp; ++ int idx; ++ ++ size = size >> 2; ++ ++ for (idx = 0, temp = buffer; idx < size; idx++, temp++) { ++ if (*temp == ATH11K_DB_MAGIC_VALUE) ++ return -EINVAL; ++ } ++ ++ return 0; ++} ++ ++static void ath11k_dbring_fill_magic_value(struct ath11k *ar, ++ void *buffer, u32 size) ++{ ++ u32 *temp; ++ int idx; ++ ++ size = size >> 2; ++ ++ for (idx = 0, temp = buffer; idx < size; idx++, temp++) ++ *temp++ = ATH11K_DB_MAGIC_VALUE; ++} ++ + static int ath11k_dbring_bufs_replenish(struct ath11k *ar, + struct ath11k_dbring *ring, + struct ath11k_dbring_element *buff) +@@ -26,6 +55,7 @@ static int ath11k_dbring_bufs_replenish( + + ptr_unaligned = buff->payload; + ptr_aligned = PTR_ALIGN(ptr_unaligned, ring->buf_align); ++ ath11k_dbring_fill_magic_value(ar, ptr_aligned, ring->buf_sz); + paddr = dma_map_single(ab->dev, ptr_aligned, ring->buf_sz, + DMA_FROM_DEVICE); + +--- a/drivers/net/wireless/ath/ath11k/dbring.h ++++ b/drivers/net/wireless/ath/ath11k/dbring.h +@@ -76,4 +76,6 @@ int ath11k_dbring_get_cap(struct ath11k_ + struct ath11k_dbring_cap *db_cap); + void ath11k_dbring_srng_cleanup(struct ath11k *ar, struct ath11k_dbring *ring); + void ath11k_dbring_buf_cleanup(struct ath11k *ar, struct ath11k_dbring *ring); ++int ath11k_dbring_validate_buffer(struct ath11k *ar, void *data, u32 size); ++ + #endif /* ATH11K_DBRING_H */ +--- a/drivers/net/wireless/ath/ath11k/spectral.c ++++ b/drivers/net/wireless/ath/ath11k/spectral.c +@@ -585,6 +585,7 @@ int ath11k_spectral_process_fft(struct a + u16 length, freq; + u8 chan_width_mhz, bin_sz; + int ret; ++ u32 check_length; + + lockdep_assert_held(&ar->spectral.lock); + +@@ -618,6 +619,13 @@ int ath11k_spectral_process_fft(struct a + return -EINVAL; + } + ++ check_length = sizeof(*fft_report) + (num_bins * ab->hw_params.spectral.fft_sz); ++ ret = ath11k_dbring_validate_buffer(ar, data, check_length); ++ if (ret) { ++ ath11k_warn(ar->ab, "found magic value in fft data, dropping\n"); ++ return ret; ++ } ++ + ret = ath11k_spectral_pull_search(ar, data, &search); + if (ret) { + ath11k_warn(ab, "failed to pull search report %d\n", ret); +@@ -751,6 +759,12 @@ static int ath11k_spectral_process_data( + goto err; + } + ++ ret = ath11k_dbring_validate_buffer(ar, data, tlv_len); ++ if (ret) { ++ ath11k_warn(ar->ab, "found magic value in spectral summary, dropping\n"); ++ goto err; ++ } ++ + summary = (struct spectral_summary_fft_report *)tlv; + ath11k_spectral_pull_summary(ar, ¶m->meta, + summary, &summ_rpt); diff --git a/package/kernel/mac80211/patches/ath11k/0135-ath11k-support-MAC-address-randomization-in-scan.patch b/package/kernel/mac80211/patches/ath11k/0135-ath11k-support-MAC-address-randomization-in-scan.patch new file mode 100644 index 000000000..772bb54bb --- /dev/null +++ b/package/kernel/mac80211/patches/ath11k/0135-ath11k-support-MAC-address-randomization-in-scan.patch @@ -0,0 +1,137 @@ +From 9cbd7fc9be82a99af690adcebd6f2cdae4c7c193 Mon Sep 17 00:00:00 2001 +From: Carl Huang +Date: Thu, 9 Dec 2021 10:17:49 +0200 +Subject: [PATCH] ath11k: support MAC address randomization in scan + +The driver reports NL80211_FEATURE_SCAN_RANDOM_MAC_ADDR capability +to upper layer based on the service bit firmware reported. Driver +sets the spoofed flag in scan_ctrl_flag to firmware if upper layer +has enabled this feature in scan request. + +Tested-on: QCA6390 hw2.0 PCI WLAN.HST.1.0.1-01740-QCAHSTSWPLZ_V2_TO_X86-1 + +Signed-off-by: Carl Huang +Signed-off-by: Kalle Valo +Link: https://lore.kernel.org/r/1638948007-9609-1-git-send-email-quic_cjhuang@quicinc.com +--- + drivers/net/wireless/ath/ath11k/mac.c | 19 +++++++++++++++++ + drivers/net/wireless/ath/ath11k/wmi.c | 30 +++++++++++++++++++++++++++ + drivers/net/wireless/ath/ath11k/wmi.h | 10 ++++++++- + 3 files changed, 58 insertions(+), 1 deletion(-) + +--- a/drivers/net/wireless/ath/ath11k/mac.c ++++ b/drivers/net/wireless/ath/ath11k/mac.c +@@ -3543,6 +3543,12 @@ static int ath11k_mac_op_hw_scan(struct + arg.chan_list[i] = req->channels[i]->center_freq; + } + ++ if (req->flags & NL80211_SCAN_FLAG_RANDOM_ADDR) { ++ arg.scan_f_add_spoofed_mac_in_probe = 1; ++ ether_addr_copy(arg.mac_addr.addr, req->mac_addr); ++ ether_addr_copy(arg.mac_mask.addr, req->mac_addr_mask); ++ } ++ + ret = ath11k_start_scan(ar, &arg); + if (ret) { + ath11k_warn(ar->ab, "failed to start hw scan: %d\n", ret); +@@ -5587,6 +5593,14 @@ static int ath11k_mac_op_start(struct ie + goto err; + } + ++ if (test_bit(WMI_TLV_SERVICE_SPOOF_MAC_SUPPORT, ar->wmi->wmi_ab->svc_map)) { ++ ret = ath11k_wmi_scan_prob_req_oui(ar, ar->mac_addr); ++ if (ret) { ++ ath11k_err(ab, "failed to set prob req oui: %i\n", ret); ++ goto err; ++ } ++ } ++ + ret = ath11k_wmi_pdev_set_param(ar, WMI_PDEV_PARAM_ARP_AC_OVERRIDE, + 0, pdev->pdev_id); + if (ret) { +@@ -8183,6 +8197,11 @@ static int __ath11k_mac_register(struct + + ar->hw->wiphy->max_ap_assoc_sta = ar->max_num_stations; + ++ if (test_bit(WMI_TLV_SERVICE_SPOOF_MAC_SUPPORT, ar->wmi->wmi_ab->svc_map)) { ++ ar->hw->wiphy->features |= ++ NL80211_FEATURE_SCAN_RANDOM_MAC_ADDR; ++ } ++ + ar->hw->queues = ATH11K_HW_MAX_QUEUES; + ar->hw->wiphy->tx_queue_len = ATH11K_QUEUE_LEN; + ar->hw->offchannel_tx_hw_queue = ATH11K_HW_MAX_QUEUES - 1; +--- a/drivers/net/wireless/ath/ath11k/wmi.c ++++ b/drivers/net/wireless/ath/ath11k/wmi.c +@@ -2181,6 +2181,8 @@ int ath11k_wmi_send_scan_start_cmd(struc + cmd->num_ssids = params->num_ssids; + cmd->ie_len = params->extraie.len; + cmd->n_probes = params->n_probes; ++ ether_addr_copy(cmd->mac_addr.addr, params->mac_addr.addr); ++ ether_addr_copy(cmd->mac_mask.addr, params->mac_mask.addr); + + ptr += sizeof(*cmd); + +@@ -7710,3 +7712,31 @@ int ath11k_wmi_wow_enable(struct ath11k + + return ath11k_wmi_cmd_send(ar->wmi, skb, WMI_WOW_ENABLE_CMDID); + } ++ ++int ath11k_wmi_scan_prob_req_oui(struct ath11k *ar, ++ const u8 mac_addr[ETH_ALEN]) ++{ ++ struct sk_buff *skb; ++ struct wmi_scan_prob_req_oui_cmd *cmd; ++ u32 prob_req_oui; ++ int len; ++ ++ prob_req_oui = (((u32)mac_addr[0]) << 16) | ++ (((u32)mac_addr[1]) << 8) | mac_addr[2]; ++ ++ len = sizeof(*cmd); ++ skb = ath11k_wmi_alloc_skb(ar->wmi->wmi_ab, len); ++ if (!skb) ++ return -ENOMEM; ++ ++ cmd = (struct wmi_scan_prob_req_oui_cmd *)skb->data; ++ cmd->tlv_header = FIELD_PREP(WMI_TLV_TAG, ++ WMI_TAG_SCAN_PROB_REQ_OUI_CMD) | ++ FIELD_PREP(WMI_TLV_LEN, sizeof(*cmd) - TLV_HDR_SIZE); ++ cmd->prob_req_oui = prob_req_oui; ++ ++ ath11k_dbg(ar->ab, ATH11K_DBG_WMI, "wmi scan prob req oui %d\n", ++ prob_req_oui); ++ ++ return ath11k_wmi_cmd_send(ar->wmi, skb, WMI_SCAN_PROB_REQ_OUI_CMDID); ++} +--- a/drivers/net/wireless/ath/ath11k/wmi.h ++++ b/drivers/net/wireless/ath/ath11k/wmi.h +@@ -3313,6 +3313,8 @@ struct scan_req_params { + u32 num_hint_bssid; + struct hint_short_ssid hint_s_ssid[WLAN_SCAN_MAX_HINT_S_SSID]; + struct hint_bssid hint_bssid[WLAN_SCAN_MAX_HINT_BSSID]; ++ struct wmi_mac_addr mac_addr; ++ struct wmi_mac_addr mac_mask; + }; + + struct wmi_ssid_arg { +@@ -3676,6 +3678,11 @@ struct wmi_scan_chan_list_cmd { + u32 pdev_id; + } __packed; + ++struct wmi_scan_prob_req_oui_cmd { ++ u32 tlv_header; ++ u32 prob_req_oui; ++} __packed; ++ + #define WMI_MGMT_SEND_DOWNLD_LEN 64 + + #define WMI_TX_PARAMS_DWORD0_POWER GENMASK(7, 0) +@@ -5530,5 +5537,6 @@ int ath11k_wmi_set_hw_mode(struct ath11k + enum wmi_host_hw_mode_config_type mode); + int ath11k_wmi_wow_host_wakeup_ind(struct ath11k *ar); + int ath11k_wmi_wow_enable(struct ath11k *ar); +- ++int ath11k_wmi_scan_prob_req_oui(struct ath11k *ar, ++ const u8 mac_addr[ETH_ALEN]); + #endif diff --git a/package/kernel/mac80211/patches/ath11k/0136-ath11k-set-DTIM-policy-to-stick-mode-for-station-int.patch b/package/kernel/mac80211/patches/ath11k/0136-ath11k-set-DTIM-policy-to-stick-mode-for-station-int.patch new file mode 100644 index 000000000..a74d67801 --- /dev/null +++ b/package/kernel/mac80211/patches/ath11k/0136-ath11k-set-DTIM-policy-to-stick-mode-for-station-int.patch @@ -0,0 +1,51 @@ +From 55e18e5a76ab5de2286d4bac703a78066278f475 Mon Sep 17 00:00:00 2001 +From: Carl Huang +Date: Thu, 9 Dec 2021 10:17:49 +0200 +Subject: [PATCH] ath11k: set DTIM policy to stick mode for station interface + +Set DTIM policy to DTIM stick mode, so station follows AP DTIM +interval rather than listen interval which is set in peer assoc cmd. +DTIM stick mode is more preferred per firmware team request. + +Tested-on: QCA6390 hw2.0 PCI WLAN.HST.1.0.1-01740-QCAHSTSWPLZ_V2_TO_X86-1 + +Signed-off-by: Carl Huang +Signed-off-by: Kalle Valo +Link: https://lore.kernel.org/r/1638948694-15582-1-git-send-email-quic_cjhuang@quicinc.com +--- + drivers/net/wireless/ath/ath11k/mac.c | 7 +++++++ + drivers/net/wireless/ath/ath11k/wmi.h | 7 +++++++ + 2 files changed, 14 insertions(+) + +--- a/drivers/net/wireless/ath/ath11k/mac.c ++++ b/drivers/net/wireless/ath/ath11k/mac.c +@@ -2682,6 +2682,13 @@ static void ath11k_bss_assoc(struct ieee + ath11k_warn(ar->ab, "failed to set vdev %i OBSS PD parameters: %d\n", + arvif->vdev_id, ret); + ++ ret = ath11k_wmi_vdev_set_param_cmd(ar, arvif->vdev_id, ++ WMI_VDEV_PARAM_DTIM_POLICY, ++ WMI_DTIM_POLICY_STICK); ++ if (ret) ++ ath11k_warn(ar->ab, "failed to set vdev %d dtim policy: %d\n", ++ arvif->vdev_id, ret); ++ + ath11k_mac_11d_scan_stop_all(ar->ab); + } + +--- a/drivers/net/wireless/ath/ath11k/wmi.h ++++ b/drivers/net/wireless/ath/ath11k/wmi.h +@@ -2169,6 +2169,13 @@ enum wmi_nss_ratio { + WMI_NSS_RATIO_2_NSS = 0x3, + }; + ++enum wmi_dtim_policy { ++ WMI_DTIM_POLICY_IGNORE = 1, ++ WMI_DTIM_POLICY_NORMAL = 2, ++ WMI_DTIM_POLICY_STICK = 3, ++ WMI_DTIM_POLICY_AUTO = 4, ++}; ++ + struct wmi_host_pdev_band_to_mac { + u32 pdev_id; + u32 start_freq; diff --git a/package/kernel/mac80211/patches/ath11k/0137-ath11k-Avoid-false-DEADLOCK-warning-reported-by-lock.patch b/package/kernel/mac80211/patches/ath11k/0137-ath11k-Avoid-false-DEADLOCK-warning-reported-by-lock.patch new file mode 100644 index 000000000..c2f097f29 --- /dev/null +++ b/package/kernel/mac80211/patches/ath11k/0137-ath11k-Avoid-false-DEADLOCK-warning-reported-by-lock.patch @@ -0,0 +1,169 @@ +From 767c94caf0efad136157110787fe221b74cb5c8a Mon Sep 17 00:00:00 2001 +From: Baochen Qiang +Date: Thu, 9 Dec 2021 09:19:49 +0800 +Subject: [PATCH] ath11k: Avoid false DEADLOCK warning reported by lockdep + +With CONFIG_LOCKDEP=y and CONFIG_DEBUG_SPINLOCK=y, lockdep reports +below warning: + +[ 166.059415] ============================================ +[ 166.059416] WARNING: possible recursive locking detected +[ 166.059418] 5.15.0-wt-ath+ #10 Tainted: G W O +[ 166.059420] -------------------------------------------- +[ 166.059421] kworker/0:2/116 is trying to acquire lock: +[ 166.059423] ffff9905f2083160 (&srng->lock){+.-.}-{2:2}, at: ath11k_hal_reo_cmd_send+0x20/0x490 [ath11k] +[ 166.059440] + but task is already holding lock: +[ 166.059442] ffff9905f2083230 (&srng->lock){+.-.}-{2:2}, at: ath11k_dp_process_reo_status+0x95/0x2d0 [ath11k] +[ 166.059491] + other info that might help us debug this: +[ 166.059492] Possible unsafe locking scenario: + +[ 166.059493] CPU0 +[ 166.059494] ---- +[ 166.059495] lock(&srng->lock); +[ 166.059498] lock(&srng->lock); +[ 166.059500] + *** DEADLOCK *** + +[ 166.059501] May be due to missing lock nesting notation + +[ 166.059502] 3 locks held by kworker/0:2/116: +[ 166.059504] #0: ffff9905c0081548 ((wq_completion)events){+.+.}-{0:0}, at: process_one_work+0x1f6/0x660 +[ 166.059511] #1: ffff9d2400a5fe68 ((debug_obj_work).work){+.+.}-{0:0}, at: process_one_work+0x1f6/0x660 +[ 166.059517] #2: ffff9905f2083230 (&srng->lock){+.-.}-{2:2}, at: ath11k_dp_process_reo_status+0x95/0x2d0 [ath11k] +[ 166.059532] + stack backtrace: +[ 166.059534] CPU: 0 PID: 116 Comm: kworker/0:2 Kdump: loaded Tainted: G W O 5.15.0-wt-ath+ #10 +[ 166.059537] Hardware name: Intel(R) Client Systems NUC8i7HVK/NUC8i7HVB, BIOS HNKBLi70.86A.0059.2019.1112.1124 11/12/2019 +[ 166.059539] Workqueue: events free_obj_work +[ 166.059543] Call Trace: +[ 166.059545] +[ 166.059547] dump_stack_lvl+0x56/0x7b +[ 166.059552] __lock_acquire+0xb9a/0x1a50 +[ 166.059556] lock_acquire+0x1e2/0x330 +[ 166.059560] ? ath11k_hal_reo_cmd_send+0x20/0x490 [ath11k] +[ 166.059571] _raw_spin_lock_bh+0x33/0x70 +[ 166.059574] ? ath11k_hal_reo_cmd_send+0x20/0x490 [ath11k] +[ 166.059584] ath11k_hal_reo_cmd_send+0x20/0x490 [ath11k] +[ 166.059594] ath11k_dp_tx_send_reo_cmd+0x3f/0x130 [ath11k] +[ 166.059605] ath11k_dp_rx_tid_del_func+0x221/0x370 [ath11k] +[ 166.059618] ath11k_dp_process_reo_status+0x22f/0x2d0 [ath11k] +[ 166.059632] ? ath11k_dp_service_srng+0x2ea/0x2f0 [ath11k] +[ 166.059643] ath11k_dp_service_srng+0x2ea/0x2f0 [ath11k] +[ 166.059655] ath11k_pci_ext_grp_napi_poll+0x1c/0x70 [ath11k_pci] +[ 166.059659] __napi_poll+0x28/0x230 +[ 166.059664] net_rx_action+0x285/0x310 +[ 166.059668] __do_softirq+0xe6/0x4d2 +[ 166.059672] irq_exit_rcu+0xd2/0xf0 +[ 166.059675] common_interrupt+0xa5/0xc0 +[ 166.059678] +[ 166.059679] +[ 166.059680] asm_common_interrupt+0x1e/0x40 +[ 166.059683] RIP: 0010:_raw_spin_unlock_irqrestore+0x38/0x70 +[ 166.059686] Code: 83 c7 18 e8 2a 95 43 ff 48 89 ef e8 22 d2 43 ff 81 e3 00 02 00 00 75 25 9c 58 f6 c4 02 75 2d 48 85 db 74 01 fb bf 01 00 00 00 63 2e 40 ff 65 8b 05 8c 59 97 5c 85 c0 74 0a 5b 5d c3 e8 00 6a +[ 166.059689] RSP: 0018:ffff9d2400a5fca0 EFLAGS: 00000206 +[ 166.059692] RAX: 0000000000000002 RBX: 0000000000000200 RCX: 0000000000000006 +[ 166.059694] RDX: 0000000000000000 RSI: ffffffffa404879b RDI: 0000000000000001 +[ 166.059696] RBP: ffff9905c0053000 R08: 0000000000000001 R09: 0000000000000001 +[ 166.059698] R10: ffff9d2400a5fc50 R11: 0000000000000001 R12: ffffe186c41e2840 +[ 166.059700] R13: 0000000000000001 R14: ffff9905c78a1c68 R15: 0000000000000001 +[ 166.059704] free_debug_processing+0x257/0x3d0 +[ 166.059708] ? free_obj_work+0x1f5/0x250 +[ 166.059712] __slab_free+0x374/0x5a0 +[ 166.059718] ? kmem_cache_free+0x2e1/0x370 +[ 166.059721] ? free_obj_work+0x1f5/0x250 +[ 166.059724] kmem_cache_free+0x2e1/0x370 +[ 166.059727] free_obj_work+0x1f5/0x250 +[ 166.059731] process_one_work+0x28b/0x660 +[ 166.059735] ? process_one_work+0x660/0x660 +[ 166.059738] worker_thread+0x37/0x390 +[ 166.059741] ? process_one_work+0x660/0x660 +[ 166.059743] kthread+0x176/0x1a0 +[ 166.059746] ? set_kthread_struct+0x40/0x40 +[ 166.059749] ret_from_fork+0x22/0x30 +[ 166.059754] + +Since these two lockes are both initialized in ath11k_hal_srng_setup, +they are assigned with the same key. As a result lockdep suspects that +the task is trying to acquire the same lock (due to same key) while +already holding it, and thus reports the DEADLOCK warning. However as +they are different spinlock instances, the warning is false positive. + +On the other hand, even no dead lock indeed, this is a major issue for +upstream regression testing as it disables lockdep functionality. + +Fix it by assigning separate lock class key for each srng->lock. + +Tested-on: WCN6855 hw2.0 PCI WLAN.HSP.1.1-01720.1-QCAHSPSWPL_V1_V2_SILICONZ_LITE-1 +Signed-off-by: Baochen Qiang +Signed-off-by: Kalle Valo +Link: https://lore.kernel.org/r/20211209011949.151472-1-quic_bqiang@quicinc.com +--- + drivers/net/wireless/ath/ath11k/hal.c | 22 ++++++++++++++++++++++ + drivers/net/wireless/ath/ath11k/hal.h | 2 ++ + 2 files changed, 24 insertions(+) + +--- a/drivers/net/wireless/ath/ath11k/hal.c ++++ b/drivers/net/wireless/ath/ath11k/hal.c +@@ -974,6 +974,7 @@ int ath11k_hal_srng_setup(struct ath11k_ + srng->msi_data = params->msi_data; + srng->initialized = 1; + spin_lock_init(&srng->lock); ++ lockdep_set_class(&srng->lock, hal->srng_key + ring_id); + + for (i = 0; i < HAL_SRNG_NUM_REG_GRP; i++) { + srng->hwreg_base[i] = srng_config->reg_start[i] + +@@ -1260,6 +1261,24 @@ static int ath11k_hal_srng_create_config + return 0; + } + ++static void ath11k_hal_register_srng_key(struct ath11k_base *ab) ++{ ++ struct ath11k_hal *hal = &ab->hal; ++ u32 ring_id; ++ ++ for (ring_id = 0; ring_id < HAL_SRNG_RING_ID_MAX; ring_id++) ++ lockdep_register_key(hal->srng_key + ring_id); ++} ++ ++static void ath11k_hal_unregister_srng_key(struct ath11k_base *ab) ++{ ++ struct ath11k_hal *hal = &ab->hal; ++ u32 ring_id; ++ ++ for (ring_id = 0; ring_id < HAL_SRNG_RING_ID_MAX; ring_id++) ++ lockdep_unregister_key(hal->srng_key + ring_id); ++} ++ + int ath11k_hal_srng_init(struct ath11k_base *ab) + { + struct ath11k_hal *hal = &ab->hal; +@@ -1279,6 +1298,8 @@ int ath11k_hal_srng_init(struct ath11k_b + if (ret) + goto err_free_cont_rdp; + ++ ath11k_hal_register_srng_key(ab); ++ + return 0; + + err_free_cont_rdp: +@@ -1293,6 +1314,7 @@ void ath11k_hal_srng_deinit(struct ath11 + { + struct ath11k_hal *hal = &ab->hal; + ++ ath11k_hal_unregister_srng_key(ab); + ath11k_hal_free_cont_rdp(ab); + ath11k_hal_free_cont_wrp(ab); + kfree(hal->srng_config); +--- a/drivers/net/wireless/ath/ath11k/hal.h ++++ b/drivers/net/wireless/ath/ath11k/hal.h +@@ -902,6 +902,8 @@ struct ath11k_hal { + /* shadow register configuration */ + u32 shadow_reg_addr[HAL_SHADOW_NUM_REGS]; + int num_shadow_reg_configured; ++ ++ struct lock_class_key srng_key[HAL_SRNG_RING_ID_MAX]; + }; + + u32 ath11k_hal_reo_qdesc_size(u32 ba_window_size, u8 tid); diff --git a/package/kernel/mac80211/patches/ath11k/0138-ath11k-Fix-deleting-uninitialized-kernel-timer-durin.patch b/package/kernel/mac80211/patches/ath11k/0138-ath11k-Fix-deleting-uninitialized-kernel-timer-durin.patch new file mode 100644 index 000000000..96e0483d8 --- /dev/null +++ b/package/kernel/mac80211/patches/ath11k/0138-ath11k-Fix-deleting-uninitialized-kernel-timer-durin.patch @@ -0,0 +1,88 @@ +From ba53ee7f7f38cf0592b8be1dcdabaf8f7535f8c1 Mon Sep 17 00:00:00 2001 +From: Rameshkumar Sundaram +Date: Thu, 9 Dec 2021 23:07:01 +0530 +Subject: [PATCH] ath11k: Fix deleting uninitialized kernel timer during + fragment cache flush + +frag_timer will be created & initialized for stations when +they associate and will be deleted during every key installation +while flushing old fragments. + +For AP interface self peer will be created and Group keys +will be installed for this peer, but there will be no real +Station entry & hence frag_timer won't be created and +initialized, deleting such uninitialized kernel timers causes below +warnings and backtraces printed with CONFIG_DEBUG_OBJECTS_TIMERS +enabled. + +[ 177.828008] ODEBUG: assert_init not available (active state 0) object type: timer_list hint: 0x0 +[ 177.836833] WARNING: CPU: 3 PID: 188 at lib/debugobjects.c:508 debug_print_object+0xb0/0xf0 +[ 177.845185] Modules linked in: ath11k_pci ath11k qmi_helpers qrtr_mhi qrtr ns mhi +[ 177.852679] CPU: 3 PID: 188 Comm: hostapd Not tainted 5.14.0-rc3-32919-g4034139e1838-dirty #14 +[ 177.865805] pstate: 60000005 (nZCv daif -PAN -UAO -TCO BTYPE=--) +[ 177.871804] pc : debug_print_object+0xb0/0xf0 +[ 177.876155] lr : debug_print_object+0xb0/0xf0 +[ 177.880505] sp : ffffffc01169b5a0 +[ 177.883810] x29: ffffffc01169b5a0 x28: ffffff80081c2320 x27: ffffff80081c4078 +[ 177.890942] x26: ffffff8003fe8f28 x25: ffffff8003de9890 x24: ffffffc01134d738 +[ 177.898075] x23: ffffffc010948f20 x22: ffffffc010b2d2e0 x21: ffffffc01169b628 +[ 177.905206] x20: ffffffc01134d700 x19: ffffffc010c80d98 x18: 00000000000003f6 +[ 177.912339] x17: 203a657079742074 x16: 63656a626f202930 x15: 0000000000000152 +[ 177.919471] x14: 0000000000000152 x13: 00000000ffffffea x12: ffffffc010d732e0 +[ 177.926603] x11: 0000000000000003 x10: ffffffc010d432a0 x9 : ffffffc010d432f8 +[ 177.933735] x8 : 000000000002ffe8 x7 : c0000000ffffdfff x6 : 0000000000000001 +[ 177.940866] x5 : 0000000000000000 x4 : 0000000000000000 x3 : 00000000ffffffff +[ 177.947997] x2 : ffffffc010c93240 x1 : ffffff80023624c0 x0 : 0000000000000054 +[ 177.955130] Call trace: +[ 177.957567] debug_print_object+0xb0/0xf0 +[ 177.961570] debug_object_assert_init+0x124/0x178 +[ 177.966269] try_to_del_timer_sync+0x1c/0x70 +[ 177.970536] del_timer_sync+0x30/0x50 +[ 177.974192] ath11k_peer_frags_flush+0x34/0x68 [ath11k] +[ 177.979439] ath11k_mac_op_set_key+0x1e4/0x338 [ath11k] +[ 177.984673] ieee80211_key_enable_hw_accel+0xc8/0x3d0 +[ 177.989722] ieee80211_key_replace+0x360/0x740 +[ 177.994160] ieee80211_key_link+0x16c/0x210 +[ 177.998337] ieee80211_add_key+0x138/0x338 +[ 178.002426] nl80211_new_key+0xfc/0x258 +[ 178.006257] genl_family_rcv_msg_doit.isra.17+0xd8/0x120 +[ 178.011565] genl_rcv_msg+0xd8/0x1c8 +[ 178.015134] netlink_rcv_skb+0x38/0xf8 +[ 178.018877] genl_rcv+0x34/0x48 +[ 178.022012] netlink_unicast+0x174/0x230 +[ 178.025928] netlink_sendmsg+0x188/0x388 +[ 178.029845] ____sys_sendmsg+0x218/0x250 +[ 178.033763] ___sys_sendmsg+0x68/0x90 +[ 178.037418] __sys_sendmsg+0x44/0x88 +[ 178.040988] __arm64_sys_sendmsg+0x20/0x28 +[ 178.045077] invoke_syscall.constprop.5+0x54/0xe0 +[ 178.049776] do_el0_svc+0x74/0xc0 +[ 178.053084] el0_svc+0x10/0x18 +[ 178.056133] el0t_64_sync_handler+0x88/0xb0 +[ 178.060310] el0t_64_sync+0x148/0x14c +[ 178.063966] ---[ end trace 8a5cf0bf9d34a058 ]--- + +Add changes to not to delete frag timer for peers during +group key installation. + +Tested on: IPQ8074 hw2.0 AHB WLAN.HK.2.5.0.1-01092-QCAHKSWPL_SILICONZ-1 + +Fixes: c3944a562102 ("ath11k: Clear the fragment cache during key install") +Signed-off-by: Rameshkumar Sundaram +Signed-off-by: Kalle Valo +Link: https://lore.kernel.org/r/1639071421-25078-1-git-send-email-quic_ramess@quicinc.com +--- + drivers/net/wireless/ath/ath11k/mac.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +--- a/drivers/net/wireless/ath/ath11k/mac.c ++++ b/drivers/net/wireless/ath/ath11k/mac.c +@@ -3747,7 +3747,7 @@ static int ath11k_mac_op_set_key(struct + /* flush the fragments cache during key (re)install to + * ensure all frags in the new frag list belong to the same key. + */ +- if (peer && cmd == SET_KEY) ++ if (peer && sta && cmd == SET_KEY) + ath11k_peer_frags_flush(ar, peer); + spin_unlock_bh(&ab->base_lock); + diff --git a/package/kernel/mac80211/patches/ath11k/0139-ath11k-Fix-a-NULL-pointer-dereference-in-ath11k_mac_.patch b/package/kernel/mac80211/patches/ath11k/0139-ath11k-Fix-a-NULL-pointer-dereference-in-ath11k_mac_.patch new file mode 100644 index 000000000..e3466c05f --- /dev/null +++ b/package/kernel/mac80211/patches/ath11k/0139-ath11k-Fix-a-NULL-pointer-dereference-in-ath11k_mac_.patch @@ -0,0 +1,50 @@ +From eccd25136386a04ebf46a64f3a34e8e0fab6d9e1 Mon Sep 17 00:00:00 2001 +From: Zhou Qingyang +Date: Mon, 13 Dec 2021 11:53:07 +0200 +Subject: [PATCH] ath11k: Fix a NULL pointer dereference in + ath11k_mac_op_hw_scan() + +In ath11k_mac_op_hw_scan(), the return value of kzalloc() is directly +used in memcpy(), which may lead to a NULL pointer dereference on +failure of kzalloc(). + +Fix this bug by adding a check of arg.extraie.ptr. + +This bug was found by a static analyzer. The analysis employs +differential checking to identify inconsistent security operations +(e.g., checks or kfrees) between two code paths and confirms that the +inconsistent operations are not recovered in the current function or +the callers, so they constitute bugs. + +Note that, as a bug found by static analysis, it can be a false +positive or hard to trigger. Multiple researchers have cross-reviewed +the bug. + +Builds with CONFIG_ATH11K=m show no new warnings, and our static +analyzer no longer warns about this code. + +Fixes: d5c65159f289 ("ath11k: driver for Qualcomm IEEE 802.11ax devices") +Signed-off-by: Zhou Qingyang +Signed-off-by: Kalle Valo +Link: https://lore.kernel.org/r/20211202155348.71315-1-zhou1615@umn.edu +--- + drivers/net/wireless/ath/ath11k/mac.c | 7 +++++-- + 1 file changed, 5 insertions(+), 2 deletions(-) + +--- a/drivers/net/wireless/ath/ath11k/mac.c ++++ b/drivers/net/wireless/ath/ath11k/mac.c +@@ -3520,9 +3520,12 @@ static int ath11k_mac_op_hw_scan(struct + arg.scan_id = ATH11K_SCAN_ID; + + if (req->ie_len) { ++ arg.extraie.ptr = kmemdup(req->ie, req->ie_len, GFP_KERNEL); ++ if (!arg.extraie.ptr) { ++ ret = -ENOMEM; ++ goto exit; ++ } + arg.extraie.len = req->ie_len; +- arg.extraie.ptr = kzalloc(req->ie_len, GFP_KERNEL); +- memcpy(arg.extraie.ptr, req->ie, req->ie_len); + } + + if (req->n_ssids) { diff --git a/package/kernel/mac80211/patches/ath11k/0140-ath11k-add-ab-to-TARGET_NUM_VDEVS-co.patch b/package/kernel/mac80211/patches/ath11k/0140-ath11k-add-ab-to-TARGET_NUM_VDEVS-co.patch new file mode 100644 index 000000000..750ec81e3 --- /dev/null +++ b/package/kernel/mac80211/patches/ath11k/0140-ath11k-add-ab-to-TARGET_NUM_VDEVS-co.patch @@ -0,0 +1,130 @@ +From 523aafd0f071c5f9e951a861c30531c1eeb01ad4 Mon Sep 17 00:00:00 2001 +From: Kalle Valo +Date: Mon, 13 Dec 2021 11:53:08 +0200 +Subject: [PATCH] ath11k: add ab to TARGET_NUM_VDEVS & co + +The next patch changes TARGET_NUM_VDEVS to be dynamic and need access to ab. +Add ab separately to keep the next patch simple. + +Compile tested only. + +Signed-off-by: Kalle Valo +Link: https://lore.kernel.org/r/20211209104351.9811-2-kvalo@kernel.org +--- + drivers/net/wireless/ath/ath11k/core.c | 2 +- + drivers/net/wireless/ath/ath11k/hw.c | 14 +++++++------- + drivers/net/wireless/ath/ath11k/hw.h | 18 +++++++++--------- + drivers/net/wireless/ath/ath11k/mac.c | 10 +++++----- + 4 files changed, 22 insertions(+), 22 deletions(-) + +--- a/drivers/net/wireless/ath/ath11k/core.c ++++ b/drivers/net/wireless/ath/ath11k/core.c +@@ -1067,7 +1067,7 @@ static int ath11k_core_reconfigure_on_cr + ath11k_dp_free(ab); + ath11k_hal_srng_deinit(ab); + +- ab->free_vdev_map = (1LL << (ab->num_radios * TARGET_NUM_VDEVS)) - 1; ++ ab->free_vdev_map = (1LL << (ab->num_radios * TARGET_NUM_VDEVS(ab))) - 1; + + ret = ath11k_hal_srng_init(ab); + if (ret) +--- a/drivers/net/wireless/ath/ath11k/hw.c ++++ b/drivers/net/wireless/ath/ath11k/hw.c +@@ -150,18 +150,18 @@ static void ath11k_hw_ipq8074_reo_setup( + static void ath11k_init_wmi_config_ipq8074(struct ath11k_base *ab, + struct target_resource_config *config) + { +- config->num_vdevs = ab->num_radios * TARGET_NUM_VDEVS; ++ config->num_vdevs = ab->num_radios * TARGET_NUM_VDEVS(ab); + + if (ab->num_radios == 2) { +- config->num_peers = TARGET_NUM_PEERS(DBS); +- config->num_tids = TARGET_NUM_TIDS(DBS); ++ config->num_peers = TARGET_NUM_PEERS(ab, DBS); ++ config->num_tids = TARGET_NUM_TIDS(ab, DBS); + } else if (ab->num_radios == 3) { +- config->num_peers = TARGET_NUM_PEERS(DBS_SBS); +- config->num_tids = TARGET_NUM_TIDS(DBS_SBS); ++ config->num_peers = TARGET_NUM_PEERS(ab, DBS_SBS); ++ config->num_tids = TARGET_NUM_TIDS(ab, DBS_SBS); + } else { + /* Control should not reach here */ +- config->num_peers = TARGET_NUM_PEERS(SINGLE); +- config->num_tids = TARGET_NUM_TIDS(SINGLE); ++ config->num_peers = TARGET_NUM_PEERS(ab, SINGLE); ++ config->num_tids = TARGET_NUM_TIDS(ab, SINGLE); + } + config->num_offload_peers = TARGET_NUM_OFFLD_PEERS; + config->num_offload_reorder_buffs = TARGET_NUM_OFFLD_REORDER_BUFFS; +--- a/drivers/net/wireless/ath/ath11k/hw.h ++++ b/drivers/net/wireless/ath/ath11k/hw.h +@@ -12,26 +12,26 @@ + /* Target configuration defines */ + + /* Num VDEVS per radio */ +-#define TARGET_NUM_VDEVS (16 + 1) ++#define TARGET_NUM_VDEVS(ab) (16 + 1) + +-#define TARGET_NUM_PEERS_PDEV (512 + TARGET_NUM_VDEVS) ++#define TARGET_NUM_PEERS_PDEV(ab) (512 + TARGET_NUM_VDEVS(ab)) + + /* Num of peers for Single Radio mode */ +-#define TARGET_NUM_PEERS_SINGLE (TARGET_NUM_PEERS_PDEV) ++#define TARGET_NUM_PEERS_SINGLE(ab) (TARGET_NUM_PEERS_PDEV(ab)) + + /* Num of peers for DBS */ +-#define TARGET_NUM_PEERS_DBS (2 * TARGET_NUM_PEERS_PDEV) ++#define TARGET_NUM_PEERS_DBS(ab) (2 * TARGET_NUM_PEERS_PDEV(ab)) + + /* Num of peers for DBS_SBS */ +-#define TARGET_NUM_PEERS_DBS_SBS (3 * TARGET_NUM_PEERS_PDEV) ++#define TARGET_NUM_PEERS_DBS_SBS(ab) (3 * TARGET_NUM_PEERS_PDEV(ab)) + + /* Max num of stations (per radio) */ +-#define TARGET_NUM_STATIONS 512 ++#define TARGET_NUM_STATIONS(ab) 512 + +-#define TARGET_NUM_PEERS(x) TARGET_NUM_PEERS_##x ++#define TARGET_NUM_PEERS(ab, x) TARGET_NUM_PEERS_##x(ab) + #define TARGET_NUM_PEER_KEYS 2 +-#define TARGET_NUM_TIDS(x) (2 * TARGET_NUM_PEERS(x) + \ +- 4 * TARGET_NUM_VDEVS + 8) ++#define TARGET_NUM_TIDS(ab, x) (2 * TARGET_NUM_PEERS(ab, x) + \ ++ 4 * TARGET_NUM_VDEVS(ab) + 8) + + #define TARGET_AST_SKID_LIMIT 16 + #define TARGET_NUM_OFFLD_PEERS 4 +--- a/drivers/net/wireless/ath/ath11k/mac.c ++++ b/drivers/net/wireless/ath/ath11k/mac.c +@@ -6004,9 +6004,9 @@ static int ath11k_mac_op_add_interface(s + goto err; + } + +- if (ar->num_created_vdevs > (TARGET_NUM_VDEVS - 1)) { ++ if (ar->num_created_vdevs > (TARGET_NUM_VDEVS(ab) - 1)) { + ath11k_warn(ab, "failed to create vdev %u, reached max vdev limit %d\n", +- ar->num_created_vdevs, TARGET_NUM_VDEVS); ++ ar->num_created_vdevs, TARGET_NUM_VDEVS(ab)); + ret = -EBUSY; + goto err; + } +@@ -8202,8 +8202,8 @@ static int __ath11k_mac_register(struct + ar->hw->wiphy->features |= NL80211_FEATURE_AP_MODE_CHAN_WIDTH_CHANGE | + NL80211_FEATURE_AP_SCAN; + +- ar->max_num_stations = TARGET_NUM_STATIONS; +- ar->max_num_peers = TARGET_NUM_PEERS_PDEV; ++ ar->max_num_stations = TARGET_NUM_STATIONS(ab); ++ ar->max_num_peers = TARGET_NUM_PEERS_PDEV(ab); + + ar->hw->wiphy->max_ap_assoc_sta = ar->max_num_stations; + +@@ -8306,7 +8306,7 @@ int ath11k_mac_register(struct ath11k_ba + + /* Initialize channel counters frequency value in hertz */ + ab->cc_freq_hz = IPQ8074_CC_FREQ_HERTZ; +- ab->free_vdev_map = (1LL << (ab->num_radios * TARGET_NUM_VDEVS)) - 1; ++ ab->free_vdev_map = (1LL << (ab->num_radios * TARGET_NUM_VDEVS(ab))) - 1; + + for (i = 0; i < ab->num_radios; i++) { + pdev = &ab->pdevs[i]; diff --git a/package/kernel/mac80211/patches/ath11k/0141-ath11k-Change-qcn9074-fw-to-operate-in-mode-2.patch b/package/kernel/mac80211/patches/ath11k/0141-ath11k-Change-qcn9074-fw-to-operate-in-mode-2.patch new file mode 100644 index 000000000..7d9f0cd76 --- /dev/null +++ b/package/kernel/mac80211/patches/ath11k/0141-ath11k-Change-qcn9074-fw-to-operate-in-mode-2.patch @@ -0,0 +1,139 @@ +From beefee71336bfb406c3e37a0de8a12881424e78c Mon Sep 17 00:00:00 2001 +From: Seevalamuthu Mariappan +Date: Mon, 13 Dec 2021 11:53:08 +0200 +Subject: [PATCH] ath11k: Change qcn9074 fw to operate in mode-2 + +In mode-2 QCN9074 firmware uses 15MB of host memory and firmware +request 1MB size segements in QMI, whereas in mode-0 firmware +uses 45MB of host memory and each segment is of 2MB size. +In mode-2 firmware operates with reduced number of vdevs and peers. + +Tested-on: QCN9074 hw1.0 PCI WLAN.HK.2.4.0.1-01838-QCAHKSWPL_SILICONZ-1 + +Signed-off-by: Seevalamuthu Mariappan +Signed-off-by: Anilkumar Kolli +Signed-off-by: Kalle Valo +Link: https://lore.kernel.org/r/20211209104351.9811-3-kvalo@kernel.org +--- + drivers/net/wireless/ath/ath11k/core.c | 18 ++++++++++++++++++ + drivers/net/wireless/ath/ath11k/hw.h | 9 ++++++--- + drivers/net/wireless/ath/ath11k/qmi.c | 2 +- + drivers/net/wireless/ath/ath11k/qmi.h | 1 - + 4 files changed, 25 insertions(+), 5 deletions(-) + +--- a/drivers/net/wireless/ath/ath11k/core.c ++++ b/drivers/net/wireless/ath/ath11k/core.c +@@ -79,6 +79,9 @@ static const struct ath11k_hw_params ath + .idle_ps = false, + .supports_sta_ps = false, + .cold_boot_calib = true, ++ .fw_mem_mode = 0, ++ .num_vdevs = 16 + 1, ++ .num_peers = 512, + .supports_suspend = false, + .hal_desc_sz = sizeof(struct hal_rx_desc_ipq8074), + .fix_l1ss = true, +@@ -134,6 +137,9 @@ static const struct ath11k_hw_params ath + .idle_ps = false, + .supports_sta_ps = false, + .cold_boot_calib = true, ++ .fw_mem_mode = 0, ++ .num_vdevs = 16 + 1, ++ .num_peers = 512, + .supports_suspend = false, + .hal_desc_sz = sizeof(struct hal_rx_desc_ipq8074), + .fix_l1ss = true, +@@ -188,6 +194,9 @@ static const struct ath11k_hw_params ath + .idle_ps = true, + .supports_sta_ps = true, + .cold_boot_calib = false, ++ .fw_mem_mode = 0, ++ .num_vdevs = 16 + 1, ++ .num_peers = 512, + .supports_suspend = true, + .hal_desc_sz = sizeof(struct hal_rx_desc_ipq8074), + .fix_l1ss = true, +@@ -242,6 +251,9 @@ static const struct ath11k_hw_params ath + .idle_ps = false, + .supports_sta_ps = false, + .cold_boot_calib = false, ++ .fw_mem_mode = 2, ++ .num_vdevs = 8, ++ .num_peers = 128, + .supports_suspend = false, + .hal_desc_sz = sizeof(struct hal_rx_desc_qcn9074), + .fix_l1ss = true, +@@ -296,6 +308,9 @@ static const struct ath11k_hw_params ath + .idle_ps = true, + .supports_sta_ps = true, + .cold_boot_calib = false, ++ .fw_mem_mode = 0, ++ .num_vdevs = 16 + 1, ++ .num_peers = 512, + .supports_suspend = true, + .hal_desc_sz = sizeof(struct hal_rx_desc_wcn6855), + .fix_l1ss = false, +@@ -349,6 +364,9 @@ static const struct ath11k_hw_params ath + .idle_ps = true, + .supports_sta_ps = true, + .cold_boot_calib = false, ++ .fw_mem_mode = 0, ++ .num_vdevs = 16 + 1, ++ .num_peers = 512, + .supports_suspend = true, + .hal_desc_sz = sizeof(struct hal_rx_desc_wcn6855), + .fix_l1ss = false, +--- a/drivers/net/wireless/ath/ath11k/hw.h ++++ b/drivers/net/wireless/ath/ath11k/hw.h +@@ -12,9 +12,9 @@ + /* Target configuration defines */ + + /* Num VDEVS per radio */ +-#define TARGET_NUM_VDEVS(ab) (16 + 1) ++#define TARGET_NUM_VDEVS(ab) (ab->hw_params.num_vdevs) + +-#define TARGET_NUM_PEERS_PDEV(ab) (512 + TARGET_NUM_VDEVS(ab)) ++#define TARGET_NUM_PEERS_PDEV(ab) (ab->hw_params.num_peers + TARGET_NUM_VDEVS(ab)) + + /* Num of peers for Single Radio mode */ + #define TARGET_NUM_PEERS_SINGLE(ab) (TARGET_NUM_PEERS_PDEV(ab)) +@@ -26,7 +26,7 @@ + #define TARGET_NUM_PEERS_DBS_SBS(ab) (3 * TARGET_NUM_PEERS_PDEV(ab)) + + /* Max num of stations (per radio) */ +-#define TARGET_NUM_STATIONS(ab) 512 ++#define TARGET_NUM_STATIONS(ab) (ab->hw_params.num_peers) + + #define TARGET_NUM_PEERS(ab, x) TARGET_NUM_PEERS_##x(ab) + #define TARGET_NUM_PEER_KEYS 2 +@@ -173,6 +173,9 @@ struct ath11k_hw_params { + bool idle_ps; + bool supports_sta_ps; + bool cold_boot_calib; ++ int fw_mem_mode; ++ u32 num_vdevs; ++ u32 num_peers; + bool supports_suspend; + u32 hal_desc_sz; + bool fix_l1ss; +--- a/drivers/net/wireless/ath/ath11k/qmi.c ++++ b/drivers/net/wireless/ath/ath11k/qmi.c +@@ -2830,7 +2830,7 @@ int ath11k_qmi_init_service(struct ath11 + memset(&ab->qmi.target_mem, 0, sizeof(struct target_mem_chunk)); + ab->qmi.ab = ab; + +- ab->qmi.target_mem_mode = ATH11K_QMI_TARGET_MEM_MODE_DEFAULT; ++ ab->qmi.target_mem_mode = ab->hw_params.fw_mem_mode; + ret = qmi_handle_init(&ab->qmi.handle, ATH11K_QMI_RESP_LEN_MAX, + &ath11k_qmi_ops, ath11k_qmi_msg_handlers); + if (ret < 0) { +--- a/drivers/net/wireless/ath/ath11k/qmi.h ++++ b/drivers/net/wireless/ath/ath11k/qmi.h +@@ -34,7 +34,6 @@ + + #define QMI_WLANFW_MAX_DATA_SIZE_V01 6144 + #define ATH11K_FIRMWARE_MODE_OFF 4 +-#define ATH11K_QMI_TARGET_MEM_MODE_DEFAULT 0 + #define ATH11K_COLD_BOOT_FW_RESET_DELAY (40 * HZ) + + struct ath11k_base; diff --git a/package/kernel/mac80211/patches/ath11k/0142-ath11k-Use-reserved-host-DDR-addresses-from-DT-for-P.patch b/package/kernel/mac80211/patches/ath11k/0142-ath11k-Use-reserved-host-DDR-addresses-from-DT-for-P.patch new file mode 100644 index 000000000..d6559dd73 --- /dev/null +++ b/package/kernel/mac80211/patches/ath11k/0142-ath11k-Use-reserved-host-DDR-addresses-from-DT-for-P.patch @@ -0,0 +1,254 @@ +From 6ac04bdc5edb418787ab2040b1f922c23464c750 Mon Sep 17 00:00:00 2001 +From: Anilkumar Kolli +Date: Tue, 14 Dec 2021 17:39:43 +0200 +Subject: [PATCH] ath11k: Use reserved host DDR addresses from DT for PCI + devices + +Host DDR memory (contiguous 45 MB in mode-0 or 15 MB in mode-2) +is reserved through DT entries for firmware usage. Send the base +address from DT entries. +If DT entry is available, PCI device will work with +fixed_mem_region else host allocates multiple segments. + +IPQ8074 on HK10 board supports multiple PCI devices. +IPQ8074 + QCN9074 is tested with this patch. + +Tested-on: QCN9074 hw1.0 PCI WLAN.HK.2.4.0.1-01838-QCAHKSWPL_SILICONZ-1 + +Signed-off-by: Anilkumar Kolli +Signed-off-by: Kalle Valo +Link: https://lore.kernel.org/r/1638789319-2950-2-git-send-email-akolli@codeaurora.org +--- + drivers/net/wireless/ath/ath11k/core.h | 1 + + drivers/net/wireless/ath/ath11k/mhi.c | 34 ++++++++++++- + drivers/net/wireless/ath/ath11k/pci.c | 11 ++++- + drivers/net/wireless/ath/ath11k/qmi.c | 67 ++++++++++++++++++++++---- + drivers/net/wireless/ath/ath11k/qmi.h | 1 + + 5 files changed, 101 insertions(+), 13 deletions(-) + +--- a/drivers/net/wireless/ath/ath11k/core.h ++++ b/drivers/net/wireless/ath/ath11k/core.h +@@ -202,6 +202,7 @@ enum ath11k_dev_flags { + ATH11K_FLAG_HTC_SUSPEND_COMPLETE, + ATH11K_FLAG_CE_IRQ_ENABLED, + ATH11K_FLAG_EXT_IRQ_ENABLED, ++ ATH11K_FLAG_FIXED_MEM_RGN, + }; + + enum ath11k_monitor_flags { +--- a/drivers/net/wireless/ath/ath11k/mhi.c ++++ b/drivers/net/wireless/ath/ath11k/mhi.c +@@ -3,6 +3,9 @@ + + #include + #include ++#include ++#include ++#include + + #include "core.h" + #include "debug.h" +@@ -318,6 +321,26 @@ static void ath11k_mhi_op_write_reg(stru + writel(val, addr); + } + ++static int ath11k_mhi_read_addr_from_dt(struct mhi_controller *mhi_ctrl) ++{ ++ struct device_node *np; ++ struct resource res; ++ int ret; ++ ++ np = of_find_node_by_type(NULL, "memory"); ++ if (!np) ++ return -ENOENT; ++ ++ ret = of_address_to_resource(np, 0, &res); ++ if (ret) ++ return ret; ++ ++ mhi_ctrl->iova_start = res.start + 0x1000000; ++ mhi_ctrl->iova_stop = res.end; ++ ++ return 0; ++} ++ + int ath11k_mhi_register(struct ath11k_pci *ab_pci) + { + struct ath11k_base *ab = ab_pci->ab; +@@ -351,8 +374,15 @@ int ath11k_mhi_register(struct ath11k_pc + if (!test_bit(ATH11K_PCI_FLAG_MULTI_MSI_VECTORS, &ab_pci->flags)) + mhi_ctrl->irq_flags = IRQF_SHARED | IRQF_NOBALANCING; + +- mhi_ctrl->iova_start = 0; +- mhi_ctrl->iova_stop = 0xffffffff; ++ if (test_bit(ATH11K_FLAG_FIXED_MEM_RGN, &ab->dev_flags)) { ++ ret = ath11k_mhi_read_addr_from_dt(mhi_ctrl); ++ if (ret < 0) ++ return ret; ++ } else { ++ mhi_ctrl->iova_start = 0; ++ mhi_ctrl->iova_stop = 0xFFFFFFFF; ++ } ++ + mhi_ctrl->sbl_size = SZ_512K; + mhi_ctrl->seg_len = SZ_512K; + mhi_ctrl->fbc_download = true; +--- a/drivers/net/wireless/ath/ath11k/pci.c ++++ b/drivers/net/wireless/ath/ath11k/pci.c +@@ -6,6 +6,7 @@ + #include + #include + #include ++#include + + #include "pci.h" + #include "core.h" +@@ -1347,7 +1348,7 @@ static int ath11k_pci_probe(struct pci_d + { + struct ath11k_base *ab; + struct ath11k_pci *ab_pci; +- u32 soc_hw_version_major, soc_hw_version_minor; ++ u32 soc_hw_version_major, soc_hw_version_minor, addr; + int ret; + + ab = ath11k_core_alloc(&pdev->dev, sizeof(*ab_pci), ATH11K_BUS_PCI, +@@ -1367,6 +1368,14 @@ static int ath11k_pci_probe(struct pci_d + pci_set_drvdata(pdev, ab); + spin_lock_init(&ab_pci->window_lock); + ++ /* Set fixed_mem_region to true for platforms support reserved memory ++ * from DT. If memory is reserved from DT for FW, ath11k driver need not ++ * allocate memory. ++ */ ++ ret = of_property_read_u32(ab->dev->of_node, "memory-region", &addr); ++ if (!ret) ++ set_bit(ATH11K_FLAG_FIXED_MEM_RGN, &ab->dev_flags); ++ + ret = ath11k_pci_claim(ab_pci, pdev); + if (ret) { + ath11k_err(ab, "failed to claim device: %d\n", ret); +--- a/drivers/net/wireless/ath/ath11k/qmi.c ++++ b/drivers/net/wireless/ath/ath11k/qmi.c +@@ -9,6 +9,8 @@ + #include "core.h" + #include "debug.h" + #include ++#include ++#include + #include + + #define SLEEP_CLOCK_SELECT_INTERNAL_BIT 0x02 +@@ -1751,7 +1753,9 @@ static int ath11k_qmi_respond_fw_mem_req + * failure to FW and FW will then request mulitple blocks of small + * chunk size memory. + */ +- if (!ab->bus_params.fixed_mem_region && ab->qmi.target_mem_delayed) { ++ if (!(ab->bus_params.fixed_mem_region || ++ test_bit(ATH11K_FLAG_FIXED_MEM_RGN, &ab->dev_flags)) && ++ ab->qmi.target_mem_delayed) { + delayed = true; + ath11k_dbg(ab, ATH11K_DBG_QMI, "qmi delays mem_request %d\n", + ab->qmi.mem_seg_count); +@@ -1818,10 +1822,12 @@ static void ath11k_qmi_free_target_mem_c + { + int i; + +- if (ab->bus_params.fixed_mem_region) +- return; +- + for (i = 0; i < ab->qmi.mem_seg_count; i++) { ++ if ((ab->bus_params.fixed_mem_region || ++ test_bit(ATH11K_FLAG_FIXED_MEM_RGN, &ab->dev_flags)) && ++ ab->qmi.target_mem[i].iaddr) ++ iounmap(ab->qmi.target_mem[i].iaddr); ++ + if (!ab->qmi.target_mem[i].vaddr) + continue; + +@@ -1869,10 +1875,44 @@ static int ath11k_qmi_alloc_target_mem_c + + static int ath11k_qmi_assign_target_mem_chunk(struct ath11k_base *ab) + { +- int i, idx; ++ struct device *dev = ab->dev; ++ struct device_node *hremote_node = NULL; ++ struct resource res; ++ u32 host_ddr_sz; ++ int i, idx, ret; + + for (i = 0, idx = 0; i < ab->qmi.mem_seg_count; i++) { + switch (ab->qmi.target_mem[i].type) { ++ case HOST_DDR_REGION_TYPE: ++ hremote_node = of_parse_phandle(dev->of_node, "memory-region", 0); ++ if (!hremote_node) { ++ ath11k_dbg(ab, ATH11K_DBG_QMI, ++ "qmi fail to get hremote_node\n"); ++ return ret; ++ } ++ ++ ret = of_address_to_resource(hremote_node, 0, &res); ++ if (ret) { ++ ath11k_dbg(ab, ATH11K_DBG_QMI, ++ "qmi fail to get reg from hremote\n"); ++ return ret; ++ } ++ ++ if (res.end - res.start + 1 < ab->qmi.target_mem[i].size) { ++ ath11k_dbg(ab, ATH11K_DBG_QMI, ++ "qmi fail to assign memory of sz\n"); ++ return -EINVAL; ++ } ++ ++ ab->qmi.target_mem[idx].paddr = res.start; ++ ab->qmi.target_mem[idx].iaddr = ++ ioremap(ab->qmi.target_mem[idx].paddr, ++ ab->qmi.target_mem[i].size); ++ ab->qmi.target_mem[idx].size = ab->qmi.target_mem[i].size; ++ host_ddr_sz = ab->qmi.target_mem[i].size; ++ ab->qmi.target_mem[idx].type = ab->qmi.target_mem[i].type; ++ idx++; ++ break; + case BDF_MEM_REGION_TYPE: + ab->qmi.target_mem[idx].paddr = ab->hw_params.bdf_addr; + ab->qmi.target_mem[idx].vaddr = NULL; +@@ -1887,10 +1927,16 @@ static int ath11k_qmi_assign_target_mem_ + } + + if (ath11k_cold_boot_cal && ab->hw_params.cold_boot_calib) { +- ab->qmi.target_mem[idx].paddr = +- ATH11K_QMI_CALDB_ADDRESS; +- ab->qmi.target_mem[idx].vaddr = +- (void *)ATH11K_QMI_CALDB_ADDRESS; ++ if (hremote_node) { ++ ab->qmi.target_mem[idx].paddr = ++ res.start + host_ddr_sz; ++ ab->qmi.target_mem[idx].iaddr = ++ ioremap(ab->qmi.target_mem[idx].paddr, ++ ab->qmi.target_mem[i].size); ++ } else { ++ ab->qmi.target_mem[idx].paddr = ++ ATH11K_QMI_CALDB_ADDRESS; ++ } + } else { + ab->qmi.target_mem[idx].paddr = 0; + ab->qmi.target_mem[idx].vaddr = NULL; +@@ -2621,7 +2667,8 @@ static void ath11k_qmi_msg_mem_request_c + msg->mem_seg[i].type, msg->mem_seg[i].size); + } + +- if (ab->bus_params.fixed_mem_region) { ++ if (ab->bus_params.fixed_mem_region || ++ test_bit(ATH11K_FLAG_FIXED_MEM_RGN, &ab->dev_flags)) { + ret = ath11k_qmi_assign_target_mem_chunk(ab); + if (ret) { + ath11k_warn(ab, "failed to assign qmi target memory: %d\n", +--- a/drivers/net/wireless/ath/ath11k/qmi.h ++++ b/drivers/net/wireless/ath/ath11k/qmi.h +@@ -94,6 +94,7 @@ struct target_mem_chunk { + u32 type; + dma_addr_t paddr; + u32 *vaddr; ++ void __iomem *iaddr; + }; + + struct target_info { diff --git a/package/kernel/mac80211/patches/ath11k/0143-ath11k-report-rssi-of-each-chain-to-mac80211-for-QCA.patch b/package/kernel/mac80211/patches/ath11k/0143-ath11k-report-rssi-of-each-chain-to-mac80211-for-QCA.patch new file mode 100644 index 000000000..a912c7d72 --- /dev/null +++ b/package/kernel/mac80211/patches/ath11k/0143-ath11k-report-rssi-of-each-chain-to-mac80211-for-QCA.patch @@ -0,0 +1,654 @@ +From b488c766442f7d9c07ea0708aa2a1a6bff1baef5 Mon Sep 17 00:00:00 2001 +From: Wen Gong +Date: Fri, 17 Dec 2021 20:27:21 +0200 +Subject: [PATCH 143/151] ath11k: report rssi of each chain to mac80211 for + QCA6390/WCN6855 + +Command "iw wls1 station dump" does not show each chain's rssi currently. + +If the rssi of each chain from mon status which parsed in function +ath11k_hal_rx_parse_mon_status_tlv() is invalid, then ath11k send +wmi cmd WMI_REQUEST_STATS_CMDID with flag WMI_REQUEST_RSSI_PER_CHAIN_STAT +to firmware, and parse the rssi of chain in wmi WMI_UPDATE_STATS_EVENTID, +then report them to mac80211. + +WMI_REQUEST_STATS_CMDID is only sent when CONFIG_ATH11K_DEBUGFS is set, +it is only called by ath11k_mac_op_sta_statistics(). It does not effect +performance and power consumption. Because after STATION connected to +AP, it is only called every 6 seconds by NetworkManager in below stack. + +[ 797.005587] CPU: 0 PID: 701 Comm: NetworkManager Tainted: G W OE 5.13.0-rc6-wt-ath+ #2 +[ 797.005596] Hardware name: LENOVO 418065C/418065C, BIOS 83ET63WW (1.33 ) 07/29/2011 +[ 797.005600] RIP: 0010:ath11k_mac_op_sta_statistics+0x2f/0x1b0 [ath11k] +[ 797.005644] Code: 41 56 41 55 4c 8d aa 58 01 00 00 41 54 55 48 89 d5 53 48 8b 82 58 01 00 00 48 89 cb 4c 8b 70 20 49 8b 06 4c 8b a0 90 08 00 00 <0f> 0b 48 8b 82 b8 01 00 00 48 ba 00 00 00 00 01 00 00 00 48 89 81 +[ 797.005651] RSP: 0018:ffffb1fc80a4b890 EFLAGS: 00010282 +[ 797.005658] RAX: ffff8a5726200000 RBX: ffffb1fc80a4b958 RCX: ffffb1fc80a4b958 +[ 797.005664] RDX: ffff8a5726a609f0 RSI: ffff8a581247f598 RDI: ffff8a5702878800 +[ 797.005668] RBP: ffff8a5726a609f0 R08: 0000000000000000 R09: 0000000000000000 +[ 797.005672] R10: 0000000000000000 R11: 0000000000000007 R12: 02dd68024f75f480 +[ 797.005676] R13: ffff8a5726a60b48 R14: ffff8a5702879f40 R15: ffff8a5726a60000 +[ 797.005681] FS: 00007f632c52a380(0000) GS:ffff8a583a200000(0000) knlGS:0000000000000000 +[ 797.005687] CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033 +[ 797.005692] CR2: 00007fb025d69000 CR3: 00000001124f6005 CR4: 00000000000606f0 +[ 797.005698] Call Trace: +[ 797.005710] sta_set_sinfo+0xa7/0xb80 [mac80211] +[ 797.005820] ieee80211_get_station+0x50/0x70 [mac80211] +[ 797.005925] nl80211_get_station+0xd1/0x200 [cfg80211] +[ 797.006045] genl_family_rcv_msg_doit.isra.15+0x111/0x140 +[ 797.006059] genl_rcv_msg+0xe6/0x1e0 +[ 797.006065] ? nl80211_dump_station+0x220/0x220 [cfg80211] +[ 797.006223] ? nl80211_send_station.isra.72+0xf50/0xf50 [cfg80211] +[ 797.006348] ? genl_family_rcv_msg_doit.isra.15+0x140/0x140 +[ 797.006355] netlink_rcv_skb+0xb9/0xf0 +[ 797.006363] genl_rcv+0x24/0x40 +[ 797.006369] netlink_unicast+0x18e/0x290 +[ 797.006375] netlink_sendmsg+0x30f/0x450 +[ 797.006382] sock_sendmsg+0x5b/0x60 +[ 797.006393] ____sys_sendmsg+0x219/0x240 +[ 797.006403] ? copy_msghdr_from_user+0x5c/0x90 +[ 797.006413] ? ____sys_recvmsg+0xf5/0x190 +[ 797.006422] ___sys_sendmsg+0x88/0xd0 +[ 797.006432] ? copy_msghdr_from_user+0x5c/0x90 +[ 797.006443] ? ___sys_recvmsg+0x9e/0xd0 +[ 797.006454] ? __fget_files+0x58/0x90 +[ 797.006461] ? __fget_light+0x2d/0x70 +[ 797.006466] ? do_epoll_wait+0xce/0x720 +[ 797.006476] ? __sys_sendmsg+0x63/0xa0 +[ 797.006485] __sys_sendmsg+0x63/0xa0 +[ 797.006497] do_syscall_64+0x3c/0xb0 +[ 797.006509] entry_SYSCALL_64_after_hwframe+0x44/0xae +[ 797.006519] RIP: 0033:0x7f632d99912d +[ 797.006526] Code: 28 89 54 24 1c 48 89 74 24 10 89 7c 24 08 e8 ca ee ff ff 8b 54 24 1c 48 8b 74 24 10 41 89 c0 8b 7c 24 08 b8 2e 00 00 00 0f 05 <48> 3d 00 f0 ff ff 77 2f 44 89 c7 48 89 44 24 08 e8 fe ee ff ff 48 +[ 797.006533] RSP: 002b:00007ffd80808c00 EFLAGS: 00000293 ORIG_RAX: 000000000000002e +[ 797.006540] RAX: ffffffffffffffda RBX: 0000563dab99d840 RCX: 00007f632d99912d +[ 797.006545] RDX: 0000000000000000 RSI: 00007ffd80808c50 RDI: 000000000000000b +[ 797.006549] RBP: 00007ffd80808c50 R08: 0000000000000000 R09: 0000000000001000 +[ 797.006552] R10: 0000563dab96f010 R11: 0000000000000293 R12: 0000563dab99d840 +[ 797.006556] R13: 0000563dabbb28c0 R14: 00007f632dad4280 R15: 0000563dabab11c0 +[ 797.006563] ---[ end trace c9dcf08920c9945c ]--- + +Tested-on: QCA6390 hw2.0 PCI WLAN.HST.1.0.1-01230-QCAHSTSWPLZ_V2_TO_X86-1 +Tested-on: WCN6855 hw2.0 PCI WLAN.HSP.1.1-02892.1-QCAHSPSWPL_V1_V2_SILICONZ_LITE-1 + +Signed-off-by: Wen Gong +Signed-off-by: Kalle Valo +Link: https://lore.kernel.org/r/20211215090944.19729-1-quic_wgong@quicinc.com +--- + drivers/net/wireless/ath/ath11k/core.c | 6 + + drivers/net/wireless/ath/ath11k/core.h | 5 + + drivers/net/wireless/ath/ath11k/debugfs.c | 37 +++++ + drivers/net/wireless/ath/ath11k/debugfs.h | 8 + + drivers/net/wireless/ath/ath11k/dp_rx.c | 8 + + drivers/net/wireless/ath/ath11k/hal_rx.c | 11 ++ + drivers/net/wireless/ath/ath11k/hal_rx.h | 12 +- + drivers/net/wireless/ath/ath11k/hw.h | 1 + + drivers/net/wireless/ath/ath11k/mac.c | 40 +++++ + drivers/net/wireless/ath/ath11k/wmi.c | 179 ++++++++++++++++++---- + drivers/net/wireless/ath/ath11k/wmi.h | 11 ++ + 11 files changed, 284 insertions(+), 34 deletions(-) + +--- a/drivers/net/wireless/ath/ath11k/core.c ++++ b/drivers/net/wireless/ath/ath11k/core.c +@@ -91,6 +91,7 @@ static const struct ath11k_hw_params ath + .supports_dynamic_smps_6ghz = false, + .alloc_cacheable_memory = true, + .wakeup_mhi = false, ++ .supports_rssi_stats = false, + }, + { + .hw_rev = ATH11K_HW_IPQ6018_HW10, +@@ -149,6 +150,7 @@ static const struct ath11k_hw_params ath + .supports_dynamic_smps_6ghz = false, + .alloc_cacheable_memory = true, + .wakeup_mhi = false, ++ .supports_rssi_stats = false, + }, + { + .name = "qca6390 hw2.0", +@@ -206,6 +208,7 @@ static const struct ath11k_hw_params ath + .supports_dynamic_smps_6ghz = false, + .alloc_cacheable_memory = false, + .wakeup_mhi = true, ++ .supports_rssi_stats = true, + }, + { + .name = "qcn9074 hw1.0", +@@ -263,6 +266,7 @@ static const struct ath11k_hw_params ath + .supports_dynamic_smps_6ghz = true, + .alloc_cacheable_memory = true, + .wakeup_mhi = false, ++ .supports_rssi_stats = false, + }, + { + .name = "wcn6855 hw2.0", +@@ -320,6 +324,7 @@ static const struct ath11k_hw_params ath + .supports_dynamic_smps_6ghz = false, + .alloc_cacheable_memory = false, + .wakeup_mhi = true, ++ .supports_rssi_stats = true, + }, + { + .name = "wcn6855 hw2.1", +@@ -376,6 +381,7 @@ static const struct ath11k_hw_params ath + .supports_dynamic_smps_6ghz = false, + .alloc_cacheable_memory = false, + .wakeup_mhi = true, ++ .supports_rssi_stats = true, + }, + }; + +--- a/drivers/net/wireless/ath/ath11k/core.h ++++ b/drivers/net/wireless/ath/ath11k/core.h +@@ -386,6 +386,7 @@ struct ath11k_sta { + u64 rx_duration; + u64 tx_duration; + u8 rssi_comb; ++ s8 chain_signal[IEEE80211_MAX_CHAINS]; + struct ath11k_htt_tx_stats *tx_stats; + struct ath11k_rx_peer_stats *rx_stats; + +@@ -416,6 +417,10 @@ enum ath11k_state { + /* Antenna noise floor */ + #define ATH11K_DEFAULT_NOISE_FLOOR -95 + ++#define ATH11K_INVALID_RSSI_FULL -1 ++ ++#define ATH11K_INVALID_RSSI_EMPTY -128 ++ + struct ath11k_fw_stats { + struct dentry *debugfs_fwstats; + u32 pdev_id; +--- a/drivers/net/wireless/ath/ath11k/debugfs.c ++++ b/drivers/net/wireless/ath/ath11k/debugfs.c +@@ -126,6 +126,11 @@ void ath11k_debugfs_fw_stats_process(str + goto complete; + } + ++ if (stats.stats_id == WMI_REQUEST_RSSI_PER_CHAIN_STAT) { ++ ar->debug.fw_stats_done = true; ++ goto complete; ++ } ++ + if (stats.stats_id == WMI_REQUEST_VDEV_STAT) { + if (list_empty(&stats.vdevs)) { + ath11k_warn(ab, "empty vdev stats"); +@@ -229,6 +234,38 @@ static int ath11k_debugfs_fw_stats_reque + return 0; + } + ++int ath11k_debugfs_get_fw_stats(struct ath11k *ar, u32 pdev_id, ++ u32 vdev_id, u32 stats_id) ++{ ++ struct ath11k_base *ab = ar->ab; ++ struct stats_request_params req_param; ++ int ret; ++ ++ mutex_lock(&ar->conf_mutex); ++ ++ if (ar->state != ATH11K_STATE_ON) { ++ ret = -ENETDOWN; ++ goto err_unlock; ++ } ++ ++ req_param.pdev_id = pdev_id; ++ req_param.vdev_id = vdev_id; ++ req_param.stats_id = stats_id; ++ ++ ret = ath11k_debugfs_fw_stats_request(ar, &req_param); ++ if (ret) ++ ath11k_warn(ab, "failed to request fw stats: %d\n", ret); ++ ++ ath11k_dbg(ab, ATH11K_DBG_WMI, ++ "debug get fw stat pdev id %d vdev id %d stats id 0x%x\n", ++ pdev_id, vdev_id, stats_id); ++ ++err_unlock: ++ mutex_unlock(&ar->conf_mutex); ++ ++ return ret; ++} ++ + static int ath11k_open_pdev_stats(struct inode *inode, struct file *file) + { + struct ath11k *ar = inode->i_private; +--- a/drivers/net/wireless/ath/ath11k/debugfs.h ++++ b/drivers/net/wireless/ath/ath11k/debugfs.h +@@ -117,6 +117,8 @@ void ath11k_debugfs_unregister(struct at + void ath11k_debugfs_fw_stats_process(struct ath11k_base *ab, struct sk_buff *skb); + + void ath11k_debugfs_fw_stats_init(struct ath11k *ar); ++int ath11k_debugfs_get_fw_stats(struct ath11k *ar, u32 pdev_id, ++ u32 vdev_id, u32 stats_id); + + static inline bool ath11k_debugfs_is_pktlog_lite_mode_enabled(struct ath11k *ar) + { +@@ -215,6 +217,12 @@ static inline int ath11k_debugfs_rx_filt + { + return 0; + } ++ ++static inline int ath11k_debugfs_get_fw_stats(struct ath11k *ar, ++ u32 pdev_id, u32 vdev_id, u32 stats_id) ++{ ++ return 0; ++} + + #endif /* CPTCFG_MAC80211_DEBUGFS*/ + +--- a/drivers/net/wireless/ath/ath11k/dp_rx.c ++++ b/drivers/net/wireless/ath/ath11k/dp_rx.c +@@ -2768,6 +2768,7 @@ static void ath11k_dp_rx_update_peer_sta + { + struct ath11k_rx_peer_stats *rx_stats = arsta->rx_stats; + u32 num_msdu; ++ int i; + + if (!rx_stats) + return; +@@ -2829,6 +2830,13 @@ static void ath11k_dp_rx_update_peer_sta + rx_stats->ru_alloc_cnt[ppdu_info->ru_alloc] += num_msdu; + + arsta->rssi_comb = ppdu_info->rssi_comb; ++ ++ BUILD_BUG_ON(ARRAY_SIZE(arsta->chain_signal) > ++ ARRAY_SIZE(ppdu_info->rssi_chain_pri20)); ++ ++ for (i = 0; i < ARRAY_SIZE(arsta->chain_signal); i++) ++ arsta->chain_signal[i] = ppdu_info->rssi_chain_pri20[i]; ++ + rx_stats->rx_duration += ppdu_info->rx_duration; + arsta->rx_duration = rx_stats->rx_duration; + } +--- a/drivers/net/wireless/ath/ath11k/hal_rx.c ++++ b/drivers/net/wireless/ath/ath11k/hal_rx.c +@@ -1080,6 +1080,9 @@ ath11k_hal_rx_parse_mon_status_tlv(struc + break; + } + case HAL_PHYRX_RSSI_LEGACY: { ++ int i; ++ bool db2dbm = test_bit(WMI_TLV_SERVICE_HW_DB2DBM_CONVERSION_SUPPORT, ++ ab->wmi_ab.svc_map); + struct hal_rx_phyrx_rssi_legacy_info *rssi = + (struct hal_rx_phyrx_rssi_legacy_info *)tlv_data; + +@@ -1090,6 +1093,14 @@ ath11k_hal_rx_parse_mon_status_tlv(struc + ppdu_info->rssi_comb = + FIELD_GET(HAL_RX_PHYRX_RSSI_LEGACY_INFO_INFO1_RSSI_COMB, + __le32_to_cpu(rssi->info0)); ++ ++ if (db2dbm) { ++ for (i = 0; i < ARRAY_SIZE(rssi->preamble); i++) { ++ ppdu_info->rssi_chain_pri20[i] = ++ le32_get_bits(rssi->preamble[i].rssi_2040, ++ HAL_RX_PHYRX_RSSI_PREAMBLE_PRI20); ++ } ++ } + break; + } + case HAL_RX_MPDU_START: { +--- a/drivers/net/wireless/ath/ath11k/hal_rx.h ++++ b/drivers/net/wireless/ath/ath11k/hal_rx.h +@@ -112,6 +112,7 @@ struct hal_rx_mon_ppdu_info { + u8 ldpc; + u8 beamformed; + u8 rssi_comb; ++ u8 rssi_chain_pri20[HAL_RX_MAX_NSS]; + u8 tid; + u8 dcm; + u8 ru_alloc; +@@ -262,8 +263,17 @@ struct hal_rx_he_sig_b2_ofdma_info { + + #define HAL_RX_PHYRX_RSSI_LEGACY_INFO_INFO1_RSSI_COMB GENMASK(15, 8) + ++#define HAL_RX_PHYRX_RSSI_PREAMBLE_PRI20 GENMASK(7, 0) ++ ++struct hal_rx_phyrx_chain_rssi { ++ __le32 rssi_2040; ++ __le32 rssi_80; ++} __packed; ++ + struct hal_rx_phyrx_rssi_legacy_info { +- __le32 rsvd[35]; ++ __le32 rsvd[3]; ++ struct hal_rx_phyrx_chain_rssi pre_rssi[HAL_RX_MAX_NSS]; ++ struct hal_rx_phyrx_chain_rssi preamble[HAL_RX_MAX_NSS]; + __le32 info0; + } __packed; + +--- a/drivers/net/wireless/ath/ath11k/hw.h ++++ b/drivers/net/wireless/ath/ath11k/hw.h +@@ -185,6 +185,7 @@ struct ath11k_hw_params { + bool supports_dynamic_smps_6ghz; + bool alloc_cacheable_memory; + bool wakeup_mhi; ++ bool supports_rssi_stats; + }; + + struct ath11k_hw_ops { +--- a/drivers/net/wireless/ath/ath11k/mac.c ++++ b/drivers/net/wireless/ath/ath11k/mac.c +@@ -7775,12 +7775,42 @@ exit: + return ret; + } + ++static void ath11k_mac_put_chain_rssi(struct station_info *sinfo, ++ struct ath11k_sta *arsta, ++ char *pre, ++ bool clear) ++{ ++ struct ath11k *ar = arsta->arvif->ar; ++ int i; ++ s8 rssi; ++ ++ for (i = 0; i < ARRAY_SIZE(sinfo->chain_signal); i++) { ++ sinfo->chains &= ~BIT(i); ++ rssi = arsta->chain_signal[i]; ++ if (clear) ++ arsta->chain_signal[i] = ATH11K_INVALID_RSSI_FULL; ++ ++ ath11k_dbg(ar->ab, ATH11K_DBG_MAC, ++ "mac sta statistics %s rssi[%d] %d\n", pre, i, rssi); ++ ++ if (rssi != ATH11K_DEFAULT_NOISE_FLOOR && ++ rssi != ATH11K_INVALID_RSSI_FULL && ++ rssi != ATH11K_INVALID_RSSI_EMPTY && ++ rssi != 0) { ++ sinfo->chain_signal[i] = rssi; ++ sinfo->chains |= BIT(i); ++ sinfo->filled |= BIT_ULL(NL80211_STA_INFO_CHAIN_SIGNAL); ++ } ++ } ++} ++ + static void ath11k_mac_op_sta_statistics(struct ieee80211_hw *hw, + struct ieee80211_vif *vif, + struct ieee80211_sta *sta, + struct station_info *sinfo) + { + struct ath11k_sta *arsta = (struct ath11k_sta *)sta->drv_priv; ++ struct ath11k *ar = arsta->arvif->ar; + + sinfo->rx_duration = arsta->rx_duration; + sinfo->filled |= BIT_ULL(NL80211_STA_INFO_RX_DURATION); +@@ -7803,6 +7833,16 @@ static void ath11k_mac_op_sta_statistics + sinfo->filled |= BIT_ULL(NL80211_STA_INFO_TX_BITRATE); + } + ++ ath11k_mac_put_chain_rssi(sinfo, arsta, "ppdu", false); ++ ++ if (!(sinfo->filled & BIT_ULL(NL80211_STA_INFO_CHAIN_SIGNAL)) && ++ arsta->arvif->vdev_type == WMI_VDEV_TYPE_STA && ++ ar->ab->hw_params.supports_rssi_stats && ++ !ath11k_debugfs_get_fw_stats(ar, ar->pdev->pdev_id, 0, ++ WMI_REQUEST_RSSI_PER_CHAIN_STAT)) { ++ ath11k_mac_put_chain_rssi(sinfo, arsta, "fw stats", true); ++ } ++ + /* TODO: Use real NF instead of default one. */ + sinfo->signal = arsta->rssi_comb + ATH11K_DEFAULT_NOISE_FLOOR; + sinfo->filled |= BIT_ULL(NL80211_STA_INFO_SIGNAL); +--- a/drivers/net/wireless/ath/ath11k/wmi.c ++++ b/drivers/net/wireless/ath/ath11k/wmi.c +@@ -73,6 +73,14 @@ struct wmi_tlv_dma_buf_release_parse { + bool meta_data_done; + }; + ++struct wmi_tlv_fw_stats_parse { ++ const struct wmi_stats_event *ev; ++ const struct wmi_per_chain_rssi_stats *rssi; ++ struct ath11k_fw_stats *stats; ++ int rssi_num; ++ bool chain_rssi_done; ++}; ++ + static const struct wmi_tlv_policy wmi_tlv_policies[] = { + [WMI_TAG_ARRAY_BYTE] + = { .min_len = 0 }, +@@ -132,6 +140,8 @@ static const struct wmi_tlv_policy wmi_t + .min_len = sizeof(struct wmi_obss_color_collision_event) }, + [WMI_TAG_11D_NEW_COUNTRY_EVENT] = { + .min_len = sizeof(struct wmi_11d_new_cc_ev) }, ++ [WMI_TAG_PER_CHAIN_RSSI_STATS] = { ++ .min_len = sizeof(struct wmi_per_chain_rssi_stats) }, + }; + + #define PRIMAP(_hw_mode_) \ +@@ -5554,37 +5564,89 @@ ath11k_wmi_pull_bcn_stats(const struct w + dst->tx_bcn_outage_cnt = src->tx_bcn_outage_cnt; + } + +-int ath11k_wmi_pull_fw_stats(struct ath11k_base *ab, struct sk_buff *skb, +- struct ath11k_fw_stats *stats) +-{ +- const void **tb; +- const struct wmi_stats_event *ev; +- const void *data; +- int i, ret; +- u32 len = skb->len; ++static int ath11k_wmi_tlv_rssi_chain_parse(struct ath11k_base *ab, ++ u16 tag, u16 len, ++ const void *ptr, void *data) ++{ ++ struct wmi_tlv_fw_stats_parse *parse = data; ++ const struct wmi_stats_event *ev = parse->ev; ++ struct ath11k_fw_stats *stats = parse->stats; ++ struct ath11k *ar; ++ struct ath11k_vif *arvif; ++ struct ieee80211_sta *sta; ++ struct ath11k_sta *arsta; ++ const struct wmi_rssi_stats *stats_rssi = (const struct wmi_rssi_stats *)ptr; ++ int j, ret = 0; + +- tb = ath11k_wmi_tlv_parse_alloc(ab, skb->data, len, GFP_ATOMIC); +- if (IS_ERR(tb)) { +- ret = PTR_ERR(tb); +- ath11k_warn(ab, "failed to parse tlv: %d\n", ret); +- return ret; ++ if (tag != WMI_TAG_RSSI_STATS) ++ return -EPROTO; ++ ++ rcu_read_lock(); ++ ++ ar = ath11k_mac_get_ar_by_pdev_id(ab, ev->pdev_id); ++ stats->stats_id = WMI_REQUEST_RSSI_PER_CHAIN_STAT; ++ ++ ath11k_dbg(ab, ATH11K_DBG_WMI, ++ "wmi stats vdev id %d mac %pM\n", ++ stats_rssi->vdev_id, stats_rssi->peer_macaddr.addr); ++ ++ arvif = ath11k_mac_get_arvif(ar, stats_rssi->vdev_id); ++ if (!arvif) { ++ ath11k_warn(ab, "not found vif for vdev id %d\n", ++ stats_rssi->vdev_id); ++ ret = -EPROTO; ++ goto exit; + } + +- ev = tb[WMI_TAG_STATS_EVENT]; +- data = tb[WMI_TAG_ARRAY_BYTE]; +- if (!ev || !data) { ++ ath11k_dbg(ab, ATH11K_DBG_WMI, ++ "wmi stats bssid %pM vif %pK\n", ++ arvif->bssid, arvif->vif); ++ ++ sta = ieee80211_find_sta_by_ifaddr(ar->hw, ++ arvif->bssid, ++ NULL); ++ if (!sta) { ++ ath11k_warn(ab, "not found station for bssid %pM\n", ++ arvif->bssid); ++ ret = -EPROTO; ++ goto exit; ++ } ++ ++ arsta = (struct ath11k_sta *)sta->drv_priv; ++ ++ BUILD_BUG_ON(ARRAY_SIZE(arsta->chain_signal) > ++ ARRAY_SIZE(stats_rssi->rssi_avg_beacon)); ++ ++ for (j = 0; j < ARRAY_SIZE(arsta->chain_signal); j++) { ++ arsta->chain_signal[j] = stats_rssi->rssi_avg_beacon[j]; ++ ath11k_dbg(ab, ATH11K_DBG_WMI, ++ "wmi stats beacon rssi[%d] %d data rssi[%d] %d\n", ++ j, ++ stats_rssi->rssi_avg_beacon[j], ++ j, ++ stats_rssi->rssi_avg_data[j]); ++ } ++ ++exit: ++ rcu_read_unlock(); ++ return ret; ++} ++ ++static int ath11k_wmi_tlv_fw_stats_data_parse(struct ath11k_base *ab, ++ struct wmi_tlv_fw_stats_parse *parse, ++ const void *ptr, ++ u16 len) ++{ ++ struct ath11k_fw_stats *stats = parse->stats; ++ const struct wmi_stats_event *ev = parse->ev; ++ int i; ++ const void *data = ptr; ++ ++ if (!ev) { + ath11k_warn(ab, "failed to fetch update stats ev"); +- kfree(tb); + return -EPROTO; + } + +- ath11k_dbg(ab, ATH11K_DBG_WMI, +- "wmi stats update ev pdev_id %d pdev %i vdev %i bcn %i\n", +- ev->pdev_id, +- ev->num_pdev_stats, ev->num_vdev_stats, +- ev->num_bcn_stats); +- +- stats->pdev_id = ev->pdev_id; + stats->stats_id = 0; + + for (i = 0; i < ev->num_pdev_stats; i++) { +@@ -5592,10 +5654,8 @@ int ath11k_wmi_pull_fw_stats(struct ath1 + struct ath11k_fw_stats_pdev *dst; + + src = data; +- if (len < sizeof(*src)) { +- kfree(tb); ++ if (len < sizeof(*src)) + return -EPROTO; +- } + + stats->stats_id = WMI_REQUEST_PDEV_STAT; + +@@ -5617,10 +5677,8 @@ int ath11k_wmi_pull_fw_stats(struct ath1 + struct ath11k_fw_stats_vdev *dst; + + src = data; +- if (len < sizeof(*src)) { +- kfree(tb); ++ if (len < sizeof(*src)) + return -EPROTO; +- } + + stats->stats_id = WMI_REQUEST_VDEV_STAT; + +@@ -5640,10 +5698,8 @@ int ath11k_wmi_pull_fw_stats(struct ath1 + struct ath11k_fw_stats_bcn *dst; + + src = data; +- if (len < sizeof(*src)) { +- kfree(tb); ++ if (len < sizeof(*src)) + return -EPROTO; +- } + + stats->stats_id = WMI_REQUEST_BCN_STAT; + +@@ -5658,10 +5714,67 @@ int ath11k_wmi_pull_fw_stats(struct ath1 + list_add_tail(&dst->list, &stats->bcn); + } + +- kfree(tb); + return 0; + } + ++static int ath11k_wmi_tlv_fw_stats_parse(struct ath11k_base *ab, ++ u16 tag, u16 len, ++ const void *ptr, void *data) ++{ ++ struct wmi_tlv_fw_stats_parse *parse = data; ++ int ret = 0; ++ ++ switch (tag) { ++ case WMI_TAG_STATS_EVENT: ++ parse->ev = (struct wmi_stats_event *)ptr; ++ parse->stats->pdev_id = parse->ev->pdev_id; ++ break; ++ case WMI_TAG_ARRAY_BYTE: ++ ret = ath11k_wmi_tlv_fw_stats_data_parse(ab, parse, ptr, len); ++ break; ++ case WMI_TAG_PER_CHAIN_RSSI_STATS: ++ parse->rssi = (struct wmi_per_chain_rssi_stats *)ptr; ++ ++ if (parse->ev->stats_id & WMI_REQUEST_RSSI_PER_CHAIN_STAT) ++ parse->rssi_num = parse->rssi->num_per_chain_rssi_stats; ++ ++ ath11k_dbg(ab, ATH11K_DBG_WMI, ++ "wmi stats id 0x%x num chain %d\n", ++ parse->ev->stats_id, ++ parse->rssi_num); ++ break; ++ case WMI_TAG_ARRAY_STRUCT: ++ if (parse->rssi_num && !parse->chain_rssi_done) { ++ ret = ath11k_wmi_tlv_iter(ab, ptr, len, ++ ath11k_wmi_tlv_rssi_chain_parse, ++ parse); ++ if (ret) { ++ ath11k_warn(ab, "failed to parse rssi chain %d\n", ++ ret); ++ return ret; ++ } ++ parse->chain_rssi_done = true; ++ } ++ break; ++ default: ++ break; ++ } ++ return ret; ++} ++ ++int ath11k_wmi_pull_fw_stats(struct ath11k_base *ab, struct sk_buff *skb, ++ struct ath11k_fw_stats *stats) ++{ ++ struct wmi_tlv_fw_stats_parse parse = { }; ++ ++ stats->stats_id = 0; ++ parse.stats = stats; ++ ++ return ath11k_wmi_tlv_iter(ab, skb->data, skb->len, ++ ath11k_wmi_tlv_fw_stats_parse, ++ &parse); ++} ++ + size_t ath11k_wmi_fw_stats_num_vdevs(struct list_head *head) + { + struct ath11k_fw_stats_vdev *i; +--- a/drivers/net/wireless/ath/ath11k/wmi.h ++++ b/drivers/net/wireless/ath/ath11k/wmi.h +@@ -4439,6 +4439,17 @@ struct wmi_stats_event { + u32 num_peer_extd2_stats; + } __packed; + ++struct wmi_rssi_stats { ++ u32 vdev_id; ++ u32 rssi_avg_beacon[WMI_MAX_CHAINS]; ++ u32 rssi_avg_data[WMI_MAX_CHAINS]; ++ struct wmi_mac_addr peer_macaddr; ++} __packed; ++ ++struct wmi_per_chain_rssi_stats { ++ u32 num_per_chain_rssi_stats; ++} __packed; ++ + struct wmi_pdev_ctl_failsafe_chk_event { + u32 pdev_id; + u32 ctl_failsafe_status; diff --git a/package/kernel/mac80211/patches/ath11k/0144-ath11k-add-signal-report-to-mac80211-for-QCA6390-and.patch b/package/kernel/mac80211/patches/ath11k/0144-ath11k-add-signal-report-to-mac80211-for-QCA6390-and.patch new file mode 100644 index 000000000..912872c8d --- /dev/null +++ b/package/kernel/mac80211/patches/ath11k/0144-ath11k-add-signal-report-to-mac80211-for-QCA6390-and.patch @@ -0,0 +1,171 @@ +From c3b39553fc7712a9621a19d9670d6f250943d50e Mon Sep 17 00:00:00 2001 +From: Wen Gong +Date: Fri, 17 Dec 2021 20:27:21 +0200 +Subject: [PATCH 144/151] ath11k: add signal report to mac80211 for QCA6390 and + WCN6855 + +IEEE80211_HW_USES_RSS is set in ath11k, then the device uses RSS and +thus requires parallel RX which implies using per-CPU station statistics +in sta_get_last_rx_stats() of mac80211. Currently signal is only set in +ath11k_mgmt_rx_event(), and not set for RX data packet, then it show +signal as 0 for iw command easily. + +Change to get signal from firmware and report to mac80211. + +For QCA6390 and WCN6855, the rssi value is already in dbm unit, so +don't need to convert it again. + +Tested-on: QCA6390 hw2.0 PCI WLAN.HST.1.0.1-01740-QCAHSTSWPLZ_V2_TO_X86-1 +Tested-on: WCN6855 hw2.0 PCI WLAN.HSP.1.1-01720.1-QCAHSPSWPL_V1_V2_SILICONZ_LITE-1 + +Signed-off-by: Wen Gong +Signed-off-by: Kalle Valo +Link: https://lore.kernel.org/r/20211216070535.31732-1-quic_wgong@quicinc.com +--- + drivers/net/wireless/ath/ath11k/core.h | 1 + + drivers/net/wireless/ath/ath11k/mac.c | 22 ++++++++++-- + drivers/net/wireless/ath/ath11k/wmi.c | 49 +++++++++++++++++++++----- + 3 files changed, 61 insertions(+), 11 deletions(-) + +--- a/drivers/net/wireless/ath/ath11k/core.h ++++ b/drivers/net/wireless/ath/ath11k/core.h +@@ -386,6 +386,7 @@ struct ath11k_sta { + u64 rx_duration; + u64 tx_duration; + u8 rssi_comb; ++ s8 rssi_beacon; + s8 chain_signal[IEEE80211_MAX_CHAINS]; + struct ath11k_htt_tx_stats *tx_stats; + struct ath11k_rx_peer_stats *rx_stats; +--- a/drivers/net/wireless/ath/ath11k/mac.c ++++ b/drivers/net/wireless/ath/ath11k/mac.c +@@ -7811,6 +7811,9 @@ static void ath11k_mac_op_sta_statistics + { + struct ath11k_sta *arsta = (struct ath11k_sta *)sta->drv_priv; + struct ath11k *ar = arsta->arvif->ar; ++ s8 signal; ++ bool db2dbm = test_bit(WMI_TLV_SERVICE_HW_DB2DBM_CONVERSION_SUPPORT, ++ ar->ab->wmi_ab.svc_map); + + sinfo->rx_duration = arsta->rx_duration; + sinfo->filled |= BIT_ULL(NL80211_STA_INFO_RX_DURATION); +@@ -7843,9 +7846,22 @@ static void ath11k_mac_op_sta_statistics + ath11k_mac_put_chain_rssi(sinfo, arsta, "fw stats", true); + } + +- /* TODO: Use real NF instead of default one. */ +- sinfo->signal = arsta->rssi_comb + ATH11K_DEFAULT_NOISE_FLOOR; +- sinfo->filled |= BIT_ULL(NL80211_STA_INFO_SIGNAL); ++ signal = arsta->rssi_comb; ++ if (!signal && ++ arsta->arvif->vdev_type == WMI_VDEV_TYPE_STA && ++ ar->ab->hw_params.supports_rssi_stats && ++ !(ath11k_debugfs_get_fw_stats(ar, ar->pdev->pdev_id, 0, ++ WMI_REQUEST_VDEV_STAT))) ++ signal = arsta->rssi_beacon; ++ ++ ath11k_dbg(ar->ab, ATH11K_DBG_MAC, ++ "mac sta statistics db2dbm %u rssi comb %d rssi beacon %d\n", ++ db2dbm, arsta->rssi_comb, arsta->rssi_beacon); ++ ++ if (signal) { ++ sinfo->signal = db2dbm ? signal : signal + ATH11K_DEFAULT_NOISE_FLOOR; ++ sinfo->filled |= BIT_ULL(NL80211_STA_INFO_SIGNAL); ++ } + } + + static const struct ieee80211_ops ath11k_ops = { +--- a/drivers/net/wireless/ath/ath11k/wmi.c ++++ b/drivers/net/wireless/ath/ath11k/wmi.c +@@ -5639,7 +5639,11 @@ static int ath11k_wmi_tlv_fw_stats_data_ + { + struct ath11k_fw_stats *stats = parse->stats; + const struct wmi_stats_event *ev = parse->ev; +- int i; ++ struct ath11k *ar; ++ struct ath11k_vif *arvif; ++ struct ieee80211_sta *sta; ++ struct ath11k_sta *arsta; ++ int i, ret = 0; + const void *data = ptr; + + if (!ev) { +@@ -5649,13 +5653,19 @@ static int ath11k_wmi_tlv_fw_stats_data_ + + stats->stats_id = 0; + ++ rcu_read_lock(); ++ ++ ar = ath11k_mac_get_ar_by_pdev_id(ab, ev->pdev_id); ++ + for (i = 0; i < ev->num_pdev_stats; i++) { + const struct wmi_pdev_stats *src; + struct ath11k_fw_stats_pdev *dst; + + src = data; +- if (len < sizeof(*src)) +- return -EPROTO; ++ if (len < sizeof(*src)) { ++ ret = -EPROTO; ++ goto exit; ++ } + + stats->stats_id = WMI_REQUEST_PDEV_STAT; + +@@ -5677,11 +5687,30 @@ static int ath11k_wmi_tlv_fw_stats_data_ + struct ath11k_fw_stats_vdev *dst; + + src = data; +- if (len < sizeof(*src)) +- return -EPROTO; ++ if (len < sizeof(*src)) { ++ ret = -EPROTO; ++ goto exit; ++ } + + stats->stats_id = WMI_REQUEST_VDEV_STAT; + ++ arvif = ath11k_mac_get_arvif(ar, src->vdev_id); ++ if (arvif) { ++ sta = ieee80211_find_sta_by_ifaddr(ar->hw, ++ arvif->bssid, ++ NULL); ++ if (sta) { ++ arsta = (struct ath11k_sta *)sta->drv_priv; ++ arsta->rssi_beacon = src->beacon_snr; ++ ath11k_dbg(ab, ATH11K_DBG_WMI, ++ "wmi stats vdev id %d snr %d\n", ++ src->vdev_id, src->beacon_snr); ++ } else { ++ ath11k_warn(ab, "not found station for bssid %pM\n", ++ arvif->bssid); ++ } ++ } ++ + data += sizeof(*src); + len -= sizeof(*src); + +@@ -5698,8 +5727,10 @@ static int ath11k_wmi_tlv_fw_stats_data_ + struct ath11k_fw_stats_bcn *dst; + + src = data; +- if (len < sizeof(*src)) +- return -EPROTO; ++ if (len < sizeof(*src)) { ++ ret = -EPROTO; ++ goto exit; ++ } + + stats->stats_id = WMI_REQUEST_BCN_STAT; + +@@ -5714,7 +5745,9 @@ static int ath11k_wmi_tlv_fw_stats_data_ + list_add_tail(&dst->list, &stats->bcn); + } + +- return 0; ++exit: ++ rcu_read_unlock(); ++ return ret; + } + + static int ath11k_wmi_tlv_fw_stats_parse(struct ath11k_base *ab, diff --git a/package/kernel/mac80211/patches/ath11k/0145-ath11k-fix-warning-of-RCU-usage-for-ath11k_mac_get_a.patch b/package/kernel/mac80211/patches/ath11k/0145-ath11k-fix-warning-of-RCU-usage-for-ath11k_mac_get_a.patch new file mode 100644 index 000000000..12120780d --- /dev/null +++ b/package/kernel/mac80211/patches/ath11k/0145-ath11k-fix-warning-of-RCU-usage-for-ath11k_mac_get_a.patch @@ -0,0 +1,124 @@ +From 01e782c891083f1847c0b62902bfe3c2812566c6 Mon Sep 17 00:00:00 2001 +From: Wen Gong +Date: Fri, 17 Dec 2021 20:27:21 +0200 +Subject: [PATCH 145/151] ath11k: fix warning of RCU usage for + ath11k_mac_get_arvif_by_vdev_id() + +When enable more debug config, it happen below warning. It is because +the caller does not add rcu_read_lock()/rcu_read_unlock() to wrap the +rcu_dereference(). + +Add rcu_read_lock()/rcu_read_unlock() to wrap rcu_dereference(), then +fixed it. + +[ 180.716604] ============================= +[ 180.716670] WARNING: suspicious RCU usage +[ 180.716734] 5.16.0-rc4-wt-ath+ #542 Not tainted +[ 180.716895] ----------------------------- +[ 180.716957] drivers/net/wireless/ath/ath11k/mac.c:506 suspicious rcu_dereference_check() usage! +[ 180.717023] + other info that might help us debug this: + +[ 180.717087] + rcu_scheduler_active = 2, debug_locks = 1 +[ 180.717151] no locks held by swapper/0/0. +[ 180.717215] + stack backtrace: +[ 180.717279] CPU: 0 PID: 0 Comm: swapper/0 Kdump: loaded Not tainted 5.16.0-rc4-wt-ath+ #542 +[ 180.717346] Hardware name: Intel(R) Client Systems NUC8i7HVK/NUC8i7HVB, BIOS HNKBLi70.86A.0067.2021.0528.1339 05/28/2021 +[ 180.717411] Call Trace: +[ 180.717475] +[ 180.717541] dump_stack_lvl+0x57/0x7d +[ 180.717610] ath11k_mac_get_arvif_by_vdev_id+0x1ab/0x2d0 [ath11k] +[ 180.717694] ? ath11k_mac_get_arvif+0x140/0x140 [ath11k] +[ 180.717798] ? ath11k_wmi_tlv_op_rx+0xc1b/0x2520 [ath11k] +[ 180.717888] ? kfree+0xe8/0x2c0 +[ 180.717959] ath11k_wmi_tlv_op_rx+0xc27/0x2520 [ath11k] +[ 180.718038] ? ath11k_mgmt_rx_event+0xda0/0xda0 [ath11k] +[ 180.718113] ? __lock_acquire+0xb72/0x1870 +[ 180.718182] ? lockdep_hardirqs_on_prepare.part.0+0x18c/0x370 +[ 180.718250] ? sched_clock_cpu+0x15/0x1b0 +[ 180.718314] ? find_held_lock+0x33/0x110 +[ 180.718381] ? __lock_release+0x4bd/0x9f0 +[ 180.718447] ? lock_downgrade+0x130/0x130 +[ 180.718517] ath11k_htc_rx_completion_handler+0x38f/0x5b0 [ath11k] +[ 180.718596] ? __local_bh_enable_ip+0xa0/0x110 +[ 180.718662] ath11k_ce_recv_process_cb+0x5ac/0x920 [ath11k] +[ 180.718783] ? __lock_acquired+0x205/0x890 +[ 180.718864] ? ath11k_ce_rx_post_pipe+0x970/0x970 [ath11k] +[ 180.718949] ? __wake_up_bit+0x100/0x100 +[ 180.719020] ath11k_pci_ce_tasklet+0x5f/0xf0 [ath11k_pci] +[ 180.719085] ? tasklet_clear_sched+0x42/0xe0 +[ 180.719148] tasklet_action_common.constprop.0+0x204/0x2f0 +[ 180.719217] __do_softirq+0x276/0x86a +[ 180.719281] ? __common_interrupt+0x92/0x1d0 +[ 180.719350] __irq_exit_rcu+0x11c/0x180 +[ 180.719418] irq_exit_rcu+0x5/0x20 +[ 180.719482] common_interrupt+0xa4/0xc0 +[ 180.719547] +[ 180.719609] +[ 180.719671] asm_common_interrupt+0x1e/0x40 +[ 180.719772] RIP: 0010:cpuidle_enter_state+0x1f3/0x8d0 +[ 180.719838] Code: 00 41 8b 77 04 bf ff ff ff ff e8 78 f1 ff ff 31 ff e8 81 fa 52 fe 80 7c 24 08 00 0f 85 9e 01 00 00 e8 11 13 78 fe fb 45 85 e4 <0f> 88 8c 02 00 00 49 63 ec 48 8d 44 6d 00 48 8d 44 85 00 48 8d 7c +[ 180.719909] RSP: 0018:ffffffffa4607dd0 EFLAGS: 00000202 +[ 180.719982] RAX: 00000000002aea91 RBX: ffffffffa4a5fec0 RCX: 1ffffffff49ca501 +[ 180.720047] RDX: 0000000000000000 RSI: ffffffffa3c6e4e0 RDI: ffffffffa3dcf2a0 +[ 180.720110] RBP: 0000000000000002 R08: 0000000000000001 R09: ffffffffa4e54d17 +[ 180.720173] R10: fffffbfff49ca9a2 R11: 0000000000000001 R12: 0000000000000002 +[ 180.720236] R13: ffff8881169ccc04 R14: 0000002a13899598 R15: ffff8881169ccc00 +[ 180.720321] cpuidle_enter+0x45/0xa0 +[ 180.720413] cpuidle_idle_call+0x274/0x3f0 +[ 180.720503] ? arch_cpu_idle_exit+0x30/0x30 +[ 180.720869] ? tsc_verify_tsc_adjust+0x97/0x2e0 +[ 180.720935] ? lockdep_hardirqs_off+0x90/0xd0 +[ 180.721002] do_idle+0xe0/0x150 +[ 180.721069] cpu_startup_entry+0x14/0x20 +[ 180.721134] start_kernel+0x3a2/0x3c2 +[ 180.721200] secondary_startup_64_no_verify+0xb0/0xbb +[ 180.721274] + +Tested-on: WCN6855 hw2.0 PCI WLAN.HSP.1.1-02892.1-QCAHSPSWPL_V1_V2_SILICONZ_LITE-1 + +Signed-off-by: Wen Gong +Signed-off-by: Kalle Valo +Link: https://lore.kernel.org/r/20211217064132.30911-1-quic_wgong@quicinc.com +--- + drivers/net/wireless/ath/ath11k/wmi.c | 6 ++++++ + 1 file changed, 6 insertions(+) + +--- a/drivers/net/wireless/ath/ath11k/wmi.c ++++ b/drivers/net/wireless/ath/ath11k/wmi.c +@@ -3605,6 +3605,8 @@ ath11k_wmi_obss_color_collision_event(st + return; + } + ++ rcu_read_lock(); ++ + ev = tb[WMI_TAG_OBSS_COLOR_COLLISION_EVT]; + if (!ev) { + ath11k_warn(ab, "failed to fetch obss color collision ev"); +@@ -3635,6 +3637,7 @@ ath11k_wmi_obss_color_collision_event(st + + exit: + kfree(tb); ++ rcu_read_unlock(); + } + + static void +@@ -6541,13 +6544,16 @@ static void ath11k_bcn_tx_status_event(s + return; + } + ++ rcu_read_lock(); + arvif = ath11k_mac_get_arvif_by_vdev_id(ab, vdev_id); + if (!arvif) { + ath11k_warn(ab, "invalid vdev id %d in bcn_tx_status", + vdev_id); ++ rcu_read_unlock(); + return; + } + ath11k_mac_bcn_tx_event(arvif); ++ rcu_read_unlock(); + } + + static void ath11k_vdev_stopped_event(struct ath11k_base *ab, struct sk_buff *skb) diff --git a/package/kernel/mac80211/patches/ath11k/0146-ath11k-report-tx-bitrate-for-iw-wlan-station-dump.patch b/package/kernel/mac80211/patches/ath11k/0146-ath11k-report-tx-bitrate-for-iw-wlan-station-dump.patch new file mode 100644 index 000000000..e7e870445 --- /dev/null +++ b/package/kernel/mac80211/patches/ath11k/0146-ath11k-report-tx-bitrate-for-iw-wlan-station-dump.patch @@ -0,0 +1,533 @@ +From 1b8bb94c0612cf32e418e90ae93cf37214d84669 Mon Sep 17 00:00:00 2001 +From: Wen Gong +Date: Mon, 20 Dec 2021 18:11:09 +0200 +Subject: [PATCH 146/151] ath11k: report tx bitrate for iw wlan station dump + +HTT_T2H_MSG_TYPE_PPDU_STATS_IND is a message which include the ppdu +info, currently it is not report from firmware for ath11k, then the +tx bitrate of "iw wlan0 station dump" always show an invalid value +"tx bitrate: 6.0 MBit/s". + +To address the issue, this is to parse the info of tx complete report +from firmware and indicate the tx rate to mac80211. + +After that, "iw wlan0 station dump" show the correct tx bit rate such +as: +tx bitrate: 78.0 MBit/s MCS 12 +tx bitrate: 144.4 MBit/s VHT-MCS 7 short GI VHT-NSS 2 +tx bitrate: 286.7 MBit/s HE-MCS 11 HE-NSS 2 HE-GI 0 HE-DCM 0 +tx bitrate: 1921.5 MBit/s 160MHz HE-MCS 9 HE-NSS 2 HE-GI 0 HE-DCM 0 + +Tested-on: QCA6390 hw2.0 PCI WLAN.HST.1.0.1-01740-QCAHSTSWPLZ_V2_TO_X86-1 + +Signed-off-by: Wen Gong +Signed-off-by: Kalle Valo +Link: https://lore.kernel.org/r/20211217093722.5739-1-quic_wgong@quicinc.com +--- + drivers/net/wireless/ath/ath11k/core.h | 1 + + drivers/net/wireless/ath/ath11k/debugfs_sta.c | 78 +------------ + drivers/net/wireless/ath/ath11k/debugfs_sta.h | 2 - + drivers/net/wireless/ath/ath11k/dp_rx.c | 28 +---- + drivers/net/wireless/ath/ath11k/dp_tx.c | 106 +++++++++++++++++- + drivers/net/wireless/ath/ath11k/dp_tx.h | 1 + + drivers/net/wireless/ath/ath11k/hal_rx.c | 4 +- + drivers/net/wireless/ath/ath11k/hal_rx.h | 27 ----- + drivers/net/wireless/ath/ath11k/mac.c | 93 +++++++++++++++ + drivers/net/wireless/ath/ath11k/mac.h | 3 + + 10 files changed, 210 insertions(+), 133 deletions(-) + +--- a/drivers/net/wireless/ath/ath11k/core.h ++++ b/drivers/net/wireless/ath/ath11k/core.h +@@ -382,6 +382,7 @@ struct ath11k_sta { + struct work_struct update_wk; + struct work_struct set_4addr_wk; + struct rate_info txrate; ++ u32 peer_nss; + struct rate_info last_txrate; + u64 rx_duration; + u64 tx_duration; +--- a/drivers/net/wireless/ath/ath11k/debugfs_sta.c ++++ b/drivers/net/wireless/ath/ath11k/debugfs_sta.c +@@ -126,85 +126,9 @@ void ath11k_debugfs_sta_add_tx_stats(str + } + + void ath11k_debugfs_sta_update_txcompl(struct ath11k *ar, +- struct sk_buff *msdu, + struct hal_tx_status *ts) + { +- struct ath11k_base *ab = ar->ab; +- struct ath11k_per_peer_tx_stats *peer_stats = &ar->cached_stats; +- enum hal_tx_rate_stats_pkt_type pkt_type; +- enum hal_tx_rate_stats_sgi sgi; +- enum hal_tx_rate_stats_bw bw; +- struct ath11k_peer *peer; +- struct ath11k_sta *arsta; +- struct ieee80211_sta *sta; +- u16 rate; +- u8 rate_idx = 0; +- int ret; +- u8 mcs; +- +- rcu_read_lock(); +- spin_lock_bh(&ab->base_lock); +- peer = ath11k_peer_find_by_id(ab, ts->peer_id); +- if (!peer || !peer->sta) { +- ath11k_warn(ab, "failed to find the peer\n"); +- spin_unlock_bh(&ab->base_lock); +- rcu_read_unlock(); +- return; +- } +- +- sta = peer->sta; +- arsta = (struct ath11k_sta *)sta->drv_priv; +- +- memset(&arsta->txrate, 0, sizeof(arsta->txrate)); +- pkt_type = FIELD_GET(HAL_TX_RATE_STATS_INFO0_PKT_TYPE, +- ts->rate_stats); +- mcs = FIELD_GET(HAL_TX_RATE_STATS_INFO0_MCS, +- ts->rate_stats); +- sgi = FIELD_GET(HAL_TX_RATE_STATS_INFO0_SGI, +- ts->rate_stats); +- bw = FIELD_GET(HAL_TX_RATE_STATS_INFO0_BW, ts->rate_stats); +- +- if (pkt_type == HAL_TX_RATE_STATS_PKT_TYPE_11A || +- pkt_type == HAL_TX_RATE_STATS_PKT_TYPE_11B) { +- ret = ath11k_mac_hw_ratecode_to_legacy_rate(mcs, +- pkt_type, +- &rate_idx, +- &rate); +- if (ret < 0) +- goto err_out; +- arsta->txrate.legacy = rate; +- } else if (pkt_type == HAL_TX_RATE_STATS_PKT_TYPE_11N) { +- if (mcs > 7) { +- ath11k_warn(ab, "Invalid HT mcs index %d\n", mcs); +- goto err_out; +- } +- +- arsta->txrate.mcs = mcs + 8 * (arsta->last_txrate.nss - 1); +- arsta->txrate.flags = RATE_INFO_FLAGS_MCS; +- if (sgi) +- arsta->txrate.flags |= RATE_INFO_FLAGS_SHORT_GI; +- } else if (pkt_type == HAL_TX_RATE_STATS_PKT_TYPE_11AC) { +- if (mcs > 9) { +- ath11k_warn(ab, "Invalid VHT mcs index %d\n", mcs); +- goto err_out; +- } +- +- arsta->txrate.mcs = mcs; +- arsta->txrate.flags = RATE_INFO_FLAGS_VHT_MCS; +- if (sgi) +- arsta->txrate.flags |= RATE_INFO_FLAGS_SHORT_GI; +- } else if (pkt_type == HAL_TX_RATE_STATS_PKT_TYPE_11AX) { +- /* TODO */ +- } +- +- arsta->txrate.nss = arsta->last_txrate.nss; +- arsta->txrate.bw = ath11k_mac_bw_to_mac80211_bw(bw); +- +- ath11k_debugfs_sta_add_tx_stats(arsta, peer_stats, rate_idx); +- +-err_out: +- spin_unlock_bh(&ab->base_lock); +- rcu_read_unlock(); ++ ath11k_dp_tx_update_txcompl(ar, ts); + } + + static ssize_t ath11k_dbg_sta_dump_tx_stats(struct file *file, +--- a/drivers/net/wireless/ath/ath11k/debugfs_sta.h ++++ b/drivers/net/wireless/ath/ath11k/debugfs_sta.h +@@ -19,7 +19,6 @@ void ath11k_debugfs_sta_add_tx_stats(str + struct ath11k_per_peer_tx_stats *peer_stats, + u8 legacy_rate_idx); + void ath11k_debugfs_sta_update_txcompl(struct ath11k *ar, +- struct sk_buff *msdu, + struct hal_tx_status *ts); + + #else /* CPTCFG_ATH11K_DEBUGFS */ +@@ -34,7 +33,6 @@ ath11k_debugfs_sta_add_tx_stats(struct a + } + + static inline void ath11k_debugfs_sta_update_txcompl(struct ath11k *ar, +- struct sk_buff *msdu, + struct hal_tx_status *ts) + { + } +--- a/drivers/net/wireless/ath/ath11k/dp_rx.c ++++ b/drivers/net/wireless/ath/ath11k/dp_rx.c +@@ -1360,25 +1360,6 @@ int ath11k_dp_htt_tlv_iter(struct ath11k + return 0; + } + +-static inline u32 ath11k_he_gi_to_nl80211_he_gi(u8 sgi) +-{ +- u32 ret = 0; +- +- switch (sgi) { +- case RX_MSDU_START_SGI_0_8_US: +- ret = NL80211_RATE_INFO_HE_GI_0_8; +- break; +- case RX_MSDU_START_SGI_1_6_US: +- ret = NL80211_RATE_INFO_HE_GI_1_6; +- break; +- case RX_MSDU_START_SGI_3_2_US: +- ret = NL80211_RATE_INFO_HE_GI_3_2; +- break; +- } +- +- return ret; +-} +- + static void + ath11k_update_per_peer_tx_stats(struct ath11k *ar, + struct htt_ppdu_stats *ppdu_stats, u8 user) +@@ -1497,14 +1478,15 @@ ath11k_update_per_peer_tx_stats(struct a + arsta->txrate.mcs = mcs; + arsta->txrate.flags = RATE_INFO_FLAGS_HE_MCS; + arsta->txrate.he_dcm = dcm; +- arsta->txrate.he_gi = ath11k_he_gi_to_nl80211_he_gi(sgi); +- arsta->txrate.he_ru_alloc = ath11k_he_ru_tones_to_nl80211_he_ru_alloc( +- (user_rate->ru_end - ++ arsta->txrate.he_gi = ath11k_mac_he_gi_to_nl80211_he_gi(sgi); ++ arsta->txrate.he_ru_alloc = ath11k_mac_phy_he_ru_to_nl80211_he_ru_alloc ++ ((user_rate->ru_end - + user_rate->ru_start) + 1); + break; + } + + arsta->txrate.nss = nss; ++ + arsta->txrate.bw = ath11k_mac_bw_to_mac80211_bw(bw); + arsta->tx_duration += tx_duration; + memcpy(&arsta->last_txrate, &arsta->txrate, sizeof(struct rate_info)); +@@ -2384,7 +2366,7 @@ static void ath11k_dp_rx_h_rate(struct a + } + rx_status->encoding = RX_ENC_HE; + rx_status->nss = nss; +- rx_status->he_gi = ath11k_he_gi_to_nl80211_he_gi(sgi); ++ rx_status->he_gi = ath11k_mac_he_gi_to_nl80211_he_gi(sgi); + rx_status->bw = ath11k_mac_bw_to_mac80211_bw(bw); + break; + } +--- a/drivers/net/wireless/ath/ath11k/dp_tx.c ++++ b/drivers/net/wireless/ath/ath11k/dp_tx.c +@@ -415,6 +415,105 @@ static void ath11k_dp_tx_cache_peer_stat + } + } + ++void ath11k_dp_tx_update_txcompl(struct ath11k *ar, struct hal_tx_status *ts) ++{ ++ struct ath11k_base *ab = ar->ab; ++ struct ath11k_per_peer_tx_stats *peer_stats = &ar->cached_stats; ++ enum hal_tx_rate_stats_pkt_type pkt_type; ++ enum hal_tx_rate_stats_sgi sgi; ++ enum hal_tx_rate_stats_bw bw; ++ struct ath11k_peer *peer; ++ struct ath11k_sta *arsta; ++ struct ieee80211_sta *sta; ++ u16 rate, ru_tones; ++ u8 mcs, rate_idx, ofdma; ++ int ret; ++ ++ spin_lock_bh(&ab->base_lock); ++ peer = ath11k_peer_find_by_id(ab, ts->peer_id); ++ if (!peer || !peer->sta) { ++ ath11k_dbg(ab, ATH11K_DBG_DP_TX, ++ "failed to find the peer by id %u\n", ts->peer_id); ++ goto err_out; ++ } ++ ++ sta = peer->sta; ++ arsta = (struct ath11k_sta *)sta->drv_priv; ++ ++ memset(&arsta->txrate, 0, sizeof(arsta->txrate)); ++ pkt_type = FIELD_GET(HAL_TX_RATE_STATS_INFO0_PKT_TYPE, ++ ts->rate_stats); ++ mcs = FIELD_GET(HAL_TX_RATE_STATS_INFO0_MCS, ++ ts->rate_stats); ++ sgi = FIELD_GET(HAL_TX_RATE_STATS_INFO0_SGI, ++ ts->rate_stats); ++ bw = FIELD_GET(HAL_TX_RATE_STATS_INFO0_BW, ts->rate_stats); ++ ru_tones = FIELD_GET(HAL_TX_RATE_STATS_INFO0_TONES_IN_RU, ts->rate_stats); ++ ofdma = FIELD_GET(HAL_TX_RATE_STATS_INFO0_OFDMA_TX, ts->rate_stats); ++ ++ /* This is to prefer choose the real NSS value arsta->last_txrate.nss, ++ * if it is invalid, then choose the NSS value while assoc. ++ */ ++ if (arsta->last_txrate.nss) ++ arsta->txrate.nss = arsta->last_txrate.nss; ++ else ++ arsta->txrate.nss = arsta->peer_nss; ++ ++ if (pkt_type == HAL_TX_RATE_STATS_PKT_TYPE_11A || ++ pkt_type == HAL_TX_RATE_STATS_PKT_TYPE_11B) { ++ ret = ath11k_mac_hw_ratecode_to_legacy_rate(mcs, ++ pkt_type, ++ &rate_idx, ++ &rate); ++ if (ret < 0) ++ goto err_out; ++ arsta->txrate.legacy = rate; ++ } else if (pkt_type == HAL_TX_RATE_STATS_PKT_TYPE_11N) { ++ if (mcs > 7) { ++ ath11k_warn(ab, "Invalid HT mcs index %d\n", mcs); ++ goto err_out; ++ } ++ ++ if (arsta->txrate.nss != 0) ++ arsta->txrate.mcs = mcs + 8 * (arsta->txrate.nss - 1); ++ arsta->txrate.flags = RATE_INFO_FLAGS_MCS; ++ if (sgi) ++ arsta->txrate.flags |= RATE_INFO_FLAGS_SHORT_GI; ++ } else if (pkt_type == HAL_TX_RATE_STATS_PKT_TYPE_11AC) { ++ if (mcs > 9) { ++ ath11k_warn(ab, "Invalid VHT mcs index %d\n", mcs); ++ goto err_out; ++ } ++ ++ arsta->txrate.mcs = mcs; ++ arsta->txrate.flags = RATE_INFO_FLAGS_VHT_MCS; ++ if (sgi) ++ arsta->txrate.flags |= RATE_INFO_FLAGS_SHORT_GI; ++ } else if (pkt_type == HAL_TX_RATE_STATS_PKT_TYPE_11AX) { ++ if (mcs > 11) { ++ ath11k_warn(ab, "Invalid HE mcs index %d\n", mcs); ++ goto err_out; ++ } ++ ++ arsta->txrate.mcs = mcs; ++ arsta->txrate.flags = RATE_INFO_FLAGS_HE_MCS; ++ arsta->txrate.he_gi = ath11k_mac_he_gi_to_nl80211_he_gi(sgi); ++ } ++ ++ arsta->txrate.bw = ath11k_mac_bw_to_mac80211_bw(bw); ++ if (ofdma && pkt_type == HAL_TX_RATE_STATS_PKT_TYPE_11AX) { ++ arsta->txrate.bw = RATE_INFO_BW_HE_RU; ++ arsta->txrate.he_ru_alloc = ++ ath11k_mac_he_ru_tones_to_nl80211_he_ru_alloc(ru_tones); ++ } ++ ++ if (ath11k_debugfs_is_extd_tx_stats_enabled(ar)) ++ ath11k_debugfs_sta_add_tx_stats(arsta, peer_stats, rate_idx); ++ ++err_out: ++ spin_unlock_bh(&ab->base_lock); ++} ++ + static void ath11k_dp_tx_complete_msdu(struct ath11k *ar, + struct sk_buff *msdu, + struct hal_tx_status *ts) +@@ -460,7 +559,8 @@ static void ath11k_dp_tx_complete_msdu(s + (info->flags & IEEE80211_TX_CTL_NO_ACK)) + info->flags |= IEEE80211_TX_STAT_NOACK_TRANSMITTED; + +- if (unlikely(ath11k_debugfs_is_extd_tx_stats_enabled(ar))) { ++ if (unlikely(ath11k_debugfs_is_extd_tx_stats_enabled(ar)) || ++ ab->hw_params.single_pdev_only) { + if (ts->flags & HAL_TX_STATUS_FLAGS_FIRST_MSDU) { + if (ar->last_ppdu_id == 0) { + ar->last_ppdu_id = ts->ppdu_id; +@@ -468,12 +568,12 @@ static void ath11k_dp_tx_complete_msdu(s + ar->cached_ppdu_id == ar->last_ppdu_id) { + ar->cached_ppdu_id = ar->last_ppdu_id; + ar->cached_stats.is_ampdu = true; +- ath11k_debugfs_sta_update_txcompl(ar, msdu, ts); ++ ath11k_dp_tx_update_txcompl(ar, ts); + memset(&ar->cached_stats, 0, + sizeof(struct ath11k_per_peer_tx_stats)); + } else { + ar->cached_stats.is_ampdu = false; +- ath11k_debugfs_sta_update_txcompl(ar, msdu, ts); ++ ath11k_dp_tx_update_txcompl(ar, ts); + memset(&ar->cached_stats, 0, + sizeof(struct ath11k_per_peer_tx_stats)); + } +--- a/drivers/net/wireless/ath/ath11k/dp_tx.h ++++ b/drivers/net/wireless/ath/ath11k/dp_tx.h +@@ -15,6 +15,7 @@ struct ath11k_dp_htt_wbm_tx_status { + int ack_rssi; + }; + ++void ath11k_dp_tx_update_txcompl(struct ath11k *ar, struct hal_tx_status *ts); + int ath11k_dp_tx_htt_h2t_ver_req_msg(struct ath11k_base *ab); + int ath11k_dp_tx(struct ath11k *ar, struct ath11k_vif *arvif, + struct ath11k_sta *arsta, struct sk_buff *skb); +--- a/drivers/net/wireless/ath/ath11k/hal_rx.c ++++ b/drivers/net/wireless/ath/ath11k/hal_rx.c +@@ -1039,7 +1039,9 @@ ath11k_hal_rx_parse_mon_status_tlv(struc + + ru_tones = FIELD_GET(HAL_RX_HE_SIG_B1_MU_INFO_INFO0_RU_ALLOCATION, + info0); +- ppdu_info->ru_alloc = ath11k_he_ru_tones_to_nl80211_he_ru_alloc(ru_tones); ++ ppdu_info->ru_alloc = ++ ath11k_mac_phy_he_ru_to_nl80211_he_ru_alloc(ru_tones); ++ + ppdu_info->reception_type = HAL_RX_RECEPTION_TYPE_MU_MIMO; + break; + } +--- a/drivers/net/wireless/ath/ath11k/hal_rx.h ++++ b/drivers/net/wireless/ath/ath11k/hal_rx.h +@@ -363,33 +363,6 @@ ath11k_hal_rx_parse_mon_status(struct at + struct hal_rx_mon_ppdu_info *ppdu_info, + struct sk_buff *skb); + +-static inline u32 ath11k_he_ru_tones_to_nl80211_he_ru_alloc(u16 ru_tones) +-{ +- u32 ret = 0; +- +- switch (ru_tones) { +- case RU_26: +- ret = NL80211_RATE_INFO_HE_RU_ALLOC_26; +- break; +- case RU_52: +- ret = NL80211_RATE_INFO_HE_RU_ALLOC_52; +- break; +- case RU_106: +- ret = NL80211_RATE_INFO_HE_RU_ALLOC_106; +- break; +- case RU_242: +- ret = NL80211_RATE_INFO_HE_RU_ALLOC_242; +- break; +- case RU_484: +- ret = NL80211_RATE_INFO_HE_RU_ALLOC_484; +- break; +- case RU_996: +- ret = NL80211_RATE_INFO_HE_RU_ALLOC_996; +- break; +- } +- return ret; +-} +- + #define REO_QUEUE_DESC_MAGIC_DEBUG_PATTERN_0 0xDDBEEF + #define REO_QUEUE_DESC_MAGIC_DEBUG_PATTERN_1 0xADBEEF + #define REO_QUEUE_DESC_MAGIC_DEBUG_PATTERN_2 0xBDBEEF +--- a/drivers/net/wireless/ath/ath11k/mac.c ++++ b/drivers/net/wireless/ath/ath11k/mac.c +@@ -246,6 +246,93 @@ static const u32 ath11k_smps_map[] = { + static int ath11k_start_vdev_delay(struct ieee80211_hw *hw, + struct ieee80211_vif *vif); + ++enum nl80211_he_ru_alloc ath11k_mac_phy_he_ru_to_nl80211_he_ru_alloc(u16 ru_phy) ++{ ++ enum nl80211_he_ru_alloc ret; ++ ++ switch (ru_phy) { ++ case RU_26: ++ ret = NL80211_RATE_INFO_HE_RU_ALLOC_26; ++ break; ++ case RU_52: ++ ret = NL80211_RATE_INFO_HE_RU_ALLOC_52; ++ break; ++ case RU_106: ++ ret = NL80211_RATE_INFO_HE_RU_ALLOC_106; ++ break; ++ case RU_242: ++ ret = NL80211_RATE_INFO_HE_RU_ALLOC_242; ++ break; ++ case RU_484: ++ ret = NL80211_RATE_INFO_HE_RU_ALLOC_484; ++ break; ++ case RU_996: ++ ret = NL80211_RATE_INFO_HE_RU_ALLOC_996; ++ break; ++ default: ++ ret = NL80211_RATE_INFO_HE_RU_ALLOC_26; ++ break; ++ } ++ ++ return ret; ++} ++ ++enum nl80211_he_ru_alloc ath11k_mac_he_ru_tones_to_nl80211_he_ru_alloc(u16 ru_tones) ++{ ++ enum nl80211_he_ru_alloc ret; ++ ++ switch (ru_tones) { ++ case 26: ++ ret = NL80211_RATE_INFO_HE_RU_ALLOC_26; ++ break; ++ case 52: ++ ret = NL80211_RATE_INFO_HE_RU_ALLOC_52; ++ break; ++ case 106: ++ ret = NL80211_RATE_INFO_HE_RU_ALLOC_106; ++ break; ++ case 242: ++ ret = NL80211_RATE_INFO_HE_RU_ALLOC_242; ++ break; ++ case 484: ++ ret = NL80211_RATE_INFO_HE_RU_ALLOC_484; ++ break; ++ case 996: ++ ret = NL80211_RATE_INFO_HE_RU_ALLOC_996; ++ break; ++ case (996 * 2): ++ ret = NL80211_RATE_INFO_HE_RU_ALLOC_2x996; ++ break; ++ default: ++ ret = NL80211_RATE_INFO_HE_RU_ALLOC_26; ++ break; ++ } ++ ++ return ret; ++} ++ ++enum nl80211_he_gi ath11k_mac_he_gi_to_nl80211_he_gi(u8 sgi) ++{ ++ enum nl80211_he_gi ret; ++ ++ switch (sgi) { ++ case RX_MSDU_START_SGI_0_8_US: ++ ret = NL80211_RATE_INFO_HE_GI_0_8; ++ break; ++ case RX_MSDU_START_SGI_1_6_US: ++ ret = NL80211_RATE_INFO_HE_GI_1_6; ++ break; ++ case RX_MSDU_START_SGI_3_2_US: ++ ret = NL80211_RATE_INFO_HE_GI_3_2; ++ break; ++ default: ++ ret = NL80211_RATE_INFO_HE_GI_0_8; ++ break; ++ } ++ ++ return ret; ++} ++ + u8 ath11k_mac_bw_to_mac80211_bw(u8 bw) + { + u8 ret = 0; +@@ -2541,8 +2628,12 @@ static void ath11k_peer_assoc_prepare(st + struct peer_assoc_params *arg, + bool reassoc) + { ++ struct ath11k_sta *arsta; ++ + lockdep_assert_held(&ar->conf_mutex); + ++ arsta = (struct ath11k_sta *)sta->drv_priv; ++ + memset(arg, 0, sizeof(*arg)); + + reinit_completion(&ar->peer_assoc_done); +@@ -2559,6 +2650,8 @@ static void ath11k_peer_assoc_prepare(st + ath11k_peer_assoc_h_qos(ar, vif, sta, arg); + ath11k_peer_assoc_h_smps(sta, arg); + ++ arsta->peer_nss = arg->peer_nss; ++ + /* TODO: amsdu_disable req? */ + } + +--- a/drivers/net/wireless/ath/ath11k/mac.h ++++ b/drivers/net/wireless/ath/ath11k/mac.h +@@ -162,6 +162,9 @@ void ath11k_mac_drain_tx(struct ath11k * + void ath11k_mac_peer_cleanup_all(struct ath11k *ar); + int ath11k_mac_tx_mgmt_pending_free(int buf_id, void *skb, void *ctx); + u8 ath11k_mac_bw_to_mac80211_bw(u8 bw); ++u32 ath11k_mac_he_gi_to_nl80211_he_gi(u8 sgi); ++enum nl80211_he_ru_alloc ath11k_mac_phy_he_ru_to_nl80211_he_ru_alloc(u16 ru_phy); ++enum nl80211_he_ru_alloc ath11k_mac_he_ru_tones_to_nl80211_he_ru_alloc(u16 ru_tones); + enum ath11k_supported_bw ath11k_mac_mac80211_bw_to_ath11k_bw(enum rate_info_bw bw); + enum hal_encrypt_type ath11k_dp_tx_get_encrypt_type(u32 cipher); + void ath11k_mac_handle_beacon(struct ath11k *ar, struct sk_buff *skb); diff --git a/package/kernel/mac80211/patches/ath11k/0147-ath11k-add-support-for-hardware-rfkill-for-QCA6390.patch b/package/kernel/mac80211/patches/ath11k/0147-ath11k-add-support-for-hardware-rfkill-for-QCA6390.patch new file mode 100644 index 000000000..bde06b9cb --- /dev/null +++ b/package/kernel/mac80211/patches/ath11k/0147-ath11k-add-support-for-hardware-rfkill-for-QCA6390.patch @@ -0,0 +1,395 @@ +From ec038c6127fa772d2c5604e329f22371830d5fa6 Mon Sep 17 00:00:00 2001 +From: Wen Gong +Date: Mon, 20 Dec 2021 18:11:09 +0200 +Subject: [PATCH 147/151] ath11k: add support for hardware rfkill for QCA6390 + +When hardware rfkill is enabled in the firmware it will report the +capability via using WMI_SYS_CAP_INFO_RFKILL bit in the WMI_SERVICE_READY +event to the host. ath11k will check the capability, and if it is enabled then +ath11k will set the GPIO information to firmware using WMI_PDEV_SET_PARAM. When +the firmware detects hardware rfkill is enabled by the user, it will report it +via WMI_RFKILL_STATE_CHANGE_EVENTID. Once ath11k receives the event it will +send wmi command WMI_PDEV_SET_PARAM to the firmware and also notifies cfg80211. + +This only enable rfkill feature for QCA6390, rfkill_pin is all initialized to 0 +for other chips in ath11k_hw_params. + +Tested-on: QCA6390 hw2.0 PCI WLAN.HST.1.0.1-01740-QCAHSTSWPLZ_V2_TO_X86-1 + +Signed-off-by: Wen Gong +Signed-off-by: Kalle Valo +Link: https://lore.kernel.org/r/20211217102334.14907-1-quic_wgong@quicinc.com +--- + drivers/net/wireless/ath/ath11k/core.c | 70 ++++++++++++++++++++++++++ + drivers/net/wireless/ath/ath11k/core.h | 4 ++ + drivers/net/wireless/ath/ath11k/hw.h | 3 ++ + drivers/net/wireless/ath/ath11k/mac.c | 58 +++++++++++++++++++++ + drivers/net/wireless/ath/ath11k/mac.h | 2 + + drivers/net/wireless/ath/ath11k/wmi.c | 41 +++++++++++++++ + drivers/net/wireless/ath/ath11k/wmi.h | 25 +++++++++ + 7 files changed, 203 insertions(+) + +--- a/drivers/net/wireless/ath/ath11k/core.c ++++ b/drivers/net/wireless/ath/ath11k/core.c +@@ -52,6 +52,9 @@ static const struct ath11k_hw_params ath + .target_ce_count = 11, + .svc_to_ce_map = ath11k_target_service_to_ce_map_wlan_ipq8074, + .svc_to_ce_map_len = 21, ++ .rfkill_pin = 0, ++ .rfkill_cfg = 0, ++ .rfkill_on_level = 0, + .single_pdev_only = false, + .rxdma1_enable = true, + .num_rxmda_per_pdev = 1, +@@ -114,6 +117,9 @@ static const struct ath11k_hw_params ath + .target_ce_count = 11, + .svc_to_ce_map = ath11k_target_service_to_ce_map_wlan_ipq6018, + .svc_to_ce_map_len = 19, ++ .rfkill_pin = 0, ++ .rfkill_cfg = 0, ++ .rfkill_on_level = 0, + .single_pdev_only = false, + .rxdma1_enable = true, + .num_rxmda_per_pdev = 1, +@@ -173,6 +179,9 @@ static const struct ath11k_hw_params ath + .target_ce_count = 9, + .svc_to_ce_map = ath11k_target_service_to_ce_map_wlan_qca6390, + .svc_to_ce_map_len = 14, ++ .rfkill_pin = 48, ++ .rfkill_cfg = 0, ++ .rfkill_on_level = 1, + .single_pdev_only = true, + .rxdma1_enable = false, + .num_rxmda_per_pdev = 2, +@@ -231,6 +240,9 @@ static const struct ath11k_hw_params ath + .target_ce_count = 9, + .svc_to_ce_map = ath11k_target_service_to_ce_map_wlan_qcn9074, + .svc_to_ce_map_len = 18, ++ .rfkill_pin = 0, ++ .rfkill_cfg = 0, ++ .rfkill_on_level = 0, + .rxdma1_enable = true, + .num_rxmda_per_pdev = 1, + .rx_mac_buf_ring = false, +@@ -289,6 +301,9 @@ static const struct ath11k_hw_params ath + .target_ce_count = 9, + .svc_to_ce_map = ath11k_target_service_to_ce_map_wlan_qca6390, + .svc_to_ce_map_len = 14, ++ .rfkill_pin = 0, ++ .rfkill_cfg = 0, ++ .rfkill_on_level = 0, + .single_pdev_only = true, + .rxdma1_enable = false, + .num_rxmda_per_pdev = 2, +@@ -347,6 +362,9 @@ static const struct ath11k_hw_params ath + .target_ce_count = 9, + .svc_to_ce_map = ath11k_target_service_to_ce_map_wlan_qca6390, + .svc_to_ce_map_len = 14, ++ .rfkill_pin = 0, ++ .rfkill_cfg = 0, ++ .rfkill_on_level = 0, + .single_pdev_only = true, + .rxdma1_enable = false, + .num_rxmda_per_pdev = 2, +@@ -1015,6 +1033,27 @@ err_firmware_stop: + return ret; + } + ++static int ath11k_core_rfkill_config(struct ath11k_base *ab) ++{ ++ struct ath11k *ar; ++ int ret = 0, i; ++ ++ if (!(ab->target_caps.sys_cap_info & WMI_SYS_CAP_INFO_RFKILL)) ++ return 0; ++ ++ for (i = 0; i < ab->num_radios; i++) { ++ ar = ab->pdevs[i].ar; ++ ++ ret = ath11k_mac_rfkill_config(ar); ++ if (ret && ret != -EOPNOTSUPP) { ++ ath11k_warn(ab, "failed to configure rfkill: %d", ret); ++ return ret; ++ } ++ } ++ ++ return ret; ++} ++ + int ath11k_core_qmi_firmware_ready(struct ath11k_base *ab) + { + int ret; +@@ -1061,6 +1100,13 @@ int ath11k_core_qmi_firmware_ready(struc + goto err_core_stop; + } + ath11k_hif_irq_enable(ab); ++ ++ ret = ath11k_core_rfkill_config(ab); ++ if (ret && ret != -EOPNOTSUPP) { ++ ath11k_err(ab, "failed to config rfkill: %d\n", ret); ++ goto err_core_stop; ++ } ++ + mutex_unlock(&ab->core_lock); + + return 0; +@@ -1126,6 +1172,7 @@ void ath11k_core_halt(struct ath11k *ar) + cancel_delayed_work_sync(&ar->scan.timeout); + cancel_work_sync(&ar->regd_update_work); + cancel_work_sync(&ab->update_11d_work); ++ cancel_work_sync(&ab->rfkill_work); + + rcu_assign_pointer(ab->pdevs_active[ar->pdev_idx], NULL); + synchronize_rcu(); +@@ -1133,6 +1180,28 @@ void ath11k_core_halt(struct ath11k *ar) + idr_init(&ar->txmgmt_idr); + } + ++static void ath11k_rfkill_work(struct work_struct *work) ++{ ++ struct ath11k_base *ab = container_of(work, struct ath11k_base, rfkill_work); ++ struct ath11k *ar; ++ bool rfkill_radio_on; ++ int i; ++ ++ spin_lock_bh(&ab->base_lock); ++ rfkill_radio_on = ab->rfkill_radio_on; ++ spin_unlock_bh(&ab->base_lock); ++ ++ for (i = 0; i < ab->num_radios; i++) { ++ ar = ab->pdevs[i].ar; ++ if (!ar) ++ continue; ++ ++ /* notify cfg80211 radio state change */ ++ ath11k_mac_rfkill_enable_radio(ar, rfkill_radio_on); ++ wiphy_rfkill_set_hw_state(ar->hw->wiphy, !rfkill_radio_on); ++ } ++} ++ + static void ath11k_update_11d(struct work_struct *work) + { + struct ath11k_base *ab = container_of(work, struct ath11k_base, update_11d_work); +@@ -1339,6 +1408,7 @@ struct ath11k_base *ath11k_core_alloc(st + init_waitqueue_head(&ab->qmi.cold_boot_waitq); + INIT_WORK(&ab->restart_work, ath11k_core_restart); + INIT_WORK(&ab->update_11d_work, ath11k_update_11d); ++ INIT_WORK(&ab->rfkill_work, ath11k_rfkill_work); + timer_setup(&ab->rx_replenish_retry, ath11k_ce_rx_replenish_retry, 0); + init_completion(&ab->htc_suspend); + init_completion(&ab->wow.wakeup_completed); +--- a/drivers/net/wireless/ath/ath11k/core.h ++++ b/drivers/net/wireless/ath/ath11k/core.h +@@ -786,6 +786,10 @@ struct ath11k_base { + + struct ath11k_dbring_cap *db_caps; + u32 num_db_cap; ++ struct work_struct rfkill_work; ++ ++ /* true means radio is on */ ++ bool rfkill_radio_on; + + /* To synchronize 11d scan vdev id */ + struct mutex vdev_id_11d_lock; +--- a/drivers/net/wireless/ath/ath11k/hw.h ++++ b/drivers/net/wireless/ath/ath11k/hw.h +@@ -151,6 +151,9 @@ struct ath11k_hw_params { + u32 svc_to_ce_map_len; + + bool single_pdev_only; ++ u32 rfkill_pin; ++ u32 rfkill_cfg; ++ u32 rfkill_on_level; + + bool rxdma1_enable; + int num_rxmda_per_pdev; +--- a/drivers/net/wireless/ath/ath11k/mac.c ++++ b/drivers/net/wireless/ath/ath11k/mac.c +@@ -5571,6 +5571,63 @@ static int ath11k_mac_mgmt_tx(struct ath + return 0; + } + ++int ath11k_mac_rfkill_config(struct ath11k *ar) ++{ ++ struct ath11k_base *ab = ar->ab; ++ u32 param; ++ int ret; ++ ++ if (ab->hw_params.rfkill_pin == 0) ++ return -EOPNOTSUPP; ++ ++ ath11k_dbg(ab, ATH11K_DBG_MAC, ++ "mac rfkill_pin %d rfkill_cfg %d rfkill_on_level %d", ++ ab->hw_params.rfkill_pin, ab->hw_params.rfkill_cfg, ++ ab->hw_params.rfkill_on_level); ++ ++ param = FIELD_PREP(WMI_RFKILL_CFG_RADIO_LEVEL, ++ ab->hw_params.rfkill_on_level) | ++ FIELD_PREP(WMI_RFKILL_CFG_GPIO_PIN_NUM, ++ ab->hw_params.rfkill_pin) | ++ FIELD_PREP(WMI_RFKILL_CFG_PIN_AS_GPIO, ++ ab->hw_params.rfkill_cfg); ++ ++ ret = ath11k_wmi_pdev_set_param(ar, WMI_PDEV_PARAM_HW_RFKILL_CONFIG, ++ param, ar->pdev->pdev_id); ++ if (ret) { ++ ath11k_warn(ab, ++ "failed to set rfkill config 0x%x: %d\n", ++ param, ret); ++ return ret; ++ } ++ ++ return 0; ++} ++ ++int ath11k_mac_rfkill_enable_radio(struct ath11k *ar, bool enable) ++{ ++ enum wmi_rfkill_enable_radio param; ++ int ret; ++ ++ if (enable) ++ param = WMI_RFKILL_ENABLE_RADIO_ON; ++ else ++ param = WMI_RFKILL_ENABLE_RADIO_OFF; ++ ++ ath11k_dbg(ar->ab, ATH11K_DBG_MAC, "mac %d rfkill enable %d", ++ ar->pdev_idx, param); ++ ++ ret = ath11k_wmi_pdev_set_param(ar, WMI_PDEV_PARAM_RFKILL_ENABLE, ++ param, ar->pdev->pdev_id); ++ if (ret) { ++ ath11k_warn(ar->ab, "failed to set rfkill enable param %d: %d\n", ++ param, ret); ++ return ret; ++ } ++ ++ return 0; ++} ++ + static void ath11k_mac_op_tx(struct ieee80211_hw *hw, + struct ieee80211_tx_control *control, + struct sk_buff *skb) +@@ -5803,6 +5860,7 @@ static void ath11k_mac_op_stop(struct ie + cancel_delayed_work_sync(&ar->scan.timeout); + cancel_work_sync(&ar->regd_update_work); + cancel_work_sync(&ar->ab->update_11d_work); ++ cancel_work_sync(&ar->ab->rfkill_work); + + spin_lock_bh(&ar->data_lock); + list_for_each_entry_safe(ppdu_stats, tmp, &ar->ppdu_stats_info, list) { +--- a/drivers/net/wireless/ath/ath11k/mac.h ++++ b/drivers/net/wireless/ath/ath11k/mac.h +@@ -147,6 +147,8 @@ u8 ath11k_mac_hw_rate_to_idx(const struc + + void __ath11k_mac_scan_finish(struct ath11k *ar); + void ath11k_mac_scan_finish(struct ath11k *ar); ++int ath11k_mac_rfkill_enable_radio(struct ath11k *ar, bool enable); ++int ath11k_mac_rfkill_config(struct ath11k *ar); + + struct ath11k_vif *ath11k_mac_get_arvif(struct ath11k *ar, u32 vdev_id); + struct ath11k_vif *ath11k_mac_get_arvif_by_vdev_id(struct ath11k_base *ab, +--- a/drivers/net/wireless/ath/ath11k/wmi.c ++++ b/drivers/net/wireless/ath/ath11k/wmi.c +@@ -128,6 +128,8 @@ static const struct wmi_tlv_policy wmi_t + = { .min_len = sizeof(struct wmi_peer_assoc_conf_event) }, + [WMI_TAG_STATS_EVENT] + = { .min_len = sizeof(struct wmi_stats_event) }, ++ [WMI_TAG_RFKILL_EVENT] = { ++ .min_len = sizeof(struct wmi_rfkill_state_change_ev) }, + [WMI_TAG_PDEV_CTL_FAILSAFE_CHECK_EVENT] + = { .min_len = sizeof(struct wmi_pdev_ctl_failsafe_chk_event) }, + [WMI_TAG_HOST_SWFDA_EVENT] = { +@@ -524,6 +526,8 @@ static int ath11k_pull_service_ready_tlv + cap->default_dbs_hw_mode_index = ev->default_dbs_hw_mode_index; + cap->num_msdu_desc = ev->num_msdu_desc; + ++ ath11k_dbg(ab, ATH11K_DBG_WMI, "wmi sys cap info 0x%x\n", cap->sys_cap_info); ++ + return 0; + } + +@@ -7334,6 +7338,40 @@ exit: + kfree(tb); + } + ++static void ath11k_rfkill_state_change_event(struct ath11k_base *ab, ++ struct sk_buff *skb) ++{ ++ const struct wmi_rfkill_state_change_ev *ev; ++ const void **tb; ++ int ret; ++ ++ tb = ath11k_wmi_tlv_parse_alloc(ab, skb->data, skb->len, GFP_ATOMIC); ++ if (IS_ERR(tb)) { ++ ret = PTR_ERR(tb); ++ ath11k_warn(ab, "failed to parse tlv: %d\n", ret); ++ return; ++ } ++ ++ ev = tb[WMI_TAG_RFKILL_EVENT]; ++ if (!ev) { ++ kfree(tb); ++ return; ++ } ++ ++ ath11k_dbg(ab, ATH11K_DBG_MAC, ++ "wmi tlv rfkill state change gpio %d type %d radio_state %d\n", ++ ev->gpio_pin_num, ++ ev->int_type, ++ ev->radio_state); ++ ++ spin_lock_bh(&ab->base_lock); ++ ab->rfkill_radio_on = (ev->radio_state == WMI_RFKILL_RADIO_STATE_ON); ++ spin_unlock_bh(&ab->base_lock); ++ ++ queue_work(ab->workqueue, &ab->rfkill_work); ++ kfree(tb); ++} ++ + static void + ath11k_wmi_pdev_temperature_event(struct ath11k_base *ab, + struct sk_buff *skb) +@@ -7606,6 +7644,9 @@ static void ath11k_wmi_tlv_op_rx(struct + case WMI_11D_NEW_COUNTRY_EVENTID: + ath11k_reg_11d_new_cc_event(ab, skb); + break; ++ case WMI_RFKILL_STATE_CHANGE_EVENTID: ++ ath11k_rfkill_state_change_event(ab, skb); ++ break; + /* TODO: Add remaining events */ + default: + ath11k_dbg(ab, ATH11K_DBG_WMI, "Unknown eventid: 0x%x\n", id); +--- a/drivers/net/wireless/ath/ath11k/wmi.h ++++ b/drivers/net/wireless/ath/ath11k/wmi.h +@@ -5215,6 +5215,31 @@ struct target_resource_config { + u32 twt_ap_sta_count; + }; + ++enum wmi_sys_cap_info_flags { ++ WMI_SYS_CAP_INFO_RXTX_LED = BIT(0), ++ WMI_SYS_CAP_INFO_RFKILL = BIT(1), ++}; ++ ++#define WMI_RFKILL_CFG_GPIO_PIN_NUM GENMASK(5, 0) ++#define WMI_RFKILL_CFG_RADIO_LEVEL BIT(6) ++#define WMI_RFKILL_CFG_PIN_AS_GPIO GENMASK(10, 7) ++ ++enum wmi_rfkill_enable_radio { ++ WMI_RFKILL_ENABLE_RADIO_ON = 0, ++ WMI_RFKILL_ENABLE_RADIO_OFF = 1, ++}; ++ ++enum wmi_rfkill_radio_state { ++ WMI_RFKILL_RADIO_STATE_OFF = 1, ++ WMI_RFKILL_RADIO_STATE_ON = 2, ++}; ++ ++struct wmi_rfkill_state_change_ev { ++ u32 gpio_pin_num; ++ u32 int_type; ++ u32 radio_state; ++} __packed; ++ + #define WMI_MAX_MEM_REQS 32 + + #define MAX_RADIOS 3 diff --git a/package/kernel/mac80211/patches/ath11k/0148-ath11k-add-regdb.bin-download-for-regdb-offload.patch b/package/kernel/mac80211/patches/ath11k/0148-ath11k-add-regdb.bin-download-for-regdb-offload.patch new file mode 100644 index 000000000..3ff08d979 --- /dev/null +++ b/package/kernel/mac80211/patches/ath11k/0148-ath11k-add-regdb.bin-download-for-regdb-offload.patch @@ -0,0 +1,256 @@ +From 01417e57939faffebfdeb2aef1f4388e95cf9271 Mon Sep 17 00:00:00 2001 +From: Wen Gong +Date: Mon, 20 Dec 2021 01:23:55 -0500 +Subject: [PATCH 148/151] ath11k: add regdb.bin download for regdb offload + +The regdomain is self-managed type for ath11k, the regdomain info is +reported from firmware, it is not from wireless regdb. Firmware fetch +the regdomain info from board data file before. Currently most of the +regdomain info has moved to another file regdb.bin from board data +file for some chips such as QCA6390 and WCN6855, so the regdomain info +left in board data file is not enough to support the feature which need +more regdomain info. + +After download regdb.bin, firmware will fetch the regdomain info from +regdb.bin instead of board data file and report to ath11k. If it does +not have the file regdb.bin, it also can initialize wlan success and +firmware then fetch regdomain info from board data file. + +Add download the regdb.bin before download board data for some specific +chip which support supports_regdb in hardware parameters. + +download regdb.bin log: +[430082.334162] ath11k_pci 0000:05:00.0: chip_id 0x2 chip_family 0xb board_id 0x106 soc_id 0x400c0200 +[430082.334169] ath11k_pci 0000:05:00.0: fw_version 0x110c8b4c fw_build_timestamp 2021-10-25 07:41 fw_build_id QC_IMAGE_VERSION_STRING=WLAN.HSP.1.1-02892-QCAHSPSWPL_V1_V2_SILICONZ_LITE-3 +[430082.334414] ath11k_pci 0000:05:00.0: boot firmware request ath11k/WCN6855/hw2.0/regdb.bin size 24310 + +output of "iw reg get" +global +country US: DFS-FCC + (2402 - 2472 @ 40), (N/A, 30), (N/A) + (5170 - 5250 @ 80), (N/A, 23), (N/A), AUTO-BW + (5250 - 5330 @ 80), (N/A, 23), (0 ms), DFS, AUTO-BW + (5490 - 5730 @ 160), (N/A, 23), (0 ms), DFS + (5735 - 5835 @ 80), (N/A, 30), (N/A) + (57240 - 63720 @ 2160), (N/A, 40), (N/A) + +phy#0 (self-managed) +country US: DFS-FCC + (2402 - 2472 @ 40), (6, 30), (N/A) + (5170 - 5250 @ 80), (N/A, 24), (N/A), AUTO-BW + (5250 - 5330 @ 80), (N/A, 24), (0 ms), DFS, AUTO-BW + (5490 - 5730 @ 160), (N/A, 24), (0 ms), DFS, AUTO-BW + (5735 - 5895 @ 160), (N/A, 30), (N/A), AUTO-BW + (5945 - 7125 @ 160), (N/A, 24), (N/A), NO-OUTDOOR, AUTO-BW + +Tested-on: QCA6390 hw2.0 PCI WLAN.HST.1.0.1-01740-QCAHSTSWPLZ_V2_TO_X86-1 +Tested-on: WCN6855 hw2.0 PCI WLAN.HSP.1.1-01720.1-QCAHSPSWPL_V1_V2_SILICONZ_LITE-1 + +Signed-off-by: Wen Gong +Signed-off-by: Kalle Valo +Link: https://lore.kernel.org/r/20211220062355.17021-1-quic_wgong@quicinc.com +--- + drivers/net/wireless/ath/ath11k/core.c | 28 ++++++++++++++++++++---- + drivers/net/wireless/ath/ath11k/core.h | 4 ++++ + drivers/net/wireless/ath/ath11k/hw.h | 2 ++ + drivers/net/wireless/ath/ath11k/qmi.c | 30 ++++++++++++++++++-------- + drivers/net/wireless/ath/ath11k/qmi.h | 1 + + 5 files changed, 52 insertions(+), 13 deletions(-) + +--- a/drivers/net/wireless/ath/ath11k/core.c ++++ b/drivers/net/wireless/ath/ath11k/core.c +@@ -87,6 +87,7 @@ static const struct ath11k_hw_params ath + .num_peers = 512, + .supports_suspend = false, + .hal_desc_sz = sizeof(struct hal_rx_desc_ipq8074), ++ .supports_regdb = false, + .fix_l1ss = true, + .credit_flow = false, + .max_tx_ring = DP_TCL_NUM_RING_MAX, +@@ -149,6 +150,7 @@ static const struct ath11k_hw_params ath + .num_peers = 512, + .supports_suspend = false, + .hal_desc_sz = sizeof(struct hal_rx_desc_ipq8074), ++ .supports_regdb = false, + .fix_l1ss = true, + .credit_flow = false, + .max_tx_ring = DP_TCL_NUM_RING_MAX, +@@ -210,6 +212,7 @@ static const struct ath11k_hw_params ath + .num_peers = 512, + .supports_suspend = true, + .hal_desc_sz = sizeof(struct hal_rx_desc_ipq8074), ++ .supports_regdb = true, + .fix_l1ss = true, + .credit_flow = true, + .max_tx_ring = DP_TCL_NUM_RING_MAX_QCA6390, +@@ -271,6 +274,7 @@ static const struct ath11k_hw_params ath + .num_peers = 128, + .supports_suspend = false, + .hal_desc_sz = sizeof(struct hal_rx_desc_qcn9074), ++ .supports_regdb = false, + .fix_l1ss = true, + .credit_flow = false, + .max_tx_ring = DP_TCL_NUM_RING_MAX, +@@ -332,6 +336,7 @@ static const struct ath11k_hw_params ath + .num_peers = 512, + .supports_suspend = true, + .hal_desc_sz = sizeof(struct hal_rx_desc_wcn6855), ++ .supports_regdb = true, + .fix_l1ss = false, + .credit_flow = true, + .max_tx_ring = DP_TCL_NUM_RING_MAX_QCA6390, +@@ -392,6 +397,7 @@ static const struct ath11k_hw_params ath + .num_peers = 512, + .supports_suspend = true, + .hal_desc_sz = sizeof(struct hal_rx_desc_wcn6855), ++ .supports_regdb = true, + .fix_l1ss = false, + .credit_flow = true, + .max_tx_ring = DP_TCL_NUM_RING_MAX_QCA6390, +@@ -760,10 +766,12 @@ err: + return ret; + } + +-static int ath11k_core_fetch_board_data_api_1(struct ath11k_base *ab, +- struct ath11k_board_data *bd) ++int ath11k_core_fetch_board_data_api_1(struct ath11k_base *ab, ++ struct ath11k_board_data *bd, ++ const char *name) + { +- bd->fw = ath11k_core_firmware_request(ab, ATH11K_DEFAULT_BOARD_FILE); ++ bd->fw = ath11k_core_firmware_request(ab, name); ++ + if (IS_ERR(bd->fw)) + return PTR_ERR(bd->fw); + +@@ -791,7 +799,7 @@ int ath11k_core_fetch_bdf(struct ath11k_ + goto success; + + ab->bd_api = 1; +- ret = ath11k_core_fetch_board_data_api_1(ab, bd); ++ ret = ath11k_core_fetch_board_data_api_1(ab, bd, ATH11K_DEFAULT_BOARD_FILE); + if (ret) { + ath11k_err(ab, "failed to fetch board-2.bin or board.bin from %s\n", + ab->hw_params.fw.dir); +@@ -803,6 +811,18 @@ success: + return 0; + } + ++int ath11k_core_fetch_regdb(struct ath11k_base *ab, struct ath11k_board_data *bd) ++{ ++ int ret; ++ ++ ret = ath11k_core_fetch_board_data_api_1(ab, bd, ATH11K_REGDB_FILE_NAME); ++ if (ret) ++ ath11k_dbg(ab, ATH11K_DBG_BOOT, "failed to fetch %s from %s\n", ++ ATH11K_REGDB_FILE_NAME, ab->hw_params.fw.dir); ++ ++ return ret; ++} ++ + static void ath11k_core_stop(struct ath11k_base *ab) + { + if (!test_bit(ATH11K_FLAG_CRASH_FLUSH, &ab->dev_flags)) +--- a/drivers/net/wireless/ath/ath11k/core.h ++++ b/drivers/net/wireless/ath/ath11k/core.h +@@ -980,6 +980,10 @@ struct ath11k_base *ath11k_core_alloc(st + void ath11k_core_free(struct ath11k_base *ath11k); + int ath11k_core_fetch_bdf(struct ath11k_base *ath11k, + struct ath11k_board_data *bd); ++int ath11k_core_fetch_regdb(struct ath11k_base *ab, struct ath11k_board_data *bd); ++int ath11k_core_fetch_board_data_api_1(struct ath11k_base *ab, ++ struct ath11k_board_data *bd, ++ const char *name); + void ath11k_core_free_bdf(struct ath11k_base *ab, struct ath11k_board_data *bd); + int ath11k_core_check_dt(struct ath11k_base *ath11k); + +--- a/drivers/net/wireless/ath/ath11k/hw.h ++++ b/drivers/net/wireless/ath/ath11k/hw.h +@@ -77,6 +77,7 @@ + #define ATH11K_DEFAULT_CAL_FILE "caldata.bin" + #define ATH11K_AMSS_FILE "amss.bin" + #define ATH11K_M3_FILE "m3.bin" ++#define ATH11K_REGDB_FILE_NAME "regdb.bin" + + enum ath11k_hw_rate_cck { + ATH11K_HW_RATE_CCK_LP_11M = 0, +@@ -181,6 +182,7 @@ struct ath11k_hw_params { + u32 num_peers; + bool supports_suspend; + u32 hal_desc_sz; ++ bool supports_regdb; + bool fix_l1ss; + bool credit_flow; + u8 max_tx_ring; +--- a/drivers/net/wireless/ath/ath11k/qmi.c ++++ b/drivers/net/wireless/ath/ath11k/qmi.c +@@ -2161,7 +2161,8 @@ err_free_req: + return ret; + } + +-static int ath11k_qmi_load_bdf_qmi(struct ath11k_base *ab) ++static int ath11k_qmi_load_bdf_qmi(struct ath11k_base *ab, ++ bool regdb) + { + struct device *dev = ab->dev; + char filename[ATH11K_QMI_MAX_BDF_FILE_NAME_SIZE]; +@@ -2172,13 +2173,21 @@ static int ath11k_qmi_load_bdf_qmi(struc + const u8 *tmp; + + memset(&bd, 0, sizeof(bd)); +- ret = ath11k_core_fetch_bdf(ab, &bd); +- if (ret) { +- ath11k_warn(ab, "qmi failed to fetch board file: %d\n", ret); +- goto out; ++ ++ if (regdb) { ++ ret = ath11k_core_fetch_regdb(ab, &bd); ++ } else { ++ ret = ath11k_core_fetch_bdf(ab, &bd); ++ if (ret) ++ ath11k_warn(ab, "qmi failed to fetch board file: %d\n", ret); + } + +- if (bd.len >= SELFMAG && memcmp(bd.data, ELFMAG, SELFMAG) == 0) ++ if (ret) ++ goto out; ++ ++ if (regdb) ++ bdf_type = ATH11K_QMI_BDF_TYPE_REGDB; ++ else if (bd.len >= SELFMAG && memcmp(bd.data, ELFMAG, SELFMAG) == 0) + bdf_type = ATH11K_QMI_BDF_TYPE_ELF; + else + bdf_type = ATH11K_QMI_BDF_TYPE_BIN; +@@ -2193,8 +2202,8 @@ static int ath11k_qmi_load_bdf_qmi(struc + goto out; + } + +- /* QCA6390 does not support cal data, skip it */ +- if (bdf_type == ATH11K_QMI_BDF_TYPE_ELF) ++ /* QCA6390/WCN6855 does not support cal data, skip it */ ++ if (bdf_type == ATH11K_QMI_BDF_TYPE_ELF || bdf_type == ATH11K_QMI_BDF_TYPE_REGDB) + goto out; + + if (ab->qmi.target.eeprom_caldata) { +@@ -2626,7 +2635,10 @@ static int ath11k_qmi_event_load_bdf(str + return ret; + } + +- ret = ath11k_qmi_load_bdf_qmi(ab); ++ if (ab->hw_params.supports_regdb) ++ ath11k_qmi_load_bdf_qmi(ab, true); ++ ++ ret = ath11k_qmi_load_bdf_qmi(ab, false); + if (ret < 0) { + ath11k_warn(ab, "failed to load board data file: %d\n", ret); + return ret; +--- a/drivers/net/wireless/ath/ath11k/qmi.h ++++ b/drivers/net/wireless/ath/ath11k/qmi.h +@@ -48,6 +48,7 @@ enum ath11k_qmi_file_type { + enum ath11k_qmi_bdf_type { + ATH11K_QMI_BDF_TYPE_BIN = 0, + ATH11K_QMI_BDF_TYPE_ELF = 1, ++ ATH11K_QMI_BDF_TYPE_REGDB = 4, + }; + + enum ath11k_qmi_event_type { diff --git a/package/kernel/mac80211/patches/ath11k/0149-ath11k-Fix-napi-related-hang.patch b/package/kernel/mac80211/patches/ath11k/0149-ath11k-Fix-napi-related-hang.patch new file mode 100644 index 000000000..32a9c569d --- /dev/null +++ b/package/kernel/mac80211/patches/ath11k/0149-ath11k-Fix-napi-related-hang.patch @@ -0,0 +1,95 @@ +From d943fdad7589653065be0e20aadc6dff37725ed4 Mon Sep 17 00:00:00 2001 +From: Ben Greear +Date: Thu, 3 Sep 2020 12:52:54 -0700 +Subject: [PATCH 149/151] ath11k: Fix napi related hang + +Similar to the same bug in ath10k, a napi disable w/out it being enabled +will hang forever. I believe I saw this while trying rmmod after driver +had some failure on startup. Fix it by keeping state on whether napi is +enabled or not. + +And, remove un-used napi pointer in ath11k driver base struct. + +Signed-off-by: Ben Greear +Signed-off-by: Kalle Valo +Link: https://lore.kernel.org/r/20200903195254.29379-1-greearb@candelatech.com +--- + drivers/net/wireless/ath/ath11k/ahb.c | 12 +++++++++--- + drivers/net/wireless/ath/ath11k/core.h | 2 +- + drivers/net/wireless/ath/ath11k/pci.c | 12 +++++++++--- + 3 files changed, 19 insertions(+), 7 deletions(-) + +--- a/drivers/net/wireless/ath/ath11k/ahb.c ++++ b/drivers/net/wireless/ath/ath11k/ahb.c +@@ -175,8 +175,11 @@ static void __ath11k_ahb_ext_irq_disable + + ath11k_ahb_ext_grp_disable(irq_grp); + +- napi_synchronize(&irq_grp->napi); +- napi_disable(&irq_grp->napi); ++ if (irq_grp->napi_enabled) { ++ napi_synchronize(&irq_grp->napi); ++ napi_disable(&irq_grp->napi); ++ irq_grp->napi_enabled = false; ++ } + } + } + +@@ -300,7 +303,10 @@ static void ath11k_ahb_ext_irq_enable(st + for (i = 0; i < ATH11K_EXT_IRQ_GRP_NUM_MAX; i++) { + struct ath11k_ext_irq_grp *irq_grp = &ab->ext_irq_grp[i]; + +- napi_enable(&irq_grp->napi); ++ if (!irq_grp->napi_enabled) { ++ napi_enable(&irq_grp->napi); ++ irq_grp->napi_enabled = true; ++ } + ath11k_ahb_ext_grp_enable(irq_grp); + } + } +--- a/drivers/net/wireless/ath/ath11k/core.h ++++ b/drivers/net/wireless/ath/ath11k/core.h +@@ -142,6 +142,7 @@ struct ath11k_ext_irq_grp { + u32 num_irq; + u32 grp_id; + u64 timestamp; ++ bool napi_enabled; + struct napi_struct napi; + struct net_device napi_ndev; + }; +@@ -743,7 +744,6 @@ struct ath11k_base { + u32 wlan_init_status; + int irq_num[ATH11K_IRQ_NUM_MAX]; + struct ath11k_ext_irq_grp ext_irq_grp[ATH11K_EXT_IRQ_GRP_NUM_MAX]; +- struct napi_struct *napi; + struct ath11k_targ_cap target_caps; + u32 ext_service_bitmap[WMI_SERVICE_EXT_BM_SIZE]; + bool pdevs_macaddr_valid; +--- a/drivers/net/wireless/ath/ath11k/pci.c ++++ b/drivers/net/wireless/ath/ath11k/pci.c +@@ -683,8 +683,11 @@ static void __ath11k_pci_ext_irq_disable + + ath11k_pci_ext_grp_disable(irq_grp); + +- napi_synchronize(&irq_grp->napi); +- napi_disable(&irq_grp->napi); ++ if (irq_grp->napi_enabled) { ++ napi_synchronize(&irq_grp->napi); ++ napi_disable(&irq_grp->napi); ++ irq_grp->napi_enabled = false; ++ } + } + } + +@@ -712,7 +715,10 @@ static void ath11k_pci_ext_irq_enable(st + for (i = 0; i < ATH11K_EXT_IRQ_GRP_NUM_MAX; i++) { + struct ath11k_ext_irq_grp *irq_grp = &ab->ext_irq_grp[i]; + +- napi_enable(&irq_grp->napi); ++ if (!irq_grp->napi_enabled) { ++ napi_enable(&irq_grp->napi); ++ irq_grp->napi_enabled = true; ++ } + ath11k_pci_ext_grp_enable(irq_grp); + } + } diff --git a/package/kernel/mac80211/patches/ath11k/0150-ath11k-add-support-of-firmware-logging-for-WCN6855.patch b/package/kernel/mac80211/patches/ath11k/0150-ath11k-add-support-of-firmware-logging-for-WCN6855.patch new file mode 100644 index 000000000..182ddf131 --- /dev/null +++ b/package/kernel/mac80211/patches/ath11k/0150-ath11k-add-support-of-firmware-logging-for-WCN6855.patch @@ -0,0 +1,295 @@ +From 42da1cc7bd537ea63ddebf88aedcdafcccb00131 Mon Sep 17 00:00:00 2001 +From: Cheng Wang +Date: Mon, 20 Dec 2021 20:10:53 +0800 +Subject: [PATCH 150/151] ath11k: add support of firmware logging for WCN6855 + +Host enables WMI firmware logging feature via QMI message. +Host receives firmware logging messages on WMI_DIAG_EVENTID, then +sends logging messages to user space via event tracing infrastructure. + +Tested-on: WCN6855 hw2.0 PCI WLAN.HSP.1.1-01720.1-QCAHSPSWPL_V1_V2_SILICONZ_LITE-1 + +Signed-off-by: Cheng Wang +Signed-off-by: Kalle Valo +Link: https://lore.kernel.org/r/20211220121053.357087-1-quic_chengwan@quicinc.com +--- + drivers/net/wireless/ath/ath11k/core.c | 6 ++ + drivers/net/wireless/ath/ath11k/hw.h | 1 + + drivers/net/wireless/ath/ath11k/qmi.c | 94 +++++++++++++++++++++++++ + drivers/net/wireless/ath/ath11k/qmi.h | 12 ++++ + drivers/net/wireless/ath/ath11k/trace.h | 28 ++++++++ + drivers/net/wireless/ath/ath11k/wmi.c | 10 +++ + 6 files changed, 151 insertions(+) + +--- a/drivers/net/wireless/ath/ath11k/core.c ++++ b/drivers/net/wireless/ath/ath11k/core.c +@@ -96,6 +96,7 @@ static const struct ath11k_hw_params ath + .alloc_cacheable_memory = true, + .wakeup_mhi = false, + .supports_rssi_stats = false, ++ .fw_wmi_diag_event = false, + }, + { + .hw_rev = ATH11K_HW_IPQ6018_HW10, +@@ -159,6 +160,7 @@ static const struct ath11k_hw_params ath + .alloc_cacheable_memory = true, + .wakeup_mhi = false, + .supports_rssi_stats = false, ++ .fw_wmi_diag_event = false, + }, + { + .name = "qca6390 hw2.0", +@@ -221,6 +223,7 @@ static const struct ath11k_hw_params ath + .alloc_cacheable_memory = false, + .wakeup_mhi = true, + .supports_rssi_stats = true, ++ .fw_wmi_diag_event = true, + }, + { + .name = "qcn9074 hw1.0", +@@ -283,6 +286,7 @@ static const struct ath11k_hw_params ath + .alloc_cacheable_memory = true, + .wakeup_mhi = false, + .supports_rssi_stats = false, ++ .fw_wmi_diag_event = false, + }, + { + .name = "wcn6855 hw2.0", +@@ -345,6 +349,7 @@ static const struct ath11k_hw_params ath + .alloc_cacheable_memory = false, + .wakeup_mhi = true, + .supports_rssi_stats = true, ++ .fw_wmi_diag_event = true, + }, + { + .name = "wcn6855 hw2.1", +@@ -406,6 +411,7 @@ static const struct ath11k_hw_params ath + .alloc_cacheable_memory = false, + .wakeup_mhi = true, + .supports_rssi_stats = true, ++ .fw_wmi_diag_event = true, + }, + }; + +--- a/drivers/net/wireless/ath/ath11k/hw.h ++++ b/drivers/net/wireless/ath/ath11k/hw.h +@@ -191,6 +191,7 @@ struct ath11k_hw_params { + bool alloc_cacheable_memory; + bool wakeup_mhi; + bool supports_rssi_stats; ++ bool fw_wmi_diag_event; + }; + + struct ath11k_hw_ops { +--- a/drivers/net/wireless/ath/ath11k/qmi.c ++++ b/drivers/net/wireless/ath/ath11k/qmi.c +@@ -1584,6 +1584,50 @@ static struct qmi_elem_info qmi_wlanfw_c + }, + }; + ++static struct qmi_elem_info qmi_wlanfw_wlan_ini_req_msg_v01_ei[] = { ++ { ++ .data_type = QMI_OPT_FLAG, ++ .elem_len = 1, ++ .elem_size = sizeof(u8), ++ .array_type = NO_ARRAY, ++ .tlv_type = 0x10, ++ .offset = offsetof(struct qmi_wlanfw_wlan_ini_req_msg_v01, ++ enablefwlog_valid), ++ }, ++ { ++ .data_type = QMI_UNSIGNED_1_BYTE, ++ .elem_len = 1, ++ .elem_size = sizeof(u8), ++ .array_type = NO_ARRAY, ++ .tlv_type = 0x10, ++ .offset = offsetof(struct qmi_wlanfw_wlan_ini_req_msg_v01, ++ enablefwlog), ++ }, ++ { ++ .data_type = QMI_EOTI, ++ .array_type = NO_ARRAY, ++ .tlv_type = QMI_COMMON_TLV_TYPE, ++ }, ++}; ++ ++static struct qmi_elem_info qmi_wlanfw_wlan_ini_resp_msg_v01_ei[] = { ++ { ++ .data_type = QMI_STRUCT, ++ .elem_len = 1, ++ .elem_size = sizeof(struct qmi_response_type_v01), ++ .array_type = NO_ARRAY, ++ .tlv_type = 0x02, ++ .offset = offsetof(struct qmi_wlanfw_wlan_ini_resp_msg_v01, ++ resp), ++ .ei_array = qmi_response_type_v01_ei, ++ }, ++ { ++ .data_type = QMI_EOTI, ++ .array_type = NO_ARRAY, ++ .tlv_type = QMI_COMMON_TLV_TYPE, ++ }, ++}; ++ + static int ath11k_qmi_host_cap_send(struct ath11k_base *ab) + { + struct qmi_wlanfw_host_cap_req_msg_v01 req; +@@ -2504,6 +2548,48 @@ out: + return ret; + } + ++static int ath11k_qmi_wlanfw_wlan_ini_send(struct ath11k_base *ab, bool enable) ++{ ++ int ret; ++ struct qmi_txn txn; ++ struct qmi_wlanfw_wlan_ini_req_msg_v01 req = {}; ++ struct qmi_wlanfw_wlan_ini_resp_msg_v01 resp = {}; ++ ++ req.enablefwlog_valid = true; ++ req.enablefwlog = enable ? 1 : 0; ++ ++ ret = qmi_txn_init(&ab->qmi.handle, &txn, ++ qmi_wlanfw_wlan_ini_resp_msg_v01_ei, &resp); ++ if (ret < 0) ++ goto out; ++ ++ ret = qmi_send_request(&ab->qmi.handle, NULL, &txn, ++ QMI_WLANFW_WLAN_INI_REQ_V01, ++ QMI_WLANFW_WLAN_INI_REQ_MSG_V01_MAX_LEN, ++ qmi_wlanfw_wlan_ini_req_msg_v01_ei, &req); ++ if (ret < 0) { ++ ath11k_warn(ab, "qmi failed to send wlan ini request, err = %d\n", ++ ret); ++ qmi_txn_cancel(&txn); ++ goto out; ++ } ++ ++ ret = qmi_txn_wait(&txn, msecs_to_jiffies(ATH11K_QMI_WLANFW_TIMEOUT_MS)); ++ if (ret < 0) { ++ ath11k_warn(ab, "qmi failed wlan ini request, err = %d\n", ret); ++ goto out; ++ } ++ ++ if (resp.resp.result != QMI_RESULT_SUCCESS_V01) { ++ ath11k_warn(ab, "qmi wlan ini request failed, result: %d, err: %d\n", ++ resp.resp.result, resp.resp.error); ++ ret = -EINVAL; ++ } ++ ++out: ++ return ret; ++} ++ + void ath11k_qmi_firmware_stop(struct ath11k_base *ab) + { + int ret; +@@ -2524,6 +2610,14 @@ int ath11k_qmi_firmware_start(struct ath + + ath11k_dbg(ab, ATH11K_DBG_QMI, "qmi firmware start\n"); + ++ if (ab->hw_params.fw_wmi_diag_event) { ++ ret = ath11k_qmi_wlanfw_wlan_ini_send(ab, true); ++ if (ret < 0) { ++ ath11k_warn(ab, "qmi failed to send wlan fw ini:%d\n", ret); ++ return ret; ++ } ++ } ++ + ret = ath11k_qmi_wlanfw_wlan_cfg_send(ab); + if (ret < 0) { + ath11k_warn(ab, "qmi failed to send wlan cfg: %d\n", ret); +--- a/drivers/net/wireless/ath/ath11k/qmi.h ++++ b/drivers/net/wireless/ath/ath11k/qmi.h +@@ -428,10 +428,12 @@ struct qmi_wlanfw_m3_info_resp_msg_v01 { + #define QMI_WLANFW_WLAN_MODE_RESP_MSG_V01_MAX_LEN 7 + #define QMI_WLANFW_WLAN_CFG_REQ_MSG_V01_MAX_LEN 803 + #define QMI_WLANFW_WLAN_CFG_RESP_MSG_V01_MAX_LEN 7 ++#define QMI_WLANFW_WLAN_INI_REQ_MSG_V01_MAX_LEN 4 + #define QMI_WLANFW_WLAN_MODE_REQ_V01 0x0022 + #define QMI_WLANFW_WLAN_MODE_RESP_V01 0x0022 + #define QMI_WLANFW_WLAN_CFG_REQ_V01 0x0023 + #define QMI_WLANFW_WLAN_CFG_RESP_V01 0x0023 ++#define QMI_WLANFW_WLAN_INI_REQ_V01 0x002F + #define QMI_WLANFW_MAX_STR_LEN_V01 16 + #define QMI_WLANFW_MAX_NUM_CE_V01 12 + #define QMI_WLANFW_MAX_NUM_SVC_V01 24 +@@ -473,6 +475,16 @@ struct qmi_wlanfw_wlan_cfg_resp_msg_v01 + struct qmi_response_type_v01 resp; + }; + ++struct qmi_wlanfw_wlan_ini_req_msg_v01 { ++ /* Must be set to true if enablefwlog is being passed */ ++ u8 enablefwlog_valid; ++ u8 enablefwlog; ++}; ++ ++struct qmi_wlanfw_wlan_ini_resp_msg_v01 { ++ struct qmi_response_type_v01 resp; ++}; ++ + int ath11k_qmi_firmware_start(struct ath11k_base *ab, + u32 mode); + void ath11k_qmi_firmware_stop(struct ath11k_base *ab); +--- a/drivers/net/wireless/ath/ath11k/trace.h ++++ b/drivers/net/wireless/ath/ath11k/trace.h +@@ -280,6 +280,34 @@ TRACE_EVENT(ath11k_log_dbg_dump, + __get_str(msg) + ) + ); ++ ++TRACE_EVENT(ath11k_wmi_diag, ++ TP_PROTO(struct ath11k_base *ab, const void *data, size_t len), ++ ++ TP_ARGS(ab, data, len), ++ ++ TP_STRUCT__entry( ++ __string(device, dev_name(ab->dev)) ++ __string(driver, dev_driver_string(ab->dev)) ++ __field(u16, len) ++ __dynamic_array(u8, data, len) ++ ), ++ ++ TP_fast_assign( ++ __assign_str(device, dev_name(ab->dev)); ++ __assign_str(driver, dev_driver_string(ab->dev)); ++ __entry->len = len; ++ memcpy(__get_dynamic_array(data), data, len); ++ ), ++ ++ TP_printk( ++ "%s %s tlv diag len %d", ++ __get_str(driver), ++ __get_str(device), ++ __entry->len ++ ) ++); ++ + #endif /* _TRACE_H_ || TRACE_HEADER_MULTI_READ*/ + + /* we don't want to use include/trace/events */ +--- a/drivers/net/wireless/ath/ath11k/wmi.c ++++ b/drivers/net/wireless/ath/ath11k/wmi.c +@@ -7525,6 +7525,13 @@ static void ath11k_wmi_event_wow_wakeup_ + complete(&ab->wow.wakeup_completed); + } + ++static void ++ath11k_wmi_diag_event(struct ath11k_base *ab, ++ struct sk_buff *skb) ++{ ++ trace_ath11k_wmi_diag(ab, skb->data, skb->len); ++} ++ + static void ath11k_wmi_tlv_op_rx(struct ath11k_base *ab, struct sk_buff *skb) + { + struct wmi_cmd_hdr *cmd_hdr; +@@ -7647,6 +7654,9 @@ static void ath11k_wmi_tlv_op_rx(struct + case WMI_RFKILL_STATE_CHANGE_EVENTID: + ath11k_rfkill_state_change_event(ab, skb); + break; ++ case WMI_DIAG_EVENTID: ++ ath11k_wmi_diag_event(ab, skb); ++ break; + /* TODO: Add remaining events */ + default: + ath11k_dbg(ab, ATH11K_DBG_WMI, "Unknown eventid: 0x%x\n", id); diff --git a/package/kernel/mac80211/patches/ath11k/0151-ath11k-Fix-unexpected-return-buffer-manager-error-fo.patch b/package/kernel/mac80211/patches/ath11k/0151-ath11k-Fix-unexpected-return-buffer-manager-error-fo.patch new file mode 100644 index 000000000..ca944f891 --- /dev/null +++ b/package/kernel/mac80211/patches/ath11k/0151-ath11k-Fix-unexpected-return-buffer-manager-error-fo.patch @@ -0,0 +1,58 @@ +From 71c748b5e01e3e28838a8e26a8966fb5adb03df7 Mon Sep 17 00:00:00 2001 +From: Baochen Qiang +Date: Wed, 22 Dec 2021 09:35:35 +0800 +Subject: [PATCH 151/151] ath11k: Fix unexpected return buffer manager error + for QCA6390 + +We are seeing below error on QCA6390: +... +[70211.671189] ath11k_pci 0000:72:00.0: failed to parse rx error in wbm_rel ring desc -22 +[70212.696154] ath11k_pci 0000:72:00.0: failed to parse rx error in wbm_rel ring desc -22 +[70213.092941] ath11k_pci 0000:72:00.0: failed to parse rx error in wbm_rel ring desc -22 +... + +The reason is that, with commit 734223d78428 ("ath11k: change return +buffer manager for QCA6390"), ath11k expects the return buffer manager +(RBM) field of descriptor configured as HAL_RX_BUF_RBM_SW1_BM when +parsing error frames from WBM2SW3_RELEASE ring. This is a wrong change +cause the RBM field is set as HAL_RX_BUF_RBM_SW3_BM. + +The same issue also applies to REO2TCL ring though we have not got any +error reported. + +Fix it by changing RBM from HAL_RX_BUF_RBM_SW1_BM to HAL_RX_BUF_RBM_SW3_BM +for these two rings. + +Tested-on: QCA6390 hw2.0 PCI WLAN.HST.1.0.1-01740-QCAHSTSWPLZ_V2_TO_X86-1 + +Fixes: 734223d78428 ("ath11k: change return buffer manager for QCA6390") +Signed-off-by: Baochen Qiang +Signed-off-by: Kalle Valo +Link: https://lore.kernel.org/r/20211222013536.582527-1-quic_bqiang@quicinc.com +--- + drivers/net/wireless/ath/ath11k/dp_rx.c | 2 +- + drivers/net/wireless/ath/ath11k/hal_rx.c | 2 +- + 2 files changed, 2 insertions(+), 2 deletions(-) + +--- a/drivers/net/wireless/ath/ath11k/dp_rx.c ++++ b/drivers/net/wireless/ath/ath11k/dp_rx.c +@@ -3837,7 +3837,7 @@ int ath11k_dp_process_rx_err(struct ath1 + ath11k_hal_rx_msdu_link_info_get(link_desc_va, &num_msdus, msdu_cookies, + &rbm); + if (rbm != HAL_RX_BUF_RBM_WBM_IDLE_DESC_LIST && +- rbm != ab->hw_params.hal_params->rx_buf_rbm) { ++ rbm != HAL_RX_BUF_RBM_SW3_BM) { + ab->soc_stats.invalid_rbm++; + ath11k_warn(ab, "invalid return buffer manager %d\n", rbm); + ath11k_dp_rx_link_desc_return(ab, desc, +--- a/drivers/net/wireless/ath/ath11k/hal_rx.c ++++ b/drivers/net/wireless/ath/ath11k/hal_rx.c +@@ -374,7 +374,7 @@ int ath11k_hal_wbm_desc_parse_err(struct + + ret_buf_mgr = FIELD_GET(BUFFER_ADDR_INFO1_RET_BUF_MGR, + wbm_desc->buf_addr_info.info1); +- if (ret_buf_mgr != ab->hw_params.hal_params->rx_buf_rbm) { ++ if (ret_buf_mgr != HAL_RX_BUF_RBM_SW3_BM) { + ab->soc_stats.invalid_rbm++; + return -EINVAL; + } diff --git a/package/kernel/mac80211/patches/ath11k/0152-ath11k-add-missing-of_node_put-to-avoid-leak.patch b/package/kernel/mac80211/patches/ath11k/0152-ath11k-add-missing-of_node_put-to-avoid-leak.patch new file mode 100644 index 000000000..8a49bb08c --- /dev/null +++ b/package/kernel/mac80211/patches/ath11k/0152-ath11k-add-missing-of_node_put-to-avoid-leak.patch @@ -0,0 +1,39 @@ +From 3d38faef0de1756994b3d95e47b2302842f729e2 Mon Sep 17 00:00:00 2001 +From: Yang Yingliang +Date: Mon, 10 Jan 2022 16:24:13 +0200 +Subject: [PATCH 152/154] ath11k: add missing of_node_put() to avoid leak + +The node pointer is returned by of_find_node_by_type() +or of_parse_phandle() with refcount incremented. Calling +of_node_put() to aovid the refcount leak. + +Fixes: 6ac04bdc5edb ("ath11k: Use reserved host DDR addresses from DT for PCI devices") +Reported-by: Hulk Robot +Signed-off-by: Yang Yingliang +Signed-off-by: Kalle Valo +Link: https://lore.kernel.org/r/20211221114003.335557-1-yangyingliang@huawei.com +--- + drivers/net/wireless/ath/ath11k/mhi.c | 1 + + drivers/net/wireless/ath/ath11k/qmi.c | 1 + + 2 files changed, 2 insertions(+) + +--- a/drivers/net/wireless/ath/ath11k/mhi.c ++++ b/drivers/net/wireless/ath/ath11k/mhi.c +@@ -332,6 +332,7 @@ static int ath11k_mhi_read_addr_from_dt( + return -ENOENT; + + ret = of_address_to_resource(np, 0, &res); ++ of_node_put(np); + if (ret) + return ret; + +--- a/drivers/net/wireless/ath/ath11k/qmi.c ++++ b/drivers/net/wireless/ath/ath11k/qmi.c +@@ -1936,6 +1936,7 @@ static int ath11k_qmi_assign_target_mem_ + } + + ret = of_address_to_resource(hremote_node, 0, &res); ++ of_node_put(hremote_node); + if (ret) { + ath11k_dbg(ab, ATH11K_DBG_QMI, + "qmi fail to get reg from hremote\n"); diff --git a/package/kernel/mac80211/patches/ath11k/0153-ath11k-fix-workqueue-not-getting-destroyed-after-rmm.patch b/package/kernel/mac80211/patches/ath11k/0153-ath11k-fix-workqueue-not-getting-destroyed-after-rmm.patch new file mode 100644 index 000000000..443ee1be0 --- /dev/null +++ b/package/kernel/mac80211/patches/ath11k/0153-ath11k-fix-workqueue-not-getting-destroyed-after-rmm.patch @@ -0,0 +1,44 @@ +From 9f4ecacf2fa47b8aadd9bca2e88cde01856de028 Mon Sep 17 00:00:00 2001 +From: Aditya Kumar Singh +Date: Mon, 10 Jan 2022 16:24:14 +0200 +Subject: [PATCH 153/154] ath11k: fix workqueue not getting destroyed after + rmmod + +Currently, ath11k_core_alloc() creates a single thread workqueue. +This workqueue is not detroyed during clean up when ath11k modules +are unloaded from the kernel and is left as it is. +If workqueue is not destroyed, it could lead to kernel +memory scarcity in a longer run. This could affect self and +other drivers workability as well. + +Add destroy workqueue in ath11k_core_free(). + +Tested on: IPQ8074 WLAN.HK.2.4.0.1-01746-QCAHKSWPL_SILICONZ-1 + +Signed-off-by: Aditya Kumar Singh +Signed-off-by: Kalle Valo +Link: https://lore.kernel.org/r/1640231787-17408-1-git-send-email-quic_adisi@quicinc.com +--- + drivers/net/wireless/ath/ath11k/core.c | 4 ++++ + 1 file changed, 4 insertions(+) + +--- a/drivers/net/wireless/ath/ath11k/core.c ++++ b/drivers/net/wireless/ath/ath11k/core.c +@@ -1,6 +1,7 @@ + // SPDX-License-Identifier: BSD-3-Clause-Clear + /* + * Copyright (c) 2018-2019 The Linux Foundation. All rights reserved. ++ * Copyright (c) 2021 Qualcomm Innovation Center, Inc. All rights reserved. + */ + + #include +@@ -1404,6 +1405,9 @@ EXPORT_SYMBOL(ath11k_core_deinit); + + void ath11k_core_free(struct ath11k_base *ab) + { ++ flush_workqueue(ab->workqueue); ++ destroy_workqueue(ab->workqueue); ++ + kfree(ab); + } + EXPORT_SYMBOL(ath11k_core_free); diff --git a/package/kernel/mac80211/patches/ath11k/0154-ath11k-Refactor-the-fallback-routine-when-peer-creat.patch b/package/kernel/mac80211/patches/ath11k/0154-ath11k-Refactor-the-fallback-routine-when-peer-creat.patch new file mode 100644 index 000000000..a2bafb5dc --- /dev/null +++ b/package/kernel/mac80211/patches/ath11k/0154-ath11k-Refactor-the-fallback-routine-when-peer-creat.patch @@ -0,0 +1,83 @@ +From fbed57d897f6ea065c45806959337a6f28d2a94d Mon Sep 17 00:00:00 2001 +From: Karthikeyan Periyasamy +Date: Mon, 10 Jan 2022 16:24:14 +0200 +Subject: [PATCH 154/154] ath11k: Refactor the fallback routine when peer + create fails + +When there is an error in peer create process from +ath11k_peer_find(), the code attempts to handle a fallback +for peer create. When this fallback fails, the driver returns +the fallback return code rather than actual error code +(-ENOENT). So refactor the fallback routine to return +the actual error code. + +Tested-on: QCN9074 hw1.0 PCI WLAN.HK.2.5.0.1-01067-QCAHKSWPL_SILICONZ-1 + +Signed-off-by: Karthikeyan Periyasamy +Signed-off-by: Kalle Valo +Link: https://lore.kernel.org/r/1640244819-21183-1-git-send-email-quic_periyasa@quicinc.com +--- + drivers/net/wireless/ath/ath11k/peer.c | 40 +++++++++++++++----------- + 1 file changed, 23 insertions(+), 17 deletions(-) + +--- a/drivers/net/wireless/ath/ath11k/peer.c ++++ b/drivers/net/wireless/ath/ath11k/peer.c +@@ -252,7 +252,7 @@ int ath11k_peer_create(struct ath11k *ar + { + struct ath11k_peer *peer; + struct ath11k_sta *arsta; +- int ret; ++ int ret, fbret; + + lockdep_assert_held(&ar->conf_mutex); + +@@ -291,22 +291,8 @@ int ath11k_peer_create(struct ath11k *ar + ath11k_warn(ar->ab, "failed to find peer %pM on vdev %i after creation\n", + param->peer_addr, param->vdev_id); + +- reinit_completion(&ar->peer_delete_done); +- +- ret = ath11k_wmi_send_peer_delete_cmd(ar, param->peer_addr, +- param->vdev_id); +- if (ret) { +- ath11k_warn(ar->ab, "failed to delete peer vdev_id %d addr %pM\n", +- param->vdev_id, param->peer_addr); +- return ret; +- } +- +- ret = ath11k_wait_for_peer_delete_done(ar, param->vdev_id, +- param->peer_addr); +- if (ret) +- return ret; +- +- return -ENOENT; ++ ret = -ENOENT; ++ goto cleanup; + } + + peer->pdev_idx = ar->pdev_idx; +@@ -335,4 +321,24 @@ int ath11k_peer_create(struct ath11k *ar + spin_unlock_bh(&ar->ab->base_lock); + + return 0; ++ ++cleanup: ++ reinit_completion(&ar->peer_delete_done); ++ ++ fbret = ath11k_wmi_send_peer_delete_cmd(ar, param->peer_addr, ++ param->vdev_id); ++ if (fbret) { ++ ath11k_warn(ar->ab, "failed to delete peer vdev_id %d addr %pM\n", ++ param->vdev_id, param->peer_addr); ++ goto exit; ++ } ++ ++ fbret = ath11k_wait_for_peer_delete_done(ar, param->vdev_id, ++ param->peer_addr); ++ if (fbret) ++ ath11k_warn(ar->ab, "failed wait for peer %pM delete done id %d fallback ret %d\n", ++ param->peer_addr, param->vdev_id, fbret); ++ ++exit: ++ return ret; + } diff --git a/package/kernel/mac80211/patches/ath11k/0155-ath11k-add-LDPC-FEC-type-in-802.11-radiotap-header.patch b/package/kernel/mac80211/patches/ath11k/0155-ath11k-add-LDPC-FEC-type-in-802.11-radiotap-header.patch new file mode 100644 index 000000000..cadbd1730 --- /dev/null +++ b/package/kernel/mac80211/patches/ath11k/0155-ath11k-add-LDPC-FEC-type-in-802.11-radiotap-header.patch @@ -0,0 +1,126 @@ +From b3febdccde3eb086b892485c923cd6b73b2ce9d7 Mon Sep 17 00:00:00 2001 +From: P Praneesh +Date: Tue, 11 Jan 2022 16:42:52 +0200 +Subject: [PATCH 155/156] ath11k: add LDPC FEC type in 802.11 radiotap header + +LDPC is one the FEC type advertised in msdu_start info2 for HT packet +type. Hence, add hardware specific callback for fetching LDPC +support from msdu start and enable RX_ENC_FLAG_LDPC flag while passing +rx status to mac80211. + +Tested-on: IPQ8074 WLAN.HK.2.4.0.1-01467-QCAHKSWPL_SILICONZ-1 + +Signed-off-by: P Praneesh +Signed-off-by: Kalle Valo +Link: https://lore.kernel.org/r/1638294648-844-3-git-send-email-quic_ppranees@quicinc.com +--- + drivers/net/wireless/ath/ath11k/dp_rx.c | 12 +++++++++++- + drivers/net/wireless/ath/ath11k/hw.c | 16 ++++++++++++++++ + drivers/net/wireless/ath/ath11k/hw.h | 1 + + 3 files changed, 28 insertions(+), 1 deletion(-) + +--- a/drivers/net/wireless/ath/ath11k/dp_rx.c ++++ b/drivers/net/wireless/ath/ath11k/dp_rx.c +@@ -43,6 +43,13 @@ static inline u8 ath11k_dp_rx_h_msdu_sta + } + + static inline ++bool ath11k_dp_rx_h_msdu_start_ldpc_support(struct ath11k_base *ab, ++ struct hal_rx_desc *desc) ++{ ++ return ab->hw_params.hw_ops->rx_desc_get_ldpc_support(desc); ++} ++ ++static inline + u8 ath11k_dp_rx_h_msdu_start_mesh_ctl_present(struct ath11k_base *ab, + struct hal_rx_desc *desc) + { +@@ -2313,7 +2320,7 @@ static void ath11k_dp_rx_h_rate(struct a + u8 bw; + u8 rate_mcs, nss; + u8 sgi; +- bool is_cck; ++ bool is_cck, is_ldpc; + + pkt_type = ath11k_dp_rx_h_msdu_start_pkt_type(ar->ab, rx_desc); + bw = ath11k_dp_rx_h_msdu_start_rx_bw(ar->ab, rx_desc); +@@ -2355,6 +2362,9 @@ static void ath11k_dp_rx_h_rate(struct a + if (sgi) + rx_status->enc_flags |= RX_ENC_FLAG_SHORT_GI; + rx_status->bw = ath11k_mac_bw_to_mac80211_bw(bw); ++ is_ldpc = ath11k_dp_rx_h_msdu_start_ldpc_support(ar->ab, rx_desc); ++ if (is_ldpc) ++ rx_status->enc_flags |= RX_ENC_FLAG_LDPC; + break; + case RX_MSDU_START_PKT_TYPE_11AX: + rx_status->rate_idx = rate_mcs; +--- a/drivers/net/wireless/ath/ath11k/hw.c ++++ b/drivers/net/wireless/ath/ath11k/hw.c +@@ -273,6 +273,12 @@ static u8 ath11k_hw_ipq8074_rx_desc_get_ + __le32_to_cpu(desc->u.ipq8074.msdu_start.info2)); + } + ++static bool ath11k_hw_ipq8074_rx_desc_get_ldpc_support(struct hal_rx_desc *desc) ++{ ++ return FIELD_GET(RX_MSDU_START_INFO2_LDPC, ++ __le32_to_cpu(desc->u.ipq8074.msdu_start.info2)); ++} ++ + static bool ath11k_hw_ipq8074_rx_desc_get_mpdu_seq_ctl_vld(struct hal_rx_desc *desc) + { + return !!FIELD_GET(RX_MPDU_START_INFO1_MPDU_SEQ_CTRL_VALID, +@@ -444,6 +450,12 @@ static u8 ath11k_hw_qcn9074_rx_desc_get_ + __le32_to_cpu(desc->u.qcn9074.msdu_start.info2)); + } + ++static bool ath11k_hw_qcn9074_rx_desc_get_ldpc_support(struct hal_rx_desc *desc) ++{ ++ return FIELD_GET(RX_MSDU_START_INFO2_LDPC, ++ __le32_to_cpu(desc->u.qcn9074.msdu_start.info2)); ++} ++ + static bool ath11k_hw_qcn9074_rx_desc_get_mpdu_seq_ctl_vld(struct hal_rx_desc *desc) + { + return !!FIELD_GET(RX_MPDU_START_INFO11_MPDU_SEQ_CTRL_VALID, +@@ -815,6 +827,7 @@ const struct ath11k_hw_ops ipq8074_ops = + .rx_desc_get_encrypt_type = ath11k_hw_ipq8074_rx_desc_get_encrypt_type, + .rx_desc_get_decap_type = ath11k_hw_ipq8074_rx_desc_get_decap_type, + .rx_desc_get_mesh_ctl = ath11k_hw_ipq8074_rx_desc_get_mesh_ctl, ++ .rx_desc_get_ldpc_support = ath11k_hw_ipq8074_rx_desc_get_ldpc_support, + .rx_desc_get_mpdu_seq_ctl_vld = ath11k_hw_ipq8074_rx_desc_get_mpdu_seq_ctl_vld, + .rx_desc_get_mpdu_fc_valid = ath11k_hw_ipq8074_rx_desc_get_mpdu_fc_valid, + .rx_desc_get_mpdu_start_seq_no = ath11k_hw_ipq8074_rx_desc_get_mpdu_start_seq_no, +@@ -853,6 +866,7 @@ const struct ath11k_hw_ops ipq6018_ops = + .rx_desc_get_encrypt_type = ath11k_hw_ipq8074_rx_desc_get_encrypt_type, + .rx_desc_get_decap_type = ath11k_hw_ipq8074_rx_desc_get_decap_type, + .rx_desc_get_mesh_ctl = ath11k_hw_ipq8074_rx_desc_get_mesh_ctl, ++ .rx_desc_get_ldpc_support = ath11k_hw_ipq8074_rx_desc_get_ldpc_support, + .rx_desc_get_mpdu_seq_ctl_vld = ath11k_hw_ipq8074_rx_desc_get_mpdu_seq_ctl_vld, + .rx_desc_get_mpdu_fc_valid = ath11k_hw_ipq8074_rx_desc_get_mpdu_fc_valid, + .rx_desc_get_mpdu_start_seq_no = ath11k_hw_ipq8074_rx_desc_get_mpdu_start_seq_no, +@@ -891,6 +905,7 @@ const struct ath11k_hw_ops qca6390_ops = + .rx_desc_get_encrypt_type = ath11k_hw_ipq8074_rx_desc_get_encrypt_type, + .rx_desc_get_decap_type = ath11k_hw_ipq8074_rx_desc_get_decap_type, + .rx_desc_get_mesh_ctl = ath11k_hw_ipq8074_rx_desc_get_mesh_ctl, ++ .rx_desc_get_ldpc_support = ath11k_hw_ipq8074_rx_desc_get_ldpc_support, + .rx_desc_get_mpdu_seq_ctl_vld = ath11k_hw_ipq8074_rx_desc_get_mpdu_seq_ctl_vld, + .rx_desc_get_mpdu_fc_valid = ath11k_hw_ipq8074_rx_desc_get_mpdu_fc_valid, + .rx_desc_get_mpdu_start_seq_no = ath11k_hw_ipq8074_rx_desc_get_mpdu_start_seq_no, +@@ -929,6 +944,7 @@ const struct ath11k_hw_ops qcn9074_ops = + .rx_desc_get_encrypt_type = ath11k_hw_qcn9074_rx_desc_get_encrypt_type, + .rx_desc_get_decap_type = ath11k_hw_qcn9074_rx_desc_get_decap_type, + .rx_desc_get_mesh_ctl = ath11k_hw_qcn9074_rx_desc_get_mesh_ctl, ++ .rx_desc_get_ldpc_support = ath11k_hw_qcn9074_rx_desc_get_ldpc_support, + .rx_desc_get_mpdu_seq_ctl_vld = ath11k_hw_qcn9074_rx_desc_get_mpdu_seq_ctl_vld, + .rx_desc_get_mpdu_fc_valid = ath11k_hw_qcn9074_rx_desc_get_mpdu_fc_valid, + .rx_desc_get_mpdu_start_seq_no = ath11k_hw_qcn9074_rx_desc_get_mpdu_start_seq_no, +--- a/drivers/net/wireless/ath/ath11k/hw.h ++++ b/drivers/net/wireless/ath/ath11k/hw.h +@@ -210,6 +210,7 @@ struct ath11k_hw_ops { + u32 (*rx_desc_get_encrypt_type)(struct hal_rx_desc *desc); + u8 (*rx_desc_get_decap_type)(struct hal_rx_desc *desc); + u8 (*rx_desc_get_mesh_ctl)(struct hal_rx_desc *desc); ++ bool (*rx_desc_get_ldpc_support)(struct hal_rx_desc *desc); + bool (*rx_desc_get_mpdu_seq_ctl_vld)(struct hal_rx_desc *desc); + bool (*rx_desc_get_mpdu_fc_valid)(struct hal_rx_desc *desc); + u16 (*rx_desc_get_mpdu_start_seq_no)(struct hal_rx_desc *desc); diff --git a/package/kernel/mac80211/patches/ath11k/0156-ath11k-free-peer-for-station-when-disconnect-from-AP.patch b/package/kernel/mac80211/patches/ath11k/0156-ath11k-free-peer-for-station-when-disconnect-from-AP.patch new file mode 100644 index 000000000..48172edfc --- /dev/null +++ b/package/kernel/mac80211/patches/ath11k/0156-ath11k-free-peer-for-station-when-disconnect-from-AP.patch @@ -0,0 +1,244 @@ +From 212ad7cb7d7592669c067125949e0a8e31ce6a0b Mon Sep 17 00:00:00 2001 +From: Wen Gong +Date: Tue, 11 Jan 2022 16:42:52 +0200 +Subject: [PATCH 156/156] ath11k: free peer for station when disconnect from AP + for QCA6390/WCN6855 + +Commit b4a0f54156ac ("ath11k: move peer delete after vdev stop of station +for QCA6390 and WCN6855") is to fix firmware crash by changing the WMI +command sequence, but actually skip all the peer delete operation, then +it lead commit 58595c9874c6 ("ath11k: Fixing dangling pointer issue upon +peer delete failure") not take effect, and then happened a use-after-free +warning from KASAN. because the peer->sta is not set to NULL and then used +later. + +Change to only skip the WMI_PEER_DELETE_CMDID for QCA6390/WCN6855. + +log of user-after-free: + +[ 534.888665] BUG: KASAN: use-after-free in ath11k_dp_rx_update_peer_stats+0x912/0xc10 [ath11k] +[ 534.888696] Read of size 8 at addr ffff8881396bb1b8 by task rtcwake/2860 + +[ 534.888705] CPU: 4 PID: 2860 Comm: rtcwake Kdump: loaded Tainted: G W 5.15.0-wt-ath+ #523 +[ 534.888712] Hardware name: Intel(R) Client Systems NUC8i7HVK/NUC8i7HVB, BIOS HNKBLi70.86A.0067.2021.0528.1339 05/28/2021 +[ 534.888716] Call Trace: +[ 534.888720] +[ 534.888726] dump_stack_lvl+0x57/0x7d +[ 534.888736] print_address_description.constprop.0+0x1f/0x170 +[ 534.888745] ? ath11k_dp_rx_update_peer_stats+0x912/0xc10 [ath11k] +[ 534.888771] kasan_report.cold+0x83/0xdf +[ 534.888783] ? ath11k_dp_rx_update_peer_stats+0x912/0xc10 [ath11k] +[ 534.888810] ath11k_dp_rx_update_peer_stats+0x912/0xc10 [ath11k] +[ 534.888840] ath11k_dp_rx_process_mon_status+0x529/0xa70 [ath11k] +[ 534.888874] ? ath11k_dp_rx_mon_status_bufs_replenish+0x3f0/0x3f0 [ath11k] +[ 534.888897] ? check_prev_add+0x20f0/0x20f0 +[ 534.888922] ? __lock_acquire+0xb72/0x1870 +[ 534.888937] ? find_held_lock+0x33/0x110 +[ 534.888954] ath11k_dp_rx_process_mon_rings+0x297/0x520 [ath11k] +[ 534.888981] ? rcu_read_unlock+0x40/0x40 +[ 534.888990] ? ath11k_dp_rx_pdev_alloc+0xd90/0xd90 [ath11k] +[ 534.889026] ath11k_dp_service_mon_ring+0x67/0xe0 [ath11k] +[ 534.889053] ? ath11k_dp_rx_process_mon_rings+0x520/0x520 [ath11k] +[ 534.889075] call_timer_fn+0x167/0x4a0 +[ 534.889084] ? add_timer_on+0x3b0/0x3b0 +[ 534.889103] ? lockdep_hardirqs_on_prepare.part.0+0x18c/0x370 +[ 534.889117] __run_timers.part.0+0x539/0x8b0 +[ 534.889123] ? ath11k_dp_rx_process_mon_rings+0x520/0x520 [ath11k] +[ 534.889157] ? call_timer_fn+0x4a0/0x4a0 +[ 534.889164] ? mark_lock_irq+0x1c30/0x1c30 +[ 534.889173] ? clockevents_program_event+0xdd/0x280 +[ 534.889189] ? mark_held_locks+0xa5/0xe0 +[ 534.889203] run_timer_softirq+0x97/0x180 +[ 534.889213] __do_softirq+0x276/0x86a +[ 534.889230] __irq_exit_rcu+0x11c/0x180 +[ 534.889238] irq_exit_rcu+0x5/0x20 +[ 534.889244] sysvec_apic_timer_interrupt+0x8e/0xc0 +[ 534.889251] +[ 534.889254] +[ 534.889259] asm_sysvec_apic_timer_interrupt+0x12/0x20 +[ 534.889265] RIP: 0010:_raw_spin_unlock_irqrestore+0x38/0x70 +[ 534.889271] Code: 74 24 10 e8 ea c2 bf fd 48 89 ef e8 12 53 c0 fd 81 e3 00 02 00 00 75 25 9c 58 f6 c4 02 75 2d 48 85 db 74 01 fb bf 01 00 00 00 13 a7 b5 fd 65 8b 05 cc d9 9c 5e 85 c0 74 0a 5b 5d c3 e8 a0 ee +[ 534.889276] RSP: 0018:ffffc90002e5f880 EFLAGS: 00000206 +[ 534.889284] RAX: 0000000000000006 RBX: 0000000000000200 RCX: ffffffff9f256f10 +[ 534.889289] RDX: 0000000000000000 RSI: ffffffffa1c6e420 RDI: 0000000000000001 +[ 534.889293] RBP: ffff8881095e6200 R08: 0000000000000001 R09: ffffffffa40d2b8f +[ 534.889298] R10: fffffbfff481a571 R11: 0000000000000001 R12: ffff8881095e6e68 +[ 534.889302] R13: ffffc90002e5f908 R14: 0000000000000246 R15: 0000000000000000 +[ 534.889316] ? mark_lock+0xd0/0x14a0 +[ 534.889332] klist_next+0x1d4/0x450 +[ 534.889340] ? dpm_wait_for_subordinate+0x2d0/0x2d0 +[ 534.889350] device_for_each_child+0xa8/0x140 +[ 534.889360] ? device_remove_class_symlinks+0x1b0/0x1b0 +[ 534.889370] ? __lock_release+0x4bd/0x9f0 +[ 534.889378] ? dpm_suspend+0x26b/0x3f0 +[ 534.889390] dpm_wait_for_subordinate+0x82/0x2d0 +[ 534.889400] ? dpm_for_each_dev+0xa0/0xa0 +[ 534.889410] ? dpm_suspend+0x233/0x3f0 +[ 534.889427] __device_suspend+0xd4/0x10c0 +[ 534.889440] ? wait_for_completion_io+0x270/0x270 +[ 534.889456] ? async_suspend_late+0xe0/0xe0 +[ 534.889463] ? async_schedule_node_domain+0x468/0x640 +[ 534.889482] dpm_suspend+0x25a/0x3f0 +[ 534.889491] ? dpm_suspend_end+0x1a0/0x1a0 +[ 534.889497] ? ktime_get+0x214/0x2f0 +[ 534.889502] ? lockdep_hardirqs_on+0x79/0x100 +[ 534.889509] ? recalibrate_cpu_khz+0x10/0x10 +[ 534.889516] ? ktime_get+0x119/0x2f0 +[ 534.889528] dpm_suspend_start+0xab/0xc0 +[ 534.889538] suspend_devices_and_enter+0x1ca/0x350 +[ 534.889546] ? suspend_enter+0x850/0x850 +[ 534.889566] enter_state+0x27c/0x3d7 +[ 534.889575] pm_suspend.cold+0x42/0x189 +[ 534.889583] state_store+0xab/0x160 +[ 534.889595] ? sysfs_file_ops+0x160/0x160 +[ 534.889601] kernfs_fop_write_iter+0x2b5/0x450 +[ 534.889615] new_sync_write+0x36a/0x600 +[ 534.889625] ? new_sync_read+0x600/0x600 +[ 534.889639] ? rcu_read_unlock+0x40/0x40 +[ 534.889668] vfs_write+0x619/0x910 +[ 534.889681] ksys_write+0xf4/0x1d0 +[ 534.889689] ? __ia32_sys_read+0xa0/0xa0 +[ 534.889699] ? lockdep_hardirqs_on_prepare.part.0+0x18c/0x370 +[ 534.889707] ? syscall_enter_from_user_mode+0x1d/0x50 +[ 534.889719] do_syscall_64+0x3b/0x90 +[ 534.889725] entry_SYSCALL_64_after_hwframe+0x44/0xae +[ 534.889731] RIP: 0033:0x7f0b9bc931e7 +[ 534.889736] Code: 64 89 02 48 c7 c0 ff ff ff ff eb bb 0f 1f 80 00 00 00 00 f3 0f 1e fa 64 8b 04 25 18 00 00 00 85 c0 75 10 b8 01 00 00 00 0f 05 <48> 3d 00 f0 ff ff 77 51 c3 48 83 ec 28 48 89 54 24 18 48 89 74 24 +[ 534.889741] RSP: 002b:00007ffd9d34cc88 EFLAGS: 00000246 ORIG_RAX: 0000000000000001 +[ 534.889749] RAX: ffffffffffffffda RBX: 0000000000000004 RCX: 00007f0b9bc931e7 +[ 534.889753] RDX: 0000000000000004 RSI: 0000561cd023c5f0 RDI: 0000000000000004 +[ 534.889757] RBP: 0000561cd023c5f0 R08: 0000000000000000 R09: 0000000000000004 +[ 534.889761] R10: 0000561ccef842a6 R11: 0000000000000246 R12: 0000000000000004 +[ 534.889765] R13: 0000561cd0239590 R14: 00007f0b9bd6f4a0 R15: 00007f0b9bd6e8a0 +[ 534.889789] + +[ 534.889796] Allocated by task 2711: +[ 534.889800] kasan_save_stack+0x1b/0x40 +[ 534.889805] __kasan_kmalloc+0x7c/0x90 +[ 534.889810] sta_info_alloc+0x98/0x1ef0 [mac80211] +[ 534.889874] ieee80211_prep_connection+0x30b/0x11e0 [mac80211] +[ 534.889950] ieee80211_mgd_auth+0x529/0xe00 [mac80211] +[ 534.890024] cfg80211_mlme_auth+0x332/0x6f0 [cfg80211] +[ 534.890090] nl80211_authenticate+0x839/0xcf0 [cfg80211] +[ 534.890147] genl_family_rcv_msg_doit+0x1f4/0x2f0 +[ 534.890154] genl_rcv_msg+0x280/0x500 +[ 534.890160] netlink_rcv_skb+0x11c/0x340 +[ 534.890165] genl_rcv+0x1f/0x30 +[ 534.890170] netlink_unicast+0x42b/0x700 +[ 534.890176] netlink_sendmsg+0x71b/0xc60 +[ 534.890181] sock_sendmsg+0xdf/0x110 +[ 534.890187] ____sys_sendmsg+0x5c0/0x850 +[ 534.890192] ___sys_sendmsg+0xe4/0x160 +[ 534.890197] __sys_sendmsg+0xb2/0x140 +[ 534.890202] do_syscall_64+0x3b/0x90 +[ 534.890207] entry_SYSCALL_64_after_hwframe+0x44/0xae + +[ 534.890215] Freed by task 2825: +[ 534.890218] kasan_save_stack+0x1b/0x40 +[ 534.890223] kasan_set_track+0x1c/0x30 +[ 534.890227] kasan_set_free_info+0x20/0x30 +[ 534.890232] __kasan_slab_free+0xce/0x100 +[ 534.890237] slab_free_freelist_hook+0xf0/0x1a0 +[ 534.890242] kfree+0xe5/0x370 +[ 534.890248] __sta_info_flush+0x333/0x4b0 [mac80211] +[ 534.890308] ieee80211_set_disassoc+0x324/0xd20 [mac80211] +[ 534.890382] ieee80211_mgd_deauth+0x537/0xee0 [mac80211] +[ 534.890472] cfg80211_mlme_deauth+0x349/0x810 [cfg80211] +[ 534.890526] cfg80211_mlme_down+0x1ce/0x270 [cfg80211] +[ 534.890578] cfg80211_disconnect+0x4f5/0x7b0 [cfg80211] +[ 534.890631] cfg80211_leave+0x24/0x40 [cfg80211] +[ 534.890677] wiphy_suspend+0x23d/0x2f0 [cfg80211] +[ 534.890723] dpm_run_callback+0xf4/0x1b0 +[ 534.890728] __device_suspend+0x648/0x10c0 +[ 534.890733] async_suspend+0x16/0xe0 +[ 534.890737] async_run_entry_fn+0x90/0x4f0 +[ 534.890741] process_one_work+0x866/0x1490 +[ 534.890747] worker_thread+0x596/0x1010 +[ 534.890751] kthread+0x35d/0x420 +[ 534.890756] ret_from_fork+0x22/0x30 + +[ 534.890763] The buggy address belongs to the object at ffff8881396ba000 + which belongs to the cache kmalloc-8k of size 8192 +[ 534.890767] The buggy address is located 4536 bytes inside of + 8192-byte region [ffff8881396ba000, ffff8881396bc000) +[ 534.890772] The buggy address belongs to the page: +[ 534.890775] page:ffffea0004e5ae00 refcount:1 mapcount:0 mapping:0000000000000000 index:0x0 pfn:0x1396b8 +[ 534.890780] head:ffffea0004e5ae00 order:3 compound_mapcount:0 compound_pincount:0 +[ 534.890784] flags: 0x200000000010200(slab|head|node=0|zone=2) +[ 534.890791] raw: 0200000000010200 ffffea000562be08 ffffea0004b04c08 ffff88810004e340 +[ 534.890795] raw: 0000000000000000 0000000000010001 00000001ffffffff 0000000000000000 +[ 534.890798] page dumped because: kasan: bad access detected + +[ 534.890804] Memory state around the buggy address: +[ 534.890807] ffff8881396bb080: fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb +[ 534.890811] ffff8881396bb100: fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb +[ 534.890814] >ffff8881396bb180: fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb +[ 534.890817] ^ +[ 534.890821] ffff8881396bb200: fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb +[ 534.890824] ffff8881396bb280: fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb +[ 534.890827] ================================================================== +[ 534.890830] Disabling lock debugging due to kernel taint + +Tested-on: WCN6855 hw2.0 PCI WLAN.HSP.1.1-01720.1-QCAHSPSWPL_V1_V2_SILICONZ_LITE-1 + +Fixes: b4a0f54156ac ("ath11k: move peer delete after vdev stop of station for QCA6390 and WCN6855") +Signed-off-by: Wen Gong +Signed-off-by: Kalle Valo +Link: https://lore.kernel.org/r/20211222070431.29595-1-quic_wgong@quicinc.com +--- + drivers/net/wireless/ath/ath11k/mac.c | 31 ++++++++++++++++----------- + 1 file changed, 18 insertions(+), 13 deletions(-) + +--- a/drivers/net/wireless/ath/ath11k/mac.c ++++ b/drivers/net/wireless/ath/ath11k/mac.c +@@ -4504,24 +4504,30 @@ static int ath11k_mac_op_sta_state(struc + sta->addr, arvif->vdev_id); + } else if ((old_state == IEEE80211_STA_NONE && + new_state == IEEE80211_STA_NOTEXIST)) { +- ath11k_dp_peer_cleanup(ar, arvif->vdev_id, sta->addr); ++ bool skip_peer_delete = ar->ab->hw_params.vdev_start_delay && ++ vif->type == NL80211_IFTYPE_STATION; + +- if (ar->ab->hw_params.vdev_start_delay && +- vif->type == NL80211_IFTYPE_STATION) +- goto free; ++ ath11k_dp_peer_cleanup(ar, arvif->vdev_id, sta->addr); + +- ret = ath11k_peer_delete(ar, arvif->vdev_id, sta->addr); +- if (ret) +- ath11k_warn(ar->ab, "Failed to delete peer: %pM for VDEV: %d\n", +- sta->addr, arvif->vdev_id); +- else +- ath11k_dbg(ar->ab, ATH11K_DBG_MAC, "Removed peer: %pM for VDEV: %d\n", +- sta->addr, arvif->vdev_id); ++ if (!skip_peer_delete) { ++ ret = ath11k_peer_delete(ar, arvif->vdev_id, sta->addr); ++ if (ret) ++ ath11k_warn(ar->ab, ++ "Failed to delete peer: %pM for VDEV: %d\n", ++ sta->addr, arvif->vdev_id); ++ else ++ ath11k_dbg(ar->ab, ++ ATH11K_DBG_MAC, ++ "Removed peer: %pM for VDEV: %d\n", ++ sta->addr, arvif->vdev_id); ++ } + + ath11k_mac_dec_num_stations(arvif, sta); + spin_lock_bh(&ar->ab->base_lock); + peer = ath11k_peer_find(ar->ab, arvif->vdev_id, sta->addr); +- if (peer && peer->sta == sta) { ++ if (skip_peer_delete && peer) { ++ peer->sta = NULL; ++ } else if (peer && peer->sta == sta) { + ath11k_warn(ar->ab, "Found peer entry %pM n vdev %i after it was supposedly removed\n", + vif->addr, arvif->vdev_id); + peer->sta = NULL; +@@ -4531,7 +4537,6 @@ static int ath11k_mac_op_sta_state(struc + } + spin_unlock_bh(&ar->ab->base_lock); + +-free: + kfree(arsta->tx_stats); + arsta->tx_stats = NULL; + diff --git a/package/kernel/mac80211/patches/ath11k/0157-ath11k-enable-RX-PPDU-stats-in-monitor-co-exist-mode.patch b/package/kernel/mac80211/patches/ath11k/0157-ath11k-enable-RX-PPDU-stats-in-monitor-co-exist-mode.patch new file mode 100644 index 000000000..a64a47889 --- /dev/null +++ b/package/kernel/mac80211/patches/ath11k/0157-ath11k-enable-RX-PPDU-stats-in-monitor-co-exist-mode.patch @@ -0,0 +1,222 @@ +From 67a9d399fcb03177152a8797a855cbd4c995c2de Mon Sep 17 00:00:00 2001 +From: Miles Hu +Date: Wed, 12 Jan 2022 10:15:10 +0200 +Subject: [PATCH 157/160] ath11k: enable RX PPDU stats in monitor co-exist mode + +RX PPDU statistics collection is missing when monitor mode co-exists +with other modes. This commit combines the processing of the destination +ring with the status ring to fix the issue. + +Tested-on: IPQ8074 hw2.0 AHB WLAN.HK.2.5.0.1-01179-QCAHKSWPL_SILICONZ-1 +Signed-off-by: Miles Hu +Signed-off-by: Aloka Dixit +Signed-off-by: Kalle Valo +Link: https://lore.kernel.org/r/20220111032224.14093-1-quic_alokad@quicinc.com +--- + drivers/net/wireless/ath/ath11k/debugfs.c | 6 ++ + drivers/net/wireless/ath/ath11k/dp_rx.c | 84 +++++++---------------- + drivers/net/wireless/ath/ath11k/hal_rx.h | 8 +-- + 3 files changed, 34 insertions(+), 64 deletions(-) + +--- a/drivers/net/wireless/ath/ath11k/debugfs.c ++++ b/drivers/net/wireless/ath/ath11k/debugfs.c +@@ -664,6 +664,12 @@ static ssize_t ath11k_write_extd_rx_stat + goto exit; + } + ++ if (test_bit(ATH11K_FLAG_MONITOR_STARTED, &ar->monitor_flags)) { ++ ar->debug.extd_rx_stats = enable; ++ ret = count; ++ goto exit; ++ } ++ + if (enable) { + rx_filter = HTT_RX_FILTER_TLV_FLAGS_MPDU_START; + rx_filter |= HTT_RX_FILTER_TLV_FLAGS_PPDU_START; +--- a/drivers/net/wireless/ath/ath11k/dp_rx.c ++++ b/drivers/net/wireless/ath/ath11k/dp_rx.c +@@ -20,6 +20,9 @@ + + #define ATH11K_DP_RX_FRAGMENT_TIMEOUT_MS (2 * HZ) + ++static void ath11k_dp_rx_mon_dest_process(struct ath11k *ar, int mac_id, ++ u32 quota, struct napi_struct *napi); ++ + static inline + u8 *ath11k_dp_rx_h_80211_hdr(struct ath11k_base *ab, struct hal_rx_desc *desc) + { +@@ -3097,12 +3100,14 @@ int ath11k_dp_rx_process_mon_status(stru + enum hal_rx_mon_status hal_status; + struct sk_buff *skb; + struct sk_buff_head skb_list; +- struct hal_rx_mon_ppdu_info ppdu_info; + struct ath11k_peer *peer; + struct ath11k_sta *arsta; + int num_buffs_reaped = 0; + u32 rx_buf_sz; + u16 log_type = 0; ++ struct ath11k_mon_data *pmon = (struct ath11k_mon_data *)&ar->dp.mon_data; ++ struct ath11k_pdev_mon_stats *rx_mon_stats = &pmon->rx_mon_stats; ++ struct hal_rx_mon_ppdu_info *ppdu_info = &pmon->mon_ppdu_info; + + __skb_queue_head_init(&skb_list); + +@@ -3111,8 +3116,8 @@ int ath11k_dp_rx_process_mon_status(stru + if (!num_buffs_reaped) + goto exit; + +- memset(&ppdu_info, 0, sizeof(ppdu_info)); +- ppdu_info.peer_id = HAL_INVALID_PEERID; ++ memset(ppdu_info, 0, sizeof(*ppdu_info)); ++ ppdu_info->peer_id = HAL_INVALID_PEERID; + + while ((skb = __skb_dequeue(&skb_list))) { + if (ath11k_debugfs_is_pktlog_lite_mode_enabled(ar)) { +@@ -3126,9 +3131,18 @@ int ath11k_dp_rx_process_mon_status(stru + if (log_type) + trace_ath11k_htt_rxdesc(ar, skb->data, log_type, rx_buf_sz); + +- hal_status = ath11k_hal_rx_parse_mon_status(ab, &ppdu_info, skb); ++ hal_status = ath11k_hal_rx_parse_mon_status(ab, ppdu_info, skb); + +- if (ppdu_info.peer_id == HAL_INVALID_PEERID || ++ if (test_bit(ATH11K_FLAG_MONITOR_STARTED, &ar->monitor_flags) && ++ pmon->mon_ppdu_status == DP_PPDU_STATUS_START && ++ hal_status == HAL_TLV_STATUS_PPDU_DONE) { ++ rx_mon_stats->status_ppdu_done++; ++ pmon->mon_ppdu_status = DP_PPDU_STATUS_DONE; ++ ath11k_dp_rx_mon_dest_process(ar, mac_id, budget, napi); ++ pmon->mon_ppdu_status = DP_PPDU_STATUS_START; ++ } ++ ++ if (ppdu_info->peer_id == HAL_INVALID_PEERID || + hal_status != HAL_RX_MON_STATUS_PPDU_DONE) { + dev_kfree_skb_any(skb); + continue; +@@ -3136,17 +3150,17 @@ int ath11k_dp_rx_process_mon_status(stru + + rcu_read_lock(); + spin_lock_bh(&ab->base_lock); +- peer = ath11k_peer_find_by_id(ab, ppdu_info.peer_id); ++ peer = ath11k_peer_find_by_id(ab, ppdu_info->peer_id); + + if (!peer || !peer->sta) { + ath11k_dbg(ab, ATH11K_DBG_DATA, + "failed to find the peer with peer_id %d\n", +- ppdu_info.peer_id); ++ ppdu_info->peer_id); + goto next_skb; + } + + arsta = (struct ath11k_sta *)peer->sta->drv_priv; +- ath11k_dp_rx_update_peer_stats(arsta, &ppdu_info); ++ ath11k_dp_rx_update_peer_stats(arsta, ppdu_info); + + if (ath11k_debugfs_is_pktlog_peer_valid(ar, peer->addr)) + trace_ath11k_htt_rxdesc(ar, skb->data, log_type, rx_buf_sz); +@@ -3156,8 +3170,8 @@ next_skb: + rcu_read_unlock(); + + dev_kfree_skb_any(skb); +- memset(&ppdu_info, 0, sizeof(ppdu_info)); +- ppdu_info.peer_id = HAL_INVALID_PEERID; ++ memset(ppdu_info, 0, sizeof(*ppdu_info)); ++ ppdu_info->peer_id = HAL_INVALID_PEERID; + } + exit: + return num_buffs_reaped; +@@ -5116,38 +5130,6 @@ static void ath11k_dp_rx_mon_dest_proces + } + } + +-static void ath11k_dp_rx_mon_status_process_tlv(struct ath11k *ar, +- int mac_id, u32 quota, +- struct napi_struct *napi) +-{ +- struct ath11k_pdev_dp *dp = &ar->dp; +- struct ath11k_mon_data *pmon = (struct ath11k_mon_data *)&dp->mon_data; +- struct hal_rx_mon_ppdu_info *ppdu_info; +- struct sk_buff *status_skb; +- u32 tlv_status = HAL_TLV_STATUS_BUF_DONE; +- struct ath11k_pdev_mon_stats *rx_mon_stats; +- +- ppdu_info = &pmon->mon_ppdu_info; +- rx_mon_stats = &pmon->rx_mon_stats; +- +- if (pmon->mon_ppdu_status != DP_PPDU_STATUS_START) +- return; +- +- while (!skb_queue_empty(&pmon->rx_status_q)) { +- status_skb = skb_dequeue(&pmon->rx_status_q); +- +- tlv_status = ath11k_hal_rx_parse_mon_status(ar->ab, ppdu_info, +- status_skb); +- if (tlv_status == HAL_TLV_STATUS_PPDU_DONE) { +- rx_mon_stats->status_ppdu_done++; +- pmon->mon_ppdu_status = DP_PPDU_STATUS_DONE; +- ath11k_dp_rx_mon_dest_process(ar, mac_id, quota, napi); +- pmon->mon_ppdu_status = DP_PPDU_STATUS_START; +- } +- dev_kfree_skb_any(status_skb); +- } +-} +- + static u32 + ath11k_dp_rx_full_mon_mpdu_pop(struct ath11k *ar, + void *ring_entry, struct sk_buff **head_msdu, +@@ -5499,22 +5481,6 @@ reap_status_ring: + return quota; + } + +-static int ath11k_dp_mon_process_rx(struct ath11k_base *ab, int mac_id, +- struct napi_struct *napi, int budget) +-{ +- struct ath11k *ar = ath11k_ab_to_ar(ab, mac_id); +- struct ath11k_pdev_dp *dp = &ar->dp; +- struct ath11k_mon_data *pmon = (struct ath11k_mon_data *)&dp->mon_data; +- int num_buffs_reaped = 0; +- +- num_buffs_reaped = ath11k_dp_rx_reap_mon_status_ring(ar->ab, mac_id, &budget, +- &pmon->rx_status_q); +- if (num_buffs_reaped) +- ath11k_dp_rx_mon_status_process_tlv(ar, mac_id, budget, napi); +- +- return num_buffs_reaped; +-} +- + int ath11k_dp_rx_process_mon_rings(struct ath11k_base *ab, int mac_id, + struct napi_struct *napi, int budget) + { +@@ -5524,8 +5490,6 @@ int ath11k_dp_rx_process_mon_rings(struc + if (test_bit(ATH11K_FLAG_MONITOR_STARTED, &ar->monitor_flags) && + ab->hw_params.full_monitor_mode) + ret = ath11k_dp_full_mon_process_rx(ab, mac_id, napi, budget); +- else if (test_bit(ATH11K_FLAG_MONITOR_STARTED, &ar->monitor_flags)) +- ret = ath11k_dp_mon_process_rx(ab, mac_id, napi, budget); + else + ret = ath11k_dp_rx_process_mon_status(ab, mac_id, napi, budget); + +--- a/drivers/net/wireless/ath/ath11k/hal_rx.h ++++ b/drivers/net/wireless/ath/ath11k/hal_rx.h +@@ -65,10 +65,6 @@ enum hal_rx_reception_type { + HAL_RX_RECEPTION_TYPE_MAX, + }; + +-#define HAL_TLV_STATUS_PPDU_NOT_DONE 0 +-#define HAL_TLV_STATUS_PPDU_DONE 1 +-#define HAL_TLV_STATUS_BUF_DONE 2 +-#define HAL_TLV_STATUS_PPDU_NON_STD_DONE 3 + #define HAL_RX_FCS_LEN 4 + + enum hal_rx_mon_status { +@@ -77,6 +73,10 @@ enum hal_rx_mon_status { + HAL_RX_MON_STATUS_BUF_DONE, + }; + ++#define HAL_TLV_STATUS_PPDU_NOT_DONE HAL_RX_MON_STATUS_PPDU_NOT_DONE ++#define HAL_TLV_STATUS_PPDU_DONE HAL_RX_MON_STATUS_PPDU_DONE ++#define HAL_TLV_STATUS_BUF_DONE HAL_RX_MON_STATUS_BUF_DONE ++ + struct hal_sw_mon_ring_entries { + dma_addr_t mon_dst_paddr; + dma_addr_t mon_status_paddr; diff --git a/package/kernel/mac80211/patches/ath11k/0158-ath11k-move-function-ath11k_dp_rx_process_mon_status.patch b/package/kernel/mac80211/patches/ath11k/0158-ath11k-move-function-ath11k_dp_rx_process_mon_status.patch new file mode 100644 index 000000000..43e5ea02e --- /dev/null +++ b/package/kernel/mac80211/patches/ath11k/0158-ath11k-move-function-ath11k_dp_rx_process_mon_status.patch @@ -0,0 +1,210 @@ +From 3cd04a438754aaa4297a5561ad9149eda73ce14d Mon Sep 17 00:00:00 2001 +From: Aloka Dixit +Date: Wed, 12 Jan 2022 10:15:10 +0200 +Subject: [PATCH 158/160] ath11k: move function ath11k_dp_rx_process_mon_status + +Move the function below ath11k_dp_rx_mon_dest_process() and remove +the forward declaration. + +Tested-on: IPQ8074 hw2.0 AHB WLAN.HK.2.5.0.1-01179-QCAHKSWPL_SILICONZ-1 +Signed-off-by: Aloka Dixit +Signed-off-by: Kalle Valo +Link: https://lore.kernel.org/r/20220111032224.14093-2-quic_alokad@quicinc.com +--- + drivers/net/wireless/ath/ath11k/dp_rx.c | 171 ++++++++++++------------ + 1 file changed, 84 insertions(+), 87 deletions(-) + +--- a/drivers/net/wireless/ath/ath11k/dp_rx.c ++++ b/drivers/net/wireless/ath/ath11k/dp_rx.c +@@ -20,9 +20,6 @@ + + #define ATH11K_DP_RX_FRAGMENT_TIMEOUT_MS (2 * HZ) + +-static void ath11k_dp_rx_mon_dest_process(struct ath11k *ar, int mac_id, +- u32 quota, struct napi_struct *napi); +- + static inline + u8 *ath11k_dp_rx_h_80211_hdr(struct ath11k_base *ab, struct hal_rx_desc *desc) + { +@@ -3093,90 +3090,6 @@ move_next: + return num_buffs_reaped; + } + +-int ath11k_dp_rx_process_mon_status(struct ath11k_base *ab, int mac_id, +- struct napi_struct *napi, int budget) +-{ +- struct ath11k *ar = ath11k_ab_to_ar(ab, mac_id); +- enum hal_rx_mon_status hal_status; +- struct sk_buff *skb; +- struct sk_buff_head skb_list; +- struct ath11k_peer *peer; +- struct ath11k_sta *arsta; +- int num_buffs_reaped = 0; +- u32 rx_buf_sz; +- u16 log_type = 0; +- struct ath11k_mon_data *pmon = (struct ath11k_mon_data *)&ar->dp.mon_data; +- struct ath11k_pdev_mon_stats *rx_mon_stats = &pmon->rx_mon_stats; +- struct hal_rx_mon_ppdu_info *ppdu_info = &pmon->mon_ppdu_info; +- +- __skb_queue_head_init(&skb_list); +- +- num_buffs_reaped = ath11k_dp_rx_reap_mon_status_ring(ab, mac_id, &budget, +- &skb_list); +- if (!num_buffs_reaped) +- goto exit; +- +- memset(ppdu_info, 0, sizeof(*ppdu_info)); +- ppdu_info->peer_id = HAL_INVALID_PEERID; +- +- while ((skb = __skb_dequeue(&skb_list))) { +- if (ath11k_debugfs_is_pktlog_lite_mode_enabled(ar)) { +- log_type = ATH11K_PKTLOG_TYPE_LITE_RX; +- rx_buf_sz = DP_RX_BUFFER_SIZE_LITE; +- } else if (ath11k_debugfs_is_pktlog_rx_stats_enabled(ar)) { +- log_type = ATH11K_PKTLOG_TYPE_RX_STATBUF; +- rx_buf_sz = DP_RX_BUFFER_SIZE; +- } +- +- if (log_type) +- trace_ath11k_htt_rxdesc(ar, skb->data, log_type, rx_buf_sz); +- +- hal_status = ath11k_hal_rx_parse_mon_status(ab, ppdu_info, skb); +- +- if (test_bit(ATH11K_FLAG_MONITOR_STARTED, &ar->monitor_flags) && +- pmon->mon_ppdu_status == DP_PPDU_STATUS_START && +- hal_status == HAL_TLV_STATUS_PPDU_DONE) { +- rx_mon_stats->status_ppdu_done++; +- pmon->mon_ppdu_status = DP_PPDU_STATUS_DONE; +- ath11k_dp_rx_mon_dest_process(ar, mac_id, budget, napi); +- pmon->mon_ppdu_status = DP_PPDU_STATUS_START; +- } +- +- if (ppdu_info->peer_id == HAL_INVALID_PEERID || +- hal_status != HAL_RX_MON_STATUS_PPDU_DONE) { +- dev_kfree_skb_any(skb); +- continue; +- } +- +- rcu_read_lock(); +- spin_lock_bh(&ab->base_lock); +- peer = ath11k_peer_find_by_id(ab, ppdu_info->peer_id); +- +- if (!peer || !peer->sta) { +- ath11k_dbg(ab, ATH11K_DBG_DATA, +- "failed to find the peer with peer_id %d\n", +- ppdu_info->peer_id); +- goto next_skb; +- } +- +- arsta = (struct ath11k_sta *)peer->sta->drv_priv; +- ath11k_dp_rx_update_peer_stats(arsta, ppdu_info); +- +- if (ath11k_debugfs_is_pktlog_peer_valid(ar, peer->addr)) +- trace_ath11k_htt_rxdesc(ar, skb->data, log_type, rx_buf_sz); +- +-next_skb: +- spin_unlock_bh(&ab->base_lock); +- rcu_read_unlock(); +- +- dev_kfree_skb_any(skb); +- memset(ppdu_info, 0, sizeof(*ppdu_info)); +- ppdu_info->peer_id = HAL_INVALID_PEERID; +- } +-exit: +- return num_buffs_reaped; +-} +- + static void ath11k_dp_rx_frag_timer(struct timer_list *timer) + { + struct dp_rx_tid *rx_tid = from_timer(rx_tid, timer, frag_timer); +@@ -5130,6 +5043,90 @@ static void ath11k_dp_rx_mon_dest_proces + } + } + ++int ath11k_dp_rx_process_mon_status(struct ath11k_base *ab, int mac_id, ++ struct napi_struct *napi, int budget) ++{ ++ struct ath11k *ar = ath11k_ab_to_ar(ab, mac_id); ++ enum hal_rx_mon_status hal_status; ++ struct sk_buff *skb; ++ struct sk_buff_head skb_list; ++ struct ath11k_peer *peer; ++ struct ath11k_sta *arsta; ++ int num_buffs_reaped = 0; ++ u32 rx_buf_sz; ++ u16 log_type = 0; ++ struct ath11k_mon_data *pmon = (struct ath11k_mon_data *)&ar->dp.mon_data; ++ struct ath11k_pdev_mon_stats *rx_mon_stats = &pmon->rx_mon_stats; ++ struct hal_rx_mon_ppdu_info *ppdu_info = &pmon->mon_ppdu_info; ++ ++ __skb_queue_head_init(&skb_list); ++ ++ num_buffs_reaped = ath11k_dp_rx_reap_mon_status_ring(ab, mac_id, &budget, ++ &skb_list); ++ if (!num_buffs_reaped) ++ goto exit; ++ ++ memset(ppdu_info, 0, sizeof(*ppdu_info)); ++ ppdu_info->peer_id = HAL_INVALID_PEERID; ++ ++ while ((skb = __skb_dequeue(&skb_list))) { ++ if (ath11k_debugfs_is_pktlog_lite_mode_enabled(ar)) { ++ log_type = ATH11K_PKTLOG_TYPE_LITE_RX; ++ rx_buf_sz = DP_RX_BUFFER_SIZE_LITE; ++ } else if (ath11k_debugfs_is_pktlog_rx_stats_enabled(ar)) { ++ log_type = ATH11K_PKTLOG_TYPE_RX_STATBUF; ++ rx_buf_sz = DP_RX_BUFFER_SIZE; ++ } ++ ++ if (log_type) ++ trace_ath11k_htt_rxdesc(ar, skb->data, log_type, rx_buf_sz); ++ ++ hal_status = ath11k_hal_rx_parse_mon_status(ab, ppdu_info, skb); ++ ++ if (test_bit(ATH11K_FLAG_MONITOR_STARTED, &ar->monitor_flags) && ++ pmon->mon_ppdu_status == DP_PPDU_STATUS_START && ++ hal_status == HAL_TLV_STATUS_PPDU_DONE) { ++ rx_mon_stats->status_ppdu_done++; ++ pmon->mon_ppdu_status = DP_PPDU_STATUS_DONE; ++ ath11k_dp_rx_mon_dest_process(ar, mac_id, budget, napi); ++ pmon->mon_ppdu_status = DP_PPDU_STATUS_START; ++ } ++ ++ if (ppdu_info->peer_id == HAL_INVALID_PEERID || ++ hal_status != HAL_RX_MON_STATUS_PPDU_DONE) { ++ dev_kfree_skb_any(skb); ++ continue; ++ } ++ ++ rcu_read_lock(); ++ spin_lock_bh(&ab->base_lock); ++ peer = ath11k_peer_find_by_id(ab, ppdu_info->peer_id); ++ ++ if (!peer || !peer->sta) { ++ ath11k_dbg(ab, ATH11K_DBG_DATA, ++ "failed to find the peer with peer_id %d\n", ++ ppdu_info->peer_id); ++ goto next_skb; ++ } ++ ++ arsta = (struct ath11k_sta *)peer->sta->drv_priv; ++ ath11k_dp_rx_update_peer_stats(arsta, ppdu_info); ++ ++ if (ath11k_debugfs_is_pktlog_peer_valid(ar, peer->addr)) ++ trace_ath11k_htt_rxdesc(ar, skb->data, log_type, rx_buf_sz); ++ ++next_skb: ++ spin_unlock_bh(&ab->base_lock); ++ rcu_read_unlock(); ++ ++ dev_kfree_skb_any(skb); ++ memset(ppdu_info, 0, sizeof(*ppdu_info)); ++ ppdu_info->peer_id = HAL_INVALID_PEERID; ++ } ++exit: ++ return num_buffs_reaped; ++} ++ + static u32 + ath11k_dp_rx_full_mon_mpdu_pop(struct ath11k *ar, + void *ring_entry, struct sk_buff **head_msdu, diff --git a/package/kernel/mac80211/patches/ath11k/0159-ath11k-fix-error-code-in-ath11k_qmi_assign_target_me.patch b/package/kernel/mac80211/patches/ath11k/0159-ath11k-fix-error-code-in-ath11k_qmi_assign_target_me.patch new file mode 100644 index 000000000..87756b313 --- /dev/null +++ b/package/kernel/mac80211/patches/ath11k/0159-ath11k-fix-error-code-in-ath11k_qmi_assign_target_me.patch @@ -0,0 +1,28 @@ +From c9b41832dc080fa59bad597de94865b3ea2d5bab Mon Sep 17 00:00:00 2001 +From: Dan Carpenter +Date: Wed, 12 Jan 2022 10:15:11 +0200 +Subject: [PATCH 159/160] ath11k: fix error code in + ath11k_qmi_assign_target_mem_chunk() + +The "ret" vairable is not set at this point. It could be uninitialized +or zero. The correct thing to return is -ENODEV. + +Fixes: 6ac04bdc5edb ("ath11k: Use reserved host DDR addresses from DT for PCI devices") +Signed-off-by: Dan Carpenter +Signed-off-by: Kalle Valo +Link: https://lore.kernel.org/r/20220111071445.GA11243@kili +--- + drivers/net/wireless/ath/ath11k/qmi.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +--- a/drivers/net/wireless/ath/ath11k/qmi.c ++++ b/drivers/net/wireless/ath/ath11k/qmi.c +@@ -1932,7 +1932,7 @@ static int ath11k_qmi_assign_target_mem_ + if (!hremote_node) { + ath11k_dbg(ab, ATH11K_DBG_QMI, + "qmi fail to get hremote_node\n"); +- return ret; ++ return -ENODEV; + } + + ret = of_address_to_resource(hremote_node, 0, &res); diff --git a/package/kernel/mac80211/patches/ath11k/0160-ath11k-Reconfigure-hardware-rate-for-WCN6855-after-v.patch b/package/kernel/mac80211/patches/ath11k/0160-ath11k-Reconfigure-hardware-rate-for-WCN6855-after-v.patch new file mode 100644 index 000000000..11cfc4b80 --- /dev/null +++ b/package/kernel/mac80211/patches/ath11k/0160-ath11k-Reconfigure-hardware-rate-for-WCN6855-after-v.patch @@ -0,0 +1,68 @@ +From dc7ff75690ea7e1920be08b2b9cc89647667bb90 Mon Sep 17 00:00:00 2001 +From: Baochen Qiang +Date: Wed, 12 Jan 2022 10:54:00 +0800 +Subject: [PATCH 160/160] ath11k: Reconfigure hardware rate for WCN6855 after + vdev is started + +There is an issue that WCN6855 tries to connect to an AP using +a hardware rate of 1Mb/s , even though the AP has announced +expected rates as [24, 36, 48, 54] in Probe Response frame. + +The reason is that WCN6855 firmware clears hardware rate info +of management frames when vdev starts and uses 1Mb/s as default. +To solve it, reconfigure the rate after vdev is started. + +Tested-on: WCN6855 hw2.0 PCI WLAN.HSP.1.1-01720.1-QCAHSPSWPL_V1_V2_SILICONZ_LITE-1 + +Signed-off-by: Baochen Qiang +Signed-off-by: Kalle Valo +Link: https://lore.kernel.org/r/20220112025400.2222-1-quic_bqiang@quicinc.com +--- + drivers/net/wireless/ath/ath11k/core.h | 1 + + drivers/net/wireless/ath/ath11k/mac.c | 18 ++++++++++++++++++ + 2 files changed, 19 insertions(+) + +--- a/drivers/net/wireless/ath/ath11k/core.h ++++ b/drivers/net/wireless/ath/ath11k/core.h +@@ -603,6 +603,7 @@ struct ath11k { + struct completion finish_11d_ch_list; + bool pending_11d; + bool regdom_set_by_user; ++ int hw_rate_code; + }; + + struct ath11k_band_cap { +--- a/drivers/net/wireless/ath/ath11k/mac.c ++++ b/drivers/net/wireless/ath/ath11k/mac.c +@@ -2862,6 +2862,11 @@ static void ath11k_recalculate_mgmt_rate + if (ret) + ath11k_warn(ar->ab, "failed to set mgmt tx rate %d\n", ret); + ++ /* For WCN6855, firmware will clear this param when vdev starts, hence ++ * cache it here so that we can reconfigure it once vdev starts. ++ */ ++ ar->hw_rate_code = hw_rate_code; ++ + vdev_param = WMI_VDEV_PARAM_BEACON_RATE; + ret = ath11k_wmi_vdev_set_param_cmd(ar, arvif->vdev_id, vdev_param, + hw_rate_code); +@@ -6960,6 +6965,19 @@ static int ath11k_start_vdev_delay(struc + return ret; + } + ++ /* Reconfigure hardware rate code since it is cleared by firmware. ++ */ ++ if (ar->hw_rate_code > 0) { ++ u32 vdev_param = WMI_VDEV_PARAM_MGMT_RATE; ++ ++ ret = ath11k_wmi_vdev_set_param_cmd(ar, arvif->vdev_id, vdev_param, ++ ar->hw_rate_code); ++ if (ret) { ++ ath11k_warn(ar->ab, "failed to set mgmt tx rate %d\n", ret); ++ return ret; ++ } ++ } ++ + if (arvif->vdev_type == WMI_VDEV_TYPE_MONITOR) { + ret = ath11k_wmi_vdev_up(ar, arvif->vdev_id, 0, ar->mac_addr); + if (ret) { diff --git a/package/kernel/mac80211/patches/ath11k/0161-ath11k-set-WMI_PEER_40MHZ-while-peer-assoc-for-6-GHz.patch b/package/kernel/mac80211/patches/ath11k/0161-ath11k-set-WMI_PEER_40MHZ-while-peer-assoc-for-6-GHz.patch new file mode 100644 index 000000000..408e0dbb3 --- /dev/null +++ b/package/kernel/mac80211/patches/ath11k/0161-ath11k-set-WMI_PEER_40MHZ-while-peer-assoc-for-6-GHz.patch @@ -0,0 +1,31 @@ +From 1cb747192de2edb7e55920af8c458e4792908486 Mon Sep 17 00:00:00 2001 +From: Wen Gong +Date: Tue, 18 Jan 2022 22:42:11 -0500 +Subject: [PATCH 161/162] ath11k: set WMI_PEER_40MHZ while peer assoc for 6 GHz + +When station connect to AP of 6 GHz with 40 MHz bandwidth, the TX is +always stay 20 MHz, it is because the flag WMI_PEER_40MHZ is not set +while peer assoc. Add the flag if remote peer is 40 MHz bandwidth. + +Tested-on: WCN6855 hw2.0 PCI WLAN.HSP.1.1-03003-QCAHSPSWPL_V1_V2_SILICONZ_LITE-2 + +Fixes: c3a7d7eb4c98 ("ath11k: add 6 GHz params in peer assoc command") +Signed-off-by: Wen Gong +Signed-off-by: Kalle Valo +Link: https://lore.kernel.org/r/20220119034211.28622-1-quic_wgong@quicinc.com +--- + drivers/net/wireless/ath/ath11k/mac.c | 3 +++ + 1 file changed, 3 insertions(+) + +--- a/drivers/net/wireless/ath/ath11k/mac.c ++++ b/drivers/net/wireless/ath/ath11k/mac.c +@@ -2319,6 +2319,9 @@ static void ath11k_peer_assoc_h_he_6ghz( + if (!arg->he_flag || band != NL80211_BAND_6GHZ || !sta->he_6ghz_capa.capa) + return; + ++ if (sta->bandwidth == IEEE80211_STA_RX_BW_40) ++ arg->bw_40 = true; ++ + if (sta->bandwidth == IEEE80211_STA_RX_BW_80) + arg->bw_80 = true; + diff --git a/package/kernel/mac80211/patches/ath11k/0162-ath11k-avoid-firmware-crash-when-reg-set-for-QCA6390.patch b/package/kernel/mac80211/patches/ath11k/0162-ath11k-avoid-firmware-crash-when-reg-set-for-QCA6390.patch new file mode 100644 index 000000000..eb4f5495c --- /dev/null +++ b/package/kernel/mac80211/patches/ath11k/0162-ath11k-avoid-firmware-crash-when-reg-set-for-QCA6390.patch @@ -0,0 +1,137 @@ +From 0d6e997b76216ca104167a2a0fb79823a7fa9e97 Mon Sep 17 00:00:00 2001 +From: Wen Gong +Date: Tue, 18 Jan 2022 23:13:55 -0500 +Subject: [PATCH 162/162] ath11k: avoid firmware crash when reg set for + QCA6390/WCN6855 + +For the NL80211_REGDOM_SET_BY_USER hint from cfg80211, it set the new +alpha2 code to ath11k, then ath11k send WMI_SET_INIT_COUNTRY_CMDID to +firmware for all chips currently. When test with WCN6855/QCA6390 chips, +this WMI CMD leads firmware crash. + +For AP based chips(ipq8074/qcn9074), WMI_SET_INIT_COUNTRY_CMDID is used +to send to firmware, for STATION based chips(WCN6855/QCA6390), it need to +use another WMI CMD WMI_SET_CURRENT_COUNTRY_CMDID. + +Add flag current_cc_support in hardware parameters, it is used to +distinguish AP/STA platform. After that, the firmware will work +normal and the regulatory feature works well for QCA6390/WCN6855. + +Tested-on: QCA6390 hw2.0 PCI WLAN.HST.1.0.1-01740-QCAHSTSWPLZ_V2_TO_X86-1 +Tested-on: WCN6855 hw2.0 PCI WLAN.HSP.1.1-03003-QCAHSPSWPL_V1_V2_SILICONZ_LITE-2 + +Signed-off-by: Wen Gong +Signed-off-by: Kalle Valo +Link: https://lore.kernel.org/r/20220119041355.32014-1-quic_wgong@quicinc.com +--- + drivers/net/wireless/ath/ath11k/core.c | 6 ++++++ + drivers/net/wireless/ath/ath11k/hw.h | 1 + + drivers/net/wireless/ath/ath11k/reg.c | 25 +++++++++++++++++-------- + 3 files changed, 24 insertions(+), 8 deletions(-) + +--- a/drivers/net/wireless/ath/ath11k/core.c ++++ b/drivers/net/wireless/ath/ath11k/core.c +@@ -98,6 +98,7 @@ static const struct ath11k_hw_params ath + .wakeup_mhi = false, + .supports_rssi_stats = false, + .fw_wmi_diag_event = false, ++ .current_cc_support = false, + }, + { + .hw_rev = ATH11K_HW_IPQ6018_HW10, +@@ -162,6 +163,7 @@ static const struct ath11k_hw_params ath + .wakeup_mhi = false, + .supports_rssi_stats = false, + .fw_wmi_diag_event = false, ++ .current_cc_support = false, + }, + { + .name = "qca6390 hw2.0", +@@ -225,6 +227,7 @@ static const struct ath11k_hw_params ath + .wakeup_mhi = true, + .supports_rssi_stats = true, + .fw_wmi_diag_event = true, ++ .current_cc_support = true, + }, + { + .name = "qcn9074 hw1.0", +@@ -288,6 +291,7 @@ static const struct ath11k_hw_params ath + .wakeup_mhi = false, + .supports_rssi_stats = false, + .fw_wmi_diag_event = false, ++ .current_cc_support = false, + }, + { + .name = "wcn6855 hw2.0", +@@ -351,6 +355,7 @@ static const struct ath11k_hw_params ath + .wakeup_mhi = true, + .supports_rssi_stats = true, + .fw_wmi_diag_event = true, ++ .current_cc_support = true, + }, + { + .name = "wcn6855 hw2.1", +@@ -413,6 +418,7 @@ static const struct ath11k_hw_params ath + .wakeup_mhi = true, + .supports_rssi_stats = true, + .fw_wmi_diag_event = true, ++ .current_cc_support = true, + }, + }; + +--- a/drivers/net/wireless/ath/ath11k/hw.h ++++ b/drivers/net/wireless/ath/ath11k/hw.h +@@ -192,6 +192,7 @@ struct ath11k_hw_params { + bool wakeup_mhi; + bool supports_rssi_stats; + bool fw_wmi_diag_event; ++ bool current_cc_support; + }; + + struct ath11k_hw_ops { +--- a/drivers/net/wireless/ath/ath11k/reg.c ++++ b/drivers/net/wireless/ath/ath11k/reg.c +@@ -46,6 +46,7 @@ ath11k_reg_notifier(struct wiphy *wiphy, + { + struct ieee80211_hw *hw = wiphy_to_ieee80211_hw(wiphy); + struct wmi_init_country_params init_country_param; ++ struct wmi_set_current_country_params set_current_param = {}; + struct ath11k *ar = hw->priv; + int ret; + +@@ -74,18 +75,26 @@ ath11k_reg_notifier(struct wiphy *wiphy, + return; + } + +- /* Set the country code to the firmware and wait for ++ /* Set the country code to the firmware and will receive + * the WMI_REG_CHAN_LIST_CC EVENT for updating the + * reg info + */ +- init_country_param.flags = ALPHA_IS_SET; +- memcpy(&init_country_param.cc_info.alpha2, request->alpha2, 2); +- init_country_param.cc_info.alpha2[2] = 0; +- +- ret = ath11k_wmi_send_init_country_cmd(ar, init_country_param); +- if (ret) +- ath11k_warn(ar->ab, +- "INIT Country code set to fw failed : %d\n", ret); ++ if (ar->ab->hw_params.current_cc_support) { ++ memcpy(&set_current_param.alpha2, request->alpha2, 2); ++ ret = ath11k_wmi_send_set_current_country_cmd(ar, &set_current_param); ++ if (ret) ++ ath11k_warn(ar->ab, ++ "failed set current country code: %d\n", ret); ++ } else { ++ init_country_param.flags = ALPHA_IS_SET; ++ memcpy(&init_country_param.cc_info.alpha2, request->alpha2, 2); ++ init_country_param.cc_info.alpha2[2] = 0; ++ ++ ret = ath11k_wmi_send_init_country_cmd(ar, init_country_param); ++ if (ret) ++ ath11k_warn(ar->ab, ++ "INIT Country code set to fw failed : %d\n", ret); ++ } + + ath11k_mac_11d_scan_stop(ar); + ar->regdom_set_by_user = true; diff --git a/package/kernel/mac80211/patches/ath11k/0163-ath11k-Rename-ath11k_ahb_ext_irq_config.patch b/package/kernel/mac80211/patches/ath11k/0163-ath11k-Rename-ath11k_ahb_ext_irq_config.patch new file mode 100644 index 000000000..2c1bdc768 --- /dev/null +++ b/package/kernel/mac80211/patches/ath11k/0163-ath11k-Rename-ath11k_ahb_ext_irq_config.patch @@ -0,0 +1,35 @@ +From a76ed59163ba82462ccb262b4c3590a3c1a115dd Mon Sep 17 00:00:00 2001 +From: Venkateswara Naralasetty +Date: Wed, 19 Jan 2022 14:48:13 +0530 +Subject: [PATCH 163/171] ath11k: Rename ath11k_ahb_ext_irq_config + +Rename ath11k_ahb_ext_irq_config() to ath11k_ahb_config_ext_irq() +for just symmetry with ath11k_ahb_free_ext_irq(). + +Signed-off-by: Venkateswara Naralasetty +Signed-off-by: Kalle Valo +Link: https://lore.kernel.org/r/1642583893-21485-1-git-send-email-quic_vnaralas@quicinc.com +--- + drivers/net/wireless/ath/ath11k/ahb.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +--- a/drivers/net/wireless/ath/ath11k/ahb.c ++++ b/drivers/net/wireless/ath/ath11k/ahb.c +@@ -466,7 +466,7 @@ static irqreturn_t ath11k_ahb_ext_interr + return IRQ_HANDLED; + } + +-static int ath11k_ahb_ext_irq_config(struct ath11k_base *ab) ++static int ath11k_ahb_config_ext_irq(struct ath11k_base *ab) + { + struct ath11k_hw_params *hw = &ab->hw_params; + int i, j; +@@ -574,7 +574,7 @@ static int ath11k_ahb_config_irq(struct + } + + /* Configure external interrupts */ +- ret = ath11k_ahb_ext_irq_config(ab); ++ ret = ath11k_ahb_config_ext_irq(ab); + + return ret; + } diff --git a/package/kernel/mac80211/patches/ath11k/0164-ath11k-fix-kernel-panic-during-unload-load-ath11k-mo.patch b/package/kernel/mac80211/patches/ath11k/0164-ath11k-fix-kernel-panic-during-unload-load-ath11k-mo.patch new file mode 100644 index 000000000..1b54c2a8b --- /dev/null +++ b/package/kernel/mac80211/patches/ath11k/0164-ath11k-fix-kernel-panic-during-unload-load-ath11k-mo.patch @@ -0,0 +1,56 @@ +From 22b59cb965f79ee1accf83172441c9ca0ecb632a Mon Sep 17 00:00:00 2001 +From: Venkateswara Naralasetty +Date: Wed, 19 Jan 2022 14:49:33 +0530 +Subject: [PATCH 164/171] ath11k: fix kernel panic during unload/load ath11k + modules + +Call netif_napi_del() from ath11k_ahb_free_ext_irq() to fix +the following kernel panic when unload/load ath11k modules +for few iterations. + +[ 971.201365] Unable to handle kernel paging request at virtual address 6d97a208 +[ 971.204227] pgd = 594c2919 +[ 971.211478] [6d97a208] *pgd=00000000 +[ 971.214120] Internal error: Oops: 5 [#1] PREEMPT SMP ARM +[ 971.412024] CPU: 2 PID: 4435 Comm: insmod Not tainted 5.4.89 #0 +[ 971.434256] Hardware name: Generic DT based system +[ 971.440165] PC is at napi_by_id+0x10/0x40 +[ 971.445019] LR is at netif_napi_add+0x160/0x1dc + +[ 971.743127] (napi_by_id) from [<807d89a0>] (netif_napi_add+0x160/0x1dc) +[ 971.751295] (netif_napi_add) from [<7f1209ac>] (ath11k_ahb_config_irq+0xf8/0x414 [ath11k_ahb]) +[ 971.759164] (ath11k_ahb_config_irq [ath11k_ahb]) from [<7f12135c>] (ath11k_ahb_probe+0x40c/0x51c [ath11k_ahb]) +[ 971.768567] (ath11k_ahb_probe [ath11k_ahb]) from [<80666864>] (platform_drv_probe+0x48/0x94) +[ 971.779670] (platform_drv_probe) from [<80664718>] (really_probe+0x1c8/0x450) +[ 971.789389] (really_probe) from [<80664cc4>] (driver_probe_device+0x15c/0x1b8) +[ 971.797547] (driver_probe_device) from [<80664f60>] (device_driver_attach+0x44/0x60) +[ 971.805795] (device_driver_attach) from [<806650a0>] (__driver_attach+0x124/0x140) +[ 971.814822] (__driver_attach) from [<80662adc>] (bus_for_each_dev+0x58/0xa4) +[ 971.823328] (bus_for_each_dev) from [<80663a2c>] (bus_add_driver+0xf0/0x1e8) +[ 971.831662] (bus_add_driver) from [<806658a4>] (driver_register+0xa8/0xf0) +[ 971.839822] (driver_register) from [<8030269c>] (do_one_initcall+0x78/0x1ac) +[ 971.847638] (do_one_initcall) from [<80392524>] (do_init_module+0x54/0x200) +[ 971.855968] (do_init_module) from [<803945b0>] (load_module+0x1e30/0x1ffc) +[ 971.864126] (load_module) from [<803948b0>] (sys_init_module+0x134/0x17c) +[ 971.871852] (sys_init_module) from [<80301000>] (ret_fast_syscall+0x0/0x50) + +Tested-on: IPQ8074 hw2.0 AHB WLAN.HK.2.6.0.1-00760-QCAHKSWPL_SILICONZ-1 + +Signed-off-by: Venkateswara Naralasetty +Signed-off-by: Kalle Valo +Link: https://lore.kernel.org/r/1642583973-21599-1-git-send-email-quic_vnaralas@quicinc.com +--- + drivers/net/wireless/ath/ath11k/ahb.c | 2 ++ + 1 file changed, 2 insertions(+) + +--- a/drivers/net/wireless/ath/ath11k/ahb.c ++++ b/drivers/net/wireless/ath/ath11k/ahb.c +@@ -391,6 +391,8 @@ static void ath11k_ahb_free_ext_irq(stru + + for (j = 0; j < irq_grp->num_irq; j++) + free_irq(ab->irq_num[irq_grp->irqs[j]], irq_grp); ++ ++ netif_napi_del(&irq_grp->napi); + } + } + diff --git a/package/kernel/mac80211/patches/ath11k/0165-ath11k-Fix-uninitialized-symbol-rx_buf_sz.patch b/package/kernel/mac80211/patches/ath11k/0165-ath11k-Fix-uninitialized-symbol-rx_buf_sz.patch new file mode 100644 index 000000000..4dd4ed68e --- /dev/null +++ b/package/kernel/mac80211/patches/ath11k/0165-ath11k-Fix-uninitialized-symbol-rx_buf_sz.patch @@ -0,0 +1,57 @@ +From dca857f07dc14c923a3c47965e771f435807b39c Mon Sep 17 00:00:00 2001 +From: Anilkumar Kolli +Date: Wed, 19 Jan 2022 20:53:13 +0530 +Subject: [PATCH 165/171] ath11k: Fix uninitialized symbol 'rx_buf_sz' + +Add missing else statement in ath11k_dp_rx_process_mon_status() +to fix below smatch warnings, + drivers/net/wireless/ath/ath11k/dp_rx.c:3105 + ath11k_dp_rx_process_mon_status() + error: uninitialized symbol 'rx_buf_sz'. + +Fixes: ab18e3bc1c13 ("ath11k: Fix pktlog lite rx events") + +Reported-by: Dan Carpenter +Signed-off-by: Anilkumar Kolli +Signed-off-by: Kalle Valo +Link: https://lore.kernel.org/r/1642605793-13518-1-git-send-email-quic_akolli@quicinc.com +--- + drivers/net/wireless/ath/ath11k/debugfs.h | 1 + + drivers/net/wireless/ath/ath11k/dp_rx.c | 7 +++++-- + 2 files changed, 6 insertions(+), 2 deletions(-) + +--- a/drivers/net/wireless/ath/ath11k/debugfs.h ++++ b/drivers/net/wireless/ath/ath11k/debugfs.h +@@ -88,6 +88,7 @@ enum ath11k_pktlog_mode { + }; + + enum ath11k_pktlog_enum { ++ ATH11K_PKTLOG_TYPE_INVALID = 0, + ATH11K_PKTLOG_TYPE_TX_CTRL = 1, + ATH11K_PKTLOG_TYPE_TX_STAT = 2, + ATH11K_PKTLOG_TYPE_TX_MSDU_ID = 3, +--- a/drivers/net/wireless/ath/ath11k/dp_rx.c ++++ b/drivers/net/wireless/ath/ath11k/dp_rx.c +@@ -5054,7 +5054,7 @@ int ath11k_dp_rx_process_mon_status(stru + struct ath11k_sta *arsta; + int num_buffs_reaped = 0; + u32 rx_buf_sz; +- u16 log_type = 0; ++ u16 log_type; + struct ath11k_mon_data *pmon = (struct ath11k_mon_data *)&ar->dp.mon_data; + struct ath11k_pdev_mon_stats *rx_mon_stats = &pmon->rx_mon_stats; + struct hal_rx_mon_ppdu_info *ppdu_info = &pmon->mon_ppdu_info; +@@ -5076,9 +5076,12 @@ int ath11k_dp_rx_process_mon_status(stru + } else if (ath11k_debugfs_is_pktlog_rx_stats_enabled(ar)) { + log_type = ATH11K_PKTLOG_TYPE_RX_STATBUF; + rx_buf_sz = DP_RX_BUFFER_SIZE; ++ } else { ++ log_type = ATH11K_PKTLOG_TYPE_INVALID; ++ rx_buf_sz = 0; + } + +- if (log_type) ++ if (log_type != ATH11K_PKTLOG_TYPE_INVALID) + trace_ath11k_htt_rxdesc(ar, skb->data, log_type, rx_buf_sz); + + hal_status = ath11k_hal_rx_parse_mon_status(ab, ppdu_info, skb); diff --git a/package/kernel/mac80211/patches/ath11k/0166-ath11k-Fix-missing-rx_desc_get_ldpc_support-in-wcn68.patch b/package/kernel/mac80211/patches/ath11k/0166-ath11k-Fix-missing-rx_desc_get_ldpc_support-in-wcn68.patch new file mode 100644 index 000000000..38cb34bdc --- /dev/null +++ b/package/kernel/mac80211/patches/ath11k/0166-ath11k-Fix-missing-rx_desc_get_ldpc_support-in-wcn68.patch @@ -0,0 +1,68 @@ +From 648ab4720cb76d0b5b1e49d3c0f0bdf28e22e52a Mon Sep 17 00:00:00 2001 +From: Baochen Qiang +Date: Wed, 26 Jan 2022 09:01:44 +0800 +Subject: [PATCH 166/171] ath11k: Fix missing rx_desc_get_ldpc_support in + wcn6855_ops + +rx_desc_get_ldpc_support is missing in wcn6855_ops, resulting on WCN6855 a +kernel crash after connecting to an AP and waiting for few minutes. Fix it by +implementing WCN6855's version of this field and adding it to wcn6855_ops. + +Crash stack: +[ 184.862605] BUG: kernel NULL pointer dereference, address: 0000000000000000 +[ 184.862615] #PF: supervisor instruction fetch in kernel mode +[ 184.862620] #PF: error_code(0x0010) - not-present page +[ 184.862626] PGD 0 P4D 0 +[ 184.862634] Oops: 0010 [#1] PREEMPT SMP PTI +[ 184.862642] CPU: 1 PID: 0 Comm: swapper/1 Kdump: loaded Not tainted 5.16.0-wt-ath+ #1 +[ 184.862651] Hardware name: Intel(R) Client Systems NUC8i7HVK/NUC8i7HVB, BIOS HNKBLi70.86A.0059.2019.1112.1124 11/12/2019 +[ 184.862656] RIP: 0010:0x0 +[ 184.862669] Code: Unable to access opcode bytes at RIP 0xffffffffffffffd6. +[ 184.862673] RSP: 0018:ffff9eedc003cca8 EFLAGS: 00010202 +[ 184.862680] RAX: 0000000000000000 RBX: ffff9eedc003cd30 RCX: 0000000000000002 +[ 184.862686] RDX: 0000000000000002 RSI: ffffffffc1773458 RDI: ffff8eb5843de240 +[ 184.862692] RBP: ffff8eb59685a0e0 R08: 0000000000000001 R09: ffff8eb6fef2b000 +[ 184.862700] R10: ffff9eedc003cd70 R11: ffff8eb5880a9ff0 R12: ffff8eb5843de240 +[ 184.862707] R13: 0000000000000000 R14: 0000000000000008 R15: 0000000000000003 +[ 184.862714] FS: 0000000000000000(0000) GS:ffff8eb6f6c40000(0000) knlGS:0000000000000000 +[ 184.862723] CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033 +[ 184.862733] CR2: ffffffffffffffd6 CR3: 000000002f60a001 CR4: 00000000003706e0 +[ 184.862743] Call Trace: +[ 184.862751] +[ 184.862759] ath11k_dp_rx_h_ppdu+0x210/0x350 [ath11k] +[ 184.862841] ath11k_dp_rx_process_received_packets+0x1e6/0x6b0 [ath11k] +[ 184.862891] ath11k_dp_process_rx+0x32d/0x3e0 [ath11k] + +Tested-on: WCN6855 hw2.0 PCI WLAN.HSP.1.1-01720.1-QCAHSPSWPL_V1_V2_SILICONZ_LITE-1 + +Fixes: b3febdccde3e ("ath11k: add LDPC FEC type in 802.11 radiotap header") +Signed-off-by: Baochen Qiang +Signed-off-by: Kalle Valo +Link: https://lore.kernel.org/r/20220126010144.2090-1-quic_bqiang@quicinc.com +--- + drivers/net/wireless/ath/ath11k/hw.c | 7 +++++++ + 1 file changed, 7 insertions(+) + +--- a/drivers/net/wireless/ath/ath11k/hw.c ++++ b/drivers/net/wireless/ath/ath11k/hw.c +@@ -813,6 +813,12 @@ static u16 ath11k_hw_wcn6855_mpdu_info_g + return peer_id; + } + ++static bool ath11k_hw_wcn6855_rx_desc_get_ldpc_support(struct hal_rx_desc *desc) ++{ ++ return FIELD_GET(RX_MSDU_START_INFO2_LDPC, ++ __le32_to_cpu(desc->u.wcn6855.msdu_start.info2)); ++} ++ + const struct ath11k_hw_ops ipq8074_ops = { + .get_hw_mac_from_pdev_id = ath11k_hw_ipq8074_mac_from_pdev_id, + .wmi_init_config = ath11k_init_wmi_config_ipq8074, +@@ -983,6 +989,7 @@ const struct ath11k_hw_ops wcn6855_ops = + .rx_desc_get_encrypt_type = ath11k_hw_wcn6855_rx_desc_get_encrypt_type, + .rx_desc_get_decap_type = ath11k_hw_wcn6855_rx_desc_get_decap_type, + .rx_desc_get_mesh_ctl = ath11k_hw_wcn6855_rx_desc_get_mesh_ctl, ++ .rx_desc_get_ldpc_support = ath11k_hw_wcn6855_rx_desc_get_ldpc_support, + .rx_desc_get_mpdu_seq_ctl_vld = ath11k_hw_wcn6855_rx_desc_get_mpdu_seq_ctl_vld, + .rx_desc_get_mpdu_fc_valid = ath11k_hw_wcn6855_rx_desc_get_mpdu_fc_valid, + .rx_desc_get_mpdu_start_seq_no = ath11k_hw_wcn6855_rx_desc_get_mpdu_start_seq_no, diff --git a/package/kernel/mac80211/patches/ath11k/0167-ath11k-pci-fix-crash-on-suspend-if-board-file-is-not.patch b/package/kernel/mac80211/patches/ath11k/0167-ath11k-pci-fix-crash-on-suspend-if-board-file-is-not.patch new file mode 100644 index 000000000..3257d2c6e --- /dev/null +++ b/package/kernel/mac80211/patches/ath11k/0167-ath11k-pci-fix-crash-on-suspend-if-board-file-is-not.patch @@ -0,0 +1,85 @@ +From b4f4c56459a5c744f7f066b9fc2b54ea995030c5 Mon Sep 17 00:00:00 2001 +From: Kalle Valo +Date: Thu, 27 Jan 2022 11:01:16 +0200 +Subject: [PATCH 167/171] ath11k: pci: fix crash on suspend if board file is + not found + +Mario reported that the kernel was crashing on suspend if ath11k was not able +to find a board file: + +[ 473.693286] PM: Suspending system (s2idle) +[ 473.693291] printk: Suspending console(s) (use no_console_suspend to debug) +[ 474.407787] BUG: unable to handle page fault for address: 0000000000002070 +[ 474.407791] #PF: supervisor read access in kernel mode +[ 474.407794] #PF: error_code(0x0000) - not-present page +[ 474.407798] PGD 0 P4D 0 +[ 474.407801] Oops: 0000 [#1] PREEMPT SMP NOPTI +[ 474.407805] CPU: 2 PID: 2350 Comm: kworker/u32:14 Tainted: G W 5.16.0 #248 +[...] +[ 474.407868] Call Trace: +[ 474.407870] +[ 474.407874] ? _raw_spin_lock_irqsave+0x2a/0x60 +[ 474.407882] ? lock_timer_base+0x72/0xa0 +[ 474.407889] ? _raw_spin_unlock_irqrestore+0x29/0x3d +[ 474.407892] ? try_to_del_timer_sync+0x54/0x80 +[ 474.407896] ath11k_dp_rx_pktlog_stop+0x49/0xc0 [ath11k] +[ 474.407912] ath11k_core_suspend+0x34/0x130 [ath11k] +[ 474.407923] ath11k_pci_pm_suspend+0x1b/0x50 [ath11k_pci] +[ 474.407928] pci_pm_suspend+0x7e/0x170 +[ 474.407935] ? pci_pm_freeze+0xc0/0xc0 +[ 474.407939] dpm_run_callback+0x4e/0x150 +[ 474.407947] __device_suspend+0x148/0x4c0 +[ 474.407951] async_suspend+0x20/0x90 +dmesg-efi-164255130401001: +Oops#1 Part1 +[ 474.407955] async_run_entry_fn+0x33/0x120 +[ 474.407959] process_one_work+0x220/0x3f0 +[ 474.407966] worker_thread+0x4a/0x3d0 +[ 474.407971] kthread+0x17a/0x1a0 +[ 474.407975] ? process_one_work+0x3f0/0x3f0 +[ 474.407979] ? set_kthread_struct+0x40/0x40 +[ 474.407983] ret_from_fork+0x22/0x30 +[ 474.407991] + +The issue here is that board file loading happens after ath11k_pci_probe() +succesfully returns (ath11k initialisation happends asynchronously) and the +suspend handler is still enabled, of course failing as ath11k is not properly +initialised. Fix this by checking ATH11K_FLAG_QMI_FAIL during both suspend and +resume. + +Tested-on: WCN6855 hw2.0 PCI WLAN.HSP.1.1-03003-QCAHSPSWPL_V1_V2_SILICONZ_LITE-2 + +Reported-by: Mario Limonciello +Link: https://bugzilla.kernel.org/show_bug.cgi?id=215504 +Signed-off-by: Kalle Valo +Link: https://lore.kernel.org/r/20220127090117.2024-1-kvalo@kernel.org +--- + drivers/net/wireless/ath/ath11k/pci.c | 10 ++++++++++ + 1 file changed, 10 insertions(+) + +--- a/drivers/net/wireless/ath/ath11k/pci.c ++++ b/drivers/net/wireless/ath/ath11k/pci.c +@@ -1571,6 +1571,11 @@ static __maybe_unused int ath11k_pci_pm_ + struct ath11k_base *ab = dev_get_drvdata(dev); + int ret; + ++ if (test_bit(ATH11K_FLAG_QMI_FAIL, &ab->dev_flags)) { ++ ath11k_dbg(ab, ATH11K_DBG_BOOT, "boot skipping pci suspend as qmi is not initialised\n"); ++ return 0; ++ } ++ + ret = ath11k_core_suspend(ab); + if (ret) + ath11k_warn(ab, "failed to suspend core: %d\n", ret); +@@ -1583,6 +1588,11 @@ static __maybe_unused int ath11k_pci_pm_ + struct ath11k_base *ab = dev_get_drvdata(dev); + int ret; + ++ if (test_bit(ATH11K_FLAG_QMI_FAIL, &ab->dev_flags)) { ++ ath11k_dbg(ab, ATH11K_DBG_BOOT, "boot skipping pci resume as qmi is not initialised\n"); ++ return 0; ++ } ++ + ret = ath11k_core_resume(ab); + if (ret) + ath11k_warn(ab, "failed to resume core: %d\n", ret); diff --git a/package/kernel/mac80211/patches/ath11k/0168-ath11k-mhi-use-mhi_sync_power_up.patch b/package/kernel/mac80211/patches/ath11k/0168-ath11k-mhi-use-mhi_sync_power_up.patch new file mode 100644 index 000000000..990d69850 --- /dev/null +++ b/package/kernel/mac80211/patches/ath11k/0168-ath11k-mhi-use-mhi_sync_power_up.patch @@ -0,0 +1,77 @@ +From 3df6d74aedfdca919cca475d15dfdbc8b05c9e5d Mon Sep 17 00:00:00 2001 +From: Kalle Valo +Date: Thu, 27 Jan 2022 11:01:17 +0200 +Subject: [PATCH 168/171] ath11k: mhi: use mhi_sync_power_up() + +If amss.bin was missing ath11k would crash during 'rmmod ath11k_pci'. The +reason for that was that we were using mhi_async_power_up() which does not +check any errors. But mhi_sync_power_up() on the other hand does check for +errors so let's use that to fix the crash. + +I was not able to find a reason why an async version was used. +ath11k_mhi_start() (which enables state ATH11K_MHI_POWER_ON) is called from +ath11k_hif_power_up(), which can sleep. So sync version should be safe to use +here. + +[ 145.569731] general protection fault, probably for non-canonical address 0xdffffc0000000000: 0000 [#1] PREEMPT SMP DEBUG_PAGEALLOC KASAN PTI +[ 145.569789] KASAN: null-ptr-deref in range [0x0000000000000000-0x0000000000000007] +[ 145.569843] CPU: 2 PID: 1628 Comm: rmmod Kdump: loaded Tainted: G W 5.16.0-wt-ath+ #567 +[ 145.569898] Hardware name: Intel(R) Client Systems NUC8i7HVK/NUC8i7HVB, BIOS HNKBLi70.86A.0067.2021.0528.1339 05/28/2021 +[ 145.569956] RIP: 0010:ath11k_hal_srng_access_begin+0xb5/0x2b0 [ath11k] +[ 145.570028] Code: df 48 89 fa 48 c1 ea 03 80 3c 02 00 0f 85 ec 01 00 00 48 8b ab a8 00 00 00 48 b8 00 00 00 00 00 fc ff df 48 89 ea 48 c1 ea 03 <0f> b6 14 02 48 89 e8 83 e0 07 83 c0 03 45 85 ed 75 48 38 d0 7c 08 +[ 145.570089] RSP: 0018:ffffc900025d7ac0 EFLAGS: 00010246 +[ 145.570144] RAX: dffffc0000000000 RBX: ffff88814fca2dd8 RCX: 1ffffffff50cb455 +[ 145.570196] RDX: 0000000000000000 RSI: ffff88814fca2dd8 RDI: ffff88814fca2e80 +[ 145.570252] RBP: 0000000000000000 R08: 0000000000000000 R09: ffffffffa8659497 +[ 145.570329] R10: fffffbfff50cb292 R11: 0000000000000001 R12: ffff88814fca0000 +[ 145.570410] R13: 0000000000000000 R14: ffff88814fca2798 R15: ffff88814fca2dd8 +[ 145.570465] FS: 00007fa399988540(0000) GS:ffff888233e00000(0000) knlGS:0000000000000000 +[ 145.570519] CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033 +[ 145.570571] CR2: 00007fa399b51421 CR3: 0000000137898002 CR4: 00000000003706e0 +[ 145.570623] Call Trace: +[ 145.570675] +[ 145.570727] ? ath11k_ce_tx_process_cb+0x34b/0x860 [ath11k] +[ 145.570797] ath11k_ce_tx_process_cb+0x356/0x860 [ath11k] +[ 145.570864] ? tasklet_init+0x150/0x150 +[ 145.570919] ? ath11k_ce_alloc_pipes+0x280/0x280 [ath11k] +[ 145.570986] ? tasklet_clear_sched+0x42/0xe0 +[ 145.571042] ? tasklet_kill+0xe9/0x1b0 +[ 145.571095] ? tasklet_clear_sched+0xe0/0xe0 +[ 145.571148] ? irq_has_action+0x120/0x120 +[ 145.571202] ath11k_ce_cleanup_pipes+0x45a/0x580 [ath11k] +[ 145.571270] ? ath11k_pci_stop+0x10e/0x170 [ath11k_pci] +[ 145.571345] ath11k_core_stop+0x8a/0xc0 [ath11k] +[ 145.571434] ath11k_core_deinit+0x9e/0x150 [ath11k] +[ 145.571499] ath11k_pci_remove+0xd2/0x260 [ath11k_pci] +[ 145.571553] pci_device_remove+0x9a/0x1c0 +[ 145.571605] __device_release_driver+0x332/0x660 +[ 145.571659] driver_detach+0x1e7/0x2c0 +[ 145.571712] bus_remove_driver+0xe2/0x2d0 +[ 145.571772] pci_unregister_driver+0x21/0x250 +[ 145.571826] __do_sys_delete_module+0x30a/0x4b0 +[ 145.571879] ? free_module+0xac0/0xac0 +[ 145.571933] ? lockdep_hardirqs_on_prepare.part.0+0x18c/0x370 +[ 145.571986] ? syscall_enter_from_user_mode+0x1d/0x50 +[ 145.572039] ? lockdep_hardirqs_on+0x79/0x100 +[ 145.572097] do_syscall_64+0x3b/0x90 +[ 145.572153] entry_SYSCALL_64_after_hwframe+0x44/0xae + +Tested-on: WCN6855 hw2.0 PCI WLAN.HSP.1.1-03003-QCAHSPSWPL_V1_V2_SILICONZ_LITE-2 + +Signed-off-by: Kalle Valo +Link: https://lore.kernel.org/r/20220127090117.2024-2-kvalo@kernel.org +--- + drivers/net/wireless/ath/ath11k/mhi.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +--- a/drivers/net/wireless/ath/ath11k/mhi.c ++++ b/drivers/net/wireless/ath/ath11k/mhi.c +@@ -563,7 +563,7 @@ static int ath11k_mhi_set_state(struct a + ret = 0; + break; + case ATH11K_MHI_POWER_ON: +- ret = mhi_async_power_up(ab_pci->mhi_ctrl); ++ ret = mhi_sync_power_up(ab_pci->mhi_ctrl); + break; + case ATH11K_MHI_POWER_OFF: + mhi_power_down(ab_pci->mhi_ctrl, true); diff --git a/package/kernel/mac80211/patches/ath11k/0169-ath11k-Add-debugfs-interface-to-configure-firmware-d.patch b/package/kernel/mac80211/patches/ath11k/0169-ath11k-Add-debugfs-interface-to-configure-firmware-d.patch new file mode 100644 index 000000000..5748341c4 --- /dev/null +++ b/package/kernel/mac80211/patches/ath11k/0169-ath11k-Add-debugfs-interface-to-configure-firmware-d.patch @@ -0,0 +1,404 @@ +From f295ad912910e08d9b887a0c952f82d9612459d4 Mon Sep 17 00:00:00 2001 +From: Seevalamuthu Mariappan +Date: Mon, 31 Jan 2022 16:16:44 +0200 +Subject: [PATCH 169/171] ath11k: Add debugfs interface to configure firmware + debug log level + +Add debugfs interface "fw_dbglog_config" to configure firmware log level. +Configuration is done via WMI command WMI_DBGLOG_CFG_CMDID. + +Command to configure, +echo " " > +/sys/kernel/debug/ath11k//macX/fw_dbglog_config + +where dbglog_param can be, + 1) WMI_DEBUG_LOG_PARAM_LOG_LEVEL - configure log level for a given module + here, = <0xaaaa00bb>, 'aaaa' - module id and 'bb' - loglevel + 2) WMI_DEBUG_LOG_PARAM_VDEV_ENABLE - enable debug log for a given vdev + here, = vdev_id + 3) WMI_DEBUG_LOG_PARAM_VDEV_DISABLE - disable debug log for a given vdev + except ERROR logs + here, = vdev_id + 4) WMI_DEBUG_LOG_PARAM_VDEV_ENABLE_BITMAP - set vdev enable bitmap + here, = vdev_enable_bitmap + 5) WMI_DEBUG_LOG_PARAM_MOD_ENABLE_BITMAP - set a given log level to all the + modules specified in the module bitmap. Command to configure for this log param, + + $ echo "5 " > + /sys/kernel/debug/ath11k//macX/fw_dbglog_config + here, + = <0xaaaaaaaa000000bb>, 'aaaaaaaa' - module bitmap and + 'bb' - loglevel + = index of module bitmap. Max module id is 512. + So, module_id_index is 0-15. + = to indicate if more configuration to follow. + + 6) WMI_DEBUG_LOG_PARAM_WOW_MOD_ENABLE_BITMAP - Wow mode specific logging enable. + Command to configure for this log param, + + $ echo "6 " > + /sys/kernel/debug/ath11k//macX/fw_dbglog_config + here, + = <0xaaaaaaaa000000bb>, 'aaaaaaaa' - module bitmap and + 'bb' - loglevel + = index of module bitmap. Max module id is 512. + So, module_id_index is 0-15. + = to indicate if more configuration to follow. + +Sample command usage, + +To enable module WLAN_MODULE_WMI and log level ATH11K_FW_DBGLOG_VERBOSE, +echo "1 0x10001" > /sys/kernel/debug/ath11k//macX/fw_dbglog_config + +To enable module bit map from 32 to 63 and log level ATH11K_FW_DBGLOG_VERBOSE, +echo "5 0xffffffff00000001 1 1" > /sys/kernel/debug/ath11k//macX/fw_dbglog_config + +Tested-on: QCN9074 hw1.0 PCI WLAN.HK.2.4.0.1-01734-QCAHKSWPL_SILICONZ-1 + +Signed-off-by: Seevalamuthu Mariappan +Signed-off-by: Kalle Valo +Link: https://lore.kernel.org/r/1642405103-32302-1-git-send-email-quic_seevalam@quicinc.com +--- + drivers/net/wireless/ath/ath11k/core.h | 4 + + drivers/net/wireless/ath/ath11k/debugfs.c | 66 ++++++++++++ + drivers/net/wireless/ath/ath11k/debugfs.h | 124 ++++++++++++++++++++++ + drivers/net/wireless/ath/ath11k/wmi.c | 53 +++++++++ + drivers/net/wireless/ath/ath11k/wmi.h | 18 ++++ + 5 files changed, 265 insertions(+) + +--- a/drivers/net/wireless/ath/ath11k/core.h ++++ b/drivers/net/wireless/ath/ath11k/core.h +@@ -441,6 +441,8 @@ struct ath11k_dbg_htt_stats { + spinlock_t lock; + }; + ++#define MAX_MODULE_ID_BITMAP_WORDS 16 ++ + struct ath11k_debug { + struct dentry *debugfs_pdev; + struct ath11k_dbg_htt_stats htt_stats; +@@ -454,6 +456,8 @@ struct ath11k_debug { + u32 pktlog_peer_valid; + u8 pktlog_peer_addr[ETH_ALEN]; + u32 rx_filter; ++ u32 mem_offset; ++ u32 module_id_bitmap[MAX_MODULE_ID_BITMAP_WORDS]; + }; + + struct ath11k_per_peer_tx_stats { +--- a/drivers/net/wireless/ath/ath11k/debugfs.c ++++ b/drivers/net/wireless/ath/ath11k/debugfs.c +@@ -874,6 +874,69 @@ static const struct file_operations fops + .llseek = default_llseek, + }; + ++static ssize_t ath11k_write_fw_dbglog(struct file *file, ++ const char __user *user_buf, ++ size_t count, loff_t *ppos) ++{ ++ struct ath11k *ar = file->private_data; ++ char buf[128] = {0}; ++ struct ath11k_fw_dbglog dbglog; ++ unsigned int param, mod_id_index, is_end; ++ u64 value; ++ int ret, num; ++ ++ ret = simple_write_to_buffer(buf, sizeof(buf) - 1, ppos, ++ user_buf, count); ++ if (ret <= 0) ++ return ret; ++ ++ num = sscanf(buf, "%u %llx %u %u", ¶m, &value, &mod_id_index, &is_end); ++ ++ if (num < 2) ++ return -EINVAL; ++ ++ mutex_lock(&ar->conf_mutex); ++ if (param == WMI_DEBUG_LOG_PARAM_MOD_ENABLE_BITMAP || ++ param == WMI_DEBUG_LOG_PARAM_WOW_MOD_ENABLE_BITMAP) { ++ if (num != 4 || mod_id_index > (MAX_MODULE_ID_BITMAP_WORDS - 1)) { ++ ret = -EINVAL; ++ goto out; ++ } ++ ar->debug.module_id_bitmap[mod_id_index] = upper_32_bits(value); ++ if (!is_end) { ++ ret = count; ++ goto out; ++ } ++ } else { ++ if (num != 2) { ++ ret = -EINVAL; ++ goto out; ++ } ++ } ++ ++ dbglog.param = param; ++ dbglog.value = lower_32_bits(value); ++ ret = ath11k_wmi_fw_dbglog_cfg(ar, ar->debug.module_id_bitmap, &dbglog); ++ if (ret) { ++ ath11k_warn(ar->ab, "fw dbglog config failed from debugfs: %d\n", ++ ret); ++ goto out; ++ } ++ ++ ret = count; ++ ++out: ++ mutex_unlock(&ar->conf_mutex); ++ return ret; ++} ++ ++static const struct file_operations fops_fw_dbglog = { ++ .write = ath11k_write_fw_dbglog, ++ .open = simple_open, ++ .owner = THIS_MODULE, ++ .llseek = default_llseek, ++}; ++ + int ath11k_debugfs_pdev_create(struct ath11k_base *ab) + { + if (test_bit(ATH11K_FLAG_REGISTERED, &ab->dev_flags)) +@@ -1140,6 +1203,9 @@ int ath11k_debugfs_register(struct ath11 + debugfs_create_file("pktlog_filter", 0644, + ar->debug.debugfs_pdev, ar, + &fops_pktlog_filter); ++ debugfs_create_file("fw_dbglog_config", 0600, ++ ar->debug.debugfs_pdev, ar, ++ &fops_fw_dbglog); + + if (ar->hw->wiphy->bands[NL80211_BAND_5GHZ]) { + debugfs_create_file("dfs_simulate_radar", 0200, +--- a/drivers/net/wireless/ath/ath11k/debugfs.h ++++ b/drivers/net/wireless/ath/ath11k/debugfs.h +@@ -108,6 +108,130 @@ enum ath11k_dbg_aggr_mode { + ATH11K_DBG_AGGR_MODE_MAX, + }; + ++enum fw_dbglog_wlan_module_id { ++ WLAN_MODULE_ID_MIN = 0, ++ WLAN_MODULE_INF = WLAN_MODULE_ID_MIN, ++ WLAN_MODULE_WMI, ++ WLAN_MODULE_STA_PWRSAVE, ++ WLAN_MODULE_WHAL, ++ WLAN_MODULE_COEX, ++ WLAN_MODULE_ROAM, ++ WLAN_MODULE_RESMGR_CHAN_MANAGER, ++ WLAN_MODULE_RESMGR, ++ WLAN_MODULE_VDEV_MGR, ++ WLAN_MODULE_SCAN, ++ WLAN_MODULE_RATECTRL, ++ WLAN_MODULE_AP_PWRSAVE, ++ WLAN_MODULE_BLOCKACK, ++ WLAN_MODULE_MGMT_TXRX, ++ WLAN_MODULE_DATA_TXRX, ++ WLAN_MODULE_HTT, ++ WLAN_MODULE_HOST, ++ WLAN_MODULE_BEACON, ++ WLAN_MODULE_OFFLOAD, ++ WLAN_MODULE_WAL, ++ WLAN_WAL_MODULE_DE, ++ WLAN_MODULE_PCIELP, ++ WLAN_MODULE_RTT, ++ WLAN_MODULE_RESOURCE, ++ WLAN_MODULE_DCS, ++ WLAN_MODULE_CACHEMGR, ++ WLAN_MODULE_ANI, ++ WLAN_MODULE_P2P, ++ WLAN_MODULE_CSA, ++ WLAN_MODULE_NLO, ++ WLAN_MODULE_CHATTER, ++ WLAN_MODULE_WOW, ++ WLAN_MODULE_WAL_VDEV, ++ WLAN_MODULE_WAL_PDEV, ++ WLAN_MODULE_TEST, ++ WLAN_MODULE_STA_SMPS, ++ WLAN_MODULE_SWBMISS, ++ WLAN_MODULE_WMMAC, ++ WLAN_MODULE_TDLS, ++ WLAN_MODULE_HB, ++ WLAN_MODULE_TXBF, ++ WLAN_MODULE_BATCH_SCAN, ++ WLAN_MODULE_THERMAL_MGR, ++ WLAN_MODULE_PHYERR_DFS, ++ WLAN_MODULE_RMC, ++ WLAN_MODULE_STATS, ++ WLAN_MODULE_NAN, ++ WLAN_MODULE_IBSS_PWRSAVE, ++ WLAN_MODULE_HIF_UART, ++ WLAN_MODULE_LPI, ++ WLAN_MODULE_EXTSCAN, ++ WLAN_MODULE_UNIT_TEST, ++ WLAN_MODULE_MLME, ++ WLAN_MODULE_SUPPL, ++ WLAN_MODULE_ERE, ++ WLAN_MODULE_OCB, ++ WLAN_MODULE_RSSI_MONITOR, ++ WLAN_MODULE_WPM, ++ WLAN_MODULE_CSS, ++ WLAN_MODULE_PPS, ++ WLAN_MODULE_SCAN_CH_PREDICT, ++ WLAN_MODULE_MAWC, ++ WLAN_MODULE_CMC_QMIC, ++ WLAN_MODULE_EGAP, ++ WLAN_MODULE_NAN20, ++ WLAN_MODULE_QBOOST, ++ WLAN_MODULE_P2P_LISTEN_OFFLOAD, ++ WLAN_MODULE_HALPHY, ++ WLAN_WAL_MODULE_ENQ, ++ WLAN_MODULE_GNSS, ++ WLAN_MODULE_WAL_MEM, ++ WLAN_MODULE_SCHED_ALGO, ++ WLAN_MODULE_TX, ++ WLAN_MODULE_RX, ++ WLAN_MODULE_WLM, ++ WLAN_MODULE_RU_ALLOCATOR, ++ WLAN_MODULE_11K_OFFLOAD, ++ WLAN_MODULE_STA_TWT, ++ WLAN_MODULE_AP_TWT, ++ WLAN_MODULE_UL_OFDMA, ++ WLAN_MODULE_HPCS_PULSE, ++ WLAN_MODULE_DTF, ++ WLAN_MODULE_QUIET_IE, ++ WLAN_MODULE_SHMEM_MGR, ++ WLAN_MODULE_CFIR, ++ WLAN_MODULE_CODE_COVER, ++ WLAN_MODULE_SHO, ++ WLAN_MODULE_MLO_MGR, ++ WLAN_MODULE_PEER_INIT, ++ WLAN_MODULE_STA_MLO_PS, ++ ++ WLAN_MODULE_ID_MAX, ++ WLAN_MODULE_ID_INVALID = WLAN_MODULE_ID_MAX, ++}; ++ ++enum fw_dbglog_log_level { ++ ATH11K_FW_DBGLOG_ML = 0, ++ ATH11K_FW_DBGLOG_VERBOSE = 0, ++ ATH11K_FW_DBGLOG_INFO, ++ ATH11K_FW_DBGLOG_INFO_LVL_1, ++ ATH11K_FW_DBGLOG_INFO_LVL_2, ++ ATH11K_FW_DBGLOG_WARN, ++ ATH11K_FW_DBGLOG_ERR, ++ ATH11K_FW_DBGLOG_LVL_MAX ++}; ++ ++struct ath11k_fw_dbglog { ++ enum wmi_debug_log_param param; ++ union { ++ struct { ++ /* log_level values are given in enum fw_dbglog_log_level */ ++ u16 log_level; ++ /* module_id values are given in enum fw_dbglog_wlan_module_id */ ++ u16 module_id; ++ }; ++ /* value is either log_level&module_id/vdev_id/vdev_id_bitmap/log_level ++ * according to param ++ */ ++ u32 value; ++ }; ++}; ++ + #ifdef CPTCFG_ATH11K_DEBUGFS + int ath11k_debugfs_soc_create(struct ath11k_base *ab); + void ath11k_debugfs_soc_destroy(struct ath11k_base *ab); +--- a/drivers/net/wireless/ath/ath11k/wmi.c ++++ b/drivers/net/wireless/ath/ath11k/wmi.c +@@ -7798,6 +7798,59 @@ int ath11k_wmi_simulate_radar(struct ath + return ath11k_wmi_send_unit_test_cmd(ar, wmi_ut, dfs_args); + } + ++int ath11k_wmi_fw_dbglog_cfg(struct ath11k *ar, u32 *module_id_bitmap, ++ struct ath11k_fw_dbglog *dbglog) ++{ ++ struct ath11k_pdev_wmi *wmi = ar->wmi; ++ struct wmi_debug_log_config_cmd_fixed_param *cmd; ++ struct sk_buff *skb; ++ struct wmi_tlv *tlv; ++ int ret, len; ++ ++ len = sizeof(*cmd) + TLV_HDR_SIZE + (MAX_MODULE_ID_BITMAP_WORDS * sizeof(u32)); ++ skb = ath11k_wmi_alloc_skb(wmi->wmi_ab, len); ++ if (!skb) ++ return -ENOMEM; ++ ++ cmd = (struct wmi_debug_log_config_cmd_fixed_param *)skb->data; ++ cmd->tlv_header = FIELD_PREP(WMI_TLV_TAG, WMI_TAG_DEBUG_LOG_CONFIG_CMD) | ++ FIELD_PREP(WMI_TLV_LEN, sizeof(*cmd) - TLV_HDR_SIZE); ++ cmd->dbg_log_param = dbglog->param; ++ ++ tlv = (struct wmi_tlv *)((u8 *)cmd + sizeof(*cmd)); ++ tlv->header = FIELD_PREP(WMI_TLV_TAG, WMI_TAG_ARRAY_UINT32) | ++ FIELD_PREP(WMI_TLV_LEN, MAX_MODULE_ID_BITMAP_WORDS * sizeof(u32)); ++ ++ switch (dbglog->param) { ++ case WMI_DEBUG_LOG_PARAM_LOG_LEVEL: ++ case WMI_DEBUG_LOG_PARAM_VDEV_ENABLE: ++ case WMI_DEBUG_LOG_PARAM_VDEV_DISABLE: ++ case WMI_DEBUG_LOG_PARAM_VDEV_ENABLE_BITMAP: ++ cmd->value = dbglog->value; ++ break; ++ case WMI_DEBUG_LOG_PARAM_MOD_ENABLE_BITMAP: ++ case WMI_DEBUG_LOG_PARAM_WOW_MOD_ENABLE_BITMAP: ++ cmd->value = dbglog->value; ++ memcpy(tlv->value, module_id_bitmap, ++ MAX_MODULE_ID_BITMAP_WORDS * sizeof(u32)); ++ /* clear current config to be used for next user config */ ++ memset(module_id_bitmap, 0, ++ MAX_MODULE_ID_BITMAP_WORDS * sizeof(u32)); ++ break; ++ default: ++ dev_kfree_skb(skb); ++ return -EINVAL; ++ } ++ ++ ret = ath11k_wmi_cmd_send(wmi, skb, WMI_DBGLOG_CFG_CMDID); ++ if (ret) { ++ ath11k_warn(ar->ab, ++ "failed to send WMI_DBGLOG_CFG_CMDID\n"); ++ dev_kfree_skb(skb); ++ } ++ return ret; ++} ++ + int ath11k_wmi_connect(struct ath11k_base *ab) + { + u32 i; +--- a/drivers/net/wireless/ath/ath11k/wmi.h ++++ b/drivers/net/wireless/ath/ath11k/wmi.h +@@ -12,6 +12,7 @@ + struct ath11k_base; + struct ath11k; + struct ath11k_fw_stats; ++struct ath11k_fw_dbglog; + + #define PSOC_HOST_MAX_NUM_SS (8) + +@@ -5240,6 +5241,21 @@ struct wmi_rfkill_state_change_ev { + u32 radio_state; + } __packed; + ++enum wmi_debug_log_param { ++ WMI_DEBUG_LOG_PARAM_LOG_LEVEL = 0x1, ++ WMI_DEBUG_LOG_PARAM_VDEV_ENABLE, ++ WMI_DEBUG_LOG_PARAM_VDEV_DISABLE, ++ WMI_DEBUG_LOG_PARAM_VDEV_ENABLE_BITMAP, ++ WMI_DEBUG_LOG_PARAM_MOD_ENABLE_BITMAP, ++ WMI_DEBUG_LOG_PARAM_WOW_MOD_ENABLE_BITMAP, ++}; ++ ++struct wmi_debug_log_config_cmd_fixed_param { ++ u32 tlv_header; ++ u32 dbg_log_param; ++ u32 value; ++} __packed; ++ + #define WMI_MAX_MEM_REQS 32 + + #define MAX_RADIOS 3 +@@ -5582,4 +5598,6 @@ int ath11k_wmi_wow_host_wakeup_ind(struc + int ath11k_wmi_wow_enable(struct ath11k *ar); + int ath11k_wmi_scan_prob_req_oui(struct ath11k *ar, + const u8 mac_addr[ETH_ALEN]); ++int ath11k_wmi_fw_dbglog_cfg(struct ath11k *ar, u32 *module_id_bitmap, ++ struct ath11k_fw_dbglog *dbglog); + #endif diff --git a/package/kernel/mac80211/patches/ath11k/0170-ath11k-add-WMI-calls-to-manually-add-del-pause-resum.patch b/package/kernel/mac80211/patches/ath11k/0170-ath11k-add-WMI-calls-to-manually-add-del-pause-resum.patch new file mode 100644 index 000000000..c49b2975e --- /dev/null +++ b/package/kernel/mac80211/patches/ath11k/0170-ath11k-add-WMI-calls-to-manually-add-del-pause-resum.patch @@ -0,0 +1,455 @@ +From 3d00e8b5b818266f43d1fabdb961e215cab45dfb Mon Sep 17 00:00:00 2001 +From: John Crispin +Date: Mon, 31 Jan 2022 16:16:44 +0200 +Subject: [PATCH 170/171] ath11k: add WMI calls to manually + add/del/pause/resume TWT dialogs + +These calls are used for debugging and will be required for WFA +certification tests. + +Tested-on: IPQ8074 hw2.0 AHB WLAN.HK.2.5.0.1-01179-QCAHKSWPL_SILICONZ-1 +Signed-off-by: John Crispin +Signed-off-by: Aloka Dixit +Signed-off-by: Kalle Valo +Link: https://lore.kernel.org/r/20220131031043.1295-1-alokad@codeaurora.org +--- + drivers/net/wireless/ath/ath11k/core.h | 1 + + drivers/net/wireless/ath/ath11k/wmi.c | 247 ++++++++++++++++++++++++- + drivers/net/wireless/ath/ath11k/wmi.h | 114 ++++++++++++ + 3 files changed, 358 insertions(+), 4 deletions(-) + +--- a/drivers/net/wireless/ath/ath11k/core.h ++++ b/drivers/net/wireless/ath/ath11k/core.h +@@ -608,6 +608,7 @@ struct ath11k { + bool pending_11d; + bool regdom_set_by_user; + int hw_rate_code; ++ u8 twt_enabled; + }; + + struct ath11k_band_cap { +--- a/drivers/net/wireless/ath/ath11k/wmi.c ++++ b/drivers/net/wireless/ath/ath11k/wmi.c +@@ -144,6 +144,8 @@ static const struct wmi_tlv_policy wmi_t + .min_len = sizeof(struct wmi_11d_new_cc_ev) }, + [WMI_TAG_PER_CHAIN_RSSI_STATS] = { + .min_len = sizeof(struct wmi_per_chain_rssi_stats) }, ++ [WMI_TAG_TWT_ADD_DIALOG_COMPLETE_EVENT] = { ++ .min_len = sizeof(struct wmi_twt_add_dialog_event) }, + }; + + #define PRIMAP(_hw_mode_) \ +@@ -3085,11 +3087,12 @@ ath11k_wmi_send_twt_enable_cmd(struct at + /* TODO add MBSSID support */ + cmd->mbss_support = 0; + +- ret = ath11k_wmi_cmd_send(wmi, skb, +- WMI_TWT_ENABLE_CMDID); ++ ret = ath11k_wmi_cmd_send(wmi, skb, WMI_TWT_ENABLE_CMDID); + if (ret) { + ath11k_warn(ab, "Failed to send WMI_TWT_ENABLE_CMDID"); + dev_kfree_skb(skb); ++ } else { ++ ar->twt_enabled = 1; + } + return ret; + } +@@ -3114,11 +3117,181 @@ ath11k_wmi_send_twt_disable_cmd(struct a + FIELD_PREP(WMI_TLV_LEN, len - TLV_HDR_SIZE); + cmd->pdev_id = pdev_id; + +- ret = ath11k_wmi_cmd_send(wmi, skb, +- WMI_TWT_DISABLE_CMDID); ++ ret = ath11k_wmi_cmd_send(wmi, skb, WMI_TWT_DISABLE_CMDID); + if (ret) { + ath11k_warn(ab, "Failed to send WMI_TWT_DISABLE_CMDID"); + dev_kfree_skb(skb); ++ } else { ++ ar->twt_enabled = 0; ++ } ++ return ret; ++} ++ ++int ath11k_wmi_send_twt_add_dialog_cmd(struct ath11k *ar, ++ struct wmi_twt_add_dialog_params *params) ++{ ++ struct ath11k_pdev_wmi *wmi = ar->wmi; ++ struct ath11k_base *ab = wmi->wmi_ab->ab; ++ struct wmi_twt_add_dialog_params_cmd *cmd; ++ struct sk_buff *skb; ++ int ret, len; ++ ++ len = sizeof(*cmd); ++ ++ skb = ath11k_wmi_alloc_skb(wmi->wmi_ab, len); ++ if (!skb) ++ return -ENOMEM; ++ ++ cmd = (struct wmi_twt_add_dialog_params_cmd *)skb->data; ++ cmd->tlv_header = FIELD_PREP(WMI_TLV_TAG, WMI_TAG_TWT_ADD_DIALOG_CMD) | ++ FIELD_PREP(WMI_TLV_LEN, len - TLV_HDR_SIZE); ++ ++ cmd->vdev_id = params->vdev_id; ++ ether_addr_copy(cmd->peer_macaddr.addr, params->peer_macaddr); ++ cmd->dialog_id = params->dialog_id; ++ cmd->wake_intvl_us = params->wake_intvl_us; ++ cmd->wake_intvl_mantis = params->wake_intvl_mantis; ++ cmd->wake_dura_us = params->wake_dura_us; ++ cmd->sp_offset_us = params->sp_offset_us; ++ cmd->flags = params->twt_cmd; ++ if (params->flag_bcast) ++ cmd->flags |= WMI_TWT_ADD_DIALOG_FLAG_BCAST; ++ if (params->flag_trigger) ++ cmd->flags |= WMI_TWT_ADD_DIALOG_FLAG_TRIGGER; ++ if (params->flag_flow_type) ++ cmd->flags |= WMI_TWT_ADD_DIALOG_FLAG_FLOW_TYPE; ++ if (params->flag_protection) ++ cmd->flags |= WMI_TWT_ADD_DIALOG_FLAG_PROTECTION; ++ ++ ath11k_dbg(ar->ab, ATH11K_DBG_WMI, ++ "wmi add twt dialog vdev %u dialog id %u wake interval %u mantissa %u wake duration %u service period offset %u flags 0x%x\n", ++ cmd->vdev_id, cmd->dialog_id, cmd->wake_intvl_us, ++ cmd->wake_intvl_mantis, cmd->wake_dura_us, cmd->sp_offset_us, ++ cmd->flags); ++ ++ ret = ath11k_wmi_cmd_send(wmi, skb, WMI_TWT_ADD_DIALOG_CMDID); ++ ++ if (ret) { ++ ath11k_warn(ab, ++ "failed to send wmi command to add twt dialog: %d", ++ ret); ++ dev_kfree_skb(skb); ++ } ++ return ret; ++} ++ ++int ath11k_wmi_send_twt_del_dialog_cmd(struct ath11k *ar, ++ struct wmi_twt_del_dialog_params *params) ++{ ++ struct ath11k_pdev_wmi *wmi = ar->wmi; ++ struct ath11k_base *ab = wmi->wmi_ab->ab; ++ struct wmi_twt_del_dialog_params_cmd *cmd; ++ struct sk_buff *skb; ++ int ret, len; ++ ++ len = sizeof(*cmd); ++ ++ skb = ath11k_wmi_alloc_skb(wmi->wmi_ab, len); ++ if (!skb) ++ return -ENOMEM; ++ ++ cmd = (struct wmi_twt_del_dialog_params_cmd *)skb->data; ++ cmd->tlv_header = FIELD_PREP(WMI_TLV_TAG, WMI_TAG_TWT_DEL_DIALOG_CMD) | ++ FIELD_PREP(WMI_TLV_LEN, len - TLV_HDR_SIZE); ++ ++ cmd->vdev_id = params->vdev_id; ++ ether_addr_copy(cmd->peer_macaddr.addr, params->peer_macaddr); ++ cmd->dialog_id = params->dialog_id; ++ ++ ath11k_dbg(ar->ab, ATH11K_DBG_WMI, ++ "wmi delete twt dialog vdev %u dialog id %u\n", ++ cmd->vdev_id, cmd->dialog_id); ++ ++ ret = ath11k_wmi_cmd_send(wmi, skb, WMI_TWT_DEL_DIALOG_CMDID); ++ if (ret) { ++ ath11k_warn(ab, ++ "failed to send wmi command to delete twt dialog: %d", ++ ret); ++ dev_kfree_skb(skb); ++ } ++ return ret; ++} ++ ++int ath11k_wmi_send_twt_pause_dialog_cmd(struct ath11k *ar, ++ struct wmi_twt_pause_dialog_params *params) ++{ ++ struct ath11k_pdev_wmi *wmi = ar->wmi; ++ struct ath11k_base *ab = wmi->wmi_ab->ab; ++ struct wmi_twt_pause_dialog_params_cmd *cmd; ++ struct sk_buff *skb; ++ int ret, len; ++ ++ len = sizeof(*cmd); ++ ++ skb = ath11k_wmi_alloc_skb(wmi->wmi_ab, len); ++ if (!skb) ++ return -ENOMEM; ++ ++ cmd = (struct wmi_twt_pause_dialog_params_cmd *)skb->data; ++ cmd->tlv_header = FIELD_PREP(WMI_TLV_TAG, ++ WMI_TAG_TWT_PAUSE_DIALOG_CMD) | ++ FIELD_PREP(WMI_TLV_LEN, len - TLV_HDR_SIZE); ++ ++ cmd->vdev_id = params->vdev_id; ++ ether_addr_copy(cmd->peer_macaddr.addr, params->peer_macaddr); ++ cmd->dialog_id = params->dialog_id; ++ ++ ath11k_dbg(ar->ab, ATH11K_DBG_WMI, ++ "wmi pause twt dialog vdev %u dialog id %u\n", ++ cmd->vdev_id, cmd->dialog_id); ++ ++ ret = ath11k_wmi_cmd_send(wmi, skb, WMI_TWT_PAUSE_DIALOG_CMDID); ++ if (ret) { ++ ath11k_warn(ab, ++ "failed to send wmi command to pause twt dialog: %d", ++ ret); ++ dev_kfree_skb(skb); ++ } ++ return ret; ++} ++ ++int ath11k_wmi_send_twt_resume_dialog_cmd(struct ath11k *ar, ++ struct wmi_twt_resume_dialog_params *params) ++{ ++ struct ath11k_pdev_wmi *wmi = ar->wmi; ++ struct ath11k_base *ab = wmi->wmi_ab->ab; ++ struct wmi_twt_resume_dialog_params_cmd *cmd; ++ struct sk_buff *skb; ++ int ret, len; ++ ++ len = sizeof(*cmd); ++ ++ skb = ath11k_wmi_alloc_skb(wmi->wmi_ab, len); ++ if (!skb) ++ return -ENOMEM; ++ ++ cmd = (struct wmi_twt_resume_dialog_params_cmd *)skb->data; ++ cmd->tlv_header = FIELD_PREP(WMI_TLV_TAG, ++ WMI_TAG_TWT_RESUME_DIALOG_CMD) | ++ FIELD_PREP(WMI_TLV_LEN, len - TLV_HDR_SIZE); ++ ++ cmd->vdev_id = params->vdev_id; ++ ether_addr_copy(cmd->peer_macaddr.addr, params->peer_macaddr); ++ cmd->dialog_id = params->dialog_id; ++ cmd->sp_offset_us = params->sp_offset_us; ++ cmd->next_twt_size = params->next_twt_size; ++ ++ ath11k_dbg(ar->ab, ATH11K_DBG_WMI, ++ "wmi resume twt dialog vdev %u dialog id %u service period offset %u next twt subfield size %u\n", ++ cmd->vdev_id, cmd->dialog_id, cmd->sp_offset_us, ++ cmd->next_twt_size); ++ ++ ret = ath11k_wmi_cmd_send(wmi, skb, WMI_TWT_RESUME_DIALOG_CMDID); ++ if (ret) { ++ ath11k_warn(ab, ++ "failed to send wmi command to resume twt dialog: %d", ++ ret); ++ dev_kfree_skb(skb); + } + return ret; + } +@@ -7532,6 +7705,66 @@ ath11k_wmi_diag_event(struct ath11k_base + trace_ath11k_wmi_diag(ab, skb->data, skb->len); + } + ++static const char *ath11k_wmi_twt_add_dialog_event_status(u32 status) ++{ ++ switch (status) { ++ case WMI_ADD_TWT_STATUS_OK: ++ return "ok"; ++ case WMI_ADD_TWT_STATUS_TWT_NOT_ENABLED: ++ return "twt disabled"; ++ case WMI_ADD_TWT_STATUS_USED_DIALOG_ID: ++ return "dialog id in use"; ++ case WMI_ADD_TWT_STATUS_INVALID_PARAM: ++ return "invalid parameters"; ++ case WMI_ADD_TWT_STATUS_NOT_READY: ++ return "not ready"; ++ case WMI_ADD_TWT_STATUS_NO_RESOURCE: ++ return "resource unavailable"; ++ case WMI_ADD_TWT_STATUS_NO_ACK: ++ return "no ack"; ++ case WMI_ADD_TWT_STATUS_NO_RESPONSE: ++ return "no response"; ++ case WMI_ADD_TWT_STATUS_DENIED: ++ return "denied"; ++ case WMI_ADD_TWT_STATUS_UNKNOWN_ERROR: ++ fallthrough; ++ default: ++ return "unknown error"; ++ } ++} ++ ++static void ath11k_wmi_twt_add_dialog_event(struct ath11k_base *ab, ++ struct sk_buff *skb) ++{ ++ const void **tb; ++ const struct wmi_twt_add_dialog_event *ev; ++ int ret; ++ ++ tb = ath11k_wmi_tlv_parse_alloc(ab, skb->data, skb->len, GFP_ATOMIC); ++ if (IS_ERR(tb)) { ++ ret = PTR_ERR(tb); ++ ath11k_warn(ab, ++ "failed to parse wmi twt add dialog status event tlv: %d\n", ++ ret); ++ return; ++ } ++ ++ ev = tb[WMI_TAG_TWT_ADD_DIALOG_COMPLETE_EVENT]; ++ if (!ev) { ++ ath11k_warn(ab, "failed to fetch twt add dialog wmi event\n"); ++ goto exit; ++ } ++ ++ if (ev->status) ++ ath11k_warn(ab, ++ "wmi add twt dialog event vdev %d dialog id %d status %s\n", ++ ev->vdev_id, ev->dialog_id, ++ ath11k_wmi_twt_add_dialog_event_status(ev->status)); ++ ++exit: ++ kfree(tb); ++} ++ + static void ath11k_wmi_tlv_op_rx(struct ath11k_base *ab, struct sk_buff *skb) + { + struct wmi_cmd_hdr *cmd_hdr; +@@ -7629,11 +7862,17 @@ static void ath11k_wmi_tlv_op_rx(struct + case WMI_OBSS_COLOR_COLLISION_DETECTION_EVENTID: + ath11k_wmi_obss_color_collision_event(ab, skb); + break; ++ case WMI_TWT_ADD_DIALOG_EVENTID: ++ ath11k_wmi_twt_add_dialog_event(ab, skb); ++ break; + /* add Unsupported events here */ + case WMI_TBTTOFFSET_EXT_UPDATE_EVENTID: + case WMI_PEER_OPER_MODE_CHANGE_EVENTID: + case WMI_TWT_ENABLE_EVENTID: + case WMI_TWT_DISABLE_EVENTID: ++ case WMI_TWT_DEL_DIALOG_EVENTID: ++ case WMI_TWT_PAUSE_DIALOG_EVENTID: ++ case WMI_TWT_RESUME_DIALOG_EVENTID: + case WMI_PDEV_DMA_RING_CFG_RSP_EVENTID: + case WMI_PEER_CREATE_CONF_EVENTID: + ath11k_dbg(ab, ATH11K_DBG_WMI, +--- a/drivers/net/wireless/ath/ath11k/wmi.h ++++ b/drivers/net/wireless/ath/ath11k/wmi.h +@@ -4953,6 +4953,112 @@ struct wmi_twt_disable_params_cmd { + u32 pdev_id; + } __packed; + ++enum WMI_HOST_TWT_COMMAND { ++ WMI_HOST_TWT_COMMAND_REQUEST_TWT = 0, ++ WMI_HOST_TWT_COMMAND_SUGGEST_TWT, ++ WMI_HOST_TWT_COMMAND_DEMAND_TWT, ++ WMI_HOST_TWT_COMMAND_TWT_GROUPING, ++ WMI_HOST_TWT_COMMAND_ACCEPT_TWT, ++ WMI_HOST_TWT_COMMAND_ALTERNATE_TWT, ++ WMI_HOST_TWT_COMMAND_DICTATE_TWT, ++ WMI_HOST_TWT_COMMAND_REJECT_TWT, ++}; ++ ++#define WMI_TWT_ADD_DIALOG_FLAG_BCAST BIT(8) ++#define WMI_TWT_ADD_DIALOG_FLAG_TRIGGER BIT(9) ++#define WMI_TWT_ADD_DIALOG_FLAG_FLOW_TYPE BIT(10) ++#define WMI_TWT_ADD_DIALOG_FLAG_PROTECTION BIT(11) ++ ++struct wmi_twt_add_dialog_params_cmd { ++ u32 tlv_header; ++ u32 vdev_id; ++ struct wmi_mac_addr peer_macaddr; ++ u32 dialog_id; ++ u32 wake_intvl_us; ++ u32 wake_intvl_mantis; ++ u32 wake_dura_us; ++ u32 sp_offset_us; ++ u32 flags; ++} __packed; ++ ++struct wmi_twt_add_dialog_params { ++ u32 vdev_id; ++ u8 peer_macaddr[ETH_ALEN]; ++ u32 dialog_id; ++ u32 wake_intvl_us; ++ u32 wake_intvl_mantis; ++ u32 wake_dura_us; ++ u32 sp_offset_us; ++ u8 twt_cmd; ++ u8 flag_bcast; ++ u8 flag_trigger; ++ u8 flag_flow_type; ++ u8 flag_protection; ++} __packed; ++ ++enum wmi_twt_add_dialog_status { ++ WMI_ADD_TWT_STATUS_OK, ++ WMI_ADD_TWT_STATUS_TWT_NOT_ENABLED, ++ WMI_ADD_TWT_STATUS_USED_DIALOG_ID, ++ WMI_ADD_TWT_STATUS_INVALID_PARAM, ++ WMI_ADD_TWT_STATUS_NOT_READY, ++ WMI_ADD_TWT_STATUS_NO_RESOURCE, ++ WMI_ADD_TWT_STATUS_NO_ACK, ++ WMI_ADD_TWT_STATUS_NO_RESPONSE, ++ WMI_ADD_TWT_STATUS_DENIED, ++ WMI_ADD_TWT_STATUS_UNKNOWN_ERROR, ++}; ++ ++struct wmi_twt_add_dialog_event { ++ u32 vdev_id; ++ struct wmi_mac_addr peer_macaddr; ++ u32 dialog_id; ++ u32 status; ++} __packed; ++ ++struct wmi_twt_del_dialog_params { ++ u32 vdev_id; ++ u8 peer_macaddr[ETH_ALEN]; ++ u32 dialog_id; ++} __packed; ++ ++struct wmi_twt_del_dialog_params_cmd { ++ u32 tlv_header; ++ u32 vdev_id; ++ struct wmi_mac_addr peer_macaddr; ++ u32 dialog_id; ++} __packed; ++ ++struct wmi_twt_pause_dialog_params { ++ u32 vdev_id; ++ u8 peer_macaddr[ETH_ALEN]; ++ u32 dialog_id; ++} __packed; ++ ++struct wmi_twt_pause_dialog_params_cmd { ++ u32 tlv_header; ++ u32 vdev_id; ++ struct wmi_mac_addr peer_macaddr; ++ u32 dialog_id; ++} __packed; ++ ++struct wmi_twt_resume_dialog_params { ++ u32 vdev_id; ++ u8 peer_macaddr[ETH_ALEN]; ++ u32 dialog_id; ++ u32 sp_offset_us; ++ u32 next_twt_size; ++} __packed; ++ ++struct wmi_twt_resume_dialog_params_cmd { ++ u32 tlv_header; ++ u32 vdev_id; ++ struct wmi_mac_addr peer_macaddr; ++ u32 dialog_id; ++ u32 sp_offset_us; ++ u32 next_twt_size; ++} __packed; ++ + struct wmi_obss_spatial_reuse_params_cmd { + u32 tlv_header; + u32 pdev_id; +@@ -5562,6 +5668,14 @@ void ath11k_wmi_fw_stats_fill(struct ath + int ath11k_wmi_simulate_radar(struct ath11k *ar); + int ath11k_wmi_send_twt_enable_cmd(struct ath11k *ar, u32 pdev_id); + int ath11k_wmi_send_twt_disable_cmd(struct ath11k *ar, u32 pdev_id); ++int ath11k_wmi_send_twt_add_dialog_cmd(struct ath11k *ar, ++ struct wmi_twt_add_dialog_params *params); ++int ath11k_wmi_send_twt_del_dialog_cmd(struct ath11k *ar, ++ struct wmi_twt_del_dialog_params *params); ++int ath11k_wmi_send_twt_pause_dialog_cmd(struct ath11k *ar, ++ struct wmi_twt_pause_dialog_params *params); ++int ath11k_wmi_send_twt_resume_dialog_cmd(struct ath11k *ar, ++ struct wmi_twt_resume_dialog_params *params); + int ath11k_wmi_send_obss_spr_cmd(struct ath11k *ar, u32 vdev_id, + struct ieee80211_he_obss_pd *he_obss_pd); + int ath11k_wmi_pdev_set_srg_bss_color_bitmap(struct ath11k *ar, u32 *bitmap); diff --git a/package/kernel/mac80211/patches/ath11k/0171-ath11k-add-debugfs-for-TWT-debug-calls.patch b/package/kernel/mac80211/patches/ath11k/0171-ath11k-add-debugfs-for-TWT-debug-calls.patch new file mode 100644 index 000000000..df5312448 --- /dev/null +++ b/package/kernel/mac80211/patches/ath11k/0171-ath11k-add-debugfs-for-TWT-debug-calls.patch @@ -0,0 +1,347 @@ +From fe98a6137d03a9e51db2197674c355d64eb3b709 Mon Sep 17 00:00:00 2001 +From: John Crispin +Date: Mon, 31 Jan 2022 16:16:44 +0200 +Subject: [PATCH 171/171] ath11k: add debugfs for TWT debug calls + +New debugfs files to manually add/delete/pause/resume TWT +dialogs for test/debug purposes. + +The debugfs files expect the following parameters +- Add dialog +echo ' + + <1:Broadcast /0:Individual> <1:Triggered / 0:Untriggered> + <1:Unannounced /0:Announced> <1:Protected / 0:Unprotected>' > + /sys/kernel/debug/ieee80211/phyX/netdev:wlanX/twt/add_dialog + +Example (Non-triggered and un-announced): +echo '00:03:7F:20:13:52 1 102400 100 30720 20480 4 0 0 1 0' > + /sys/kernel/debug/ieee80211/phy0/netdev:wlan0/twt/add_dialog + +- Delete dialog +echo ' ' > + /sys/kernel/debug/ieee80211/phyX/netdev:wlanX/twt/del_dialog + +- Pause dialog +echo ' ' > + /sys/kernel/debug/ieee80211/phyX/netdev:wlanX/twt/pause_dialog + +- Resume dialog +echo ' ' > + /sys/kernel/debug/ieee80211/phyX/netdev:wlanX/twt/resume_dialog + +Example: +echo '00:03:7F:20:13:52 1 2000000 3' > + /sys/kernel/debug/ieee80211/phy0/netdev:wlan0/twt/resume_dialog + +Tested-on: IPQ8074 hw2.0 AHB WLAN.HK.2.5.0.1-01179-QCAHKSWPL_SILICONZ-1 +Signed-off-by: John Crispin +Signed-off-by: Aloka Dixit +Signed-off-by: Kalle Valo +Link: https://lore.kernel.org/r/20220131031043.1295-2-alokad@codeaurora.org +--- + drivers/net/wireless/ath/ath11k/core.h | 3 + + drivers/net/wireless/ath/ath11k/debugfs.c | 222 ++++++++++++++++++++++ + drivers/net/wireless/ath/ath11k/debugfs.h | 14 +- + drivers/net/wireless/ath/ath11k/mac.c | 7 + + 4 files changed, 245 insertions(+), 1 deletion(-) + +--- a/drivers/net/wireless/ath/ath11k/core.h ++++ b/drivers/net/wireless/ath/ath11k/core.h +@@ -263,6 +263,9 @@ struct ath11k_vif { + bool bcca_zero_sent; + bool do_not_send_tmpl; + struct ieee80211_chanctx_conf chanctx; ++#ifdef CPTCFG_ATH11K_DEBUGFS ++ struct dentry *debugfs_twt; ++#endif /* CPTCFG_ATH11K_DEBUGFS */ + }; + + struct ath11k_vif_iter { +--- a/drivers/net/wireless/ath/ath11k/debugfs.c ++++ b/drivers/net/wireless/ath/ath11k/debugfs.c +@@ -1222,3 +1222,225 @@ int ath11k_debugfs_register(struct ath11 + void ath11k_debugfs_unregister(struct ath11k *ar) + { + } ++ ++static ssize_t ath11k_write_twt_add_dialog(struct file *file, ++ const char __user *ubuf, ++ size_t count, loff_t *ppos) ++{ ++ struct ath11k_vif *arvif = file->private_data; ++ struct wmi_twt_add_dialog_params params = { 0 }; ++ u8 buf[128] = {0}; ++ int ret; ++ ++ if (arvif->ar->twt_enabled == 0) { ++ ath11k_err(arvif->ar->ab, "twt support is not enabled\n"); ++ return -EOPNOTSUPP; ++ } ++ ++ ret = simple_write_to_buffer(buf, sizeof(buf) - 1, ppos, ubuf, count); ++ if (ret < 0) ++ return ret; ++ ++ buf[ret] = '\0'; ++ ret = sscanf(buf, ++ "%02hhx:%02hhx:%02hhx:%02hhx:%02hhx:%02hhx %u %u %u %u %u %hhu %hhu %hhu %hhu %hhu", ++ ¶ms.peer_macaddr[0], ++ ¶ms.peer_macaddr[1], ++ ¶ms.peer_macaddr[2], ++ ¶ms.peer_macaddr[3], ++ ¶ms.peer_macaddr[4], ++ ¶ms.peer_macaddr[5], ++ ¶ms.dialog_id, ++ ¶ms.wake_intvl_us, ++ ¶ms.wake_intvl_mantis, ++ ¶ms.wake_dura_us, ++ ¶ms.sp_offset_us, ++ ¶ms.twt_cmd, ++ ¶ms.flag_bcast, ++ ¶ms.flag_trigger, ++ ¶ms.flag_flow_type, ++ ¶ms.flag_protection); ++ if (ret != 16) ++ return -EINVAL; ++ ++ params.vdev_id = arvif->vdev_id; ++ ++ ret = ath11k_wmi_send_twt_add_dialog_cmd(arvif->ar, ¶ms); ++ if (ret) ++ return ret; ++ ++ return count; ++} ++ ++static ssize_t ath11k_write_twt_del_dialog(struct file *file, ++ const char __user *ubuf, ++ size_t count, loff_t *ppos) ++{ ++ struct ath11k_vif *arvif = file->private_data; ++ struct wmi_twt_del_dialog_params params = { 0 }; ++ u8 buf[64] = {0}; ++ int ret; ++ ++ if (arvif->ar->twt_enabled == 0) { ++ ath11k_err(arvif->ar->ab, "twt support is not enabled\n"); ++ return -EOPNOTSUPP; ++ } ++ ++ ret = simple_write_to_buffer(buf, sizeof(buf) - 1, ppos, ubuf, count); ++ if (ret < 0) ++ return ret; ++ ++ buf[ret] = '\0'; ++ ret = sscanf(buf, "%02hhx:%02hhx:%02hhx:%02hhx:%02hhx:%02hhx %u", ++ ¶ms.peer_macaddr[0], ++ ¶ms.peer_macaddr[1], ++ ¶ms.peer_macaddr[2], ++ ¶ms.peer_macaddr[3], ++ ¶ms.peer_macaddr[4], ++ ¶ms.peer_macaddr[5], ++ ¶ms.dialog_id); ++ if (ret != 7) ++ return -EINVAL; ++ ++ params.vdev_id = arvif->vdev_id; ++ ++ ret = ath11k_wmi_send_twt_del_dialog_cmd(arvif->ar, ¶ms); ++ if (ret) ++ return ret; ++ ++ return count; ++} ++ ++static ssize_t ath11k_write_twt_pause_dialog(struct file *file, ++ const char __user *ubuf, ++ size_t count, loff_t *ppos) ++{ ++ struct ath11k_vif *arvif = file->private_data; ++ struct wmi_twt_pause_dialog_params params = { 0 }; ++ u8 buf[64] = {0}; ++ int ret; ++ ++ if (arvif->ar->twt_enabled == 0) { ++ ath11k_err(arvif->ar->ab, "twt support is not enabled\n"); ++ return -EOPNOTSUPP; ++ } ++ ++ ret = simple_write_to_buffer(buf, sizeof(buf) - 1, ppos, ubuf, count); ++ if (ret < 0) ++ return ret; ++ ++ buf[ret] = '\0'; ++ ret = sscanf(buf, "%02hhx:%02hhx:%02hhx:%02hhx:%02hhx:%02hhx %u", ++ ¶ms.peer_macaddr[0], ++ ¶ms.peer_macaddr[1], ++ ¶ms.peer_macaddr[2], ++ ¶ms.peer_macaddr[3], ++ ¶ms.peer_macaddr[4], ++ ¶ms.peer_macaddr[5], ++ ¶ms.dialog_id); ++ if (ret != 7) ++ return -EINVAL; ++ ++ params.vdev_id = arvif->vdev_id; ++ ++ ret = ath11k_wmi_send_twt_pause_dialog_cmd(arvif->ar, ¶ms); ++ if (ret) ++ return ret; ++ ++ return count; ++} ++ ++static ssize_t ath11k_write_twt_resume_dialog(struct file *file, ++ const char __user *ubuf, ++ size_t count, loff_t *ppos) ++{ ++ struct ath11k_vif *arvif = file->private_data; ++ struct wmi_twt_resume_dialog_params params = { 0 }; ++ u8 buf[64] = {0}; ++ int ret; ++ ++ if (arvif->ar->twt_enabled == 0) { ++ ath11k_err(arvif->ar->ab, "twt support is not enabled\n"); ++ return -EOPNOTSUPP; ++ } ++ ++ ret = simple_write_to_buffer(buf, sizeof(buf) - 1, ppos, ubuf, count); ++ if (ret < 0) ++ return ret; ++ ++ buf[ret] = '\0'; ++ ret = sscanf(buf, "%02hhx:%02hhx:%02hhx:%02hhx:%02hhx:%02hhx %u %u %u", ++ ¶ms.peer_macaddr[0], ++ ¶ms.peer_macaddr[1], ++ ¶ms.peer_macaddr[2], ++ ¶ms.peer_macaddr[3], ++ ¶ms.peer_macaddr[4], ++ ¶ms.peer_macaddr[5], ++ ¶ms.dialog_id, ++ ¶ms.sp_offset_us, ++ ¶ms.next_twt_size); ++ if (ret != 9) ++ return -EINVAL; ++ ++ params.vdev_id = arvif->vdev_id; ++ ++ ret = ath11k_wmi_send_twt_resume_dialog_cmd(arvif->ar, ¶ms); ++ if (ret) ++ return ret; ++ ++ return count; ++} ++ ++static const struct file_operations ath11k_fops_twt_add_dialog = { ++ .write = ath11k_write_twt_add_dialog, ++ .open = simple_open ++}; ++ ++static const struct file_operations ath11k_fops_twt_del_dialog = { ++ .write = ath11k_write_twt_del_dialog, ++ .open = simple_open ++}; ++ ++static const struct file_operations ath11k_fops_twt_pause_dialog = { ++ .write = ath11k_write_twt_pause_dialog, ++ .open = simple_open ++}; ++ ++static const struct file_operations ath11k_fops_twt_resume_dialog = { ++ .write = ath11k_write_twt_resume_dialog, ++ .open = simple_open ++}; ++ ++int ath11k_debugfs_add_interface(struct ath11k_vif *arvif) ++{ ++ if (arvif->vif->type == NL80211_IFTYPE_AP && !arvif->debugfs_twt) { ++ arvif->debugfs_twt = debugfs_create_dir("twt", ++ arvif->vif->debugfs_dir); ++ if (!arvif->debugfs_twt || IS_ERR(arvif->debugfs_twt)) { ++ ath11k_warn(arvif->ar->ab, ++ "failed to create directory %p\n", ++ arvif->debugfs_twt); ++ arvif->debugfs_twt = NULL; ++ return -1; ++ } ++ ++ debugfs_create_file("add_dialog", 0200, arvif->debugfs_twt, ++ arvif, &ath11k_fops_twt_add_dialog); ++ ++ debugfs_create_file("del_dialog", 0200, arvif->debugfs_twt, ++ arvif, &ath11k_fops_twt_del_dialog); ++ ++ debugfs_create_file("pause_dialog", 0200, arvif->debugfs_twt, ++ arvif, &ath11k_fops_twt_pause_dialog); ++ ++ debugfs_create_file("resume_dialog", 0200, arvif->debugfs_twt, ++ arvif, &ath11k_fops_twt_resume_dialog); ++ } ++ return 0; ++} ++ ++void ath11k_debugfs_remove_interface(struct ath11k_vif *arvif) ++{ ++ debugfs_remove_recursive(arvif->debugfs_twt); ++ arvif->debugfs_twt = NULL; ++} +--- a/drivers/net/wireless/ath/ath11k/debugfs.h ++++ b/drivers/net/wireless/ath/ath11k/debugfs.h +@@ -276,6 +276,9 @@ static inline int ath11k_debugfs_rx_filt + return ar->debug.rx_filter; + } + ++int ath11k_debugfs_add_interface(struct ath11k_vif *arvif); ++void ath11k_debugfs_remove_interface(struct ath11k_vif *arvif); ++ + #else + static inline int ath11k_debugfs_soc_create(struct ath11k_base *ab) + { +@@ -349,6 +352,15 @@ static inline int ath11k_debugfs_get_fw_ + return 0; + } + +-#endif /* CPTCFG_MAC80211_DEBUGFS*/ ++static inline int ath11k_debugfs_add_interface(struct ath11k_vif *arvif) ++{ ++ return 0; ++} ++ ++static inline void ath11k_debugfs_remove_interface(struct ath11k_vif *arvif) ++{ ++} ++ ++#endif /* CPTCFG_ATH11K_DEBUGFS*/ + + #endif /* _ATH11K_DEBUGFS_H_ */ +--- a/drivers/net/wireless/ath/ath11k/mac.c ++++ b/drivers/net/wireless/ath/ath11k/mac.c +@@ -6354,6 +6354,10 @@ static int ath11k_mac_op_add_interface(s + } + } + ++ ret = ath11k_debugfs_add_interface(arvif); ++ if (ret) ++ goto err_peer_del; ++ + mutex_unlock(&ar->conf_mutex); + + return 0; +@@ -6388,6 +6392,7 @@ err_vdev_del: + spin_unlock_bh(&ar->data_lock); + + err: ++ ath11k_debugfs_remove_interface(arvif); + mutex_unlock(&ar->conf_mutex); + + return ret; +@@ -6486,6 +6491,8 @@ err_vdev_del: + /* Recalc txpower for remaining vdev */ + ath11k_mac_txpower_recalc(ar); + ++ ath11k_debugfs_remove_interface(arvif); ++ + /* TODO: recal traffic pause state based on the available vdevs */ + + mutex_unlock(&ar->conf_mutex); diff --git a/package/kernel/mac80211/patches/ath11k/0172-ath11k-fix-uninitialized-rate_idx-in-ath11k_dp_tx_up.patch b/package/kernel/mac80211/patches/ath11k/0172-ath11k-fix-uninitialized-rate_idx-in-ath11k_dp_tx_up.patch new file mode 100644 index 000000000..c42c99243 --- /dev/null +++ b/package/kernel/mac80211/patches/ath11k/0172-ath11k-fix-uninitialized-rate_idx-in-ath11k_dp_tx_up.patch @@ -0,0 +1,36 @@ +From 8c4c567fa291e4805d5116f1333b2ed83877032b Mon Sep 17 00:00:00 2001 +From: Wen Gong +Date: Wed, 9 Feb 2022 01:08:16 -0500 +Subject: [PATCH] ath11k: fix uninitialized rate_idx in + ath11k_dp_tx_update_txcompl() + +The rate_idx which passed to ath11k_debugfs_sta_add_tx_stats() by +ath11k_dp_tx_update_txcompl() is not initialized, add initialization +for it. + +Tested-on: WCN6855 hw2.0 PCI WLAN.HSP.1.1-03003-QCAHSPSWPL_V1_V2_SILICONZ_LITE-2 + +Fixes: 1b8bb94c0612 ("ath11k: report tx bitrate for iw wlan station dump") +Signed-off-by: Wen Gong +Signed-off-by: Kalle Valo +Link: https://lore.kernel.org/r/20220209060816.423-1-quic_wgong@quicinc.com +--- + drivers/net/wireless/ath/ath11k/dp_tx.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/drivers/net/wireless/ath/ath11k/dp_tx.c b/drivers/net/wireless/ath/ath11k/dp_tx.c +index 91d6244b6543..8402961c6688 100644 +--- a/drivers/net/wireless/ath/ath11k/dp_tx.c ++++ b/drivers/net/wireless/ath/ath11k/dp_tx.c +@@ -426,7 +426,7 @@ void ath11k_dp_tx_update_txcompl(struct ath11k *ar, struct hal_tx_status *ts) + struct ath11k_sta *arsta; + struct ieee80211_sta *sta; + u16 rate, ru_tones; +- u8 mcs, rate_idx, ofdma; ++ u8 mcs, rate_idx = 0, ofdma; + int ret; + + spin_lock_bh(&ab->base_lock); +-- +2.35.1 + diff --git a/package/kernel/mac80211/patches/ath11k/0173-ath11k-fix-WARN_ON-during-ath11k_mac_update_vif_chan.patch b/package/kernel/mac80211/patches/ath11k/0173-ath11k-fix-WARN_ON-during-ath11k_mac_update_vif_chan.patch new file mode 100644 index 000000000..46269aed4 --- /dev/null +++ b/package/kernel/mac80211/patches/ath11k/0173-ath11k-fix-WARN_ON-during-ath11k_mac_update_vif_chan.patch @@ -0,0 +1,68 @@ +From 5ed98fb704d97894a2c7217989fd8290e4b7b985 Mon Sep 17 00:00:00 2001 +From: Venkateswara Naralasetty +Date: Wed, 9 Feb 2022 19:43:38 +0530 +Subject: [PATCH] ath11k: fix WARN_ON during ath11k_mac_update_vif_chan + +Fix WARN_ON() from ath11k_mac_update_vif_chan() if vdev is not up. +Since change_chanctx can be called even before vdev_up from +ieee80211_start_ap->ieee80211_vif_use_channel-> +ieee80211_recalc_radar_chanctx. + +Do vdev stop followed by a vdev start in case of vdev is down. + +Tested-on: QCN9074 hw1.0 PCI WLAN.HK.2.5.0.1-01100-QCAHKSWPL_SILICONZ-1 + +Signed-off-by: Venkateswara Naralasetty +Signed-off-by: Kalle Valo +Link: https://lore.kernel.org/r/1644416019-820-1-git-send-email-quic_vnaralas@quicinc.com +--- + drivers/net/wireless/ath/ath11k/mac.c | 32 ++++++++++++++++++++++----- + 1 file changed, 26 insertions(+), 6 deletions(-) + +diff --git a/drivers/net/wireless/ath/ath11k/mac.c b/drivers/net/wireless/ath/ath11k/mac.c +index ed899055944e..d5922a0a35f9 100644 +--- a/drivers/net/wireless/ath/ath11k/mac.c ++++ b/drivers/net/wireless/ath/ath11k/mac.c +@@ -6856,13 +6856,33 @@ ath11k_mac_update_vif_chan(struct ath11k *ar, + if (WARN_ON(!arvif->is_started)) + continue; + +- if (WARN_ON(!arvif->is_up)) +- continue; ++ /* change_chanctx can be called even before vdev_up from ++ * ieee80211_start_ap->ieee80211_vif_use_channel-> ++ * ieee80211_recalc_radar_chanctx. ++ * ++ * Firmware expect vdev_restart only if vdev is up. ++ * If vdev is down then it expect vdev_stop->vdev_start. ++ */ ++ if (arvif->is_up) { ++ ret = ath11k_mac_vdev_restart(arvif, &vifs[i].new_ctx->def); ++ if (ret) { ++ ath11k_warn(ab, "failed to restart vdev %d: %d\n", ++ arvif->vdev_id, ret); ++ continue; ++ } ++ } else { ++ ret = ath11k_mac_vdev_stop(arvif); ++ if (ret) { ++ ath11k_warn(ab, "failed to stop vdev %d: %d\n", ++ arvif->vdev_id, ret); ++ continue; ++ } ++ ++ ret = ath11k_mac_vdev_start(arvif, &vifs[i].new_ctx->def); ++ if (ret) ++ ath11k_warn(ab, "failed to start vdev %d: %d\n", ++ arvif->vdev_id, ret); + +- ret = ath11k_mac_vdev_restart(arvif, &vifs[i].new_ctx->def); +- if (ret) { +- ath11k_warn(ab, "failed to restart vdev %d: %d\n", +- arvif->vdev_id, ret); + continue; + } + +-- +2.35.1 + diff --git a/package/kernel/mac80211/patches/ath11k/0174-ath11k-fix-radar-detection-in-160-Mhz.patch b/package/kernel/mac80211/patches/ath11k/0174-ath11k-fix-radar-detection-in-160-Mhz.patch new file mode 100644 index 000000000..269bee5cf --- /dev/null +++ b/package/kernel/mac80211/patches/ath11k/0174-ath11k-fix-radar-detection-in-160-Mhz.patch @@ -0,0 +1,123 @@ +From 4f6dd92305f74c43f09e2ff867011e0029ee0e0d Mon Sep 17 00:00:00 2001 +From: Venkateswara Naralasetty +Date: Wed, 9 Feb 2022 19:43:39 +0530 +Subject: [PATCH] ath11k: fix radar detection in 160 Mhz + +Radar detection fails in the secondary 80 MHz when the +the AP's primary 80 MHz is in non-DFS region in 160 MHz. + +This is due to WMI channel flag WMI_CHAN_INFO_DFS_FREQ2 is not set +properly in case of the primary 80 MHz is in non-DFS region. +HALPHY detects the radar pulses in the secondary 80 MHz only when +WMI_CHAN_INFO_DFS_FREQ2 is set. + +Fix this issue by setting WMI channel flag WMI_CHAN_INFO_DFS_FREQ2 +based on the radar_enabled flag from the channel context. + +Tested-on: QCN9074 hw1.0 PCI WLAN.HK.2.5.0.1-01100-QCAHKSWPL_SILICONZ-1 + +Signed-off-by: Venkateswara Naralasetty +Signed-off-by: Kalle Valo +Link: https://lore.kernel.org/r/1644416019-820-2-git-send-email-quic_vnaralas@quicinc.com +--- + drivers/net/wireless/ath/ath11k/mac.c | 25 +++++++++++++------------ + 1 file changed, 13 insertions(+), 12 deletions(-) + +diff --git a/drivers/net/wireless/ath/ath11k/mac.c b/drivers/net/wireless/ath/ath11k/mac.c +index d5922a0a35f9..68754e9914b3 100644 +--- a/drivers/net/wireless/ath/ath11k/mac.c ++++ b/drivers/net/wireless/ath/ath11k/mac.c +@@ -6630,12 +6630,13 @@ static void ath11k_mac_op_remove_chanctx(struct ieee80211_hw *hw, + + static int + ath11k_mac_vdev_start_restart(struct ath11k_vif *arvif, +- const struct cfg80211_chan_def *chandef, ++ struct ieee80211_chanctx_conf *ctx, + bool restart) + { + struct ath11k *ar = arvif->ar; + struct ath11k_base *ab = ar->ab; + struct wmi_vdev_start_req_arg arg = {}; ++ const struct cfg80211_chan_def *chandef = &ctx->def; + int he_support = arvif->vif->bss_conf.he_support; + int ret = 0; + +@@ -6670,8 +6671,7 @@ ath11k_mac_vdev_start_restart(struct ath11k_vif *arvif, + arg.channel.chan_radar = + !!(chandef->chan->flags & IEEE80211_CHAN_RADAR); + +- arg.channel.freq2_radar = +- !!(chandef->chan->flags & IEEE80211_CHAN_RADAR); ++ arg.channel.freq2_radar = ctx->radar_enabled; + + arg.channel.passive = arg.channel.chan_radar; + +@@ -6781,15 +6781,15 @@ static int ath11k_mac_vdev_stop(struct ath11k_vif *arvif) + } + + static int ath11k_mac_vdev_start(struct ath11k_vif *arvif, +- const struct cfg80211_chan_def *chandef) ++ struct ieee80211_chanctx_conf *ctx) + { +- return ath11k_mac_vdev_start_restart(arvif, chandef, false); ++ return ath11k_mac_vdev_start_restart(arvif, ctx, false); + } + + static int ath11k_mac_vdev_restart(struct ath11k_vif *arvif, +- const struct cfg80211_chan_def *chandef) ++ struct ieee80211_chanctx_conf *ctx) + { +- return ath11k_mac_vdev_start_restart(arvif, chandef, true); ++ return ath11k_mac_vdev_start_restart(arvif, ctx, true); + } + + struct ath11k_mac_change_chanctx_arg { +@@ -6864,7 +6864,7 @@ ath11k_mac_update_vif_chan(struct ath11k *ar, + * If vdev is down then it expect vdev_stop->vdev_start. + */ + if (arvif->is_up) { +- ret = ath11k_mac_vdev_restart(arvif, &vifs[i].new_ctx->def); ++ ret = ath11k_mac_vdev_restart(arvif, vifs[i].new_ctx); + if (ret) { + ath11k_warn(ab, "failed to restart vdev %d: %d\n", + arvif->vdev_id, ret); +@@ -6878,7 +6878,7 @@ ath11k_mac_update_vif_chan(struct ath11k *ar, + continue; + } + +- ret = ath11k_mac_vdev_start(arvif, &vifs[i].new_ctx->def); ++ ret = ath11k_mac_vdev_start(arvif, vifs[i].new_ctx); + if (ret) + ath11k_warn(ab, "failed to start vdev %d: %d\n", + arvif->vdev_id, ret); +@@ -6967,7 +6967,8 @@ static void ath11k_mac_op_change_chanctx(struct ieee80211_hw *hw, + if (WARN_ON(changed & IEEE80211_CHANCTX_CHANGE_CHANNEL)) + goto unlock; + +- if (changed & IEEE80211_CHANCTX_CHANGE_WIDTH) ++ if (changed & IEEE80211_CHANCTX_CHANGE_WIDTH || ++ changed & IEEE80211_CHANCTX_CHANGE_RADAR) + ath11k_mac_update_active_vif_chan(ar, ctx); + + /* TODO: Recalc radar detection */ +@@ -6987,7 +6988,7 @@ static int ath11k_start_vdev_delay(struct ieee80211_hw *hw, + if (WARN_ON(arvif->is_started)) + return -EBUSY; + +- ret = ath11k_mac_vdev_start(arvif, &arvif->chanctx.def); ++ ret = ath11k_mac_vdev_start(arvif, &arvif->chanctx); + if (ret) { + ath11k_warn(ab, "failed to start vdev %i addr %pM on freq %d: %d\n", + arvif->vdev_id, vif->addr, +@@ -7081,7 +7082,7 @@ ath11k_mac_op_assign_vif_chanctx(struct ieee80211_hw *hw, + goto out; + } + +- ret = ath11k_mac_vdev_start(arvif, &ctx->def); ++ ret = ath11k_mac_vdev_start(arvif, ctx); + if (ret) { + ath11k_warn(ab, "failed to start vdev %i addr %pM on freq %d: %d\n", + arvif->vdev_id, vif->addr, +-- +2.35.1 + diff --git a/package/kernel/mac80211/patches/ath11k/0175-ath11k-fix-destination-monitor-ring-out-of-sync.patch b/package/kernel/mac80211/patches/ath11k/0175-ath11k-fix-destination-monitor-ring-out-of-sync.patch new file mode 100644 index 000000000..a24118943 --- /dev/null +++ b/package/kernel/mac80211/patches/ath11k/0175-ath11k-fix-destination-monitor-ring-out-of-sync.patch @@ -0,0 +1,118 @@ +From 1e15aacd12386d8f1372929a3fd52db9ef3344fc Mon Sep 17 00:00:00 2001 +From: Karthikeyan Kathirvel +Date: Thu, 10 Feb 2022 12:17:06 +0530 +Subject: [PATCH] ath11k: fix destination monitor ring out of sync + +More than 20000 PPDU id jumping causing status ring and destination +ring processing not sync. The status ring is processed and the +destination ring is not processed. Since destination is not reaped for +so long, backpressure occurs at the destination ring. + +To address this issue update the PPDU id with the latest PPDU, this +will allow the destination ring to be reaped and will prevent the +rings from getting out of sync. + +Tested-on: IPQ8074 hw2.0 AHB WLAN.HK.2.4.0.1.r1-00026-QCAHKSWPL_SILICONZ-2 +Signed-off-by: Karthikeyan Kathirvel +Signed-off-by: Kalle Valo +Link: https://lore.kernel.org/r/20220210064706.6171-1-quic_kathirve@quicinc.com +--- + drivers/net/wireless/ath/ath11k/dp.h | 3 ++ + drivers/net/wireless/ath/ath11k/dp_rx.c | 42 +++++++++++++++++++++---- + 2 files changed, 39 insertions(+), 6 deletions(-) + +diff --git a/drivers/net/wireless/ath/ath11k/dp.h b/drivers/net/wireless/ath/ath11k/dp.h +index 409d6cc5a1d5..b6ec2d6a2bb6 100644 +--- a/drivers/net/wireless/ath/ath11k/dp.h ++++ b/drivers/net/wireless/ath/ath11k/dp.h +@@ -115,6 +115,8 @@ struct ath11k_pdev_mon_stats { + u32 dest_mpdu_drop; + u32 dup_mon_linkdesc_cnt; + u32 dup_mon_buf_cnt; ++ u32 dest_mon_stuck; ++ u32 dest_mon_not_reaped; + }; + + struct dp_full_mon_mpdu { +@@ -167,6 +169,7 @@ struct ath11k_mon_data { + + struct ath11k_pdev_dp { + u32 mac_id; ++ u32 mon_dest_ring_stuck_cnt; + atomic_t num_tx_pending; + wait_queue_head_t tx_empty_waitq; + struct dp_rxdma_ring rx_refill_buf_ring; +diff --git a/drivers/net/wireless/ath/ath11k/dp_rx.c b/drivers/net/wireless/ath/ath11k/dp_rx.c +index 99dc9b5bbf4b..20c9e7904261 100644 +--- a/drivers/net/wireless/ath/ath11k/dp_rx.c ++++ b/drivers/net/wireless/ath/ath11k/dp_rx.c +@@ -4959,6 +4959,12 @@ static int ath11k_dp_rx_mon_deliver(struct ath11k *ar, u32 mac_id, + return -EINVAL; + } + ++/* The destination ring processing is stuck if the destination is not ++ * moving while status ring moves 16 PPDU. The destination ring processing ++ * skips this destination ring PPDU as a workaround. ++ */ ++#define MON_DEST_RING_STUCK_MAX_CNT 16 ++ + static void ath11k_dp_rx_mon_dest_process(struct ath11k *ar, int mac_id, + u32 quota, struct napi_struct *napi) + { +@@ -4972,6 +4978,7 @@ static void ath11k_dp_rx_mon_dest_process(struct ath11k *ar, int mac_id, + u32 ring_id; + struct ath11k_pdev_mon_stats *rx_mon_stats; + u32 npackets = 0; ++ u32 mpdu_rx_bufs_used; + + if (ar->ab->hw_params.rxdma1_enable) + ring_id = dp->rxdma_mon_dst_ring.ring_id; +@@ -5001,16 +5008,39 @@ static void ath11k_dp_rx_mon_dest_process(struct ath11k *ar, int mac_id, + head_msdu = NULL; + tail_msdu = NULL; + +- rx_bufs_used += ath11k_dp_rx_mon_mpdu_pop(ar, mac_id, ring_entry, +- &head_msdu, +- &tail_msdu, +- &npackets, &ppdu_id); ++ mpdu_rx_bufs_used = ath11k_dp_rx_mon_mpdu_pop(ar, mac_id, ring_entry, ++ &head_msdu, ++ &tail_msdu, ++ &npackets, &ppdu_id); ++ ++ rx_bufs_used += mpdu_rx_bufs_used; ++ ++ if (mpdu_rx_bufs_used) { ++ dp->mon_dest_ring_stuck_cnt = 0; ++ } else { ++ dp->mon_dest_ring_stuck_cnt++; ++ rx_mon_stats->dest_mon_not_reaped++; ++ } ++ ++ if (dp->mon_dest_ring_stuck_cnt > MON_DEST_RING_STUCK_MAX_CNT) { ++ rx_mon_stats->dest_mon_stuck++; ++ ath11k_dbg(ar->ab, ATH11K_DBG_DATA, ++ "status ring ppdu_id=%d dest ring ppdu_id=%d mon_dest_ring_stuck_cnt=%d dest_mon_not_reaped=%u dest_mon_stuck=%u\n", ++ pmon->mon_ppdu_info.ppdu_id, ppdu_id, ++ dp->mon_dest_ring_stuck_cnt, ++ rx_mon_stats->dest_mon_not_reaped, ++ rx_mon_stats->dest_mon_stuck); ++ pmon->mon_ppdu_info.ppdu_id = ppdu_id; ++ continue; ++ } + + if (ppdu_id != pmon->mon_ppdu_info.ppdu_id) { + pmon->mon_ppdu_status = DP_PPDU_STATUS_START; + ath11k_dbg(ar->ab, ATH11K_DBG_DATA, +- "dest_rx: new ppdu_id %x != status ppdu_id %x", +- ppdu_id, pmon->mon_ppdu_info.ppdu_id); ++ "dest_rx: new ppdu_id %x != status ppdu_id %x dest_mon_not_reaped = %u dest_mon_stuck = %u\n", ++ ppdu_id, pmon->mon_ppdu_info.ppdu_id, ++ rx_mon_stats->dest_mon_not_reaped, ++ rx_mon_stats->dest_mon_stuck); + break; + } + if (head_msdu && tail_msdu) { +-- +2.35.1 + diff --git a/package/kernel/mac80211/patches/ath11k/0176-ath11k-Fix-frames-flush-failure-caused-by-deadlock.patch b/package/kernel/mac80211/patches/ath11k/0176-ath11k-Fix-frames-flush-failure-caused-by-deadlock.patch new file mode 100644 index 000000000..85b01b2ad --- /dev/null +++ b/package/kernel/mac80211/patches/ath11k/0176-ath11k-Fix-frames-flush-failure-caused-by-deadlock.patch @@ -0,0 +1,131 @@ +From 261b07519518bd14cb168b287b17e1d195f8d0c8 Mon Sep 17 00:00:00 2001 +From: Baochen Qiang +Date: Thu, 17 Feb 2022 16:45:45 +0800 +Subject: [PATCH] ath11k: Fix frames flush failure caused by deadlock + +We are seeing below warnings: + +kernel: [25393.301506] ath11k_pci 0000:01:00.0: failed to flush mgmt transmit queue 0 +kernel: [25398.421509] ath11k_pci 0000:01:00.0: failed to flush mgmt transmit queue 0 +kernel: [25398.421831] ath11k_pci 0000:01:00.0: dropping mgmt frame for vdev 0, is_started 0 + +this means ath11k fails to flush mgmt. frames because wmi_mgmt_tx_work +has no chance to run in 5 seconds. + +By setting /proc/sys/kernel/hung_task_timeout_secs to 20 and increasing +ATH11K_FLUSH_TIMEOUT to 50 we get below warnings: + +kernel: [ 120.763160] INFO: task wpa_supplicant:924 blocked for more than 20 seconds. +kernel: [ 120.763169] Not tainted 5.10.90 #12 +kernel: [ 120.763177] "echo 0 > /proc/sys/kernel/hung_task_timeout_secs" disables this message. +kernel: [ 120.763186] task:wpa_supplicant state:D stack: 0 pid: 924 ppid: 1 flags:0x000043a0 +kernel: [ 120.763201] Call Trace: +kernel: [ 120.763214] __schedule+0x785/0x12fa +kernel: [ 120.763224] ? lockdep_hardirqs_on_prepare+0xe2/0x1bb +kernel: [ 120.763242] schedule+0x7e/0xa1 +kernel: [ 120.763253] schedule_timeout+0x98/0xfe +kernel: [ 120.763266] ? run_local_timers+0x4a/0x4a +kernel: [ 120.763291] ath11k_mac_flush_tx_complete+0x197/0x2b1 [ath11k 13c3a9bf37790f4ac8103b3decf7ab4008ac314a] +kernel: [ 120.763306] ? init_wait_entry+0x2e/0x2e +kernel: [ 120.763343] __ieee80211_flush_queues+0x167/0x21f [mac80211 335da900954f1c5ea7f1613d92088ce83342042c] +kernel: [ 120.763378] __ieee80211_recalc_idle+0x105/0x125 [mac80211 335da900954f1c5ea7f1613d92088ce83342042c] +kernel: [ 120.763411] ieee80211_recalc_idle+0x14/0x27 [mac80211 335da900954f1c5ea7f1613d92088ce83342042c] +kernel: [ 120.763441] ieee80211_free_chanctx+0x77/0xa2 [mac80211 335da900954f1c5ea7f1613d92088ce83342042c] +kernel: [ 120.763473] __ieee80211_vif_release_channel+0x100/0x131 [mac80211 335da900954f1c5ea7f1613d92088ce83342042c] +kernel: [ 120.763540] ieee80211_vif_release_channel+0x66/0x81 [mac80211 335da900954f1c5ea7f1613d92088ce83342042c] +kernel: [ 120.763572] ieee80211_destroy_auth_data+0xa3/0xe6 [mac80211 335da900954f1c5ea7f1613d92088ce83342042c] +kernel: [ 120.763612] ieee80211_mgd_deauth+0x178/0x29b [mac80211 335da900954f1c5ea7f1613d92088ce83342042c] +kernel: [ 120.763654] cfg80211_mlme_deauth+0x1a8/0x22c [cfg80211 8945aa5bc2af5f6972336665d8ad6f9c191ad5be] +kernel: [ 120.763697] nl80211_deauthenticate+0xfa/0x123 [cfg80211 8945aa5bc2af5f6972336665d8ad6f9c191ad5be] +kernel: [ 120.763715] genl_rcv_msg+0x392/0x3c2 +kernel: [ 120.763750] ? nl80211_associate+0x432/0x432 [cfg80211 8945aa5bc2af5f6972336665d8ad6f9c191ad5be] +kernel: [ 120.763782] ? nl80211_associate+0x432/0x432 [cfg80211 8945aa5bc2af5f6972336665d8ad6f9c191ad5be] +kernel: [ 120.763802] ? genl_rcv+0x36/0x36 +kernel: [ 120.763814] netlink_rcv_skb+0x89/0xf7 +kernel: [ 120.763829] genl_rcv+0x28/0x36 +kernel: [ 120.763840] netlink_unicast+0x179/0x24b +kernel: [ 120.763854] netlink_sendmsg+0x393/0x401 +kernel: [ 120.763872] sock_sendmsg+0x72/0x76 +kernel: [ 120.763886] ____sys_sendmsg+0x170/0x1e6 +kernel: [ 120.763897] ? copy_msghdr_from_user+0x7a/0xa2 +kernel: [ 120.763914] ___sys_sendmsg+0x95/0xd1 +kernel: [ 120.763940] __sys_sendmsg+0x85/0xbf +kernel: [ 120.763956] do_syscall_64+0x43/0x55 +kernel: [ 120.763966] entry_SYSCALL_64_after_hwframe+0x44/0xa9 +kernel: [ 120.763977] RIP: 0033:0x79089f3fcc83 +kernel: [ 120.763986] RSP: 002b:00007ffe604f0508 EFLAGS: 00000246 ORIG_RAX: 000000000000002e +kernel: [ 120.763997] RAX: ffffffffffffffda RBX: 000059b40e987690 RCX: 000079089f3fcc83 +kernel: [ 120.764006] RDX: 0000000000000000 RSI: 00007ffe604f0558 RDI: 0000000000000009 +kernel: [ 120.764014] RBP: 00007ffe604f0540 R08: 0000000000000004 R09: 0000000000400000 +kernel: [ 120.764023] R10: 00007ffe604f0638 R11: 0000000000000246 R12: 000059b40ea04980 +kernel: [ 120.764032] R13: 00007ffe604f0638 R14: 000059b40e98c360 R15: 00007ffe604f0558 +... +kernel: [ 120.765230] INFO: task kworker/u32:26:4239 blocked for more than 20 seconds. +kernel: [ 120.765238] Not tainted 5.10.90 #12 +kernel: [ 120.765245] "echo 0 > /proc/sys/kernel/hung_task_timeout_secs" disables this message. +kernel: [ 120.765253] task:kworker/u32:26 state:D stack: 0 pid: 4239 ppid: 2 flags:0x00004080 +kernel: [ 120.765284] Workqueue: phy0 ieee80211_iface_work [mac80211] +kernel: [ 120.765295] Call Trace: +kernel: [ 120.765306] __schedule+0x785/0x12fa +kernel: [ 120.765316] ? find_held_lock+0x3d/0xb2 +kernel: [ 120.765331] schedule+0x7e/0xa1 +kernel: [ 120.765340] schedule_preempt_disabled+0x15/0x1e +kernel: [ 120.765349] __mutex_lock_common+0x561/0xc0d +kernel: [ 120.765375] ? ieee80211_sta_work+0x3e/0x1232 [mac80211 335da900954f1c5ea7f1613d92088ce83342042c] +kernel: [ 120.765390] mutex_lock_nested+0x20/0x26 +kernel: [ 120.765416] ieee80211_sta_work+0x3e/0x1232 [mac80211 335da900954f1c5ea7f1613d92088ce83342042c] +kernel: [ 120.765430] ? skb_dequeue+0x54/0x5e +kernel: [ 120.765456] ? ieee80211_iface_work+0x7b/0x339 [mac80211 335da900954f1c5ea7f1613d92088ce83342042c] +kernel: [ 120.765485] process_one_work+0x270/0x504 +kernel: [ 120.765501] worker_thread+0x215/0x376 +kernel: [ 120.765514] kthread+0x159/0x168 +kernel: [ 120.765526] ? pr_cont_work+0x5b/0x5b +kernel: [ 120.765536] ? kthread_blkcg+0x31/0x31 +kernel: [ 120.765550] ret_from_fork+0x22/0x30 +... +kernel: [ 120.765867] Showing all locks held in the system: +... +kernel: [ 120.766164] 5 locks held by wpa_supplicant/924: +kernel: [ 120.766172] #0: ffffffffb1e63eb0 (cb_lock){++++}-{3:3}, at: genl_rcv+0x19/0x36 +kernel: [ 120.766197] #1: ffffffffb1e5b1c8 (rtnl_mutex){+.+.}-{3:3}, at: nl80211_pre_doit+0x2a/0x15c [cfg80211] +kernel: [ 120.766238] #2: ffff99f08347cd08 (&wdev->mtx){+.+.}-{3:3}, at: nl80211_deauthenticate+0xde/0x123 [cfg80211] +kernel: [ 120.766279] #3: ffff99f09df12a48 (&local->mtx){+.+.}-{3:3}, at: ieee80211_destroy_auth_data+0x9b/0xe6 [mac80211] +kernel: [ 120.766321] #4: ffff99f09df12ce0 (&local->chanctx_mtx){+.+.}-{3:3}, at: ieee80211_vif_release_channel+0x5e/0x81 [mac80211] +... +kernel: [ 120.766585] 3 locks held by kworker/u32:26/4239: +kernel: [ 120.766593] #0: ffff99f04458f948 ((wq_completion)phy0){+.+.}-{0:0}, at: process_one_work+0x19a/0x504 +kernel: [ 120.766621] #1: ffffbad54b3cfe50 ((work_completion)(&sdata->work)){+.+.}-{0:0}, at: process_one_work+0x1c0/0x504 +kernel: [ 120.766649] #2: ffff99f08347cd08 (&wdev->mtx){+.+.}-{3:3}, at: ieee80211_sta_work+0x3e/0x1232 [mac80211] + +With above info the issue is clear: First wmi_mgmt_tx_work is inserted +to local->workqueue after sdata->work inserted, then wpa_supplicant +acquires wdev->mtx in nl80211_deauthenticate and finally calls +ath11k_mac_op_flush where it waits all mgmt. frames to be sent out by +wmi_mgmt_tx_work. Meanwhile, sdata->work is blocked by wdev->mtx in +ieee80211_sta_work, as a result wmi_mgmt_tx_work has no chance to run. + +Change to use ab->workqueue instead of local->workqueue to fix this issue. + +Signed-off-by: Baochen Qiang +Signed-off-by: Kalle Valo +Link: https://lore.kernel.org/r/20220217084545.18844-1-quic_bqiang@quicinc.com +--- + drivers/net/wireless/ath/ath11k/mac.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/drivers/net/wireless/ath/ath11k/mac.c b/drivers/net/wireless/ath/ath11k/mac.c +index 68754e9914b3a..0b3b6f3ae4aac 100644 +--- a/drivers/net/wireless/ath/ath11k/mac.c ++++ b/drivers/net/wireless/ath/ath11k/mac.c +@@ -5579,7 +5579,7 @@ static int ath11k_mac_mgmt_tx(struct ath11k *ar, struct sk_buff *skb, + + skb_queue_tail(q, skb); + atomic_inc(&ar->num_pending_mgmt_tx); +- ieee80211_queue_work(ar->hw, &ar->wmi_mgmt_tx_work); ++ queue_work(ar->ab->workqueue, &ar->wmi_mgmt_tx_work); + + return 0; + } +-- +2.35.1 + diff --git a/package/kernel/mac80211/patches/ath11k/0177-ath11k-Handle-failure-in-qmi-firmware-ready.patch b/package/kernel/mac80211/patches/ath11k/0177-ath11k-Handle-failure-in-qmi-firmware-ready.patch new file mode 100644 index 000000000..a59096eb0 --- /dev/null +++ b/package/kernel/mac80211/patches/ath11k/0177-ath11k-Handle-failure-in-qmi-firmware-ready.patch @@ -0,0 +1,46 @@ +From a19c0e104db95f78540982c64d78217cd9830d72 Mon Sep 17 00:00:00 2001 +From: Seevalamuthu Mariappan +Date: Thu, 17 Feb 2022 11:56:35 +0530 +Subject: [PATCH] ath11k: Handle failure in qmi firmware ready + +In some scenarios like firmware crashes during init time +and hardware gets restarted after qmi firmware ready event. +During restart, ath11k_core_qmi_firmware_ready() returns timeout. +But, this failure is not handled and ATH11K_FLAG_REGISTERED is set. + +When hardware restart completed, firmware sends firmware ready event +again. Since ATH11K_FLAG_REGISTERED is already set, ath11k handles +this as core restart. Inits are not done because of previous timeout. +But ath11k_core_restart does deinit's which causes NULL pointer crash. + +Fix this by handling failure from ath11k_core_qmi_firmware_ready(). + +Tested-on: QCN9074 hw1.0 PCI WLAN.HK.2.7.0.1-00881-QCAHKSWPL_SILICONZ-1 + +Signed-off-by: Seevalamuthu Mariappan +Signed-off-by: Kalle Valo +Link: https://lore.kernel.org/r/1645079195-13564-1-git-send-email-quic_seevalam@quicinc.com +--- + drivers/net/wireless/ath/ath11k/qmi.c | 6 +++++- + 1 file changed, 5 insertions(+), 1 deletion(-) + +diff --git a/drivers/net/wireless/ath/ath11k/qmi.c b/drivers/net/wireless/ath/ath11k/qmi.c +index d4d831566a894..04e966830c188 100644 +--- a/drivers/net/wireless/ath/ath11k/qmi.c ++++ b/drivers/net/wireless/ath/ath11k/qmi.c +@@ -2960,7 +2960,11 @@ static void ath11k_qmi_driver_event_work(struct work_struct *work) + clear_bit(ATH11K_FLAG_CRASH_FLUSH, + &ab->dev_flags); + clear_bit(ATH11K_FLAG_RECOVERY, &ab->dev_flags); +- ath11k_core_qmi_firmware_ready(ab); ++ ret = ath11k_core_qmi_firmware_ready(ab); ++ if (ret) { ++ set_bit(ATH11K_FLAG_QMI_FAIL, &ab->dev_flags); ++ break; ++ } + set_bit(ATH11K_FLAG_REGISTERED, &ab->dev_flags); + } + +-- +2.35.1 + diff --git a/package/kernel/mac80211/patches/ath11k/0178-ath11k-Invalidate-cached-reo-ring-entry-before-acces.patch b/package/kernel/mac80211/patches/ath11k/0178-ath11k-Invalidate-cached-reo-ring-entry-before-acces.patch new file mode 100644 index 000000000..049b79a24 --- /dev/null +++ b/package/kernel/mac80211/patches/ath11k/0178-ath11k-Invalidate-cached-reo-ring-entry-before-acces.patch @@ -0,0 +1,49 @@ +From f2180ccb52b5fd0876291ad2df37e2898cac18cf Mon Sep 17 00:00:00 2001 +From: Rameshkumar Sundaram +Date: Wed, 16 Feb 2022 14:02:34 +0530 +Subject: [PATCH] ath11k: Invalidate cached reo ring entry before accessing it + +REO2SW ring descriptor is currently allocated in cacheable memory. +While reaping reo ring entries on second trial after updating head +pointer, first entry is not invalidated before accessing it. + +This results in host reaping and using cached descriptor which is +already overwritten in memory by DMA device (HW). +Since the contents of descriptor(buffer id, peer info and other information +bits) are outdated host throws errors like below while parsing corresponding +MSDU's and drops them. + +[347712.048904] ath11k_pci 0004:01:00.0: msdu_done bit in attention is not set +[349173.355503] ath11k_pci 0004:01:00.0: frame rx with invalid buf_id 962 + +Move the try_again: label above ath11k_hal_srng_access_begin() +so that first entry will be invalidated and prefetched. + +Tested-on: QCN9074 hw1.0 PCI WLAN.HK.2.5.0.1-01100-QCAHKSWPL_SILICONZ-1 + +Fixes: 6452f0a3d565 ("ath11k: allocate dst ring descriptors from cacheable memory") +Signed-off-by: Rameshkumar Sundaram +Signed-off-by: Kalle Valo +Link: https://lore.kernel.org/r/1645000354-32558-1-git-send-email-quic_ramess@quicinc.com +--- + drivers/net/wireless/ath/ath11k/dp_rx.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/drivers/net/wireless/ath/ath11k/dp_rx.c b/drivers/net/wireless/ath/ath11k/dp_rx.c +index 20c9e79042613..9183d6f2e5efc 100644 +--- a/drivers/net/wireless/ath/ath11k/dp_rx.c ++++ b/drivers/net/wireless/ath/ath11k/dp_rx.c +@@ -2652,9 +2652,9 @@ int ath11k_dp_process_rx(struct ath11k_base *ab, int ring_id, + + spin_lock_bh(&srng->lock); + ++try_again: + ath11k_hal_srng_access_begin(ab, srng); + +-try_again: + while (likely(desc = + (struct hal_reo_dest_ring *)ath11k_hal_srng_dst_get_next_entry(ab, + srng))) { +-- +2.35.1 + diff --git a/package/kernel/mac80211/patches/ath11k/0179-ath11k-Replace-zero-length-arrays-with-flexible-arra.patch b/package/kernel/mac80211/patches/ath11k/0179-ath11k-Replace-zero-length-arrays-with-flexible-arra.patch new file mode 100644 index 000000000..28d46cdcf --- /dev/null +++ b/package/kernel/mac80211/patches/ath11k/0179-ath11k-Replace-zero-length-arrays-with-flexible-arra.patch @@ -0,0 +1,150 @@ +From e9e591686ccb51d53048dabe8e6020b5a3bba45d Mon Sep 17 00:00:00 2001 +From: "Gustavo A. R. Silva" +Date: Wed, 16 Feb 2022 13:48:36 -0600 +Subject: [PATCH] ath11k: Replace zero-length arrays with flexible-array + members +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +There is a regular need in the kernel to provide a way to declare +having a dynamically sized set of trailing elements in a structure. +Kernel code should always use “flexible array members”[1] for these +cases. The older style of one-element or zero-length arrays should +no longer be used[2]. + +[1] https://en.wikipedia.org/wiki/Flexible_array_member +[2] https://www.kernel.org/doc/html/v5.16/process/deprecated.html#zero-length-and-one-element-arrays + +Link: https://github.com/KSPP/linux/issues/78 +Signed-off-by: Gustavo A. R. Silva +Reviewed-by: Kees Cook +Signed-off-by: Kalle Valo +Link: https://lore.kernel.org/r/20220216194836.GA904035@embeddedor +--- + drivers/net/wireless/ath/ath11k/ce.h | 2 +- + drivers/net/wireless/ath/ath11k/core.h | 2 +- + drivers/net/wireless/ath/ath11k/dp.h | 10 +++++----- + drivers/net/wireless/ath/ath11k/rx_desc.h | 6 +++--- + drivers/net/wireless/ath/ath11k/spectral.c | 2 +- + 5 files changed, 11 insertions(+), 11 deletions(-) + +diff --git a/drivers/net/wireless/ath/ath11k/ce.h b/drivers/net/wireless/ath/ath11k/ce.h +index 8255b6cfab0c7..9644ff909502e 100644 +--- a/drivers/net/wireless/ath/ath11k/ce.h ++++ b/drivers/net/wireless/ath/ath11k/ce.h +@@ -145,7 +145,7 @@ struct ath11k_ce_ring { + u32 hal_ring_id; + + /* keep last */ +- struct sk_buff *skb[0]; ++ struct sk_buff *skb[]; + }; + + struct ath11k_ce_pipe { +diff --git a/drivers/net/wireless/ath/ath11k/core.h b/drivers/net/wireless/ath/ath11k/core.h +index 10846e9e871a9..d2fc7a7a98f4c 100644 +--- a/drivers/net/wireless/ath/ath11k/core.h ++++ b/drivers/net/wireless/ath/ath11k/core.h +@@ -815,7 +815,7 @@ struct ath11k_base { + } id; + + /* must be last */ +- u8 drv_priv[0] __aligned(sizeof(void *)); ++ u8 drv_priv[] __aligned(sizeof(void *)); + }; + + struct ath11k_fw_stats_pdev { +diff --git a/drivers/net/wireless/ath/ath11k/dp.h b/drivers/net/wireless/ath/ath11k/dp.h +index b6ec2d6a2bb61..e9dfa209098b1 100644 +--- a/drivers/net/wireless/ath/ath11k/dp.h ++++ b/drivers/net/wireless/ath/ath11k/dp.h +@@ -1173,12 +1173,12 @@ struct ath11k_htt_ppdu_stats_msg { + u32 ppdu_id; + u32 timestamp; + u32 rsvd; +- u8 data[0]; ++ u8 data[]; + } __packed; + + struct htt_tlv { + u32 header; +- u8 value[0]; ++ u8 value[]; + } __packed; + + #define HTT_TLV_TAG GENMASK(11, 0) +@@ -1365,7 +1365,7 @@ struct htt_ppdu_stats_usr_cmn_array { + * tx_ppdu_stats_info is variable length, with length = + * number_of_ppdu_stats * sizeof (struct htt_tx_ppdu_stats_info) + */ +- struct htt_tx_ppdu_stats_info tx_ppdu_info[0]; ++ struct htt_tx_ppdu_stats_info tx_ppdu_info[]; + } __packed; + + struct htt_ppdu_user_stats { +@@ -1427,7 +1427,7 @@ struct htt_ppdu_stats_info { + */ + struct htt_pktlog_msg { + u32 hdr; +- u8 payload[0]; ++ u8 payload[]; + }; + + /** +@@ -1648,7 +1648,7 @@ struct ath11k_htt_extd_stats_msg { + u32 info0; + u64 cookie; + u32 info1; +- u8 data[0]; ++ u8 data[]; + } __packed; + + #define HTT_MAC_ADDR_L32_0 GENMASK(7, 0) +diff --git a/drivers/net/wireless/ath/ath11k/rx_desc.h b/drivers/net/wireless/ath/ath11k/rx_desc.h +index 79c50804d7dcd..26ecc1bcd9d57 100644 +--- a/drivers/net/wireless/ath/ath11k/rx_desc.h ++++ b/drivers/net/wireless/ath/ath11k/rx_desc.h +@@ -1445,7 +1445,7 @@ struct hal_rx_desc_ipq8074 { + __le32 hdr_status_tag; + __le32 phy_ppdu_id; + u8 hdr_status[HAL_RX_DESC_HDR_STATUS_LEN]; +- u8 msdu_payload[0]; ++ u8 msdu_payload[]; + } __packed; + + struct hal_rx_desc_qcn9074 { +@@ -1464,7 +1464,7 @@ struct hal_rx_desc_qcn9074 { + __le32 hdr_status_tag; + __le32 phy_ppdu_id; + u8 hdr_status[HAL_RX_DESC_HDR_STATUS_LEN]; +- u8 msdu_payload[0]; ++ u8 msdu_payload[]; + } __packed; + + struct hal_rx_desc_wcn6855 { +@@ -1483,7 +1483,7 @@ struct hal_rx_desc_wcn6855 { + __le32 hdr_status_tag; + __le32 phy_ppdu_id; + u8 hdr_status[HAL_RX_DESC_HDR_STATUS_LEN]; +- u8 msdu_payload[0]; ++ u8 msdu_payload[]; + } __packed; + + struct hal_rx_desc { +diff --git a/drivers/net/wireless/ath/ath11k/spectral.c b/drivers/net/wireless/ath/ath11k/spectral.c +index 4100cc1449a2b..2b18871d5f7cb 100644 +--- a/drivers/net/wireless/ath/ath11k/spectral.c ++++ b/drivers/net/wireless/ath/ath11k/spectral.c +@@ -107,7 +107,7 @@ struct spectral_search_fft_report { + __le32 info1; + __le32 info2; + __le32 reserve0; +- u8 bins[0]; ++ u8 bins[]; + } __packed; + + struct ath11k_spectral_search_report { +-- +2.35.1 + diff --git a/package/kernel/mac80211/patches/ath11k/0180-ath11k-configure-RDDM-size-to-mhi-for-recovery-by-fi.patch b/package/kernel/mac80211/patches/ath11k/0180-ath11k-configure-RDDM-size-to-mhi-for-recovery-by-fi.patch new file mode 100644 index 000000000..e516d82e4 --- /dev/null +++ b/package/kernel/mac80211/patches/ath11k/0180-ath11k-configure-RDDM-size-to-mhi-for-recovery-by-fi.patch @@ -0,0 +1,40 @@ +From 03e0add74212b63674ffa1304e55d6c929fb8458 Mon Sep 17 00:00:00 2001 +From: Wen Gong +Date: Mon, 14 Feb 2022 19:53:16 +0200 +Subject: [PATCH] ath11k: configure RDDM size to mhi for recovery by firmware + +The rddm_size is needed by firmware while mhi enter RDDM state, add it +to support recovery when ath11k receive MHI_CB_EE_RDDM message. + +Tested-on: WCN6855 hw2.0 PCI WLAN.HSP.1.1-03003-QCAHSPSWPL_V1_V2_SILICONZ_LITE-2 + +Signed-off-by: Wen Gong +Signed-off-by: Kalle Valo +Link: https://lore.kernel.org/r/20220209060012.32478-4-quic_wgong@quicinc.com +--- + drivers/net/wireless/ath/ath11k/mhi.c | 2 ++ + 1 file changed, 2 insertions(+) + +diff --git a/drivers/net/wireless/ath/ath11k/mhi.c b/drivers/net/wireless/ath/ath11k/mhi.c +index 8b21438028169..fc3524e83e52c 100644 +--- a/drivers/net/wireless/ath/ath11k/mhi.c ++++ b/drivers/net/wireless/ath/ath11k/mhi.c +@@ -13,6 +13,7 @@ + #include "pci.h" + + #define MHI_TIMEOUT_DEFAULT_MS 90000 ++#define RDDM_DUMP_SIZE 0x420000 + + static struct mhi_channel_config ath11k_mhi_channels_qca6390[] = { + { +@@ -382,6 +383,7 @@ int ath11k_mhi_register(struct ath11k_pci *ab_pci) + mhi_ctrl->iova_stop = 0xFFFFFFFF; + } + ++ mhi_ctrl->rddm_size = RDDM_DUMP_SIZE; + mhi_ctrl->sbl_size = SZ_512K; + mhi_ctrl->seg_len = SZ_512K; + mhi_ctrl->fbc_download = true; +-- +2.35.1 + diff --git a/package/kernel/mac80211/patches/ath11k/0181-ath11k-fix-invalid-m3-buffer-address.patch b/package/kernel/mac80211/patches/ath11k/0181-ath11k-fix-invalid-m3-buffer-address.patch new file mode 100644 index 000000000..85daf86b9 --- /dev/null +++ b/package/kernel/mac80211/patches/ath11k/0181-ath11k-fix-invalid-m3-buffer-address.patch @@ -0,0 +1,34 @@ +From e52b6a02bfc00d74cee385dea60f9894121c1f2d Mon Sep 17 00:00:00 2001 +From: Carl Huang +Date: Mon, 14 Feb 2022 19:53:16 +0200 +Subject: [PATCH] ath11k: fix invalid m3 buffer address + +This is to fix m3 buffer reuse issue as m3_mem->size isn't set to +ZERO in free function, which leads invalid m3 downloading to +firmware and firmware crashed. + +Tested-on: WCN6855 hw2.0 PCI WLAN.HSP.1.1-03003-QCAHSPSWPL_V1_V2_SILICONZ_LITE-2 + +Signed-off-by: Carl Huang +Signed-off-by: Wen Gong +Signed-off-by: Kalle Valo +Link: https://lore.kernel.org/r/20220209060012.32478-3-quic_wgong@quicinc.com +--- + drivers/net/wireless/ath/ath11k/qmi.c | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/drivers/net/wireless/ath/ath11k/qmi.c b/drivers/net/wireless/ath/ath11k/qmi.c +index 1144e828cf5cc..d4d831566a894 100644 +--- a/drivers/net/wireless/ath/ath11k/qmi.c ++++ b/drivers/net/wireless/ath/ath11k/qmi.c +@@ -2342,6 +2342,7 @@ static void ath11k_qmi_m3_free(struct ath11k_base *ab) + dma_free_coherent(ab->dev, m3_mem->size, + m3_mem->vaddr, m3_mem->paddr); + m3_mem->vaddr = NULL; ++ m3_mem->size = 0; + } + + static int ath11k_qmi_wlanfw_m3_info_send(struct ath11k_base *ab) +-- +2.35.1 + diff --git a/package/kernel/mac80211/patches/ath11k/0182-ath11k-add-ath11k_qmi_free_resource-for-recovery.patch b/package/kernel/mac80211/patches/ath11k/0182-ath11k-add-ath11k_qmi_free_resource-for-recovery.patch new file mode 100644 index 000000000..51671ea1d --- /dev/null +++ b/package/kernel/mac80211/patches/ath11k/0182-ath11k-add-ath11k_qmi_free_resource-for-recovery.patch @@ -0,0 +1,45 @@ +From 5f71968e3c769b1d3c3cb0831ef870663b3c1f89 Mon Sep 17 00:00:00 2001 +From: Wen Gong +Date: Mon, 14 Feb 2022 19:53:16 +0200 +Subject: [PATCH] ath11k: add ath11k_qmi_free_resource() for recovery + +ath11k_qmi_free_target_mem_chunk() and ath11k_qmi_m3_free() is static +in qmi.c, they are needed for recovery, export them in a new function. + +Tested-on: WCN6855 hw2.0 PCI WLAN.HSP.1.1-03003-QCAHSPSWPL_V1_V2_SILICONZ_LITE-2 + +Signed-off-by: Wen Gong +Signed-off-by: Kalle Valo +Link: https://lore.kernel.org/r/20220209060012.32478-2-quic_wgong@quicinc.com +--- + drivers/net/wireless/ath/ath11k/qmi.c | 5 +++++ + drivers/net/wireless/ath/ath11k/qmi.h | 1 + + 2 files changed, 6 insertions(+) + +diff --git a/drivers/net/wireless/ath/ath11k/qmi.c b/drivers/net/wireless/ath/ath11k/qmi.c +index d0701e8eca9c0..1144e828cf5cc 100644 +--- a/drivers/net/wireless/ath/ath11k/qmi.c ++++ b/drivers/net/wireless/ath/ath11k/qmi.c +@@ -3025,3 +3025,8 @@ void ath11k_qmi_deinit_service(struct ath11k_base *ab) + } + EXPORT_SYMBOL(ath11k_qmi_deinit_service); + ++void ath11k_qmi_free_resource(struct ath11k_base *ab) ++{ ++ ath11k_qmi_free_target_mem_chunk(ab); ++ ath11k_qmi_m3_free(ab); ++} +diff --git a/drivers/net/wireless/ath/ath11k/qmi.h b/drivers/net/wireless/ath/ath11k/qmi.h +index ba2eff4d59cb5..61678de56ac7e 100644 +--- a/drivers/net/wireless/ath/ath11k/qmi.h ++++ b/drivers/net/wireless/ath/ath11k/qmi.h +@@ -492,5 +492,6 @@ void ath11k_qmi_event_work(struct work_struct *work); + void ath11k_qmi_msg_recv_work(struct work_struct *work); + void ath11k_qmi_deinit_service(struct ath11k_base *ab); + int ath11k_qmi_init_service(struct ath11k_base *ab); ++void ath11k_qmi_free_resource(struct ath11k_base *ab); + + #endif +-- +2.35.1 + diff --git a/package/kernel/mac80211/patches/ath11k/100-ath11k-load-appropriate-board-data-from-board-id.patch b/package/kernel/mac80211/patches/ath11k/100-ath11k-load-appropriate-board-data-from-board-id.patch new file mode 100644 index 000000000..022607e59 --- /dev/null +++ b/package/kernel/mac80211/patches/ath11k/100-ath11k-load-appropriate-board-data-from-board-id.patch @@ -0,0 +1,47 @@ +From 89aec0a67ee30cd11762aede86b3edfdb2433663 Mon Sep 17 00:00:00 2001 +From: Venkateswara Naralasetty +Date: Thu, 2 Jul 2020 12:04:34 +0530 +Subject: [PATCH] ath11k: load appropriate board data based on board id + +This patch adds support to read board id from dts and load +appropriate board data. + +Adding the patch which was removed as a part of commit id - +Ib950b3271fede9ccf7d53fe9629c38ee729a0ef5 + +Signed-off-by: Venkateswara Naralasetty +Signed-off-by: Lavanya Suresh +--- + drivers/net/wireless/ath/ath11k/qmi.c | 9 +++++++-- + 1 file changed, 7 insertions(+), 2 deletions(-) + +--- a/drivers/net/wireless/ath/ath11k/qmi.c ++++ b/drivers/net/wireless/ath/ath11k/qmi.c +@@ -2003,9 +2003,11 @@ static int ath11k_qmi_assign_target_mem_ + + static int ath11k_qmi_request_target_cap(struct ath11k_base *ab) + { ++ struct device *dev = ab->dev; + struct qmi_wlanfw_cap_req_msg_v01 req; + struct qmi_wlanfw_cap_resp_msg_v01 resp; + struct qmi_txn txn; ++ unsigned int board_id; + int ret = 0; + int r; + +@@ -2048,10 +2050,13 @@ static int ath11k_qmi_request_target_cap + ab->qmi.target.chip_family = resp.chip_info.chip_family; + } + +- if (resp.board_info_valid) ++ if (!of_property_read_u32(dev->of_node, "qcom,board_id", &board_id) && board_id != 0xFF) { ++ ab->qmi.target.board_id = board_id; ++ } else if (resp.board_info_valid) { + ab->qmi.target.board_id = resp.board_info.board_id; +- else ++ } else { + ab->qmi.target.board_id = 0xFF; ++ } + + if (resp.soc_info_valid) + ab->qmi.target.soc_id = resp.soc_info.soc_id; diff --git a/package/kernel/mac80211/patches/ath11k/101-ath11k-update-debugfs-support-for-mupltiple-radios-i.patch b/package/kernel/mac80211/patches/ath11k/101-ath11k-update-debugfs-support-for-mupltiple-radios-i.patch new file mode 100644 index 000000000..89f36f39a --- /dev/null +++ b/package/kernel/mac80211/patches/ath11k/101-ath11k-update-debugfs-support-for-mupltiple-radios-i.patch @@ -0,0 +1,209 @@ +From 62c6c38a1e55a4f0c659dbb16cfa8196c3ac8467 Mon Sep 17 00:00:00 2001 +From: Anilkumar Kolli +Date: Tue, 14 Dec 2021 17:07:29 +0200 +Subject: [PATCH] ath11k: update debugfs support for mupltiple radios in PCI + bus + +debugfs_ath11k struct is moved to ath11k_core, since its common +for both pci and ahb. + +Current ath11k_pci insmod fails if there are multiple PCI rdaios, + + ath11k_pci 0000:01:00.0: Hardware name qcn9074 hw1.0 + debugfs: Directory 'ath11k' with parent '/' already present! + ath11k_pci 0000:01:00.0: failed to create ath11k debugfs + ath11k_pci 0000:01:00.0: failed to create soc core: -17 + ath11k_pci 0000:01:00.0: failed to init core: -17 + ath11k_pci: probe of 0000:01:00.0 failed with error -17 + +To avoid the failure, debugfs directory is created with soc_name +and bus_id to allow creating debugfs directory for second PCI radio. + +with this Debugfs entries looks like, + # ls -l /sys/kernel/debug/ath11k/ + ipq8074 hw2.0 qcn9000 hw1.0_0000:01:00.0 qcn9000 hw1.0_0001:01:00.0 + + # ls -l /sys/kernel/debug/ath11k/ipq8074 hw2.0/ + mac0 mac1 simulate_fw_crash soc_dp_stats + + # ls -l /sys/kernel/debug/ath11k/qcn9000 hw1.0_0000:01:00.0 + mac0 simulate_fw_crash soc_dp_stats + + # /sys/kernel/debug/ath11k/qcn9000 hw1.0_0001:01:00.0: + mac0 simulate_fw_crash soc_dp_stats + +Tested-on: QCN9074 hw1.0 PCI WLAN.HK.2.4.0.1.r2-00012-QCAHKSWPL_SILICONZ-1 + +Signed-off-by: Anilkumar Kolli +Patchwork-Id: 12101611 +Signed-off-by: Kalle Valo +--- + drivers/net/wireless/ath/ath11k/core.c | 12 +++++ + drivers/net/wireless/ath/ath11k/core.h | 1 - + drivers/net/wireless/ath/ath11k/debugfs.c | 57 +++++++++++++++++++---- + drivers/net/wireless/ath/ath11k/debugfs.h | 11 +++++ + 4 files changed, 70 insertions(+), 11 deletions(-) + +--- a/drivers/net/wireless/ath/ath11k/core.c ++++ b/drivers/net/wireless/ath/ath11k/core.c +@@ -1461,5 +1461,17 @@ err_sc_free: + } + EXPORT_SYMBOL(ath11k_core_alloc); + ++static int ath11k_init(void) ++{ ++ return ath11k_debugfs_create(); ++} ++module_init(ath11k_init); ++ ++static void ath11k_exit(void) ++{ ++ ath11k_debugfs_destroy(); ++} ++module_exit(ath11k_exit); ++ + MODULE_DESCRIPTION("Core module for Qualcomm Atheros 802.11ax wireless LAN cards."); + MODULE_LICENSE("Dual BSD/GPL"); +--- a/drivers/net/wireless/ath/ath11k/core.h ++++ b/drivers/net/wireless/ath/ath11k/core.h +@@ -777,7 +777,6 @@ struct ath11k_base { + enum ath11k_dfs_region dfs_region; + #ifdef CPTCFG_ATH11K_DEBUGFS + struct dentry *debugfs_soc; +- struct dentry *debugfs_ath11k; + #endif + struct ath11k_soc_dp_stats soc_stats; + +--- a/drivers/net/wireless/ath/ath11k/debugfs.c ++++ b/drivers/net/wireless/ath/ath11k/debugfs.c +@@ -13,6 +13,8 @@ + #include "debugfs_htt_stats.h" + #include "peer.h" + ++struct dentry *debugfs_ath11k; ++ + static const char *htt_bp_umac_ring[HTT_SW_UMAC_RING_IDX_MAX] = { + "REO2SW1_RING", + "REO2SW2_RING", +@@ -942,10 +944,6 @@ int ath11k_debugfs_pdev_create(struct at + if (test_bit(ATH11K_FLAG_REGISTERED, &ab->dev_flags)) + return 0; + +- ab->debugfs_soc = debugfs_create_dir(ab->hw_params.name, ab->debugfs_ath11k); +- if (IS_ERR(ab->debugfs_soc)) +- return PTR_ERR(ab->debugfs_soc); +- + debugfs_create_file("simulate_fw_crash", 0600, ab->debugfs_soc, ab, + &fops_simulate_fw_crash); + +@@ -957,24 +955,58 @@ int ath11k_debugfs_pdev_create(struct at + + void ath11k_debugfs_pdev_destroy(struct ath11k_base *ab) + { +- debugfs_remove_recursive(ab->debugfs_soc); +- ab->debugfs_soc = NULL; + } + + int ath11k_debugfs_soc_create(struct ath11k_base *ab) + { +- ab->debugfs_ath11k = debugfs_create_dir("ath11k", NULL); ++ struct device *dev = ab->dev; ++ char soc_name[64] = {0}; ++ ++ if (!(IS_ERR_OR_NULL(ab->debugfs_soc))) ++ return 0; ++ ++ if (ab->hif.bus == ATH11K_BUS_AHB) { ++ snprintf(soc_name, sizeof(soc_name), "%s", ab->hw_params.name); ++ } else { ++ snprintf(soc_name, sizeof(soc_name), "%s_%s", ++ ab->hw_params.name, dev_name(dev)); ++ } + +- return PTR_ERR_OR_ZERO(ab->debugfs_ath11k); ++ ab->debugfs_soc = debugfs_create_dir(soc_name, debugfs_ath11k); ++ if (IS_ERR_OR_NULL(ab->debugfs_soc)) { ++ if (IS_ERR(ab->debugfs_soc)) ++ return PTR_ERR(ab->debugfs_soc); ++ return -ENOMEM; ++ } ++ ++ return 0; + } + + void ath11k_debugfs_soc_destroy(struct ath11k_base *ab) + { +- debugfs_remove_recursive(ab->debugfs_ath11k); +- ab->debugfs_ath11k = NULL; ++ debugfs_remove_recursive(ab->debugfs_soc); ++ ab->debugfs_soc = NULL; + } + EXPORT_SYMBOL(ath11k_debugfs_soc_destroy); + ++int ath11k_debugfs_create(void) ++{ ++ debugfs_ath11k = debugfs_create_dir("ath11k", NULL); ++ if (IS_ERR_OR_NULL(debugfs_ath11k)) { ++ if (IS_ERR(debugfs_ath11k)) ++ return PTR_ERR(debugfs_ath11k); ++ return -ENOMEM; ++ } ++ ++ return 0; ++} ++ ++void ath11k_debugfs_destroy(void) ++{ ++ debugfs_remove_recursive(debugfs_ath11k); ++ debugfs_ath11k = NULL; ++} ++ + void ath11k_debugfs_fw_stats_init(struct ath11k *ar) + { + struct dentry *fwstats_dir = debugfs_create_dir("fw_stats", +@@ -1180,6 +1212,9 @@ int ath11k_debugfs_register(struct ath11 + char pdev_name[5]; + char buf[100] = {0}; + ++ if (!(IS_ERR_OR_NULL(ar->debug.debugfs_pdev))) ++ return 0; ++ + snprintf(pdev_name, sizeof(pdev_name), "%s%d", "mac", ar->pdev_idx); + + ar->debug.debugfs_pdev = debugfs_create_dir(pdev_name, ab->debugfs_soc); +@@ -1221,6 +1256,8 @@ int ath11k_debugfs_register(struct ath11 + + void ath11k_debugfs_unregister(struct ath11k *ar) + { ++ debugfs_remove_recursive(ar->debug.debugfs_pdev); ++ ar->debug.debugfs_pdev = NULL; + } + + static ssize_t ath11k_write_twt_add_dialog(struct file *file, +--- a/drivers/net/wireless/ath/ath11k/debugfs.h ++++ b/drivers/net/wireless/ath/ath11k/debugfs.h +@@ -233,6 +233,8 @@ struct ath11k_fw_dbglog { + }; + + #ifdef CPTCFG_ATH11K_DEBUGFS ++int ath11k_debugfs_create(void); ++void ath11k_debugfs_destroy(void); + int ath11k_debugfs_soc_create(struct ath11k_base *ab); + void ath11k_debugfs_soc_destroy(struct ath11k_base *ab); + int ath11k_debugfs_pdev_create(struct ath11k_base *ab); +@@ -280,6 +282,15 @@ int ath11k_debugfs_add_interface(struct + void ath11k_debugfs_remove_interface(struct ath11k_vif *arvif); + + #else ++static inline int ath11k_debugfs_create(void) ++{ ++ return 0; ++} ++ ++static inline void ath11k_debugfs_destroy(void) ++{ ++} ++ + static inline int ath11k_debugfs_soc_create(struct ath11k_base *ab) + { + return 0; diff --git a/package/kernel/mac80211/patches/ath11k/102-ath11k-Enable-threaded-NAPI-on-some-radios.patch b/package/kernel/mac80211/patches/ath11k/102-ath11k-Enable-threaded-NAPI-on-some-radios.patch new file mode 100644 index 000000000..1a3819f77 --- /dev/null +++ b/package/kernel/mac80211/patches/ath11k/102-ath11k-Enable-threaded-NAPI-on-some-radios.patch @@ -0,0 +1,109 @@ +From 65252b91331a9be068ebbd53f15ad6fd1113031b Mon Sep 17 00:00:00 2001 +From: Manikanta Pubbisetty +Date: Sun, 13 Feb 2022 20:46:07 +0100 +Subject: [PATCH] ath11k: Enable threaded NAPI on some radios + +Enable threaded NAPI on IPQ8074 and QCN9074. + +Unlike traditional NAPI poll which runs in softirq context and on the +core which scheduled the NAPI, threaded NAPI makes use of kernel threads +which are under direct control of the scheduler and helps in balancing the +NAPI processing load across multiple CPUs, this helps in improving +throughput. + +In the case of IPQ8074 it increased the throughput at 80MHz by about +200Mbps. + +Tested-on: IPQ8074 hw2.0 AHB WLAN.HK.2.5.0.1-01201-QCAHKSWPL_SILICONZ-1 + +Signed-off-by: Manikanta Pubbisetty +Signed-off-by: Robert Marko +--- + drivers/net/wireless/ath/ath11k/ahb.c | 2 ++ + drivers/net/wireless/ath/ath11k/core.c | 6 ++++++ + drivers/net/wireless/ath/ath11k/hw.h | 1 + + drivers/net/wireless/ath/ath11k/pci.c | 2 ++ + 4 files changed, 11 insertions(+) + +--- a/drivers/net/wireless/ath/ath11k/ahb.c ++++ b/drivers/net/wireless/ath/ath11k/ahb.c +@@ -304,6 +304,8 @@ static void ath11k_ahb_ext_irq_enable(st + struct ath11k_ext_irq_grp *irq_grp = &ab->ext_irq_grp[i]; + + if (!irq_grp->napi_enabled) { ++ if (ab->hw_params.threaded_napi) ++ dev_set_threaded(&irq_grp->napi_ndev, true); + napi_enable(&irq_grp->napi); + irq_grp->napi_enabled = true; + } +--- a/drivers/net/wireless/ath/ath11k/core.c ++++ b/drivers/net/wireless/ath/ath11k/core.c +@@ -99,6 +99,7 @@ static const struct ath11k_hw_params ath + .supports_rssi_stats = false, + .fw_wmi_diag_event = false, + .current_cc_support = false, ++ .threaded_napi = true, + }, + { + .hw_rev = ATH11K_HW_IPQ6018_HW10, +@@ -164,6 +165,7 @@ static const struct ath11k_hw_params ath + .supports_rssi_stats = false, + .fw_wmi_diag_event = false, + .current_cc_support = false, ++ .threaded_napi = false, + }, + { + .name = "qca6390 hw2.0", +@@ -228,6 +230,7 @@ static const struct ath11k_hw_params ath + .supports_rssi_stats = true, + .fw_wmi_diag_event = true, + .current_cc_support = true, ++ .threaded_napi = false, + }, + { + .name = "qcn9074 hw1.0", +@@ -292,6 +295,7 @@ static const struct ath11k_hw_params ath + .supports_rssi_stats = false, + .fw_wmi_diag_event = false, + .current_cc_support = false, ++ .threaded_napi = true, + }, + { + .name = "wcn6855 hw2.0", +@@ -356,6 +360,7 @@ static const struct ath11k_hw_params ath + .supports_rssi_stats = true, + .fw_wmi_diag_event = true, + .current_cc_support = true, ++ .threaded_napi = false, + }, + { + .name = "wcn6855 hw2.1", +@@ -419,6 +424,7 @@ static const struct ath11k_hw_params ath + .supports_rssi_stats = true, + .fw_wmi_diag_event = true, + .current_cc_support = true, ++ .threaded_napi = false, + }, + }; + +--- a/drivers/net/wireless/ath/ath11k/hw.h ++++ b/drivers/net/wireless/ath/ath11k/hw.h +@@ -193,6 +193,7 @@ struct ath11k_hw_params { + bool supports_rssi_stats; + bool fw_wmi_diag_event; + bool current_cc_support; ++ bool threaded_napi; + }; + + struct ath11k_hw_ops { +--- a/drivers/net/wireless/ath/ath11k/pci.c ++++ b/drivers/net/wireless/ath/ath11k/pci.c +@@ -716,6 +716,8 @@ static void ath11k_pci_ext_irq_enable(st + struct ath11k_ext_irq_grp *irq_grp = &ab->ext_irq_grp[i]; + + if (!irq_grp->napi_enabled) { ++ if (ab->hw_params.threaded_napi) ++ dev_set_threaded(&irq_grp->napi_ndev, true); + napi_enable(&irq_grp->napi); + irq_grp->napi_enabled = true; + } diff --git a/package/kernel/mac80211/patches/ath11k/900-ath11k-Disable-coldboot-calibration-for-IPQ8074.patch b/package/kernel/mac80211/patches/ath11k/900-ath11k-Disable-coldboot-calibration-for-IPQ8074.patch new file mode 100644 index 000000000..06d1137ae --- /dev/null +++ b/package/kernel/mac80211/patches/ath11k/900-ath11k-Disable-coldboot-calibration-for-IPQ8074.patch @@ -0,0 +1,24 @@ +From fee0e35d4e652243bfd8cf4c52e1706e0cc9b88d Mon Sep 17 00:00:00 2001 +From: Robert Marko +Date: Sat, 16 Oct 2021 19:34:10 +0200 +Subject: [PATCH] ath11k: Disable coldboot calibration for IPQ8074 + +There is a bug with the remoteproc reset after coldboot calibration, +so until that is resolved disabled it to allow using the radio. + +Signed-off-by: Robert Marko +--- + drivers/net/wireless/ath/ath11k/core.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +--- a/drivers/net/wireless/ath/ath11k/core.c ++++ b/drivers/net/wireless/ath/ath11k/core.c +@@ -82,7 +82,7 @@ static const struct ath11k_hw_params ath + .supports_shadow_regs = false, + .idle_ps = false, + .supports_sta_ps = false, +- .cold_boot_calib = true, ++ .cold_boot_calib = false, + .fw_mem_mode = 0, + .num_vdevs = 16 + 1, + .num_peers = 512, diff --git a/package/kernel/mac80211/patches/ath11k/901-ath11k-ipq8074-support-512MB-memory-profile.patch b/package/kernel/mac80211/patches/ath11k/901-ath11k-ipq8074-support-512MB-memory-profile.patch new file mode 100644 index 000000000..73b412415 --- /dev/null +++ b/package/kernel/mac80211/patches/ath11k/901-ath11k-ipq8074-support-512MB-memory-profile.patch @@ -0,0 +1,63 @@ +From 20ad5a47dd5093a8eb934a64f398d16d4952de91 Mon Sep 17 00:00:00 2001 +From: Robert Marko +Date: Wed, 15 Dec 2021 19:44:52 +0100 +Subject: [PATCH] ath11k: ipq8074: support 512MB memory profile + +ath11k is really memory intensive for devices with less that 1GB of ram, +so lets port the QSDK patch that adds a profile for devices with 512MB +of RAM. + +Signed-off-by: Csaba Sipos +Signed-off-by: Robert Marko +--- + drivers/net/wireless/ath/ath11k/Kconfig | 12 ++ + drivers/net/wireless/ath/ath11k/core.c | 6 + + local-symbols | 2 + + 4 files changed, 176 insertions(+) +--- a/drivers/net/wireless/ath/ath11k/Kconfig ++++ b/drivers/net/wireless/ath/ath11k/Kconfig +@@ -60,3 +60,15 @@ config ATH11K_SPECTRAL + Enable ath11k spectral scan support + + Say Y to enable access to the FFT/spectral data via debugfs. ++ ++config ATH11K_MEM_PROFILE_512MB ++ bool "Atheros ath11k 512MB memory profile" ++ depends on ATH11K ++ help ++ Use limits for the 512MB memory size instead of 1GB. ++ ++config ATH11K_MEM_PROFILE_1GB ++ bool "Atheros ath11k 1GB memory profile" ++ depends on ATH11K ++ help ++ Use limits for the 1GB memory size. +--- a/drivers/net/wireless/ath/ath11k/core.c ++++ b/drivers/net/wireless/ath/ath11k/core.c +@@ -83,9 +83,15 @@ static const struct ath11k_hw_params ath + .idle_ps = false, + .supports_sta_ps = false, + .cold_boot_calib = false, ++#ifdef CPTCFG_ATH11K_MEM_PROFILE_1GB + .fw_mem_mode = 0, + .num_vdevs = 16 + 1, + .num_peers = 512, ++#elif CPTCFG_ATH11K_MEM_PROFILE_512MB ++ .fw_mem_mode = 1, ++ .num_vdevs = 8, ++ .num_peers = 128, ++#endif + .supports_suspend = false, + .hal_desc_sz = sizeof(struct hal_rx_desc_ipq8074), + .supports_regdb = false, +--- a/local-symbols ++++ b/local-symbols +@@ -148,6 +148,8 @@ ATH11K_DEBUG= + ATH11K_DEBUGFS= + ATH11K_TRACING= + ATH11K_SPECTRAL= ++ATH11K_MEM_PROFILE_512MB= ++ATH11K_MEM_PROFILE_1GB= + WLAN_VENDOR_ATMEL= + ATMEL= + PCI_ATMEL= diff --git a/package/kernel/mac80211/patches/subsys/0001-v5.16-ieee80211-Add-new-A-MPDU-factor-macro-for-HE-6-GHz-p.patch b/package/kernel/mac80211/patches/subsys/0001-v5.16-ieee80211-Add-new-A-MPDU-factor-macro-for-HE-6-GHz-p.patch new file mode 100644 index 000000000..3092d9c47 --- /dev/null +++ b/package/kernel/mac80211/patches/subsys/0001-v5.16-ieee80211-Add-new-A-MPDU-factor-macro-for-HE-6-GHz-p.patch @@ -0,0 +1,27 @@ +From 62b8963cd84df1fc04986cd9b27586acce758f36 Mon Sep 17 00:00:00 2001 +From: Pradeep Kumar Chitrapu +Date: Tue, 28 Sep 2021 14:00:45 +0300 +Subject: [PATCH] ieee80211: Add new A-MPDU factor macro for HE 6 GHz peer caps + +Add IEEE80211_HE_6GHZ_MAX_AMPDU_FACTOR as per IEEE Std 802.11ax-2021, +9.4.2.263 to use for peer max A-MPDU factor in 6 GHz band. + +Signed-off-by: Pradeep Kumar Chitrapu +Signed-off-by: Jouni Malinen +Acked-by: Johannes Berg +Signed-off-by: Kalle Valo +Link: https://lore.kernel.org/r/20210913175510.193005-1-jouni@codeaurora.org +--- + include/linux/ieee80211.h | 1 + + 1 file changed, 1 insertion(+) + +--- a/include/linux/ieee80211.h ++++ b/include/linux/ieee80211.h +@@ -2084,6 +2084,7 @@ int ieee80211_get_vht_max_nss(struct iee + + #define IEEE80211_HE_VHT_MAX_AMPDU_FACTOR 20 + #define IEEE80211_HE_HT_MAX_AMPDU_FACTOR 16 ++#define IEEE80211_HE_6GHZ_MAX_AMPDU_FACTOR 13 + + /* 802.11ax HE PHY capabilities */ + #define IEEE80211_HE_PHY_CAP0_CHANNEL_WIDTH_SET_40MHZ_IN_2G 0x02