From ad25ee36f00172f7d53242dc77c69fff7ced0755 Mon Sep 17 00:00:00 2001 From: Xingyuan Mo Date: Sun, 17 Dec 2023 13:29:01 +0200 Subject: [PATCH 01/71] wifi: ath10k: fix NULL pointer dereference in ath10k_wmi_tlv_op_pull_mgmt_tx_compl_ev() We should check whether the WMI_TLV_TAG_STRUCT_MGMT_TX_COMPL_EVENT tlv is present before accessing it, otherwise a null pointer deference error will occur. Fixes: dc405152bb64 ("ath10k: handle mgmt tx completion event") Signed-off-by: Xingyuan Mo Acked-by: Jeff Johnson Signed-off-by: Kalle Valo Link: https://msgid.link/20231208043433.271449-1-hdthky0@gmail.com --- drivers/net/wireless/ath/ath10k/wmi-tlv.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/drivers/net/wireless/ath/ath10k/wmi-tlv.c b/drivers/net/wireless/ath/ath10k/wmi-tlv.c index 6b6aa3c36744..0ce08e9a0a3d 100644 --- a/drivers/net/wireless/ath/ath10k/wmi-tlv.c +++ b/drivers/net/wireless/ath/ath10k/wmi-tlv.c @@ -851,6 +851,10 @@ ath10k_wmi_tlv_op_pull_mgmt_tx_compl_ev(struct ath10k *ar, struct sk_buff *skb, } ev = tb[WMI_TLV_TAG_STRUCT_MGMT_TX_COMPL_EVENT]; + if (!ev) { + kfree(tb); + return -EPROTO; + } arg->desc_id = ev->desc_id; arg->status = ev->status; From f5e6c0c4b0877e0ec0221df6c0041c0f39b6ce0f Mon Sep 17 00:00:00 2001 From: Dmitry Antipov Date: Sun, 17 Dec 2023 13:29:02 +0200 Subject: [PATCH 02/71] wifi: ath11k: refactor ath11k_wmi_tlv_parse_alloc() Since 'ath11k_wmi_tlv_parse_alloc()' always operates on 'skb->data, skb->len' tuple, it may be simplified to pass the only 'skb' argument instead (which also implies refactoring of 'ath11k_pull_bcn_tx_status_ev()' and 'ath11k_pull_chan_info_ev()' in the same way). Compile tested only. Signed-off-by: Dmitry Antipov Signed-off-by: Kalle Valo Link: https://msgid.link/20231214161117.75145-1-dmantipov@yandex.ru --- drivers/net/wireless/ath/ath11k/testmode.c | 2 +- drivers/net/wireless/ath/ath11k/wmi.c | 73 +++++++++++----------- drivers/net/wireless/ath/ath11k/wmi.h | 4 +- 3 files changed, 39 insertions(+), 40 deletions(-) diff --git a/drivers/net/wireless/ath/ath11k/testmode.c b/drivers/net/wireless/ath/ath11k/testmode.c index 43bb23265d34..302d66092b97 100644 --- a/drivers/net/wireless/ath/ath11k/testmode.c +++ b/drivers/net/wireless/ath/ath11k/testmode.c @@ -198,7 +198,7 @@ static void ath11k_tm_wmi_event_segmented(struct ath11k_base *ab, u32 cmd_id, u16 length; int ret; - tb = ath11k_wmi_tlv_parse_alloc(ab, skb->data, skb->len, GFP_ATOMIC); + tb = ath11k_wmi_tlv_parse_alloc(ab, skb, GFP_ATOMIC); if (IS_ERR(tb)) { ret = PTR_ERR(tb); ath11k_warn(ab, "failed to parse ftm event tlv: %d\n", ret); diff --git a/drivers/net/wireless/ath/ath11k/wmi.c b/drivers/net/wireless/ath/ath11k/wmi.c index 8a65fa04b48d..89514899fcd5 100644 --- a/drivers/net/wireless/ath/ath11k/wmi.c +++ b/drivers/net/wireless/ath/ath11k/wmi.c @@ -238,8 +238,8 @@ static int ath11k_wmi_tlv_parse(struct ath11k_base *ar, const void **tb, (void *)tb); } -const void **ath11k_wmi_tlv_parse_alloc(struct ath11k_base *ab, const void *ptr, - size_t len, gfp_t gfp) +const void **ath11k_wmi_tlv_parse_alloc(struct ath11k_base *ab, + struct sk_buff *skb, gfp_t gfp) { const void **tb; int ret; @@ -248,7 +248,7 @@ const void **ath11k_wmi_tlv_parse_alloc(struct ath11k_base *ab, const void *ptr, if (!tb) return ERR_PTR(-ENOMEM); - ret = ath11k_wmi_tlv_parse(ab, tb, ptr, len); + ret = ath11k_wmi_tlv_parse(ab, tb, skb->data, skb->len); if (ret) { kfree(tb); return ERR_PTR(ret); @@ -3930,7 +3930,7 @@ ath11k_wmi_obss_color_collision_event(struct ath11k_base *ab, struct sk_buff *sk struct ath11k_vif *arvif; int ret; - tb = ath11k_wmi_tlv_parse_alloc(ab, skb->data, skb->len, GFP_ATOMIC); + tb = ath11k_wmi_tlv_parse_alloc(ab, skb, GFP_ATOMIC); if (IS_ERR(tb)) { ret = PTR_ERR(tb); ath11k_warn(ab, "failed to parse tlv: %d\n", ret); @@ -5003,7 +5003,7 @@ static int ath11k_pull_vdev_start_resp_tlv(struct ath11k_base *ab, struct sk_buf const struct wmi_vdev_start_resp_event *ev; int ret; - tb = ath11k_wmi_tlv_parse_alloc(ab, skb->data, skb->len, GFP_ATOMIC); + tb = ath11k_wmi_tlv_parse_alloc(ab, skb, GFP_ATOMIC); if (IS_ERR(tb)) { ret = PTR_ERR(tb); ath11k_warn(ab, "failed to parse tlv: %d\n", ret); @@ -5102,7 +5102,7 @@ static int ath11k_pull_reg_chan_list_update_ev(struct ath11k_base *ab, ath11k_dbg(ab, ATH11K_DBG_WMI, "processing regulatory channel list\n"); - tb = ath11k_wmi_tlv_parse_alloc(ab, skb->data, skb->len, GFP_ATOMIC); + tb = ath11k_wmi_tlv_parse_alloc(ab, skb, GFP_ATOMIC); if (IS_ERR(tb)) { ret = PTR_ERR(tb); ath11k_warn(ab, "failed to parse tlv: %d\n", ret); @@ -5278,7 +5278,7 @@ static int ath11k_pull_reg_chan_list_ext_update_ev(struct ath11k_base *ab, ath11k_dbg(ab, ATH11K_DBG_WMI, "processing regulatory ext channel list\n"); - tb = ath11k_wmi_tlv_parse_alloc(ab, skb->data, skb->len, GFP_ATOMIC); + tb = ath11k_wmi_tlv_parse_alloc(ab, skb, GFP_ATOMIC); if (IS_ERR(tb)) { ret = PTR_ERR(tb); ath11k_warn(ab, "failed to parse tlv: %d\n", ret); @@ -5634,7 +5634,7 @@ static int ath11k_pull_peer_del_resp_ev(struct ath11k_base *ab, struct sk_buff * const struct wmi_peer_delete_resp_event *ev; int ret; - tb = ath11k_wmi_tlv_parse_alloc(ab, skb->data, skb->len, GFP_ATOMIC); + tb = ath11k_wmi_tlv_parse_alloc(ab, skb, GFP_ATOMIC); if (IS_ERR(tb)) { ret = PTR_ERR(tb); ath11k_warn(ab, "failed to parse tlv: %d\n", ret); @@ -5666,7 +5666,7 @@ static int ath11k_pull_vdev_del_resp_ev(struct ath11k_base *ab, const struct wmi_vdev_delete_resp_event *ev; int ret; - tb = ath11k_wmi_tlv_parse_alloc(ab, skb->data, skb->len, GFP_ATOMIC); + tb = ath11k_wmi_tlv_parse_alloc(ab, skb, GFP_ATOMIC); if (IS_ERR(tb)) { ret = PTR_ERR(tb); ath11k_warn(ab, "failed to parse tlv: %d\n", ret); @@ -5686,15 +5686,15 @@ static int ath11k_pull_vdev_del_resp_ev(struct ath11k_base *ab, return 0; } -static int ath11k_pull_bcn_tx_status_ev(struct ath11k_base *ab, void *evt_buf, - u32 len, u32 *vdev_id, - u32 *tx_status) +static int ath11k_pull_bcn_tx_status_ev(struct ath11k_base *ab, + struct sk_buff *skb, + u32 *vdev_id, u32 *tx_status) { const void **tb; const struct wmi_bcn_tx_status_event *ev; int ret; - tb = ath11k_wmi_tlv_parse_alloc(ab, evt_buf, len, GFP_ATOMIC); + tb = ath11k_wmi_tlv_parse_alloc(ab, skb, GFP_ATOMIC); if (IS_ERR(tb)) { ret = PTR_ERR(tb); ath11k_warn(ab, "failed to parse tlv: %d\n", ret); @@ -5722,7 +5722,7 @@ static int ath11k_pull_vdev_stopped_param_tlv(struct ath11k_base *ab, struct sk_ const struct wmi_vdev_stopped_event *ev; int ret; - tb = ath11k_wmi_tlv_parse_alloc(ab, skb->data, skb->len, GFP_ATOMIC); + tb = ath11k_wmi_tlv_parse_alloc(ab, skb, GFP_ATOMIC); if (IS_ERR(tb)) { ret = PTR_ERR(tb); ath11k_warn(ab, "failed to parse tlv: %d\n", ret); @@ -5876,7 +5876,7 @@ static int ath11k_pull_mgmt_tx_compl_param_tlv(struct ath11k_base *ab, const struct wmi_mgmt_tx_compl_event *ev; int ret; - tb = ath11k_wmi_tlv_parse_alloc(ab, skb->data, skb->len, GFP_ATOMIC); + tb = ath11k_wmi_tlv_parse_alloc(ab, skb, GFP_ATOMIC); if (IS_ERR(tb)) { ret = PTR_ERR(tb); ath11k_warn(ab, "failed to parse tlv: %d\n", ret); @@ -6052,7 +6052,7 @@ static int ath11k_pull_scan_ev(struct ath11k_base *ab, struct sk_buff *skb, const struct wmi_scan_event *ev; int ret; - tb = ath11k_wmi_tlv_parse_alloc(ab, skb->data, skb->len, GFP_ATOMIC); + tb = ath11k_wmi_tlv_parse_alloc(ab, skb, GFP_ATOMIC); if (IS_ERR(tb)) { ret = PTR_ERR(tb); ath11k_warn(ab, "failed to parse tlv: %d\n", ret); @@ -6085,7 +6085,7 @@ static int ath11k_pull_peer_sta_kickout_ev(struct ath11k_base *ab, struct sk_buf const struct wmi_peer_sta_kickout_event *ev; int ret; - tb = ath11k_wmi_tlv_parse_alloc(ab, skb->data, skb->len, GFP_ATOMIC); + tb = ath11k_wmi_tlv_parse_alloc(ab, skb, GFP_ATOMIC); if (IS_ERR(tb)) { ret = PTR_ERR(tb); ath11k_warn(ab, "failed to parse tlv: %d\n", ret); @@ -6112,7 +6112,7 @@ static int ath11k_pull_roam_ev(struct ath11k_base *ab, struct sk_buff *skb, const struct wmi_roam_event *ev; int ret; - tb = ath11k_wmi_tlv_parse_alloc(ab, skb->data, skb->len, GFP_ATOMIC); + tb = ath11k_wmi_tlv_parse_alloc(ab, skb, GFP_ATOMIC); if (IS_ERR(tb)) { ret = PTR_ERR(tb); ath11k_warn(ab, "failed to parse tlv: %d\n", ret); @@ -6153,14 +6153,14 @@ static int freq_to_idx(struct ath11k *ar, int freq) return idx; } -static int ath11k_pull_chan_info_ev(struct ath11k_base *ab, u8 *evt_buf, - u32 len, struct wmi_chan_info_event *ch_info_ev) +static int ath11k_pull_chan_info_ev(struct ath11k_base *ab, struct sk_buff *skb, + struct wmi_chan_info_event *ch_info_ev) { const void **tb; const struct wmi_chan_info_event *ev; int ret; - tb = ath11k_wmi_tlv_parse_alloc(ab, evt_buf, len, GFP_ATOMIC); + tb = ath11k_wmi_tlv_parse_alloc(ab, skb, GFP_ATOMIC); if (IS_ERR(tb)) { ret = PTR_ERR(tb); ath11k_warn(ab, "failed to parse tlv: %d\n", ret); @@ -6199,7 +6199,7 @@ ath11k_pull_pdev_bss_chan_info_ev(struct ath11k_base *ab, struct sk_buff *skb, const struct wmi_pdev_bss_chan_info_event *ev; int ret; - tb = ath11k_wmi_tlv_parse_alloc(ab, skb->data, skb->len, GFP_ATOMIC); + tb = ath11k_wmi_tlv_parse_alloc(ab, skb, GFP_ATOMIC); if (IS_ERR(tb)) { ret = PTR_ERR(tb); ath11k_warn(ab, "failed to parse tlv: %d\n", ret); @@ -6239,7 +6239,7 @@ ath11k_pull_vdev_install_key_compl_ev(struct ath11k_base *ab, struct sk_buff *sk const struct wmi_vdev_install_key_compl_event *ev; int ret; - tb = ath11k_wmi_tlv_parse_alloc(ab, skb->data, skb->len, GFP_ATOMIC); + tb = ath11k_wmi_tlv_parse_alloc(ab, skb, GFP_ATOMIC); if (IS_ERR(tb)) { ret = PTR_ERR(tb); ath11k_warn(ab, "failed to parse tlv: %d\n", ret); @@ -6270,7 +6270,7 @@ static int ath11k_pull_peer_assoc_conf_ev(struct ath11k_base *ab, struct sk_buff const struct wmi_peer_assoc_conf_event *ev; int ret; - tb = ath11k_wmi_tlv_parse_alloc(ab, skb->data, skb->len, GFP_ATOMIC); + tb = ath11k_wmi_tlv_parse_alloc(ab, skb, GFP_ATOMIC); if (IS_ERR(tb)) { ret = PTR_ERR(tb); ath11k_warn(ab, "failed to parse tlv: %d\n", ret); @@ -6995,7 +6995,7 @@ static int ath11k_reg_11d_new_cc_event(struct ath11k_base *ab, struct sk_buff *s const void **tb; int ret, i; - tb = ath11k_wmi_tlv_parse_alloc(ab, skb->data, skb->len, GFP_ATOMIC); + tb = ath11k_wmi_tlv_parse_alloc(ab, skb, GFP_ATOMIC); if (IS_ERR(tb)) { ret = PTR_ERR(tb); ath11k_warn(ab, "failed to parse tlv: %d\n", ret); @@ -7384,8 +7384,7 @@ static void ath11k_bcn_tx_status_event(struct ath11k_base *ab, struct sk_buff *s struct ath11k_vif *arvif; u32 vdev_id, tx_status; - if (ath11k_pull_bcn_tx_status_ev(ab, skb->data, skb->len, - &vdev_id, &tx_status) != 0) { + if (ath11k_pull_bcn_tx_status_ev(ab, skb, &vdev_id, &tx_status) != 0) { ath11k_warn(ab, "failed to extract bcn tx status"); return; } @@ -7416,7 +7415,7 @@ static void ath11k_wmi_event_peer_sta_ps_state_chg(struct ath11k_base *ab, enum ath11k_wmi_peer_ps_state peer_previous_ps_state; int ret; - tb = ath11k_wmi_tlv_parse_alloc(ab, skb->data, skb->len, GFP_ATOMIC); + tb = ath11k_wmi_tlv_parse_alloc(ab, skb, GFP_ATOMIC); if (IS_ERR(tb)) { ret = PTR_ERR(tb); ath11k_warn(ab, "failed to parse tlv: %d\n", ret); @@ -7884,7 +7883,7 @@ static void ath11k_chan_info_event(struct ath11k_base *ab, struct sk_buff *skb) /* HW channel counters frequency value in hertz */ u32 cc_freq_hz = ab->cc_freq_hz; - if (ath11k_pull_chan_info_ev(ab, skb->data, skb->len, &ch_info_ev) != 0) { + if (ath11k_pull_chan_info_ev(ab, skb, &ch_info_ev) != 0) { ath11k_warn(ab, "failed to extract chan info event"); return; } @@ -8216,7 +8215,7 @@ static void ath11k_pdev_ctl_failsafe_check_event(struct ath11k_base *ab, const struct wmi_pdev_ctl_failsafe_chk_event *ev; int ret; - tb = ath11k_wmi_tlv_parse_alloc(ab, skb->data, skb->len, GFP_ATOMIC); + tb = ath11k_wmi_tlv_parse_alloc(ab, skb, GFP_ATOMIC); if (IS_ERR(tb)) { ret = PTR_ERR(tb); ath11k_warn(ab, "failed to parse tlv: %d\n", ret); @@ -8281,7 +8280,7 @@ ath11k_wmi_pdev_csa_switch_count_status_event(struct ath11k_base *ab, const u32 *vdev_ids; int ret; - tb = ath11k_wmi_tlv_parse_alloc(ab, skb->data, skb->len, GFP_ATOMIC); + tb = ath11k_wmi_tlv_parse_alloc(ab, skb, GFP_ATOMIC); if (IS_ERR(tb)) { ret = PTR_ERR(tb); ath11k_warn(ab, "failed to parse tlv: %d\n", ret); @@ -8315,7 +8314,7 @@ ath11k_wmi_pdev_dfs_radar_detected_event(struct ath11k_base *ab, struct sk_buff struct ath11k *ar; int ret; - tb = ath11k_wmi_tlv_parse_alloc(ab, skb->data, skb->len, GFP_ATOMIC); + tb = ath11k_wmi_tlv_parse_alloc(ab, skb, GFP_ATOMIC); if (IS_ERR(tb)) { ret = PTR_ERR(tb); ath11k_warn(ab, "failed to parse tlv: %d\n", ret); @@ -8369,7 +8368,7 @@ ath11k_wmi_pdev_temperature_event(struct ath11k_base *ab, const struct wmi_pdev_temperature_event *ev; int ret; - tb = ath11k_wmi_tlv_parse_alloc(ab, skb->data, skb->len, GFP_ATOMIC); + tb = ath11k_wmi_tlv_parse_alloc(ab, skb, GFP_ATOMIC); if (IS_ERR(tb)) { ret = PTR_ERR(tb); ath11k_warn(ab, "failed to parse tlv: %d\n", ret); @@ -8409,7 +8408,7 @@ static void ath11k_fils_discovery_event(struct ath11k_base *ab, const struct wmi_fils_discovery_event *ev; int ret; - tb = ath11k_wmi_tlv_parse_alloc(ab, skb->data, skb->len, GFP_ATOMIC); + tb = ath11k_wmi_tlv_parse_alloc(ab, skb, GFP_ATOMIC); if (IS_ERR(tb)) { ret = PTR_ERR(tb); ath11k_warn(ab, @@ -8441,7 +8440,7 @@ static void ath11k_probe_resp_tx_status_event(struct ath11k_base *ab, const struct wmi_probe_resp_tx_status_event *ev; int ret; - tb = ath11k_wmi_tlv_parse_alloc(ab, skb->data, skb->len, GFP_ATOMIC); + tb = ath11k_wmi_tlv_parse_alloc(ab, skb, GFP_ATOMIC); if (IS_ERR(tb)) { ret = PTR_ERR(tb); ath11k_warn(ab, @@ -8567,7 +8566,7 @@ static void ath11k_wmi_twt_add_dialog_event(struct ath11k_base *ab, const struct wmi_twt_add_dialog_event *ev; int ret; - tb = ath11k_wmi_tlv_parse_alloc(ab, skb->data, skb->len, GFP_ATOMIC); + tb = ath11k_wmi_tlv_parse_alloc(ab, skb, GFP_ATOMIC); if (IS_ERR(tb)) { ret = PTR_ERR(tb); ath11k_warn(ab, @@ -8604,7 +8603,7 @@ static void ath11k_wmi_gtk_offload_status_event(struct ath11k_base *ab, u64 replay_ctr; int ret; - tb = ath11k_wmi_tlv_parse_alloc(ab, skb->data, skb->len, GFP_ATOMIC); + tb = ath11k_wmi_tlv_parse_alloc(ab, skb, GFP_ATOMIC); if (IS_ERR(tb)) { ret = PTR_ERR(tb); ath11k_warn(ab, "failed to parse tlv: %d\n", ret); diff --git a/drivers/net/wireless/ath/ath11k/wmi.h b/drivers/net/wireless/ath/ath11k/wmi.h index ff0a9a92beeb..b1b4ee804b7b 100644 --- a/drivers/net/wireless/ath/ath11k/wmi.h +++ b/drivers/net/wireless/ath/ath11k/wmi.h @@ -6295,8 +6295,8 @@ enum wmi_sta_keepalive_method { #define WMI_STA_KEEPALIVE_INTERVAL_DEFAULT 30 #define WMI_STA_KEEPALIVE_INTERVAL_DISABLE 0 -const void **ath11k_wmi_tlv_parse_alloc(struct ath11k_base *ab, const void *ptr, - size_t len, gfp_t gfp); +const void **ath11k_wmi_tlv_parse_alloc(struct ath11k_base *ab, + struct sk_buff *skb, gfp_t gfp); int ath11k_wmi_cmd_send(struct ath11k_pdev_wmi *wmi, struct sk_buff *skb, u32 cmd_id); struct sk_buff *ath11k_wmi_alloc_skb(struct ath11k_wmi_base *wmi_sc, u32 len); From 504130491026be9cf19f9de562172d340a06a2bb Mon Sep 17 00:00:00 2001 From: Wenli Looi Date: Sun, 17 Dec 2023 13:29:02 +0200 Subject: [PATCH 03/71] wifi: ath9k: delete some unused/duplicate macros MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The rate macros are for AR9002 and not correct for AR9003. The AGC 3 macros are unused and have incorrect values, at least for QCN5502, where AR_AGC3_BASE should be 0x2de00. This change does not appear to affect the final binary. Signed-off-by: Wenli Looi Acked-by: Toke Høiland-Jørgensen Signed-off-by: Kalle Valo Link: https://msgid.link/20230629231625.951744-3-wlooi@ucalgary.ca --- drivers/net/wireless/ath/ath9k/ar9003_phy.h | 9 --------- drivers/net/wireless/ath/ath9k/reg_aic.h | 4 ---- 2 files changed, 13 deletions(-) diff --git a/drivers/net/wireless/ath/ath9k/ar9003_phy.h b/drivers/net/wireless/ath/ath9k/ar9003_phy.h index 57e2b4c89125..ad72a30b67c3 100644 --- a/drivers/net/wireless/ath/ath9k/ar9003_phy.h +++ b/drivers/net/wireless/ath/ath9k/ar9003_phy.h @@ -851,8 +851,6 @@ #define AR_PHY_TXGAIN_FORCED_TXBB1DBGAIN 0x0000000e #define AR_PHY_TXGAIN_FORCED_TXBB1DBGAIN_S 1 -#define AR_PHY_POWER_TX_RATE1 0x9934 -#define AR_PHY_POWER_TX_RATE2 0x9938 #define AR_PHY_POWER_TX_RATE_MAX 0x993c #define AR_PHY_POWER_TX_RATE_MAX_TPC_ENABLE 0x00000040 #define PHY_AGC_CLR 0x10000000 @@ -1041,13 +1039,6 @@ #define AR_PHY_TX_IQCAL_STATUS_B2_FAILED 0x00000001 -/* - * AGC 3 Register Map - */ -#define AR_AGC3_BASE 0xce00 - -#define AR_PHY_RSSI_3 (AR_AGC3_BASE + 0x180) - /* GLB Registers */ #define AR_GLB_BASE 0x20000 #define AR_GLB_GPIO_CONTROL (AR_GLB_BASE) diff --git a/drivers/net/wireless/ath/ath9k/reg_aic.h b/drivers/net/wireless/ath/ath9k/reg_aic.h index 955147ab48a2..f50994910eae 100644 --- a/drivers/net/wireless/ath/ath9k/reg_aic.h +++ b/drivers/net/wireless/ath/ath9k/reg_aic.h @@ -17,10 +17,6 @@ #ifndef REG_AIC_H #define REG_AIC_H -#define AR_SM_BASE 0xa200 -#define AR_SM1_BASE 0xb200 -#define AR_AGC_BASE 0x9e00 - #define AR_PHY_AIC_CTRL_0_B0 (AR_SM_BASE + 0x4b0) #define AR_PHY_AIC_CTRL_1_B0 (AR_SM_BASE + 0x4b4) #define AR_PHY_AIC_CTRL_2_B0 (AR_SM_BASE + 0x4b8) From 27ce06d018cec6a5042069fb21b000753dd147d2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Uwe=20Kleine-K=C3=B6nig?= Date: Sun, 17 Dec 2023 13:29:03 +0200 Subject: [PATCH 04/71] wifi: ath9k: Convert to platform remove callback returning void MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The .remove() callback for a platform driver returns an int which makes many driver authors wrongly assume it's possible to do error handling by returning an error code. However the value returned is ignored (apart from emitting a warning) and this typically results in resource leaks. To improve here there is a quest to make the remove callback return void. In the first step of this quest all drivers are converted to .remove_new(), which already returns void. Eventually after all drivers are converted, .remove_new() will be renamed to .remove(). Trivially convert this driver from always returning zero in the remove callback to the void returning variant. Signed-off-by: Uwe Kleine-König Reviewed-by: Jeff Johnson Acked-by: Toke Høiland-Jørgensen Signed-off-by: Kalle Valo Link: https://msgid.link/20231117093056.873834-11-u.kleine-koenig@pengutronix.de --- drivers/net/wireless/ath/ath9k/ahb.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/drivers/net/wireless/ath/ath9k/ahb.c b/drivers/net/wireless/ath/ath9k/ahb.c index 9bfaadfa6c00..1a6697b6e3b4 100644 --- a/drivers/net/wireless/ath/ath9k/ahb.c +++ b/drivers/net/wireless/ath/ath9k/ahb.c @@ -144,7 +144,7 @@ static int ath_ahb_probe(struct platform_device *pdev) return ret; } -static int ath_ahb_remove(struct platform_device *pdev) +static void ath_ahb_remove(struct platform_device *pdev) { struct ieee80211_hw *hw = platform_get_drvdata(pdev); @@ -155,13 +155,11 @@ static int ath_ahb_remove(struct platform_device *pdev) free_irq(sc->irq, sc); ieee80211_free_hw(sc->hw); } - - return 0; } static struct platform_driver ath_ahb_driver = { .probe = ath_ahb_probe, - .remove = ath_ahb_remove, + .remove_new = ath_ahb_remove, .driver = { .name = "ath9k", }, From d6b27eb997ef9a2aa51633b3111bc4a04748e6d3 Mon Sep 17 00:00:00 2001 From: Dmitry Antipov Date: Sun, 17 Dec 2023 13:29:03 +0200 Subject: [PATCH 05/71] wifi: ath9k: fix LNA selection in ath_ant_try_scan() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit In 'ath_ant_try_scan()', (most likely) the 2nd LNA's signal strength should be used in comparison against RSSI when selecting first LNA as the main one. Compile tested only. Found by Linux Verification Center (linuxtesting.org) with SVACE. Signed-off-by: Dmitry Antipov Acked-by: Toke Høiland-Jørgensen Signed-off-by: Kalle Valo Link: https://msgid.link/20231211172502.25202-1-dmantipov@yandex.ru --- drivers/net/wireless/ath/ath9k/antenna.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/wireless/ath/ath9k/antenna.c b/drivers/net/wireless/ath/ath9k/antenna.c index 988222cea9df..acc84e6711b0 100644 --- a/drivers/net/wireless/ath/ath9k/antenna.c +++ b/drivers/net/wireless/ath/ath9k/antenna.c @@ -643,7 +643,7 @@ static void ath_ant_try_scan(struct ath_ant_comb *antcomb, conf->main_lna_conf = ATH_ANT_DIV_COMB_LNA1; conf->alt_lna_conf = ATH_ANT_DIV_COMB_LNA1_PLUS_LNA2; } else if (antcomb->rssi_sub > - antcomb->rssi_lna1) { + antcomb->rssi_lna2) { /* set to A-B */ conf->main_lna_conf = ATH_ANT_DIV_COMB_LNA1; conf->alt_lna_conf = ATH_ANT_DIV_COMB_LNA1_MINUS_LNA2; From d2eb318f4b6be1176e87ac3f9f8cc976be1c014b Mon Sep 17 00:00:00 2001 From: Jeff Johnson Date: Sun, 17 Dec 2023 13:29:03 +0200 Subject: [PATCH 06/71] wifi: ath10k: use flexible array in struct wmi_host_mem_chunks Currently struct wmi_host_mem_chunks defines: struct host_memory_chunk items[1]; Per the guidance in [1] this should be a flexible array. However there is a documented requirement: some fw revisions require at least 1 chunk regardless of count To satisfy this requirement, follow the guidance from [2] and wrap the array in a union which contains both the flexible array and a single instance of the underlying struct. Since the footprint of the struct is unchanged, no additional driver changes are required. No functional changes, compile tested only. [1] https://docs.kernel.org/process/deprecated.html#zero-length-and-one-element-arrays [2] https://lore.kernel.org/linux-wireless/202308301529.AC90A9EF98@keescook/ Signed-off-by: Jeff Johnson Reviewed-by: Kees Cook Reviewed-by: Gustavo A. R. Silva Signed-off-by: Kalle Valo Link: https://msgid.link/20231213-wmi_host_mem_chunks_flexarray-v1-1-92922d92fa2c@quicinc.com --- drivers/net/wireless/ath/ath10k/wmi.h | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/drivers/net/wireless/ath/ath10k/wmi.h b/drivers/net/wireless/ath/ath10k/wmi.h index 9146df98fcee..833ce0251a2c 100644 --- a/drivers/net/wireless/ath/ath10k/wmi.h +++ b/drivers/net/wireless/ath/ath10k/wmi.h @@ -3069,7 +3069,10 @@ struct host_memory_chunk { struct wmi_host_mem_chunks { __le32 count; /* some fw revisions require at least 1 chunk regardless of count */ - struct host_memory_chunk items[1]; + union { + struct host_memory_chunk item; + DECLARE_FLEX_ARRAY(struct host_memory_chunk, items); + }; } __packed; struct wmi_init_cmd { From 72ca7c4073ac126be1c2341644838ef5f146b36b Mon Sep 17 00:00:00 2001 From: Jeff Johnson Date: Sun, 17 Dec 2023 13:29:03 +0200 Subject: [PATCH 07/71] wifi: ath10k: use flexible arrays for WMI start scan TLVs Currently ath10k defines the following struct: struct wmi_start_scan_tlvs { u8 tlvs[0]; } __packed; Per the guidance in [1] this should be a flexible array. However, a direct replace to u8 tlvs[] results in the compilation error: flexible array member in a struct with no named members This is because C99 6.7.2.1 (16) requires that a structure containing a flexible array member must have more than one named member. So rather than defining a separate struct wmi_start_scan_tlvs which contains the flexible tlvs[] array, just define the tlvs[] array where struct wmi_start_scan_tlvs is being used. No functional changes, compile tested only. [1] https://docs.kernel.org/process/deprecated.html#zero-length-and-one-element-arrays Signed-off-by: Jeff Johnson Reviewed-by: Kees Cook Reviewed-by: Gustavo A. R. Silva Signed-off-by: Kalle Valo Link: https://msgid.link/20231213-wmi_host_mem_chunks_flexarray-v1-2-92922d92fa2c@quicinc.com --- drivers/net/wireless/ath/ath10k/wmi.c | 8 ++++---- drivers/net/wireless/ath/ath10k/wmi.h | 11 ++--------- 2 files changed, 6 insertions(+), 13 deletions(-) diff --git a/drivers/net/wireless/ath/ath10k/wmi.c b/drivers/net/wireless/ath/ath10k/wmi.c index 88befe92f95d..4d5aadbc7159 100644 --- a/drivers/net/wireless/ath/ath10k/wmi.c +++ b/drivers/net/wireless/ath/ath10k/wmi.c @@ -6927,14 +6927,14 @@ void ath10k_wmi_put_start_scan_common(struct wmi_start_scan_common *cmn, } static void -ath10k_wmi_put_start_scan_tlvs(struct wmi_start_scan_tlvs *tlvs, +ath10k_wmi_put_start_scan_tlvs(u8 *tlvs, const struct wmi_start_scan_arg *arg) { struct wmi_ie_data *ie; struct wmi_chan_list *channels; struct wmi_ssid_list *ssids; struct wmi_bssid_list *bssids; - void *ptr = tlvs->tlvs; + void *ptr = tlvs; int i; if (arg->n_channels) { @@ -7012,7 +7012,7 @@ ath10k_wmi_op_gen_start_scan(struct ath10k *ar, cmd = (struct wmi_start_scan_cmd *)skb->data; ath10k_wmi_put_start_scan_common(&cmd->common, arg); - ath10k_wmi_put_start_scan_tlvs(&cmd->tlvs, arg); + ath10k_wmi_put_start_scan_tlvs(cmd->tlvs, arg); cmd->burst_duration_ms = __cpu_to_le32(0); @@ -7041,7 +7041,7 @@ ath10k_wmi_10x_op_gen_start_scan(struct ath10k *ar, cmd = (struct wmi_10x_start_scan_cmd *)skb->data; ath10k_wmi_put_start_scan_common(&cmd->common, arg); - ath10k_wmi_put_start_scan_tlvs(&cmd->tlvs, arg); + ath10k_wmi_put_start_scan_tlvs(cmd->tlvs, arg); ath10k_dbg(ar, ATH10K_DBG_WMI, "wmi 10x start scan\n"); return skb; diff --git a/drivers/net/wireless/ath/ath10k/wmi.h b/drivers/net/wireless/ath/ath10k/wmi.h index 833ce0251a2c..52a409ff94e7 100644 --- a/drivers/net/wireless/ath/ath10k/wmi.h +++ b/drivers/net/wireless/ath/ath10k/wmi.h @@ -3218,23 +3218,16 @@ struct wmi_start_scan_common { __le32 scan_ctrl_flags; } __packed; -struct wmi_start_scan_tlvs { - /* TLV parameters. These includes channel list, ssid list, bssid list, - * extra ies. - */ - u8 tlvs[0]; -} __packed; - struct wmi_start_scan_cmd { struct wmi_start_scan_common common; __le32 burst_duration_ms; - struct wmi_start_scan_tlvs tlvs; + u8 tlvs[]; } __packed; /* This is the definition from 10.X firmware branch */ struct wmi_10x_start_scan_cmd { struct wmi_start_scan_common common; - struct wmi_start_scan_tlvs tlvs; + u8 tlvs[]; } __packed; struct wmi_ssid_arg { From 26eb704a46f89d50a58ccb22b317b73ee85fa233 Mon Sep 17 00:00:00 2001 From: Jeff Johnson Date: Sun, 17 Dec 2023 13:29:03 +0200 Subject: [PATCH 08/71] wifi: ath10k: remove struct wmi_pdev_chanlist_update_event Currently struct wmi_pdev_chanlist_update_event defines: struct wmi_channel channel_list[1]; Per the guidance in [1] this should be a flexible array. However during conversion it was discovered that this struct is not used, so just remove the entire struct. No functional changes, compile tested only. [1] https://docs.kernel.org/process/deprecated.html#zero-length-and-one-element-arrays Signed-off-by: Jeff Johnson Reviewed-by: Kees Cook Reviewed-by: Gustavo A. R. Silva Signed-off-by: Kalle Valo Link: https://msgid.link/20231213-wmi_host_mem_chunks_flexarray-v1-3-92922d92fa2c@quicinc.com --- drivers/net/wireless/ath/ath10k/wmi.h | 7 ------- 1 file changed, 7 deletions(-) diff --git a/drivers/net/wireless/ath/ath10k/wmi.h b/drivers/net/wireless/ath/ath10k/wmi.h index 52a409ff94e7..37a7d421bd86 100644 --- a/drivers/net/wireless/ath/ath10k/wmi.h +++ b/drivers/net/wireless/ath/ath10k/wmi.h @@ -4256,13 +4256,6 @@ struct wmi_peer_sta_ps_state_chg_event { __le32 peer_ps_state; } __packed; -struct wmi_pdev_chanlist_update_event { - /* number of channels */ - __le32 num_chan; - /* array of channels */ - struct wmi_channel channel_list[1]; -} __packed; - #define WMI_MAX_DEBUG_MESG (sizeof(u32) * 32) struct wmi_debug_mesg_event { From b0c0794b05ec07a150bd39be3d43854a9dd93cad Mon Sep 17 00:00:00 2001 From: Jeff Johnson Date: Sun, 17 Dec 2023 13:29:03 +0200 Subject: [PATCH 09/71] wifi: ath10k: remove unused template structs Currently both the wmi_bcn_tmpl_cmd and wmi_prb_tmpl_cmd structs define: u8 data[1]; Per the guidance in [1] both instances of this should be flexible arrays. However during conversion it was discovered that neither of these structs are actually used, so just remove them. No functional changes, compile tested only. [1] https://docs.kernel.org/process/deprecated.html#zero-length-and-one-element-arrays Signed-off-by: Jeff Johnson Reviewed-by: Kees Cook Reviewed-by: Gustavo A. R. Silva Signed-off-by: Kalle Valo Link: https://msgid.link/20231213-wmi_host_mem_chunks_flexarray-v1-4-92922d92fa2c@quicinc.com --- drivers/net/wireless/ath/ath10k/wmi.h | 24 ------------------------ 1 file changed, 24 deletions(-) diff --git a/drivers/net/wireless/ath/ath10k/wmi.h b/drivers/net/wireless/ath/ath10k/wmi.h index 37a7d421bd86..e16410e348ca 100644 --- a/drivers/net/wireless/ath/ath10k/wmi.h +++ b/drivers/net/wireless/ath/ath10k/wmi.h @@ -5782,30 +5782,6 @@ struct wmi_bcn_prb_info { /* app IE */ } __packed; -struct wmi_bcn_tmpl_cmd { - /* unique id identifying the VDEV, generated by the caller */ - __le32 vdev_id; - /* TIM IE offset from the beginning of the template. */ - __le32 tim_ie_offset; - /* beacon probe capabilities and IEs */ - struct wmi_bcn_prb_info bcn_prb_info; - /* beacon buffer length */ - __le32 buf_len; - /* variable length data */ - u8 data[1]; -} __packed; - -struct wmi_prb_tmpl_cmd { - /* unique id identifying the VDEV, generated by the caller */ - __le32 vdev_id; - /* beacon probe capabilities and IEs */ - struct wmi_bcn_prb_info bcn_prb_info; - /* beacon buffer length */ - __le32 buf_len; - /* Variable length data */ - u8 data[1]; -} __packed; - enum wmi_sta_ps_mode { /* enable power save for the given STA VDEV */ WMI_STA_PS_MODE_DISABLED = 0, From cb188e862c1ce195ce8beaac10b554c33847f4c8 Mon Sep 17 00:00:00 2001 From: Jeff Johnson Date: Sun, 17 Dec 2023 13:29:03 +0200 Subject: [PATCH 10/71] wifi: ath10k: use flexible array in struct wmi_tdls_peer_capabilities Currently struct wmi_tdls_peer_capabilities defines: struct wmi_channel peer_chan_list[1]; Per the guidance in [1] this should be a flexible array, and at one point Gustavo was trying to fix this [2], but had questions about the correct behavior when the associated peer_chan_len is 0. I have been unable to determine if firmware requires that at least one record be present even if peer_chan_len is 0. But since that is the current behavior, follow the example from [3] and replace the one-element array with a union that contains both a flexible array and a single instance of the array element. This results in a struct that has the same footprint as the original, so no other driver changes are required. No functional changes, compile tested only. [1] https://docs.kernel.org/process/deprecated.html#zero-length-and-one-element-arrays [2] https://lore.kernel.org/linux-wireless/626ae2e7-66f8-423b-b17f-e75c1a6d29b3@embeddedor.com/ [3] https://lore.kernel.org/linux-wireless/202308301529.AC90A9EF98@keescook/ Signed-off-by: Jeff Johnson Reviewed-by: Kees Cook Reviewed-by: Gustavo A. R. Silva Signed-off-by: Kalle Valo Link: https://msgid.link/20231213-wmi_host_mem_chunks_flexarray-v1-5-92922d92fa2c@quicinc.com --- drivers/net/wireless/ath/ath10k/wmi.h | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/drivers/net/wireless/ath/ath10k/wmi.h b/drivers/net/wireless/ath/ath10k/wmi.h index e16410e348ca..b64b6e214bae 100644 --- a/drivers/net/wireless/ath/ath10k/wmi.h +++ b/drivers/net/wireless/ath/ath10k/wmi.h @@ -7162,7 +7162,13 @@ struct wmi_tdls_peer_capabilities { __le32 is_peer_responder; __le32 pref_offchan_num; __le32 pref_offchan_bw; - struct wmi_channel peer_chan_list[1]; + union { + /* to match legacy implementation allocate room for + * at least one record even if peer_chan_len is 0 + */ + struct wmi_channel peer_chan_min_allocation; + DECLARE_FLEX_ARRAY(struct wmi_channel, peer_chan_list); + }; } __packed; struct wmi_10_4_tdls_peer_update_cmd { From 6b9923f1f6d1b57a2ae932540a6273a0face54fe Mon Sep 17 00:00:00 2001 From: Jeff Johnson Date: Sun, 17 Dec 2023 13:29:03 +0200 Subject: [PATCH 11/71] wifi: ath10k: remove duplicate memset() in 10.4 TDLS peer update In [1] it was identified that in ath10k_wmi_10_4_gen_tdls_peer_update() the memset(skb->data, 0, sizeof(*cmd)) is unnecessary since function ath10k_wmi_alloc_skb() already zeroes skb->data, so remove it. No functional changes, compile tested only. [1] https://lore.kernel.org/linux-wireless/626ae2e7-66f8-423b-b17f-e75c1a6d29b3@embeddedor.com/ Signed-off-by: Jeff Johnson Reviewed-by: Kees Cook Reviewed-by: Gustavo A. R. Silva Signed-off-by: Kalle Valo Link: https://msgid.link/20231213-wmi_host_mem_chunks_flexarray-v1-6-92922d92fa2c@quicinc.com --- drivers/net/wireless/ath/ath10k/wmi.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/drivers/net/wireless/ath/ath10k/wmi.c b/drivers/net/wireless/ath/ath10k/wmi.c index 4d5aadbc7159..0cfd9484c45e 100644 --- a/drivers/net/wireless/ath/ath10k/wmi.c +++ b/drivers/net/wireless/ath/ath10k/wmi.c @@ -8918,8 +8918,6 @@ ath10k_wmi_10_4_gen_tdls_peer_update(struct ath10k *ar, if (!skb) return ERR_PTR(-ENOMEM); - memset(skb->data, 0, sizeof(*cmd)); - cmd = (struct wmi_10_4_tdls_peer_update_cmd *)skb->data; cmd->vdev_id = __cpu_to_le32(arg->vdev_id); ether_addr_copy(cmd->peer_macaddr.addr, arg->addr); From f4c2a9d62213cf7004db5c74ce12d26d63a23629 Mon Sep 17 00:00:00 2001 From: Wen Gong Date: Sun, 17 Dec 2023 13:29:03 +0200 Subject: [PATCH 12/71] wifi: ath12k: add string type to search board data in board-2.bin for WCN7850 Currently ath12k only supports 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 PCI bus chip in board-2.bin. For WCN7850, it is not enough to distinguish all different chips. Add a new string type which includes bus, chip id, board id, vendor, device, subsystem-vendor and subsystem-device for WCN7850. ath12k will first load board-2.bin and searches in it for the board data with the above parameters. If matched with one board data, ath12k downloads it to firmware. And if not, downloads board.bin instead. Tested-on: WCN7850 hw2.0 PCI WLAN.HMT.1.0-03427-QCAHMTSWPL_V1.0_V2.0_SILICONZ-1.15378.4 Signed-off-by: Wen Gong Signed-off-by: Baochen Qiang Signed-off-by: Kalle Valo Link: https://msgid.link/20231216060140.30611-2-quic_bqiang@quicinc.com --- drivers/net/wireless/ath/ath12k/core.c | 27 ++++++++++++++++++++------ drivers/net/wireless/ath/ath12k/core.h | 13 +++++++++++++ drivers/net/wireless/ath/ath12k/pci.c | 10 ++++++++++ 3 files changed, 44 insertions(+), 6 deletions(-) diff --git a/drivers/net/wireless/ath/ath12k/core.c b/drivers/net/wireless/ath/ath12k/core.c index 6c01b282fcd3..b8027f76a02e 100644 --- a/drivers/net/wireless/ath/ath12k/core.c +++ b/drivers/net/wireless/ath/ath12k/core.c @@ -114,11 +114,26 @@ static int ath12k_core_create_board_name(struct ath12k_base *ab, char *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", - ath12k_bus_str(ab->hif.bus), - ab->qmi.target.chip_id, - ab->qmi.target.board_id, variant); + switch (ab->id.bdf_search) { + case ATH12K_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", + ath12k_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", + ath12k_bus_str(ab->hif.bus), + ab->qmi.target.chip_id, + ab->qmi.target.board_id, variant); + break; + } ath12k_dbg(ab, ATH12K_DBG_BOOT, "boot using board name '%s'\n", name); @@ -356,7 +371,7 @@ int ath12k_core_fetch_board_data_api_1(struct ath12k_base *ab, return 0; } -#define BOARD_NAME_SIZE 100 +#define BOARD_NAME_SIZE 200 int ath12k_core_fetch_bdf(struct ath12k_base *ab, struct ath12k_board_data *bd) { char boardname[BOARD_NAME_SIZE]; diff --git a/drivers/net/wireless/ath/ath12k/core.h b/drivers/net/wireless/ath/ath12k/core.h index 8458dc292821..385fda03e913 100644 --- a/drivers/net/wireless/ath/ath12k/core.h +++ b/drivers/net/wireless/ath/ath12k/core.h @@ -55,6 +55,11 @@ #define ATH12K_RECONFIGURE_TIMEOUT_HZ (10 * HZ) #define ATH12K_RECOVER_START_TIMEOUT_HZ (20 * HZ) +enum ath12k_bdf_search { + ATH12K_BDF_SEARCH_DEFAULT, + ATH12K_BDF_SEARCH_BUS_AND_BOARD, +}; + enum wme_ac { WME_AC_BE, WME_AC_BK, @@ -793,6 +798,14 @@ struct ath12k_base { /* true means radio is on */ bool rfkill_radio_on; + struct { + enum ath12k_bdf_search bdf_search; + u32 vendor; + u32 device; + u32 subsystem_vendor; + u32 subsystem_device; + } id; + /* must be last */ u8 drv_priv[] __aligned(sizeof(void *)); }; diff --git a/drivers/net/wireless/ath/ath12k/pci.c b/drivers/net/wireless/ath/ath12k/pci.c index f0d2e2d8719c..76438b3afd55 100644 --- a/drivers/net/wireless/ath/ath12k/pci.c +++ b/drivers/net/wireless/ath/ath12k/pci.c @@ -1310,6 +1310,15 @@ static int ath12k_pci_probe(struct pci_dev *pdev, goto err_free_core; } + ath12k_dbg(ab, ATH12K_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 QCN9274_DEVICE_ID: ab_pci->msi_config = &ath12k_msi_config[0]; @@ -1333,6 +1342,7 @@ static int ath12k_pci_probe(struct pci_dev *pdev, } break; case WCN7850_DEVICE_ID: + ab->id.bdf_search = ATH12K_BDF_SEARCH_BUS_AND_BOARD; ab_pci->msi_config = &ath12k_msi_config[0]; ab->static_window_map = false; ab_pci->pci_ops = &ath12k_pci_ops_wcn7850; From 7173972a2eb1107ae3dc076f1cd27abce132e027 Mon Sep 17 00:00:00 2001 From: Wen Gong Date: Sun, 17 Dec 2023 13:29:04 +0200 Subject: [PATCH 13/71] wifi: ath12k: add fallback board name without variant while searching board-2.bin Currently a variant value read from DT or SMBIOS is considered while searching board-2.bin, this may fail because not all board-2.bin files contains that symbol. Add fallback board name which removes variant value and searches again in board-2.bin when fails to increase boot up success rate. dmesg log after this patch: [169547.248472] ath12k_pci 0000:05:00.0: boot using board name 'bus=pci,vendor=17cb,device=1103,subsystem-vendor=17cb,subsystem-device=3374,qmi-chip-id=2,qmi-board-id=262,variant=test' [169547.248565] ath12k_pci 0000:05:00.0: boot firmware request ath12k/WCN7850/hw2.0/board-2.bin size 180324 [169547.248568] ath12k_pci 0000:05:00.0: board name [169547.248570] ath12k_pci 0000:05:00.0: 00000000: 62 75 73 3d 70 63 69 2c 76 65 6e 64 6f 72 3d 31 bus=pci,vendor=1 [169547.248571] ath12k_pci 0000:05:00.0: 00000010: 37 63 62 2c 64 65 76 69 63 65 3d 31 31 30 33 2c 7cb,device=1103, [169547.248572] ath12k_pci 0000:05:00.0: 00000020: 73 75 62 73 79 73 74 65 6d 2d 76 65 6e 64 6f 72 subsystem-vendor [169547.248574] ath12k_pci 0000:05:00.0: 00000030: 3d 31 37 63 62 2c 73 75 62 73 79 73 74 65 6d 2d =17cb,subsystem- [169547.248575] ath12k_pci 0000:05:00.0: 00000040: 64 65 76 69 63 65 3d 33 33 37 34 2c 71 6d 69 2d device=3374,qmi- [169547.248576] ath12k_pci 0000:05:00.0: 00000050: 63 68 69 70 2d 69 64 3d 32 2c 71 6d 69 2d 62 6f chip-id=2,qmi-bo [169547.248577] ath12k_pci 0000:05:00.0: 00000060: 61 72 64 2d 69 64 3d 32 36 32 ard-id=262 [169547.248578] ath12k_pci 0000:05:00.0: board name [169547.248579] ath12k_pci 0000:05:00.0: 00000000: 62 75 73 3d 70 63 69 2c 76 65 6e 64 6f 72 3d 31 bus=pci,vendor=1 [169547.248581] ath12k_pci 0000:05:00.0: 00000010: 37 63 62 2c 64 65 76 69 63 65 3d 31 31 30 33 2c 7cb,device=1103, [169547.248582] ath12k_pci 0000:05:00.0: 00000020: 73 75 62 73 79 73 74 65 6d 2d 76 65 6e 64 6f 72 subsystem-vendor [169547.248583] ath12k_pci 0000:05:00.0: 00000030: 3d 31 37 63 62 2c 73 75 62 73 79 73 74 65 6d 2d =17cb,subsystem- [169547.248584] ath12k_pci 0000:05:00.0: 00000040: 64 65 76 69 63 65 3d 33 33 37 34 2c 71 6d 69 2d device=3374,qmi- [169547.248585] ath12k_pci 0000:05:00.0: 00000050: 63 68 69 70 2d 69 64 3d 32 2c 71 6d 69 2d 62 6f chip-id=2,qmi-bo [169547.248587] ath12k_pci 0000:05:00.0: 00000060: 61 72 64 2d 69 64 3d 32 36 36 ard-id=266 [169547.248588] ath12k_pci 0000:05:00.0: board name [169547.248589] ath12k_pci 0000:05:00.0: 00000000: 62 75 73 3d 70 63 69 2c 76 65 6e 64 6f 72 3d 31 bus=pci,vendor=1 [169547.248590] ath12k_pci 0000:05:00.0: 00000010: 37 63 62 2c 64 65 76 69 63 65 3d 31 31 30 33 2c 7cb,device=1103, [169547.248591] ath12k_pci 0000:05:00.0: 00000020: 73 75 62 73 79 73 74 65 6d 2d 76 65 6e 64 6f 72 subsystem-vendor [169547.248592] ath12k_pci 0000:05:00.0: 00000030: 3d 31 37 63 62 2c 73 75 62 73 79 73 74 65 6d 2d =17cb,subsystem- [169547.248594] ath12k_pci 0000:05:00.0: 00000040: 64 65 76 69 63 65 3d 33 33 37 34 2c 71 6d 69 2d device=3374,qmi- [169547.248595] ath12k_pci 0000:05:00.0: 00000050: 63 68 69 70 2d 69 64 3d 31 38 2c 71 6d 69 2d 62 chip-id=18,qmi-b [169547.248596] ath12k_pci 0000:05:00.0: 00000060: 6f 61 72 64 2d 69 64 3d 32 36 36 oard-id=266 [169547.248597] ath12k_pci 0000:05:00.0: failed to fetch board data for bus=pci,vendor=17cb,device=1103,subsystem-vendor=17cb,subsystem-device=3374,qmi-chip-id=2,qmi-board-id=262,variant=test from ath12k/WCN7850/hw2.0/board-2.bin [169547.248476] ath12k_pci 0000:05:00.0: boot using board name 'bus=pci,vendor=17cb,device=1103,subsystem-vendor=17cb,subsystem-device=3374,qmi-chip-id=2,qmi-board-id=262' [169547.248634] ath12k_pci 0000:05:00.0: boot firmware request ath12k/WCN7850/hw2.0/board-2.bin size 180324 [169547.248636] ath12k_pci 0000:05:00.0: board name [169547.248637] ath12k_pci 0000:05:00.0: 00000000: 62 75 73 3d 70 63 69 2c 76 65 6e 64 6f 72 3d 31 bus=pci,vendor=1 [169547.248638] ath12k_pci 0000:05:00.0: 00000010: 37 63 62 2c 64 65 76 69 63 65 3d 31 31 30 33 2c 7cb,device=1103, [169547.248639] ath12k_pci 0000:05:00.0: 00000020: 73 75 62 73 79 73 74 65 6d 2d 76 65 6e 64 6f 72 subsystem-vendor [169547.248641] ath12k_pci 0000:05:00.0: 00000030: 3d 31 37 63 62 2c 73 75 62 73 79 73 74 65 6d 2d =17cb,subsystem- [169547.248642] ath12k_pci 0000:05:00.0: 00000040: 64 65 76 69 63 65 3d 33 33 37 34 2c 71 6d 69 2d device=3374,qmi- [169547.248643] ath12k_pci 0000:05:00.0: 00000050: 63 68 69 70 2d 69 64 3d 32 2c 71 6d 69 2d 62 6f chip-id=2,qmi-bo [169547.248645] ath12k_pci 0000:05:00.0: 00000060: 61 72 64 2d 69 64 3d 32 36 32 ard-id=262 [169547.248646] ath12k_pci 0000:05:00.0: boot found match for name 'bus=pci,vendor=17cb,device=1103,subsystem-vendor=17cb,subsystem-device=3374,qmi-chip-id=2,qmi-board-id=262' [169547.248647] ath12k_pci 0000:05:00.0: boot found board data for 'bus=pci,vendor=17cb,device=1103,subsystem-vendor=17cb,subsystem-device=3374,qmi-chip-id=2,qmi-board-id=262' [169547.248649] ath12k_pci 0000:05:00.0: using board api 2 Tested-on: WCN7850 hw2.0 PCI WLAN.HMT.1.0-03427-QCAHMTSWPL_V1.0_V2.0_SILICONZ-1.15378.4 Signed-off-by: Wen Gong Signed-off-by: Baochen Qiang Signed-off-by: Kalle Valo Link: https://msgid.link/20231216060140.30611-3-quic_bqiang@quicinc.com --- drivers/net/wireless/ath/ath12k/core.c | 48 ++++++++++++++++++++++---- 1 file changed, 41 insertions(+), 7 deletions(-) diff --git a/drivers/net/wireless/ath/ath12k/core.c b/drivers/net/wireless/ath/ath12k/core.c index b8027f76a02e..672aa174704b 100644 --- a/drivers/net/wireless/ath/ath12k/core.c +++ b/drivers/net/wireless/ath/ath12k/core.c @@ -104,13 +104,13 @@ int ath12k_core_resume(struct ath12k_base *ab) return 0; } -static int ath12k_core_create_board_name(struct ath12k_base *ab, char *name, - size_t name_len) +static int __ath12k_core_create_board_name(struct ath12k_base *ab, char *name, + size_t name_len, bool with_variant) { /* strlen(',variant=') + strlen(ab->qmi.target.bdf_ext) */ char variant[9 + ATH12K_QMI_BDF_EXT_STR_LENGTH] = { 0 }; - if (ab->qmi.target.bdf_ext[0] != '\0') + if (with_variant && ab->qmi.target.bdf_ext[0] != '\0') scnprintf(variant, sizeof(variant), ",variant=%s", ab->qmi.target.bdf_ext); @@ -140,6 +140,18 @@ static int ath12k_core_create_board_name(struct ath12k_base *ab, char *name, return 0; } +static int ath12k_core_create_board_name(struct ath12k_base *ab, char *name, + size_t name_len) +{ + return __ath12k_core_create_board_name(ab, name, name_len, true); +} + +static int ath12k_core_create_fallback_board_name(struct ath12k_base *ab, char *name, + size_t name_len) +{ + return __ath12k_core_create_board_name(ab, name, name_len, false); +} + const struct firmware *ath12k_core_firmware_request(struct ath12k_base *ab, const char *file) { @@ -343,7 +355,7 @@ static int ath12k_core_fetch_board_data_api_n(struct ath12k_base *ab, out: if (!bd->data || !bd->len) { - ath12k_err(ab, + ath12k_dbg(ab, ATH12K_DBG_BOOT, "failed to fetch board data for %s from %s\n", boardname, filepath); ret = -ENODATA; @@ -374,11 +386,14 @@ int ath12k_core_fetch_board_data_api_1(struct ath12k_base *ab, #define BOARD_NAME_SIZE 200 int ath12k_core_fetch_bdf(struct ath12k_base *ab, struct ath12k_board_data *bd) { - char boardname[BOARD_NAME_SIZE]; + char boardname[BOARD_NAME_SIZE], fallback_boardname[BOARD_NAME_SIZE]; + char *filename, filepath[100]; int bd_api; int ret; - ret = ath12k_core_create_board_name(ab, boardname, BOARD_NAME_SIZE); + filename = ATH12K_BOARD_API2_FILE; + + ret = ath12k_core_create_board_name(ab, boardname, sizeof(boardname)); if (ret) { ath12k_err(ab, "failed to create board name: %d", ret); return ret; @@ -389,10 +404,29 @@ int ath12k_core_fetch_bdf(struct ath12k_base *ab, struct ath12k_board_data *bd) if (!ret) goto success; + ret = ath12k_core_create_fallback_board_name(ab, fallback_boardname, + sizeof(fallback_boardname)); + if (ret) { + ath12k_err(ab, "failed to create fallback board name: %d", ret); + return ret; + } + + ret = ath12k_core_fetch_board_data_api_n(ab, bd, fallback_boardname); + if (!ret) + goto success; + bd_api = 1; ret = ath12k_core_fetch_board_data_api_1(ab, bd, ATH12K_DEFAULT_BOARD_FILE); if (ret) { - ath12k_err(ab, "failed to fetch board-2.bin or board.bin from %s\n", + ath12k_core_create_firmware_path(ab, filename, + filepath, sizeof(filepath)); + ath12k_err(ab, "failed to fetch board data for %s from %s\n", + boardname, filepath); + if (memcmp(boardname, fallback_boardname, strlen(boardname))) + ath12k_err(ab, "failed to fetch board data for %s from %s\n", + fallback_boardname, filepath); + + ath12k_err(ab, "failed to fetch board.bin from %s\n", ab->hw_params->fw.dir); return ret; } From 97474e5f54243be13d72cbda50624f0114213c7d Mon Sep 17 00:00:00 2001 From: Wen Gong Date: Sun, 17 Dec 2023 13:29:04 +0200 Subject: [PATCH 14/71] wifi: ath12k: remove unused ATH12K_BD_IE_BOARD_EXT Currently ATH12K_BD_IE_BOARD_EXT is not used, so remove it. Tested-on: WCN7850 hw2.0 PCI WLAN.HMT.1.0-03427-QCAHMTSWPL_V1.0_V2.0_SILICONZ-1.15378.4 Signed-off-by: Wen Gong Signed-off-by: Baochen Qiang Signed-off-by: Kalle Valo Link: https://msgid.link/20231216060140.30611-4-quic_bqiang@quicinc.com --- drivers/net/wireless/ath/ath12k/hw.h | 1 - 1 file changed, 1 deletion(-) diff --git a/drivers/net/wireless/ath/ath12k/hw.h b/drivers/net/wireless/ath/ath12k/hw.h index d2622bfef942..130d99f7e426 100644 --- a/drivers/net/wireless/ath/ath12k/hw.h +++ b/drivers/net/wireless/ath/ath12k/hw.h @@ -245,7 +245,6 @@ enum ath12k_bd_ie_board_type { enum ath12k_bd_ie_type { /* contains sub IEs of enum ath12k_bd_ie_board_type */ ATH12K_BD_IE_BOARD = 0, - ATH12K_BD_IE_BOARD_EXT = 1, }; struct ath12k_hw_regs { From 511207452221a94242664be47c4ceb63d5c6b293 Mon Sep 17 00:00:00 2001 From: Wen Gong Date: Sun, 17 Dec 2023 13:29:04 +0200 Subject: [PATCH 15/71] wifi: ath12k: add support to search regdb data in board-2.bin for WCN7850 Currently ath12k only downloads the same regdb.bin file for all WCN7850 chips, actually ath12k needs to distinguish all different WCN7850 chips. This is to re-use the string type which includes bus, chip id, board id, vendor, device, subsystem-vendor, subsystem-device and variant for WCN7850 to distinguish different regdb in board-2.bin. ath12k will first load board-2.bin and search in it for the regdb data with the above parameters. If matched with one regdb data, download it to firmware. And if not, download regdb.bin instead. Add enum value ATH12K_BD_IE_REGDB and enum type ath12k_bd_ie_regdb_type to distinguish regdb data and board data since they are in the same file board-2.bin. Test log: [ 3833.091948] ath12k_pci 0000:05:00.0: boot using board name 'bus=pci,vendor=17cb,device=1103,subsystem-vendor=17cb,subsystem-device=3374,qmi-chip-id=2,qmi-board-id=262' [ 3833.092072] ath12k_pci 0000:05:00.0: boot firmware request ath12k/WCN7850/hw2.0/board-2.bin size 205316 [ 3833.092079] ath12k_pci 0000:05:00.0: board name [ 3833.092083] ath12k_pci 0000:05:00.0: 00000000: 62 75 73 3d 70 63 69 2c 71 6d 69 2d 63 68 69 70 bus=pci,qmi-chip [ 3833.092088] ath12k_pci 0000:05:00.0: 00000010: 2d 69 64 3d 31 -id=1 [ 3833.092091] ath12k_pci 0000:05:00.0: board name [ 3833.092095] ath12k_pci 0000:05:00.0: 00000000: 62 75 73 3d 70 63 69 2c 71 6d 69 2d 63 68 69 70 bus=pci,qmi-chip [ 3833.092099] ath12k_pci 0000:05:00.0: 00000010: 2d 69 64 3d 32 -id=2 [ 3833.092102] ath12k_pci 0000:05:00.0: board name [ 3833.092105] ath12k_pci 0000:05:00.0: 00000000: 62 75 73 3d 70 63 69 2c 71 6d 69 2d 63 68 69 70 bus=pci,qmi-chip [ 3833.092109] ath12k_pci 0000:05:00.0: 00000010: 2d 69 64 3d 33 -id=3 [ 3833.092112] ath12k_pci 0000:05:00.0: board name [ 3833.092116] ath12k_pci 0000:05:00.0: 00000000: 62 75 73 3d 70 63 69 2c 76 65 6e 64 6f 72 3d 31 bus=pci,vendor=1 [ 3833.092119] ath12k_pci 0000:05:00.0: 00000010: 37 63 62 2c 64 65 76 69 63 65 3d 31 31 30 33 2c 7cb,device=1103, [ 3833.092123] ath12k_pci 0000:05:00.0: 00000020: 73 75 62 73 79 73 74 65 6d 2d 76 65 6e 64 6f 72 subsystem-vendor [ 3833.092126] ath12k_pci 0000:05:00.0: 00000030: 3d 31 37 63 62 2c 73 75 62 73 79 73 74 65 6d 2d =17cb,subsystem- [ 3833.092130] ath12k_pci 0000:05:00.0: 00000040: 64 65 76 69 63 65 3d 33 33 37 34 2c 71 6d 69 2d device=3374,qmi- [ 3833.092133] ath12k_pci 0000:05:00.0: 00000050: 63 68 69 70 2d 69 64 3d 32 2c 71 6d 69 2d 62 6f chip-id=2,qmi-bo [ 3833.092137] ath12k_pci 0000:05:00.0: 00000060: 61 72 64 2d 69 64 3d 32 36 36 2c 76 61 72 69 61 ard-id=266,varia [ 3833.092140] ath12k_pci 0000:05:00.0: 00000070: 6e 74 3d 48 50 5f 47 38 5f 4c 61 6e 63 69 61 31 nt=HP_G8_Lancia1 [ 3833.092144] ath12k_pci 0000:05:00.0: 00000080: 35 5 [ 3833.092147] ath12k_pci 0000:05:00.0: board name [ 3833.092150] ath12k_pci 0000:05:00.0: 00000000: 62 75 73 3d 70 63 69 2c 76 65 6e 64 6f 72 3d 31 bus=pci,vendor=1 [ 3833.092154] ath12k_pci 0000:05:00.0: 00000010: 37 63 62 2c 64 65 76 69 63 65 3d 31 31 30 33 2c 7cb,device=1103, [ 3833.092157] ath12k_pci 0000:05:00.0: 00000020: 73 75 62 73 79 73 74 65 6d 2d 76 65 6e 64 6f 72 subsystem-vendor [ 3833.092161] ath12k_pci 0000:05:00.0: 00000030: 3d 31 37 63 62 2c 73 75 62 73 79 73 74 65 6d 2d =17cb,subsystem- [ 3833.092165] ath12k_pci 0000:05:00.0: 00000040: 64 65 76 69 63 65 3d 33 33 37 34 2c 71 6d 69 2d device=3374,qmi- [ 3833.092168] ath12k_pci 0000:05:00.0: 00000050: 63 68 69 70 2d 69 64 3d 32 2c 71 6d 69 2d 62 6f chip-id=2,qmi-bo [ 3833.092172] ath12k_pci 0000:05:00.0: 00000060: 61 72 64 2d 69 64 3d 32 36 36 ard-id=266 [ 3833.092206] ath12k_pci 0000:05:00.0: board name [ 3833.092209] ath12k_pci 0000:05:00.0: 00000000: 62 75 73 3d 70 63 69 2c 76 65 6e 64 6f 72 3d 31 bus=pci,vendor=1 [ 3833.092213] ath12k_pci 0000:05:00.0: 00000010: 37 63 62 2c 64 65 76 69 63 65 3d 31 31 30 33 2c 7cb,device=1103, [ 3833.092216] ath12k_pci 0000:05:00.0: 00000020: 73 75 62 73 79 73 74 65 6d 2d 76 65 6e 64 6f 72 subsystem-vendor [ 3833.092220] ath12k_pci 0000:05:00.0: 00000030: 3d 31 37 63 62 2c 73 75 62 73 79 73 74 65 6d 2d =17cb,subsystem- [ 3833.092223] ath12k_pci 0000:05:00.0: 00000040: 64 65 76 69 63 65 3d 33 33 37 34 2c 71 6d 69 2d device=3374,qmi- [ 3833.092227] ath12k_pci 0000:05:00.0: 00000050: 63 68 69 70 2d 69 64 3d 32 2c 71 6d 69 2d 62 6f chip-id=2,qmi-bo [ 3833.092230] ath12k_pci 0000:05:00.0: 00000060: 61 72 64 2d 69 64 3d 32 36 32 ard-id=262 [ 3833.092234] ath12k_pci 0000:05:00.0: boot found match regdb data for name 'bus=pci,vendor=17cb,device=1103,subsystem-vendor=17cb,subsystem-device=3374,qmi-chip-id=2,qmi-board-id=262' [ 3833.092238] ath12k_pci 0000:05:00.0: board name [ 3833.092241] ath12k_pci 0000:05:00.0: 00000000: 62 75 73 3d 70 63 69 2c 71 6d 69 2d 63 68 69 70 bus=pci,qmi-chip [ 3833.092245] ath12k_pci 0000:05:00.0: 00000010: 2d 69 64 3d 31 31 -id=11 [ 3833.092248] ath12k_pci 0000:05:00.0: board name [ 3833.092251] ath12k_pci 0000:05:00.0: 00000000: 62 75 73 3d 70 63 69 2c 71 6d 69 2d 63 68 69 70 bus=pci,qmi-chip [ 3833.092255] ath12k_pci 0000:05:00.0: 00000010: 2d 69 64 3d 32 32 -id=22 [ 3833.092258] ath12k_pci 0000:05:00.0: board name [ 3833.092261] ath12k_pci 0000:05:00.0: 00000000: 62 75 73 3d 70 63 69 2c 71 6d 69 2d 63 68 69 70 bus=pci,qmi-chip [ 3833.092265] ath12k_pci 0000:05:00.0: 00000010: 2d 69 64 3d 33 33 -id=33 [ 3833.092268] ath12k_pci 0000:05:00.0: boot found regdb data for 'bus=pci,vendor=17cb,device=1103,subsystem-vendor=17cb,subsystem-device=3374,qmi-chip-id=2,qmi-board-id=262' [ 3833.092272] ath12k_pci 0000:05:00.0: fetched regdb Tested-on: WCN7850 hw2.0 PCI WLAN.HMT.1.0-03427-QCAHMTSWPL_V1.0_V2.0_SILICONZ-1.15378.4 Signed-off-by: Wen Gong Signed-off-by: Baochen Qiang Signed-off-by: Kalle Valo Link: https://msgid.link/20231216060140.30611-5-quic_bqiang@quicinc.com --- drivers/net/wireless/ath/ath12k/core.c | 96 +++++++++++++++++++------- drivers/net/wireless/ath/ath12k/core.h | 1 + drivers/net/wireless/ath/ath12k/hw.h | 19 +++++ drivers/net/wireless/ath/ath12k/qmi.c | 3 +- 4 files changed, 92 insertions(+), 27 deletions(-) diff --git a/drivers/net/wireless/ath/ath12k/core.c b/drivers/net/wireless/ath/ath12k/core.c index 672aa174704b..80fce8099bdf 100644 --- a/drivers/net/wireless/ath/ath12k/core.c +++ b/drivers/net/wireless/ath/ath12k/core.c @@ -186,7 +186,9 @@ static int ath12k_core_parse_bd_ie_board(struct ath12k_base *ab, struct ath12k_board_data *bd, const void *buf, size_t buf_len, const char *boardname, - int bd_ie_type) + int ie_id, + int name_id, + int data_id) { const struct ath12k_fw_ie *hdr; bool name_match_found; @@ -196,7 +198,7 @@ static int ath12k_core_parse_bd_ie_board(struct ath12k_base *ab, name_match_found = false; - /* go through ATH12K_BD_IE_BOARD_ elements */ + /* go through ATH12K_BD_IE_BOARD_/ATH12K_BD_IE_REGDB_ elements */ while (buf_len > sizeof(struct ath12k_fw_ie)) { hdr = buf; board_ie_id = le32_to_cpu(hdr->id); @@ -207,48 +209,50 @@ static int ath12k_core_parse_bd_ie_board(struct ath12k_base *ab, buf += sizeof(*hdr); if (buf_len < ALIGN(board_ie_len, 4)) { - ath12k_err(ab, "invalid ATH12K_BD_IE_BOARD length: %zu < %zu\n", + ath12k_err(ab, "invalid %s length: %zu < %zu\n", + ath12k_bd_ie_type_str(ie_id), buf_len, ALIGN(board_ie_len, 4)); ret = -EINVAL; goto out; } - switch (board_ie_id) { - case ATH12K_BD_IE_BOARD_NAME: + if (board_ie_id == name_id) { ath12k_dbg_dump(ab, ATH12K_DBG_BOOT, "board name", "", board_ie_data, board_ie_len); if (board_ie_len != strlen(boardname)) - break; + goto next; ret = memcmp(board_ie_data, boardname, strlen(boardname)); if (ret) - break; + goto next; name_match_found = true; ath12k_dbg(ab, ATH12K_DBG_BOOT, - "boot found match for name '%s'", + "boot found match %s for name '%s'", + ath12k_bd_ie_type_str(ie_id), boardname); - break; - case ATH12K_BD_IE_BOARD_DATA: + } else if (board_ie_id == data_id) { if (!name_match_found) /* no match found */ - break; + goto next; ath12k_dbg(ab, ATH12K_DBG_BOOT, - "boot found board data for '%s'", boardname); + "boot found %s for '%s'", + ath12k_bd_ie_type_str(ie_id), + boardname); bd->data = board_ie_data; bd->len = board_ie_len; ret = 0; goto out; - default: - ath12k_warn(ab, "unknown ATH12K_BD_IE_BOARD found: %d\n", + } else { + ath12k_warn(ab, "unknown %s id found: %d\n", + ath12k_bd_ie_type_str(ie_id), board_ie_id); - break; } - +next: /* jump over the padding */ board_ie_len = ALIGN(board_ie_len, 4); @@ -265,7 +269,10 @@ static int ath12k_core_parse_bd_ie_board(struct ath12k_base *ab, static int ath12k_core_fetch_board_data_api_n(struct ath12k_base *ab, struct ath12k_board_data *bd, - const char *boardname) + const char *boardname, + int ie_id_match, + int name_id, + int data_id) { size_t len, magic_len; const u8 *data; @@ -330,22 +337,23 @@ static int ath12k_core_fetch_board_data_api_n(struct ath12k_base *ab, goto err; } - switch (ie_id) { - case ATH12K_BD_IE_BOARD: + if (ie_id == ie_id_match) { ret = ath12k_core_parse_bd_ie_board(ab, bd, data, ie_len, boardname, - ATH12K_BD_IE_BOARD); + ie_id_match, + name_id, + data_id); if (ret == -ENOENT) /* no match found, continue */ - break; + goto next; else if (ret) /* there was an error, bail out */ goto err; /* either found or error, so stop searching */ goto out; } - +next: /* jump over the padding */ ie_len = ALIGN(ie_len, 4); @@ -356,7 +364,8 @@ static int ath12k_core_fetch_board_data_api_n(struct ath12k_base *ab, out: if (!bd->data || !bd->len) { ath12k_dbg(ab, ATH12K_DBG_BOOT, - "failed to fetch board data for %s from %s\n", + "failed to fetch %s for %s from %s\n", + ath12k_bd_ie_type_str(ie_id_match), boardname, filepath); ret = -ENODATA; goto err; @@ -400,7 +409,10 @@ int ath12k_core_fetch_bdf(struct ath12k_base *ab, struct ath12k_board_data *bd) } bd_api = 2; - ret = ath12k_core_fetch_board_data_api_n(ab, bd, boardname); + ret = ath12k_core_fetch_board_data_api_n(ab, bd, boardname, + ATH12K_BD_IE_BOARD, + ATH12K_BD_IE_BOARD_NAME, + ATH12K_BD_IE_BOARD_DATA); if (!ret) goto success; @@ -411,7 +423,10 @@ int ath12k_core_fetch_bdf(struct ath12k_base *ab, struct ath12k_board_data *bd) return ret; } - ret = ath12k_core_fetch_board_data_api_n(ab, bd, fallback_boardname); + ret = ath12k_core_fetch_board_data_api_n(ab, bd, fallback_boardname, + ATH12K_BD_IE_BOARD, + ATH12K_BD_IE_BOARD_NAME, + ATH12K_BD_IE_BOARD_DATA); if (!ret) goto success; @@ -436,6 +451,37 @@ int ath12k_core_fetch_bdf(struct ath12k_base *ab, struct ath12k_board_data *bd) return 0; } +int ath12k_core_fetch_regdb(struct ath12k_base *ab, struct ath12k_board_data *bd) +{ + char boardname[BOARD_NAME_SIZE]; + int ret; + + ret = ath12k_core_create_board_name(ab, boardname, BOARD_NAME_SIZE); + if (ret) { + ath12k_dbg(ab, ATH12K_DBG_BOOT, + "failed to create board name for regdb: %d", ret); + goto exit; + } + + ret = ath12k_core_fetch_board_data_api_n(ab, bd, boardname, + ATH12K_BD_IE_REGDB, + ATH12K_BD_IE_REGDB_NAME, + ATH12K_BD_IE_REGDB_DATA); + if (!ret) + goto exit; + + ret = ath12k_core_fetch_board_data_api_1(ab, bd, ATH12K_REGDB_FILE_NAME); + if (ret) + ath12k_dbg(ab, ATH12K_DBG_BOOT, "failed to fetch %s from %s\n", + ATH12K_REGDB_FILE_NAME, ab->hw_params->fw.dir); + +exit: + if (!ret) + ath12k_dbg(ab, ATH12K_DBG_BOOT, "fetched regdb\n"); + + return ret; +} + static void ath12k_core_stop(struct ath12k_base *ab) { if (!test_bit(ATH12K_FLAG_CRASH_FLUSH, &ab->dev_flags)) diff --git a/drivers/net/wireless/ath/ath12k/core.h b/drivers/net/wireless/ath/ath12k/core.h index 385fda03e913..ba0a30f1ea29 100644 --- a/drivers/net/wireless/ath/ath12k/core.h +++ b/drivers/net/wireless/ath/ath12k/core.h @@ -823,6 +823,7 @@ int ath12k_core_fetch_board_data_api_1(struct ath12k_base *ab, int ath12k_core_fetch_bdf(struct ath12k_base *ath12k, struct ath12k_board_data *bd); void ath12k_core_free_bdf(struct ath12k_base *ab, struct ath12k_board_data *bd); +int ath12k_core_fetch_regdb(struct ath12k_base *ab, struct ath12k_board_data *bd); int ath12k_core_check_dt(struct ath12k_base *ath12k); int ath12k_core_check_smbios(struct ath12k_base *ab); void ath12k_core_halt(struct ath12k *ar); diff --git a/drivers/net/wireless/ath/ath12k/hw.h b/drivers/net/wireless/ath/ath12k/hw.h index 130d99f7e426..fa8230def22b 100644 --- a/drivers/net/wireless/ath/ath12k/hw.h +++ b/drivers/net/wireless/ath/ath12k/hw.h @@ -242,9 +242,16 @@ enum ath12k_bd_ie_board_type { ATH12K_BD_IE_BOARD_DATA = 1, }; +enum ath12k_bd_ie_regdb_type { + ATH12K_BD_IE_REGDB_NAME = 0, + ATH12K_BD_IE_REGDB_DATA = 1, +}; + enum ath12k_bd_ie_type { /* contains sub IEs of enum ath12k_bd_ie_board_type */ ATH12K_BD_IE_BOARD = 0, + /* contains sub IEs of enum ath12k_bd_ie_regdb_type */ + ATH12K_BD_IE_REGDB = 1, }; struct ath12k_hw_regs { @@ -314,6 +321,18 @@ struct ath12k_hw_regs { u32 hal_reo_status_ring_base; }; +static inline const char *ath12k_bd_ie_type_str(enum ath12k_bd_ie_type type) +{ + switch (type) { + case ATH12K_BD_IE_BOARD: + return "board data"; + case ATH12K_BD_IE_REGDB: + return "regdb data"; + } + + return "unknown"; +} + int ath12k_hw_init(struct ath12k_base *ab); #endif diff --git a/drivers/net/wireless/ath/ath12k/qmi.c b/drivers/net/wireless/ath/ath12k/qmi.c index 77a132f6bbd1..f29291064e20 100644 --- a/drivers/net/wireless/ath/ath12k/qmi.c +++ b/drivers/net/wireless/ath/ath12k/qmi.c @@ -2423,8 +2423,7 @@ static int ath12k_qmi_load_bdf_qmi(struct ath12k_base *ab, break; case ATH12K_QMI_BDF_TYPE_REGDB: - ret = ath12k_core_fetch_board_data_api_1(ab, &bd, - ATH12K_REGDB_FILE_NAME); + ret = ath12k_core_fetch_regdb(ab, &bd); if (ret) { ath12k_warn(ab, "qmi failed to load regdb bin:\n"); goto out; From 52f8c45fa36df0754b4562b7b535be8475304ebe Mon Sep 17 00:00:00 2001 From: Baochen Qiang Date: Sun, 17 Dec 2023 13:29:04 +0200 Subject: [PATCH 16/71] wifi: ath12k: support default regdb while searching board-2.bin for WCN7850 Sometimes board-2.bin does not have the regdb data which matches the parameters such as vendor, device, subsystem-vendor, subsystem-device etc. Add default regdb data with only 'bus=%s' into board-2.bin for WCN7850, then ath12k uses 'bus=pci' to search regdb data in board-2.bin for WCN7850. [ 46.114895] ath12k_pci 0000:03:00.0: boot using board name 'bus=pci,vendor=17cb,device=1107,subsystem-vendor=17cb,subsystem-device=3378,qmi-chip-id=2,qmi-board-id=260' [ 46.118167] ath12k_pci 0000:03:00.0: boot firmware request ath12k/WCN7850/hw2.0/board-2.bin size 380280 [ 46.118173] ath12k_pci 0000:03:00.0: board name [ 46.118176] ath12k_pci 0000:03:00.0: 00000000: 62 75 73 3d 70 63 69 bus=pci [ 46.118179] ath12k_pci 0000:03:00.0: failed to fetch regdb data for bus=pci,vendor=17cb,device=1107,subsystem-vendor=17cb,subsystem-device=3378,qmi-chip-id=2,qmi-board-id=260 from ath12k/WCN7850/hw2.0/board-2.bin [ 46.118239] ath12k_pci 0000:03:00.0: boot using board name 'bus=pci' [ 46.119842] ath12k_pci 0000:03:00.0: boot firmware request ath12k/WCN7850/hw2.0/board-2.bin size 380280 [ 46.119847] ath12k_pci 0000:03:00.0: board name [ 46.119849] ath12k_pci 0000:03:00.0: 00000000: 62 75 73 3d 70 63 69 bus=pci [ 46.119852] ath12k_pci 0000:03:00.0: boot found match regdb data for name 'bus=pci' [ 46.119855] ath12k_pci 0000:03:00.0: boot found regdb data for 'bus=pci' [ 46.119857] ath12k_pci 0000:03:00.0: fetched regdb Tested-on: WCN7850 hw2.0 PCI WLAN.HMT.1.0-03427-QCAHMTSWPL_V1.0_V2.0_SILICONZ-1.15378.4 Signed-off-by: Baochen Qiang Signed-off-by: Kalle Valo Link: https://msgid.link/20231216060140.30611-6-quic_bqiang@quicinc.com --- drivers/net/wireless/ath/ath12k/core.c | 53 +++++++++++++++++++------- 1 file changed, 40 insertions(+), 13 deletions(-) diff --git a/drivers/net/wireless/ath/ath12k/core.c b/drivers/net/wireless/ath/ath12k/core.c index 80fce8099bdf..d73e2d33a41e 100644 --- a/drivers/net/wireless/ath/ath12k/core.c +++ b/drivers/net/wireless/ath/ath12k/core.c @@ -105,7 +105,8 @@ int ath12k_core_resume(struct ath12k_base *ab) } static int __ath12k_core_create_board_name(struct ath12k_base *ab, char *name, - size_t name_len, bool with_variant) + size_t name_len, bool with_variant, + bool bus_type_mode) { /* strlen(',variant=') + strlen(ab->qmi.target.bdf_ext) */ char variant[9 + ATH12K_QMI_BDF_EXT_STR_LENGTH] = { 0 }; @@ -116,15 +117,20 @@ static int __ath12k_core_create_board_name(struct ath12k_base *ab, char *name, switch (ab->id.bdf_search) { case ATH12K_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", - ath12k_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); + if (bus_type_mode) + scnprintf(name, name_len, + "bus=%s", + ath12k_bus_str(ab->hif.bus)); + else + 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", + ath12k_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, @@ -143,13 +149,19 @@ static int __ath12k_core_create_board_name(struct ath12k_base *ab, char *name, static int ath12k_core_create_board_name(struct ath12k_base *ab, char *name, size_t name_len) { - return __ath12k_core_create_board_name(ab, name, name_len, true); + return __ath12k_core_create_board_name(ab, name, name_len, true, false); } static int ath12k_core_create_fallback_board_name(struct ath12k_base *ab, char *name, size_t name_len) { - return __ath12k_core_create_board_name(ab, name, name_len, false); + return __ath12k_core_create_board_name(ab, name, name_len, false, false); +} + +static int ath12k_core_create_bus_type_board_name(struct ath12k_base *ab, char *name, + size_t name_len) +{ + return __ath12k_core_create_board_name(ab, name, name_len, false, true); } const struct firmware *ath12k_core_firmware_request(struct ath12k_base *ab, @@ -453,7 +465,7 @@ int ath12k_core_fetch_bdf(struct ath12k_base *ab, struct ath12k_board_data *bd) int ath12k_core_fetch_regdb(struct ath12k_base *ab, struct ath12k_board_data *bd) { - char boardname[BOARD_NAME_SIZE]; + char boardname[BOARD_NAME_SIZE], default_boardname[BOARD_NAME_SIZE]; int ret; ret = ath12k_core_create_board_name(ab, boardname, BOARD_NAME_SIZE); @@ -470,6 +482,21 @@ int ath12k_core_fetch_regdb(struct ath12k_base *ab, struct ath12k_board_data *bd if (!ret) goto exit; + ret = ath12k_core_create_bus_type_board_name(ab, default_boardname, + BOARD_NAME_SIZE); + if (ret) { + ath12k_dbg(ab, ATH12K_DBG_BOOT, + "failed to create default board name for regdb: %d", ret); + goto exit; + } + + ret = ath12k_core_fetch_board_data_api_n(ab, bd, default_boardname, + ATH12K_BD_IE_REGDB, + ATH12K_BD_IE_REGDB_NAME, + ATH12K_BD_IE_REGDB_DATA); + if (!ret) + goto exit; + ret = ath12k_core_fetch_board_data_api_1(ab, bd, ATH12K_REGDB_FILE_NAME); if (ret) ath12k_dbg(ab, ATH12K_DBG_BOOT, "failed to fetch %s from %s\n", From e7ab40b733094dfc50dad58bbce81f544af1d8cc Mon Sep 17 00:00:00 2001 From: Jeff Johnson Date: Sun, 17 Dec 2023 09:26:46 -0800 Subject: [PATCH 17/71] wifi: ath12k: Make QMI message rules const Commit ff6d365898d4 ("soc: qcom: qmi: use const for struct qmi_elem_info") allows QMI message encoding/decoding rules to be const, so do that for ath12k. Compile tested only. Signed-off-by: Jeff Johnson Signed-off-by: Kalle Valo Link: https://msgid.link/20231217-ath12k-qmi_elem_info-const-v1-1-7ebb0de0a2b6@quicinc.com --- drivers/net/wireless/ath/ath12k/qmi.c | 64 +++++++++++++-------------- 1 file changed, 32 insertions(+), 32 deletions(-) diff --git a/drivers/net/wireless/ath/ath12k/qmi.c b/drivers/net/wireless/ath/ath12k/qmi.c index f29291064e20..536856234f3b 100644 --- a/drivers/net/wireless/ath/ath12k/qmi.c +++ b/drivers/net/wireless/ath/ath12k/qmi.c @@ -17,7 +17,7 @@ #define PLATFORM_CAP_PCIE_GLOBAL_RESET 0x08 #define ATH12K_QMI_MAX_CHUNK_SIZE 2097152 -static struct qmi_elem_info wlfw_host_mlo_chip_info_s_v01_ei[] = { +static const struct qmi_elem_info wlfw_host_mlo_chip_info_s_v01_ei[] = { { .data_type = QMI_UNSIGNED_1_BYTE, .elem_len = 1, @@ -61,7 +61,7 @@ static struct qmi_elem_info wlfw_host_mlo_chip_info_s_v01_ei[] = { }, }; -static struct qmi_elem_info qmi_wlanfw_host_cap_req_msg_v01_ei[] = { +static const struct qmi_elem_info qmi_wlanfw_host_cap_req_msg_v01_ei[] = { { .data_type = QMI_OPT_FLAG, .elem_len = 1, @@ -511,7 +511,7 @@ static struct qmi_elem_info qmi_wlanfw_host_cap_req_msg_v01_ei[] = { }, }; -static struct qmi_elem_info qmi_wlanfw_host_cap_resp_msg_v01_ei[] = { +static const struct qmi_elem_info qmi_wlanfw_host_cap_resp_msg_v01_ei[] = { { .data_type = QMI_STRUCT, .elem_len = 1, @@ -528,7 +528,7 @@ static struct qmi_elem_info qmi_wlanfw_host_cap_resp_msg_v01_ei[] = { }, }; -static struct qmi_elem_info qmi_wlanfw_ind_register_req_msg_v01_ei[] = { +static const struct qmi_elem_info qmi_wlanfw_ind_register_req_msg_v01_ei[] = { { .data_type = QMI_OPT_FLAG, .elem_len = 1, @@ -753,7 +753,7 @@ static struct qmi_elem_info qmi_wlanfw_ind_register_req_msg_v01_ei[] = { }, }; -static struct qmi_elem_info qmi_wlanfw_ind_register_resp_msg_v01_ei[] = { +static const struct qmi_elem_info qmi_wlanfw_ind_register_resp_msg_v01_ei[] = { { .data_type = QMI_STRUCT, .elem_len = 1, @@ -789,7 +789,7 @@ static struct qmi_elem_info qmi_wlanfw_ind_register_resp_msg_v01_ei[] = { }, }; -static struct qmi_elem_info qmi_wlanfw_mem_cfg_s_v01_ei[] = { +static const struct qmi_elem_info qmi_wlanfw_mem_cfg_s_v01_ei[] = { { .data_type = QMI_UNSIGNED_8_BYTE, .elem_len = 1, @@ -821,7 +821,7 @@ static struct qmi_elem_info qmi_wlanfw_mem_cfg_s_v01_ei[] = { }, }; -static struct qmi_elem_info qmi_wlanfw_mem_seg_s_v01_ei[] = { +static const struct qmi_elem_info qmi_wlanfw_mem_seg_s_v01_ei[] = { { .data_type = QMI_UNSIGNED_4_BYTE, .elem_len = 1, @@ -863,7 +863,7 @@ static struct qmi_elem_info qmi_wlanfw_mem_seg_s_v01_ei[] = { }, }; -static struct qmi_elem_info qmi_wlanfw_request_mem_ind_msg_v01_ei[] = { +static const struct qmi_elem_info qmi_wlanfw_request_mem_ind_msg_v01_ei[] = { { .data_type = QMI_DATA_LEN, .elem_len = 1, @@ -890,7 +890,7 @@ static struct qmi_elem_info qmi_wlanfw_request_mem_ind_msg_v01_ei[] = { }, }; -static struct qmi_elem_info qmi_wlanfw_mem_seg_resp_s_v01_ei[] = { +static const struct qmi_elem_info qmi_wlanfw_mem_seg_resp_s_v01_ei[] = { { .data_type = QMI_UNSIGNED_8_BYTE, .elem_len = 1, @@ -930,7 +930,7 @@ static struct qmi_elem_info qmi_wlanfw_mem_seg_resp_s_v01_ei[] = { }, }; -static struct qmi_elem_info qmi_wlanfw_respond_mem_req_msg_v01_ei[] = { +static const struct qmi_elem_info qmi_wlanfw_respond_mem_req_msg_v01_ei[] = { { .data_type = QMI_DATA_LEN, .elem_len = 1, @@ -957,7 +957,7 @@ static struct qmi_elem_info qmi_wlanfw_respond_mem_req_msg_v01_ei[] = { }, }; -static struct qmi_elem_info qmi_wlanfw_respond_mem_resp_msg_v01_ei[] = { +static const struct qmi_elem_info qmi_wlanfw_respond_mem_resp_msg_v01_ei[] = { { .data_type = QMI_STRUCT, .elem_len = 1, @@ -975,7 +975,7 @@ static struct qmi_elem_info qmi_wlanfw_respond_mem_resp_msg_v01_ei[] = { }, }; -static struct qmi_elem_info qmi_wlanfw_cap_req_msg_v01_ei[] = { +static const struct qmi_elem_info qmi_wlanfw_cap_req_msg_v01_ei[] = { { .data_type = QMI_EOTI, .array_type = NO_ARRAY, @@ -983,7 +983,7 @@ static struct qmi_elem_info qmi_wlanfw_cap_req_msg_v01_ei[] = { }, }; -static struct qmi_elem_info qmi_wlanfw_rf_chip_info_s_v01_ei[] = { +static const struct qmi_elem_info qmi_wlanfw_rf_chip_info_s_v01_ei[] = { { .data_type = QMI_UNSIGNED_4_BYTE, .elem_len = 1, @@ -1009,7 +1009,7 @@ static struct qmi_elem_info qmi_wlanfw_rf_chip_info_s_v01_ei[] = { }, }; -static struct qmi_elem_info qmi_wlanfw_rf_board_info_s_v01_ei[] = { +static const struct qmi_elem_info qmi_wlanfw_rf_board_info_s_v01_ei[] = { { .data_type = QMI_UNSIGNED_4_BYTE, .elem_len = 1, @@ -1026,7 +1026,7 @@ static struct qmi_elem_info qmi_wlanfw_rf_board_info_s_v01_ei[] = { }, }; -static struct qmi_elem_info qmi_wlanfw_soc_info_s_v01_ei[] = { +static const struct qmi_elem_info qmi_wlanfw_soc_info_s_v01_ei[] = { { .data_type = QMI_UNSIGNED_4_BYTE, .elem_len = 1, @@ -1042,7 +1042,7 @@ static struct qmi_elem_info qmi_wlanfw_soc_info_s_v01_ei[] = { }, }; -static struct qmi_elem_info qmi_wlanfw_dev_mem_info_s_v01_ei[] = { +static const struct qmi_elem_info qmi_wlanfw_dev_mem_info_s_v01_ei[] = { { .data_type = QMI_UNSIGNED_8_BYTE, .elem_len = 1, @@ -1068,7 +1068,7 @@ static struct qmi_elem_info qmi_wlanfw_dev_mem_info_s_v01_ei[] = { }, }; -static struct qmi_elem_info qmi_wlanfw_fw_version_info_s_v01_ei[] = { +static const struct qmi_elem_info qmi_wlanfw_fw_version_info_s_v01_ei[] = { { .data_type = QMI_UNSIGNED_4_BYTE, .elem_len = 1, @@ -1094,7 +1094,7 @@ static struct qmi_elem_info qmi_wlanfw_fw_version_info_s_v01_ei[] = { }, }; -static struct qmi_elem_info qmi_wlanfw_cap_resp_msg_v01_ei[] = { +static const struct qmi_elem_info qmi_wlanfw_cap_resp_msg_v01_ei[] = { { .data_type = QMI_STRUCT, .elem_len = 1, @@ -1348,7 +1348,7 @@ static struct qmi_elem_info qmi_wlanfw_cap_resp_msg_v01_ei[] = { }, }; -static struct qmi_elem_info qmi_wlanfw_bdf_download_req_msg_v01_ei[] = { +static const struct qmi_elem_info qmi_wlanfw_bdf_download_req_msg_v01_ei[] = { { .data_type = QMI_UNSIGNED_1_BYTE, .elem_len = 1, @@ -1483,7 +1483,7 @@ static struct qmi_elem_info qmi_wlanfw_bdf_download_req_msg_v01_ei[] = { }, }; -static struct qmi_elem_info qmi_wlanfw_bdf_download_resp_msg_v01_ei[] = { +static const struct qmi_elem_info qmi_wlanfw_bdf_download_resp_msg_v01_ei[] = { { .data_type = QMI_STRUCT, .elem_len = 1, @@ -1501,7 +1501,7 @@ static struct qmi_elem_info qmi_wlanfw_bdf_download_resp_msg_v01_ei[] = { }, }; -static struct qmi_elem_info qmi_wlanfw_m3_info_req_msg_v01_ei[] = { +static const struct qmi_elem_info qmi_wlanfw_m3_info_req_msg_v01_ei[] = { { .data_type = QMI_UNSIGNED_8_BYTE, .elem_len = 1, @@ -1525,7 +1525,7 @@ static struct qmi_elem_info qmi_wlanfw_m3_info_req_msg_v01_ei[] = { }, }; -static struct qmi_elem_info qmi_wlanfw_m3_info_resp_msg_v01_ei[] = { +static const struct qmi_elem_info qmi_wlanfw_m3_info_resp_msg_v01_ei[] = { { .data_type = QMI_STRUCT, .elem_len = 1, @@ -1542,7 +1542,7 @@ static struct qmi_elem_info qmi_wlanfw_m3_info_resp_msg_v01_ei[] = { }, }; -static struct qmi_elem_info qmi_wlanfw_ce_tgt_pipe_cfg_s_v01_ei[] = { +static const struct qmi_elem_info qmi_wlanfw_ce_tgt_pipe_cfg_s_v01_ei[] = { { .data_type = QMI_UNSIGNED_4_BYTE, .elem_len = 1, @@ -1595,7 +1595,7 @@ static struct qmi_elem_info qmi_wlanfw_ce_tgt_pipe_cfg_s_v01_ei[] = { }, }; -static struct qmi_elem_info qmi_wlanfw_ce_svc_pipe_cfg_s_v01_ei[] = { +static const struct qmi_elem_info qmi_wlanfw_ce_svc_pipe_cfg_s_v01_ei[] = { { .data_type = QMI_UNSIGNED_4_BYTE, .elem_len = 1, @@ -1630,7 +1630,7 @@ static struct qmi_elem_info qmi_wlanfw_ce_svc_pipe_cfg_s_v01_ei[] = { }, }; -static struct qmi_elem_info qmi_wlanfw_shadow_reg_cfg_s_v01_ei[] = { +static const struct qmi_elem_info qmi_wlanfw_shadow_reg_cfg_s_v01_ei[] = { { .data_type = QMI_UNSIGNED_2_BYTE, .elem_len = 1, @@ -1654,7 +1654,7 @@ static struct qmi_elem_info qmi_wlanfw_shadow_reg_cfg_s_v01_ei[] = { }, }; -static struct qmi_elem_info qmi_wlanfw_shadow_reg_v3_cfg_s_v01_ei[] = { +static const struct qmi_elem_info qmi_wlanfw_shadow_reg_v3_cfg_s_v01_ei[] = { { .data_type = QMI_UNSIGNED_4_BYTE, .elem_len = 1, @@ -1671,7 +1671,7 @@ static struct qmi_elem_info qmi_wlanfw_shadow_reg_v3_cfg_s_v01_ei[] = { }, }; -static struct qmi_elem_info qmi_wlanfw_wlan_mode_req_msg_v01_ei[] = { +static const struct qmi_elem_info qmi_wlanfw_wlan_mode_req_msg_v01_ei[] = { { .data_type = QMI_UNSIGNED_4_BYTE, .elem_len = 1, @@ -1706,7 +1706,7 @@ static struct qmi_elem_info qmi_wlanfw_wlan_mode_req_msg_v01_ei[] = { }, }; -static struct qmi_elem_info qmi_wlanfw_wlan_mode_resp_msg_v01_ei[] = { +static const struct qmi_elem_info qmi_wlanfw_wlan_mode_resp_msg_v01_ei[] = { { .data_type = QMI_STRUCT, .elem_len = 1, @@ -1724,7 +1724,7 @@ static struct qmi_elem_info qmi_wlanfw_wlan_mode_resp_msg_v01_ei[] = { }, }; -static struct qmi_elem_info qmi_wlanfw_wlan_cfg_req_msg_v01_ei[] = { +static const struct qmi_elem_info qmi_wlanfw_wlan_cfg_req_msg_v01_ei[] = { { .data_type = QMI_OPT_FLAG, .elem_len = 1, @@ -1862,7 +1862,7 @@ static struct qmi_elem_info qmi_wlanfw_wlan_cfg_req_msg_v01_ei[] = { }, }; -static struct qmi_elem_info qmi_wlanfw_wlan_cfg_resp_msg_v01_ei[] = { +static const struct qmi_elem_info qmi_wlanfw_wlan_cfg_resp_msg_v01_ei[] = { { .data_type = QMI_STRUCT, .elem_len = 1, @@ -1879,14 +1879,14 @@ static struct qmi_elem_info qmi_wlanfw_wlan_cfg_resp_msg_v01_ei[] = { }, }; -static struct qmi_elem_info qmi_wlanfw_mem_ready_ind_msg_v01_ei[] = { +static const struct qmi_elem_info qmi_wlanfw_mem_ready_ind_msg_v01_ei[] = { { .data_type = QMI_EOTI, .array_type = NO_ARRAY, }, }; -static struct qmi_elem_info qmi_wlanfw_fw_ready_ind_msg_v01_ei[] = { +static const struct qmi_elem_info qmi_wlanfw_fw_ready_ind_msg_v01_ei[] = { { .data_type = QMI_EOTI, .array_type = NO_ARRAY, From aaf244141ed7195a9a56e03c2367f4a9d0b727a8 Mon Sep 17 00:00:00 2001 From: Zhenghao Gu Date: Wed, 20 Dec 2023 20:33:08 +0200 Subject: [PATCH 18/71] wifi: ath11k: fix IOMMU errors on buffer rings virt_to_phys() doesn't work on systems with IOMMU enabled, which have non-identity physical-to-IOVA mappings. It leads to IO_PAGE_FAULTs like this: [IO_PAGE_FAULT domain=0x0023 address=0x1cce00000 flags=0x0020] And no association to the AP can be established. This patch changes that to dma_map_single(), which works correctly. Even virt_to_phys() documentation says device drivers should not use it: This function does not give bus mappings for DMA transfers. In almost all conceivable cases a device driver should not be using this function Tested-on: QCN9074 hw1.0 PCI WLAN.HK.2.7.0.1-01744-QCAHKSWPL_SILICONZ-1 Signed-off-by: Zhenghao Gu Acked-by: Jeff Johnson Signed-off-by: Kalle Valo Link: https://msgid.link/20231212031914.47339-1-imguzh@gmail.com --- drivers/net/wireless/ath/ath11k/dp.c | 20 +++++++++++++++++--- drivers/net/wireless/ath/ath11k/hal.c | 19 +++++++++++++++++-- 2 files changed, 34 insertions(+), 5 deletions(-) diff --git a/drivers/net/wireless/ath/ath11k/dp.c b/drivers/net/wireless/ath/ath11k/dp.c index 8975dc57ad77..1a62407e5a9f 100644 --- a/drivers/net/wireless/ath/ath11k/dp.c +++ b/drivers/net/wireless/ath/ath11k/dp.c @@ -104,11 +104,14 @@ void ath11k_dp_srng_cleanup(struct ath11k_base *ab, struct dp_srng *ring) if (!ring->vaddr_unaligned) return; - if (ring->cached) + if (ring->cached) { + dma_unmap_single(ab->dev, ring->paddr_unaligned, ring->size, + DMA_FROM_DEVICE); kfree(ring->vaddr_unaligned); - else + } else { dma_free_coherent(ab->dev, ring->size, ring->vaddr_unaligned, ring->paddr_unaligned); + } ring->vaddr_unaligned = NULL; } @@ -249,7 +252,18 @@ int ath11k_dp_srng_setup(struct ath11k_base *ab, struct dp_srng *ring, if (cached) { ring->vaddr_unaligned = kzalloc(ring->size, GFP_KERNEL); - ring->paddr_unaligned = virt_to_phys(ring->vaddr_unaligned); + if (!ring->vaddr_unaligned) + return -ENOMEM; + + ring->paddr_unaligned = dma_map_single(ab->dev, + ring->vaddr_unaligned, + ring->size, + DMA_FROM_DEVICE); + if (dma_mapping_error(ab->dev, ring->paddr_unaligned)) { + kfree(ring->vaddr_unaligned); + ring->vaddr_unaligned = NULL; + return -ENOMEM; + } } } diff --git a/drivers/net/wireless/ath/ath11k/hal.c b/drivers/net/wireless/ath/ath11k/hal.c index c060c4b5c0cc..f3d04568c221 100644 --- a/drivers/net/wireless/ath/ath11k/hal.c +++ b/drivers/net/wireless/ath/ath11k/hal.c @@ -626,15 +626,30 @@ u32 *ath11k_hal_srng_dst_peek(struct ath11k_base *ab, struct hal_srng *srng) return NULL; } +static u32 *ath11k_hal_srng_dst_peek_with_dma(struct ath11k_base *ab, + struct hal_srng *srng, dma_addr_t *paddr) +{ + lockdep_assert_held(&srng->lock); + + if (srng->u.dst_ring.tp != srng->u.dst_ring.cached_hp) { + *paddr = srng->ring_base_paddr + + sizeof(*srng->ring_base_vaddr) * srng->u.dst_ring.tp; + return srng->ring_base_vaddr + srng->u.dst_ring.tp; + } + + return NULL; +} + static void ath11k_hal_srng_prefetch_desc(struct ath11k_base *ab, struct hal_srng *srng) { + dma_addr_t desc_paddr; u32 *desc; /* prefetch only if desc is available */ - desc = ath11k_hal_srng_dst_peek(ab, srng); + desc = ath11k_hal_srng_dst_peek_with_dma(ab, srng, &desc_paddr); if (likely(desc)) { - dma_sync_single_for_cpu(ab->dev, virt_to_phys(desc), + dma_sync_single_for_cpu(ab->dev, desc_paddr, (srng->entry_size * sizeof(u32)), DMA_FROM_DEVICE); prefetch(desc); From fba97a777dcb90896ab1dc32e796d85bb7bbcd69 Mon Sep 17 00:00:00 2001 From: Dmitry Antipov Date: Tue, 19 Dec 2023 12:10:18 +0300 Subject: [PATCH 19/71] wifi: ath12k: refactor ath12k_wmi_tlv_parse_alloc() Since 'ath12k_wmi_tlv_parse_alloc()' always operates on 'skb->data, skb->len' tuple, it may be simplified to pass the only 'skb' argument instead (which implies refactoring of 'ath12k_pull_bcn_tx_status_ev()', 'ath12k_pull_chan_info_ev()' and 'ath12k_pull_pdev_temp_ev()' in the same way). This is an ath12k counterpart of the recently submitted ath11k patch and compile tested only as well. Signed-off-by: Dmitry Antipov Signed-off-by: Kalle Valo Link: https://msgid.link/20231219091022.70861-1-dmantipov@yandex.ru --- drivers/net/wireless/ath/ath12k/wmi.c | 69 +++++++++++++-------------- 1 file changed, 34 insertions(+), 35 deletions(-) diff --git a/drivers/net/wireless/ath/ath12k/wmi.c b/drivers/net/wireless/ath/ath12k/wmi.c index 11cc3005c0f9..553d2566b3f7 100644 --- a/drivers/net/wireless/ath/ath12k/wmi.c +++ b/drivers/net/wireless/ath/ath12k/wmi.c @@ -359,8 +359,8 @@ static int ath12k_wmi_tlv_parse(struct ath12k_base *ar, const void **tb, } static const void ** -ath12k_wmi_tlv_parse_alloc(struct ath12k_base *ab, const void *ptr, - size_t len, gfp_t gfp) +ath12k_wmi_tlv_parse_alloc(struct ath12k_base *ab, + struct sk_buff *skb, gfp_t gfp) { const void **tb; int ret; @@ -369,7 +369,7 @@ ath12k_wmi_tlv_parse_alloc(struct ath12k_base *ab, const void *ptr, if (!tb) return ERR_PTR(-ENOMEM); - ret = ath12k_wmi_tlv_parse(ab, tb, ptr, len); + ret = ath12k_wmi_tlv_parse(ab, tb, skb->data, skb->len); if (ret) { kfree(tb); return ERR_PTR(ret); @@ -4374,7 +4374,7 @@ static int ath12k_pull_vdev_start_resp_tlv(struct ath12k_base *ab, struct sk_buf const struct wmi_vdev_start_resp_event *ev; int ret; - tb = ath12k_wmi_tlv_parse_alloc(ab, skb->data, skb->len, GFP_ATOMIC); + tb = ath12k_wmi_tlv_parse_alloc(ab, skb, GFP_ATOMIC); if (IS_ERR(tb)) { ret = PTR_ERR(tb); ath12k_warn(ab, "failed to parse tlv: %d\n", ret); @@ -4452,7 +4452,7 @@ static int ath12k_pull_reg_chan_list_ext_update_ev(struct ath12k_base *ab, ath12k_dbg(ab, ATH12K_DBG_WMI, "processing regulatory ext channel list\n"); - tb = ath12k_wmi_tlv_parse_alloc(ab, skb->data, skb->len, GFP_ATOMIC); + tb = ath12k_wmi_tlv_parse_alloc(ab, skb, GFP_ATOMIC); if (IS_ERR(tb)) { ret = PTR_ERR(tb); ath12k_warn(ab, "failed to parse tlv: %d\n", ret); @@ -4738,7 +4738,7 @@ static int ath12k_pull_peer_del_resp_ev(struct ath12k_base *ab, struct sk_buff * const struct wmi_peer_delete_resp_event *ev; int ret; - tb = ath12k_wmi_tlv_parse_alloc(ab, skb->data, skb->len, GFP_ATOMIC); + tb = ath12k_wmi_tlv_parse_alloc(ab, skb, GFP_ATOMIC); if (IS_ERR(tb)) { ret = PTR_ERR(tb); ath12k_warn(ab, "failed to parse tlv: %d\n", ret); @@ -4770,7 +4770,7 @@ static int ath12k_pull_vdev_del_resp_ev(struct ath12k_base *ab, const struct wmi_vdev_delete_resp_event *ev; int ret; - tb = ath12k_wmi_tlv_parse_alloc(ab, skb->data, skb->len, GFP_ATOMIC); + tb = ath12k_wmi_tlv_parse_alloc(ab, skb, GFP_ATOMIC); if (IS_ERR(tb)) { ret = PTR_ERR(tb); ath12k_warn(ab, "failed to parse tlv: %d\n", ret); @@ -4790,15 +4790,15 @@ static int ath12k_pull_vdev_del_resp_ev(struct ath12k_base *ab, return 0; } -static int ath12k_pull_bcn_tx_status_ev(struct ath12k_base *ab, void *evt_buf, - u32 len, u32 *vdev_id, - u32 *tx_status) +static int ath12k_pull_bcn_tx_status_ev(struct ath12k_base *ab, + struct sk_buff *skb, + u32 *vdev_id, u32 *tx_status) { const void **tb; const struct wmi_bcn_tx_status_event *ev; int ret; - tb = ath12k_wmi_tlv_parse_alloc(ab, evt_buf, len, GFP_ATOMIC); + tb = ath12k_wmi_tlv_parse_alloc(ab, skb, GFP_ATOMIC); if (IS_ERR(tb)) { ret = PTR_ERR(tb); ath12k_warn(ab, "failed to parse tlv: %d\n", ret); @@ -4826,7 +4826,7 @@ static int ath12k_pull_vdev_stopped_param_tlv(struct ath12k_base *ab, struct sk_ const struct wmi_vdev_stopped_event *ev; int ret; - tb = ath12k_wmi_tlv_parse_alloc(ab, skb->data, skb->len, GFP_ATOMIC); + tb = ath12k_wmi_tlv_parse_alloc(ab, skb, GFP_ATOMIC); if (IS_ERR(tb)) { ret = PTR_ERR(tb); ath12k_warn(ab, "failed to parse tlv: %d\n", ret); @@ -4970,7 +4970,7 @@ static int ath12k_pull_mgmt_tx_compl_param_tlv(struct ath12k_base *ab, const struct wmi_mgmt_tx_compl_event *ev; int ret; - tb = ath12k_wmi_tlv_parse_alloc(ab, skb->data, skb->len, GFP_ATOMIC); + tb = ath12k_wmi_tlv_parse_alloc(ab, skb, GFP_ATOMIC); if (IS_ERR(tb)) { ret = PTR_ERR(tb); ath12k_warn(ab, "failed to parse tlv: %d\n", ret); @@ -5141,7 +5141,7 @@ static int ath12k_pull_scan_ev(struct ath12k_base *ab, struct sk_buff *skb, const struct wmi_scan_event *ev; int ret; - tb = ath12k_wmi_tlv_parse_alloc(ab, skb->data, skb->len, GFP_ATOMIC); + tb = ath12k_wmi_tlv_parse_alloc(ab, skb, GFP_ATOMIC); if (IS_ERR(tb)) { ret = PTR_ERR(tb); ath12k_warn(ab, "failed to parse tlv: %d\n", ret); @@ -5174,7 +5174,7 @@ static int ath12k_pull_peer_sta_kickout_ev(struct ath12k_base *ab, struct sk_buf const struct wmi_peer_sta_kickout_event *ev; int ret; - tb = ath12k_wmi_tlv_parse_alloc(ab, skb->data, skb->len, GFP_ATOMIC); + tb = ath12k_wmi_tlv_parse_alloc(ab, skb, GFP_ATOMIC); if (IS_ERR(tb)) { ret = PTR_ERR(tb); ath12k_warn(ab, "failed to parse tlv: %d\n", ret); @@ -5201,7 +5201,7 @@ static int ath12k_pull_roam_ev(struct ath12k_base *ab, struct sk_buff *skb, const struct wmi_roam_event *ev; int ret; - tb = ath12k_wmi_tlv_parse_alloc(ab, skb->data, skb->len, GFP_ATOMIC); + tb = ath12k_wmi_tlv_parse_alloc(ab, skb, GFP_ATOMIC); if (IS_ERR(tb)) { ret = PTR_ERR(tb); ath12k_warn(ab, "failed to parse tlv: %d\n", ret); @@ -5245,14 +5245,14 @@ static int freq_to_idx(struct ath12k *ar, int freq) return idx; } -static int ath12k_pull_chan_info_ev(struct ath12k_base *ab, u8 *evt_buf, - u32 len, struct wmi_chan_info_event *ch_info_ev) +static int ath12k_pull_chan_info_ev(struct ath12k_base *ab, struct sk_buff *skb, + struct wmi_chan_info_event *ch_info_ev) { const void **tb; const struct wmi_chan_info_event *ev; int ret; - tb = ath12k_wmi_tlv_parse_alloc(ab, evt_buf, len, GFP_ATOMIC); + tb = ath12k_wmi_tlv_parse_alloc(ab, skb, GFP_ATOMIC); if (IS_ERR(tb)) { ret = PTR_ERR(tb); ath12k_warn(ab, "failed to parse tlv: %d\n", ret); @@ -5291,7 +5291,7 @@ ath12k_pull_pdev_bss_chan_info_ev(struct ath12k_base *ab, struct sk_buff *skb, const struct wmi_pdev_bss_chan_info_event *ev; int ret; - tb = ath12k_wmi_tlv_parse_alloc(ab, skb->data, skb->len, GFP_ATOMIC); + tb = ath12k_wmi_tlv_parse_alloc(ab, skb, GFP_ATOMIC); if (IS_ERR(tb)) { ret = PTR_ERR(tb); ath12k_warn(ab, "failed to parse tlv: %d\n", ret); @@ -5331,7 +5331,7 @@ ath12k_pull_vdev_install_key_compl_ev(struct ath12k_base *ab, struct sk_buff *sk const struct wmi_vdev_install_key_compl_event *ev; int ret; - tb = ath12k_wmi_tlv_parse_alloc(ab, skb->data, skb->len, GFP_ATOMIC); + tb = ath12k_wmi_tlv_parse_alloc(ab, skb, GFP_ATOMIC); if (IS_ERR(tb)) { ret = PTR_ERR(tb); ath12k_warn(ab, "failed to parse tlv: %d\n", ret); @@ -5362,7 +5362,7 @@ static int ath12k_pull_peer_assoc_conf_ev(struct ath12k_base *ab, struct sk_buff const struct wmi_peer_assoc_conf_event *ev; int ret; - tb = ath12k_wmi_tlv_parse_alloc(ab, skb->data, skb->len, GFP_ATOMIC); + tb = ath12k_wmi_tlv_parse_alloc(ab, skb, GFP_ATOMIC); if (IS_ERR(tb)) { ret = PTR_ERR(tb); ath12k_warn(ab, "failed to parse tlv: %d\n", ret); @@ -5384,13 +5384,13 @@ static int ath12k_pull_peer_assoc_conf_ev(struct ath12k_base *ab, struct sk_buff } static int -ath12k_pull_pdev_temp_ev(struct ath12k_base *ab, u8 *evt_buf, - u32 len, const struct wmi_pdev_temperature_event *ev) +ath12k_pull_pdev_temp_ev(struct ath12k_base *ab, struct sk_buff *skb, + const struct wmi_pdev_temperature_event *ev) { const void **tb; int ret; - tb = ath12k_wmi_tlv_parse_alloc(ab, evt_buf, len, GFP_ATOMIC); + tb = ath12k_wmi_tlv_parse_alloc(ab, skb, GFP_ATOMIC); if (IS_ERR(tb)) { ret = PTR_ERR(tb); ath12k_warn(ab, "failed to parse tlv: %d\n", ret); @@ -5725,8 +5725,7 @@ static void ath12k_bcn_tx_status_event(struct ath12k_base *ab, struct sk_buff *s { u32 vdev_id, tx_status; - if (ath12k_pull_bcn_tx_status_ev(ab, skb->data, skb->len, - &vdev_id, &tx_status) != 0) { + if (ath12k_pull_bcn_tx_status_ev(ab, skb, &vdev_id, &tx_status) != 0) { ath12k_warn(ab, "failed to extract bcn tx status"); return; } @@ -6110,7 +6109,7 @@ static void ath12k_chan_info_event(struct ath12k_base *ab, struct sk_buff *skb) /* HW channel counters frequency value in hertz */ u32 cc_freq_hz = ab->cc_freq_hz; - if (ath12k_pull_chan_info_ev(ab, skb->data, skb->len, &ch_info_ev) != 0) { + if (ath12k_pull_chan_info_ev(ab, skb, &ch_info_ev) != 0) { ath12k_warn(ab, "failed to extract chan info event"); return; } @@ -6395,7 +6394,7 @@ static void ath12k_pdev_ctl_failsafe_check_event(struct ath12k_base *ab, const struct wmi_pdev_ctl_failsafe_chk_event *ev; int ret; - tb = ath12k_wmi_tlv_parse_alloc(ab, skb->data, skb->len, GFP_ATOMIC); + tb = ath12k_wmi_tlv_parse_alloc(ab, skb, GFP_ATOMIC); if (IS_ERR(tb)) { ret = PTR_ERR(tb); ath12k_warn(ab, "failed to parse tlv: %d\n", ret); @@ -6460,7 +6459,7 @@ ath12k_wmi_pdev_csa_switch_count_status_event(struct ath12k_base *ab, const u32 *vdev_ids; int ret; - tb = ath12k_wmi_tlv_parse_alloc(ab, skb->data, skb->len, GFP_ATOMIC); + tb = ath12k_wmi_tlv_parse_alloc(ab, skb, GFP_ATOMIC); if (IS_ERR(tb)) { ret = PTR_ERR(tb); ath12k_warn(ab, "failed to parse tlv: %d\n", ret); @@ -6494,7 +6493,7 @@ ath12k_wmi_pdev_dfs_radar_detected_event(struct ath12k_base *ab, struct sk_buff struct ath12k *ar; int ret; - tb = ath12k_wmi_tlv_parse_alloc(ab, skb->data, skb->len, GFP_ATOMIC); + tb = ath12k_wmi_tlv_parse_alloc(ab, skb, GFP_ATOMIC); if (IS_ERR(tb)) { ret = PTR_ERR(tb); ath12k_warn(ab, "failed to parse tlv: %d\n", ret); @@ -6546,7 +6545,7 @@ ath12k_wmi_pdev_temperature_event(struct ath12k_base *ab, struct ath12k *ar; struct wmi_pdev_temperature_event ev = {0}; - if (ath12k_pull_pdev_temp_ev(ab, skb->data, skb->len, &ev) != 0) { + if (ath12k_pull_pdev_temp_ev(ab, skb, &ev) != 0) { ath12k_warn(ab, "failed to extract pdev temperature event"); return; } @@ -6573,7 +6572,7 @@ static void ath12k_fils_discovery_event(struct ath12k_base *ab, const struct wmi_fils_discovery_event *ev; int ret; - tb = ath12k_wmi_tlv_parse_alloc(ab, skb->data, skb->len, GFP_ATOMIC); + tb = ath12k_wmi_tlv_parse_alloc(ab, skb, GFP_ATOMIC); if (IS_ERR(tb)) { ret = PTR_ERR(tb); ath12k_warn(ab, @@ -6603,7 +6602,7 @@ static void ath12k_probe_resp_tx_status_event(struct ath12k_base *ab, const struct wmi_probe_resp_tx_status_event *ev; int ret; - tb = ath12k_wmi_tlv_parse_alloc(ab, skb->data, skb->len, GFP_ATOMIC); + tb = ath12k_wmi_tlv_parse_alloc(ab, skb, GFP_ATOMIC); if (IS_ERR(tb)) { ret = PTR_ERR(tb); ath12k_warn(ab, @@ -6635,7 +6634,7 @@ static void ath12k_rfkill_state_change_event(struct ath12k_base *ab, const void **tb; int ret; - tb = ath12k_wmi_tlv_parse_alloc(ab, skb->data, skb->len, GFP_ATOMIC); + tb = ath12k_wmi_tlv_parse_alloc(ab, skb, GFP_ATOMIC); if (IS_ERR(tb)) { ret = PTR_ERR(tb); ath12k_warn(ab, "failed to parse tlv: %d\n", ret); From e3d373ec4f02bf41379d91707e3e3f2a46464cd7 Mon Sep 17 00:00:00 2001 From: Wen Gong Date: Thu, 11 Jan 2024 15:56:57 +0200 Subject: [PATCH 20/71] wifi: ath11k: add support to select 6 GHz regulatory type There are 3 types of regulatory rules for AP mode and 6 type for station mode. Add wmi_vdev_type and ieee80211_ap_reg_power to select the exact reg rules. Tested-on: WCN6855 hw2.0 PCI WLAN.HSP.1.1-03125-QCAHSPSWPL_V1_V2_SILICONZ_LITE-3.6510.23 Signed-off-by: Wen Gong Signed-off-by: Baochen Qiang Signed-off-by: Kalle Valo Link: https://msgid.link/20231218085844.2658-2-quic_bqiang@quicinc.com --- drivers/net/wireless/ath/ath11k/reg.c | 70 +++++++++++++++++++++------ drivers/net/wireless/ath/ath11k/reg.h | 6 ++- drivers/net/wireless/ath/ath11k/wmi.c | 3 +- 3 files changed, 62 insertions(+), 17 deletions(-) diff --git a/drivers/net/wireless/ath/ath11k/reg.c b/drivers/net/wireless/ath/ath11k/reg.c index b4fd4d2107c7..78b99ab10c63 100644 --- a/drivers/net/wireless/ath/ath11k/reg.c +++ b/drivers/net/wireless/ath/ath11k/reg.c @@ -618,25 +618,68 @@ ath11k_reg_update_weather_radar_band(struct ath11k_base *ab, *rule_idx = i; } +enum wmi_reg_6ghz_ap_type +ath11k_reg_ap_pwr_convert(enum ieee80211_ap_reg_power power_type) +{ + switch (power_type) { + case IEEE80211_REG_LPI_AP: + return WMI_REG_INDOOR_AP; + case IEEE80211_REG_SP_AP: + return WMI_REG_STANDARD_POWER_AP; + case IEEE80211_REG_VLP_AP: + return WMI_REG_VERY_LOW_POWER_AP; + default: + return WMI_REG_MAX_AP_TYPE; + } +} + struct ieee80211_regdomain * ath11k_reg_build_regd(struct ath11k_base *ab, - struct cur_regulatory_info *reg_info, bool intersect) + struct cur_regulatory_info *reg_info, bool intersect, + enum wmi_vdev_type vdev_type, + enum ieee80211_ap_reg_power power_type) { struct ieee80211_regdomain *tmp_regd, *default_regd, *new_regd = NULL; - struct cur_reg_rule *reg_rule; + struct cur_reg_rule *reg_rule, *reg_rule_6ghz; u8 i = 0, j = 0, k = 0; u8 num_rules; u16 max_bw; - u32 flags; + u32 flags, reg_6ghz_number, max_bw_6ghz; char alpha2[3]; num_rules = reg_info->num_5ghz_reg_rules + reg_info->num_2ghz_reg_rules; - /* FIXME: Currently taking reg rules for 6 GHz only from Indoor AP mode list. - * This can be updated after complete 6 GHz regulatory support is added. - */ - if (reg_info->is_ext_reg_event) - num_rules += reg_info->num_6ghz_rules_ap[WMI_REG_INDOOR_AP]; + if (reg_info->is_ext_reg_event) { + if (vdev_type == WMI_VDEV_TYPE_STA) { + enum wmi_reg_6ghz_ap_type ap_type; + + ap_type = ath11k_reg_ap_pwr_convert(power_type); + + if (ap_type == WMI_REG_MAX_AP_TYPE) + ap_type = WMI_REG_INDOOR_AP; + + reg_6ghz_number = reg_info->num_6ghz_rules_client + [ap_type][WMI_REG_DEFAULT_CLIENT]; + + if (reg_6ghz_number == 0) { + ap_type = WMI_REG_INDOOR_AP; + reg_6ghz_number = reg_info->num_6ghz_rules_client + [ap_type][WMI_REG_DEFAULT_CLIENT]; + } + + reg_rule_6ghz = reg_info->reg_rules_6ghz_client_ptr + [ap_type][WMI_REG_DEFAULT_CLIENT]; + max_bw_6ghz = reg_info->max_bw_6ghz_client + [ap_type][WMI_REG_DEFAULT_CLIENT]; + } else { + reg_6ghz_number = reg_info->num_6ghz_rules_ap[WMI_REG_INDOOR_AP]; + reg_rule_6ghz = + reg_info->reg_rules_6ghz_ap_ptr[WMI_REG_INDOOR_AP]; + max_bw_6ghz = reg_info->max_bw_6ghz_ap[WMI_REG_INDOOR_AP]; + } + + num_rules += reg_6ghz_number; + } if (!num_rules) goto ret; @@ -683,13 +726,10 @@ ath11k_reg_build_regd(struct ath11k_base *ab, * per other BW rule flags we pass from here */ flags = NL80211_RRF_AUTO_BW; - } else if (reg_info->is_ext_reg_event && - reg_info->num_6ghz_rules_ap[WMI_REG_INDOOR_AP] && - (k < reg_info->num_6ghz_rules_ap[WMI_REG_INDOOR_AP])) { - reg_rule = reg_info->reg_rules_6ghz_ap_ptr[WMI_REG_INDOOR_AP] + - k++; - max_bw = min_t(u16, reg_rule->max_bw, - reg_info->max_bw_6ghz_ap[WMI_REG_INDOOR_AP]); + } else if (reg_info->is_ext_reg_event && reg_6ghz_number && + k < reg_6ghz_number) { + reg_rule = reg_rule_6ghz + k++; + max_bw = min_t(u16, reg_rule->max_bw, max_bw_6ghz); flags = NL80211_RRF_AUTO_BW; } else { break; diff --git a/drivers/net/wireless/ath/ath11k/reg.h b/drivers/net/wireless/ath/ath11k/reg.h index f28902f85e41..989b27b16bea 100644 --- a/drivers/net/wireless/ath/ath11k/reg.h +++ b/drivers/net/wireless/ath/ath11k/reg.h @@ -34,7 +34,11 @@ void ath11k_reg_free(struct ath11k_base *ab); void ath11k_regd_update_work(struct work_struct *work); struct ieee80211_regdomain * ath11k_reg_build_regd(struct ath11k_base *ab, - struct cur_regulatory_info *reg_info, bool intersect); + struct cur_regulatory_info *reg_info, bool intersect, + enum wmi_vdev_type vdev_type, + enum ieee80211_ap_reg_power power_type); int ath11k_regd_update(struct ath11k *ar); int ath11k_reg_update_chan_list(struct ath11k *ar, bool wait); +enum wmi_reg_6ghz_ap_type +ath11k_reg_ap_pwr_convert(enum ieee80211_ap_reg_power power_type); #endif diff --git a/drivers/net/wireless/ath/ath11k/wmi.c b/drivers/net/wireless/ath/ath11k/wmi.c index 89514899fcd5..58882829351e 100644 --- a/drivers/net/wireless/ath/ath11k/wmi.c +++ b/drivers/net/wireless/ath/ath11k/wmi.c @@ -7151,7 +7151,8 @@ static int ath11k_reg_chan_list_event(struct ath11k_base *ab, !ath11k_reg_is_world_alpha((char *)reg_info->alpha2)) intersect = true; - regd = ath11k_reg_build_regd(ab, reg_info, intersect); + regd = ath11k_reg_build_regd(ab, reg_info, intersect, + WMI_VDEV_TYPE_AP, IEEE80211_REG_LPI_AP); if (!regd) { ath11k_warn(ab, "failed to build regd from reg_info\n"); goto fallback; From 7004bdceef605e5c1c5ab4aaf282002ad7523ddd Mon Sep 17 00:00:00 2001 From: Wen Gong Date: Thu, 11 Jan 2024 15:56:57 +0200 Subject: [PATCH 21/71] wifi: ath11k: store cur_regulatory_info for each radio The regulatory info of WMI_REG_CHAN_LIST_CC_EXT_EVENTID is not saved in ath11k now, the info should be saved in ath11k. Save the info for each radio and support switch regulatory rules dynamically. As mac.c will also call ath11k_reg_handle_chan_list() in next patches move the function to reg.c. Tested-on: WCN6855 hw2.0 PCI WLAN.HSP.1.1-03125-QCAHSPSWPL_V1_V2_SILICONZ_LITE-3.6510.23 Signed-off-by: Wen Gong Acked-by: Jeff Johnson Signed-off-by: Baochen Qiang Signed-off-by: Kalle Valo Link: https://msgid.link/20231218085844.2658-3-quic_bqiang@quicinc.com --- drivers/net/wireless/ath/ath11k/core.h | 1 + drivers/net/wireless/ath/ath11k/reg.c | 179 +++++++++++++++++++++++++ drivers/net/wireless/ath/ath11k/reg.h | 5 + drivers/net/wireless/ath/ath11k/wmi.c | 148 +++----------------- drivers/net/wireless/ath/ath11k/wmi.h | 1 + 5 files changed, 207 insertions(+), 127 deletions(-) diff --git a/drivers/net/wireless/ath/ath11k/core.h b/drivers/net/wireless/ath/ath11k/core.h index 7e3b6779f4e9..cc91f7d3ca8e 100644 --- a/drivers/net/wireless/ath/ath11k/core.h +++ b/drivers/net/wireless/ath/ath11k/core.h @@ -922,6 +922,7 @@ struct ath11k_base { * This may or may not be used during the runtime */ struct ieee80211_regdomain *new_regd[MAX_RADIOS]; + struct cur_regulatory_info *reg_info_store; /* Current DFS Regulatory */ enum ath11k_dfs_region dfs_region; diff --git a/drivers/net/wireless/ath/ath11k/reg.c b/drivers/net/wireless/ath/ath11k/reg.c index 78b99ab10c63..adcd9063a59c 100644 --- a/drivers/net/wireless/ath/ath11k/reg.c +++ b/drivers/net/wireless/ath/ath11k/reg.c @@ -798,6 +798,159 @@ ath11k_reg_build_regd(struct ath11k_base *ab, return new_regd; } +static bool ath11k_reg_is_world_alpha(char *alpha) +{ + if (alpha[0] == '0' && alpha[1] == '0') + return true; + + if (alpha[0] == 'n' && alpha[1] == 'a') + return true; + + return false; +} + +static enum wmi_vdev_type ath11k_reg_get_ar_vdev_type(struct ath11k *ar) +{ + struct ath11k_vif *arvif; + + /* Currently each struct ath11k maps to one struct ieee80211_hw/wiphy + * and one struct ieee80211_regdomain, so it could only store one group + * reg rules. It means multi-interface concurrency in the same ath11k is + * not support for the regdomain. So get the vdev type of the first entry + * now. After concurrency support for the regdomain, this should change. + */ + arvif = list_first_entry_or_null(&ar->arvifs, struct ath11k_vif, list); + if (arvif) + return arvif->vdev_type; + + return WMI_VDEV_TYPE_UNSPEC; +} + +int ath11k_reg_handle_chan_list(struct ath11k_base *ab, + struct cur_regulatory_info *reg_info, + enum ieee80211_ap_reg_power power_type) +{ + struct ieee80211_regdomain *regd; + bool intersect = false; + int pdev_idx; + struct ath11k *ar; + enum wmi_vdev_type vdev_type; + + ath11k_dbg(ab, ATH11K_DBG_WMI, "event reg handle chan list"); + + if (reg_info->status_code != REG_SET_CC_STATUS_PASS) { + /* In case of failure to set the requested ctry, + * fw retains the current regd. We print a failure info + * and return from here. + */ + ath11k_warn(ab, "Failed to set the requested Country regulatory setting\n"); + return -EINVAL; + } + + pdev_idx = reg_info->phy_id; + + /* Avoid default reg rule updates sent during FW recovery if + * it is already available + */ + spin_lock(&ab->base_lock); + if (test_bit(ATH11K_FLAG_RECOVERY, &ab->dev_flags) && + ab->default_regd[pdev_idx]) { + spin_unlock(&ab->base_lock); + goto retfail; + } + spin_unlock(&ab->base_lock); + + if (pdev_idx >= ab->num_radios) { + /* Process the event for phy0 only if single_pdev_only + * is true. If pdev_idx is valid but not 0, discard the + * event. Otherwise, it goes to fallback. In either case + * ath11k_reg_reset_info() needs to be called to avoid + * memory leak issue. + */ + ath11k_reg_reset_info(reg_info); + + if (ab->hw_params.single_pdev_only && + pdev_idx < ab->hw_params.num_rxmda_per_pdev) + return 0; + goto fallback; + } + + /* Avoid multiple overwrites to default regd, during core + * stop-start after mac registration. + */ + if (ab->default_regd[pdev_idx] && !ab->new_regd[pdev_idx] && + !memcmp((char *)ab->default_regd[pdev_idx]->alpha2, + (char *)reg_info->alpha2, 2)) + goto retfail; + + /* Intersect new rules with default regd if a new country setting was + * requested, i.e a default regd was already set during initialization + * and the regd coming from this event has a valid country info. + */ + if (ab->default_regd[pdev_idx] && + !ath11k_reg_is_world_alpha((char *) + ab->default_regd[pdev_idx]->alpha2) && + !ath11k_reg_is_world_alpha((char *)reg_info->alpha2)) + intersect = true; + + ar = ab->pdevs[pdev_idx].ar; + vdev_type = ath11k_reg_get_ar_vdev_type(ar); + + ath11k_dbg(ab, ATH11K_DBG_WMI, + "wmi handle chan list power type %d vdev type %d intersect %d\n", + power_type, vdev_type, intersect); + + regd = ath11k_reg_build_regd(ab, reg_info, intersect, vdev_type, power_type); + if (!regd) { + ath11k_warn(ab, "failed to build regd from reg_info\n"); + goto fallback; + } + + if (power_type == IEEE80211_REG_UNSET_AP) { + ath11k_reg_reset_info(&ab->reg_info_store[pdev_idx]); + ab->reg_info_store[pdev_idx] = *reg_info; + } + + spin_lock(&ab->base_lock); + if (ab->default_regd[pdev_idx]) { + /* The initial rules from FW after WMI Init is to build + * the default regd. From then on, any rules updated for + * the pdev could be due to user reg changes. + * Free previously built regd before assigning the newly + * generated regd to ar. NULL pointer handling will be + * taken care by kfree itself. + */ + ar = ab->pdevs[pdev_idx].ar; + kfree(ab->new_regd[pdev_idx]); + ab->new_regd[pdev_idx] = regd; + 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 + */ + ab->default_regd[pdev_idx] = regd; + } + ab->dfs_region = reg_info->dfs_region; + spin_unlock(&ab->base_lock); + + return 0; + +fallback: + /* Fallback to older reg (by sending previous country setting + * again if fw has succeeded and we failed to process here. + * The Regdomain should be uniform across driver and fw. Since the + * FW has processed the command and sent a success status, we expect + * this function to succeed as well. If it doesn't, CTRY needs to be + * reverted at the fw and the old SCAN_CHAN_LIST cmd needs to be sent. + */ + /* TODO: This is rare, but still should also be handled */ + WARN_ON(1); + +retfail: + + return -EINVAL; +} + void ath11k_regd_update_work(struct work_struct *work) { struct ath11k *ar = container_of(work, struct ath11k, @@ -821,10 +974,36 @@ void ath11k_reg_init(struct ath11k *ar) ar->hw->wiphy->reg_notifier = ath11k_reg_notifier; } +void ath11k_reg_reset_info(struct cur_regulatory_info *reg_info) +{ + int i, j; + + if (!reg_info) + return; + + kfree(reg_info->reg_rules_2ghz_ptr); + kfree(reg_info->reg_rules_5ghz_ptr); + + for (i = 0; i < WMI_REG_CURRENT_MAX_AP_TYPE; i++) { + kfree(reg_info->reg_rules_6ghz_ap_ptr[i]); + + for (j = 0; j < WMI_REG_MAX_CLIENT_TYPE; j++) + kfree(reg_info->reg_rules_6ghz_client_ptr[i][j]); + } + + memset(reg_info, 0, sizeof(*reg_info)); +} + void ath11k_reg_free(struct ath11k_base *ab) { int i; + for (i = 0; i < ab->num_radios; i++) + ath11k_reg_reset_info(&ab->reg_info_store[i]); + + kfree(ab->reg_info_store); + ab->reg_info_store = NULL; + for (i = 0; i < ab->hw_params.max_radios; i++) { kfree(ab->default_regd[i]); kfree(ab->new_regd[i]); diff --git a/drivers/net/wireless/ath/ath11k/reg.h b/drivers/net/wireless/ath/ath11k/reg.h index 989b27b16bea..64edb794260a 100644 --- a/drivers/net/wireless/ath/ath11k/reg.h +++ b/drivers/net/wireless/ath/ath11k/reg.h @@ -30,6 +30,7 @@ enum ath11k_dfs_region { /* ATH11K Regulatory API's */ void ath11k_reg_init(struct ath11k *ar); +void ath11k_reg_reset_info(struct cur_regulatory_info *reg_info); void ath11k_reg_free(struct ath11k_base *ab); void ath11k_regd_update_work(struct work_struct *work); struct ieee80211_regdomain * @@ -41,4 +42,8 @@ int ath11k_regd_update(struct ath11k *ar); int ath11k_reg_update_chan_list(struct ath11k *ar, bool wait); enum wmi_reg_6ghz_ap_type ath11k_reg_ap_pwr_convert(enum ieee80211_ap_reg_power power_type); +int ath11k_reg_handle_chan_list(struct ath11k_base *ab, + struct cur_regulatory_info *reg_info, + enum ieee80211_ap_reg_power power_type); + #endif diff --git a/drivers/net/wireless/ath/ath11k/wmi.c b/drivers/net/wireless/ath/ath11k/wmi.c index 58882829351e..7e604d4b9a77 100644 --- a/drivers/net/wireless/ath/ath11k/wmi.c +++ b/drivers/net/wireless/ath/ath11k/wmi.c @@ -4749,6 +4749,14 @@ static int ath11k_wmi_tlv_ext_soc_hal_reg_caps_parse(struct ath11k_base *soc, soc->pdevs[0].pdev_id = 0; } + if (!soc->reg_info_store) { + soc->reg_info_store = kcalloc(soc->num_radios, + sizeof(*soc->reg_info_store), + GFP_ATOMIC); + if (!soc->reg_info_store) + return -ENOMEM; + } + return 0; } @@ -7060,32 +7068,15 @@ static void ath11k_wmi_htc_tx_complete(struct ath11k_base *ab, wake_up(&wmi->tx_ce_desc_wq); } -static bool ath11k_reg_is_world_alpha(char *alpha) -{ - 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, +static int ath11k_reg_chan_list_event(struct ath11k_base *ab, struct sk_buff *skb, enum wmi_reg_chan_list_cmd_type id) { - struct cur_regulatory_info *reg_info = NULL; - struct ieee80211_regdomain *regd = NULL; - bool intersect = false; - int ret = 0, pdev_idx, i, j; - struct ath11k *ar; + struct cur_regulatory_info *reg_info; + int ret; reg_info = kzalloc(sizeof(*reg_info), GFP_ATOMIC); - if (!reg_info) { - ret = -ENOMEM; - goto fallback; - } + if (!reg_info) + return -ENOMEM; if (id == WMI_REG_CHAN_LIST_CC_ID) ret = ath11k_pull_reg_chan_list_update_ev(ab, skb, reg_info); @@ -7093,119 +7084,22 @@ static int ath11k_reg_chan_list_event(struct ath11k_base *ab, ret = ath11k_pull_reg_chan_list_ext_update_ev(ab, skb, reg_info); if (ret) { - ath11k_warn(ab, "failed to extract regulatory info from received event\n"); - goto fallback; - } - - ath11k_dbg(ab, ATH11K_DBG_WMI, "event reg chan list id %d", id); - - if (reg_info->status_code != REG_SET_CC_STATUS_PASS) { - /* In case of failure to set the requested ctry, - * fw retains the current regd. We print a failure info - * and return from here. - */ - ath11k_warn(ab, "Failed to set the requested Country regulatory setting\n"); + ath11k_warn(ab, "failed to extract regulatory info\n"); goto mem_free; } - pdev_idx = reg_info->phy_id; - - /* Avoid default reg rule updates sent during FW recovery if - * it is already available - */ - spin_lock(&ab->base_lock); - if (test_bit(ATH11K_FLAG_RECOVERY, &ab->dev_flags) && - ab->default_regd[pdev_idx]) { - spin_unlock(&ab->base_lock); + ret = ath11k_reg_handle_chan_list(ab, reg_info, IEEE80211_REG_UNSET_AP); + if (ret) { + ath11k_warn(ab, "failed to process regulatory info %d\n", ret); goto mem_free; } - spin_unlock(&ab->base_lock); - if (pdev_idx >= ab->num_radios) { - /* Process the event for phy0 only if single_pdev_only - * is true. If pdev_idx is valid but not 0, discard the - * event. Otherwise, it goes to fallback. - */ - if (ab->hw_params.single_pdev_only && - pdev_idx < ab->hw_params.num_rxmda_per_pdev) - goto mem_free; - else - goto fallback; - } + kfree(reg_info); + return 0; - /* Avoid multiple overwrites to default regd, during core - * stop-start after mac registration. - */ - if (ab->default_regd[pdev_idx] && !ab->new_regd[pdev_idx] && - !memcmp((char *)ab->default_regd[pdev_idx]->alpha2, - (char *)reg_info->alpha2, 2)) - goto mem_free; - - /* Intersect new rules with default regd if a new country setting was - * requested, i.e a default regd was already set during initialization - * and the regd coming from this event has a valid country info. - */ - if (ab->default_regd[pdev_idx] && - !ath11k_reg_is_world_alpha((char *) - ab->default_regd[pdev_idx]->alpha2) && - !ath11k_reg_is_world_alpha((char *)reg_info->alpha2)) - intersect = true; - - regd = ath11k_reg_build_regd(ab, reg_info, intersect, - WMI_VDEV_TYPE_AP, IEEE80211_REG_LPI_AP); - if (!regd) { - ath11k_warn(ab, "failed to build regd from reg_info\n"); - goto fallback; - } - - spin_lock(&ab->base_lock); - if (ab->default_regd[pdev_idx]) { - /* The initial rules from FW after WMI Init is to build - * the default regd. From then on, any rules updated for - * the pdev could be due to user reg changes. - * Free previously built regd before assigning the newly - * generated regd to ar. NULL pointer handling will be - * taken care by kfree itself. - */ - ar = ab->pdevs[pdev_idx].ar; - kfree(ab->new_regd[pdev_idx]); - ab->new_regd[pdev_idx] = regd; - 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 - */ - ab->default_regd[pdev_idx] = regd; - } - ab->dfs_region = reg_info->dfs_region; - spin_unlock(&ab->base_lock); - - goto mem_free; - -fallback: - /* Fallback to older reg (by sending previous country setting - * again if fw has succeeded and we failed to process here. - * The Regdomain should be uniform across driver and fw. Since the - * FW has processed the command and sent a success status, we expect - * this function to succeed as well. If it doesn't, CTRY needs to be - * reverted at the fw and the old SCAN_CHAN_LIST cmd needs to be sent. - */ - /* TODO: This is rare, but still should also be handled */ - WARN_ON(1); mem_free: - if (reg_info) { - kfree(reg_info->reg_rules_2ghz_ptr); - kfree(reg_info->reg_rules_5ghz_ptr); - if (reg_info->is_ext_reg_event) { - for (i = 0; i < WMI_REG_CURRENT_MAX_AP_TYPE; i++) - kfree(reg_info->reg_rules_6ghz_ap_ptr[i]); - - for (j = 0; j < WMI_REG_CURRENT_MAX_AP_TYPE; j++) - for (i = 0; i < WMI_REG_MAX_CLIENT_TYPE; i++) - kfree(reg_info->reg_rules_6ghz_client_ptr[j][i]); - } - kfree(reg_info); - } + ath11k_reg_reset_info(reg_info); + kfree(reg_info); return ret; } diff --git a/drivers/net/wireless/ath/ath11k/wmi.h b/drivers/net/wireless/ath/ath11k/wmi.h index b1b4ee804b7b..a466d2bb4bb8 100644 --- a/drivers/net/wireless/ath/ath11k/wmi.h +++ b/drivers/net/wireless/ath/ath11k/wmi.h @@ -4951,6 +4951,7 @@ struct ath11k_targ_cap { }; enum wmi_vdev_type { + WMI_VDEV_TYPE_UNSPEC = 0, WMI_VDEV_TYPE_AP = 1, WMI_VDEV_TYPE_STA = 2, WMI_VDEV_TYPE_IBSS = 3, From cf2df0080bd59cb97a1519ddefaf59788febdaa5 Mon Sep 17 00:00:00 2001 From: Baochen Qiang Date: Thu, 11 Jan 2024 15:56:57 +0200 Subject: [PATCH 22/71] wifi: ath11k: fix a possible dead lock caused by ab->base_lock spin_lock()/spin_unlock() are used in ath11k_reg_chan_list_event() to acquire/release ab->base_lock. For now this is safe because that function is only called in soft IRQ context. But ath11k_reg_chan_list_event() will be called from process context in an upcoming patch, and this can result in a deadlock if ab->base_lock is acquired in process context and then soft IRQ occurs on the same CPU and tries to acquire that lock. Fix it by using spin_lock_bh() and spin_unlock_bh() instead. Tested-on: WCN6855 hw2.0 PCI WLAN.HSP.1.1-03125-QCAHSPSWPL_V1_V2_SILICONZ_LITE-3.6510.23 Fixes: 69a0fcf8a9f2 ("ath11k: Avoid reg rules update during firmware recovery") Signed-off-by: Baochen Qiang Signed-off-by: Wen Gong Acked-by: Jeff Johnson Signed-off-by: Kalle Valo Link: https://msgid.link/20231218085844.2658-4-quic_bqiang@quicinc.com --- drivers/net/wireless/ath/ath11k/reg.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/drivers/net/wireless/ath/ath11k/reg.c b/drivers/net/wireless/ath/ath11k/reg.c index adcd9063a59c..d4fd3509e608 100644 --- a/drivers/net/wireless/ath/ath11k/reg.c +++ b/drivers/net/wireless/ath/ath11k/reg.c @@ -852,13 +852,13 @@ int ath11k_reg_handle_chan_list(struct ath11k_base *ab, /* Avoid default reg rule updates sent during FW recovery if * it is already available */ - spin_lock(&ab->base_lock); + spin_lock_bh(&ab->base_lock); if (test_bit(ATH11K_FLAG_RECOVERY, &ab->dev_flags) && ab->default_regd[pdev_idx]) { - spin_unlock(&ab->base_lock); + spin_unlock_bh(&ab->base_lock); goto retfail; } - spin_unlock(&ab->base_lock); + spin_unlock_bh(&ab->base_lock); if (pdev_idx >= ab->num_radios) { /* Process the event for phy0 only if single_pdev_only @@ -911,7 +911,7 @@ int ath11k_reg_handle_chan_list(struct ath11k_base *ab, ab->reg_info_store[pdev_idx] = *reg_info; } - spin_lock(&ab->base_lock); + spin_lock_bh(&ab->base_lock); if (ab->default_regd[pdev_idx]) { /* The initial rules from FW after WMI Init is to build * the default regd. From then on, any rules updated for @@ -931,7 +931,7 @@ int ath11k_reg_handle_chan_list(struct ath11k_base *ab, ab->default_regd[pdev_idx] = regd; } ab->dfs_region = reg_info->dfs_region; - spin_unlock(&ab->base_lock); + spin_unlock_bh(&ab->base_lock); return 0; From 17144d32e90708cd5532055f3d9894ced9ac45a2 Mon Sep 17 00:00:00 2001 From: Wen Gong Date: Thu, 11 Jan 2024 15:56:57 +0200 Subject: [PATCH 23/71] wifi: ath11k: update regulatory rules when interface added There are two power types for 6 GHz regulatory, one is AP, another is client. When firmware boots up, WMI_REG_CHAN_LIST_CC_EXT_EVENTID is sent from firmware at an early stage, the interface mode is not decided at this point, then ath11k select reg rules of AP type as default. After interface is created, it is exactly decided the interface type such as AP/mesh point/station. Then ath11k need to update reg rules to the exact power type matched to the interface type. The client power type is used for station interface, and AP power type is used for AP/mesh point interface. Tested-on: WCN6855 hw2.0 PCI WLAN.HSP.1.1-03125-QCAHSPSWPL_V1_V2_SILICONZ_LITE-3.6510.23 Signed-off-by: Wen Gong Acked-by: Jeff Johnson Signed-off-by: Baochen Qiang Signed-off-by: Kalle Valo Link: https://msgid.link/20231218085844.2658-5-quic_bqiang@quicinc.com --- drivers/net/wireless/ath/ath11k/mac.c | 8 ++++++++ drivers/net/wireless/ath/ath11k/wmi.c | 6 ++++++ drivers/net/wireless/ath/ath11k/wmi.h | 1 + 3 files changed, 15 insertions(+) diff --git a/drivers/net/wireless/ath/ath11k/mac.c b/drivers/net/wireless/ath/ath11k/mac.c index db241589424d..3f52428433d1 100644 --- a/drivers/net/wireless/ath/ath11k/mac.c +++ b/drivers/net/wireless/ath/ath11k/mac.c @@ -6949,6 +6949,14 @@ static int ath11k_mac_op_add_interface(struct ieee80211_hw *hw, ret); } + if (ath11k_wmi_supports_6ghz_cc_ext(ar)) { + struct cur_regulatory_info *reg_info; + + reg_info = &ab->reg_info_store[ar->pdev_idx]; + ath11k_dbg(ab, ATH11K_DBG_MAC, "interface added to change reg rules\n"); + ath11k_reg_handle_chan_list(ab, reg_info, IEEE80211_REG_LPI_AP); + } + mutex_unlock(&ar->conf_mutex); return 0; diff --git a/drivers/net/wireless/ath/ath11k/wmi.c b/drivers/net/wireless/ath/ath11k/wmi.c index 7e604d4b9a77..5c6f3bdcb4af 100644 --- a/drivers/net/wireless/ath/ath11k/wmi.c +++ b/drivers/net/wireless/ath/ath11k/wmi.c @@ -9687,3 +9687,9 @@ int ath11k_wmi_sta_keepalive(struct ath11k *ar, return ath11k_wmi_cmd_send(wmi, skb, WMI_STA_KEEPALIVE_CMDID); } + +bool ath11k_wmi_supports_6ghz_cc_ext(struct ath11k *ar) +{ + return test_bit(WMI_TLV_SERVICE_REG_CC_EXT_EVENT_SUPPORT, + ar->ab->wmi_ab.svc_map) && ar->supports_6ghz; +} diff --git a/drivers/net/wireless/ath/ath11k/wmi.h b/drivers/net/wireless/ath/ath11k/wmi.h index a466d2bb4bb8..528756198a7a 100644 --- a/drivers/net/wireless/ath/ath11k/wmi.h +++ b/drivers/net/wireless/ath/ath11k/wmi.h @@ -6480,5 +6480,6 @@ int ath11k_wmi_pdev_set_bios_sar_table_param(struct ath11k *ar, const u8 *sar_va int ath11k_wmi_pdev_set_bios_geo_table_param(struct ath11k *ar); int ath11k_wmi_sta_keepalive(struct ath11k *ar, const struct wmi_sta_keepalive_arg *arg); +bool ath11k_wmi_supports_6ghz_cc_ext(struct ath11k *ar); #endif From 1329beb56297021042788223e666f6ccd2e11a0a Mon Sep 17 00:00:00 2001 From: Wen Gong Date: Thu, 11 Jan 2024 15:56:58 +0200 Subject: [PATCH 24/71] wifi: ath11k: update regulatory rules when connect to AP on 6 GHz band for station When station connect to AP on 6 GHz band, it needs switch the regulatory rules according to the regulatory info sub field in HE operation element. Switch to the power type which AP used for station interface. Tested-on: WCN6855 hw2.0 PCI WLAN.HSP.1.1-03125-QCAHSPSWPL_V1_V2_SILICONZ_LITE-3.6510.23 Signed-off-by: Wen Gong Acked-by: Jeff Johnson Signed-off-by: Baochen Qiang Signed-off-by: Kalle Valo Link: https://msgid.link/20231218085844.2658-6-quic_bqiang@quicinc.com --- drivers/net/wireless/ath/ath11k/mac.c | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/drivers/net/wireless/ath/ath11k/mac.c b/drivers/net/wireless/ath/ath11k/mac.c index 3f52428433d1..0b2b79ca5b1d 100644 --- a/drivers/net/wireless/ath/ath11k/mac.c +++ b/drivers/net/wireless/ath/ath11k/mac.c @@ -7619,6 +7619,8 @@ ath11k_mac_op_assign_vif_chanctx(struct ieee80211_hw *hw, struct ath11k_vif *arvif = ath11k_vif_to_arvif(vif); int ret; struct peer_create_params param; + struct cur_regulatory_info *reg_info; + enum ieee80211_ap_reg_power power_type; mutex_lock(&ar->conf_mutex); @@ -7626,6 +7628,22 @@ ath11k_mac_op_assign_vif_chanctx(struct ieee80211_hw *hw, "chanctx assign ptr %p vdev_id %i\n", ctx, arvif->vdev_id); + if (ath11k_wmi_supports_6ghz_cc_ext(ar) && + ctx->def.chan->band == NL80211_BAND_6GHZ && + arvif->vdev_type == WMI_VDEV_TYPE_STA) { + reg_info = &ab->reg_info_store[ar->pdev_idx]; + power_type = vif->bss_conf.power_type; + + ath11k_dbg(ab, ATH11K_DBG_MAC, "chanctx power type %d\n", power_type); + + if (power_type == IEEE80211_REG_UNSET_AP) { + ret = -EINVAL; + goto out; + } + + ath11k_reg_handle_chan_list(ab, reg_info, power_type); + } + /* for QCA6390 bss peer must be created before vdev_start */ if (ab->hw_params.vdev_start_delay && arvif->vdev_type != WMI_VDEV_TYPE_AP && From 28f64d368b21c551d5faf33687e7228531256d10 Mon Sep 17 00:00:00 2001 From: Wen Gong Date: Thu, 11 Jan 2024 15:56:58 +0200 Subject: [PATCH 25/71] wifi: ath11k: save power spectral density(PSD) of regulatory rule Save the power spectral density (PSD) report from firmware to struct ieee80211_reg_rule. Tested-on: WCN6855 hw2.0 PCI WLAN.HSP.1.1-03125-QCAHSPSWPL_V1_V2_SILICONZ_LITE-3.6510.23 Signed-off-by: Wen Gong Acked-by: Jeff Johnson Signed-off-by: Baochen Qiang Signed-off-by: Kalle Valo Link: https://msgid.link/20231218085844.2658-7-quic_bqiang@quicinc.com --- drivers/net/wireless/ath/ath11k/reg.c | 18 +++++++++++++----- 1 file changed, 13 insertions(+), 5 deletions(-) diff --git a/drivers/net/wireless/ath/ath11k/reg.c b/drivers/net/wireless/ath/ath11k/reg.c index d4fd3509e608..737fcd450d4b 100644 --- a/drivers/net/wireless/ath/ath11k/reg.c +++ b/drivers/net/wireless/ath/ath11k/reg.c @@ -425,6 +425,11 @@ static void ath11k_reg_intersect_rules(struct ieee80211_reg_rule *rule1, /* Use the flags of both the rules */ new_rule->flags = rule1->flags | rule2->flags; + if ((rule1->flags & NL80211_RRF_PSD) && (rule2->flags & NL80211_RRF_PSD)) + new_rule->psd = min_t(s8, rule1->psd, rule2->psd); + else + new_rule->flags &= ~NL80211_RRF_PSD; + /* To be safe, lts use the max cac timeout of both rules */ new_rule->dfs_cac_ms = max_t(u32, rule1->dfs_cac_ms, rule2->dfs_cac_ms); @@ -527,13 +532,14 @@ ath11k_reg_adjust_bw(u16 start_freq, u16 end_freq, u16 max_bw) static void ath11k_reg_update_rule(struct ieee80211_reg_rule *reg_rule, u32 start_freq, u32 end_freq, u32 bw, u32 ant_gain, u32 reg_pwr, - u32 reg_flags) + s8 psd, u32 reg_flags) { reg_rule->freq_range.start_freq_khz = MHZ_TO_KHZ(start_freq); reg_rule->freq_range.end_freq_khz = MHZ_TO_KHZ(end_freq); reg_rule->freq_range.max_bandwidth_khz = MHZ_TO_KHZ(bw); reg_rule->power_rule.max_antenna_gain = DBI_TO_MBI(ant_gain); reg_rule->power_rule.max_eirp = DBM_TO_MBM(reg_pwr); + reg_rule->psd = psd; reg_rule->flags = reg_flags; } @@ -563,7 +569,7 @@ ath11k_reg_update_weather_radar_band(struct ath11k_base *ab, reg_rule->start_freq, ETSI_WEATHER_RADAR_BAND_LOW, bw, reg_rule->ant_gain, reg_rule->reg_power, - flags); + reg_rule->psd_eirp, flags); ath11k_dbg(ab, ATH11K_DBG_REG, "\t%d. (%d - %d @ %d) (%d, %d) (%d ms) (FLAGS %d)\n", @@ -584,7 +590,7 @@ ath11k_reg_update_weather_radar_band(struct ath11k_base *ab, ath11k_reg_update_rule(regd->reg_rules + i, start_freq, end_freq, bw, reg_rule->ant_gain, - reg_rule->reg_power, flags); + reg_rule->reg_power, reg_rule->psd_eirp, flags); regd->reg_rules[i].dfs_cac_ms = ETSI_WEATHER_RADAR_BAND_CAC_TIMEOUT; @@ -605,7 +611,7 @@ ath11k_reg_update_weather_radar_band(struct ath11k_base *ab, ETSI_WEATHER_RADAR_BAND_HIGH, reg_rule->end_freq, bw, reg_rule->ant_gain, reg_rule->reg_power, - flags); + reg_rule->psd_eirp, flags); ath11k_dbg(ab, ATH11K_DBG_REG, "\t%d. (%d - %d @ %d) (%d, %d) (%d ms) (FLAGS %d)\n", @@ -731,6 +737,8 @@ ath11k_reg_build_regd(struct ath11k_base *ab, reg_rule = reg_rule_6ghz + k++; max_bw = min_t(u16, reg_rule->max_bw, max_bw_6ghz); flags = NL80211_RRF_AUTO_BW; + if (reg_rule->psd_flag) + flags |= NL80211_RRF_PSD; } else { break; } @@ -742,7 +750,7 @@ ath11k_reg_build_regd(struct ath11k_base *ab, reg_rule->start_freq, reg_rule->end_freq, max_bw, reg_rule->ant_gain, reg_rule->reg_power, - flags); + reg_rule->psd_eirp, flags); /* Update dfs cac timeout if the dfs domain is ETSI and the * new rule covers weather radar band. From 6f4e235be6550f67791616d88682fb99f4e670e4 Mon Sep 17 00:00:00 2001 From: Wen Gong Date: Thu, 11 Jan 2024 15:56:58 +0200 Subject: [PATCH 26/71] wifi: ath11k: add parse of transmit power envelope element MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The transmit power envelope element has some fields for power, ath11k should parse it according to IEEE Std 802.11ax™‐2021. Tested-on: WCN6855 hw2.0 PCI WLAN.HSP.1.1-03125-QCAHSPSWPL_V1_V2_SILICONZ_LITE-3.6510.23 Signed-off-by: Wen Gong Acked-by: Jeff Johnson Signed-off-by: Baochen Qiang Signed-off-by: Kalle Valo Link: https://msgid.link/20231218085844.2658-8-quic_bqiang@quicinc.com --- drivers/net/wireless/ath/ath11k/core.h | 39 +++++ drivers/net/wireless/ath/ath11k/mac.c | 188 +++++++++++++++++++++++++ 2 files changed, 227 insertions(+) diff --git a/drivers/net/wireless/ath/ath11k/core.h b/drivers/net/wireless/ath/ath11k/core.h index cc91f7d3ca8e..9a398de5dc44 100644 --- a/drivers/net/wireless/ath/ath11k/core.h +++ b/drivers/net/wireless/ath/ath11k/core.h @@ -314,6 +314,43 @@ struct ath11k_rekey_data { bool enable_offload; }; +/** + * struct ath11k_chan_power_info - TPE containing power info per channel chunk + * @chan_cfreq: channel center freq (MHz) + * e.g. + * channel 37/20 MHz, it is 6135 + * channel 37/40 MHz, it is 6125 + * channel 37/80 MHz, it is 6145 + * channel 37/160 MHz, it is 6185 + * @tx_power: transmit power (dBm) + */ +struct ath11k_chan_power_info { + u16 chan_cfreq; + s8 tx_power; +}; + +/** + * struct ath11k_reg_tpc_power_info - regulatory TPC power info + * @is_psd_power: is PSD power or not + * @eirp_power: Maximum EIRP power (dBm), valid only if power is PSD + * @ap_power_type: type of power (SP/LPI/VLP) + * @num_pwr_levels: number of power levels + * @reg_max: Array of maximum TX power (dBm) per PSD value + * @ap_constraint_power: AP constraint power (dBm) + * @tpe: TPE values processed from TPE IE + * @chan_power_info: power info to send to firmware + */ +struct ath11k_reg_tpc_power_info { + bool is_psd_power; + u8 eirp_power; + enum wmi_reg_6ghz_ap_type ap_power_type; + u8 num_pwr_levels; + u8 reg_max[IEEE80211_MAX_NUM_PWR_LEVEL]; + u8 ap_constraint_power; + s8 tpe[IEEE80211_MAX_NUM_PWR_LEVEL]; + struct ath11k_chan_power_info chan_power_info[IEEE80211_MAX_NUM_PWR_LEVEL]; +}; + struct ath11k_vif { u32 vdev_id; enum wmi_vdev_type vdev_type; @@ -369,6 +406,8 @@ struct ath11k_vif { struct ath11k_arp_ns_offload arp_ns_offload; struct ath11k_rekey_data rekey_data; + struct ath11k_reg_tpc_power_info reg_tpc_info; + #ifdef CONFIG_ATH11K_DEBUGFS struct dentry *debugfs_twt; #endif /* CONFIG_ATH11K_DEBUGFS */ diff --git a/drivers/net/wireless/ath/ath11k/mac.c b/drivers/net/wireless/ath/ath11k/mac.c index 0b2b79ca5b1d..4be5b2a35ec9 100644 --- a/drivers/net/wireless/ath/ath11k/mac.c +++ b/drivers/net/wireless/ath/ath11k/mac.c @@ -7608,6 +7608,192 @@ static int ath11k_start_vdev_delay(struct ieee80211_hw *hw, return 0; } +static u8 ath11k_mac_get_tpe_count(u8 txpwr_intrprt, u8 txpwr_cnt) +{ + switch (txpwr_intrprt) { + /* Refer "Table 9-276-Meaning of Maximum Transmit Power Count subfield + * if the Maximum Transmit Power Interpretation subfield is 0 or 2" of + * "IEEE Std 802.11ax 2021". + */ + case IEEE80211_TPE_LOCAL_EIRP: + case IEEE80211_TPE_REG_CLIENT_EIRP: + txpwr_cnt = txpwr_cnt <= 3 ? txpwr_cnt : 3; + txpwr_cnt = txpwr_cnt + 1; + break; + /* Refer "Table 9-277-Meaning of Maximum Transmit Power Count subfield + * if Maximum Transmit Power Interpretation subfield is 1 or 3" of + * "IEEE Std 802.11ax 2021". + */ + case IEEE80211_TPE_LOCAL_EIRP_PSD: + case IEEE80211_TPE_REG_CLIENT_EIRP_PSD: + txpwr_cnt = txpwr_cnt <= 4 ? txpwr_cnt : 4; + txpwr_cnt = txpwr_cnt ? (BIT(txpwr_cnt - 1)) : 1; + break; + } + + return txpwr_cnt; +} + +static u8 ath11k_mac_get_num_pwr_levels(struct cfg80211_chan_def *chan_def) +{ + if (chan_def->chan->flags & IEEE80211_CHAN_PSD) { + switch (chan_def->width) { + case NL80211_CHAN_WIDTH_20: + return 1; + case NL80211_CHAN_WIDTH_40: + return 2; + case NL80211_CHAN_WIDTH_80: + return 4; + case NL80211_CHAN_WIDTH_80P80: + case NL80211_CHAN_WIDTH_160: + return 8; + default: + return 1; + } + } else { + switch (chan_def->width) { + case NL80211_CHAN_WIDTH_20: + return 1; + case NL80211_CHAN_WIDTH_40: + return 2; + case NL80211_CHAN_WIDTH_80: + return 3; + case NL80211_CHAN_WIDTH_80P80: + case NL80211_CHAN_WIDTH_160: + return 4; + default: + return 1; + } + } +} + +static void ath11k_mac_parse_tx_pwr_env(struct ath11k *ar, + struct ieee80211_vif *vif, + struct ieee80211_chanctx_conf *ctx) +{ + struct ath11k_base *ab = ar->ab; + struct ath11k_vif *arvif = (void *)vif->drv_priv; + struct ieee80211_bss_conf *bss_conf = &vif->bss_conf; + struct ieee80211_tx_pwr_env *single_tpe; + enum wmi_reg_6ghz_client_type client_type; + struct cur_regulatory_info *reg_info; + int i; + u8 pwr_count, pwr_interpret, pwr_category; + u8 psd_index = 0, non_psd_index = 0, local_tpe_count = 0, reg_tpe_count = 0; + bool use_local_tpe, non_psd_set = false, psd_set = false; + + reg_info = &ab->reg_info_store[ar->pdev_idx]; + client_type = reg_info->client_type; + + for (i = 0; i < bss_conf->tx_pwr_env_num; i++) { + single_tpe = &bss_conf->tx_pwr_env[i]; + pwr_category = u8_get_bits(single_tpe->tx_power_info, + IEEE80211_TX_PWR_ENV_INFO_CATEGORY); + pwr_interpret = u8_get_bits(single_tpe->tx_power_info, + IEEE80211_TX_PWR_ENV_INFO_INTERPRET); + + if (pwr_category == client_type) { + if (pwr_interpret == IEEE80211_TPE_LOCAL_EIRP || + pwr_interpret == IEEE80211_TPE_LOCAL_EIRP_PSD) + local_tpe_count++; + else if (pwr_interpret == IEEE80211_TPE_REG_CLIENT_EIRP || + pwr_interpret == IEEE80211_TPE_REG_CLIENT_EIRP_PSD) + reg_tpe_count++; + } + } + + if (!reg_tpe_count && !local_tpe_count) { + ath11k_warn(ab, + "no transmit power envelope match client power type %d\n", + client_type); + return; + } else if (!reg_tpe_count) { + use_local_tpe = true; + } else { + use_local_tpe = false; + } + + for (i = 0; i < bss_conf->tx_pwr_env_num; i++) { + single_tpe = &bss_conf->tx_pwr_env[i]; + pwr_category = u8_get_bits(single_tpe->tx_power_info, + IEEE80211_TX_PWR_ENV_INFO_CATEGORY); + pwr_interpret = u8_get_bits(single_tpe->tx_power_info, + IEEE80211_TX_PWR_ENV_INFO_INTERPRET); + + if (pwr_category != client_type) + continue; + + /* get local transmit power envelope */ + if (use_local_tpe) { + if (pwr_interpret == IEEE80211_TPE_LOCAL_EIRP) { + non_psd_index = i; + non_psd_set = true; + } else if (pwr_interpret == IEEE80211_TPE_LOCAL_EIRP_PSD) { + psd_index = i; + psd_set = true; + } + /* get regulatory transmit power envelope */ + } else { + if (pwr_interpret == IEEE80211_TPE_REG_CLIENT_EIRP) { + non_psd_index = i; + non_psd_set = true; + } else if (pwr_interpret == IEEE80211_TPE_REG_CLIENT_EIRP_PSD) { + psd_index = i; + psd_set = true; + } + } + } + + if (non_psd_set && !psd_set) { + single_tpe = &bss_conf->tx_pwr_env[non_psd_index]; + pwr_count = u8_get_bits(single_tpe->tx_power_info, + IEEE80211_TX_PWR_ENV_INFO_COUNT); + pwr_interpret = u8_get_bits(single_tpe->tx_power_info, + IEEE80211_TX_PWR_ENV_INFO_INTERPRET); + arvif->reg_tpc_info.is_psd_power = false; + arvif->reg_tpc_info.eirp_power = 0; + + arvif->reg_tpc_info.num_pwr_levels = + ath11k_mac_get_tpe_count(pwr_interpret, pwr_count); + + for (i = 0; i < arvif->reg_tpc_info.num_pwr_levels; i++) { + ath11k_dbg(ab, ATH11K_DBG_MAC, + "non PSD power[%d] : %d\n", + i, single_tpe->tx_power[i]); + arvif->reg_tpc_info.tpe[i] = single_tpe->tx_power[i] / 2; + } + } + + if (psd_set) { + single_tpe = &bss_conf->tx_pwr_env[psd_index]; + pwr_count = u8_get_bits(single_tpe->tx_power_info, + IEEE80211_TX_PWR_ENV_INFO_COUNT); + pwr_interpret = u8_get_bits(single_tpe->tx_power_info, + IEEE80211_TX_PWR_ENV_INFO_INTERPRET); + arvif->reg_tpc_info.is_psd_power = true; + + if (pwr_count == 0) { + ath11k_dbg(ab, ATH11K_DBG_MAC, + "TPE PSD power : %d\n", single_tpe->tx_power[0]); + arvif->reg_tpc_info.num_pwr_levels = + ath11k_mac_get_num_pwr_levels(&ctx->def); + + for (i = 0; i < arvif->reg_tpc_info.num_pwr_levels; i++) + arvif->reg_tpc_info.tpe[i] = single_tpe->tx_power[0] / 2; + } else { + arvif->reg_tpc_info.num_pwr_levels = + ath11k_mac_get_tpe_count(pwr_interpret, pwr_count); + + for (i = 0; i < arvif->reg_tpc_info.num_pwr_levels; i++) { + ath11k_dbg(ab, ATH11K_DBG_MAC, + "TPE PSD power[%d] : %d\n", + i, single_tpe->tx_power[i]); + arvif->reg_tpc_info.tpe[i] = single_tpe->tx_power[i] / 2; + } + } + } +} + static int ath11k_mac_op_assign_vif_chanctx(struct ieee80211_hw *hw, struct ieee80211_vif *vif, @@ -7642,6 +7828,8 @@ ath11k_mac_op_assign_vif_chanctx(struct ieee80211_hw *hw, } ath11k_reg_handle_chan_list(ab, reg_info, power_type); + + ath11k_mac_parse_tx_pwr_env(ar, vif, ctx); } /* for QCA6390 bss peer must be created before vdev_start */ From 46f20de2c4f8faadea12679a3edb2082f35dcf1e Mon Sep 17 00:00:00 2001 From: Wen Gong Date: Thu, 11 Jan 2024 15:56:58 +0200 Subject: [PATCH 27/71] wifi: ath11k: save max transmit power in vdev start response event from firmware Save the max transmit power received in the vdev start response event from firmware. A subsequent patch will use this to calculate the final power value for WMI_VDEV_SET_TPC_POWER_CMDID. Tested-on: WCN6855 hw2.0 PCI WLAN.HSP.1.1-03125-QCAHSPSWPL_V1_V2_SILICONZ_LITE-3.6510.23 Signed-off-by: Wen Gong Acked-by: Jeff Johnson Signed-off-by: Baochen Qiang Signed-off-by: Kalle Valo Link: https://msgid.link/20231218085844.2658-9-quic_bqiang@quicinc.com --- drivers/net/wireless/ath/ath11k/core.h | 1 + drivers/net/wireless/ath/ath11k/wmi.c | 3 ++- drivers/net/wireless/ath/ath11k/wmi.h | 1 + 3 files changed, 4 insertions(+), 1 deletion(-) diff --git a/drivers/net/wireless/ath/ath11k/core.h b/drivers/net/wireless/ath/ath11k/core.h index 9a398de5dc44..12fa5b28520f 100644 --- a/drivers/net/wireless/ath/ath11k/core.h +++ b/drivers/net/wireless/ath/ath11k/core.h @@ -778,6 +778,7 @@ struct ath11k { /* protected by conf_mutex */ bool ps_state_enable; bool ps_timekeeper_enable; + s8 max_allowed_tx_power; }; struct ath11k_band_cap { diff --git a/drivers/net/wireless/ath/ath11k/wmi.c b/drivers/net/wireless/ath/ath11k/wmi.c index 5c6f3bdcb4af..3a3a2b697119 100644 --- a/drivers/net/wireless/ath/ath11k/wmi.c +++ b/drivers/net/wireless/ath/ath11k/wmi.c @@ -5036,6 +5036,7 @@ static int ath11k_pull_vdev_start_resp_tlv(struct ath11k_base *ab, struct sk_buf vdev_rsp->mac_id = ev->mac_id; vdev_rsp->cfgd_tx_streams = ev->cfgd_tx_streams; vdev_rsp->cfgd_rx_streams = ev->cfgd_rx_streams; + vdev_rsp->max_allowed_tx_power = ev->max_allowed_tx_power; kfree(tb); return 0; @@ -7257,7 +7258,7 @@ static void ath11k_vdev_start_resp_event(struct ath11k_base *ab, struct sk_buff } ar->last_wmi_vdev_start_status = 0; - + ar->max_allowed_tx_power = vdev_start_resp.max_allowed_tx_power; status = vdev_start_resp.status; if (WARN_ON_ONCE(status)) { diff --git a/drivers/net/wireless/ath/ath11k/wmi.h b/drivers/net/wireless/ath/ath11k/wmi.h index 528756198a7a..7f6287f22cf5 100644 --- a/drivers/net/wireless/ath/ath11k/wmi.h +++ b/drivers/net/wireless/ath/ath11k/wmi.h @@ -4119,6 +4119,7 @@ struct wmi_vdev_start_resp_event { }; u32 cfgd_tx_streams; u32 cfgd_rx_streams; + s32 max_allowed_tx_power; } __packed; /* VDEV start response status codes */ From 92425f788feede9bf152ecf3fb7a264942ee7719 Mon Sep 17 00:00:00 2001 From: Wen Gong Date: Thu, 11 Jan 2024 15:56:58 +0200 Subject: [PATCH 28/71] wifi: ath11k: fill parameters for vdev set tpc power WMI command Prepare the parameters which are needed for WMI command WMI_VDEV_SET_TPC_POWER_CMDID. Tested-on: WCN6855 hw2.0 PCI WLAN.HSP.1.1-03125-QCAHSPSWPL_V1_V2_SILICONZ_LITE-3.6510.23 Signed-off-by: Wen Gong Acked-by: Jeff Johnson Signed-off-by: Baochen Qiang Signed-off-by: Kalle Valo Link: https://msgid.link/20231218085844.2658-10-quic_bqiang@quicinc.com --- drivers/net/wireless/ath/ath11k/mac.c | 284 ++++++++++++++++++++++++++ drivers/net/wireless/ath/ath11k/mac.h | 5 +- 2 files changed, 288 insertions(+), 1 deletion(-) diff --git a/drivers/net/wireless/ath/ath11k/mac.c b/drivers/net/wireless/ath/ath11k/mac.c index 4be5b2a35ec9..f812a6f44b82 100644 --- a/drivers/net/wireless/ath/ath11k/mac.c +++ b/drivers/net/wireless/ath/ath11k/mac.c @@ -7667,6 +7667,290 @@ static u8 ath11k_mac_get_num_pwr_levels(struct cfg80211_chan_def *chan_def) } } +static u16 ath11k_mac_get_6ghz_start_frequency(struct cfg80211_chan_def *chan_def) +{ + u16 diff_seq; + + /* It is to get the lowest channel number's center frequency of the chan. + * For example, + * bandwidth=40 MHz, center frequency is 5965, lowest channel is 1 + * with center frequency 5955, its diff is 5965 - 5955 = 10. + * bandwidth=80 MHz, center frequency is 5985, lowest channel is 1 + * with center frequency 5955, its diff is 5985 - 5955 = 30. + * bandwidth=160 MHz, center frequency is 6025, lowest channel is 1 + * with center frequency 5955, its diff is 6025 - 5955 = 70. + */ + switch (chan_def->width) { + case NL80211_CHAN_WIDTH_160: + diff_seq = 70; + break; + case NL80211_CHAN_WIDTH_80: + case NL80211_CHAN_WIDTH_80P80: + diff_seq = 30; + break; + case NL80211_CHAN_WIDTH_40: + diff_seq = 10; + break; + default: + diff_seq = 0; + } + + return chan_def->center_freq1 - diff_seq; +} + +static u16 ath11k_mac_get_seg_freq(struct cfg80211_chan_def *chan_def, + u16 start_seq, u8 seq) +{ + u16 seg_seq; + + /* It is to get the center frequency of the specific bandwidth. + * start_seq means the lowest channel number's center frequency. + * seq 0/1/2/3 means 20 MHz/40 MHz/80 MHz/160 MHz&80P80. + * For example, + * lowest channel is 1, its center frequency 5955, + * center frequency is 5955 when bandwidth=20 MHz, its diff is 5955 - 5955 = 0. + * lowest channel is 1, its center frequency 5955, + * center frequency is 5965 when bandwidth=40 MHz, its diff is 5965 - 5955 = 10. + * lowest channel is 1, its center frequency 5955, + * center frequency is 5985 when bandwidth=80 MHz, its diff is 5985 - 5955 = 30. + * lowest channel is 1, its center frequency 5955, + * center frequency is 6025 when bandwidth=160 MHz, its diff is 6025 - 5955 = 70. + */ + if (chan_def->width == NL80211_CHAN_WIDTH_80P80 && seq == 3) + return chan_def->center_freq2; + + seg_seq = 10 * (BIT(seq) - 1); + return seg_seq + start_seq; +} + +static void ath11k_mac_get_psd_channel(struct ath11k *ar, + u16 step_freq, + u16 *start_freq, + u16 *center_freq, + u8 i, + struct ieee80211_channel **temp_chan, + s8 *tx_power) +{ + /* It is to get the center frequency for each 20 MHz. + * For example, if the chan is 160 MHz and center frequency is 6025, + * then it include 8 channels, they are 1/5/9/13/17/21/25/29, + * channel number 1's center frequency is 5955, it is parameter start_freq. + * parameter i is the step of the 8 channels. i is 0~7 for the 8 channels. + * the channel 1/5/9/13/17/21/25/29 maps i=0/1/2/3/4/5/6/7, + * and maps its center frequency is 5955/5975/5995/6015/6035/6055/6075/6095, + * the gap is 20 for each channel, parameter step_freq means the gap. + * after get the center frequency of each channel, it is easy to find the + * struct ieee80211_channel of it and get the max_reg_power. + */ + *center_freq = *start_freq + i * step_freq; + *temp_chan = ieee80211_get_channel(ar->hw->wiphy, *center_freq); + *tx_power = (*temp_chan)->max_reg_power; +} + +static void ath11k_mac_get_eirp_power(struct ath11k *ar, + u16 *start_freq, + u16 *center_freq, + u8 i, + struct ieee80211_channel **temp_chan, + struct cfg80211_chan_def *def, + s8 *tx_power) +{ + /* It is to get the center frequency for 20 MHz/40 MHz/80 MHz/ + * 160 MHz&80P80 bandwidth, and then plus 10 to the center frequency, + * it is the center frequency of a channel number. + * For example, when configured channel number is 1. + * center frequency is 5965 when bandwidth=40 MHz, after plus 10, it is 5975, + * then it is channel number 5. + * center frequency is 5985 when bandwidth=80 MHz, after plus 10, it is 5995, + * then it is channel number 9. + * center frequency is 6025 when bandwidth=160 MHz, after plus 10, it is 6035, + * then it is channel number 17. + * after get the center frequency of each channel, it is easy to find the + * struct ieee80211_channel of it and get the max_reg_power. + */ + *center_freq = ath11k_mac_get_seg_freq(def, *start_freq, i); + + /* For the 20 MHz, its center frequency is same with same channel */ + if (i != 0) + *center_freq += 10; + + *temp_chan = ieee80211_get_channel(ar->hw->wiphy, *center_freq); + *tx_power = (*temp_chan)->max_reg_power; +} + +void ath11k_mac_fill_reg_tpc_info(struct ath11k *ar, + struct ieee80211_vif *vif, + struct ieee80211_chanctx_conf *ctx) +{ + struct ath11k_base *ab = ar->ab; + struct ath11k_vif *arvif = (void *)vif->drv_priv; + struct ieee80211_bss_conf *bss_conf = &vif->bss_conf; + struct ath11k_reg_tpc_power_info *reg_tpc_info = &arvif->reg_tpc_info; + struct ieee80211_channel *chan, *temp_chan; + u8 pwr_lvl_idx, num_pwr_levels, pwr_reduction; + bool is_psd_power = false, is_tpe_present = false; + s8 max_tx_power[IEEE80211_MAX_NUM_PWR_LEVEL], + psd_power, tx_power, eirp_power; + u16 start_freq, center_freq; + + chan = ctx->def.chan; + start_freq = ath11k_mac_get_6ghz_start_frequency(&ctx->def); + pwr_reduction = bss_conf->pwr_reduction; + + if (arvif->reg_tpc_info.num_pwr_levels) { + is_tpe_present = true; + num_pwr_levels = arvif->reg_tpc_info.num_pwr_levels; + } else { + num_pwr_levels = ath11k_mac_get_num_pwr_levels(&ctx->def); + } + + for (pwr_lvl_idx = 0; pwr_lvl_idx < num_pwr_levels; pwr_lvl_idx++) { + /* STA received TPE IE*/ + if (is_tpe_present) { + /* local power is PSD power*/ + if (chan->flags & IEEE80211_CHAN_PSD) { + /* Connecting AP is psd power */ + if (reg_tpc_info->is_psd_power) { + is_psd_power = true; + ath11k_mac_get_psd_channel(ar, 20, + &start_freq, + ¢er_freq, + pwr_lvl_idx, + &temp_chan, + &tx_power); + psd_power = temp_chan->psd; + eirp_power = tx_power; + max_tx_power[pwr_lvl_idx] = + min_t(s8, + psd_power, + reg_tpc_info->tpe[pwr_lvl_idx]); + /* Connecting AP is not psd power */ + } else { + ath11k_mac_get_eirp_power(ar, + &start_freq, + ¢er_freq, + pwr_lvl_idx, + &temp_chan, + &ctx->def, + &tx_power); + psd_power = temp_chan->psd; + /* convert psd power to EIRP power based + * on channel width + */ + tx_power = + min_t(s8, tx_power, + psd_power + 13 + pwr_lvl_idx * 3); + max_tx_power[pwr_lvl_idx] = + min_t(s8, + tx_power, + reg_tpc_info->tpe[pwr_lvl_idx]); + } + /* local power is not PSD power */ + } else { + /* Connecting AP is psd power */ + if (reg_tpc_info->is_psd_power) { + is_psd_power = true; + ath11k_mac_get_psd_channel(ar, 20, + &start_freq, + ¢er_freq, + pwr_lvl_idx, + &temp_chan, + &tx_power); + eirp_power = tx_power; + max_tx_power[pwr_lvl_idx] = + reg_tpc_info->tpe[pwr_lvl_idx]; + /* Connecting AP is not psd power */ + } else { + ath11k_mac_get_eirp_power(ar, + &start_freq, + ¢er_freq, + pwr_lvl_idx, + &temp_chan, + &ctx->def, + &tx_power); + max_tx_power[pwr_lvl_idx] = + min_t(s8, + tx_power, + reg_tpc_info->tpe[pwr_lvl_idx]); + } + } + /* STA not received TPE IE */ + } else { + /* local power is PSD power*/ + if (chan->flags & IEEE80211_CHAN_PSD) { + is_psd_power = true; + ath11k_mac_get_psd_channel(ar, 20, + &start_freq, + ¢er_freq, + pwr_lvl_idx, + &temp_chan, + &tx_power); + psd_power = temp_chan->psd; + eirp_power = tx_power; + max_tx_power[pwr_lvl_idx] = psd_power; + } else { + ath11k_mac_get_eirp_power(ar, + &start_freq, + ¢er_freq, + pwr_lvl_idx, + &temp_chan, + &ctx->def, + &tx_power); + max_tx_power[pwr_lvl_idx] = tx_power; + } + } + + if (is_psd_power) { + /* If AP local power constraint is present */ + if (pwr_reduction) + eirp_power = eirp_power - pwr_reduction; + + /* If firmware updated max tx power is non zero, then take + * the min of firmware updated ap tx power + * and max power derived from above mentioned parameters. + */ + ath11k_dbg(ab, ATH11K_DBG_MAC, + "eirp power : %d firmware report power : %d\n", + eirp_power, ar->max_allowed_tx_power); + /* Firmware reports lower max_allowed_tx_power during vdev + * start response. In case of 6 GHz, firmware is not aware + * of EIRP power unless driver sets EIRP power through WMI + * TPC command. So radio which does not support idle power + * save can set maximum calculated EIRP power directly to + * firmware through TPC command without min comparison with + * vdev start response's max_allowed_tx_power. + */ + if (ar->max_allowed_tx_power && ab->hw_params.idle_ps) + eirp_power = min_t(s8, + eirp_power, + ar->max_allowed_tx_power); + } else { + /* If AP local power constraint is present */ + if (pwr_reduction) + max_tx_power[pwr_lvl_idx] = + max_tx_power[pwr_lvl_idx] - pwr_reduction; + /* If firmware updated max tx power is non zero, then take + * the min of firmware updated ap tx power + * and max power derived from above mentioned parameters. + */ + if (ar->max_allowed_tx_power && ab->hw_params.idle_ps) + max_tx_power[pwr_lvl_idx] = + min_t(s8, + max_tx_power[pwr_lvl_idx], + ar->max_allowed_tx_power); + } + reg_tpc_info->chan_power_info[pwr_lvl_idx].chan_cfreq = center_freq; + reg_tpc_info->chan_power_info[pwr_lvl_idx].tx_power = + max_tx_power[pwr_lvl_idx]; + } + + reg_tpc_info->num_pwr_levels = num_pwr_levels; + reg_tpc_info->is_psd_power = is_psd_power; + reg_tpc_info->eirp_power = eirp_power; + reg_tpc_info->ap_power_type = + ath11k_reg_ap_pwr_convert(vif->bss_conf.power_type); +} + static void ath11k_mac_parse_tx_pwr_env(struct ath11k *ar, struct ieee80211_vif *vif, struct ieee80211_chanctx_conf *ctx) diff --git a/drivers/net/wireless/ath/ath11k/mac.h b/drivers/net/wireless/ath/ath11k/mac.h index 0dfdeed5177b..f5800fbecff8 100644 --- a/drivers/net/wireless/ath/ath11k/mac.h +++ b/drivers/net/wireless/ath/ath11k/mac.h @@ -1,7 +1,7 @@ /* SPDX-License-Identifier: BSD-3-Clause-Clear */ /* * Copyright (c) 2018-2019 The Linux Foundation. All rights reserved. - * Copyright (c) 2021-2022 Qualcomm Innovation Center, Inc. All rights reserved. + * Copyright (c) 2021-2023 Qualcomm Innovation Center, Inc. All rights reserved. */ #ifndef ATH11K_MAC_H @@ -176,4 +176,7 @@ int ath11k_mac_wait_tx_complete(struct ath11k *ar); int ath11k_mac_vif_set_keepalive(struct ath11k_vif *arvif, enum wmi_sta_keepalive_method method, u32 interval); +void ath11k_mac_fill_reg_tpc_info(struct ath11k *ar, + struct ieee80211_vif *vif, + struct ieee80211_chanctx_conf *ctx); #endif From f8a573bd5f3b1c272c431831add259deabfd9948 Mon Sep 17 00:00:00 2001 From: Wen Gong Date: Thu, 11 Jan 2024 15:56:58 +0200 Subject: [PATCH 29/71] wifi: ath11k: add WMI_TLV_SERVICE_EXT_TPC_REG_SUPPORT service bit Firmware advertises support for SERVICE_EXT_TPC_REG via a WMI service bit. Add the definition of this service bit so that a subsequent patch can check whether or not firmware supports this service. Tested-on: WCN6855 hw2.0 PCI WLAN.HSP.1.1-03125-QCAHSPSWPL_V1_V2_SILICONZ_LITE-3.6510.23 Signed-off-by: Wen Gong Acked-by: Jeff Johnson Signed-off-by: Baochen Qiang Signed-off-by: Kalle Valo Link: https://msgid.link/20231218085844.2658-11-quic_bqiang@quicinc.com --- drivers/net/wireless/ath/ath11k/wmi.h | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/net/wireless/ath/ath11k/wmi.h b/drivers/net/wireless/ath/ath11k/wmi.h index 7f6287f22cf5..9ed802194a5b 100644 --- a/drivers/net/wireless/ath/ath11k/wmi.h +++ b/drivers/net/wireless/ath/ath11k/wmi.h @@ -2114,6 +2114,7 @@ enum wmi_tlv_service { /* The second 128 bits */ WMI_MAX_EXT_SERVICE = 256, WMI_TLV_SERVICE_SCAN_CONFIG_PER_CHANNEL = 265, + WMI_TLV_SERVICE_EXT_TPC_REG_SUPPORT = 280, WMI_TLV_SERVICE_REG_CC_EXT_EVENT_SUPPORT = 281, WMI_TLV_SERVICE_BIOS_SAR_SUPPORT = 326, WMI_TLV_SERVICE_SUPPORT_11D_FOR_HOST_SCAN = 357, From ed0a61dcb2d3936cf15dfc04341c4d0fc297919f Mon Sep 17 00:00:00 2001 From: Wen Gong Date: Thu, 11 Jan 2024 15:56:59 +0200 Subject: [PATCH 30/71] wifi: ath11k: add handler for WMI_VDEV_SET_TPC_POWER_CMDID Add the handler for WMI_VDEV_SET_TPC_POWER_CMDID, it is for 6 GHz band. Tested-on: WCN6855 hw2.0 PCI WLAN.HSP.1.1-03125-QCAHSPSWPL_V1_V2_SILICONZ_LITE-3.6510.23 Signed-off-by: Wen Gong Signed-off-by: Baochen Qiang Signed-off-by: Kalle Valo Link: https://msgid.link/20231218085844.2658-12-quic_bqiang@quicinc.com --- drivers/net/wireless/ath/ath11k/wmi.c | 64 +++++++++++++++++++++++++++ drivers/net/wireless/ath/ath11k/wmi.h | 57 ++++++++++++++++++++++++ 2 files changed, 121 insertions(+) diff --git a/drivers/net/wireless/ath/ath11k/wmi.c b/drivers/net/wireless/ath/ath11k/wmi.c index 3a3a2b697119..688ee20528a0 100644 --- a/drivers/net/wireless/ath/ath11k/wmi.c +++ b/drivers/net/wireless/ath/ath11k/wmi.c @@ -2379,6 +2379,70 @@ int ath11k_wmi_send_scan_start_cmd(struct ath11k *ar, return ret; } +int ath11k_wmi_send_vdev_set_tpc_power(struct ath11k *ar, + u32 vdev_id, + struct ath11k_reg_tpc_power_info *param) +{ + struct ath11k_pdev_wmi *wmi = ar->wmi; + struct wmi_vdev_set_tpc_power_cmd *cmd; + struct wmi_vdev_ch_power_info *ch; + struct sk_buff *skb; + struct wmi_tlv *tlv; + u8 *ptr; + int i, ret, len, array_len; + + array_len = sizeof(*ch) * param->num_pwr_levels; + len = sizeof(*cmd) + TLV_HDR_SIZE + array_len; + + skb = ath11k_wmi_alloc_skb(wmi->wmi_ab, len); + if (!skb) + return -ENOMEM; + + ptr = skb->data; + + cmd = (struct wmi_vdev_set_tpc_power_cmd *)ptr; + cmd->tlv_header = FIELD_PREP(WMI_TLV_TAG, WMI_TAG_VDEV_SET_TPC_POWER_CMD) | + FIELD_PREP(WMI_TLV_LEN, sizeof(*cmd) - TLV_HDR_SIZE); + cmd->vdev_id = vdev_id; + cmd->psd_power = param->is_psd_power; + cmd->eirp_power = param->eirp_power; + cmd->power_type_6ghz = param->ap_power_type; + + ath11k_dbg(ar->ab, ATH11K_DBG_WMI, + "tpc vdev id %d is psd power %d eirp power %d 6 ghz power type %d\n", + vdev_id, param->is_psd_power, param->eirp_power, param->ap_power_type); + + ptr += sizeof(*cmd); + tlv = (struct wmi_tlv *)ptr; + tlv->header = FIELD_PREP(WMI_TLV_TAG, WMI_TAG_ARRAY_STRUCT) | + FIELD_PREP(WMI_TLV_LEN, array_len); + + ptr += TLV_HDR_SIZE; + ch = (struct wmi_vdev_ch_power_info *)ptr; + + for (i = 0; i < param->num_pwr_levels; i++, ch++) { + ch->tlv_header = FIELD_PREP(WMI_TLV_TAG, + WMI_TAG_VDEV_CH_POWER_INFO) | + FIELD_PREP(WMI_TLV_LEN, + sizeof(*ch) - TLV_HDR_SIZE); + + ch->chan_cfreq = param->chan_power_info[i].chan_cfreq; + ch->tx_power = param->chan_power_info[i].tx_power; + + ath11k_dbg(ar->ab, ATH11K_DBG_WMI, "tpc chan freq %d TX power %d\n", + ch->chan_cfreq, ch->tx_power); + } + + ret = ath11k_wmi_cmd_send(wmi, skb, WMI_VDEV_SET_TPC_POWER_CMDID); + if (ret) { + ath11k_warn(ar->ab, "failed to send WMI_VDEV_SET_TPC_POWER_CMDID\n"); + dev_kfree_skb(skb); + return ret; + } + + return 0; +} + int ath11k_wmi_send_scan_stop_cmd(struct ath11k *ar, struct scan_cancel_param *param) { diff --git a/drivers/net/wireless/ath/ath11k/wmi.h b/drivers/net/wireless/ath/ath11k/wmi.h index 9ed802194a5b..6dcd14700570 100644 --- a/drivers/net/wireless/ath/ath11k/wmi.h +++ b/drivers/net/wireless/ath/ath11k/wmi.h @@ -15,6 +15,7 @@ struct ath11k; struct ath11k_fw_stats; struct ath11k_fw_dbglog; struct ath11k_vif; +struct ath11k_reg_tpc_power_info; #define PSOC_HOST_MAX_NUM_SS (8) @@ -327,6 +328,22 @@ enum wmi_tlv_cmd_id { WMI_VDEV_SET_CUSTOM_AGGR_SIZE_CMDID, WMI_VDEV_ENCRYPT_DECRYPT_DATA_REQ_CMDID, WMI_VDEV_ADD_MAC_ADDR_TO_RX_FILTER_CMDID, + WMI_VDEV_SET_ARP_STAT_CMDID, + WMI_VDEV_GET_ARP_STAT_CMDID, + WMI_VDEV_GET_TX_POWER_CMDID, + WMI_VDEV_LIMIT_OFFCHAN_CMDID, + WMI_VDEV_SET_CUSTOM_SW_RETRY_TH_CMDID, + WMI_VDEV_CHAINMASK_CONFIG_CMDID, + WMI_VDEV_GET_BCN_RECEPTION_STATS_CMDID, + WMI_VDEV_GET_MWS_COEX_INFO_CMDID, + WMI_VDEV_DELETE_ALL_PEER_CMDID, + WMI_VDEV_BSS_MAX_IDLE_TIME_CMDID, + WMI_VDEV_AUDIO_SYNC_TRIGGER_CMDID, + WMI_VDEV_AUDIO_SYNC_QTIMER_CMDID, + WMI_VDEV_SET_PCL_CMDID, + WMI_VDEV_GET_BIG_DATA_CMDID, + WMI_VDEV_GET_BIG_DATA_P2_CMDID, + WMI_VDEV_SET_TPC_POWER_CMDID, WMI_PEER_CREATE_CMDID = WMI_TLV_CMD(WMI_GRP_PEER), WMI_PEER_DELETE_CMDID, WMI_PEER_FLUSH_TIDS_CMDID, @@ -1880,6 +1897,8 @@ enum wmi_tlv_tag { WMI_TAG_PDEV_NON_SRG_OBSS_BSSID_ENABLE_BITMAP_CMD, WMI_TAG_REGULATORY_RULE_EXT_STRUCT = 0x3A9, WMI_TAG_REG_CHAN_LIST_CC_EXT_EVENT, + WMI_TAG_VDEV_SET_TPC_POWER_CMD = 0x3B5, + WMI_TAG_VDEV_CH_POWER_INFO, WMI_TAG_PDEV_SET_BIOS_SAR_TABLE_CMD = 0x3D8, WMI_TAG_PDEV_SET_BIOS_GEO_TABLE_CMD, WMI_TAG_MAX @@ -3169,6 +3188,41 @@ struct wlan_ssid { u8 ssid[WLAN_SSID_MAX_LEN]; }; +struct wmi_vdev_ch_power_info { + u32 tlv_header; + + /* Channel center frequency (MHz) */ + u32 chan_cfreq; + + /* Unit: dBm, either PSD/EIRP power for this frequency or + * incremental for non-PSD BW + */ + u32 tx_power; +} __packed; + +struct wmi_vdev_set_tpc_power_cmd { + u32 tlv_header; + u32 vdev_id; + + /* Value: 0 or 1, is PSD power or not */ + u32 psd_power; + + /* Maximum EIRP power (dBm units), valid only if power is PSD */ + u32 eirp_power; + + /* Type: WMI_6GHZ_REG_TYPE, used for halphy CTL lookup */ + u32 power_type_6ghz; + + /* This fixed_param TLV is followed by the below TLVs: + * num_pwr_levels of wmi_vdev_ch_power_info + * For PSD power, it is the PSD/EIRP power of the frequency (20 MHz chunks). + * For non-PSD power, the power values are for 20, 40, and till + * BSS BW power levels. + * The num_pwr_levels will be checked by sw how many elements present + * in the variable-length array. + */ +} __packed; + #define WMI_IE_BITMAP_SIZE 8 /* prefix used by scan requestor ids on the host */ @@ -6483,5 +6537,8 @@ int ath11k_wmi_pdev_set_bios_geo_table_param(struct ath11k *ar); int ath11k_wmi_sta_keepalive(struct ath11k *ar, const struct wmi_sta_keepalive_arg *arg); bool ath11k_wmi_supports_6ghz_cc_ext(struct ath11k *ar); +int ath11k_wmi_send_vdev_set_tpc_power(struct ath11k *ar, + u32 vdev_id, + struct ath11k_reg_tpc_power_info *param); #endif From 74ef2d05ede63fd6416aa635aa8972dff901325f Mon Sep 17 00:00:00 2001 From: Wen Gong Date: Thu, 11 Jan 2024 15:56:59 +0200 Subject: [PATCH 31/71] wifi: ath11k: use WMI_VDEV_SET_TPC_POWER_CMDID when EXT_TPC_REG_SUPPORT for 6 GHz When station is connected to a 6 GHz AP, it has 2 ways to configure the power limit to firmware. The first way is to send 2 WMI commands WMI_PDEV_PARAM_TXPOWER_LIMIT2G/WMI_PDEV_PARAM_TXPOWER_LIMIT5G to firmware, the second way is to send WMI_VDEV_SET_TPC_POWER_CMDID to firmware which include more parameters for power control. When firmware supports SERVICE_EXT_TPC_REG, it means firmware supports WMI_VDEV_SET_TPC_POWER_CMDID, then ath11k selects the second way. Tested-on: WCN6855 hw2.0 PCI WLAN.HSP.1.1-03125-QCAHSPSWPL_V1_V2_SILICONZ_LITE-3.6510.23 Signed-off-by: Wen Gong Signed-off-by: Baochen Qiang Signed-off-by: Kalle Valo Link: https://msgid.link/20231218085844.2658-13-quic_bqiang@quicinc.com --- drivers/net/wireless/ath/ath11k/mac.c | 24 ++++++++++++++++++++++-- 1 file changed, 22 insertions(+), 2 deletions(-) diff --git a/drivers/net/wireless/ath/ath11k/mac.c b/drivers/net/wireless/ath/ath11k/mac.c index f812a6f44b82..bf4a97967177 100644 --- a/drivers/net/wireless/ath/ath11k/mac.c +++ b/drivers/net/wireless/ath/ath11k/mac.c @@ -3397,6 +3397,18 @@ static int ath11k_mac_config_obss_pd(struct ath11k *ar, return 0; } +static bool ath11k_mac_supports_station_tpc(struct ath11k *ar, + struct ath11k_vif *arvif, + const struct cfg80211_chan_def *chandef) +{ + return ath11k_wmi_supports_6ghz_cc_ext(ar) && + test_bit(WMI_TLV_SERVICE_EXT_TPC_REG_SUPPORT, ar->ab->wmi_ab.svc_map) && + arvif->vdev_type == WMI_VDEV_TYPE_STA && + arvif->vdev_subtype == WMI_VDEV_SUBTYPE_NONE && + chandef->chan && + chandef->chan->band == NL80211_BAND_6GHZ; +} + static void ath11k_mac_op_bss_info_changed(struct ieee80211_hw *hw, struct ieee80211_vif *vif, struct ieee80211_bss_conf *info, @@ -3596,7 +3608,6 @@ static void ath11k_mac_op_bss_info_changed(struct ieee80211_hw *hw, if (changed & BSS_CHANGED_TXPOWER) { ath11k_dbg(ar->ab, ATH11K_DBG_MAC, "vdev_id %i txpower %d\n", arvif->vdev_id, info->txpower); - arvif->txpower = info->txpower; ath11k_mac_txpower_recalc(ar); } @@ -7285,6 +7296,15 @@ ath11k_mac_vdev_start_restart(struct ath11k_vif *arvif, return ret; } + /* TODO: For now we only set TPC power here. However when + * channel changes, say CSA, it should be updated again. + */ + if (ath11k_mac_supports_station_tpc(ar, arvif, chandef)) { + ath11k_mac_fill_reg_tpc_info(ar, arvif->vif, &arvif->chanctx); + ath11k_wmi_send_vdev_set_tpc_power(ar, arvif->vdev_id, + &arvif->reg_tpc_info); + } + if (!restart) ar->num_started_vdevs++; @@ -8112,7 +8132,7 @@ ath11k_mac_op_assign_vif_chanctx(struct ieee80211_hw *hw, } ath11k_reg_handle_chan_list(ab, reg_info, power_type); - + arvif->chanctx = *ctx; ath11k_mac_parse_tx_pwr_env(ar, vif, ctx); } From 59cf57ab3deea979ffc0a6f7c22f4331e59d32f0 Mon Sep 17 00:00:00 2001 From: Jeff Johnson Date: Thu, 11 Jan 2024 10:05:30 -0800 Subject: [PATCH 32/71] wifi: ath12k: Remove unnecessary struct qmi_txn initializers Currently most of the ath12k QMI messaging functions define their struct qmi_txn variables with a {} initializer. However, all of these functions subsequently call qmi_txn_init(), and the very first thing that function does is zero the struct. Hence, the initializers are unnecessary. Since these consume code space and cpu cycles, remove them. No functional changes, compile tested only. Signed-off-by: Jeff Johnson Signed-off-by: Kalle Valo Link: https://msgid.link/20240111-qmi-cleanup-v2-1-53343af953d5@quicinc.com --- drivers/net/wireless/ath/ath12k/qmi.c | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/drivers/net/wireless/ath/ath12k/qmi.c b/drivers/net/wireless/ath/ath12k/qmi.c index 536856234f3b..180e86c2a10c 100644 --- a/drivers/net/wireless/ath/ath12k/qmi.c +++ b/drivers/net/wireless/ath/ath12k/qmi.c @@ -1,7 +1,7 @@ // SPDX-License-Identifier: BSD-3-Clause-Clear /* * Copyright (c) 2018-2021 The Linux Foundation. All rights reserved. - * Copyright (c) 2021-2023 Qualcomm Innovation Center, Inc. All rights reserved. + * Copyright (c) 2021-2024 Qualcomm Innovation Center, Inc. All rights reserved. */ #include @@ -1921,7 +1921,7 @@ static int ath12k_qmi_host_cap_send(struct ath12k_base *ab) { 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)); @@ -2069,7 +2069,7 @@ static int ath12k_qmi_respond_fw_mem_request(struct ath12k_base *ab) { 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; @@ -2210,7 +2210,7 @@ static int ath12k_qmi_request_target_cap(struct ath12k_base *ab) { struct qmi_wlanfw_cap_req_msg_v01 req; struct qmi_wlanfw_cap_resp_msg_v01 resp; - struct qmi_txn txn = {}; + struct qmi_txn txn; unsigned int board_id = ATH12K_BOARD_ID_DEFAULT; int ret = 0; int r; @@ -2311,7 +2311,7 @@ static int ath12k_qmi_load_file_target_mem(struct ath12k_base *ab, { 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; int ret; u32 remaining = len; @@ -2547,7 +2547,7 @@ static int ath12k_qmi_wlanfw_m3_info_send(struct ath12k_base *ab) 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)); @@ -2598,7 +2598,7 @@ static int ath12k_qmi_wlanfw_mode_send(struct ath12k_base *ab, { 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)); @@ -2651,7 +2651,7 @@ static int ath12k_qmi_wlanfw_wlan_cfg_send(struct ath12k_base *ab) 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; From 2e82b5f09a97f1b98b885470c81c1248bec103af Mon Sep 17 00:00:00 2001 From: Jeff Johnson Date: Thu, 11 Jan 2024 10:05:31 -0800 Subject: [PATCH 33/71] wifi: ath12k: Add missing qmi_txn_cancel() calls Per the QMI documentation "A client calling qmi_txn_init() must call either qmi_txn_wait() or qmi_txn_cancel() to free up the allocated resources." Unfortunately, in most of the ath12k messaging functions, when qmi_send_request() fails, the function returns without performing the necessary cleanup. So update those functions to call qmi_txn_cancel() when qmi_send_request() fails. No functional changes, compile tested only. Signed-off-by: Jeff Johnson Signed-off-by: Kalle Valo Link: https://msgid.link/20240111-qmi-cleanup-v2-2-53343af953d5@quicinc.com --- drivers/net/wireless/ath/ath12k/qmi.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/drivers/net/wireless/ath/ath12k/qmi.c b/drivers/net/wireless/ath/ath12k/qmi.c index 180e86c2a10c..1f2df2e3fbce 100644 --- a/drivers/net/wireless/ath/ath12k/qmi.c +++ b/drivers/net/wireless/ath/ath12k/qmi.c @@ -1977,6 +1977,7 @@ static int ath12k_qmi_host_cap_send(struct ath12k_base *ab) 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); ath12k_warn(ab, "Failed to send host capability request,err = %d\n", ret); goto out; } @@ -2040,6 +2041,7 @@ static int ath12k_qmi_fw_ind_register_send(struct ath12k_base *ab) 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); ath12k_warn(ab, "Failed to send indication register request, err = %d\n", ret); goto out; @@ -2114,6 +2116,7 @@ static int ath12k_qmi_respond_fw_mem_request(struct ath12k_base *ab) 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); ath12k_warn(ab, "qmi failed to respond memory request, err = %d\n", ret); goto out; @@ -2229,6 +2232,7 @@ static int ath12k_qmi_request_target_cap(struct ath12k_base *ab) QMI_WLANFW_CAP_REQ_MSG_V01_MAX_LEN, qmi_wlanfw_cap_req_msg_v01_ei, &req); if (ret < 0) { + qmi_txn_cancel(&txn); ath12k_warn(ab, "qmi failed to send target cap request, err = %d\n", ret); goto out; @@ -2572,6 +2576,7 @@ static int ath12k_qmi_wlanfw_m3_info_send(struct ath12k_base *ab) 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); ath12k_warn(ab, "qmi failed to send M3 information request, err = %d\n", ret); goto out; @@ -2618,6 +2623,7 @@ static int ath12k_qmi_wlanfw_mode_send(struct ath12k_base *ab, 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); ath12k_warn(ab, "qmi failed to send mode request, mode: %d, err = %d\n", mode, ret); goto out; @@ -2709,6 +2715,7 @@ static int ath12k_qmi_wlanfw_wlan_cfg_send(struct ath12k_base *ab) 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); ath12k_warn(ab, "qmi failed to send wlan config request, err = %d\n", ret); goto out; From 6d2b0a066941c5d9c56c79d95c91dcec2fd7a7fa Mon Sep 17 00:00:00 2001 From: Jeff Johnson Date: Thu, 11 Jan 2024 10:05:32 -0800 Subject: [PATCH 34/71] wifi: ath12k: Use initializers for QMI message buffers Currently most of the QMI messaging functions use memset() to zero out the QMI message buffers. Prefer to use a {} initializer to allow the compiler to generate optimized code and avoid the function call overhead. No functional changes, compile tested only. Signed-off-by: Jeff Johnson Signed-off-by: Kalle Valo Link: https://msgid.link/20240111-qmi-cleanup-v2-3-53343af953d5@quicinc.com --- drivers/net/wireless/ath/ath12k/qmi.c | 40 ++++++++------------------- 1 file changed, 11 insertions(+), 29 deletions(-) diff --git a/drivers/net/wireless/ath/ath12k/qmi.c b/drivers/net/wireless/ath/ath12k/qmi.c index 1f2df2e3fbce..c4c7f31a91cd 100644 --- a/drivers/net/wireless/ath/ath12k/qmi.c +++ b/drivers/net/wireless/ath/ath12k/qmi.c @@ -1919,14 +1919,11 @@ static void ath12k_host_cap_parse_mlo(struct qmi_wlanfw_host_cap_req_msg_v01 *re static int ath12k_qmi_host_cap_send(struct ath12k_base *ab) { - struct qmi_wlanfw_host_cap_req_msg_v01 req; - struct qmi_wlanfw_host_cap_resp_msg_v01 resp; + struct qmi_wlanfw_host_cap_req_msg_v01 req = {}; + struct qmi_wlanfw_host_cap_resp_msg_v01 resp = {}; struct qmi_txn txn; int ret = 0; - memset(&req, 0, sizeof(req)); - memset(&resp, 0, sizeof(resp)); - req.num_clients_valid = 1; req.num_clients = 1; req.mem_cfg_mode = ab->qmi.target_mem_mode; @@ -2070,7 +2067,7 @@ static int ath12k_qmi_fw_ind_register_send(struct ath12k_base *ab) static int ath12k_qmi_respond_fw_mem_request(struct ath12k_base *ab) { struct qmi_wlanfw_respond_mem_req_msg_v01 *req; - struct qmi_wlanfw_respond_mem_resp_msg_v01 resp; + struct qmi_wlanfw_respond_mem_resp_msg_v01 resp = {}; struct qmi_txn txn; int ret = 0, i; bool delayed; @@ -2079,8 +2076,6 @@ static int ath12k_qmi_respond_fw_mem_request(struct ath12k_base *ab) if (!req) return -ENOMEM; - memset(&resp, 0, sizeof(resp)); - /* Some targets by default request a block of big contiguous * DMA memory, it's hard to allocate from kernel. So host returns * failure to firmware and firmware then request multiple blocks of @@ -2090,7 +2085,6 @@ static int ath12k_qmi_respond_fw_mem_request(struct ath12k_base *ab) delayed = true; ath12k_dbg(ab, ATH12K_DBG_QMI, "qmi delays mem_request %d\n", ab->qmi.mem_seg_count); - memset(req, 0, sizeof(*req)); } else { delayed = false; req->mem_seg_len = ab->qmi.mem_seg_count; @@ -2211,17 +2205,14 @@ static int ath12k_qmi_alloc_target_mem_chunk(struct ath12k_base *ab) static int ath12k_qmi_request_target_cap(struct ath12k_base *ab) { - struct qmi_wlanfw_cap_req_msg_v01 req; - struct qmi_wlanfw_cap_resp_msg_v01 resp; + struct qmi_wlanfw_cap_req_msg_v01 req = {}; + struct qmi_wlanfw_cap_resp_msg_v01 resp = {}; struct qmi_txn txn; unsigned int board_id = ATH12K_BOARD_ID_DEFAULT; int ret = 0; int r; int i; - 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); if (ret < 0) @@ -2314,7 +2305,7 @@ static int ath12k_qmi_load_file_target_mem(struct ath12k_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_wlanfw_bdf_download_resp_msg_v01 resp = {}; struct qmi_txn txn; const u8 *temp = data; int ret; @@ -2323,7 +2314,6 @@ static int ath12k_qmi_load_file_target_mem(struct ath12k_base *ab, req = kzalloc(sizeof(*req), GFP_KERNEL); if (!req) return -ENOMEM; - memset(&resp, 0, sizeof(resp)); while (remaining) { req->valid = 1; @@ -2549,14 +2539,11 @@ static void ath12k_qmi_m3_free(struct ath12k_base *ab) static int ath12k_qmi_wlanfw_m3_info_send(struct ath12k_base *ab) { 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_wlanfw_m3_info_req_msg_v01 req = {}; + struct qmi_wlanfw_m3_info_resp_msg_v01 resp = {}; struct qmi_txn txn; int ret = 0; - memset(&req, 0, sizeof(req)); - memset(&resp, 0, sizeof(resp)); - ret = ath12k_qmi_m3_load(ab); if (ret) { ath12k_err(ab, "failed to load m3 firmware: %d", ret); @@ -2601,14 +2588,11 @@ static int ath12k_qmi_wlanfw_m3_info_send(struct ath12k_base *ab) static int ath12k_qmi_wlanfw_mode_send(struct ath12k_base *ab, u32 mode) { - struct qmi_wlanfw_wlan_mode_req_msg_v01 req; - struct qmi_wlanfw_wlan_mode_resp_msg_v01 resp; + struct qmi_wlanfw_wlan_mode_req_msg_v01 req = {}; + struct qmi_wlanfw_wlan_mode_resp_msg_v01 resp = {}; struct qmi_txn txn; int ret = 0; - memset(&req, 0, sizeof(req)); - memset(&resp, 0, sizeof(resp)); - req.mode = mode; req.hw_debug_valid = 1; req.hw_debug = 0; @@ -2654,7 +2638,7 @@ static int ath12k_qmi_wlanfw_mode_send(struct ath12k_base *ab, static int ath12k_qmi_wlanfw_wlan_cfg_send(struct ath12k_base *ab) { struct qmi_wlanfw_wlan_cfg_req_msg_v01 *req; - struct qmi_wlanfw_wlan_cfg_resp_msg_v01 resp; + 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; @@ -2667,8 +2651,6 @@ static int ath12k_qmi_wlanfw_wlan_cfg_send(struct ath12k_base *ab) if (!req) return -ENOMEM; - memset(&resp, 0, sizeof(resp)); - req->host_version_valid = 1; strscpy(req->host_version, ATH12K_HOST_VERSION_STRING, sizeof(req->host_version)); From eaf9f17b861b665a0bc8dff120ae3c9028642e6d Mon Sep 17 00:00:00 2001 From: Karthikeyan Periyasamy Date: Sun, 14 Jan 2024 17:02:38 +0200 Subject: [PATCH 35/71] wifi: ath12k: relocate ath12k_dp_pdev_pre_alloc() call Currently, the data path pdev pre alloc and mac allocate are called separately from the core start procedure. The data path pdev pre alloc can be called from the mac allocate procedure itself since initialization related to pdev happens in the mac allocate procedure. So move the caller of DP pdev pre alloc from the core start procedure to the mac allocate procedure. This change helps in the future to easily decouple the mac allocate procedure from core start handling in order to support MLO in multi chip. Tested-on: QCN9274 hw2.0 PCI WLAN.WBE.1.0.1-00029-QCAHKSWPL_SILICONZ-1 Signed-off-by: Karthikeyan Periyasamy Signed-off-by: Kalle Valo Link: https://msgid.link/20231206034920.1037449-2-quic_periyasa@quicinc.com --- drivers/net/wireless/ath/ath12k/core.c | 2 -- drivers/net/wireless/ath/ath12k/mac.c | 2 ++ 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/net/wireless/ath/ath12k/core.c b/drivers/net/wireless/ath/ath12k/core.c index d73e2d33a41e..ababe7f01b5b 100644 --- a/drivers/net/wireless/ath/ath12k/core.c +++ b/drivers/net/wireless/ath/ath12k/core.c @@ -714,8 +714,6 @@ static int ath12k_core_start(struct ath12k_base *ab, ath12k_dp_cc_config(ab); - ath12k_dp_pdev_pre_alloc(ab); - ret = ath12k_dp_rx_pdev_reo_setup(ab); if (ret) { ath12k_err(ab, "failed to initialize reo destination rings: %d\n", ret); diff --git a/drivers/net/wireless/ath/ath12k/mac.c b/drivers/net/wireless/ath/ath12k/mac.c index 88cec54c6c2e..49d56f5d8896 100644 --- a/drivers/net/wireless/ath/ath12k/mac.c +++ b/drivers/net/wireless/ath/ath12k/mac.c @@ -7667,6 +7667,8 @@ int ath12k_mac_allocate(struct ath12k_base *ab) clear_bit(ATH12K_FLAG_MONITOR_ENABLED, &ar->monitor_flags); } + ath12k_dp_pdev_pre_alloc(ab); + return 0; err_free_mac: From 8a742a79f90e3d3f0378b030110eccac8d28b655 Mon Sep 17 00:00:00 2001 From: Karthikeyan Periyasamy Date: Sun, 14 Jan 2024 17:02:38 +0200 Subject: [PATCH 36/71] wifi: ath12k: refactor ath12k_mac_allocate() and ath12k_mac_destroy() Currently, the MAC allocation and destroy helper functions are tightly coupled with the link/radio (ar) structure. In the future, to support single/Multi link operations, need to refactor these helper functions across the core and mac sub modules, so that it can be easy to scale these functions to support single/Multi link operations. Tested-on: QCN9274 hw2.0 PCI WLAN.WBE.1.0.1-00029-QCAHKSWPL_SILICONZ-1 Signed-off-by: Karthikeyan Periyasamy Signed-off-by: Kalle Valo Link: https://msgid.link/20231206034920.1037449-3-quic_periyasa@quicinc.com --- drivers/net/wireless/ath/ath12k/mac.c | 150 +++++++++++++++----------- 1 file changed, 88 insertions(+), 62 deletions(-) diff --git a/drivers/net/wireless/ath/ath12k/mac.c b/drivers/net/wireless/ath/ath12k/mac.c index 49d56f5d8896..09a1a2edf842 100644 --- a/drivers/net/wireless/ath/ath12k/mac.c +++ b/drivers/net/wireless/ath/ath12k/mac.c @@ -7607,77 +7607,47 @@ int ath12k_mac_register(struct ath12k_base *ab) return ret; } -int ath12k_mac_allocate(struct ath12k_base *ab) +static void ath12k_mac_setup(struct ath12k *ar) { - struct ieee80211_hw *hw; - struct ath12k *ar; - struct ath12k_pdev *pdev; - int ret; - int i; + struct ath12k_base *ab = ar->ab; + struct ath12k_pdev *pdev = ar->pdev; + u8 pdev_idx = ar->pdev_idx; - if (test_bit(ATH12K_FLAG_REGISTERED, &ab->dev_flags)) - return 0; + ar->lmac_id = ath12k_hw_get_mac_from_pdev_id(ab->hw_params, pdev_idx); - for (i = 0; i < ab->num_radios; i++) { - pdev = &ab->pdevs[i]; - hw = ieee80211_alloc_hw(sizeof(struct ath12k), &ath12k_ops); - if (!hw) { - ath12k_warn(ab, "failed to allocate mac80211 hw device\n"); - ret = -ENOMEM; - goto err_free_mac; - } + ar->wmi = &ab->wmi_ab.wmi[pdev_idx]; + /* FIXME: wmi[0] is already initialized during attach, + * Should we do this again? + */ + ath12k_wmi_pdev_attach(ab, pdev_idx); - ar = hw->priv; - ar->hw = hw; - ar->ab = ab; - ar->pdev = pdev; - ar->pdev_idx = i; - ar->lmac_id = ath12k_hw_get_mac_from_pdev_id(ab->hw_params, i); + ar->cfg_tx_chainmask = pdev->cap.tx_chain_mask; + ar->cfg_rx_chainmask = pdev->cap.rx_chain_mask; + ar->num_tx_chains = hweight32(pdev->cap.tx_chain_mask); + ar->num_rx_chains = hweight32(pdev->cap.rx_chain_mask); - ar->wmi = &ab->wmi_ab.wmi[i]; - /* FIXME: wmi[0] is already initialized during attach, - * Should we do this again? - */ - ath12k_wmi_pdev_attach(ab, i); + spin_lock_init(&ar->data_lock); + INIT_LIST_HEAD(&ar->arvifs); + INIT_LIST_HEAD(&ar->ppdu_stats_info); + mutex_init(&ar->conf_mutex); + init_completion(&ar->vdev_setup_done); + init_completion(&ar->vdev_delete_done); + init_completion(&ar->peer_assoc_done); + init_completion(&ar->peer_delete_done); + init_completion(&ar->install_key_done); + init_completion(&ar->bss_survey_done); + init_completion(&ar->scan.started); + init_completion(&ar->scan.completed); - ar->cfg_tx_chainmask = pdev->cap.tx_chain_mask; - ar->cfg_rx_chainmask = pdev->cap.rx_chain_mask; - ar->num_tx_chains = hweight32(pdev->cap.tx_chain_mask); - ar->num_rx_chains = hweight32(pdev->cap.rx_chain_mask); + INIT_DELAYED_WORK(&ar->scan.timeout, ath12k_scan_timeout_work); + INIT_WORK(&ar->regd_update_work, ath12k_regd_update_work); - pdev->ar = ar; - spin_lock_init(&ar->data_lock); - INIT_LIST_HEAD(&ar->arvifs); - INIT_LIST_HEAD(&ar->ppdu_stats_info); - mutex_init(&ar->conf_mutex); - init_completion(&ar->vdev_setup_done); - init_completion(&ar->vdev_delete_done); - init_completion(&ar->peer_assoc_done); - init_completion(&ar->peer_delete_done); - init_completion(&ar->install_key_done); - init_completion(&ar->bss_survey_done); - init_completion(&ar->scan.started); - init_completion(&ar->scan.completed); - - INIT_DELAYED_WORK(&ar->scan.timeout, ath12k_scan_timeout_work); - INIT_WORK(&ar->regd_update_work, ath12k_regd_update_work); - - INIT_WORK(&ar->wmi_mgmt_tx_work, ath12k_mgmt_over_wmi_tx_work); - skb_queue_head_init(&ar->wmi_mgmt_tx_queue); - clear_bit(ATH12K_FLAG_MONITOR_ENABLED, &ar->monitor_flags); - } - - ath12k_dp_pdev_pre_alloc(ab); - - return 0; - -err_free_mac: - ath12k_mac_destroy(ab); - - return ret; + INIT_WORK(&ar->wmi_mgmt_tx_work, ath12k_mgmt_over_wmi_tx_work); + skb_queue_head_init(&ar->wmi_mgmt_tx_queue); + clear_bit(ATH12K_FLAG_MONITOR_ENABLED, &ar->monitor_flags); } -void ath12k_mac_destroy(struct ath12k_base *ab) +static void ath12k_mac_hw_destroy(struct ath12k_base *ab) { struct ath12k *ar; struct ath12k_pdev *pdev; @@ -7693,3 +7663,59 @@ void ath12k_mac_destroy(struct ath12k_base *ab) pdev->ar = NULL; } } + +static int ath12k_mac_hw_allocate(struct ath12k_base *ab) +{ + struct ieee80211_hw *hw; + struct ath12k *ar; + struct ath12k_pdev *pdev; + int ret; + int i; + + for (i = 0; i < ab->num_radios; i++) { + pdev = &ab->pdevs[i]; + hw = ieee80211_alloc_hw(sizeof(struct ath12k), &ath12k_ops); + if (!hw) { + ath12k_warn(ab, "failed to allocate mac80211 hw device\n"); + ret = -ENOMEM; + goto err_free_mac; + } + + ar = hw->priv; + ar->hw = hw; + ar->ab = ab; + ar->pdev = pdev; + ar->pdev_idx = i; + pdev->ar = ar; + + ath12k_mac_setup(ar); + } + + return 0; + +err_free_mac: + ath12k_mac_hw_destroy(ab); + + return ret; +} + +void ath12k_mac_destroy(struct ath12k_base *ab) +{ + ath12k_mac_hw_destroy(ab); +} + +int ath12k_mac_allocate(struct ath12k_base *ab) +{ + int ret; + + if (test_bit(ATH12K_FLAG_REGISTERED, &ab->dev_flags)) + return 0; + + ret = ath12k_mac_hw_allocate(ab); + if (ret) + return ret; + + ath12k_dp_pdev_pre_alloc(ab); + + return 0; +} From d2b7a6e5fa1c92deabe77aa57ef16f599f3b4247 Mon Sep 17 00:00:00 2001 From: Karthikeyan Periyasamy Date: Sun, 14 Jan 2024 17:02:39 +0200 Subject: [PATCH 37/71] wifi: ath12k: refactor ath12k_mac_setup_channels_rates() Currently, the MAC setup helper function is accessing the mac80211 hw data. In the future, to support single/multi link operation, need to decouple the mac80211 hw data from this helper function so that it can be easy to scale these functions to support single/multi link operations. So remove the mac80211 hw access from the ath12k_mac_setup_channels_rates() helper function. Tested-on: QCN9274 hw2.0 PCI WLAN.WBE.1.0.1-00029-QCAHKSWPL_SILICONZ-1 Signed-off-by: Karthikeyan Periyasamy Signed-off-by: Kalle Valo Link: https://msgid.link/20231206034920.1037449-4-quic_periyasa@quicinc.com --- drivers/net/wireless/ath/ath12k/mac.c | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/drivers/net/wireless/ath/ath12k/mac.c b/drivers/net/wireless/ath/ath12k/mac.c index 09a1a2edf842..33e03208479d 100644 --- a/drivers/net/wireless/ath/ath12k/mac.c +++ b/drivers/net/wireless/ath/ath12k/mac.c @@ -7158,9 +7158,9 @@ static u32 ath12k_get_phy_id(struct ath12k *ar, u32 band) } static int ath12k_mac_setup_channels_rates(struct ath12k *ar, - u32 supported_bands) + u32 supported_bands, + struct ieee80211_supported_band *bands[]) { - struct ieee80211_hw *hw = ar->hw; struct ieee80211_supported_band *band; struct ath12k_wmi_hal_reg_capabilities_ext_arg *reg_cap; void *channels; @@ -7186,7 +7186,7 @@ static int ath12k_mac_setup_channels_rates(struct ath12k *ar, band->channels = channels; band->n_bitrates = ath12k_g_rates_size; band->bitrates = ath12k_g_rates; - hw->wiphy->bands[NL80211_BAND_2GHZ] = band; + bands[NL80211_BAND_2GHZ] = band; if (ar->ab->hw_params->single_pdev_only) { phy_id = ath12k_get_phy_id(ar, WMI_HOST_WLAN_2G_CAP); @@ -7213,7 +7213,7 @@ static int ath12k_mac_setup_channels_rates(struct ath12k *ar, band->channels = channels; band->n_bitrates = ath12k_a_rates_size; band->bitrates = ath12k_a_rates; - hw->wiphy->bands[NL80211_BAND_6GHZ] = band; + bands[NL80211_BAND_6GHZ] = band; ath12k_mac_update_ch_list(ar, band, reg_cap->low_5ghz_chan, reg_cap->high_5ghz_chan); @@ -7235,7 +7235,7 @@ static int ath12k_mac_setup_channels_rates(struct ath12k *ar, band->channels = channels; band->n_bitrates = ath12k_a_rates_size; band->bitrates = ath12k_a_rates; - hw->wiphy->bands[NL80211_BAND_5GHZ] = band; + bands[NL80211_BAND_5GHZ] = band; if (ar->ab->hw_params->single_pdev_only) { phy_id = ath12k_get_phy_id(ar, WMI_HOST_WLAN_5G_CAP); @@ -7414,7 +7414,8 @@ static int __ath12k_mac_register(struct ath12k *ar) SET_IEEE80211_DEV(hw, ab->dev); ret = ath12k_mac_setup_channels_rates(ar, - cap->supported_bands); + cap->supported_bands, + hw->wiphy->bands); if (ret) goto err; From d786c9f5fe3472ac102160c113a7bba8ec79a6c6 Mon Sep 17 00:00:00 2001 From: Karthikeyan Periyasamy Date: Sun, 14 Jan 2024 17:02:39 +0200 Subject: [PATCH 38/71] wifi: ath12k: refactor ath12k_mac_register() and ath12k_mac_unregister() Currently, the mac80211 hw registration procedure is tightly coupled with the handling of link/radio (ar). Define a new helper function to separate the link/radio handling from the mac80211 hw registration procedure for improved code readability. Also, it can be easy to scale these functionality to support single/multi link operation in the future. Tested-on: QCN9274 hw2.0 PCI WLAN.WBE.1.0.1-00029-QCAHKSWPL_SILICONZ-1 Signed-off-by: Karthikeyan Periyasamy Signed-off-by: Kalle Valo Link: https://msgid.link/20231206034920.1037449-5-quic_periyasa@quicinc.com --- drivers/net/wireless/ath/ath12k/mac.c | 183 ++++++++++++++------------ 1 file changed, 102 insertions(+), 81 deletions(-) diff --git a/drivers/net/wireless/ath/ath12k/mac.c b/drivers/net/wireless/ath/ath12k/mac.c index 33e03208479d..4fc338bace8d 100644 --- a/drivers/net/wireless/ath/ath12k/mac.c +++ b/drivers/net/wireless/ath/ath12k/mac.c @@ -7349,7 +7349,17 @@ static const struct wiphy_iftype_ext_capab ath12k_iftypes_ext_capa[] = { }, }; -static void __ath12k_mac_unregister(struct ath12k *ar) +static void ath12k_mac_cleanup_unregister(struct ath12k *ar) +{ + idr_for_each(&ar->txmgmt_idr, ath12k_mac_tx_mgmt_pending_free, ar); + idr_destroy(&ar->txmgmt_idr); + + kfree(ar->mac.sbands[NL80211_BAND_2GHZ].channels); + kfree(ar->mac.sbands[NL80211_BAND_5GHZ].channels); + kfree(ar->mac.sbands[NL80211_BAND_6GHZ].channels); +} + +static void ath12k_mac_hw_unregister(struct ath12k *ar) { struct ieee80211_hw *hw = ar->hw; struct wiphy *wiphy = hw->wiphy; @@ -7358,12 +7368,7 @@ static void __ath12k_mac_unregister(struct ath12k *ar) ieee80211_unregister_hw(hw); - idr_for_each(&ar->txmgmt_idr, ath12k_mac_tx_mgmt_pending_free, ar); - idr_destroy(&ar->txmgmt_idr); - - kfree(ar->mac.sbands[NL80211_BAND_2GHZ].channels); - kfree(ar->mac.sbands[NL80211_BAND_5GHZ].channels); - kfree(ar->mac.sbands[NL80211_BAND_6GHZ].channels); + ath12k_mac_cleanup_unregister(ar); kfree(wiphy->iface_combinations[0].limits); kfree(wiphy->iface_combinations); @@ -7371,28 +7376,41 @@ static void __ath12k_mac_unregister(struct ath12k *ar) SET_IEEE80211_DEV(hw, NULL); } -void ath12k_mac_unregister(struct ath12k_base *ab) +static int ath12k_mac_setup_register(struct ath12k *ar, + u32 *ht_cap, + struct ieee80211_supported_band *bands[]) { - struct ath12k *ar; - struct ath12k_pdev *pdev; - int i; + struct ath12k_pdev_cap *cap = &ar->pdev->cap; + int ret; - for (i = 0; i < ab->num_radios; i++) { - pdev = &ab->pdevs[i]; - ar = pdev->ar; - if (!ar) - continue; + init_waitqueue_head(&ar->txmgmt_empty_waitq); + idr_init(&ar->txmgmt_idr); + spin_lock_init(&ar->txmgmt_idr_lock); - __ath12k_mac_unregister(ar); - } + ath12k_pdev_caps_update(ar); + + ret = ath12k_mac_setup_channels_rates(ar, + cap->supported_bands, + bands); + if (ret) + return ret; + + ath12k_mac_setup_ht_vht_cap(ar, cap, ht_cap); + ath12k_mac_setup_sband_iftype_data(ar, cap); + + ar->max_num_stations = TARGET_NUM_STATIONS; + ar->max_num_peers = TARGET_NUM_PEERS_PDEV; + + return 0; } -static int __ath12k_mac_register(struct ath12k *ar) +static int ath12k_mac_hw_register(struct ath12k *ar) { struct ath12k_base *ab = ar->ab; struct ieee80211_hw *hw = ar->hw; struct wiphy *wiphy = hw->wiphy; - struct ath12k_pdev_cap *cap = &ar->pdev->cap; + struct ath12k_pdev *pdev = ar->pdev; + struct ath12k_pdev_cap *cap = &pdev->cap; static const u32 cipher_suites[] = { WLAN_CIPHER_SUITE_TKIP, WLAN_CIPHER_SUITE_CCMP, @@ -7407,25 +7425,24 @@ static int __ath12k_mac_register(struct ath12k *ar) int ret; u32 ht_cap = 0; - ath12k_pdev_caps_update(ar); + if (ab->pdevs_macaddr_valid) { + ether_addr_copy(ar->mac_addr, pdev->mac_addr); + } else { + ether_addr_copy(ar->mac_addr, ab->mac_addr); + ar->mac_addr[4] += ar->pdev_idx; + } + + ret = ath12k_mac_setup_register(ar, &ht_cap, hw->wiphy->bands); + if (ret) + goto out; SET_IEEE80211_PERM_ADDR(hw, ar->mac_addr); - SET_IEEE80211_DEV(hw, ab->dev); - ret = ath12k_mac_setup_channels_rates(ar, - cap->supported_bands, - hw->wiphy->bands); - if (ret) - goto err; - - ath12k_mac_setup_ht_vht_cap(ar, cap, &ht_cap); - ath12k_mac_setup_sband_iftype_data(ar, cap); - ret = ath12k_mac_setup_iface_combinations(ar); if (ret) { ath12k_err(ar->ab, "failed to setup interface combinations: %d\n", ret); - goto err_free_channels; + goto err_setup_unregister; } wiphy->available_antennas_rx = cap->rx_chain_mask; @@ -7484,9 +7501,6 @@ static int __ath12k_mac_register(struct ath12k *ar) 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; - wiphy->max_ap_assoc_sta = ar->max_num_stations; hw->queues = ATH12K_HW_MAX_QUEUES; @@ -7553,58 +7567,14 @@ static int __ath12k_mac_register(struct ath12k *ar) kfree(wiphy->iface_combinations[0].limits); kfree(wiphy->iface_combinations); -err_free_channels: +err_setup_unregister: kfree(ar->mac.sbands[NL80211_BAND_2GHZ].channels); kfree(ar->mac.sbands[NL80211_BAND_5GHZ].channels); kfree(ar->mac.sbands[NL80211_BAND_6GHZ].channels); -err: SET_IEEE80211_DEV(hw, NULL); - return ret; -} - -int ath12k_mac_register(struct ath12k_base *ab) -{ - struct ath12k *ar; - struct ath12k_pdev *pdev; - int i; - int ret; - - if (test_bit(ATH12K_FLAG_REGISTERED, &ab->dev_flags)) - return 0; - - for (i = 0; i < ab->num_radios; i++) { - pdev = &ab->pdevs[i]; - ar = pdev->ar; - if (ab->pdevs_macaddr_valid) { - ether_addr_copy(ar->mac_addr, pdev->mac_addr); - } else { - ether_addr_copy(ar->mac_addr, ab->mac_addr); - ar->mac_addr[4] += i; - } - - ret = __ath12k_mac_register(ar); - if (ret) - goto err_cleanup; - - init_waitqueue_head(&ar->txmgmt_empty_waitq); - idr_init(&ar->txmgmt_idr); - spin_lock_init(&ar->txmgmt_idr_lock); - } - - /* Initialize channel counters frequency value in hertz */ - ab->cc_freq_hz = 320000; - ab->free_vdev_map = (1LL << (ab->num_radios * TARGET_NUM_VDEVS)) - 1; - - return 0; - -err_cleanup: - for (i = i - 1; i >= 0; i--) { - pdev = &ab->pdevs[i]; - ar = pdev->ar; - __ath12k_mac_unregister(ar); - } +out: return ret; } @@ -7648,6 +7618,57 @@ static void ath12k_mac_setup(struct ath12k *ar) clear_bit(ATH12K_FLAG_MONITOR_ENABLED, &ar->monitor_flags); } +int ath12k_mac_register(struct ath12k_base *ab) +{ + struct ath12k *ar; + struct ath12k_pdev *pdev; + int i; + int ret; + + if (test_bit(ATH12K_FLAG_REGISTERED, &ab->dev_flags)) + return 0; + + /* Initialize channel counters frequency value in hertz */ + ab->cc_freq_hz = 320000; + 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; + + ret = ath12k_mac_hw_register(ar); + if (ret) + goto err_cleanup; + } + + return 0; + +err_cleanup: + for (i = i - 1; i >= 0; i--) { + pdev = &ab->pdevs[i]; + ar = pdev->ar; + ath12k_mac_hw_unregister(ar); + } + + return ret; +} + +void ath12k_mac_unregister(struct ath12k_base *ab) +{ + struct ath12k *ar; + struct ath12k_pdev *pdev; + int i; + + for (i = 0; i < ab->num_radios; i++) { + pdev = &ab->pdevs[i]; + ar = pdev->ar; + if (!ar) + continue; + + ath12k_mac_hw_unregister(ar); + } +} + static void ath12k_mac_hw_destroy(struct ath12k_base *ab) { struct ath12k *ar; From 3e141f0034d573f133fc3e73508949ba64461a4a Mon Sep 17 00:00:00 2001 From: Karthikeyan Periyasamy Date: Sun, 14 Jan 2024 17:02:40 +0200 Subject: [PATCH 39/71] wifi: ath12k: refactor ath12k_mac_op_config() To support single wiphy abstraction, introduce link/radio specific helper function in the mac80211 callback config(). This way, the callback can be extended to handle multiple link/radio in the future. Tested-on: QCN9274 hw2.0 PCI WLAN.WBE.1.0.1-00029-QCAHKSWPL_SILICONZ-1 Tested-on: WCN7850 hw2.0 PCI WLAN.HMT.1.0-03427-QCAHMTSWPL_V1.0_V2.0_SILICONZ-1.15378.4 Signed-off-by: Karthikeyan Periyasamy Acked-by: Jeff Johnson Signed-off-by: Kalle Valo Link: https://msgid.link/20240103063731.3356060-2-quic_periyasa@quicinc.com --- drivers/net/wireless/ath/ath12k/mac.c | 19 ++++++++++++++++--- 1 file changed, 16 insertions(+), 3 deletions(-) diff --git a/drivers/net/wireless/ath/ath12k/mac.c b/drivers/net/wireless/ath/ath12k/mac.c index 4fc338bace8d..06ecbb382b63 100644 --- a/drivers/net/wireless/ath/ath12k/mac.c +++ b/drivers/net/wireless/ath/ath12k/mac.c @@ -1,7 +1,7 @@ // SPDX-License-Identifier: BSD-3-Clause-Clear /* * Copyright (c) 2018-2021 The Linux Foundation. All rights reserved. - * Copyright (c) 2021-2023 Qualcomm Innovation Center, Inc. All rights reserved. + * Copyright (c) 2021-2024 Qualcomm Innovation Center, Inc. All rights reserved. */ #include @@ -1083,9 +1083,9 @@ static int ath12k_mac_monitor_stop(struct ath12k *ar) return ret; } -static int ath12k_mac_op_config(struct ieee80211_hw *hw, u32 changed) +static int ath12k_mac_config(struct ath12k *ar, u32 changed) { - struct ath12k *ar = hw->priv; + struct ieee80211_hw *hw = ar->hw; struct ieee80211_conf *conf = &hw->conf; int ret = 0; @@ -1122,6 +1122,19 @@ static int ath12k_mac_op_config(struct ieee80211_hw *hw, u32 changed) return ret; } +static int ath12k_mac_op_config(struct ieee80211_hw *hw, u32 changed) +{ + struct ath12k *ar = hw->priv; + int ret; + + ret = ath12k_mac_config(ar, changed); + if (ret) + ath12k_warn(ar->ab, "failed to update config pdev idx %d: %d\n", + ar->pdev_idx, ret); + + return ret; +} + static int ath12k_mac_setup_bcn_tmpl(struct ath12k_vif *arvif) { struct ath12k *ar = arvif->ar; From ce20a10fdff41afbbc119e91cf3e2378d81e2eb0 Mon Sep 17 00:00:00 2001 From: Karthikeyan Periyasamy Date: Sun, 14 Jan 2024 17:02:40 +0200 Subject: [PATCH 40/71] wifi: ath12k: refactor ath12k_bss_assoc() To support single wiphy abstraction, introduce link/radio specific helper function in the mac80211 callback bss_info_change(). This way, the callback can be extended to handle multiple link/radio in the future. Tested-on: QCN9274 hw2.0 PCI WLAN.WBE.1.0.1-00029-QCAHKSWPL_SILICONZ-1 Tested-on: WCN7850 hw2.0 PCI WLAN.HMT.1.0-03427-QCAHMTSWPL_V1.0_V2.0_SILICONZ-1.15378.4 Signed-off-by: Karthikeyan Periyasamy Acked-by: Jeff Johnson Signed-off-by: Kalle Valo Link: https://msgid.link/20240103063731.3356060-3-quic_periyasa@quicinc.com --- drivers/net/wireless/ath/ath12k/mac.c | 43 ++++++++++++++++----------- 1 file changed, 26 insertions(+), 17 deletions(-) diff --git a/drivers/net/wireless/ath/ath12k/mac.c b/drivers/net/wireless/ath/ath12k/mac.c index 06ecbb382b63..58bd850bb86e 100644 --- a/drivers/net/wireless/ath/ath12k/mac.c +++ b/drivers/net/wireless/ath/ath12k/mac.c @@ -2279,12 +2279,11 @@ static int ath12k_setup_peer_smps(struct ath12k *ar, struct ath12k_vif *arvif, ath12k_smps_map[smps]); } -static void ath12k_bss_assoc(struct ieee80211_hw *hw, - struct ieee80211_vif *vif, +static void ath12k_bss_assoc(struct ath12k *ar, + struct ath12k_vif *arvif, struct ieee80211_bss_conf *bss_conf) { - struct ath12k *ar = hw->priv; - struct ath12k_vif *arvif = ath12k_vif_to_arvif(vif); + struct ieee80211_vif *vif = arvif->vif; struct ath12k_wmi_peer_assoc_arg peer_arg; struct ieee80211_sta *ap_sta; struct ath12k_peer *peer; @@ -2374,11 +2373,9 @@ static void ath12k_bss_assoc(struct ieee80211_hw *hw, arvif->vdev_id, ret); } -static void ath12k_bss_disassoc(struct ieee80211_hw *hw, - struct ieee80211_vif *vif) +static void ath12k_bss_disassoc(struct ath12k *ar, + struct ath12k_vif *arvif) { - struct ath12k *ar = hw->priv; - struct ath12k_vif *arvif = ath12k_vif_to_arvif(vif); int ret; lockdep_assert_held(&ar->conf_mutex); @@ -2504,13 +2501,12 @@ static int ath12k_mac_fils_discovery(struct ath12k_vif *arvif, return ret; } -static void ath12k_mac_op_bss_info_changed(struct ieee80211_hw *hw, - struct ieee80211_vif *vif, - struct ieee80211_bss_conf *info, - u64 changed) +static void ath12k_mac_bss_info_changed(struct ath12k *ar, + struct ath12k_vif *arvif, + struct ieee80211_bss_conf *info, + u64 changed) { - struct ath12k *ar = hw->priv; - struct ath12k_vif *arvif = ath12k_vif_to_arvif(vif); + struct ieee80211_vif *vif = arvif->vif; struct cfg80211_chan_def def; u32 param_id, param_value; enum nl80211_band band; @@ -2523,7 +2519,7 @@ static void ath12k_mac_op_bss_info_changed(struct ieee80211_hw *hw, u8 rateidx; u32 rate; - mutex_lock(&ar->conf_mutex); + lockdep_assert_held(&ar->conf_mutex); if (changed & BSS_CHANGED_BEACON_INT) { arvif->beacon_interval = info->beacon_int; @@ -2679,9 +2675,9 @@ static void ath12k_mac_op_bss_info_changed(struct ieee80211_hw *hw, if (changed & BSS_CHANGED_ASSOC) { if (vif->cfg.assoc) - ath12k_bss_assoc(hw, vif, info); + ath12k_bss_assoc(ar, arvif, info); else - ath12k_bss_disassoc(hw, vif); + ath12k_bss_disassoc(ar, arvif); } if (changed & BSS_CHANGED_TXPOWER) { @@ -2783,6 +2779,19 @@ static void ath12k_mac_op_bss_info_changed(struct ieee80211_hw *hw, if (changed & BSS_CHANGED_EHT_PUNCTURING) arvif->punct_bitmap = info->eht_puncturing; +} + +static void ath12k_mac_op_bss_info_changed(struct ieee80211_hw *hw, + struct ieee80211_vif *vif, + struct ieee80211_bss_conf *info, + u64 changed) +{ + struct ath12k *ar = hw->priv; + struct ath12k_vif *arvif = ath12k_vif_to_arvif(vif); + + mutex_lock(&ar->conf_mutex); + + ath12k_mac_bss_info_changed(ar, arvif, info, changed); mutex_unlock(&ar->conf_mutex); } From 00c9b1a6d21d03b8fb74f1029c370dccce294dd5 Mon Sep 17 00:00:00 2001 From: Karthikeyan Periyasamy Date: Sun, 14 Jan 2024 17:02:40 +0200 Subject: [PATCH 41/71] wifi: ath12k: refactor ath12k_mac_op_conf_tx() To support single wiphy abstraction, introduce link/radio specific helper function in the mac80211 callback conf_tx(). This way, the callback can be extended to handle multiple link/radio in the future. Tested-on: QCN9274 hw2.0 PCI WLAN.WBE.1.0.1-00029-QCAHKSWPL_SILICONZ-1 Tested-on: WCN7850 hw2.0 PCI WLAN.HMT.1.0-03427-QCAHMTSWPL_V1.0_V2.0_SILICONZ-1.15378.4 Signed-off-by: Karthikeyan Periyasamy Acked-by: Jeff Johnson Signed-off-by: Kalle Valo Link: https://msgid.link/20240103063731.3356060-4-quic_periyasa@quicinc.com --- drivers/net/wireless/ath/ath12k/mac.c | 41 ++++++++++++++++++--------- 1 file changed, 28 insertions(+), 13 deletions(-) diff --git a/drivers/net/wireless/ath/ath12k/mac.c b/drivers/net/wireless/ath/ath12k/mac.c index 58bd850bb86e..37ae22d27ccb 100644 --- a/drivers/net/wireless/ath/ath12k/mac.c +++ b/drivers/net/wireless/ath/ath12k/mac.c @@ -3986,10 +3986,10 @@ static void ath12k_mac_op_sta_rc_update(struct ieee80211_hw *hw, ieee80211_queue_work(hw, &arsta->update_wk); } -static int ath12k_conf_tx_uapsd(struct ath12k *ar, struct ieee80211_vif *vif, +static int ath12k_conf_tx_uapsd(struct ath12k_vif *arvif, u16 ac, bool enable) { - struct ath12k_vif *arvif = ath12k_vif_to_arvif(vif); + struct ath12k *ar = arvif->ar; u32 value; int ret; @@ -4043,17 +4043,16 @@ static int ath12k_conf_tx_uapsd(struct ath12k *ar, struct ieee80211_vif *vif, return ret; } -static int ath12k_mac_op_conf_tx(struct ieee80211_hw *hw, - struct ieee80211_vif *vif, - unsigned int link_id, u16 ac, - const struct ieee80211_tx_queue_params *params) +static int ath12k_mac_conf_tx(struct ath12k_vif *arvif, + unsigned int link_id, u16 ac, + const struct ieee80211_tx_queue_params *params) { - struct ath12k *ar = hw->priv; - struct ath12k_vif *arvif = ath12k_vif_to_arvif(vif); struct wmi_wmm_params_arg *p = NULL; + struct ath12k *ar = arvif->ar; + struct ath12k_base *ab = ar->ab; int ret; - mutex_lock(&ar->conf_mutex); + lockdep_assert_held(&ar->conf_mutex); switch (ac) { case IEEE80211_AC_VO: @@ -4083,17 +4082,33 @@ static int ath12k_mac_op_conf_tx(struct ieee80211_hw *hw, ret = ath12k_wmi_send_wmm_update_cmd(ar, arvif->vdev_id, &arvif->wmm_params); if (ret) { - ath12k_warn(ar->ab, "failed to set wmm params: %d\n", ret); + ath12k_warn(ab, "pdev idx %d failed to set wmm params: %d\n", + ar->pdev_idx, ret); goto exit; } - ret = ath12k_conf_tx_uapsd(ar, vif, ac, params->uapsd); - + ret = ath12k_conf_tx_uapsd(arvif, ac, params->uapsd); if (ret) - ath12k_warn(ar->ab, "failed to set sta uapsd: %d\n", ret); + ath12k_warn(ab, "pdev idx %d failed to set sta uapsd: %d\n", + ar->pdev_idx, ret); exit: + return ret; +} + +static int ath12k_mac_op_conf_tx(struct ieee80211_hw *hw, + struct ieee80211_vif *vif, + unsigned int link_id, u16 ac, + const struct ieee80211_tx_queue_params *params) +{ + struct ath12k *ar = hw->priv; + struct ath12k_vif *arvif = ath12k_vif_to_arvif(vif); + int ret; + + mutex_lock(&ar->conf_mutex); + ret = ath12k_mac_conf_tx(arvif, link_id, ac, params); mutex_unlock(&ar->conf_mutex); + return ret; } From e1e275a699061fba965b5653a8f03d550bb5fe6e Mon Sep 17 00:00:00 2001 From: Karthikeyan Periyasamy Date: Sun, 14 Jan 2024 17:02:40 +0200 Subject: [PATCH 42/71] wifi: ath12k: refactor ath12k_mac_op_start() To support single wiphy abstraction, introduce link/radio specific helper function in the mac80211 callback start(). This way, the callback can be extended to handle multiple link/radio in the future. Tested-on: QCN9274 hw2.0 PCI WLAN.WBE.1.0.1-00029-QCAHKSWPL_SILICONZ-1 Tested-on: WCN7850 hw2.0 PCI WLAN.HMT.1.0-03427-QCAHMTSWPL_V1.0_V2.0_SILICONZ-1.15378.4 Signed-off-by: Karthikeyan Periyasamy Acked-by: Jeff Johnson Signed-off-by: Kalle Valo Link: https://msgid.link/20240103063731.3356060-5-quic_periyasa@quicinc.com --- drivers/net/wireless/ath/ath12k/mac.c | 31 ++++++++++++++++++++------- 1 file changed, 23 insertions(+), 8 deletions(-) diff --git a/drivers/net/wireless/ath/ath12k/mac.c b/drivers/net/wireless/ath/ath12k/mac.c index 37ae22d27ccb..d48161b43a4a 100644 --- a/drivers/net/wireless/ath/ath12k/mac.c +++ b/drivers/net/wireless/ath/ath12k/mac.c @@ -5081,14 +5081,12 @@ static void ath12k_mac_wait_reconfigure(struct ath12k_base *ab) ATH12K_RECONFIGURE_TIMEOUT_HZ); } -static int ath12k_mac_op_start(struct ieee80211_hw *hw) +static int ath12k_mac_start(struct ath12k *ar) { - struct ath12k *ar = hw->priv; struct ath12k_base *ab = ar->ab; struct ath12k_pdev *pdev = ar->pdev; int ret; - ath12k_mac_drain_tx(ar); mutex_lock(&ar->conf_mutex); switch (ar->state) { @@ -5111,14 +5109,14 @@ static int ath12k_mac_op_start(struct ieee80211_hw *hw) 1, pdev->pdev_id); if (ret) { - ath12k_err(ar->ab, "failed to enable PMF QOS: (%d\n", ret); + ath12k_err(ab, "failed to enable PMF QOS: (%d\n", ret); goto err; } ret = ath12k_wmi_pdev_set_param(ar, WMI_PDEV_PARAM_DYNAMIC_BW, 1, pdev->pdev_id); if (ret) { - ath12k_err(ar->ab, "failed to enable dynamic bw: %d\n", ret); + ath12k_err(ab, "failed to enable dynamic bw: %d\n", ret); goto err; } @@ -5148,7 +5146,7 @@ static int ath12k_mac_op_start(struct ieee80211_hw *hw) 1, pdev->pdev_id); if (ret) { - ath12k_err(ar->ab, "failed to enable MESH MCAST ENABLE: (%d\n", ret); + ath12k_err(ab, "failed to enable MESH MCAST ENABLE: (%d\n", ret); goto err; } @@ -5174,7 +5172,7 @@ static int ath12k_mac_op_start(struct ieee80211_hw *hw) } if (ret == -ENOTSUPP) - ath12k_dbg(ar->ab, ATH12K_DBG_MAC, + ath12k_dbg(ab, ATH12K_DBG_MAC, "monitor status config is not yet supported"); /* Configure the hash seed for hash based reo dest ring selection */ @@ -5196,7 +5194,6 @@ static int ath12k_mac_op_start(struct ieee80211_hw *hw) &ab->pdevs[ar->pdev_idx]); return 0; - err: ar->state = ATH12K_STATE_OFF; mutex_unlock(&ar->conf_mutex); @@ -5204,6 +5201,24 @@ static int ath12k_mac_op_start(struct ieee80211_hw *hw) return ret; } +static int ath12k_mac_op_start(struct ieee80211_hw *hw) +{ + struct ath12k *ar = hw->priv; + struct ath12k_base *ab = ar->ab; + int ret; + + ath12k_mac_drain_tx(ar); + + ret = ath12k_mac_start(ar); + if (ret) { + ath12k_err(ab, "fail to start mac operations in pdev idx %d ret %d\n", + ar->pdev_idx, ret); + return ret; + } + + return 0; +} + int ath12k_mac_rfkill_config(struct ath12k *ar) { struct ath12k_base *ab = ar->ab; From 3bbc9c7429ff9e9c79c36add3742f7292d135b98 Mon Sep 17 00:00:00 2001 From: Karthikeyan Periyasamy Date: Sun, 14 Jan 2024 17:02:40 +0200 Subject: [PATCH 43/71] wifi: ath12k: refactor ath12k_mac_op_stop() To support single wiphy abstraction, introduce link/radio specific helper function in the mac80211 callback stop(). This way, the callback can be extended to handle multiple link/radio in the future. Tested-on: QCN9274 hw2.0 PCI WLAN.WBE.1.0.1-00029-QCAHKSWPL_SILICONZ-1 Tested-on: WCN7850 hw2.0 PCI WLAN.HMT.1.0-03427-QCAHMTSWPL_V1.0_V2.0_SILICONZ-1.15378.4 Signed-off-by: Karthikeyan Periyasamy Acked-by: Jeff Johnson Signed-off-by: Kalle Valo Link: https://msgid.link/20240103063731.3356060-6-quic_periyasa@quicinc.com --- drivers/net/wireless/ath/ath12k/mac.c | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/drivers/net/wireless/ath/ath12k/mac.c b/drivers/net/wireless/ath/ath12k/mac.c index d48161b43a4a..b6ee5527f350 100644 --- a/drivers/net/wireless/ath/ath12k/mac.c +++ b/drivers/net/wireless/ath/ath12k/mac.c @@ -5276,14 +5276,11 @@ int ath12k_mac_rfkill_enable_radio(struct ath12k *ar, bool enable) return 0; } -static void ath12k_mac_op_stop(struct ieee80211_hw *hw) +static void ath12k_mac_stop(struct ath12k *ar) { - struct ath12k *ar = hw->priv; struct htt_ppdu_stats_info *ppdu_stats, *tmp; int ret; - ath12k_mac_drain_tx(ar); - mutex_lock(&ar->conf_mutex); ret = ath12k_mac_config_mon_status_default(ar, false); if (ret && (ret != -ENOTSUPP)) @@ -5312,6 +5309,15 @@ static void ath12k_mac_op_stop(struct ieee80211_hw *hw) atomic_set(&ar->num_pending_mgmt_tx, 0); } +static void ath12k_mac_op_stop(struct ieee80211_hw *hw) +{ + struct ath12k *ar = hw->priv; + + ath12k_mac_drain_tx(ar); + + ath12k_mac_stop(ar); +} + static u8 ath12k_mac_get_vdev_stats_id(struct ath12k_vif *arvif) { From 92b30bb397869f94724b59d85f16e8de00fa9bc4 Mon Sep 17 00:00:00 2001 From: Karthikeyan Periyasamy Date: Sun, 14 Jan 2024 17:02:40 +0200 Subject: [PATCH 44/71] wifi: ath12k: refactor ath12k_mac_op_update_vif_offload() To support single wiphy abstraction, introduce link/radio specific helper function in the mac80211 callback update_vif_offload(). This way, the callback can be extended to handle multiple link/radio in the future. Tested-on: QCN9274 hw2.0 PCI WLAN.WBE.1.0.1-00029-QCAHKSWPL_SILICONZ-1 Tested-on: WCN7850 hw2.0 PCI WLAN.HMT.1.0-03427-QCAHMTSWPL_V1.0_V2.0_SILICONZ-1.15378.4 Signed-off-by: Karthikeyan Periyasamy Acked-by: Jeff Johnson Signed-off-by: Kalle Valo Link: https://msgid.link/20240103063731.3356060-7-quic_periyasa@quicinc.com --- drivers/net/wireless/ath/ath12k/mac.c | 17 ++++++++++++----- 1 file changed, 12 insertions(+), 5 deletions(-) diff --git a/drivers/net/wireless/ath/ath12k/mac.c b/drivers/net/wireless/ath/ath12k/mac.c index b6ee5527f350..bc6746abebf0 100644 --- a/drivers/net/wireless/ath/ath12k/mac.c +++ b/drivers/net/wireless/ath/ath12k/mac.c @@ -5434,12 +5434,11 @@ static int ath12k_set_he_mu_sounding_mode(struct ath12k *ar, return ret; } -static void ath12k_mac_op_update_vif_offload(struct ieee80211_hw *hw, - struct ieee80211_vif *vif) +static void ath12k_mac_update_vif_offload(struct ath12k_vif *arvif) { - struct ath12k *ar = hw->priv; + struct ieee80211_vif *vif = arvif->vif; + struct ath12k *ar = arvif->ar; struct ath12k_base *ab = ar->ab; - struct ath12k_vif *arvif = ath12k_vif_to_arvif(vif); u32 param_id, param_value; int ret; @@ -5481,6 +5480,14 @@ static void ath12k_mac_op_update_vif_offload(struct ieee80211_hw *hw, } } +static void ath12k_mac_op_update_vif_offload(struct ieee80211_hw *hw, + struct ieee80211_vif *vif) +{ + struct ath12k_vif *arvif = ath12k_vif_to_arvif(vif); + + ath12k_mac_update_vif_offload(arvif); +} + static int ath12k_mac_op_add_interface(struct ieee80211_hw *hw, struct ieee80211_vif *vif) { @@ -5584,7 +5591,7 @@ static int ath12k_mac_op_add_interface(struct ieee80211_hw *hw, list_add(&arvif->list, &ar->arvifs); spin_unlock_bh(&ar->data_lock); - ath12k_mac_op_update_vif_offload(hw, vif); + ath12k_mac_update_vif_offload(arvif); nss = hweight32(ar->cfg_tx_chainmask) ? : 1; ret = ath12k_wmi_vdev_set_param_cmd(ar, arvif->vdev_id, From d629b0c149c913d633ada52357069b8ac7fc81c6 Mon Sep 17 00:00:00 2001 From: Karthikeyan Periyasamy Date: Sun, 14 Jan 2024 17:02:41 +0200 Subject: [PATCH 45/71] wifi: ath12k: refactor ath12k_mac_op_configure_filter() To support single wiphy abstraction, introduce link/radio specific helper function in the mac80211 callback configure_filter(). This way, the callback can be extended to handle multiple link/radio in the future. Tested-on: QCN9274 hw2.0 PCI WLAN.WBE.1.0.1-00029-QCAHKSWPL_SILICONZ-1 Tested-on: WCN7850 hw2.0 PCI WLAN.HMT.1.0-03427-QCAHMTSWPL_V1.0_V2.0_SILICONZ-1.15378.4 Signed-off-by: Karthikeyan Periyasamy Acked-by: Jeff Johnson Signed-off-by: Kalle Valo Link: https://msgid.link/20240103063731.3356060-8-quic_periyasa@quicinc.com --- drivers/net/wireless/ath/ath12k/mac.c | 28 ++++++++++++++++++--------- 1 file changed, 19 insertions(+), 9 deletions(-) diff --git a/drivers/net/wireless/ath/ath12k/mac.c b/drivers/net/wireless/ath/ath12k/mac.c index bc6746abebf0..ef9e3558f5eb 100644 --- a/drivers/net/wireless/ath/ath12k/mac.c +++ b/drivers/net/wireless/ath/ath12k/mac.c @@ -5831,19 +5831,15 @@ static void ath12k_mac_op_remove_interface(struct ieee80211_hw *hw, FIF_PROBE_REQ | \ FIF_FCSFAIL) -static void ath12k_mac_op_configure_filter(struct ieee80211_hw *hw, - unsigned int changed_flags, - unsigned int *total_flags, - u64 multicast) +static void ath12k_mac_configure_filter(struct ath12k *ar, + unsigned int total_flags) { - struct ath12k *ar = hw->priv; bool reset_flag; int ret; - mutex_lock(&ar->conf_mutex); + lockdep_assert_held(&ar->conf_mutex); - *total_flags &= SUPPORTED_FILTERS; - ar->filter_flags = *total_flags; + ar->filter_flags = total_flags; /* For monitor mode */ reset_flag = !(ar->filter_flags & FIF_BCN_PRBRESP_PROMISC); @@ -5858,9 +5854,23 @@ static void ath12k_mac_op_configure_filter(struct ieee80211_hw *hw, ath12k_warn(ar->ab, "fail to set monitor filter: %d\n", ret); } + ath12k_dbg(ar->ab, ATH12K_DBG_MAC, "total_flags:0x%x, reset_flag:%d\n", - *total_flags, reset_flag); + total_flags, reset_flag); +} + +static void ath12k_mac_op_configure_filter(struct ieee80211_hw *hw, + unsigned int changed_flags, + unsigned int *total_flags, + u64 multicast) +{ + struct ath12k *ar = hw->priv; + + mutex_lock(&ar->conf_mutex); + + *total_flags &= SUPPORTED_FILTERS; + ath12k_mac_configure_filter(ar, *total_flags); mutex_unlock(&ar->conf_mutex); } From 5b1b5dbfd6a6590606d7dbb99b0708be100a4acb Mon Sep 17 00:00:00 2001 From: Karthikeyan Periyasamy Date: Sun, 14 Jan 2024 17:02:41 +0200 Subject: [PATCH 46/71] wifi: ath12k: refactor ath12k_mac_op_ampdu_action() To support single wiphy abstraction, introduce link/radio specific helper function in the mac80211 callback ampdu_action(). This way, the callback can be extended to handle multiple link/radio in the future. Tested-on: QCN9274 hw2.0 PCI WLAN.WBE.1.0.1-00029-QCAHKSWPL_SILICONZ-1 Tested-on: WCN7850 hw2.0 PCI WLAN.HMT.1.0-03427-QCAHMTSWPL_V1.0_V2.0_SILICONZ-1.15378.4 Signed-off-by: Karthikeyan Periyasamy Acked-by: Jeff Johnson Signed-off-by: Kalle Valo Link: https://msgid.link/20240103063731.3356060-9-quic_periyasa@quicinc.com --- drivers/net/wireless/ath/ath12k/mac.c | 26 +++++++++++++++++++++----- 1 file changed, 21 insertions(+), 5 deletions(-) diff --git a/drivers/net/wireless/ath/ath12k/mac.c b/drivers/net/wireless/ath/ath12k/mac.c index ef9e3558f5eb..895bf9d19457 100644 --- a/drivers/net/wireless/ath/ath12k/mac.c +++ b/drivers/net/wireless/ath/ath12k/mac.c @@ -5901,14 +5901,13 @@ static int ath12k_mac_op_set_antenna(struct ieee80211_hw *hw, u32 tx_ant, u32 rx return ret; } -static int ath12k_mac_op_ampdu_action(struct ieee80211_hw *hw, - struct ieee80211_vif *vif, - struct ieee80211_ampdu_params *params) +static int ath12k_mac_ampdu_action(struct ath12k_vif *arvif, + struct ieee80211_ampdu_params *params) { - struct ath12k *ar = hw->priv; + struct ath12k *ar = arvif->ar; int ret = -EINVAL; - mutex_lock(&ar->conf_mutex); + lockdep_assert_held(&ar->conf_mutex); switch (params->action) { case IEEE80211_AMPDU_RX_START: @@ -5929,8 +5928,25 @@ static int ath12k_mac_op_ampdu_action(struct ieee80211_hw *hw, break; } + return ret; +} + +static int ath12k_mac_op_ampdu_action(struct ieee80211_hw *hw, + struct ieee80211_vif *vif, + struct ieee80211_ampdu_params *params) +{ + struct ath12k *ar = hw->priv; + struct ath12k_vif *arvif = ath12k_vif_to_arvif(vif); + int ret = -EINVAL; + + mutex_lock(&ar->conf_mutex); + ret = ath12k_mac_ampdu_action(arvif, params); mutex_unlock(&ar->conf_mutex); + if (ret) + ath12k_warn(ar->ab, "pdev idx %d unable to perform ampdu action %d ret %d\n", + ar->pdev_idx, params->action, ret); + return ret; } From b33dcbe8d53d1e57cfc9bc035f43a27af5b6a973 Mon Sep 17 00:00:00 2001 From: Karthikeyan Periyasamy Date: Sun, 14 Jan 2024 17:02:41 +0200 Subject: [PATCH 47/71] wifi: ath12k: refactor ath12k_mac_op_flush() To support single wiphy abstraction, introduce link/radio specific helper function in the mac80211 callback flush(). This way, the callback can be extended to handle multiple link/radio in the future. Tested-on: QCN9274 hw2.0 PCI WLAN.WBE.1.0.1-00029-QCAHKSWPL_SILICONZ-1 Tested-on: WCN7850 hw2.0 PCI WLAN.HMT.1.0-03427-QCAHMTSWPL_V1.0_V2.0_SILICONZ-1.15378.4 Signed-off-by: Karthikeyan Periyasamy Acked-by: Jeff Johnson Signed-off-by: Kalle Valo Link: https://msgid.link/20240103063731.3356060-10-quic_periyasa@quicinc.com --- drivers/net/wireless/ath/ath12k/mac.c | 18 ++++++++++++------ 1 file changed, 12 insertions(+), 6 deletions(-) diff --git a/drivers/net/wireless/ath/ath12k/mac.c b/drivers/net/wireless/ath/ath12k/mac.c index 895bf9d19457..ce916bf2dcc9 100644 --- a/drivers/net/wireless/ath/ath12k/mac.c +++ b/drivers/net/wireless/ath/ath12k/mac.c @@ -6644,15 +6644,10 @@ static int ath12k_mac_op_set_frag_threshold(struct ieee80211_hw *hw, u32 value) return -EOPNOTSUPP; } -static void ath12k_mac_op_flush(struct ieee80211_hw *hw, struct ieee80211_vif *vif, - u32 queues, bool drop) +static void ath12k_mac_flush(struct ath12k *ar) { - struct ath12k *ar = hw->priv; long time_left; - if (drop) - return; - time_left = wait_event_timeout(ar->dp.tx_empty_waitq, (atomic_read(&ar->dp.num_tx_pending) == 0), ATH12K_FLUSH_TIMEOUT); @@ -6667,6 +6662,17 @@ static void ath12k_mac_op_flush(struct ieee80211_hw *hw, struct ieee80211_vif *v time_left); } +static void ath12k_mac_op_flush(struct ieee80211_hw *hw, struct ieee80211_vif *vif, + u32 queues, bool drop) +{ + struct ath12k *ar = hw->priv; + + if (drop) + return; + + ath12k_mac_flush(ar); +} + static int ath12k_mac_bitrate_mask_num_ht_rates(struct ath12k *ar, enum nl80211_band band, From 5bdfb8c9db223009d15a2379b87d16cc800d439a Mon Sep 17 00:00:00 2001 From: Karthikeyan Periyasamy Date: Sun, 14 Jan 2024 17:02:41 +0200 Subject: [PATCH 48/71] wifi: ath12k: ath12k_start_vdev_delay(): convert to use ar To support single wiphy abstraction, remove the mac80211 hw data dependency from the start vdev delay function. This way, this function can be extended to handle multiple link/radio in the future. Tested-on: QCN9274 hw2.0 PCI WLAN.WBE.1.0.1-00029-QCAHKSWPL_SILICONZ-1 Tested-on: WCN7850 hw2.0 PCI WLAN.HMT.1.0-03427-QCAHMTSWPL_V1.0_V2.0_SILICONZ-1.15378.4 Signed-off-by: Karthikeyan Periyasamy Acked-by: Jeff Johnson Signed-off-by: Kalle Valo Link: https://msgid.link/20240103063731.3356060-11-quic_periyasa@quicinc.com --- drivers/net/wireless/ath/ath12k/mac.c | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/drivers/net/wireless/ath/ath12k/mac.c b/drivers/net/wireless/ath/ath12k/mac.c index ce916bf2dcc9..a90c0309230a 100644 --- a/drivers/net/wireless/ath/ath12k/mac.c +++ b/drivers/net/wireless/ath/ath12k/mac.c @@ -241,8 +241,8 @@ static const u32 ath12k_smps_map[] = { [WLAN_HT_CAP_SM_PS_DISABLED] = WMI_PEER_SMPS_PS_NONE, }; -static int ath12k_start_vdev_delay(struct ieee80211_hw *hw, - struct ieee80211_vif *vif); +static int ath12k_start_vdev_delay(struct ath12k *ar, + struct ath12k_vif *arvif); static const char *ath12k_mac_phymode_str(enum wmi_phy_mode mode) { @@ -3718,7 +3718,7 @@ static int ath12k_mac_station_add(struct ath12k *ar, if (ab->hw_params->vdev_start_delay && !arvif->is_started && arvif->vdev_type != WMI_VDEV_TYPE_AP) { - ret = ath12k_start_vdev_delay(ar->hw, vif); + ret = ath12k_start_vdev_delay(ar, arvif); if (ret) { ath12k_warn(ab, "failed to delay vdev start: %d\n", ret); goto free_peer; @@ -6411,12 +6411,11 @@ static void ath12k_mac_op_change_chanctx(struct ieee80211_hw *hw, mutex_unlock(&ar->conf_mutex); } -static int ath12k_start_vdev_delay(struct ieee80211_hw *hw, - struct ieee80211_vif *vif) +static int ath12k_start_vdev_delay(struct ath12k *ar, + struct ath12k_vif *arvif) { - struct ath12k *ar = hw->priv; struct ath12k_base *ab = ar->ab; - struct ath12k_vif *arvif = ath12k_vif_to_arvif(vif); + struct ieee80211_vif *vif = arvif->vif; int ret; if (WARN_ON(arvif->is_started)) From 9666ad011992b51da2a4623d20084a363a3a095e Mon Sep 17 00:00:00 2001 From: Jeff Johnson Date: Sun, 14 Jan 2024 17:02:42 +0200 Subject: [PATCH 49/71] wifi: ath11k: document HAL_RX_BUF_RBM_SW4_BM Commit 7636c9a6e7d7 ("wifi: ath11k: Add multi TX ring support for WCN6750") added HAL_RX_BUF_RBM_SW4_BM to enum hal_rx_buf_return_buf_manager. However, as flagged by the kernel-doc script, the documentation was not updated: drivers/net/wireless/ath/ath11k/hal.h:689: warning: Enum value 'HAL_RX_BUF_RBM_SW4_BM' not described in enum 'hal_rx_buf_return_buf_manager' So update the documentation. No functional changes, compile tested only. Signed-off-by: Jeff Johnson Signed-off-by: Kalle Valo Link: https://msgid.link/20240111-document-hal_rx_buf_rbm_sw4_bm-v1-1-ad277e8ab3cc@quicinc.com --- drivers/net/wireless/ath/ath11k/hal.h | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/net/wireless/ath/ath11k/hal.h b/drivers/net/wireless/ath/ath11k/hal.h index 80447f488954..65e8f244ebb9 100644 --- a/drivers/net/wireless/ath/ath11k/hal.h +++ b/drivers/net/wireless/ath/ath11k/hal.h @@ -1,7 +1,7 @@ /* SPDX-License-Identifier: BSD-3-Clause-Clear */ /* * Copyright (c) 2018-2019 The Linux Foundation. All rights reserved. - * Copyright (c) 2021-2022 Qualcomm Innovation Center, Inc. All rights reserved. + * Copyright (c) 2021-2022, 2024 Qualcomm Innovation Center, Inc. All rights reserved. */ #ifndef ATH11K_HAL_H @@ -674,6 +674,7 @@ struct hal_srng_config { * @HAL_RX_BUF_RBM_SW1_BM: For Tx completion -- returned to host * @HAL_RX_BUF_RBM_SW2_BM: For Tx completion -- returned to host * @HAL_RX_BUF_RBM_SW3_BM: For Rx release -- returned to host + * @HAL_RX_BUF_RBM_SW4_BM: For Tx completion -- returned to host */ enum hal_rx_buf_return_buf_manager { From 76fece36f17a535c75ebc83d026bacad1263fd37 Mon Sep 17 00:00:00 2001 From: Karthikeyan Periyasamy Date: Tue, 16 Jan 2024 14:33:07 +0200 Subject: [PATCH 50/71] wifi: ath12k: refactor QMI MLO host capability helper function Currently, QMI MLO host capability parameters are specific to the WCN7850 platform. To make use of this helper function across all the platforms, move the platform specific MLO capability parameter to the HW param configuration. Tested-on: QCN9274 hw2.0 PCI WLAN.WBE.1.0.1-00029-QCAHKSWPL_SILICONZ-1 Tested-on: WCN7850 hw2.0 PCI WLAN.HMT.1.0.c5-00481-QCAHMTSWPL_V1.0_V2.0_SILICONZ-3 Signed-off-by: Karthikeyan Periyasamy Acked-by: Jeff Johnson Signed-off-by: Kalle Valo Link: https://msgid.link/20240113001659.1022465-2-quic_periyasa@quicinc.com --- drivers/net/wireless/ath/ath12k/hw.c | 9 +++++++ drivers/net/wireless/ath/ath12k/hw.h | 3 +++ drivers/net/wireless/ath/ath12k/qmi.c | 34 +++++++++++++++++++-------- 3 files changed, 36 insertions(+), 10 deletions(-) diff --git a/drivers/net/wireless/ath/ath12k/hw.c b/drivers/net/wireless/ath/ath12k/hw.c index de60d988d860..cbb6e2b6d826 100644 --- a/drivers/net/wireless/ath/ath12k/hw.c +++ b/drivers/net/wireless/ath/ath12k/hw.c @@ -914,6 +914,9 @@ static const struct ath12k_hw_params ath12k_hw_params[] = { .rfkill_on_level = 0, .rddm_size = 0, + + .def_num_link = 0, + .max_mlo_peer = 256, }, { .name = "wcn7850 hw2.0", @@ -978,6 +981,9 @@ static const struct ath12k_hw_params ath12k_hw_params[] = { .rfkill_on_level = 1, .rddm_size = 0x780000, + + .def_num_link = 2, + .max_mlo_peer = 32, }, { .name = "qcn9274 hw2.0", @@ -1040,6 +1046,9 @@ static const struct ath12k_hw_params ath12k_hw_params[] = { .rfkill_on_level = 0, .rddm_size = 0, + + .def_num_link = 0, + .max_mlo_peer = 256, }, }; diff --git a/drivers/net/wireless/ath/ath12k/hw.h b/drivers/net/wireless/ath/ath12k/hw.h index fa8230def22b..0c3b416ae150 100644 --- a/drivers/net/wireless/ath/ath12k/hw.h +++ b/drivers/net/wireless/ath/ath12k/hw.h @@ -192,6 +192,9 @@ struct ath12k_hw_params { u32 rfkill_on_level; u32 rddm_size; + + u8 def_num_link; + u16 max_mlo_peer; }; struct ath12k_hw_ops { diff --git a/drivers/net/wireless/ath/ath12k/qmi.c b/drivers/net/wireless/ath/ath12k/qmi.c index c4c7f31a91cd..916dec626702 100644 --- a/drivers/net/wireless/ath/ath12k/qmi.c +++ b/drivers/net/wireless/ath/ath12k/qmi.c @@ -1893,8 +1893,16 @@ static const struct qmi_elem_info qmi_wlanfw_fw_ready_ind_msg_v01_ei[] = { }, }; -static void ath12k_host_cap_parse_mlo(struct qmi_wlanfw_host_cap_req_msg_v01 *req) +static void ath12k_host_cap_parse_mlo(struct ath12k_base *ab, + struct qmi_wlanfw_host_cap_req_msg_v01 *req) { + struct wlfw_host_mlo_chip_info_s_v01 *info; + u8 hw_link_id = 0; + int i; + + if (!ab->hw_params->def_num_link) + return; + req->mlo_capable_valid = 1; req->mlo_capable = 1; req->mlo_chip_id_valid = 1; @@ -1905,16 +1913,22 @@ static void ath12k_host_cap_parse_mlo(struct qmi_wlanfw_host_cap_req_msg_v01 *re /* Max peer number generally won't change for the same device * but needs to be synced with host driver. */ - req->max_mlo_peer = 32; + req->max_mlo_peer = ab->hw_params->max_mlo_peer; req->mlo_num_chips_valid = 1; req->mlo_num_chips = 1; + + info = &req->mlo_chip_info[0]; + info->chip_id = 0; + info->num_local_links = ab->hw_params->def_num_link; + + for (i = 0; i < info->num_local_links; i++) { + info->hw_link_id[i] = hw_link_id; + info->valid_mlo_link_id[i] = 1; + + hw_link_id++; + } + req->mlo_chip_info_valid = 1; - req->mlo_chip_info[0].chip_id = 0; - req->mlo_chip_info[0].num_local_links = 2; - req->mlo_chip_info[0].hw_link_id[0] = 0; - req->mlo_chip_info[0].hw_link_id[1] = 1; - req->mlo_chip_info[0].valid_mlo_link_id[0] = 1; - req->mlo_chip_info[0].valid_mlo_link_id[1] = 1; } static int ath12k_qmi_host_cap_send(struct ath12k_base *ab) @@ -1960,10 +1974,10 @@ static int ath12k_qmi_host_cap_send(struct ath12k_base *ab) */ req.nm_modem |= SLEEP_CLOCK_SELECT_INTERNAL_BIT; req.nm_modem |= PLATFORM_CAP_PCIE_GLOBAL_RESET; - - ath12k_host_cap_parse_mlo(&req); } + ath12k_host_cap_parse_mlo(ab, &req); + ret = qmi_txn_init(&ab->qmi.handle, &txn, qmi_wlanfw_host_cap_resp_msg_v01_ei, &resp); if (ret < 0) From 53a65445c144f99a6769788d0c04b64cdbb497d4 Mon Sep 17 00:00:00 2001 From: Karthikeyan Periyasamy Date: Tue, 16 Jan 2024 14:33:07 +0200 Subject: [PATCH 51/71] wifi: ath12k: add QMI PHY capability learn support Currently, the number of PHY is learned from the firmware service ready event message. However, on the QCN9274 platform, number of PHY is a variable parameter. To enable MLO capability in the QMI host capability request message, the driver needs the PHY count information earlier than the firmware service ready event. Therefore, a new QMI message, "PHY capability message", is introduced to retrieve this information. This message allows the driver to fill in the MLO parameter in the QMI host capability request message. If the new QMI PHY capability message fails, the default configuration in the HW params will be used. Tested-on: QCN9274 hw2.0 PCI WLAN.WBE.1.0.1-00029-QCAHKSWPL_SILICONZ-1 Tested-on: WCN7850 hw2.0 PCI WLAN.HMT.1.0.c5-00481-QCAHMTSWPL_V1.0_V2.0_SILICONZ-3 Signed-off-by: Karthikeyan Periyasamy Acked-by: Jeff Johnson Signed-off-by: Kalle Valo Link: https://msgid.link/20240113001659.1022465-3-quic_periyasa@quicinc.com --- drivers/net/wireless/ath/ath12k/core.c | 1 + drivers/net/wireless/ath/ath12k/qmi.c | 124 ++++++++++++++++++++++++- drivers/net/wireless/ath/ath12k/qmi.h | 17 ++++ 3 files changed, 140 insertions(+), 2 deletions(-) diff --git a/drivers/net/wireless/ath/ath12k/core.c b/drivers/net/wireless/ath/ath12k/core.c index ababe7f01b5b..6cab747ff858 100644 --- a/drivers/net/wireless/ath/ath12k/core.c +++ b/drivers/net/wireless/ath/ath12k/core.c @@ -1174,6 +1174,7 @@ struct ath12k_base *ath12k_core_alloc(struct device *dev, size_t priv_size, ab->dev = dev; ab->hif.bus = bus; + ab->qmi.num_radios = U8_MAX; return ab; diff --git a/drivers/net/wireless/ath/ath12k/qmi.c b/drivers/net/wireless/ath/ath12k/qmi.c index 916dec626702..d20d08023c81 100644 --- a/drivers/net/wireless/ath/ath12k/qmi.c +++ b/drivers/net/wireless/ath/ath12k/qmi.c @@ -528,6 +528,67 @@ static const struct qmi_elem_info qmi_wlanfw_host_cap_resp_msg_v01_ei[] = { }, }; +static const struct qmi_elem_info qmi_wlanfw_phy_cap_req_msg_v01_ei[] = { + { + .data_type = QMI_EOTI, + .array_type = NO_ARRAY, + .tlv_type = QMI_COMMON_TLV_TYPE, + }, +}; + +static const struct qmi_elem_info qmi_wlanfw_phy_cap_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_phy_cap_resp_msg_v01, resp), + .ei_array = qmi_response_type_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_phy_cap_resp_msg_v01, + num_phy_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_phy_cap_resp_msg_v01, + num_phy), + }, + { + .data_type = QMI_OPT_FLAG, + .elem_len = 1, + .elem_size = sizeof(u8), + .array_type = NO_ARRAY, + .tlv_type = 0x11, + .offset = offsetof(struct qmi_wlanfw_phy_cap_resp_msg_v01, + board_id_valid), + }, + { + .data_type = QMI_UNSIGNED_4_BYTE, + .elem_len = 1, + .elem_size = sizeof(u32), + .array_type = NO_ARRAY, + .tlv_type = 0x11, + .offset = offsetof(struct qmi_wlanfw_phy_cap_resp_msg_v01, + board_id), + }, + { + .data_type = QMI_EOTI, + .array_type = NO_ARRAY, + .tlv_type = QMI_COMMON_TLV_TYPE, + }, +}; + static const struct qmi_elem_info qmi_wlanfw_ind_register_req_msg_v01_ei[] = { { .data_type = QMI_OPT_FLAG, @@ -1900,8 +1961,12 @@ static void ath12k_host_cap_parse_mlo(struct ath12k_base *ab, u8 hw_link_id = 0; int i; - if (!ab->hw_params->def_num_link) + if (!ab->qmi.num_radios || ab->qmi.num_radios == U8_MAX) { + ath12k_dbg(ab, ATH12K_DBG_QMI, + "skip QMI MLO cap due to invalid num_radio %d\n", + ab->qmi.num_radios); return; + } req->mlo_capable_valid = 1; req->mlo_capable = 1; @@ -1919,7 +1984,7 @@ static void ath12k_host_cap_parse_mlo(struct ath12k_base *ab, info = &req->mlo_chip_info[0]; info->chip_id = 0; - info->num_local_links = ab->hw_params->def_num_link; + info->num_local_links = ab->qmi.num_radios; for (i = 0; i < info->num_local_links; i++) { info->hw_link_id[i] = hw_link_id; @@ -2008,6 +2073,59 @@ static int ath12k_qmi_host_cap_send(struct ath12k_base *ab) return ret; } +static void ath12k_qmi_phy_cap_send(struct ath12k_base *ab) +{ + struct qmi_wlanfw_phy_cap_req_msg_v01 req = {}; + struct qmi_wlanfw_phy_cap_resp_msg_v01 resp = {}; + struct qmi_txn txn; + int ret; + + ret = qmi_txn_init(&ab->qmi.handle, &txn, + qmi_wlanfw_phy_cap_resp_msg_v01_ei, &resp); + if (ret < 0) + goto out; + + ret = qmi_send_request(&ab->qmi.handle, NULL, &txn, + QMI_WLANFW_PHY_CAP_REQ_V01, + QMI_WLANFW_PHY_CAP_REQ_MSG_V01_MAX_LEN, + qmi_wlanfw_phy_cap_req_msg_v01_ei, &req); + if (ret < 0) { + qmi_txn_cancel(&txn); + ath12k_warn(ab, "failed to send phy capability request: %d\n", ret); + goto out; + } + + ret = qmi_txn_wait(&txn, msecs_to_jiffies(ATH12K_QMI_WLANFW_TIMEOUT_MS)); + if (ret < 0) + goto out; + + if (resp.resp.result != QMI_RESULT_SUCCESS_V01) { + ret = -EOPNOTSUPP; + goto out; + } + + if (!resp.num_phy_valid) { + ret = -ENODATA; + goto out; + } + + ab->qmi.num_radios = resp.num_phy; + + ath12k_dbg(ab, ATH12K_DBG_QMI, "phy capability resp valid %d num_phy %d valid %d board_id %d\n", + resp.num_phy_valid, resp.num_phy, + resp.board_id_valid, resp.board_id); + + return; + +out: + /* If PHY capability not advertised then rely on default num link */ + ab->qmi.num_radios = ab->hw_params->def_num_link; + + ath12k_dbg(ab, ATH12K_DBG_QMI, + "no valid response from PHY capability, choose default num_phy %d\n", + ab->qmi.num_radios); +} + static int ath12k_qmi_fw_ind_register_send(struct ath12k_base *ab) { struct qmi_wlanfw_ind_register_req_msg_v01 *req; @@ -2794,6 +2912,8 @@ static int ath12k_qmi_event_server_arrive(struct ath12k_qmi *qmi) struct ath12k_base *ab = qmi->ab; int ret; + ath12k_qmi_phy_cap_send(ab); + ret = ath12k_qmi_fw_ind_register_send(ab); if (ret < 0) { ath12k_warn(ab, "qmi failed to send FW indication QMI:%d\n", ret); diff --git a/drivers/net/wireless/ath/ath12k/qmi.h b/drivers/net/wireless/ath/ath12k/qmi.h index e25bbaa125e8..bfed22c310be 100644 --- a/drivers/net/wireless/ath/ath12k/qmi.h +++ b/drivers/net/wireless/ath/ath12k/qmi.h @@ -141,6 +141,7 @@ struct ath12k_qmi { u32 target_mem_mode; bool target_mem_delayed; u8 cal_done; + u8 num_radios; struct target_info target; struct m3_mem_region m3_mem; unsigned int service_ins_id; @@ -251,6 +252,22 @@ struct qmi_wlanfw_host_cap_resp_msg_v01 { struct qmi_response_type_v01 resp; }; +#define QMI_WLANFW_PHY_CAP_REQ_MSG_V01_MAX_LEN 0 +#define QMI_WLANFW_PHY_CAP_REQ_V01 0x0057 +#define QMI_WLANFW_PHY_CAP_RESP_MSG_V01_MAX_LEN 18 +#define QMI_WLANFW_PHY_CAP_RESP_V01 0x0057 + +struct qmi_wlanfw_phy_cap_req_msg_v01 { +}; + +struct qmi_wlanfw_phy_cap_resp_msg_v01 { + struct qmi_response_type_v01 resp; + u8 num_phy_valid; + u8 num_phy; + u8 board_id_valid; + u32 board_id; +}; + #define QMI_WLANFW_IND_REGISTER_REQ_MSG_V01_MAX_LEN 54 #define QMI_WLANFW_IND_REGISTER_REQ_V01 0x0020 #define QMI_WLANFW_IND_REGISTER_RESP_MSG_V01_MAX_LEN 18 From 49b88e5f3fa114ed187f876082aa5bc4349f5bc7 Mon Sep 17 00:00:00 2001 From: Karthikeyan Periyasamy Date: Wed, 17 Jan 2024 13:34:29 +0530 Subject: [PATCH 52/71] wifi: ath12k: replace ENOTSUPP with EOPNOTSUPP ENOTSUPP is not a standard error code, don't use it. Replace with EOPNOTSUPP instead. No functional changes, compile tested only. Signed-off-by: Karthikeyan Periyasamy Acked-by: Jeff Johnson Signed-off-by: Kalle Valo Link: https://msgid.link/20240117080431.2907471-2-quic_periyasa@quicinc.com --- drivers/net/wireless/ath/ath12k/dp_tx.c | 6 +++--- drivers/net/wireless/ath/ath12k/hal_rx.c | 4 ++-- drivers/net/wireless/ath/ath12k/mac.c | 8 ++++---- 3 files changed, 9 insertions(+), 9 deletions(-) diff --git a/drivers/net/wireless/ath/ath12k/dp_tx.c b/drivers/net/wireless/ath/ath12k/dp_tx.c index 62f9cdbb811c..05d5f14cdfa1 100644 --- a/drivers/net/wireless/ath/ath12k/dp_tx.c +++ b/drivers/net/wireless/ath/ath12k/dp_tx.c @@ -1,7 +1,7 @@ // SPDX-License-Identifier: BSD-3-Clause-Clear /* * Copyright (c) 2018-2021 The Linux Foundation. All rights reserved. - * Copyright (c) 2021-2023 Qualcomm Innovation Center, Inc. All rights reserved. + * Copyright (c) 2021-2024 Qualcomm Innovation Center, Inc. All rights reserved. */ #include "core.h" @@ -151,7 +151,7 @@ int ath12k_dp_tx(struct ath12k *ar, struct ath12k_vif *arvif, if (!(info->flags & IEEE80211_TX_CTL_HW_80211_ENCAP) && !ieee80211_is_data(hdr->frame_control)) - return -ENOTSUPP; + return -EOPNOTSUPP; pool_id = skb_get_queue_mapping(skb) & (ATH12K_HW_MAX_QUEUES - 1); @@ -837,7 +837,7 @@ int ath12k_dp_tx_htt_h2t_ver_req_msg(struct ath12k_base *ab) if (dp->htt_tgt_ver_major != HTT_TARGET_VERSION_MAJOR) { ath12k_err(ab, "unsupported htt major version %d supported version is %d\n", dp->htt_tgt_ver_major, HTT_TARGET_VERSION_MAJOR); - return -ENOTSUPP; + return -EOPNOTSUPP; } return 0; diff --git a/drivers/net/wireless/ath/ath12k/hal_rx.c b/drivers/net/wireless/ath/ath12k/hal_rx.c index 4f25eb9f7745..4fc08d4f85b5 100644 --- a/drivers/net/wireless/ath/ath12k/hal_rx.c +++ b/drivers/net/wireless/ath/ath12k/hal_rx.c @@ -1,7 +1,7 @@ // SPDX-License-Identifier: BSD-3-Clause-Clear /* * Copyright (c) 2018-2021 The Linux Foundation. All rights reserved. - * Copyright (c) 2021-2023 Qualcomm Innovation Center, Inc. All rights reserved. + * Copyright (c) 2021-2024 Qualcomm Innovation Center, Inc. All rights reserved. */ #include "debug.h" @@ -247,7 +247,7 @@ int ath12k_hal_reo_cmd_send(struct ath12k_base *ab, struct hal_srng *srng, case HAL_REO_CMD_UNBLOCK_CACHE: case HAL_REO_CMD_FLUSH_TIMEOUT_LIST: ath12k_warn(ab, "Unsupported reo command %d\n", type); - ret = -ENOTSUPP; + ret = -EOPNOTSUPP; break; default: ath12k_warn(ab, "Unknown reo command %d\n", type); diff --git a/drivers/net/wireless/ath/ath12k/mac.c b/drivers/net/wireless/ath/ath12k/mac.c index a90c0309230a..d453e4165228 100644 --- a/drivers/net/wireless/ath/ath12k/mac.c +++ b/drivers/net/wireless/ath/ath12k/mac.c @@ -5055,7 +5055,7 @@ void ath12k_mac_drain_tx(struct ath12k *ar) static int ath12k_mac_config_mon_status_default(struct ath12k *ar, bool enable) { - return -ENOTSUPP; + return -EOPNOTSUPP; /* TODO: Need to support new monitor mode */ } @@ -5165,13 +5165,13 @@ static int ath12k_mac_start(struct ath12k *ar) * such as rssi, rx_duration. */ ret = ath12k_mac_config_mon_status_default(ar, true); - if (ret && (ret != -ENOTSUPP)) { + if (ret && (ret != -EOPNOTSUPP)) { ath12k_err(ab, "failed to configure monitor status ring with default rx_filter: (%d)\n", ret); goto err; } - if (ret == -ENOTSUPP) + if (ret == -EOPNOTSUPP) ath12k_dbg(ab, ATH12K_DBG_MAC, "monitor status config is not yet supported"); @@ -5283,7 +5283,7 @@ static void ath12k_mac_stop(struct ath12k *ar) mutex_lock(&ar->conf_mutex); ret = ath12k_mac_config_mon_status_default(ar, false); - if (ret && (ret != -ENOTSUPP)) + if (ret && (ret != -EOPNOTSUPP)) ath12k_err(ar->ab, "failed to clear rx_filter for monitor status ring: (%d)\n", ret); From 3422402bacd0322875be2e2a97a98e67d30c1b14 Mon Sep 17 00:00:00 2001 From: Karthikeyan Periyasamy Date: Wed, 17 Jan 2024 13:34:30 +0530 Subject: [PATCH 53/71] wifi: ath11k: replace ENOTSUPP with EOPNOTSUPP ENOTSUPP is not a standard error code, don't use it. Replace with EOPNOTSUPP instead. No functional changes, compile tested only. Signed-off-by: Karthikeyan Periyasamy Acked-by: Jeff Johnson Signed-off-by: Kalle Valo Link: https://msgid.link/20240117080431.2907471-3-quic_periyasa@quicinc.com --- drivers/net/wireless/ath/ath11k/dp_tx.c | 6 +++--- drivers/net/wireless/ath/ath11k/hal_rx.c | 4 ++-- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/drivers/net/wireless/ath/ath11k/dp_tx.c b/drivers/net/wireless/ath/ath11k/dp_tx.c index c1072e66e3e8..272b1c35f98d 100644 --- a/drivers/net/wireless/ath/ath11k/dp_tx.c +++ b/drivers/net/wireless/ath/ath11k/dp_tx.c @@ -1,7 +1,7 @@ // SPDX-License-Identifier: BSD-3-Clause-Clear /* * Copyright (c) 2018-2019 The Linux Foundation. All rights reserved. - * Copyright (c) 2021-2023 Qualcomm Innovation Center, Inc. All rights reserved. + * Copyright (c) 2021-2024 Qualcomm Innovation Center, Inc. All rights reserved. */ #include "core.h" @@ -103,7 +103,7 @@ int ath11k_dp_tx(struct ath11k *ar, struct ath11k_vif *arvif, if (unlikely(!(info->flags & IEEE80211_TX_CTL_HW_80211_ENCAP) && !ieee80211_is_data(hdr->frame_control))) - return -ENOTSUPP; + return -EOPNOTSUPP; pool_id = skb_get_queue_mapping(skb) & (ATH11K_HW_MAX_QUEUES - 1); @@ -1018,7 +1018,7 @@ int ath11k_dp_tx_htt_h2t_ver_req_msg(struct ath11k_base *ab) if (dp->htt_tgt_ver_major != HTT_TARGET_VERSION_MAJOR) { ath11k_err(ab, "unsupported htt major version %d supported version is %d\n", dp->htt_tgt_ver_major, HTT_TARGET_VERSION_MAJOR); - return -ENOTSUPP; + return -EOPNOTSUPP; } return 0; diff --git a/drivers/net/wireless/ath/ath11k/hal_rx.c b/drivers/net/wireless/ath/ath11k/hal_rx.c index e758ee8e17c9..8f7dd43dc1bd 100644 --- a/drivers/net/wireless/ath/ath11k/hal_rx.c +++ b/drivers/net/wireless/ath/ath11k/hal_rx.c @@ -1,7 +1,7 @@ // SPDX-License-Identifier: BSD-3-Clause-Clear /* * Copyright (c) 2018-2019 The Linux Foundation. All rights reserved. - * Copyright (c) 2021-2023 Qualcomm Innovation Center, Inc. All rights reserved. + * Copyright (c) 2021-2024 Qualcomm Innovation Center, Inc. All rights reserved. */ #include "debug.h" @@ -246,7 +246,7 @@ int ath11k_hal_reo_cmd_send(struct ath11k_base *ab, struct hal_srng *srng, case HAL_REO_CMD_UNBLOCK_CACHE: case HAL_REO_CMD_FLUSH_TIMEOUT_LIST: ath11k_warn(ab, "Unsupported reo command %d\n", type); - ret = -ENOTSUPP; + ret = -EOPNOTSUPP; break; default: ath11k_warn(ab, "Unknown reo command %d\n", type); From bc2ef64931c263104532723e9d8d923cfb357ab6 Mon Sep 17 00:00:00 2001 From: Karthikeyan Periyasamy Date: Wed, 17 Jan 2024 13:34:31 +0530 Subject: [PATCH 54/71] wifi: ath10k: replace ENOTSUPP with EOPNOTSUPP ENOTSUPP is not a standard error code, don't use it. Replace with EOPNOTSUPP instead. No functional changes, compile tested only. Signed-off-by: Karthikeyan Periyasamy Acked-by: Jeff Johnson Signed-off-by: Kalle Valo Link: https://msgid.link/20240117080431.2907471-4-quic_periyasa@quicinc.com --- drivers/net/wireless/ath/ath10k/core.c | 4 ++-- drivers/net/wireless/ath/ath10k/htt.c | 3 ++- drivers/net/wireless/ath/ath10k/mac.c | 6 +++--- drivers/net/wireless/ath/ath10k/pci.c | 10 +++++----- drivers/net/wireless/ath/ath10k/wmi-tlv.c | 7 ++++--- drivers/net/wireless/ath/ath10k/wmi.c | 12 ++++++------ 6 files changed, 22 insertions(+), 20 deletions(-) diff --git a/drivers/net/wireless/ath/ath10k/core.c b/drivers/net/wireless/ath/ath10k/core.c index 0032f8aa892f..9ce6f49ab261 100644 --- a/drivers/net/wireless/ath/ath10k/core.c +++ b/drivers/net/wireless/ath/ath10k/core.c @@ -3,7 +3,7 @@ * Copyright (c) 2005-2011 Atheros Communications Inc. * Copyright (c) 2011-2017 Qualcomm Atheros, Inc. * Copyright (c) 2018-2019, The Linux Foundation. All rights reserved. - * Copyright (c) 2021-2023 Qualcomm Innovation Center, Inc. All rights reserved. + * Copyright (c) 2021-2024 Qualcomm Innovation Center, Inc. All rights reserved. */ #include @@ -3613,7 +3613,7 @@ struct ath10k *ath10k_core_create(size_t priv_size, struct device *dev, default: ath10k_err(ar, "unsupported core hardware revision %d\n", hw_rev); - ret = -ENOTSUPP; + ret = -EOPNOTSUPP; goto err_free_mac; } diff --git a/drivers/net/wireless/ath/ath10k/htt.c b/drivers/net/wireless/ath/ath10k/htt.c index 907e1e13871a..dbaf262cd7c1 100644 --- a/drivers/net/wireless/ath/ath10k/htt.c +++ b/drivers/net/wireless/ath/ath10k/htt.c @@ -2,6 +2,7 @@ /* * Copyright (c) 2005-2011 Atheros Communications Inc. * Copyright (c) 2011-2017 Qualcomm Atheros, Inc. + * Copyright (c) 2024 Qualcomm Innovation Center, Inc. All rights reserved. */ #include @@ -381,7 +382,7 @@ static int ath10k_htt_verify_version(struct ath10k_htt *htt) htt->target_version_major != 3) { ath10k_err(ar, "unsupported htt major version %d. supported versions are 2 and 3\n", htt->target_version_major); - return -ENOTSUPP; + return -EOPNOTSUPP; } return 0; diff --git a/drivers/net/wireless/ath/ath10k/mac.c b/drivers/net/wireless/ath/ath10k/mac.c index 090bcf148d0c..fc503db2fd8e 100644 --- a/drivers/net/wireless/ath/ath10k/mac.c +++ b/drivers/net/wireless/ath/ath10k/mac.c @@ -3,7 +3,7 @@ * Copyright (c) 2005-2011 Atheros Communications Inc. * Copyright (c) 2011-2017 Qualcomm Atheros, Inc. * Copyright (c) 2018-2019, The Linux Foundation. All rights reserved. - * Copyright (c) 2021-2023 Qualcomm Innovation Center, Inc. All rights reserved. + * Copyright (c) 2021-2024 Qualcomm Innovation Center, Inc. All rights reserved. */ #include "mac.h" @@ -4056,7 +4056,7 @@ static int ath10k_mac_tx(struct ath10k *ar, !(skb_cb->flags & ATH10K_SKB_F_RAW_TX)) { WARN_ON_ONCE(1); ieee80211_free_txskb(hw, skb); - return -ENOTSUPP; + return -EOPNOTSUPP; } } @@ -7065,7 +7065,7 @@ static int ath10k_mac_set_tid_config(struct ath10k *ar, struct ieee80211_sta *st if (sta) { if (!sta->wme) - return -ENOTSUPP; + return -EOPNOTSUPP; arsta = (struct ath10k_sta *)sta->drv_priv; diff --git a/drivers/net/wireless/ath/ath10k/pci.c b/drivers/net/wireless/ath/ath10k/pci.c index 3de2de6d44bc..5c34b156b4ff 100644 --- a/drivers/net/wireless/ath/ath10k/pci.c +++ b/drivers/net/wireless/ath/ath10k/pci.c @@ -2,7 +2,7 @@ /* * Copyright (c) 2005-2011 Atheros Communications Inc. * Copyright (c) 2011-2017 Qualcomm Atheros, Inc. - * Copyright (c) 2022-2023 Qualcomm Innovation Center, Inc. All rights reserved. + * Copyright (c) 2022-2024 Qualcomm Innovation Center, Inc. All rights reserved. */ #include @@ -889,7 +889,7 @@ static u32 ath10k_pci_targ_cpu_to_ce_addr(struct ath10k *ar, u32 addr) struct ath10k_pci *ar_pci = ath10k_pci_priv(ar); if (WARN_ON_ONCE(!ar_pci->targ_cpu_to_ce_addr)) - return -ENOTSUPP; + return -EOPNOTSUPP; return ar_pci->targ_cpu_to_ce_addr(ar, addr); } @@ -2668,7 +2668,7 @@ static int ath10k_pci_safe_chip_reset(struct ath10k *ar) struct ath10k_pci *ar_pci = ath10k_pci_priv(ar); if (!ar_pci->pci_soft_reset) - return -ENOTSUPP; + return -EOPNOTSUPP; return ar_pci->pci_soft_reset(ar); } @@ -2808,7 +2808,7 @@ static int ath10k_pci_chip_reset(struct ath10k *ar) struct ath10k_pci *ar_pci = ath10k_pci_priv(ar); if (WARN_ON(!ar_pci->pci_hard_reset)) - return -ENOTSUPP; + return -EOPNOTSUPP; return ar_pci->pci_hard_reset(ar); } @@ -3594,7 +3594,7 @@ static int ath10k_pci_probe(struct pci_dev *pdev, break; default: WARN_ON(1); - return -ENOTSUPP; + return -EOPNOTSUPP; } ar = ath10k_core_create(sizeof(*ar_pci), &pdev->dev, ATH10K_BUS_PCI, diff --git a/drivers/net/wireless/ath/ath10k/wmi-tlv.c b/drivers/net/wireless/ath/ath10k/wmi-tlv.c index 0ce08e9a0a3d..aed97fd121ba 100644 --- a/drivers/net/wireless/ath/ath10k/wmi-tlv.c +++ b/drivers/net/wireless/ath/ath10k/wmi-tlv.c @@ -3,6 +3,7 @@ * Copyright (c) 2005-2011 Atheros Communications Inc. * Copyright (c) 2011-2017 Qualcomm Atheros, Inc. * Copyright (c) 2018-2019, The Linux Foundation. All rights reserved. + * Copyright (c) 2024 Qualcomm Innovation Center, Inc. All rights reserved. */ #include "core.h" #include "debug.h" @@ -1351,7 +1352,7 @@ static int ath10k_wmi_tlv_op_pull_svc_rdy_ev(struct ath10k *ar, __le32_to_cpu(ev->abi.abi_ver_ns1) != WMI_TLV_ABI_VER_NS1 || __le32_to_cpu(ev->abi.abi_ver_ns2) != WMI_TLV_ABI_VER_NS2 || __le32_to_cpu(ev->abi.abi_ver_ns3) != WMI_TLV_ABI_VER_NS3) { - return -ENOTSUPP; + return -EOPNOTSUPP; } arg->min_tx_power = ev->hw_min_tx_power; @@ -2123,9 +2124,9 @@ static int ath10k_wmi_tlv_op_get_vdev_subtype(struct ath10k *ar, case WMI_VDEV_SUBTYPE_MESH_11S: return WMI_TLV_VDEV_SUBTYPE_MESH_11S; case WMI_VDEV_SUBTYPE_MESH_NON_11S: - return -ENOTSUPP; + return -EOPNOTSUPP; } - return -ENOTSUPP; + return -EOPNOTSUPP; } static struct sk_buff * diff --git a/drivers/net/wireless/ath/ath10k/wmi.c b/drivers/net/wireless/ath/ath10k/wmi.c index 0cfd9484c45e..9e2f0a50aaea 100644 --- a/drivers/net/wireless/ath/ath10k/wmi.c +++ b/drivers/net/wireless/ath/ath10k/wmi.c @@ -3,7 +3,7 @@ * Copyright (c) 2005-2011 Atheros Communications Inc. * Copyright (c) 2011-2017 Qualcomm Atheros, Inc. * Copyright (c) 2018-2019, The Linux Foundation. All rights reserved. - * Copyright (c) 2021-2022 Qualcomm Innovation Center, Inc. All rights reserved. + * Copyright (c) 2021-2024 Qualcomm Innovation Center, Inc. All rights reserved. */ #include @@ -8733,9 +8733,9 @@ int ath10k_wmi_op_get_vdev_subtype(struct ath10k *ar, return WMI_VDEV_SUBTYPE_LEGACY_PROXY_STA; case WMI_VDEV_SUBTYPE_MESH_11S: case WMI_VDEV_SUBTYPE_MESH_NON_11S: - return -ENOTSUPP; + return -EOPNOTSUPP; } - return -ENOTSUPP; + return -EOPNOTSUPP; } static int ath10k_wmi_10_2_4_op_get_vdev_subtype(struct ath10k *ar, @@ -8755,9 +8755,9 @@ static int ath10k_wmi_10_2_4_op_get_vdev_subtype(struct ath10k *ar, case WMI_VDEV_SUBTYPE_MESH_11S: return WMI_VDEV_SUBTYPE_10_2_4_MESH_11S; case WMI_VDEV_SUBTYPE_MESH_NON_11S: - return -ENOTSUPP; + return -EOPNOTSUPP; } - return -ENOTSUPP; + return -EOPNOTSUPP; } static int ath10k_wmi_10_4_op_get_vdev_subtype(struct ath10k *ar, @@ -8779,7 +8779,7 @@ static int ath10k_wmi_10_4_op_get_vdev_subtype(struct ath10k *ar, case WMI_VDEV_SUBTYPE_MESH_NON_11S: return WMI_VDEV_SUBTYPE_10_4_MESH_NON_11S; } - return -ENOTSUPP; + return -EOPNOTSUPP; } static struct sk_buff * From 60b9376583217c8726be0a57d9ff71d52e9ce261 Mon Sep 17 00:00:00 2001 From: Baochen Qiang Date: Wed, 29 Nov 2023 10:04:12 +0800 Subject: [PATCH 55/71] wifi: ath12k: fix wrong definitions of hal_reo_update_rx_queue Some fields of hal_reo_update_rx_queue structure are wrongly defined, so fix it. Tested-on: WCN7850 hw2.0 PCI WLAN.HMT.1.0-03427-QCAHMTSWPL_V1.0_V2.0_SILICONZ-1.15378.4 Signed-off-by: Baochen Qiang Acked-by: Jeff Johnson Signed-off-by: Kalle Valo Link: https://msgid.link/20231129020414.56425-2-quic_bqiang@quicinc.com --- drivers/net/wireless/ath/ath12k/hal_desc.h | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/drivers/net/wireless/ath/ath12k/hal_desc.h b/drivers/net/wireless/ath/ath12k/hal_desc.h index 6c17adc6d60b..ec204939e50c 100644 --- a/drivers/net/wireless/ath/ath12k/hal_desc.h +++ b/drivers/net/wireless/ath/ath12k/hal_desc.h @@ -2500,13 +2500,13 @@ struct hal_rx_reo_queue { #define HAL_REO_UPD_RX_QUEUE_INFO1_PN_HANDLE_ENABLE BIT(30) #define HAL_REO_UPD_RX_QUEUE_INFO1_IGNORE_AMPDU_FLG BIT(31) -#define HAL_REO_UPD_RX_QUEUE_INFO2_BA_WINDOW_SIZE GENMASK(7, 0) -#define HAL_REO_UPD_RX_QUEUE_INFO2_PN_SIZE GENMASK(9, 8) -#define HAL_REO_UPD_RX_QUEUE_INFO2_SVLD BIT(10) -#define HAL_REO_UPD_RX_QUEUE_INFO2_SSN GENMASK(22, 11) -#define HAL_REO_UPD_RX_QUEUE_INFO2_SEQ_2K_ERR BIT(23) -#define HAL_REO_UPD_RX_QUEUE_INFO2_PN_ERR BIT(24) -#define HAL_REO_UPD_RX_QUEUE_INFO2_PN_VALID BIT(25) +#define HAL_REO_UPD_RX_QUEUE_INFO2_BA_WINDOW_SIZE GENMASK(9, 0) +#define HAL_REO_UPD_RX_QUEUE_INFO2_PN_SIZE GENMASK(11, 10) +#define HAL_REO_UPD_RX_QUEUE_INFO2_SVLD BIT(12) +#define HAL_REO_UPD_RX_QUEUE_INFO2_SSN GENMASK(24, 13) +#define HAL_REO_UPD_RX_QUEUE_INFO2_SEQ_2K_ERR BIT(25) +#define HAL_REO_UPD_RX_QUEUE_INFO2_PN_ERR BIT(26) +#define HAL_REO_UPD_RX_QUEUE_INFO2_PN_VALID BIT(27) struct hal_reo_update_rx_queue { struct hal_reo_cmd_hdr cmd; From b0970f50839ecbb71d43914fe88ea7eeb3416a21 Mon Sep 17 00:00:00 2001 From: Baochen Qiang Date: Wed, 17 Jan 2024 14:05:30 +0200 Subject: [PATCH 56/71] wifi: ath12k: add support for BA1024 Currently the maximum block ACK window size supported is 256. This results in that, when connected to an AP which supports larger BA sizes like BA512 or BA1024, only BA256 is established, leading to a lower peak throughput. So add support for BA1024, this is done by allocating a larger REO queue and advertising IEEE80211_MAX_AMPDU_BUF_EHT support to MAC80211. Tested-on: WCN7850 hw2.0 PCI WLAN.HMT.1.0-03427-QCAHMTSWPL_V1.0_V2.0_SILICONZ-1.15378.4 Signed-off-by: Baochen Qiang Acked-by: Jeff Johnson Signed-off-by: Kalle Valo Link: https://msgid.link/20231129020414.56425-3-quic_bqiang@quicinc.com --- drivers/net/wireless/ath/ath12k/dp.h | 2 +- drivers/net/wireless/ath/ath12k/hal_desc.h | 6 ++++++ drivers/net/wireless/ath/ath12k/hal_rx.c | 11 ++++++++--- drivers/net/wireless/ath/ath12k/mac.c | 2 +- 4 files changed, 16 insertions(+), 5 deletions(-) diff --git a/drivers/net/wireless/ath/ath12k/dp.h b/drivers/net/wireless/ath/ath12k/dp.h index 1df3cdd46140..f8fc72a178ef 100644 --- a/drivers/net/wireless/ath/ath12k/dp.h +++ b/drivers/net/wireless/ath/ath12k/dp.h @@ -150,7 +150,7 @@ struct ath12k_pdev_dp { #define DP_RX_HASH_ENABLE 1 /* Enable hash based Rx steering */ -#define DP_BA_WIN_SZ_MAX 256 +#define DP_BA_WIN_SZ_MAX 1024 #define DP_TCL_NUM_RING_MAX 4 diff --git a/drivers/net/wireless/ath/ath12k/hal_desc.h b/drivers/net/wireless/ath/ath12k/hal_desc.h index ec204939e50c..63340256d3f6 100644 --- a/drivers/net/wireless/ath/ath12k/hal_desc.h +++ b/drivers/net/wireless/ath/ath12k/hal_desc.h @@ -2517,6 +2517,12 @@ struct hal_reo_update_rx_queue { __le32 pn[4]; } __packed; +struct hal_rx_reo_queue_1k { + struct hal_desc_header desc_hdr; + __le32 rx_bitmap_1023_288[23]; + __le32 reserved[8]; +} __packed; + #define HAL_REO_UNBLOCK_CACHE_INFO0_UNBLK_CACHE BIT(0) #define HAL_REO_UNBLOCK_CACHE_INFO0_RESOURCE_IDX GENMASK(2, 1) diff --git a/drivers/net/wireless/ath/ath12k/hal_rx.c b/drivers/net/wireless/ath/ath12k/hal_rx.c index 4fc08d4f85b5..f7c1aaa3b5d4 100644 --- a/drivers/net/wireless/ath/ath12k/hal_rx.c +++ b/drivers/net/wireless/ath/ath12k/hal_rx.c @@ -688,23 +688,28 @@ void ath12k_hal_reo_update_rx_reo_queue_status(struct ath12k_base *ab, u32 ath12k_hal_reo_qdesc_size(u32 ba_window_size, u8 tid) { - u32 num_ext_desc; + u32 num_ext_desc, num_1k_desc = 0; if (ba_window_size <= 1) { if (tid != HAL_DESC_REO_NON_QOS_TID) num_ext_desc = 1; else num_ext_desc = 0; + } else if (ba_window_size <= 105) { num_ext_desc = 1; } else if (ba_window_size <= 210) { num_ext_desc = 2; - } else { + } else if (ba_window_size <= 256) { num_ext_desc = 3; + } else { + num_ext_desc = 10; + num_1k_desc = 1; } return sizeof(struct hal_rx_reo_queue) + - (num_ext_desc * sizeof(struct hal_rx_reo_queue_ext)); + (num_ext_desc * sizeof(struct hal_rx_reo_queue_ext)) + + (num_1k_desc * sizeof(struct hal_rx_reo_queue_1k)); } void ath12k_hal_reo_qdesc_setup(struct hal_rx_reo_queue *qdesc, diff --git a/drivers/net/wireless/ath/ath12k/mac.c b/drivers/net/wireless/ath/ath12k/mac.c index d453e4165228..408f1fada337 100644 --- a/drivers/net/wireless/ath/ath12k/mac.c +++ b/drivers/net/wireless/ath/ath12k/mac.c @@ -7602,7 +7602,7 @@ static int ath12k_mac_hw_register(struct ath12k *ar) hw->queues = ATH12K_HW_MAX_QUEUES; wiphy->tx_queue_len = ATH12K_QUEUE_LEN; hw->offchannel_tx_hw_queue = ATH12K_HW_MAX_QUEUES - 1; - hw->max_rx_aggregation_subframes = IEEE80211_MAX_AMPDU_BUF_HE; + hw->max_rx_aggregation_subframes = IEEE80211_MAX_AMPDU_BUF_EHT; hw->vif_data_size = sizeof(struct ath12k_vif); hw->sta_data_size = sizeof(struct ath12k_sta); From 955df16f2a4c3023753680925e71e099818c2329 Mon Sep 17 00:00:00 2001 From: Baochen Qiang Date: Wed, 17 Jan 2024 14:05:39 +0200 Subject: [PATCH 57/71] wifi: ath12k: change MAC buffer ring size to 2048 For WCN7850, there is a SRNG named MAC buffer ring, i.e., dp->rx_mac_buf_ring. During initialization, it is setup by host and then under control of firmware. During RX process, firmware fetches buffers from dp->rx_refill_buf_ring to fill that MAC buffer ring, and those buffers are taken by RXDMA to carry real WLAN frames received from air. Currently a low RX throughput is observed. Checking firmware log, lots of errors are reported by MAC buffer ring, complaining that it is running out of buffers, which further indicates that RXDMA is suffering from starvation. Currently the size of dp->rx_mac_buf_ring is configured as 1024. After changing it to 2048, those error messages are reduced, and a 6.4% increase is seen in peak throughput. Note that 2048 is an empirical value. It is chosen here because the RX throughput meets our expectation after the change. This change only applies to WCN7850 since other chips don't have a MAC buffer ring. Tested-on: WCN7850 hw2.0 PCI WLAN.HMT.1.0-03427-QCAHMTSWPL_V1.0_V2.0_SILICONZ-1.15378.4 Signed-off-by: Baochen Qiang Acked-by: Jeff Johnson Signed-off-by: Kalle Valo Link: https://msgid.link/20231129020414.56425-4-quic_bqiang@quicinc.com --- drivers/net/wireless/ath/ath12k/dp.h | 1 + drivers/net/wireless/ath/ath12k/dp_rx.c | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/net/wireless/ath/ath12k/dp.h b/drivers/net/wireless/ath/ath12k/dp.h index f8fc72a178ef..0a10cd362356 100644 --- a/drivers/net/wireless/ath/ath12k/dp.h +++ b/drivers/net/wireless/ath/ath12k/dp.h @@ -170,6 +170,7 @@ struct ath12k_pdev_dp { #define DP_REO_CMD_RING_SIZE 128 #define DP_REO_STATUS_RING_SIZE 2048 #define DP_RXDMA_BUF_RING_SIZE 4096 +#define DP_RX_MAC_BUF_RING_SIZE 2048 #define DP_RXDMA_REFILL_RING_SIZE 2048 #define DP_RXDMA_ERR_DST_RING_SIZE 1024 #define DP_RXDMA_MON_STATUS_RING_SIZE 1024 diff --git a/drivers/net/wireless/ath/ath12k/dp_rx.c b/drivers/net/wireless/ath/ath12k/dp_rx.c index 1ee83f765929..07430289023f 100644 --- a/drivers/net/wireless/ath/ath12k/dp_rx.c +++ b/drivers/net/wireless/ath/ath12k/dp_rx.c @@ -4086,7 +4086,7 @@ int ath12k_dp_rx_alloc(struct ath12k_base *ab) ret = ath12k_dp_srng_setup(ab, &dp->rx_mac_buf_ring[i], HAL_RXDMA_BUF, 1, - i, 1024); + i, DP_RX_MAC_BUF_RING_SIZE); if (ret) { ath12k_warn(ab, "failed to setup rx_mac_buf_ring %d\n", i); From b856f023b40fa7735ca19de433fc1307d69c36d0 Mon Sep 17 00:00:00 2001 From: Karthikeyan Periyasamy Date: Thu, 18 Jan 2024 06:33:19 +0530 Subject: [PATCH 58/71] wifi: ath12k: Refactor the mac80211 hw access from link/radio Currently, mac80211 hardware accesses link/radio structure directly in multiple locations. Introduce helper function to avoid this direct access, as this change will facilitate refactoring for Multi-link operation support. Tested-on: QCN9274 hw2.0 PCI WLAN.WBE.1.0.1-00029-QCAHKSWPL_SILICONZ-1 Tested-on: WCN7850 hw2.0 PCI WLAN.HMT.1.0.c5-00481-QCAHMTSWPL_V1.0_V2.0_SILICONZ-3 Signed-off-by: Karthikeyan Periyasamy Signed-off-by: Kalle Valo Link: https://msgid.link/20240118010320.3918136-2-quic_periyasa@quicinc.com --- drivers/net/wireless/ath/ath12k/core.c | 10 +++-- drivers/net/wireless/ath/ath12k/core.h | 6 ++- drivers/net/wireless/ath/ath12k/dp_mon.c | 4 +- drivers/net/wireless/ath/ath12k/dp_rx.c | 6 +-- drivers/net/wireless/ath/ath12k/dp_tx.c | 4 +- drivers/net/wireless/ath/ath12k/mac.c | 51 ++++++++++++++---------- drivers/net/wireless/ath/ath12k/reg.c | 6 +-- drivers/net/wireless/ath/ath12k/wmi.c | 17 ++++---- 8 files changed, 60 insertions(+), 44 deletions(-) diff --git a/drivers/net/wireless/ath/ath12k/core.c b/drivers/net/wireless/ath/ath12k/core.c index 6cab747ff858..d21618ca70b9 100644 --- a/drivers/net/wireless/ath/ath12k/core.c +++ b/drivers/net/wireless/ath/ath12k/core.c @@ -1,7 +1,7 @@ // SPDX-License-Identifier: BSD-3-Clause-Clear /* * Copyright (c) 2018-2021 The Linux Foundation. All rights reserved. - * Copyright (c) 2021-2023 Qualcomm Innovation Center, Inc. All rights reserved. + * Copyright (c) 2021-2024 Qualcomm Innovation Center, Inc. All rights reserved. */ #include @@ -879,6 +879,7 @@ static void ath12k_rfkill_work(struct work_struct *work) { struct ath12k_base *ab = container_of(work, struct ath12k_base, rfkill_work); struct ath12k *ar; + struct ieee80211_hw *hw; bool rfkill_radio_on; int i; @@ -891,8 +892,9 @@ static void ath12k_rfkill_work(struct work_struct *work) if (!ar) continue; + hw = ath12k_ar_to_hw(ar); ath12k_mac_rfkill_enable_radio(ar, rfkill_radio_on); - wiphy_rfkill_set_hw_state(ar->hw->wiphy, !rfkill_radio_on); + wiphy_rfkill_set_hw_state(hw->wiphy, !rfkill_radio_on); } } @@ -936,7 +938,7 @@ static void ath12k_core_pre_reconfigure_recovery(struct ath12k_base *ab) if (!ar || ar->state == ATH12K_STATE_OFF) continue; - ieee80211_stop_queues(ar->hw); + ieee80211_stop_queues(ath12k_ar_to_hw(ar)); ath12k_mac_drain_tx(ar); complete(&ar->scan.started); complete(&ar->scan.completed); @@ -976,7 +978,7 @@ static void ath12k_core_post_reconfigure_recovery(struct ath12k_base *ab) case ATH12K_STATE_ON: ar->state = ATH12K_STATE_RESTARTING; ath12k_core_halt(ar); - ieee80211_restart_hw(ar->hw); + ieee80211_restart_hw(ath12k_ar_to_hw(ar)); break; case ATH12K_STATE_OFF: ath12k_warn(ab, diff --git a/drivers/net/wireless/ath/ath12k/core.h b/drivers/net/wireless/ath/ath12k/core.h index ba0a30f1ea29..10a292b28d4d 100644 --- a/drivers/net/wireless/ath/ath12k/core.h +++ b/drivers/net/wireless/ath/ath12k/core.h @@ -1,7 +1,7 @@ /* SPDX-License-Identifier: BSD-3-Clause-Clear */ /* * Copyright (c) 2018-2021 The Linux Foundation. All rights reserved. - * Copyright (c) 2021-2023 Qualcomm Innovation Center, Inc. All rights reserved. + * Copyright (c) 2021-2024 Qualcomm Innovation Center, Inc. All rights reserved. */ #ifndef ATH12K_CORE_H @@ -896,4 +896,8 @@ static inline const char *ath12k_bus_str(enum ath12k_bus bus) return "unknown"; } +static inline struct ieee80211_hw *ath12k_ar_to_hw(struct ath12k *ar) +{ + return ar->hw; +} #endif /* _CORE_H_ */ diff --git a/drivers/net/wireless/ath/ath12k/dp_mon.c b/drivers/net/wireless/ath/ath12k/dp_mon.c index be4b39f5fa80..2432ab605c85 100644 --- a/drivers/net/wireless/ath/ath12k/dp_mon.c +++ b/drivers/net/wireless/ath/ath12k/dp_mon.c @@ -1,7 +1,7 @@ // SPDX-License-Identifier: BSD-3-Clause-Clear /* * Copyright (c) 2019-2021 The Linux Foundation. All rights reserved. - * Copyright (c) 2021-2023 Qualcomm Innovation Center, Inc. All rights reserved. + * Copyright (c) 2021-2024 Qualcomm Innovation Center, Inc. All rights reserved. */ #include "dp_mon.h" @@ -1130,7 +1130,7 @@ static void ath12k_dp_mon_rx_deliver_msdu(struct ath12k *ar, struct napi_struct !(is_mcbc && rx_status->flag & RX_FLAG_DECRYPTED)) rx_status->flag |= RX_FLAG_8023; - ieee80211_rx_napi(ar->hw, pubsta, msdu, napi); + ieee80211_rx_napi(ath12k_ar_to_hw(ar), pubsta, msdu, napi); } static int ath12k_dp_mon_rx_deliver(struct ath12k *ar, u32 mac_id, diff --git a/drivers/net/wireless/ath/ath12k/dp_rx.c b/drivers/net/wireless/ath/ath12k/dp_rx.c index 07430289023f..a31c24b54851 100644 --- a/drivers/net/wireless/ath/ath12k/dp_rx.c +++ b/drivers/net/wireless/ath/ath12k/dp_rx.c @@ -1,7 +1,7 @@ // SPDX-License-Identifier: BSD-3-Clause-Clear /* * Copyright (c) 2018-2021 The Linux Foundation. All rights reserved. - * Copyright (c) 2021-2023 Qualcomm Innovation Center, Inc. All rights reserved. + * Copyright (c) 2021-2024 Qualcomm Innovation Center, Inc. All rights reserved. */ #include @@ -2458,7 +2458,7 @@ static void ath12k_dp_rx_deliver_msdu(struct ath12k *ar, struct napi_struct *nap !(is_mcbc && rx_status->flag & RX_FLAG_DECRYPTED)) rx_status->flag |= RX_FLAG_8023; - ieee80211_rx_napi(ar->hw, pubsta, msdu, napi); + ieee80211_rx_napi(ath12k_ar_to_hw(ar), pubsta, msdu, napi); } static int ath12k_dp_rx_process_msdu(struct ath12k *ar, @@ -2844,7 +2844,7 @@ static int ath12k_dp_rx_h_verify_tkip_mic(struct ath12k *ar, struct ath12k_peer ath12k_dp_rx_h_ppdu(ar, rx_desc, rxs); ath12k_dp_rx_h_undecap(ar, msdu, rx_desc, HAL_ENCRYPT_TYPE_TKIP_MIC, rxs, true); - ieee80211_rx(ar->hw, msdu); + ieee80211_rx(ath12k_ar_to_hw(ar), msdu); return -EINVAL; } diff --git a/drivers/net/wireless/ath/ath12k/dp_tx.c b/drivers/net/wireless/ath/ath12k/dp_tx.c index 05d5f14cdfa1..d4db94112deb 100644 --- a/drivers/net/wireless/ath/ath12k/dp_tx.c +++ b/drivers/net/wireless/ath/ath12k/dp_tx.c @@ -401,7 +401,7 @@ ath12k_dp_tx_htt_tx_complete_buf(struct ath12k_base *ab, } } - ieee80211_tx_status_skb(ar->hw, msdu); + ieee80211_tx_status_skb(ath12k_ar_to_hw(ar), msdu); } static void @@ -498,7 +498,7 @@ static void ath12k_dp_tx_complete_msdu(struct ath12k *ar, * Might end up reporting it out-of-band from HTT stats. */ - ieee80211_tx_status_skb(ar->hw, msdu); + ieee80211_tx_status_skb(ath12k_ar_to_hw(ar), msdu); exit: rcu_read_unlock(); diff --git a/drivers/net/wireless/ath/ath12k/mac.c b/drivers/net/wireless/ath/ath12k/mac.c index 408f1fada337..27c5337a764e 100644 --- a/drivers/net/wireless/ath/ath12k/mac.c +++ b/drivers/net/wireless/ath/ath12k/mac.c @@ -542,7 +542,7 @@ struct ath12k_vif *ath12k_mac_get_arvif(struct ath12k *ar, u32 vdev_id) arvif_iter.vdev_id = vdev_id; flags = IEEE80211_IFACE_ITER_RESUME_ALL; - ieee80211_iterate_active_interfaces_atomic(ar->hw, + ieee80211_iterate_active_interfaces_atomic(ath12k_ar_to_hw(ar), flags, ath12k_get_arvif_iter, &arvif_iter); @@ -1040,7 +1040,7 @@ static int ath12k_mac_monitor_start(struct ath12k *ar) if (ar->monitor_started) return 0; - ieee80211_iter_chan_contexts_atomic(ar->hw, + ieee80211_iter_chan_contexts_atomic(ath12k_ar_to_hw(ar), ath12k_mac_get_any_chandef_iter, &chandef); if (!chandef) @@ -1085,7 +1085,7 @@ static int ath12k_mac_monitor_stop(struct ath12k *ar) static int ath12k_mac_config(struct ath12k *ar, u32 changed) { - struct ieee80211_hw *hw = ar->hw; + struct ieee80211_hw *hw = ath12k_ar_to_hw(ar); struct ieee80211_conf *conf = &hw->conf; int ret = 0; @@ -1139,7 +1139,7 @@ static int ath12k_mac_setup_bcn_tmpl(struct ath12k_vif *arvif) { struct ath12k *ar = arvif->ar; struct ath12k_base *ab = ar->ab; - struct ieee80211_hw *hw = ar->hw; + struct ieee80211_hw *hw = ath12k_ar_to_hw(ar); struct ieee80211_vif *vif = arvif->vif; struct ieee80211_mutable_offsets offs = {}; struct sk_buff *bcn; @@ -1227,6 +1227,7 @@ static void ath12k_peer_assoc_h_basic(struct ath12k *ar, struct ath12k_wmi_peer_assoc_arg *arg) { struct ath12k_vif *arvif = ath12k_vif_to_arvif(vif); + struct ieee80211_hw *hw = ath12k_ar_to_hw(ar); u32 aid; lockdep_assert_held(&ar->conf_mutex); @@ -1241,7 +1242,7 @@ static void ath12k_peer_assoc_h_basic(struct ath12k *ar, arg->peer_associd = aid; arg->auth_flag = true; /* TODO: STA WAR in ath10k for listen interval required? */ - arg->peer_listen_intval = ar->hw->conf.listen_interval; + arg->peer_listen_intval = hw->conf.listen_interval; arg->peer_nss = 1; arg->peer_caps = vif->bss_conf.assoc_capability; } @@ -1255,6 +1256,7 @@ static void ath12k_peer_assoc_h_crypto(struct ath12k *ar, struct cfg80211_chan_def def; struct cfg80211_bss *bss; struct ath12k_vif *arvif = ath12k_vif_to_arvif(vif); + struct ieee80211_hw *hw = ath12k_ar_to_hw(ar); const u8 *rsnie = NULL; const u8 *wpaie = NULL; @@ -1263,7 +1265,7 @@ static void ath12k_peer_assoc_h_crypto(struct ath12k *ar, if (WARN_ON(ath12k_mac_vif_chan(vif, &def))) return; - bss = cfg80211_get_bss(ar->hw->wiphy, def.chan, info->bssid, NULL, 0, + bss = cfg80211_get_bss(hw->wiphy, def.chan, info->bssid, NULL, 0, IEEE80211_BSS_TYPE_ANY, IEEE80211_PRIVACY_ANY); if (arvif->rsnie_present || arvif->wpaie_present) { @@ -1283,7 +1285,7 @@ static void ath12k_peer_assoc_h_crypto(struct ath12k *ar, ies->data, ies->len); rcu_read_unlock(); - cfg80211_put_bss(ar->hw->wiphy, bss); + cfg80211_put_bss(hw->wiphy, bss); } /* FIXME: base on RSN IE/WPA IE is a correct idea? */ @@ -1317,6 +1319,7 @@ static void ath12k_peer_assoc_h_rates(struct ath12k *ar, struct cfg80211_chan_def def; const struct ieee80211_supported_band *sband; const struct ieee80211_rate *rates; + struct ieee80211_hw *hw = ath12k_ar_to_hw(ar); enum nl80211_band band; u32 ratemask; u8 rate; @@ -1328,7 +1331,7 @@ static void ath12k_peer_assoc_h_rates(struct ath12k *ar, return; band = def.chan->band; - sband = ar->hw->wiphy->bands[band]; + sband = hw->wiphy->bands[band]; ratemask = sta->deflink.supp_rates[band]; ratemask &= arvif->bitrate_mask.control[band].legacy; rates = sband->bitrates; @@ -2423,6 +2426,7 @@ static void ath12k_recalculate_mgmt_rate(struct ath12k *ar, struct cfg80211_chan_def *def) { struct ath12k_vif *arvif = ath12k_vif_to_arvif(vif); + struct ieee80211_hw *hw = ath12k_ar_to_hw(ar); const struct ieee80211_supported_band *sband; u8 basic_rate_idx; int hw_rate_code; @@ -2432,7 +2436,7 @@ static void ath12k_recalculate_mgmt_rate(struct ath12k *ar, lockdep_assert_held(&ar->conf_mutex); - sband = ar->hw->wiphy->bands[def->chan->band]; + sband = hw->wiphy->bands[def->chan->band]; basic_rate_idx = ffs(vif->bss_conf.basic_rates) - 1; bitrate = sband->bitrates[basic_rate_idx].bitrate; @@ -2459,6 +2463,7 @@ static int ath12k_mac_fils_discovery(struct ath12k_vif *arvif, struct ieee80211_bss_conf *info) { struct ath12k *ar = arvif->ar; + struct ieee80211_hw *hw = ath12k_ar_to_hw(ar); struct sk_buff *tmpl; int ret; u32 interval; @@ -2467,7 +2472,7 @@ static int ath12k_mac_fils_discovery(struct ath12k_vif *arvif, if (info->fils_discovery.max_interval) { interval = info->fils_discovery.max_interval; - tmpl = ieee80211_get_fils_discovery_tmpl(ar->hw, arvif->vif); + tmpl = ieee80211_get_fils_discovery_tmpl(hw, arvif->vif); if (tmpl) ret = ath12k_wmi_fils_discovery_tmpl(ar, arvif->vdev_id, tmpl); @@ -2475,7 +2480,7 @@ static int ath12k_mac_fils_discovery(struct ath12k_vif *arvif, unsol_bcast_probe_resp_enabled = 1; interval = info->unsol_bcast_probe_resp_interval; - tmpl = ieee80211_get_unsol_bcast_probe_resp_tmpl(ar->hw, + tmpl = ieee80211_get_unsol_bcast_probe_resp_tmpl(hw, arvif->vif); if (tmpl) ret = ath12k_wmi_probe_resp_tmpl(ar, arvif->vdev_id, @@ -2798,6 +2803,8 @@ static void ath12k_mac_op_bss_info_changed(struct ieee80211_hw *hw, void __ath12k_mac_scan_finish(struct ath12k *ar) { + struct ieee80211_hw *hw = ath12k_ar_to_hw(ar); + lockdep_assert_held(&ar->data_lock); switch (ar->scan.state) { @@ -2806,7 +2813,7 @@ void __ath12k_mac_scan_finish(struct ath12k *ar) case ATH12K_SCAN_RUNNING: case ATH12K_SCAN_ABORTING: if (ar->scan.is_roc && ar->scan.roc_notify) - ieee80211_remain_on_channel_expired(ar->hw); + ieee80211_remain_on_channel_expired(hw); fallthrough; case ATH12K_SCAN_STARTING: if (!ar->scan.is_roc) { @@ -2817,7 +2824,7 @@ void __ath12k_mac_scan_finish(struct ath12k *ar) ATH12K_SCAN_STARTING)), }; - ieee80211_scan_completed(ar->hw, &info); + ieee80211_scan_completed(hw, &info); } ar->scan.state = ATH12K_SCAN_IDLE; @@ -3036,7 +3043,7 @@ static int ath12k_mac_op_hw_scan(struct ieee80211_hw *hw, } /* Add a margin to account for event/command processing */ - ieee80211_queue_delayed_work(ar->hw, &ar->scan.timeout, + ieee80211_queue_delayed_work(ath12k_ar_to_hw(ar), &ar->scan.timeout, msecs_to_jiffies(arg.max_scan_time + ATH12K_MAC_SCAN_TIMEOUT_MSECS)); @@ -4819,7 +4826,7 @@ static void ath12k_mgmt_over_wmi_tx_drop(struct ath12k *ar, struct sk_buff *skb) { int num_mgmt; - ieee80211_free_txskb(ar->hw, skb); + ieee80211_free_txskb(ath12k_ar_to_hw(ar), skb); num_mgmt = atomic_dec_if_positive(&ar->num_pending_mgmt_tx); @@ -4996,7 +5003,7 @@ static int ath12k_mac_mgmt_tx(struct ath12k *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); + ieee80211_queue_work(ath12k_ar_to_hw(ar), &ar->wmi_mgmt_tx_work); return 0; } @@ -6357,7 +6364,7 @@ ath12k_mac_update_active_vif_chan(struct ath12k *ar, struct ieee80211_chanctx_conf *ctx) { struct ath12k_mac_change_chanctx_arg arg = { .ctx = ctx }; - struct ieee80211_hw *hw = ar->hw; + struct ieee80211_hw *hw = ath12k_ar_to_hw(ar); lockdep_assert_held(&ar->conf_mutex); @@ -6874,7 +6881,7 @@ static void ath12k_mac_set_bitrate_mask_iter(void *data, arsta->changed |= IEEE80211_RC_SUPP_RATES_CHANGED; spin_unlock_bh(&ar->data_lock); - ieee80211_queue_work(ar->hw, &arsta->update_wk); + ieee80211_queue_work(ath12k_ar_to_hw(ar), &arsta->update_wk); } static void ath12k_mac_disable_peer_fixed_rate(void *data, @@ -7350,7 +7357,7 @@ static int ath12k_mac_setup_channels_rates(struct ath12k *ar, static int ath12k_mac_setup_iface_combinations(struct ath12k *ar) { struct ath12k_base *ab = ar->ab; - struct ieee80211_hw *hw = ar->hw; + struct ieee80211_hw *hw = ath12k_ar_to_hw(ar); struct wiphy *wiphy = hw->wiphy; struct ieee80211_iface_combination *combinations; struct ieee80211_iface_limit *limits; @@ -7457,7 +7464,7 @@ static void ath12k_mac_cleanup_unregister(struct ath12k *ar) static void ath12k_mac_hw_unregister(struct ath12k *ar) { - struct ieee80211_hw *hw = ar->hw; + struct ieee80211_hw *hw = ath12k_ar_to_hw(ar); struct wiphy *wiphy = hw->wiphy; cancel_work_sync(&ar->regd_update_work); @@ -7503,7 +7510,7 @@ static int ath12k_mac_setup_register(struct ath12k *ar, static int ath12k_mac_hw_register(struct ath12k *ar) { struct ath12k_base *ab = ar->ab; - struct ieee80211_hw *hw = ar->hw; + struct ieee80211_hw *hw = ath12k_ar_to_hw(ar); struct wiphy *wiphy = hw->wiphy; struct ath12k_pdev *pdev = ar->pdev; struct ath12k_pdev_cap *cap = &pdev->cap; @@ -7777,7 +7784,7 @@ static void ath12k_mac_hw_destroy(struct ath12k_base *ab) if (!ar) continue; - ieee80211_free_hw(ar->hw); + ieee80211_free_hw(ath12k_ar_to_hw(ar)); pdev->ar = NULL; } } diff --git a/drivers/net/wireless/ath/ath12k/reg.c b/drivers/net/wireless/ath/ath12k/reg.c index f924bc13ccff..88e71d171355 100644 --- a/drivers/net/wireless/ath/ath12k/reg.c +++ b/drivers/net/wireless/ath/ath12k/reg.c @@ -1,7 +1,7 @@ // SPDX-License-Identifier: BSD-3-Clause-Clear /* * Copyright (c) 2018-2021 The Linux Foundation. All rights reserved. - * Copyright (c) 2021-2023 Qualcomm Innovation Center, Inc. All rights reserved. + * Copyright (c) 2021-2024 Qualcomm Innovation Center, Inc. All rights reserved. */ #include #include "core.h" @@ -95,7 +95,7 @@ int ath12k_reg_update_chan_list(struct ath12k *ar) struct ieee80211_supported_band **bands; struct ath12k_wmi_scan_chan_list_arg *arg; struct ieee80211_channel *channel; - struct ieee80211_hw *hw = ar->hw; + struct ieee80211_hw *hw = ath12k_ar_to_hw(ar); struct ath12k_wmi_channel_arg *ch; enum nl80211_band band; int num_channels = 0; @@ -199,7 +199,7 @@ static void ath12k_copy_regd(struct ieee80211_regdomain *regd_orig, int ath12k_regd_update(struct ath12k *ar, bool init) { - struct ieee80211_hw *hw = ar->hw; + struct ieee80211_hw *hw = ath12k_ar_to_hw(ar); struct ieee80211_regdomain *regd, *regd_copy = NULL; int ret, regd_len, pdev_id; struct ath12k_base *ab; diff --git a/drivers/net/wireless/ath/ath12k/wmi.c b/drivers/net/wireless/ath/ath12k/wmi.c index 553d2566b3f7..4d41c335ef34 100644 --- a/drivers/net/wireless/ath/ath12k/wmi.c +++ b/drivers/net/wireless/ath/ath12k/wmi.c @@ -1,7 +1,7 @@ // SPDX-License-Identifier: BSD-3-Clause-Clear /* * Copyright (c) 2018-2021 The Linux Foundation. All rights reserved. - * Copyright (c) 2021-2023 Qualcomm Innovation Center, Inc. All rights reserved. + * Copyright (c) 2021-2024 Qualcomm Innovation Center, Inc. All rights reserved. */ #include #include @@ -4948,7 +4948,7 @@ static int wmi_process_mgmt_tx_comp(struct ath12k *ar, u32 desc_id, if ((!(info->flags & IEEE80211_TX_CTL_NO_ACK)) && !status) info->flags |= IEEE80211_TX_STAT_ACK; - ieee80211_tx_status_irqsafe(ar->hw, msdu); + ieee80211_tx_status_irqsafe(ath12k_ar_to_hw(ar), msdu); num_mgmt = atomic_dec_if_positive(&ar->num_pending_mgmt_tx); @@ -5076,6 +5076,8 @@ static void ath12k_wmi_event_scan_bss_chan(struct ath12k *ar) static void ath12k_wmi_event_scan_foreign_chan(struct ath12k *ar, u32 freq) { + struct ieee80211_hw *hw = ath12k_ar_to_hw(ar); + lockdep_assert_held(&ar->data_lock); switch (ar->scan.state) { @@ -5087,7 +5089,7 @@ static void ath12k_wmi_event_scan_foreign_chan(struct ath12k *ar, u32 freq) break; case ATH12K_SCAN_RUNNING: case ATH12K_SCAN_ABORTING: - ar->scan_channel = ieee80211_get_channel(ar->hw->wiphy, freq); + ar->scan_channel = ieee80211_get_channel(hw->wiphy, freq); break; } } @@ -5226,13 +5228,14 @@ static int ath12k_pull_roam_ev(struct ath12k_base *ab, struct sk_buff *skb, static int freq_to_idx(struct ath12k *ar, int freq) { struct ieee80211_supported_band *sband; + struct ieee80211_hw *hw = ath12k_ar_to_hw(ar); int band, ch, idx = 0; for (band = NL80211_BAND_2GHZ; band < NUM_NL80211_BANDS; band++) { if (!ar->mac.sbands[band].channels) continue; - sband = ar->hw->wiphy->bands[band]; + sband = hw->wiphy->bands[band]; if (!sband) continue; @@ -5863,7 +5866,7 @@ static void ath12k_mgmt_rx_event(struct ath12k_base *ab, struct sk_buff *skb) status->freq, status->band, status->signal, status->rate_idx); - ieee80211_rx_ni(ar->hw, skb); + ieee80211_rx_ni(ath12k_ar_to_hw(ar), skb); exit: rcu_read_unlock(); @@ -6036,7 +6039,7 @@ static void ath12k_peer_sta_kickout_event(struct ath12k_base *ab, struct sk_buff goto exit; } - sta = ieee80211_find_sta_by_ifaddr(ar->hw, + sta = ieee80211_find_sta_by_ifaddr(ath12k_ar_to_hw(ar), arg.mac_addr, NULL); if (!sta) { ath12k_warn(ab, "Spurious quick kickout for STA %pM\n", @@ -6530,7 +6533,7 @@ ath12k_wmi_pdev_dfs_radar_detected_event(struct ath12k_base *ab, struct sk_buff if (ar->dfs_block_radar_events) ath12k_info(ab, "DFS Radar detected, but ignored as requested\n"); else - ieee80211_radar_detected(ar->hw); + ieee80211_radar_detected(ath12k_ar_to_hw(ar)); exit: rcu_read_unlock(); From 6db6e70a17f6fb3f2cfae31bb212a2179d0f6e6b Mon Sep 17 00:00:00 2001 From: Karthikeyan Periyasamy Date: Thu, 18 Jan 2024 07:58:56 +0200 Subject: [PATCH 59/71] wifi: ath12k: Introduce the container for mac80211 hw To support multi link operation, we need to combine all the link/pdev under a single wiphy. This avoids the overhead of synchronization across multiple hardware instances in both the cfg80211 and mac80211 layers. Currently, each link/pdev is registered as separate wiphy, tightly coupled with link/pdev/radio (ar) structure. To enable single wiphy registration within the chip, we decouple the wiphy data entity from the link/pdev/radio (ar) structure and move it under the chip (ab) structure with a new data container (ath12k_hw) structure. This approach improves scalability for future multi link operation support. mac80211 hw private data structure diagram ------------------------------------------ Now After +---------------------+ +---------------------+ |mac80211 hw priv data| |mac80211 hw priv data| | | | | | | | | | | | | | | | ath12k_hw (ah) | | | | | | | +-------------------> | | | ath12k (ar) | | +-------------+ | | | | | | | | | | | ath12k (ar) | | | | | | | | | | | | | | | | | +-------------+ | | | | | | | | | +---------------------+ +---------------------+ Tested-on: QCN9274 hw2.0 PCI WLAN.WBE.1.0.1-00029-QCAHKSWPL_SILICONZ-1 Tested-on: WCN7850 hw2.0 PCI WLAN.HMT.1.0.c5-00481-QCAHMTSWPL_V1.0_V2.0_SILICONZ-3 Signed-off-by: Karthikeyan Periyasamy Signed-off-by: Kalle Valo Link: https://msgid.link/20240118010320.3918136-3-quic_periyasa@quicinc.com --- drivers/net/wireless/ath/ath12k/core.c | 10 +- drivers/net/wireless/ath/ath12k/core.h | 37 ++- drivers/net/wireless/ath/ath12k/mac.c | 421 +++++++++++++++++-------- drivers/net/wireless/ath/ath12k/mac.h | 4 +- drivers/net/wireless/ath/ath12k/reg.c | 3 +- 5 files changed, 337 insertions(+), 138 deletions(-) diff --git a/drivers/net/wireless/ath/ath12k/core.c b/drivers/net/wireless/ath/ath12k/core.c index d21618ca70b9..1baad3302157 100644 --- a/drivers/net/wireless/ath/ath12k/core.c +++ b/drivers/net/wireless/ath/ath12k/core.c @@ -923,6 +923,7 @@ static void ath12k_core_pre_reconfigure_recovery(struct ath12k_base *ab) { struct ath12k *ar; struct ath12k_pdev *pdev; + struct ath12k_hw *ah; int i; spin_lock_bh(&ab->base_lock); @@ -932,13 +933,20 @@ static void ath12k_core_pre_reconfigure_recovery(struct ath12k_base *ab) if (ab->is_reset) set_bit(ATH12K_FLAG_CRASH_FLUSH, &ab->dev_flags); + for (i = 0; i < ab->num_hw; i++) { + if (!ab->ah[i]) + continue; + + ah = ab->ah[i]; + ieee80211_stop_queues(ah->hw); + } + for (i = 0; i < ab->num_radios; i++) { pdev = &ab->pdevs[i]; ar = pdev->ar; if (!ar || ar->state == ATH12K_STATE_OFF) continue; - ieee80211_stop_queues(ath12k_ar_to_hw(ar)); ath12k_mac_drain_tx(ar); complete(&ar->scan.started); complete(&ar->scan.completed); diff --git a/drivers/net/wireless/ath/ath12k/core.h b/drivers/net/wireless/ath/ath12k/core.h index 10a292b28d4d..a56fc74366b4 100644 --- a/drivers/net/wireless/ath/ath12k/core.h +++ b/drivers/net/wireless/ath/ath12k/core.h @@ -473,7 +473,7 @@ struct ath12k_per_peer_tx_stats { struct ath12k { struct ath12k_base *ab; struct ath12k_pdev *pdev; - struct ieee80211_hw *hw; + struct ath12k_hw *ah; struct ath12k_wmi_pdev *wmi; struct ath12k_pdev_dp dp; u8 mac_addr[ETH_ALEN]; @@ -537,6 +537,7 @@ struct ath12k { /* pdev_idx starts from 0 whereas pdev->pdev_id starts with 1 */ u8 pdev_idx; u8 lmac_id; + u8 hw_link_id; struct completion peer_assoc_done; struct completion peer_delete_done; @@ -596,6 +597,13 @@ struct ath12k { int monitor_vdev_id; }; +struct ath12k_hw { + struct ieee80211_hw *hw; + + u8 num_radio; + struct ath12k radio[] __aligned(sizeof(void *)); +}; + struct ath12k_band_cap { u32 phy_id; u32 max_bw_supported; @@ -729,6 +737,16 @@ struct ath12k_base { u8 fw_pdev_count; struct ath12k_pdev __rcu *pdevs_active[MAX_RADIOS]; + + /* Holds information of wiphy (hw) registration. + * + * In Multi/Single Link Operation case, all pdevs are registered as + * a single wiphy. In other (legacy/Non-MLO) cases, each pdev is + * registered as separate wiphys. + */ + struct ath12k_hw *ah[MAX_RADIOS]; + u8 num_hw; + struct ath12k_wmi_hal_reg_capabilities_ext_arg hal_reg_cap[MAX_RADIOS]; unsigned long long free_vdev_map; unsigned long long free_vdev_stats_id_map; @@ -810,6 +828,11 @@ struct ath12k_base { u8 drv_priv[] __aligned(sizeof(void *)); }; +struct ath12k_pdev_map { + struct ath12k_base *ab; + u8 pdev_idx; +}; + int ath12k_core_qmi_firmware_ready(struct ath12k_base *ab); int ath12k_core_pre_init(struct ath12k_base *ab); int ath12k_core_init(struct ath12k_base *ath12k); @@ -896,8 +919,18 @@ static inline const char *ath12k_bus_str(enum ath12k_bus bus) return "unknown"; } +static inline struct ath12k_hw *ath12k_hw_to_ah(struct ieee80211_hw *hw) +{ + return hw->priv; +} + +static inline struct ath12k *ath12k_ah_to_ar(struct ath12k_hw *ah) +{ + return ah->radio; +} + static inline struct ieee80211_hw *ath12k_ar_to_hw(struct ath12k *ar) { - return ar->hw; + return ar->ah->hw; } #endif /* _CORE_H_ */ diff --git a/drivers/net/wireless/ath/ath12k/mac.c b/drivers/net/wireless/ath/ath12k/mac.c index 27c5337a764e..fe600dbef875 100644 --- a/drivers/net/wireless/ath/ath12k/mac.c +++ b/drivers/net/wireless/ath/ath12k/mac.c @@ -1124,9 +1124,12 @@ static int ath12k_mac_config(struct ath12k *ar, u32 changed) static int ath12k_mac_op_config(struct ieee80211_hw *hw, u32 changed) { - struct ath12k *ar = hw->priv; + struct ath12k_hw *ah = ath12k_hw_to_ah(hw); + struct ath12k *ar; int ret; + ar = ath12k_ah_to_ar(ah); + ret = ath12k_mac_config(ar, changed); if (ret) ath12k_warn(ar->ab, "failed to update config pdev idx %d: %d\n", @@ -2791,9 +2794,12 @@ static void ath12k_mac_op_bss_info_changed(struct ieee80211_hw *hw, struct ieee80211_bss_conf *info, u64 changed) { - struct ath12k *ar = hw->priv; + struct ath12k_hw *ah = ath12k_hw_to_ah(hw); + struct ath12k *ar; struct ath12k_vif *arvif = ath12k_vif_to_arvif(vif); + ar = ath12k_ah_to_ar(ah); + mutex_lock(&ar->conf_mutex); ath12k_mac_bss_info_changed(ar, arvif, info, changed); @@ -2969,13 +2975,16 @@ static int ath12k_mac_op_hw_scan(struct ieee80211_hw *hw, struct ieee80211_vif *vif, struct ieee80211_scan_request *hw_req) { - struct ath12k *ar = hw->priv; + struct ath12k_hw *ah = ath12k_hw_to_ah(hw); + struct ath12k *ar; struct ath12k_vif *arvif = ath12k_vif_to_arvif(vif); struct cfg80211_scan_request *req = &hw_req->req; struct ath12k_wmi_scan_req_arg arg = {}; int ret; int i; + ar = ath12k_ah_to_ar(ah); + mutex_lock(&ar->conf_mutex); spin_lock_bh(&ar->data_lock); @@ -3054,13 +3063,17 @@ static int ath12k_mac_op_hw_scan(struct ieee80211_hw *hw, kfree(arg.extraie.ptr); mutex_unlock(&ar->conf_mutex); + return ret; } static void ath12k_mac_op_cancel_hw_scan(struct ieee80211_hw *hw, struct ieee80211_vif *vif) { - struct ath12k *ar = hw->priv; + struct ath12k_hw *ah = ath12k_hw_to_ah(hw); + struct ath12k *ar; + + ar = ath12k_ah_to_ar(ah); mutex_lock(&ar->conf_mutex); ath12k_scan_abort(ar); @@ -3188,8 +3201,9 @@ static int ath12k_mac_op_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd, struct ieee80211_vif *vif, struct ieee80211_sta *sta, struct ieee80211_key_conf *key) { - struct ath12k *ar = hw->priv; - struct ath12k_base *ab = ar->ab; + struct ath12k_hw *ah = ath12k_hw_to_ah(hw); + struct ath12k *ar; + struct ath12k_base *ab; struct ath12k_vif *arvif = ath12k_vif_to_arvif(vif); struct ath12k_peer *peer; struct ath12k_sta *arsta; @@ -3204,6 +3218,9 @@ static int ath12k_mac_op_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd, key->cipher == WLAN_CIPHER_SUITE_BIP_CMAC_256) return 1; + ar = ath12k_ah_to_ar(ah); + ab = ar->ab; + if (test_bit(ATH12K_FLAG_HW_CRYPTO_DISABLED, &ar->ab->dev_flags)) return 1; @@ -3779,7 +3796,8 @@ static int ath12k_mac_op_sta_state(struct ieee80211_hw *hw, enum ieee80211_sta_state old_state, enum ieee80211_sta_state new_state) { - struct ath12k *ar = hw->priv; + struct ath12k_hw *ah = ath12k_hw_to_ah(hw); + struct ath12k *ar; struct ath12k_vif *arvif = ath12k_vif_to_arvif(vif); struct ath12k_sta *arsta = ath12k_sta_to_arsta(sta); struct ath12k_peer *peer; @@ -3790,6 +3808,8 @@ static int ath12k_mac_op_sta_state(struct ieee80211_hw *hw, new_state == IEEE80211_STA_NOTEXIST)) cancel_work_sync(&arsta->update_wk); + ar = ath12k_ah_to_ar(ah); + mutex_lock(&ar->conf_mutex); if (old_state == IEEE80211_STA_NOTEXIST && @@ -3885,6 +3905,7 @@ static int ath12k_mac_op_sta_state(struct ieee80211_hw *hw, } mutex_unlock(&ar->conf_mutex); + return ret; } @@ -3892,7 +3913,8 @@ static int ath12k_mac_op_sta_set_txpwr(struct ieee80211_hw *hw, struct ieee80211_vif *vif, struct ieee80211_sta *sta) { - struct ath12k *ar = hw->priv; + struct ath12k_hw *ah = ath12k_hw_to_ah(hw); + struct ath12k *ar; struct ath12k_vif *arvif = ath12k_vif_to_arvif(vif); int ret; s16 txpwr; @@ -3908,6 +3930,8 @@ static int ath12k_mac_op_sta_set_txpwr(struct ieee80211_hw *hw, if (txpwr > ATH12K_TX_POWER_MAX_VAL || txpwr < ATH12K_TX_POWER_MIN_VAL) return -EINVAL; + ar = ath12k_ah_to_ar(ah); + mutex_lock(&ar->conf_mutex); ret = ath12k_wmi_set_peer_param(ar, sta->addr, arvif->vdev_id, @@ -3928,12 +3952,15 @@ static void ath12k_mac_op_sta_rc_update(struct ieee80211_hw *hw, struct ieee80211_sta *sta, u32 changed) { - struct ath12k *ar = hw->priv; + struct ath12k_hw *ah = ath12k_hw_to_ah(hw); + struct ath12k *ar; struct ath12k_sta *arsta = ath12k_sta_to_arsta(sta); struct ath12k_vif *arvif = ath12k_vif_to_arvif(vif); struct ath12k_peer *peer; u32 bw, smps; + ar = ath12k_ah_to_ar(ah); + spin_lock_bh(&ar->ab->base_lock); peer = ath12k_peer_find(ar->ab, arvif->vdev_id, sta->addr); @@ -4108,10 +4135,13 @@ static int ath12k_mac_op_conf_tx(struct ieee80211_hw *hw, unsigned int link_id, u16 ac, const struct ieee80211_tx_queue_params *params) { - struct ath12k *ar = hw->priv; + struct ath12k_hw *ah = ath12k_hw_to_ah(hw); + struct ath12k *ar; struct ath12k_vif *arvif = ath12k_vif_to_arvif(vif); int ret; + ar = ath12k_ah_to_ar(ah); + mutex_lock(&ar->conf_mutex); ret = ath12k_mac_conf_tx(arvif, link_id, ac, params); mutex_unlock(&ar->conf_mutex); @@ -5013,10 +5043,10 @@ static void ath12k_mac_op_tx(struct ieee80211_hw *hw, struct sk_buff *skb) { struct ath12k_skb_cb *skb_cb = ATH12K_SKB_CB(skb); - struct ath12k *ar = hw->priv; struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); struct ieee80211_vif *vif = info->control.vif; struct ath12k_vif *arvif = ath12k_vif_to_arvif(vif); + struct ath12k *ar = arvif->ar; struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data; struct ieee80211_key_conf *key = info->control.hw_key; u32 info_flags = info->flags; @@ -5210,7 +5240,8 @@ static int ath12k_mac_start(struct ath12k *ar) static int ath12k_mac_op_start(struct ieee80211_hw *hw) { - struct ath12k *ar = hw->priv; + struct ath12k_hw *ah = ath12k_hw_to_ah(hw); + struct ath12k *ar = ath12k_ah_to_ar(ah); struct ath12k_base *ab = ar->ab; int ret; @@ -5318,7 +5349,8 @@ static void ath12k_mac_stop(struct ath12k *ar) static void ath12k_mac_op_stop(struct ieee80211_hw *hw) { - struct ath12k *ar = hw->priv; + struct ath12k_hw *ah = ath12k_hw_to_ah(hw); + struct ath12k *ar = ath12k_ah_to_ar(ah); ath12k_mac_drain_tx(ar); @@ -5498,8 +5530,9 @@ static void ath12k_mac_op_update_vif_offload(struct ieee80211_hw *hw, static int ath12k_mac_op_add_interface(struct ieee80211_hw *hw, struct ieee80211_vif *vif) { - struct ath12k *ar = hw->priv; - struct ath12k_base *ab = ar->ab; + struct ath12k_hw *ah = ath12k_hw_to_ah(hw); + struct ath12k *ar; + struct ath12k_base *ab; struct ath12k_vif *arvif = ath12k_vif_to_arvif(vif); struct ath12k_wmi_vdev_create_arg vdev_arg = {0}; struct ath12k_wmi_peer_create_arg peer_param; @@ -5511,6 +5544,9 @@ static int ath12k_mac_op_add_interface(struct ieee80211_hw *hw, vif->driver_flags |= IEEE80211_VIF_SUPPORTS_UAPSD; + ar = ath12k_ah_to_ar(ah); + ab = ar->ab; + mutex_lock(&ar->conf_mutex); if (vif->type == NL80211_IFTYPE_AP && @@ -5757,12 +5793,16 @@ static void ath12k_mac_vif_unref(struct ath12k_dp *dp, struct ieee80211_vif *vif static void ath12k_mac_op_remove_interface(struct ieee80211_hw *hw, struct ieee80211_vif *vif) { - struct ath12k *ar = hw->priv; + struct ath12k_hw *ah = ath12k_hw_to_ah(hw); + struct ath12k *ar; struct ath12k_vif *arvif = ath12k_vif_to_arvif(vif); - struct ath12k_base *ab = ar->ab; + struct ath12k_base *ab; unsigned long time_left; int ret; + ar = ath12k_ah_to_ar(ah); + ab = ar->ab; + mutex_lock(&ar->conf_mutex); ath12k_dbg(ab, ATH12K_DBG_MAC, "mac remove interface (vdev %d)\n", @@ -5872,7 +5912,10 @@ static void ath12k_mac_op_configure_filter(struct ieee80211_hw *hw, unsigned int *total_flags, u64 multicast) { - struct ath12k *ar = hw->priv; + struct ath12k_hw *ah = ath12k_hw_to_ah(hw); + struct ath12k *ar; + + ar = ath12k_ah_to_ar(ah); mutex_lock(&ar->conf_mutex); @@ -5884,7 +5927,10 @@ static void ath12k_mac_op_configure_filter(struct ieee80211_hw *hw, static int ath12k_mac_op_get_antenna(struct ieee80211_hw *hw, u32 *tx_ant, u32 *rx_ant) { - struct ath12k *ar = hw->priv; + struct ath12k_hw *ah = ath12k_hw_to_ah(hw); + struct ath12k *ar; + + ar = ath12k_ah_to_ar(ah); mutex_lock(&ar->conf_mutex); @@ -5898,9 +5944,12 @@ static int ath12k_mac_op_get_antenna(struct ieee80211_hw *hw, u32 *tx_ant, u32 * static int ath12k_mac_op_set_antenna(struct ieee80211_hw *hw, u32 tx_ant, u32 rx_ant) { - struct ath12k *ar = hw->priv; + struct ath12k_hw *ah = ath12k_hw_to_ah(hw); + struct ath12k *ar; int ret; + ar = ath12k_ah_to_ar(ah); + mutex_lock(&ar->conf_mutex); ret = __ath12k_set_antenna(ar, tx_ant, rx_ant); mutex_unlock(&ar->conf_mutex); @@ -5942,10 +5991,13 @@ static int ath12k_mac_op_ampdu_action(struct ieee80211_hw *hw, struct ieee80211_vif *vif, struct ieee80211_ampdu_params *params) { - struct ath12k *ar = hw->priv; + struct ath12k_hw *ah = ath12k_hw_to_ah(hw); + struct ath12k *ar; struct ath12k_vif *arvif = ath12k_vif_to_arvif(vif); int ret = -EINVAL; + ar = ath12k_ah_to_ar(ah); + mutex_lock(&ar->conf_mutex); ret = ath12k_mac_ampdu_action(arvif, params); mutex_unlock(&ar->conf_mutex); @@ -5960,8 +6012,12 @@ static int ath12k_mac_op_ampdu_action(struct ieee80211_hw *hw, static int ath12k_mac_op_add_chanctx(struct ieee80211_hw *hw, struct ieee80211_chanctx_conf *ctx) { - struct ath12k *ar = hw->priv; - struct ath12k_base *ab = ar->ab; + struct ath12k_hw *ah = ath12k_hw_to_ah(hw); + struct ath12k *ar; + struct ath12k_base *ab; + + ar = ath12k_ah_to_ar(ah); + ab = ar->ab; ath12k_dbg(ab, ATH12K_DBG_MAC, "mac chanctx add freq %u width %d ptr %pK\n", @@ -5984,8 +6040,12 @@ static int ath12k_mac_op_add_chanctx(struct ieee80211_hw *hw, static void ath12k_mac_op_remove_chanctx(struct ieee80211_hw *hw, struct ieee80211_chanctx_conf *ctx) { - struct ath12k *ar = hw->priv; - struct ath12k_base *ab = ar->ab; + struct ath12k_hw *ah = ath12k_hw_to_ah(hw); + struct ath12k *ar; + struct ath12k_base *ab; + + ar = ath12k_ah_to_ar(ah); + ab = ar->ab; ath12k_dbg(ab, ATH12K_DBG_MAC, "mac chanctx remove freq %u width %d ptr %pK\n", @@ -6393,8 +6453,12 @@ static void ath12k_mac_op_change_chanctx(struct ieee80211_hw *hw, struct ieee80211_chanctx_conf *ctx, u32 changed) { - struct ath12k *ar = hw->priv; - struct ath12k_base *ab = ar->ab; + struct ath12k_hw *ah = ath12k_hw_to_ah(hw); + struct ath12k *ar; + struct ath12k_base *ab; + + ar = ath12k_ah_to_ar(ah); + ab = ar->ab; mutex_lock(&ar->conf_mutex); @@ -6456,12 +6520,16 @@ ath12k_mac_op_assign_vif_chanctx(struct ieee80211_hw *hw, struct ieee80211_bss_conf *link_conf, struct ieee80211_chanctx_conf *ctx) { - struct ath12k *ar = hw->priv; - struct ath12k_base *ab = ar->ab; + struct ath12k_hw *ah = ath12k_hw_to_ah(hw); + struct ath12k *ar; + struct ath12k_base *ab; struct ath12k_vif *arvif = ath12k_vif_to_arvif(vif); int ret; struct ath12k_wmi_peer_create_arg param; + ar = ath12k_ah_to_ar(ah); + ab = ar->ab; + mutex_lock(&ar->conf_mutex); ath12k_dbg(ab, ATH12K_DBG_MAC, @@ -6535,11 +6603,15 @@ ath12k_mac_op_unassign_vif_chanctx(struct ieee80211_hw *hw, struct ieee80211_bss_conf *link_conf, struct ieee80211_chanctx_conf *ctx) { - struct ath12k *ar = hw->priv; - struct ath12k_base *ab = ar->ab; + struct ath12k_hw *ah = ath12k_hw_to_ah(hw); + struct ath12k *ar; + struct ath12k_base *ab; struct ath12k_vif *arvif = ath12k_vif_to_arvif(vif); int ret; + ar = ath12k_ah_to_ar(ah); + ab = ar->ab; + mutex_lock(&ar->conf_mutex); ath12k_dbg(ab, ATH12K_DBG_MAC, @@ -6587,7 +6659,10 @@ ath12k_mac_op_switch_vif_chanctx(struct ieee80211_hw *hw, int n_vifs, enum ieee80211_chanctx_switch_mode mode) { - struct ath12k *ar = hw->priv; + struct ath12k_hw *ah = ath12k_hw_to_ah(hw); + struct ath12k *ar; + + ar = ath12k_ah_to_ar(ah); mutex_lock(&ar->conf_mutex); @@ -6629,10 +6704,15 @@ ath12k_set_vdev_param_to_all_vifs(struct ath12k *ar, int param, u32 value) */ static int ath12k_mac_op_set_rts_threshold(struct ieee80211_hw *hw, u32 value) { - struct ath12k *ar = hw->priv; - int param_id = WMI_VDEV_PARAM_RTS_THRESHOLD; + struct ath12k_hw *ah = ath12k_hw_to_ah(hw); + struct ath12k *ar; + int param_id = WMI_VDEV_PARAM_RTS_THRESHOLD, ret; - return ath12k_set_vdev_param_to_all_vifs(ar, param_id, value); + ar = ath12k_ah_to_ar(ah); + + ret = ath12k_set_vdev_param_to_all_vifs(ar, param_id, value); + + return ret; } static int ath12k_mac_op_set_frag_threshold(struct ieee80211_hw *hw, u32 value) @@ -6671,7 +6751,8 @@ static void ath12k_mac_flush(struct ath12k *ar) static void ath12k_mac_op_flush(struct ieee80211_hw *hw, struct ieee80211_vif *vif, u32 queues, bool drop) { - struct ath12k *ar = hw->priv; + struct ath12k_hw *ah = ath12k_hw_to_ah(hw); + struct ath12k *ar = ath12k_ah_to_ar(ah); if (drop) return; @@ -6929,8 +7010,10 @@ ath12k_mac_op_set_bitrate_mask(struct ieee80211_hw *hw, ldpc = !!(ar->ht_cap_info & WMI_HT_CAP_LDPC); sgi = mask->control[band].gi; - if (sgi == NL80211_TXRATE_FORCE_LGI) - return -EINVAL; + if (sgi == NL80211_TXRATE_FORCE_LGI) { + ret = -EINVAL; + goto out; + } /* mac80211 doesn't support sending a fixed HT/VHT MCS alone, rather it * requires passing at least one of used basic rates along with them. @@ -6946,7 +7029,7 @@ ath12k_mac_op_set_bitrate_mask(struct ieee80211_hw *hw, if (ret) { ath12k_warn(ar->ab, "failed to get single legacy rate for vdev %i: %d\n", arvif->vdev_id, ret); - return ret; + goto out; } ieee80211_iterate_stations_atomic(hw, ath12k_mac_disable_peer_fixed_rate, @@ -6991,7 +7074,8 @@ ath12k_mac_op_set_bitrate_mask(struct ieee80211_hw *hw, */ ath12k_warn(ar->ab, "Setting more than one MCS Value in bitrate mask not supported\n"); - return -EINVAL; + ret = -EINVAL; + goto out; } ieee80211_iterate_stations_atomic(hw, @@ -7018,6 +7102,7 @@ ath12k_mac_op_set_bitrate_mask(struct ieee80211_hw *hw, mutex_unlock(&ar->conf_mutex); +out: return ret; } @@ -7025,14 +7110,18 @@ static void ath12k_mac_op_reconfig_complete(struct ieee80211_hw *hw, enum ieee80211_reconfig_type reconfig_type) { - struct ath12k *ar = hw->priv; - struct ath12k_base *ab = ar->ab; + struct ath12k_hw *ah = ath12k_hw_to_ah(hw); + struct ath12k *ar; + struct ath12k_base *ab; struct ath12k_vif *arvif; int recovery_count; if (reconfig_type != IEEE80211_RECONFIG_TYPE_RESTART) return; + ar = ath12k_ah_to_ar(ah); + ab = ar->ab; + mutex_lock(&ar->conf_mutex); if (ar->state == ATH12K_STATE_RESTARTED) { @@ -7116,7 +7205,8 @@ ath12k_mac_update_bss_chan_survey(struct ath12k *ar, static int ath12k_mac_op_get_survey(struct ieee80211_hw *hw, int idx, struct survey_info *survey) { - struct ath12k *ar = hw->priv; + struct ath12k_hw *ah = ath12k_hw_to_ah(hw); + struct ath12k *ar; struct ieee80211_supported_band *sband; struct survey_info *ar_survey; int ret = 0; @@ -7124,6 +7214,8 @@ static int ath12k_mac_op_get_survey(struct ieee80211_hw *hw, int idx, if (idx >= ATH12K_NUM_CHANS) return -ENOENT; + ar = ath12k_ah_to_ar(ah); + ar_survey = &ar->survey[idx]; mutex_lock(&ar->conf_mutex); @@ -7155,6 +7247,7 @@ static int ath12k_mac_op_get_survey(struct ieee80211_hw *hw, int idx, exit: mutex_unlock(&ar->conf_mutex); + return ret; } @@ -7354,20 +7447,44 @@ static int ath12k_mac_setup_channels_rates(struct ath12k *ar, return 0; } -static int ath12k_mac_setup_iface_combinations(struct ath12k *ar) +static u16 ath12k_mac_get_ifmodes(struct ath12k_hw *ah) { - struct ath12k_base *ab = ar->ab; - struct ieee80211_hw *hw = ath12k_ar_to_hw(ar); - struct wiphy *wiphy = hw->wiphy; + struct ath12k *ar = ath12k_ah_to_ar(ah); + u16 interface_modes = U16_MAX; + + interface_modes &= ar->ab->hw_params->interface_modes; + + return interface_modes == U16_MAX ? 0 : interface_modes; +} + +static bool ath12k_mac_is_iface_mode_enable(struct ath12k_hw *ah, + enum nl80211_iftype type) +{ + struct ath12k *ar = ath12k_ah_to_ar(ah); + u16 interface_modes, mode; + bool is_enable = true; + + mode = BIT(type); + + interface_modes = ar->ab->hw_params->interface_modes; + if (!(interface_modes & mode)) + is_enable = false; + + return is_enable; +} + +static int ath12k_mac_setup_iface_combinations(struct ath12k_hw *ah) +{ + struct wiphy *wiphy = ah->hw->wiphy; struct ieee80211_iface_combination *combinations; struct ieee80211_iface_limit *limits; int n_limits, max_interfaces; bool ap, mesh; - ap = ab->hw_params->interface_modes & BIT(NL80211_IFTYPE_AP); + ap = ath12k_mac_is_iface_mode_enable(ah, NL80211_IFTYPE_AP); mesh = IS_ENABLED(CONFIG_MAC80211_MESH) && - ab->hw_params->interface_modes & BIT(NL80211_IFTYPE_MESH_POINT); + ath12k_mac_is_iface_mode_enable(ah, NL80211_IFTYPE_MESH_POINT); combinations = kzalloc(sizeof(*combinations), GFP_KERNEL); if (!combinations) @@ -7462,10 +7579,11 @@ static void ath12k_mac_cleanup_unregister(struct ath12k *ar) kfree(ar->mac.sbands[NL80211_BAND_6GHZ].channels); } -static void ath12k_mac_hw_unregister(struct ath12k *ar) +static void ath12k_mac_hw_unregister(struct ath12k_hw *ah) { - struct ieee80211_hw *hw = ath12k_ar_to_hw(ar); + struct ieee80211_hw *hw = ah->hw; struct wiphy *wiphy = hw->wiphy; + struct ath12k *ar = ath12k_ah_to_ar(ah); cancel_work_sync(&ar->regd_update_work); @@ -7507,13 +7625,14 @@ static int ath12k_mac_setup_register(struct ath12k *ar, return 0; } -static int ath12k_mac_hw_register(struct ath12k *ar) +static int ath12k_mac_hw_register(struct ath12k_hw *ah) { - struct ath12k_base *ab = ar->ab; - struct ieee80211_hw *hw = ath12k_ar_to_hw(ar); + struct ieee80211_hw *hw = ah->hw; struct wiphy *wiphy = hw->wiphy; - struct ath12k_pdev *pdev = ar->pdev; - struct ath12k_pdev_cap *cap = &pdev->cap; + struct ath12k *ar = ath12k_ah_to_ar(ah); + struct ath12k_base *ab = ar->ab; + struct ath12k_pdev *pdev; + struct ath12k_pdev_cap *cap; static const u32 cipher_suites[] = { WLAN_CIPHER_SUITE_TKIP, WLAN_CIPHER_SUITE_CCMP, @@ -7528,30 +7647,34 @@ static int ath12k_mac_hw_register(struct ath12k *ar) int ret; u32 ht_cap = 0; - if (ab->pdevs_macaddr_valid) { + pdev = ar->pdev; + + if (ab->pdevs_macaddr_valid) ether_addr_copy(ar->mac_addr, pdev->mac_addr); - } else { + else ether_addr_copy(ar->mac_addr, ab->mac_addr); - ar->mac_addr[4] += ar->pdev_idx; - } ret = ath12k_mac_setup_register(ar, &ht_cap, hw->wiphy->bands); if (ret) goto out; - SET_IEEE80211_PERM_ADDR(hw, ar->mac_addr); - SET_IEEE80211_DEV(hw, ab->dev); + wiphy->max_ap_assoc_sta = ar->max_num_stations; - ret = ath12k_mac_setup_iface_combinations(ar); - if (ret) { - ath12k_err(ar->ab, "failed to setup interface combinations: %d\n", ret); - goto err_setup_unregister; - } + cap = &pdev->cap; wiphy->available_antennas_rx = cap->rx_chain_mask; wiphy->available_antennas_tx = cap->tx_chain_mask; - wiphy->interface_modes = ab->hw_params->interface_modes; + SET_IEEE80211_PERM_ADDR(hw, ar->mac_addr); + SET_IEEE80211_DEV(hw, ab->dev); + + ret = ath12k_mac_setup_iface_combinations(ah); + if (ret) { + ath12k_err(ab, "failed to setup interface combinations: %d\n", ret); + goto err_cleanup_unregister; + } + + wiphy->interface_modes = ath12k_mac_get_ifmodes(ah); if (wiphy->bands[NL80211_BAND_2GHZ] && wiphy->bands[NL80211_BAND_5GHZ] && @@ -7604,8 +7727,6 @@ static int ath12k_mac_hw_register(struct ath12k *ar) wiphy->features |= NL80211_FEATURE_AP_MODE_CHAN_WIDTH_CHANGE | NL80211_FEATURE_AP_SCAN; - wiphy->max_ap_assoc_sta = ar->max_num_stations; - hw->queues = ATH12K_HW_MAX_QUEUES; wiphy->tx_queue_len = ATH12K_QUEUE_LEN; hw->offchannel_tx_hw_queue = ATH12K_HW_MAX_QUEUES - 1; @@ -7642,7 +7763,7 @@ static int ath12k_mac_hw_register(struct ath12k *ar) ret = ieee80211_register_hw(hw); if (ret) { - ath12k_err(ar->ab, "ieee80211 registration failed: %d\n", ret); + ath12k_err(ab, "ieee80211 registration failed: %d\n", ret); goto err_free_if_combs; } @@ -7670,14 +7791,12 @@ static int ath12k_mac_hw_register(struct ath12k *ar) kfree(wiphy->iface_combinations[0].limits); kfree(wiphy->iface_combinations); -err_setup_unregister: - kfree(ar->mac.sbands[NL80211_BAND_2GHZ].channels); - kfree(ar->mac.sbands[NL80211_BAND_5GHZ].channels); - kfree(ar->mac.sbands[NL80211_BAND_6GHZ].channels); - - SET_IEEE80211_DEV(hw, NULL); +err_cleanup_unregister: + ath12k_mac_cleanup_unregister(ar); out: + SET_IEEE80211_DEV(hw, NULL); + return ret; } @@ -7723,8 +7842,7 @@ static void ath12k_mac_setup(struct ath12k *ar) int ath12k_mac_register(struct ath12k_base *ab) { - struct ath12k *ar; - struct ath12k_pdev *pdev; + struct ath12k_hw *ah; int i; int ret; @@ -7735,22 +7853,23 @@ int ath12k_mac_register(struct ath12k_base *ab) ab->cc_freq_hz = 320000; 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; + for (i = 0; i < ab->num_hw; i++) { + ah = ab->ah[i]; - ret = ath12k_mac_hw_register(ar); + ret = ath12k_mac_hw_register(ah); if (ret) - goto err_cleanup; + goto err; } return 0; -err_cleanup: +err: for (i = i - 1; i >= 0; i--) { - pdev = &ab->pdevs[i]; - ar = pdev->ar; - ath12k_mac_hw_unregister(ar); + ah = ab->ah[i]; + if (!ah) + continue; + + ath12k_mac_hw_unregister(ah); } return ret; @@ -7758,89 +7877,125 @@ int ath12k_mac_register(struct ath12k_base *ab) void ath12k_mac_unregister(struct ath12k_base *ab) { - struct ath12k *ar; - struct ath12k_pdev *pdev; + struct ath12k_hw *ah; int i; - for (i = 0; i < ab->num_radios; i++) { - pdev = &ab->pdevs[i]; - ar = pdev->ar; - if (!ar) + for (i = ab->num_hw - 1; i >= 0; i--) { + ah = ab->ah[i]; + if (!ah) continue; - ath12k_mac_hw_unregister(ar); + ath12k_mac_hw_unregister(ah); } } -static void ath12k_mac_hw_destroy(struct ath12k_base *ab) +static void ath12k_mac_hw_destroy(struct ath12k_hw *ah) { - struct ath12k *ar; - struct ath12k_pdev *pdev; - int i; - - for (i = 0; i < ab->num_radios; i++) { - pdev = &ab->pdevs[i]; - ar = pdev->ar; - if (!ar) - continue; - - ieee80211_free_hw(ath12k_ar_to_hw(ar)); - pdev->ar = NULL; - } + ieee80211_free_hw(ah->hw); } -static int ath12k_mac_hw_allocate(struct ath12k_base *ab) +static struct ath12k_hw *ath12k_mac_hw_allocate(struct ath12k_base *ab, + struct ath12k_pdev_map *pdev_map, + u8 num_pdev_map) { struct ieee80211_hw *hw; struct ath12k *ar; struct ath12k_pdev *pdev; - int ret; + struct ath12k_hw *ah; int i; + u8 pdev_idx; - for (i = 0; i < ab->num_radios; i++) { - pdev = &ab->pdevs[i]; - hw = ieee80211_alloc_hw(sizeof(struct ath12k), &ath12k_ops); - if (!hw) { - ath12k_warn(ab, "failed to allocate mac80211 hw device\n"); - ret = -ENOMEM; - goto err_free_mac; - } + hw = ieee80211_alloc_hw(struct_size(ah, radio, num_pdev_map), + &ath12k_ops); + if (!hw) + return NULL; - ar = hw->priv; - ar->hw = hw; + ah = ath12k_hw_to_ah(hw); + ah->hw = hw; + ah->num_radio = num_pdev_map; + + for (i = 0; i < num_pdev_map; i++) { + ab = pdev_map[i].ab; + pdev_idx = pdev_map[i].pdev_idx; + pdev = &ab->pdevs[pdev_idx]; + + ar = ath12k_ah_to_ar(ah); + ar->ah = ah; ar->ab = ab; + ar->hw_link_id = i; ar->pdev = pdev; - ar->pdev_idx = i; + ar->pdev_idx = pdev_idx; pdev->ar = ar; ath12k_mac_setup(ar); } - return 0; - -err_free_mac: - ath12k_mac_hw_destroy(ab); - - return ret; + return ah; } void ath12k_mac_destroy(struct ath12k_base *ab) { - ath12k_mac_hw_destroy(ab); + struct ath12k_pdev *pdev; + int i; + + for (i = 0; i < ab->num_radios; i++) { + pdev = &ab->pdevs[i]; + if (!pdev->ar) + continue; + + pdev->ar = NULL; + } + + for (i = 0; i < ab->num_hw; i++) { + if (!ab->ah[i]) + continue; + + ath12k_mac_hw_destroy(ab->ah[i]); + ab->ah[i] = NULL; + } } int ath12k_mac_allocate(struct ath12k_base *ab) { - int ret; + struct ath12k_hw *ah; + struct ath12k_pdev_map pdev_map[MAX_RADIOS]; + int ret, i, j; + u8 radio_per_hw; if (test_bit(ATH12K_FLAG_REGISTERED, &ab->dev_flags)) return 0; - ret = ath12k_mac_hw_allocate(ab); - if (ret) - return ret; + ab->num_hw = ab->num_radios; + radio_per_hw = 1; + + for (i = 0; i < ab->num_hw; i++) { + for (j = 0; j < radio_per_hw; j++) { + pdev_map[j].ab = ab; + pdev_map[j].pdev_idx = (i * radio_per_hw) + j; + } + + ah = ath12k_mac_hw_allocate(ab, pdev_map, radio_per_hw); + if (!ah) { + ath12k_warn(ab, "failed to allocate mac80211 hw device for hw_idx %d\n", + i); + goto err; + } + + ab->ah[i] = ah; + } ath12k_dp_pdev_pre_alloc(ab); return 0; + +err: + for (i = i - 1; i >= 0; i--) { + if (!ab->ah[i]) + continue; + + ath12k_mac_hw_destroy(ab->ah[i]); + ab->ah[i] = NULL; + } + + return ret; } diff --git a/drivers/net/wireless/ath/ath12k/mac.h b/drivers/net/wireless/ath/ath12k/mac.h index 7c63bb628adc..3f5e1be0dff9 100644 --- a/drivers/net/wireless/ath/ath12k/mac.h +++ b/drivers/net/wireless/ath/ath12k/mac.h @@ -1,7 +1,7 @@ /* SPDX-License-Identifier: BSD-3-Clause-Clear */ /* * Copyright (c) 2018-2021 The Linux Foundation. All rights reserved. - * Copyright (c) 2021-2023 Qualcomm Innovation Center, Inc. All rights reserved. + * Copyright (c) 2021-2024 Qualcomm Innovation Center, Inc. All rights reserved. */ #ifndef ATH12K_MAC_H @@ -12,6 +12,8 @@ struct ath12k; struct ath12k_base; +struct ath12k_hw; +struct ath12k_pdev_map; struct ath12k_generic_iter { struct ath12k *ar; diff --git a/drivers/net/wireless/ath/ath12k/reg.c b/drivers/net/wireless/ath/ath12k/reg.c index 88e71d171355..a164f15d1e2b 100644 --- a/drivers/net/wireless/ath/ath12k/reg.c +++ b/drivers/net/wireless/ath/ath12k/reg.c @@ -48,7 +48,8 @@ ath12k_reg_notifier(struct wiphy *wiphy, struct regulatory_request *request) { struct ieee80211_hw *hw = wiphy_to_ieee80211_hw(wiphy); struct ath12k_wmi_init_country_arg arg; - struct ath12k *ar = hw->priv; + struct ath12k_hw *ah = ath12k_hw_to_ah(hw); + struct ath12k *ar = ath12k_ah_to_ar(ah); int ret; ath12k_dbg(ar->ab, ATH12K_DBG_REG, From 9f9df1a2535f6c890242b80d8538bd90ae540647 Mon Sep 17 00:00:00 2001 From: Baochen Qiang Date: Thu, 18 Jan 2024 07:53:48 +0200 Subject: [PATCH 60/71] wifi: ath12k: add support for collecting firmware log Currently there is no way to collect firmware log because firmware does not send it to host. Also host does not handle WMI_DIAG_EVENTID which is used by firmware to upload firmware log. So add support for it by firstly enabling firmware log upload via a QMI message, and secondly processing WMI DIAG event to expose it to userspace via trace event. This change applies to both WCN7850 and QCN9274. Tested-on: WCN7850 hw2.0 PCI WLAN.HMT.1.0-03427-QCAHMTSWPL_V1.0_V2.0_SILICONZ-1.15378.4 Signed-off-by: Baochen Qiang Acked-by: Jeff Johnson Signed-off-by: Kalle Valo Link: https://msgid.link/20240115023726.2866-1-quic_bqiang@quicinc.com --- drivers/net/wireless/ath/ath12k/qmi.c | 93 +++++++++++++++++++++++++ drivers/net/wireless/ath/ath12k/qmi.h | 17 ++++- drivers/net/wireless/ath/ath12k/trace.h | 29 +++++++- drivers/net/wireless/ath/ath12k/wmi.c | 9 +++ 4 files changed, 146 insertions(+), 2 deletions(-) diff --git a/drivers/net/wireless/ath/ath12k/qmi.c b/drivers/net/wireless/ath/ath12k/qmi.c index d20d08023c81..69f56400367c 100644 --- a/drivers/net/wireless/ath/ath12k/qmi.c +++ b/drivers/net/wireless/ath/ath12k/qmi.c @@ -1954,6 +1954,50 @@ static const struct qmi_elem_info qmi_wlanfw_fw_ready_ind_msg_v01_ei[] = { }, }; +static const 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, + enable_fwlog_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, + enable_fwlog), + }, + { + .data_type = QMI_EOTI, + .array_type = NO_ARRAY, + .tlv_type = QMI_COMMON_TLV_TYPE, + }, +}; + +static const 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 void ath12k_host_cap_parse_mlo(struct ath12k_base *ab, struct qmi_wlanfw_host_cap_req_msg_v01 *req) { @@ -2853,6 +2897,49 @@ static int ath12k_qmi_wlanfw_wlan_cfg_send(struct ath12k_base *ab) return ret; } +static int ath12k_qmi_wlanfw_wlan_ini_send(struct ath12k_base *ab) +{ + struct qmi_wlanfw_wlan_ini_resp_msg_v01 resp = {}; + struct qmi_wlanfw_wlan_ini_req_msg_v01 req = {}; + struct qmi_txn txn; + int ret; + + req.enable_fwlog_valid = true; + req.enable_fwlog = 1; + + 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, + ATH12K_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) { + qmi_txn_cancel(&txn); + ath12k_warn(ab, "failed to send QMI wlan ini request: %d\n", + ret); + goto out; + } + + ret = qmi_txn_wait(&txn, msecs_to_jiffies(ATH12K_QMI_WLANFW_TIMEOUT_MS)); + if (ret < 0) { + ath12k_warn(ab, "failed to receive QMI wlan ini request: %d\n", ret); + goto out; + } + + if (resp.resp.result != QMI_RESULT_SUCCESS_V01) { + ath12k_warn(ab, "QMI wlan ini response failure: %d %d\n", + resp.resp.result, resp.resp.error); + ret = -EINVAL; + goto out; + } + +out: + return ret; +} + void ath12k_qmi_firmware_stop(struct ath12k_base *ab) { int ret; @@ -2869,6 +2956,12 @@ int ath12k_qmi_firmware_start(struct ath12k_base *ab, { int ret; + ret = ath12k_qmi_wlanfw_wlan_ini_send(ab); + if (ret < 0) { + ath12k_warn(ab, "qmi failed to send wlan fw ini: %d\n", ret); + return ret; + } + ret = ath12k_qmi_wlanfw_wlan_cfg_send(ab); if (ret < 0) { ath12k_warn(ab, "qmi failed to send wlan cfg:%d\n", ret); diff --git a/drivers/net/wireless/ath/ath12k/qmi.h b/drivers/net/wireless/ath/ath12k/qmi.h index bfed22c310be..828ab2bf037d 100644 --- a/drivers/net/wireless/ath/ath12k/qmi.h +++ b/drivers/net/wireless/ath/ath12k/qmi.h @@ -1,7 +1,7 @@ /* SPDX-License-Identifier: BSD-3-Clause-Clear */ /* * Copyright (c) 2018-2021 The Linux Foundation. All rights reserved. - * Copyright (c) 2021-2023 Qualcomm Innovation Center, Inc. All rights reserved. + * Copyright (c) 2021-2024 Qualcomm Innovation Center, Inc. All rights reserved. */ #ifndef ATH12K_QMI_H @@ -576,6 +576,21 @@ struct qmi_wlanfw_wlan_cfg_resp_msg_v01 { struct qmi_response_type_v01 resp; }; +#define ATH12K_QMI_WLANFW_WLAN_INI_REQ_V01 0x002F +#define ATH12K_QMI_WLANFW_WLAN_INI_RESP_V01 0x002F +#define QMI_WLANFW_WLAN_INI_REQ_MSG_V01_MAX_LEN 7 +#define QMI_WLANFW_WLAN_INI_RESP_MSG_V01_MAX_LEN 7 + +struct qmi_wlanfw_wlan_ini_req_msg_v01 { + /* Must be set to true if enable_fwlog is being passed */ + u8 enable_fwlog_valid; + u8 enable_fwlog; +}; + +struct qmi_wlanfw_wlan_ini_resp_msg_v01 { + struct qmi_response_type_v01 resp; +}; + int ath12k_qmi_firmware_start(struct ath12k_base *ab, u32 mode); void ath12k_qmi_firmware_stop(struct ath12k_base *ab); diff --git a/drivers/net/wireless/ath/ath12k/trace.h b/drivers/net/wireless/ath/ath12k/trace.h index f72096684b74..240737e1542d 100644 --- a/drivers/net/wireless/ath/ath12k/trace.h +++ b/drivers/net/wireless/ath/ath12k/trace.h @@ -1,7 +1,7 @@ /* SPDX-License-Identifier: BSD-3-Clause-Clear */ /* * Copyright (c) 2019-2021 The Linux Foundation. All rights reserved. - * Copyright (c) 2021-2022 Qualcomm Innovation Center, Inc. All rights reserved. + * Copyright (c) 2021-2022, 2024 Qualcomm Innovation Center, Inc. All rights reserved. */ #if !defined(_TRACE_H_) || defined(TRACE_HEADER_MULTI_READ) @@ -140,6 +140,33 @@ TRACE_EVENT(ath12k_htt_rxdesc, ) ); +TRACE_EVENT(ath12k_wmi_diag, + TP_PROTO(struct ath12k_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 */ diff --git a/drivers/net/wireless/ath/ath12k/wmi.c b/drivers/net/wireless/ath/ath12k/wmi.c index 4d41c335ef34..2fa724e5851a 100644 --- a/drivers/net/wireless/ath/ath12k/wmi.c +++ b/drivers/net/wireless/ath/ath12k/wmi.c @@ -6664,6 +6664,12 @@ static void ath12k_rfkill_state_change_event(struct ath12k_base *ab, kfree(tb); } +static void +ath12k_wmi_diag_event(struct ath12k_base *ab, struct sk_buff *skb) +{ + trace_ath12k_wmi_diag(ab, skb->data, skb->len); +} + static void ath12k_wmi_op_rx(struct ath12k_base *ab, struct sk_buff *skb) { struct wmi_cmd_hdr *cmd_hdr; @@ -6774,6 +6780,9 @@ static void ath12k_wmi_op_rx(struct ath12k_base *ab, struct sk_buff *skb) case WMI_VDEV_DELETE_RESP_EVENTID: ath12k_vdev_delete_resp_event(ab, skb); break; + case WMI_DIAG_EVENTID: + ath12k_wmi_diag_event(ab, skb); + break; /* TODO: Add remaining events */ default: ath12k_dbg(ab, ATH12K_DBG_WMI, "Unknown eventid: 0x%x\n", id); From 1779487e72e0390d240df271be0005397d0110f3 Mon Sep 17 00:00:00 2001 From: Jeff Johnson Date: Thu, 18 Jan 2024 08:12:53 -0800 Subject: [PATCH 61/71] wifi: ath10k: add missing wmi_10_4_feature_mask documentation Currently kernel-doc reports the following issues: drivers/net/wireless/ath/ath10k/wmi.h:3033: warning: Enum value 'WMI_10_4_EXT_PEER_TID_CONFIGS_SUPPORT' not described in enum 'wmi_10_4_feature_mask' drivers/net/wireless/ath/ath10k/wmi.h:3033: warning: Enum value 'WMI_10_4_REPORT_AIRTIME' not described in enum 'wmi_10_4_feature_mask' Update the kernel-doc for enum wmi_10_4_feature_mask to add the missing documentation. No functional changes, compile tested only. Signed-off-by: Jeff Johnson Signed-off-by: Kalle Valo Link: https://msgid.link/20240118-ath10k-kerneldoc-v1-1-99c7e8d95aad@quicinc.com --- drivers/net/wireless/ath/ath10k/wmi.h | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/drivers/net/wireless/ath/ath10k/wmi.h b/drivers/net/wireless/ath/ath10k/wmi.h index b64b6e214bae..2379501225a4 100644 --- a/drivers/net/wireless/ath/ath10k/wmi.h +++ b/drivers/net/wireless/ath/ath10k/wmi.h @@ -3,7 +3,7 @@ * Copyright (c) 2005-2011 Atheros Communications Inc. * Copyright (c) 2011-2017 Qualcomm Atheros, Inc. * Copyright (c) 2018-2019, The Linux Foundation. All rights reserved. - * Copyright (c) 2021-2023 Qualcomm Innovation Center, Inc. All rights reserved. + * Copyright (c) 2021-2024 Qualcomm Innovation Center, Inc. All rights reserved. */ #ifndef _WMI_H_ @@ -3008,8 +3008,11 @@ enum wmi_coex_version { * @WMI_10_4_TDLS_UAPSD_SLEEP_STA: TDLS sleep sta support enable/disable * @WMI_10_4_TDLS_CONN_TRACKER_IN_HOST_MODE: TDLS connection tracker in host * enable/disable - * @WMI_10_4_TDLS_EXPLICIT_MODE_ONLY:Explicit TDLS mode enable/disable + * @WMI_10_4_TDLS_EXPLICIT_MODE_ONLY: Explicit TDLS mode enable/disable * @WMI_10_4_TX_DATA_ACK_RSSI: Enable DATA ACK RSSI if firmware is capable + * @WMI_10_4_EXT_PEER_TID_CONFIGS_SUPPORT: Firmware supports Extended Peer + * TID configuration for QoS related settings + * @WMI_10_4_REPORT_AIRTIME: Firmware supports transmit airtime reporting */ enum wmi_10_4_feature_mask { WMI_10_4_LTEU_SUPPORT = BIT(0), From 5f813b0447feef3a4883b66e600c7317a4d7d76b Mon Sep 17 00:00:00 2001 From: Jeff Johnson Date: Thu, 18 Jan 2024 08:12:54 -0800 Subject: [PATCH 62/71] wifi: ath10k: correctly document enum wmi_tlv_tx_pause_id Currently kernel-doc reports the issue: drivers/net/wireless/ath/ath10k/wmi-tlv.h:2363: warning: cannot understand function prototype: 'enum wmi_tlv_tx_pause_id ' Update the enum wmi_tlv_tx_pause_id documentation to fix this issue. No functional changes, compile tested only. Signed-off-by: Jeff Johnson Acked-by: Randy Dunlap Signed-off-by: Kalle Valo Link: https://msgid.link/20240118-ath10k-kerneldoc-v1-2-99c7e8d95aad@quicinc.com --- drivers/net/wireless/ath/ath10k/wmi-tlv.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/net/wireless/ath/ath10k/wmi-tlv.h b/drivers/net/wireless/ath/ath10k/wmi-tlv.h index 83a8f07a687f..8a2f87d0a3a3 100644 --- a/drivers/net/wireless/ath/ath10k/wmi-tlv.h +++ b/drivers/net/wireless/ath/ath10k/wmi-tlv.h @@ -3,7 +3,7 @@ * Copyright (c) 2005-2011 Atheros Communications Inc. * Copyright (c) 2011-2017 Qualcomm Atheros, Inc. * Copyright (c) 2018-2019, The Linux Foundation. All rights reserved. - * Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved. + * Copyright (c) 2022, 2024 Qualcomm Innovation Center, Inc. All rights reserved. */ #ifndef _WMI_TLV_H #define _WMI_TLV_H @@ -2343,7 +2343,7 @@ struct wmi_tlv_adaptive_qcs { } __packed; /** - * wmi_tlv_tx_pause_id - firmware tx queue pause reason types + * enum wmi_tlv_tx_pause_id - firmware tx queue pause reason types * * @WMI_TLV_TX_PAUSE_ID_MCC: used for by multi-channel firmware scheduler. * Only vdev_map is valid. From 75dd17fdef110d99a2613d1284d2863cfc7cf6e9 Mon Sep 17 00:00:00 2001 From: Jeff Johnson Date: Thu, 18 Jan 2024 08:12:55 -0800 Subject: [PATCH 63/71] wifi: ath10k: fix htt_q_state_conf & htt_q_state kernel-doc Currently kernel-doc reports: drivers/net/wireless/ath/ath10k/htt.h:1488: warning: cannot understand function prototype: 'struct htt_q_state_conf ' drivers/net/wireless/ath/ath10k/htt.h:1542: warning: cannot understand function prototype: 'struct htt_q_state ' Update the kernel-doc for these two structs to resolve the warnings. No functional changes, compile tested only. Signed-off-by: Jeff Johnson Acked-by: Randy Dunlap Signed-off-by: Kalle Valo Link: https://msgid.link/20240118-ath10k-kerneldoc-v1-3-99c7e8d95aad@quicinc.com --- drivers/net/wireless/ath/ath10k/htt.h | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/drivers/net/wireless/ath/ath10k/htt.h b/drivers/net/wireless/ath/ath10k/htt.h index 4a9270e2a4c8..eb0ce2f49315 100644 --- a/drivers/net/wireless/ath/ath10k/htt.h +++ b/drivers/net/wireless/ath/ath10k/htt.h @@ -3,7 +3,7 @@ * Copyright (c) 2005-2011 Atheros Communications Inc. * Copyright (c) 2011-2017 Qualcomm Atheros, Inc. * Copyright (c) 2018, The Linux Foundation. All rights reserved. - * Copyright (c) 2021, 2023 Qualcomm Innovation Center, Inc. All rights reserved. + * Copyright (c) 2021, 2023-2024 Qualcomm Innovation Center, Inc. All rights reserved. */ #ifndef _HTT_H_ @@ -1474,15 +1474,19 @@ enum htt_q_depth_type { #define HTT_TX_Q_STATE_ENTRY_MULTIPLIER 0 /** - * htt_q_state_conf - part of htt_frag_desc_bank_cfg for host q state config + * struct htt_q_state_conf - part of htt_frag_desc_bank_cfg for host q state config * * Defines host q state format and behavior. See htt_q_state. * + * @paddr: Queue physical address + * @num_peers: Number of supported peers + * @num_tids: Number of supported TIDs * @record_size: Defines the size of each host q entry in bytes. In practice * however firmware (at least 10.4.3-00191) ignores this host * configuration value and uses hardcoded value of 1. * @record_multiplier: This is valid only when q depth type is MSDUs. It * defines the exponent for the power of 2 multiplication. + * @pad: struct padding for 32-bit alignment */ struct htt_q_state_conf { __le32 paddr; @@ -1518,7 +1522,7 @@ struct htt_frag_desc_bank_cfg64 { #define HTT_TX_Q_STATE_ENTRY_EXP_LSB 6 /** - * htt_q_state - shared between host and firmware via DMA + * struct htt_q_state - shared between host and firmware via DMA * * This structure is used for the host to expose it's software queue state to * firmware so that its rate control can schedule fetch requests for optimized From c80cc5cfefbaca35e019a26f31faa11031c13665 Mon Sep 17 00:00:00 2001 From: Jeff Johnson Date: Thu, 18 Jan 2024 08:12:56 -0800 Subject: [PATCH 64/71] wifi: ath10k: Fix htt_data_tx_completion kernel-doc warning Currently kernel-doc reports: drivers/net/wireless/ath/ath10k/htt.h:911: warning: Cannot understand * @brief target -> host TX completion indication message definition on line 911 - I thought it was a doc line This is because even though struct htt_data_tx_completion uses the kernel-doc marker "/**", it doesn't actual use kernel-doc syntax for the documentation. Rather than try to update this legacy driver documentation to use kernel-doc style, just replace the comment marker. No functional changes, compile tested only. Signed-off-by: Jeff Johnson Acked-by: Randy Dunlap Signed-off-by: Kalle Valo Link: https://msgid.link/20240118-ath10k-kerneldoc-v1-4-99c7e8d95aad@quicinc.com --- drivers/net/wireless/ath/ath10k/htt.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/wireless/ath/ath10k/htt.h b/drivers/net/wireless/ath/ath10k/htt.h index eb0ce2f49315..603f6de62b0a 100644 --- a/drivers/net/wireless/ath/ath10k/htt.h +++ b/drivers/net/wireless/ath/ath10k/htt.h @@ -906,7 +906,7 @@ struct htt_data_tx_completion_ext { __le16 msdus_rssi[]; } __packed; -/** +/* * @brief target -> host TX completion indication message definition * * @details From f020c30299323c206b9041dd478ac040dd828ec0 Mon Sep 17 00:00:00 2001 From: Jeff Johnson Date: Thu, 18 Jan 2024 08:12:57 -0800 Subject: [PATCH 65/71] wifi: ath10k: Fix enum ath10k_fw_crash_dump_type kernel-doc The kernel-doc script currently reports: drivers/net/wireless/ath/ath10k/coredump.h:27: warning: Enum value 'ATH10K_FW_CRASH_DUMP_REGISTERS' not described in enum 'ath10k_fw_crash_dump_type' drivers/net/wireless/ath/ath10k/coredump.h:27: warning: Enum value 'ATH10K_FW_CRASH_DUMP_CE_DATA' not described in enum 'ath10k_fw_crash_dump_type' drivers/net/wireless/ath/ath10k/coredump.h:27: warning: Enum value 'ATH10K_FW_CRASH_DUMP_RAM_DATA' not described in enum 'ath10k_fw_crash_dump_type' drivers/net/wireless/ath/ath10k/coredump.h:27: warning: Enum value 'ATH10K_FW_CRASH_DUMP_MAX' not described in enum 'ath10k_fw_crash_dump_type' drivers/net/wireless/ath/ath10k/coredump.h:27: warning: Excess enum value 'ATH10K_FW_CRASH_DUMP_REGDUMP' description in 'ath10k_fw_crash_dump_type' Fix these issues with the enum ath10k_fw_crash_dump_type kernel-doc. No functional changes, compile tested only. Signed-off-by: Jeff Johnson Acked-by: Randy Dunlap Signed-off-by: Kalle Valo Link: https://msgid.link/20240118-ath10k-kerneldoc-v1-5-99c7e8d95aad@quicinc.com --- drivers/net/wireless/ath/ath10k/coredump.h | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/drivers/net/wireless/ath/ath10k/coredump.h b/drivers/net/wireless/ath/ath10k/coredump.h index e5ef0352e319..8d274e0f374b 100644 --- a/drivers/net/wireless/ath/ath10k/coredump.h +++ b/drivers/net/wireless/ath/ath10k/coredump.h @@ -1,7 +1,7 @@ /* SPDX-License-Identifier: ISC */ /* * Copyright (c) 2011-2017 Qualcomm Atheros, Inc. - * Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved. + * Copyright (c) 2022, 2024 Qualcomm Innovation Center, Inc. All rights reserved. */ #ifndef _COREDUMP_H_ @@ -13,7 +13,11 @@ /** * enum ath10k_fw_crash_dump_type - types of data in the dump file - * @ATH10K_FW_CRASH_DUMP_REGDUMP: Register crash dump in binary format + * @ATH10K_FW_CRASH_DUMP_REGISTERS: Register crash dump in binary format + * @ATH10K_FW_CRASH_DUMP_CE_DATA: Copy Engine crash dump data + * @ATH10K_FW_CRASH_DUMP_RAM_DATA: RAM crash dump data, contains multiple + * struct ath10k_dump_ram_data_hdr + * @ATH10K_FW_CRASH_DUMP_MAX: Maximum enumeration */ enum ath10k_fw_crash_dump_type { ATH10K_FW_CRASH_DUMP_REGISTERS = 0, From 67a48d937fac917947540c9f89630d472cd61fcb Mon Sep 17 00:00:00 2001 From: Sriram R Date: Wed, 17 Jan 2024 11:56:28 +0530 Subject: [PATCH 66/71] wifi: ath12k: Fix issues in channel list update Currently, the logic used to select the 6 GHz band is incorrect, which may cause 6 GHz supported channels to not be updated properly. This is because the 6 GHz Max frequency supported by the driver is being compared to the Max frequency supported on the board. If in some cases, the 6 GHz Max frequency supported on the board is less than the defined 6 GHz Max frequency, all 6 GHz channels are disabled. To address this, compare the max frequency supported by the board to the defined 6 GHz Minimum frequency by the driver. Similarly, when a dual mac card supports both 6 GHz and 5 GHz radios, if the 5 GHz radio gets enumerated first before 6 GHz, the checks in ath12k_mac_setup_channels_rates() can cause the 5 GHz channels which were enabled earlier to get disabled when the 6 GHz channel list is updated. This is because the Min 6 GHz frequency defined in the driver is 5945 MHz, which should be 5925 MHz since channel 2 is not considered currently, but the firmware can pass 5925 MHz as the minimum. Hence, update the Min frequency supported by the driver to 5925 MHz. In addition, ensure that the channel list update to firmware updates only the channels that the current radio (ar) supports rather than considering the wiphy support. This would be required when multiple pdevs are supported in a wiphy and they support different ranges of frequencies or bands as in single wiphy support. Fixes: d889913205cf ("wifi: ath12k: driver for Qualcomm Wi-Fi 7 devices") Tested-on: QCN9274 hw2.0 PCI WLAN.WBE.1.0.1-00029-QCAHKSWPL_SILICONZ-1 Tested-on: QCN9274 hw2.0 PCI WLAN.WBE.1.1.1-00188-QCAHKSWPL_SILICONZ-1 Tested-on: WCN7850 hw2.0 PCI WLAN.HMT.1.0.c5-00481-QCAHMTSWPL_V1.0_V2.0_SILICONZ-3 Signed-off-by: Sriram R Acked-by: Jeff Johnson Signed-off-by: Kalle Valo Link: https://msgid.link/20240117062628.8260-1-quic_srirrama@quicinc.com --- drivers/net/wireless/ath/ath12k/core.h | 2 +- drivers/net/wireless/ath/ath12k/mac.c | 2 +- drivers/net/wireless/ath/ath12k/reg.c | 4 ++-- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/drivers/net/wireless/ath/ath12k/core.h b/drivers/net/wireless/ath/ath12k/core.h index a56fc74366b4..5c6c1e2eddb6 100644 --- a/drivers/net/wireless/ath/ath12k/core.h +++ b/drivers/net/wireless/ath/ath12k/core.h @@ -425,7 +425,7 @@ struct ath12k_sta { }; #define ATH12K_MIN_5G_FREQ 4150 -#define ATH12K_MIN_6G_FREQ 5945 +#define ATH12K_MIN_6G_FREQ 5925 #define ATH12K_MAX_6G_FREQ 7115 #define ATH12K_NUM_CHANS 100 #define ATH12K_MAX_5G_CHAN 173 diff --git a/drivers/net/wireless/ath/ath12k/mac.c b/drivers/net/wireless/ath/ath12k/mac.c index fe600dbef875..a27480a69b27 100644 --- a/drivers/net/wireless/ath/ath12k/mac.c +++ b/drivers/net/wireless/ath/ath12k/mac.c @@ -7394,7 +7394,7 @@ static int ath12k_mac_setup_channels_rates(struct ath12k *ar, } if (supported_bands & WMI_HOST_WLAN_5G_CAP) { - if (reg_cap->high_5ghz_chan >= ATH12K_MAX_6G_FREQ) { + if (reg_cap->high_5ghz_chan >= ATH12K_MIN_6G_FREQ) { channels = kmemdup(ath12k_6ghz_channels, sizeof(ath12k_6ghz_channels), GFP_KERNEL); if (!channels) { diff --git a/drivers/net/wireless/ath/ath12k/reg.c b/drivers/net/wireless/ath/ath12k/reg.c index a164f15d1e2b..f308e9a6ed55 100644 --- a/drivers/net/wireless/ath/ath12k/reg.c +++ b/drivers/net/wireless/ath/ath12k/reg.c @@ -104,7 +104,7 @@ int ath12k_reg_update_chan_list(struct ath12k *ar) bands = hw->wiphy->bands; for (band = 0; band < NUM_NL80211_BANDS; band++) { - if (!bands[band]) + if (!(ar->mac.sbands[band].channels && bands[band])) continue; for (i = 0; i < bands[band]->n_channels; i++) { @@ -130,7 +130,7 @@ int ath12k_reg_update_chan_list(struct ath12k *ar) ch = arg->channel; for (band = 0; band < NUM_NL80211_BANDS; band++) { - if (!bands[band]) + if (!(ar->mac.sbands[band].channels && bands[band])) continue; for (i = 0; i < bands[band]->n_channels; i++) { From dbd73acb22d85873ecca51fdb33a0e50d11e8021 Mon Sep 17 00:00:00 2001 From: Baochen Qiang Date: Tue, 23 Jan 2024 09:52:01 +0800 Subject: [PATCH 67/71] wifi: ath11k: enable 36 bit mask for stream DMA Currently 32 bit DMA mask is used, telling kernel to get us an DMA address under 4GB when mapping a buffer. This results in a very high CPU overhead in the case where IOMMU is disabled and more than 4GB system memory is installed. The reason is, with more than 4GB memory installed, kernel is likely to allocate a buffer whose physical address is above 4GB. While with IOMMU disabled, kernel has to involve SWIOTLB to map/unmap that buffer, which consumes lots of CPU cycles. We did hit an issue caused by the reason mentioned above: in a system that disables IOMMU and gets 8GB memory installed, a total of 40.5% CPU usage is observed in throughput test. CPU profiling shows nearly 60% of CPU cycles are consumed by SWIOTLB. By enabling 36 bit DMA mask, we can bypass SWIOTLB for any buffer whose physical address is below 64GB. There are two types of DMA mask within struct device, named dma_mask and coherent_dma_mask. Here we only enable 36 bit for dma_mask, because firmware crashes if coherent_dma_mask is also enabled, due to some unknown hardware limitations. This is acceptable because coherent_dma_mask is used for mapping a consistent DMA buffer, which generally does not happen in a hot path. With this change, the total CPU usage mentioned in above issue drops to 18.9%. Tested-on: WCN6855 hw2.1 PCI WLAN.HSP.1.1-03125-QCAHSPSWPL_V1_V2_SILICONZ_LITE-3.6510.23 Tested-on: QCN9074 hw1.0 PCI WLAN.HK.2.7.0.1-01744-QCAHKSWPL_SILICONZ-1 Tested-on: IPQ8074 hw2.0 AHB WLAN.HK.2.7.0.1-01744-QCAHKSWPL_SILICONZ-1 Signed-off-by: Baochen Qiang Acked-by: Jeff Johnson Signed-off-by: Kalle Valo Link: https://msgid.link/20240123015201.28939-1-quic_bqiang@quicinc.com --- drivers/net/wireless/ath/ath11k/mhi.c | 4 ++-- drivers/net/wireless/ath/ath11k/pci.c | 19 +++++++++++++++---- drivers/net/wireless/ath/ath11k/pci.h | 3 ++- 3 files changed, 19 insertions(+), 7 deletions(-) diff --git a/drivers/net/wireless/ath/ath11k/mhi.c b/drivers/net/wireless/ath/ath11k/mhi.c index 6835c14b82cc..e6e69bb91103 100644 --- a/drivers/net/wireless/ath/ath11k/mhi.c +++ b/drivers/net/wireless/ath/ath11k/mhi.c @@ -1,7 +1,7 @@ // SPDX-License-Identifier: BSD-3-Clause-Clear /* * Copyright (c) 2020 The Linux Foundation. All rights reserved. - * Copyright (c) 2021-2023 Qualcomm Innovation Center, Inc. All rights reserved. + * Copyright (c) 2021-2024 Qualcomm Innovation Center, Inc. All rights reserved. */ #include @@ -423,7 +423,7 @@ int ath11k_mhi_register(struct ath11k_pci *ab_pci) goto free_controller; } else { mhi_ctrl->iova_start = 0; - mhi_ctrl->iova_stop = 0xFFFFFFFF; + mhi_ctrl->iova_stop = ab_pci->dma_mask; } mhi_ctrl->rddm_size = RDDM_DUMP_SIZE; diff --git a/drivers/net/wireless/ath/ath11k/pci.c b/drivers/net/wireless/ath/ath11k/pci.c index 09e65c5e55c4..d667d5e06a66 100644 --- a/drivers/net/wireless/ath/ath11k/pci.c +++ b/drivers/net/wireless/ath/ath11k/pci.c @@ -1,7 +1,7 @@ // SPDX-License-Identifier: BSD-3-Clause-Clear /* * Copyright (c) 2019-2020 The Linux Foundation. All rights reserved. - * Copyright (c) 2021-2023 Qualcomm Innovation Center, Inc. All rights reserved. + * Copyright (c) 2021-2024 Qualcomm Innovation Center, Inc. All rights reserved. */ #include @@ -18,7 +18,8 @@ #include "qmi.h" #define ATH11K_PCI_BAR_NUM 0 -#define ATH11K_PCI_DMA_MASK 32 +#define ATH11K_PCI_DMA_MASK 36 +#define ATH11K_PCI_COHERENT_DMA_MASK 32 #define TCSR_SOC_HW_VERSION 0x0224 #define TCSR_SOC_HW_VERSION_MAJOR_MASK GENMASK(11, 8) @@ -526,14 +527,24 @@ static int ath11k_pci_claim(struct ath11k_pci *ab_pci, struct pci_dev *pdev) goto disable_device; } - ret = dma_set_mask_and_coherent(&pdev->dev, - DMA_BIT_MASK(ATH11K_PCI_DMA_MASK)); + ret = dma_set_mask(&pdev->dev, + DMA_BIT_MASK(ATH11K_PCI_DMA_MASK)); if (ret) { ath11k_err(ab, "failed to set pci dma mask to %d: %d\n", ATH11K_PCI_DMA_MASK, ret); goto release_region; } + ab_pci->dma_mask = DMA_BIT_MASK(ATH11K_PCI_DMA_MASK); + + ret = dma_set_coherent_mask(&pdev->dev, + DMA_BIT_MASK(ATH11K_PCI_COHERENT_DMA_MASK)); + if (ret) { + ath11k_err(ab, "failed to set pci coherent dma mask to %d: %d\n", + ATH11K_PCI_COHERENT_DMA_MASK, ret); + goto release_region; + } + pci_set_master(pdev); ab->mem_len = pci_resource_len(pdev, ATH11K_PCI_BAR_NUM); diff --git a/drivers/net/wireless/ath/ath11k/pci.h b/drivers/net/wireless/ath/ath11k/pci.h index e9a01f344ec6..6be73333d90b 100644 --- a/drivers/net/wireless/ath/ath11k/pci.h +++ b/drivers/net/wireless/ath/ath11k/pci.h @@ -1,7 +1,7 @@ /* SPDX-License-Identifier: BSD-3-Clause-Clear */ /* * Copyright (c) 2019-2020 The Linux Foundation. All rights reserved. - * Copyright (c) 2021-2022, Qualcomm Innovation Center, Inc. All rights reserved. + * Copyright (c) 2021-2022,2024 Qualcomm Innovation Center, Inc. All rights reserved. */ #ifndef _ATH11K_PCI_H #define _ATH11K_PCI_H @@ -72,6 +72,7 @@ struct ath11k_pci { /* enum ath11k_pci_flags */ unsigned long flags; u16 link_ctl; + u64 dma_mask; }; static inline struct ath11k_pci *ath11k_pci_priv(struct ath11k_base *ab) From 171203f0c4093dfe7e73ceb6c38033595f329f56 Mon Sep 17 00:00:00 2001 From: Baochen Qiang Date: Tue, 23 Jan 2024 10:56:57 +0800 Subject: [PATCH 68/71] wifi: ath11k: remove invalid peer create logic In ath11k_mac_op_assign_vif_chanctx(), there is a logic to create peer using ar->mac_addr for a STA vdev. This is invalid because a STA vdev should have a peer created using AP's MAC address. Besides, if we run into that logic, it means a peer has already been created earlier, we should not create it again. So remove it. This is found during code review. Tested-on: QCA6390 hw2.0 PCI WLAN.HST.1.0.1-01740-QCAHSTSWPLZ_V2_TO_X86-1 Tested-on: WCN6855 hw2.1 PCI WLAN.HSP.1.1-03125-QCAHSPSWPL_V1_V2_SILICONZ_LITE-3.6510.23 Tested-on: QCN9074 hw1.0 PCI WLAN.HK.2.7.0.1-01744-QCAHKSWPL_SILICONZ-1 Tested-on: IPQ8074 hw2.0 AHB WLAN.HK.2.7.0.1-01744-QCAHKSWPL_SILICONZ-1 Signed-off-by: Baochen Qiang Acked-by: Jeff Johnson Signed-off-by: Kalle Valo Link: https://msgid.link/20240123025700.2929-2-quic_bqiang@quicinc.com --- drivers/net/wireless/ath/ath11k/mac.c | 18 +----------------- 1 file changed, 1 insertion(+), 17 deletions(-) diff --git a/drivers/net/wireless/ath/ath11k/mac.c b/drivers/net/wireless/ath/ath11k/mac.c index bf4a97967177..33ab66afb97f 100644 --- a/drivers/net/wireless/ath/ath11k/mac.c +++ b/drivers/net/wireless/ath/ath11k/mac.c @@ -1,7 +1,7 @@ // SPDX-License-Identifier: BSD-3-Clause-Clear /* * Copyright (c) 2018-2019 The Linux Foundation. All rights reserved. - * Copyright (c) 2021-2023 Qualcomm Innovation Center, Inc. All rights reserved. + * Copyright (c) 2021-2024 Qualcomm Innovation Center, Inc. All rights reserved. */ #include @@ -8108,7 +8108,6 @@ ath11k_mac_op_assign_vif_chanctx(struct ieee80211_hw *hw, struct ath11k_base *ab = ar->ab; struct ath11k_vif *arvif = ath11k_vif_to_arvif(vif); int ret; - struct peer_create_params param; struct cur_regulatory_info *reg_info; enum ieee80211_ap_reg_power power_type; @@ -8151,21 +8150,6 @@ ath11k_mac_op_assign_vif_chanctx(struct ieee80211_hw *hw, goto out; } - if (ab->hw_params.vdev_start_delay && - arvif->vdev_type != WMI_VDEV_TYPE_AP && - arvif->vdev_type != WMI_VDEV_TYPE_MONITOR) { - param.vdev_id = arvif->vdev_id; - param.peer_type = WMI_PEER_TYPE_DEFAULT; - param.peer_addr = ar->mac_addr; - - ret = ath11k_peer_create(ar, arvif, NULL, ¶m); - if (ret) { - ath11k_warn(ab, "failed to create peer after vdev start delay: %d", - ret); - goto out; - } - } - if (arvif->vdev_type == WMI_VDEV_TYPE_MONITOR) { ret = ath11k_mac_monitor_start(ar); if (ret) { From 629642fa8b25b8dfecefc9e2177a44c009858da7 Mon Sep 17 00:00:00 2001 From: Baochen Qiang Date: Tue, 23 Jan 2024 10:56:58 +0800 Subject: [PATCH 69/71] wifi: ath11k: rename ath11k_start_vdev_delay() Rename ath11k_start_vdev_delay() as ath11k_mac_start_vdev_delay() to follow naming convention. Tested-on: QCA6390 hw2.0 PCI WLAN.HST.1.0.1-01740-QCAHSTSWPLZ_V2_TO_X86-1 Tested-on: WCN6855 hw2.1 PCI WLAN.HSP.1.1-03125-QCAHSPSWPL_V1_V2_SILICONZ_LITE-3.6510.23 Tested-on: QCN9074 hw1.0 PCI WLAN.HK.2.7.0.1-01744-QCAHKSWPL_SILICONZ-1 Tested-on: IPQ8074 hw2.0 AHB WLAN.HK.2.7.0.1-01744-QCAHKSWPL_SILICONZ-1 Signed-off-by: Baochen Qiang Acked-by: Jeff Johnson Signed-off-by: Kalle Valo Link: https://msgid.link/20240123025700.2929-3-quic_bqiang@quicinc.com --- drivers/net/wireless/ath/ath11k/mac.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/drivers/net/wireless/ath/ath11k/mac.c b/drivers/net/wireless/ath/ath11k/mac.c index 33ab66afb97f..9d041065f81c 100644 --- a/drivers/net/wireless/ath/ath11k/mac.c +++ b/drivers/net/wireless/ath/ath11k/mac.c @@ -255,8 +255,8 @@ static const u32 ath11k_smps_map[] = { [WLAN_HT_CAP_SM_PS_DISABLED] = WMI_PEER_SMPS_PS_NONE, }; -static int ath11k_start_vdev_delay(struct ieee80211_hw *hw, - struct ieee80211_vif *vif); +static int ath11k_mac_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) { @@ -4987,7 +4987,7 @@ static int ath11k_mac_station_add(struct ath11k *ar, if (ab->hw_params.vdev_start_delay && !arvif->is_started && arvif->vdev_type != WMI_VDEV_TYPE_AP) { - ret = ath11k_start_vdev_delay(ar->hw, vif); + ret = ath11k_mac_start_vdev_delay(ar->hw, vif); if (ret) { ath11k_warn(ab, "failed to delay vdev start: %d\n", ret); goto free_tx_stats; @@ -7581,8 +7581,8 @@ static void ath11k_mac_op_change_chanctx(struct ieee80211_hw *hw, mutex_unlock(&ar->conf_mutex); } -static int ath11k_start_vdev_delay(struct ieee80211_hw *hw, - struct ieee80211_vif *vif) +static int ath11k_mac_start_vdev_delay(struct ieee80211_hw *hw, + struct ieee80211_vif *vif) { struct ath11k *ar = hw->priv; struct ath11k_base *ab = ar->ab; From ce59902e56ea0477ad9bef0067d0e47b6c4d707d Mon Sep 17 00:00:00 2001 From: Baochen Qiang Date: Tue, 23 Jan 2024 10:56:59 +0800 Subject: [PATCH 70/71] wifi: ath11k: avoid forward declaration of ath11k_mac_start_vdev_delay() Currently ath11k_mac_start_vdev_delay() needs a forward declaration because it is defined after where it is called. Avoid this by re-arranging ath11k_mac_station_add() and ath11k_mac_op_sta_state(). No functional changes. Compile tested only. Signed-off-by: Baochen Qiang Acked-by: Jeff Johnson Signed-off-by: Kalle Valo Link: https://msgid.link/20240123025700.2929-4-quic_bqiang@quicinc.com --- drivers/net/wireless/ath/ath11k/mac.c | 459 +++++++++++++------------- 1 file changed, 228 insertions(+), 231 deletions(-) diff --git a/drivers/net/wireless/ath/ath11k/mac.c b/drivers/net/wireless/ath/ath11k/mac.c index 9d041065f81c..324bbb377eac 100644 --- a/drivers/net/wireless/ath/ath11k/mac.c +++ b/drivers/net/wireless/ath/ath11k/mac.c @@ -255,9 +255,6 @@ static const u32 ath11k_smps_map[] = { [WLAN_HT_CAP_SM_PS_DISABLED] = WMI_PEER_SMPS_PS_NONE, }; -static int ath11k_mac_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; @@ -4917,100 +4914,6 @@ static void ath11k_mac_dec_num_stations(struct ath11k_vif *arvif, ar->num_stations--; } -static int ath11k_mac_station_add(struct ath11k *ar, - struct ieee80211_vif *vif, - struct ieee80211_sta *sta) -{ - struct ath11k_base *ab = ar->ab; - struct ath11k_vif *arvif = ath11k_vif_to_arvif(vif); - struct ath11k_sta *arsta = ath11k_sta_to_arsta(sta); - struct peer_create_params peer_param; - int ret; - - lockdep_assert_held(&ar->conf_mutex); - - ret = ath11k_mac_inc_num_stations(arvif, sta); - if (ret) { - ath11k_warn(ab, "refusing to associate station: too many connected already (%d)\n", - ar->max_num_stations); - goto exit; - } - - arsta->rx_stats = kzalloc(sizeof(*arsta->rx_stats), GFP_KERNEL); - if (!arsta->rx_stats) { - ret = -ENOMEM; - goto dec_num_station; - } - - peer_param.vdev_id = arvif->vdev_id; - peer_param.peer_addr = sta->addr; - peer_param.peer_type = WMI_PEER_TYPE_DEFAULT; - - ret = ath11k_peer_create(ar, arvif, sta, &peer_param); - if (ret) { - ath11k_warn(ab, "Failed to add peer: %pM for VDEV: %d\n", - sta->addr, arvif->vdev_id); - goto free_rx_stats; - } - - ath11k_dbg(ab, ATH11K_DBG_MAC, "Added peer: %pM for VDEV: %d\n", - sta->addr, arvif->vdev_id); - - if (ath11k_debugfs_is_extd_tx_stats_enabled(ar)) { - arsta->tx_stats = kzalloc(sizeof(*arsta->tx_stats), GFP_KERNEL); - if (!arsta->tx_stats) { - ret = -ENOMEM; - goto free_peer; - } - } - - 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 set mesh STA %pM 4addr capability: %d\n", - sta->addr, ret); - goto free_tx_stats; - } - } - - ret = ath11k_dp_peer_setup(ar, arvif->vdev_id, sta->addr); - if (ret) { - ath11k_warn(ab, "failed to setup dp for peer %pM on vdev %i (%d)\n", - sta->addr, arvif->vdev_id, ret); - goto free_tx_stats; - } - - if (ab->hw_params.vdev_start_delay && - !arvif->is_started && - arvif->vdev_type != WMI_VDEV_TYPE_AP) { - ret = ath11k_mac_start_vdev_delay(ar->hw, vif); - if (ret) { - ath11k_warn(ab, "failed to delay vdev start: %d\n", ret); - goto free_tx_stats; - } - } - - ewma_avg_rssi_init(&arsta->avg_rssi); - return 0; - -free_tx_stats: - kfree(arsta->tx_stats); - arsta->tx_stats = NULL; -free_peer: - ath11k_peer_delete(ar, arvif->vdev_id, sta->addr); -free_rx_stats: - kfree(arsta->rx_stats); - arsta->rx_stats = NULL; -dec_num_station: - ath11k_mac_dec_num_stations(arvif, sta); -exit: - return ret; -} - static u32 ath11k_mac_ieee80211_sta_bw_to_wmi(struct ath11k *ar, struct ieee80211_sta *sta) { @@ -5039,140 +4942,6 @@ static u32 ath11k_mac_ieee80211_sta_bw_to_wmi(struct ath11k *ar, return bw; } -static int ath11k_mac_op_sta_state(struct ieee80211_hw *hw, - struct ieee80211_vif *vif, - struct ieee80211_sta *sta, - enum ieee80211_sta_state old_state, - enum ieee80211_sta_state new_state) -{ - struct ath11k *ar = hw->priv; - struct ath11k_vif *arvif = ath11k_vif_to_arvif(vif); - struct ath11k_sta *arsta = ath11k_sta_to_arsta(sta); - struct ath11k_peer *peer; - int ret = 0; - - /* cancel must be done outside the mutex to avoid deadlock */ - if ((old_state == IEEE80211_STA_NONE && - new_state == IEEE80211_STA_NOTEXIST)) { - cancel_work_sync(&arsta->update_wk); - cancel_work_sync(&arsta->set_4addr_wk); - } - - mutex_lock(&ar->conf_mutex); - - if (old_state == IEEE80211_STA_NOTEXIST && - new_state == IEEE80211_STA_NONE) { - memset(arsta, 0, sizeof(*arsta)); - arsta->arvif = arvif; - arsta->peer_ps_state = WMI_PEER_PS_STATE_DISABLED; - 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) - ath11k_warn(ar->ab, "Failed to add station: %pM for VDEV: %d\n", - sta->addr, arvif->vdev_id); - } else if ((old_state == IEEE80211_STA_NONE && - new_state == IEEE80211_STA_NOTEXIST)) { - bool skip_peer_delete = ar->ab->hw_params.vdev_start_delay && - vif->type == NL80211_IFTYPE_STATION; - - ath11k_dp_peer_cleanup(ar, arvif->vdev_id, sta->addr); - - 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); - mutex_lock(&ar->ab->tbl_mtx_lock); - spin_lock_bh(&ar->ab->base_lock); - peer = ath11k_peer_find(ar->ab, arvif->vdev_id, sta->addr); - 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); - ath11k_peer_rhash_delete(ar->ab, peer); - peer->sta = NULL; - list_del(&peer->list); - kfree(peer); - ar->num_peers--; - } - spin_unlock_bh(&ar->ab->base_lock); - mutex_unlock(&ar->ab->tbl_mtx_lock); - - kfree(arsta->tx_stats); - arsta->tx_stats = NULL; - - kfree(arsta->rx_stats); - arsta->rx_stats = NULL; - } else if (old_state == IEEE80211_STA_AUTH && - new_state == IEEE80211_STA_ASSOC && - (vif->type == NL80211_IFTYPE_AP || - vif->type == NL80211_IFTYPE_MESH_POINT || - vif->type == NL80211_IFTYPE_ADHOC)) { - ret = ath11k_station_assoc(ar, vif, sta, false); - if (ret) - ath11k_warn(ar->ab, "Failed to associate station: %pM\n", - sta->addr); - - spin_lock_bh(&ar->data_lock); - /* Set arsta bw and prev bw */ - arsta->bw = ath11k_mac_ieee80211_sta_bw_to_wmi(ar, sta); - arsta->bw_prev = arsta->bw; - spin_unlock_bh(&ar->data_lock); - } 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 || - vif->type == NL80211_IFTYPE_ADHOC)) { - ret = ath11k_station_disassoc(ar, vif, sta); - if (ret) - ath11k_warn(ar->ab, "Failed to disassociate station: %pM\n", - sta->addr); - } - - mutex_unlock(&ar->conf_mutex); - return ret; -} - static int ath11k_mac_op_sta_set_txpwr(struct ieee80211_hw *hw, struct ieee80211_vif *vif, struct ieee80211_sta *sta) @@ -9610,6 +9379,234 @@ static int ath11k_mac_op_get_txpower(struct ieee80211_hw *hw, return 0; } +static int ath11k_mac_station_add(struct ath11k *ar, + struct ieee80211_vif *vif, + struct ieee80211_sta *sta) +{ + struct ath11k_base *ab = ar->ab; + struct ath11k_vif *arvif = ath11k_vif_to_arvif(vif); + struct ath11k_sta *arsta = ath11k_sta_to_arsta(sta); + struct peer_create_params peer_param; + int ret; + + lockdep_assert_held(&ar->conf_mutex); + + ret = ath11k_mac_inc_num_stations(arvif, sta); + if (ret) { + ath11k_warn(ab, "refusing to associate station: too many connected already (%d)\n", + ar->max_num_stations); + goto exit; + } + + arsta->rx_stats = kzalloc(sizeof(*arsta->rx_stats), GFP_KERNEL); + if (!arsta->rx_stats) { + ret = -ENOMEM; + goto dec_num_station; + } + + peer_param.vdev_id = arvif->vdev_id; + peer_param.peer_addr = sta->addr; + peer_param.peer_type = WMI_PEER_TYPE_DEFAULT; + + ret = ath11k_peer_create(ar, arvif, sta, &peer_param); + if (ret) { + ath11k_warn(ab, "Failed to add peer: %pM for VDEV: %d\n", + sta->addr, arvif->vdev_id); + goto free_rx_stats; + } + + ath11k_dbg(ab, ATH11K_DBG_MAC, "Added peer: %pM for VDEV: %d\n", + sta->addr, arvif->vdev_id); + + if (ath11k_debugfs_is_extd_tx_stats_enabled(ar)) { + arsta->tx_stats = kzalloc(sizeof(*arsta->tx_stats), GFP_KERNEL); + if (!arsta->tx_stats) { + ret = -ENOMEM; + goto free_peer; + } + } + + 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 set mesh STA %pM 4addr capability: %d\n", + sta->addr, ret); + goto free_tx_stats; + } + } + + ret = ath11k_dp_peer_setup(ar, arvif->vdev_id, sta->addr); + if (ret) { + ath11k_warn(ab, "failed to setup dp for peer %pM on vdev %i (%d)\n", + sta->addr, arvif->vdev_id, ret); + goto free_tx_stats; + } + + if (ab->hw_params.vdev_start_delay && + !arvif->is_started && + arvif->vdev_type != WMI_VDEV_TYPE_AP) { + ret = ath11k_mac_start_vdev_delay(ar->hw, vif); + if (ret) { + ath11k_warn(ab, "failed to delay vdev start: %d\n", ret); + goto free_tx_stats; + } + } + + ewma_avg_rssi_init(&arsta->avg_rssi); + return 0; + +free_tx_stats: + kfree(arsta->tx_stats); + arsta->tx_stats = NULL; +free_peer: + ath11k_peer_delete(ar, arvif->vdev_id, sta->addr); +free_rx_stats: + kfree(arsta->rx_stats); + arsta->rx_stats = NULL; +dec_num_station: + ath11k_mac_dec_num_stations(arvif, sta); +exit: + return ret; +} + +static int ath11k_mac_op_sta_state(struct ieee80211_hw *hw, + struct ieee80211_vif *vif, + struct ieee80211_sta *sta, + enum ieee80211_sta_state old_state, + enum ieee80211_sta_state new_state) +{ + struct ath11k *ar = hw->priv; + struct ath11k_vif *arvif = ath11k_vif_to_arvif(vif); + struct ath11k_sta *arsta = ath11k_sta_to_arsta(sta); + struct ath11k_peer *peer; + int ret = 0; + + /* cancel must be done outside the mutex to avoid deadlock */ + if ((old_state == IEEE80211_STA_NONE && + new_state == IEEE80211_STA_NOTEXIST)) { + cancel_work_sync(&arsta->update_wk); + cancel_work_sync(&arsta->set_4addr_wk); + } + + mutex_lock(&ar->conf_mutex); + + if (old_state == IEEE80211_STA_NOTEXIST && + new_state == IEEE80211_STA_NONE) { + memset(arsta, 0, sizeof(*arsta)); + arsta->arvif = arvif; + arsta->peer_ps_state = WMI_PEER_PS_STATE_DISABLED; + 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) + ath11k_warn(ar->ab, "Failed to add station: %pM for VDEV: %d\n", + sta->addr, arvif->vdev_id); + } else if ((old_state == IEEE80211_STA_NONE && + new_state == IEEE80211_STA_NOTEXIST)) { + bool skip_peer_delete = ar->ab->hw_params.vdev_start_delay && + vif->type == NL80211_IFTYPE_STATION; + + ath11k_dp_peer_cleanup(ar, arvif->vdev_id, sta->addr); + + 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); + mutex_lock(&ar->ab->tbl_mtx_lock); + spin_lock_bh(&ar->ab->base_lock); + peer = ath11k_peer_find(ar->ab, arvif->vdev_id, sta->addr); + 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); + ath11k_peer_rhash_delete(ar->ab, peer); + peer->sta = NULL; + list_del(&peer->list); + kfree(peer); + ar->num_peers--; + } + spin_unlock_bh(&ar->ab->base_lock); + mutex_unlock(&ar->ab->tbl_mtx_lock); + + kfree(arsta->tx_stats); + arsta->tx_stats = NULL; + + kfree(arsta->rx_stats); + arsta->rx_stats = NULL; + } else if (old_state == IEEE80211_STA_AUTH && + new_state == IEEE80211_STA_ASSOC && + (vif->type == NL80211_IFTYPE_AP || + vif->type == NL80211_IFTYPE_MESH_POINT || + vif->type == NL80211_IFTYPE_ADHOC)) { + ret = ath11k_station_assoc(ar, vif, sta, false); + if (ret) + ath11k_warn(ar->ab, "Failed to associate station: %pM\n", + sta->addr); + + spin_lock_bh(&ar->data_lock); + /* Set arsta bw and prev bw */ + arsta->bw = ath11k_mac_ieee80211_sta_bw_to_wmi(ar, sta); + arsta->bw_prev = arsta->bw; + spin_unlock_bh(&ar->data_lock); + } 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 || + vif->type == NL80211_IFTYPE_ADHOC)) { + ret = ath11k_station_disassoc(ar, vif, sta); + if (ret) + ath11k_warn(ar->ab, "Failed to disassociate station: %pM\n", + sta->addr); + } + + mutex_unlock(&ar->conf_mutex); + return ret; +} + static const struct ieee80211_ops ath11k_ops = { .tx = ath11k_mac_op_tx, .wake_tx_queue = ieee80211_handle_wake_tx_queue, From 9d5f28c1366f48efae7b1df0f622285519e74dce Mon Sep 17 00:00:00 2001 From: Baochen Qiang Date: Tue, 23 Jan 2024 10:57:00 +0800 Subject: [PATCH 71/71] wifi: ath11k: fix connection failure due to unexpected peer delete Currently ath11k_mac_op_unassign_vif_chanctx() deletes peer but ath11k_mac_op_assign_vif_chanctx() doesn't create it. This results in connection failure if MAC80211 calls drv_unassign_vif_chanctx() and drv_assign_vif_chanctx() during AUTH and ASSOC, see below log: [ 102.372431] wlan0: authenticated [ 102.372585] ath11k_pci 0000:01:00.0: wlan0: disabling HT/VHT/HE as WMM/QoS is not supported by the AP [ 102.372593] ath11k_pci 0000:01:00.0: mac chanctx unassign ptr ffff895084638598 vdev_id 0 [ 102.372808] ath11k_pci 0000:01:00.0: WMI vdev stop id 0x0 [ 102.383114] ath11k_pci 0000:01:00.0: vdev stopped for vdev id 0 [ 102.384689] ath11k_pci 0000:01:00.0: WMI peer delete vdev_id 0 peer_addr 20:e5:2a:21:c4:51 [ 102.396676] ath11k_pci 0000:01:00.0: htt peer unmap vdev 0 peer 20:e5:2a:21:c4:51 id 3 [ 102.396711] ath11k_pci 0000:01:00.0: peer delete resp for vdev id 0 addr 20:e5:2a:21:c4:51 [ 102.396722] ath11k_pci 0000:01:00.0: mac removed peer 20:e5:2a:21:c4:51 vdev 0 after vdev stop [ 102.396780] ath11k_pci 0000:01:00.0: mac chanctx assign ptr ffff895084639c18 vdev_id 0 [ 102.400628] wlan0: associate with 20:e5:2a:21:c4:51 (try 1/3) [ 102.508864] wlan0: associate with 20:e5:2a:21:c4:51 (try 2/3) [ 102.612815] wlan0: associate with 20:e5:2a:21:c4:51 (try 3/3) [ 102.720846] wlan0: association with 20:e5:2a:21:c4:51 timed out The peer delete logic in ath11k_mac_op_unassign_vif_chanctx() is introduced by commit b4a0f54156ac ("ath11k: move peer delete after vdev stop of station for QCA6390 and WCN6855") to fix firmware crash issue caused by unexpected vdev stop/peer delete sequence. Actually for a STA interface peer should be deleted in ath11k_mac_op_sta_state() when STA's state changes from IEEE80211_STA_NONE to IEEE80211_STA_NOTEXIST, which also coincides with current peer creation design that peer is created during IEEE80211_STA_NOTEXIST -> IEEE80211_STA_NONE transition. So move peer delete back to ath11k_mac_op_sta_state(), also stop vdev before deleting peer to fix the firmware crash issue mentioned there. In this way the connection failure mentioned here is also fixed. Tested-on: QCA6390 hw2.0 PCI WLAN.HST.1.0.1-01740-QCAHSTSWPLZ_V2_TO_X86-1 Tested-on: WCN6855 hw2.1 PCI WLAN.HSP.1.1-03125-QCAHSPSWPL_V1_V2_SILICONZ_LITE-3.6510.23 Tested-on: QCN9074 hw1.0 PCI WLAN.HK.2.7.0.1-01744-QCAHKSWPL_SILICONZ-1 Tested-on: IPQ8074 hw2.0 AHB WLAN.HK.2.7.0.1-01744-QCAHKSWPL_SILICONZ-1 Fixes: b4a0f54156ac ("ath11k: move peer delete after vdev stop of station for QCA6390 and WCN6855") Signed-off-by: Baochen Qiang Acked-by: Jeff Johnson Signed-off-by: Kalle Valo Link: https://msgid.link/20240123025700.2929-5-quic_bqiang@quicinc.com --- drivers/net/wireless/ath/ath11k/mac.c | 139 ++++++++++++++++---------- 1 file changed, 85 insertions(+), 54 deletions(-) diff --git a/drivers/net/wireless/ath/ath11k/mac.c b/drivers/net/wireless/ath/ath11k/mac.c index 324bbb377eac..4a6ab45e9386 100644 --- a/drivers/net/wireless/ath/ath11k/mac.c +++ b/drivers/net/wireless/ath/ath11k/mac.c @@ -7397,6 +7397,30 @@ static int ath11k_mac_start_vdev_delay(struct ieee80211_hw *hw, return 0; } +static int ath11k_mac_stop_vdev_early(struct ieee80211_hw *hw, + struct ieee80211_vif *vif) +{ + struct ath11k *ar = hw->priv; + struct ath11k_base *ab = ar->ab; + struct ath11k_vif *arvif = ath11k_vif_to_arvif(vif); + int ret; + + if (WARN_ON(!arvif->is_started)) + return -EBUSY; + + ret = ath11k_mac_vdev_stop(arvif); + if (ret) { + ath11k_warn(ab, "failed to stop vdev %i: %d\n", + arvif->vdev_id, ret); + return ret; + } + + arvif->is_started = false; + + /* TODO: Setup ps and cts/rts protection */ + return 0; +} + static u8 ath11k_mac_get_tpe_count(u8 txpwr_intrprt, u8 txpwr_cnt) { switch (txpwr_intrprt) { @@ -7931,15 +7955,17 @@ ath11k_mac_op_assign_vif_chanctx(struct ieee80211_hw *hw, goto out; } - 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, - ctx->def.chan->center_freq, ret); - goto out; - } + if (!arvif->is_started) { + 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, + ctx->def.chan->center_freq, ret); + goto out; + } - arvif->is_started = true; + arvif->is_started = true; + } if (arvif->vdev_type != WMI_VDEV_TYPE_MONITOR && test_bit(ATH11K_FLAG_MONITOR_VDEV_CREATED, &ar->monitor_flags)) { @@ -7979,8 +8005,6 @@ ath11k_mac_op_unassign_vif_chanctx(struct ieee80211_hw *hw, "chanctx unassign ptr %p vdev_id %i\n", ctx, arvif->vdev_id); - WARN_ON(!arvif->is_started); - if (ab->hw_params.vdev_start_delay && arvif->vdev_type == WMI_VDEV_TYPE_MONITOR) { spin_lock_bh(&ab->base_lock); @@ -8004,24 +8028,13 @@ ath11k_mac_op_unassign_vif_chanctx(struct ieee80211_hw *hw, return; } - ret = ath11k_mac_vdev_stop(arvif); - if (ret) - ath11k_warn(ab, "failed to stop vdev %i: %d\n", - arvif->vdev_id, ret); - - 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 (arvif->is_started) { + ret = ath11k_mac_vdev_stop(arvif); 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, - "removed peer %pM vdev %d after vdev stop\n", - arvif->bssid, arvif->vdev_id); + ath11k_warn(ab, "failed to stop vdev %i: %d\n", + arvif->vdev_id, ret); + + arvif->is_started = false; } if (ab->hw_params.vdev_start_delay && @@ -9473,6 +9486,46 @@ static int ath11k_mac_station_add(struct ath11k *ar, return ret; } +static int ath11k_mac_station_remove(struct ath11k *ar, + struct ieee80211_vif *vif, + struct ieee80211_sta *sta) +{ + struct ath11k_base *ab = ar->ab; + struct ath11k_vif *arvif = ath11k_vif_to_arvif(vif); + struct ath11k_sta *arsta = ath11k_sta_to_arsta(sta); + int ret; + + if (ab->hw_params.vdev_start_delay && + arvif->is_started && + arvif->vdev_type != WMI_VDEV_TYPE_AP) { + ret = ath11k_mac_stop_vdev_early(ar->hw, vif); + if (ret) { + ath11k_warn(ab, "failed to do early vdev stop: %d\n", ret); + return ret; + } + } + + ath11k_dp_peer_cleanup(ar, arvif->vdev_id, sta->addr); + + ret = ath11k_peer_delete(ar, arvif->vdev_id, sta->addr); + if (ret) + ath11k_warn(ab, "Failed to delete peer: %pM for VDEV: %d\n", + sta->addr, arvif->vdev_id); + else + ath11k_dbg(ab, ATH11K_DBG_MAC, "Removed peer: %pM for VDEV: %d\n", + sta->addr, arvif->vdev_id); + + ath11k_mac_dec_num_stations(arvif, sta); + + kfree(arsta->tx_stats); + arsta->tx_stats = NULL; + + kfree(arsta->rx_stats); + arsta->rx_stats = NULL; + + return ret; +} + static int ath11k_mac_op_sta_state(struct ieee80211_hw *hw, struct ieee80211_vif *vif, struct ieee80211_sta *sta, @@ -9508,31 +9561,15 @@ static int ath11k_mac_op_sta_state(struct ieee80211_hw *hw, sta->addr, arvif->vdev_id); } else if ((old_state == IEEE80211_STA_NONE && new_state == IEEE80211_STA_NOTEXIST)) { - bool skip_peer_delete = ar->ab->hw_params.vdev_start_delay && - vif->type == NL80211_IFTYPE_STATION; + ret = ath11k_mac_station_remove(ar, vif, sta); + if (ret) + ath11k_warn(ar->ab, "Failed to remove station: %pM for VDEV: %d\n", + sta->addr, arvif->vdev_id); - ath11k_dp_peer_cleanup(ar, arvif->vdev_id, sta->addr); - - 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); mutex_lock(&ar->ab->tbl_mtx_lock); spin_lock_bh(&ar->ab->base_lock); peer = ath11k_peer_find(ar->ab, arvif->vdev_id, sta->addr); - if (skip_peer_delete && peer) { - peer->sta = NULL; - } else if (peer && peer->sta == sta) { + 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); ath11k_peer_rhash_delete(ar->ab, peer); @@ -9543,12 +9580,6 @@ static int ath11k_mac_op_sta_state(struct ieee80211_hw *hw, } spin_unlock_bh(&ar->ab->base_lock); mutex_unlock(&ar->ab->tbl_mtx_lock); - - kfree(arsta->tx_stats); - arsta->tx_stats = NULL; - - kfree(arsta->rx_stats); - arsta->rx_stats = NULL; } else if (old_state == IEEE80211_STA_AUTH && new_state == IEEE80211_STA_ASSOC && (vif->type == NL80211_IFTYPE_AP ||