From ad25ee36f00172f7d53242dc77c69fff7ced0755 Mon Sep 17 00:00:00 2001 From: Xingyuan Mo Date: Sun, 17 Dec 2023 13:29:01 +0200 Subject: 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(+) (limited to 'drivers/net') 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; -- cgit v1.2.3 From f5e6c0c4b0877e0ec0221df6c0041c0f39b6ce0f Mon Sep 17 00:00:00 2001 From: Dmitry Antipov Date: Sun, 17 Dec 2023 13:29:02 +0200 Subject: 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(-) (limited to 'drivers/net') 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 @@ exit: 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); -- cgit v1.2.3 From 504130491026be9cf19f9de562172d340a06a2bb Mon Sep 17 00:00:00 2001 From: Wenli Looi Date: Sun, 17 Dec 2023 13:29:02 +0200 Subject: 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(-) (limited to 'drivers/net') 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) -- cgit v1.2.3 From 27ce06d018cec6a5042069fb21b000753dd147d2 Mon Sep 17 00:00:00 2001 From: Uwe Kleine-König Date: Sun, 17 Dec 2023 13:29:03 +0200 Subject: 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(-) (limited to 'drivers/net') 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", }, -- cgit v1.2.3 From d6b27eb997ef9a2aa51633b3111bc4a04748e6d3 Mon Sep 17 00:00:00 2001 From: Dmitry Antipov Date: Sun, 17 Dec 2023 13:29:03 +0200 Subject: 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(-) (limited to 'drivers/net') 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; -- cgit v1.2.3 From d2eb318f4b6be1176e87ac3f9f8cc976be1c014b Mon Sep 17 00:00:00 2001 From: Jeff Johnson Date: Sun, 17 Dec 2023 13:29:03 +0200 Subject: 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(-) (limited to 'drivers/net') 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 { -- cgit v1.2.3 From 72ca7c4073ac126be1c2341644838ef5f146b36b Mon Sep 17 00:00:00 2001 From: Jeff Johnson Date: Sun, 17 Dec 2023 13:29:03 +0200 Subject: 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(-) (limited to 'drivers/net') 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 { -- cgit v1.2.3 From 26eb704a46f89d50a58ccb22b317b73ee85fa233 Mon Sep 17 00:00:00 2001 From: Jeff Johnson Date: Sun, 17 Dec 2023 13:29:03 +0200 Subject: 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(-) (limited to 'drivers/net') 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 { -- cgit v1.2.3 From b0c0794b05ec07a150bd39be3d43854a9dd93cad Mon Sep 17 00:00:00 2001 From: Jeff Johnson Date: Sun, 17 Dec 2023 13:29:03 +0200 Subject: 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(-) (limited to 'drivers/net') 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, -- cgit v1.2.3 From cb188e862c1ce195ce8beaac10b554c33847f4c8 Mon Sep 17 00:00:00 2001 From: Jeff Johnson Date: Sun, 17 Dec 2023 13:29:03 +0200 Subject: 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(-) (limited to 'drivers/net') 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 { -- cgit v1.2.3 From 6b9923f1f6d1b57a2ae932540a6273a0face54fe Mon Sep 17 00:00:00 2001 From: Jeff Johnson Date: Sun, 17 Dec 2023 13:29:03 +0200 Subject: 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(-) (limited to 'drivers/net') 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); -- cgit v1.2.3 From f4c2a9d62213cf7004db5c74ce12d26d63a23629 Mon Sep 17 00:00:00 2001 From: Wen Gong Date: Sun, 17 Dec 2023 13:29:03 +0200 Subject: 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(-) (limited to 'drivers/net') 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; -- cgit v1.2.3 From 7173972a2eb1107ae3dc076f1cd27abce132e027 Mon Sep 17 00:00:00 2001 From: Wen Gong Date: Sun, 17 Dec 2023 13:29:04 +0200 Subject: 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(-) (limited to 'drivers/net') 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; } -- cgit v1.2.3 From 97474e5f54243be13d72cbda50624f0114213c7d Mon Sep 17 00:00:00 2001 From: Wen Gong Date: Sun, 17 Dec 2023 13:29:04 +0200 Subject: 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(-) (limited to 'drivers/net') 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 { -- cgit v1.2.3 From 511207452221a94242664be47c4ceb63d5c6b293 Mon Sep 17 00:00:00 2001 From: Wen Gong Date: Sun, 17 Dec 2023 13:29:04 +0200 Subject: 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(-) (limited to 'drivers/net') 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 @@ out: 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 @@ success: 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; -- cgit v1.2.3 From 52f8c45fa36df0754b4562b7b535be8475304ebe Mon Sep 17 00:00:00 2001 From: Baochen Qiang Date: Sun, 17 Dec 2023 13:29:04 +0200 Subject: 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(-) (limited to 'drivers/net') 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 @@ success: 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", -- cgit v1.2.3 From e7ab40b733094dfc50dad58bbce81f544af1d8cc Mon Sep 17 00:00:00 2001 From: Jeff Johnson Date: Sun, 17 Dec 2023 09:26:46 -0800 Subject: 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(-) (limited to 'drivers/net') 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, -- cgit v1.2.3 From aaf244141ed7195a9a56e03c2367f4a9d0b727a8 Mon Sep 17 00:00:00 2001 From: Zhenghao Gu Date: Wed, 20 Dec 2023 20:33:08 +0200 Subject: 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(-) (limited to 'drivers/net') 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); -- cgit v1.2.3 From fba97a777dcb90896ab1dc32e796d85bb7bbcd69 Mon Sep 17 00:00:00 2001 From: Dmitry Antipov Date: Tue, 19 Dec 2023 12:10:18 +0300 Subject: 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(-) (limited to 'drivers/net') 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 @@ exit: 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); -- cgit v1.2.3 From e3d373ec4f02bf41379d91707e3e3f2a46464cd7 Mon Sep 17 00:00:00 2001 From: Wen Gong Date: Thu, 11 Jan 2024 15:56:57 +0200 Subject: 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(-) (limited to 'drivers/net') 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; -- cgit v1.2.3 From 7004bdceef605e5c1c5ab4aaf282002ad7523ddd Mon Sep 17 00:00:00 2001 From: Wen Gong Date: Thu, 11 Jan 2024 15:56:57 +0200 Subject: 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(-) (limited to 'drivers/net') 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 @@ ret: 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"); - 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); + ath11k_warn(ab, "failed to extract regulatory info\n"); 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; - } - - /* 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)) + 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; - - /* 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; + kfree(reg_info); + 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); 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, -- cgit v1.2.3 From cf2df0080bd59cb97a1519ddefaf59788febdaa5 Mon Sep 17 00:00:00 2001 From: Baochen Qiang Date: Thu, 11 Jan 2024 15:56:57 +0200 Subject: 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(-) (limited to 'drivers/net') 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; -- cgit v1.2.3 From 17144d32e90708cd5532055f3d9894ced9ac45a2 Mon Sep 17 00:00:00 2001 From: Wen Gong Date: Thu, 11 Jan 2024 15:56:57 +0200 Subject: 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(+) (limited to 'drivers/net') 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 -- cgit v1.2.3 From 1329beb56297021042788223e666f6ccd2e11a0a Mon Sep 17 00:00:00 2001 From: Wen Gong Date: Thu, 11 Jan 2024 15:56:58 +0200 Subject: 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(+) (limited to 'drivers/net') 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 && -- cgit v1.2.3 From 28f64d368b21c551d5faf33687e7228531256d10 Mon Sep 17 00:00:00 2001 From: Wen Gong Date: Thu, 11 Jan 2024 15:56:58 +0200 Subject: 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(-) (limited to 'drivers/net') 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. -- cgit v1.2.3 From 6f4e235be6550f67791616d88682fb99f4e670e4 Mon Sep 17 00:00:00 2001 From: Wen Gong Date: Thu, 11 Jan 2024 15:56:58 +0200 Subject: 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(+) (limited to 'drivers/net') 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 */ -- cgit v1.2.3 From 46f20de2c4f8faadea12679a3edb2082f35dcf1e Mon Sep 17 00:00:00 2001 From: Wen Gong Date: Thu, 11 Jan 2024 15:56:58 +0200 Subject: 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(-) (limited to 'drivers/net') 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 */ -- cgit v1.2.3 From 92425f788feede9bf152ecf3fb7a264942ee7719 Mon Sep 17 00:00:00 2001 From: Wen Gong Date: Thu, 11 Jan 2024 15:56:58 +0200 Subject: 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(-) (limited to 'drivers/net') 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 -- cgit v1.2.3 From f8a573bd5f3b1c272c431831add259deabfd9948 Mon Sep 17 00:00:00 2001 From: Wen Gong Date: Thu, 11 Jan 2024 15:56:58 +0200 Subject: 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(+) (limited to 'drivers/net') 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, -- cgit v1.2.3 From ed0a61dcb2d3936cf15dfc04341c4d0fc297919f Mon Sep 17 00:00:00 2001 From: Wen Gong Date: Thu, 11 Jan 2024 15:56:59 +0200 Subject: 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(+) (limited to 'drivers/net') 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 -- cgit v1.2.3 From 74ef2d05ede63fd6416aa635aa8972dff901325f Mon Sep 17 00:00:00 2001 From: Wen Gong Date: Thu, 11 Jan 2024 15:56:59 +0200 Subject: 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(-) (limited to 'drivers/net') 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); } -- cgit v1.2.3 From 59cf57ab3deea979ffc0a6f7c22f4331e59d32f0 Mon Sep 17 00:00:00 2001 From: Jeff Johnson Date: Thu, 11 Jan 2024 10:05:30 -0800 Subject: 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(-) (limited to 'drivers/net') 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; -- cgit v1.2.3 From 2e82b5f09a97f1b98b885470c81c1248bec103af Mon Sep 17 00:00:00 2001 From: Jeff Johnson Date: Thu, 11 Jan 2024 10:05:31 -0800 Subject: 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(+) (limited to 'drivers/net') 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; -- cgit v1.2.3 From 6d2b0a066941c5d9c56c79d95c91dcec2fd7a7fa Mon Sep 17 00:00:00 2001 From: Jeff Johnson Date: Thu, 11 Jan 2024 10:05:32 -0800 Subject: 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(-) (limited to 'drivers/net') 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 @@ resp_out: 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 @@ out: 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 @@ out: 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)); -- cgit v1.2.3 From eaf9f17b861b665a0bc8dff120ae3c9028642e6d Mon Sep 17 00:00:00 2001 From: Karthikeyan Periyasamy Date: Sun, 14 Jan 2024 17:02:38 +0200 Subject: 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(-) (limited to 'drivers/net') 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: -- cgit v1.2.3 From 8a742a79f90e3d3f0378b030110eccac8d28b655 Mon Sep 17 00:00:00 2001 From: Karthikeyan Periyasamy Date: Sun, 14 Jan 2024 17:02:38 +0200 Subject: 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 | 126 ++++++++++++++++++++-------------- 1 file changed, 76 insertions(+), 50 deletions(-) (limited to 'drivers/net') 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,7 +7607,64 @@ err_cleanup: return ret; } -int ath12k_mac_allocate(struct ath12k_base *ab) +static void ath12k_mac_setup(struct ath12k *ar) +{ + struct ath12k_base *ab = ar->ab; + struct ath12k_pdev *pdev = ar->pdev; + u8 pdev_idx = ar->pdev_idx; + + ar->lmac_id = ath12k_hw_get_mac_from_pdev_id(ab->hw_params, pdev_idx); + + 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->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); + + 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); +} + +static void ath12k_mac_hw_destroy(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; + + ieee80211_free_hw(ar->hw); + pdev->ar = NULL; + } +} + +static int ath12k_mac_hw_allocate(struct ath12k_base *ab) { struct ieee80211_hw *hw; struct ath12k *ar; @@ -7615,9 +7672,6 @@ int ath12k_mac_allocate(struct ath12k_base *ab) int ret; int i; - if (test_bit(ATH12K_FLAG_REGISTERED, &ab->dev_flags)) - return 0; - for (i = 0; i < ab->num_radios; i++) { pdev = &ab->pdevs[i]; hw = ieee80211_alloc_hw(sizeof(struct ath12k), &ath12k_ops); @@ -7632,64 +7686,36 @@ int ath12k_mac_allocate(struct ath12k_base *ab) 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->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); - - 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); - 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); + ath12k_mac_setup(ar); + } return 0; err_free_mac: - ath12k_mac_destroy(ab); + ath12k_mac_hw_destroy(ab); return ret; } void ath12k_mac_destroy(struct ath12k_base *ab) { - struct ath12k *ar; - struct ath12k_pdev *pdev; - int i; + ath12k_mac_hw_destroy(ab); +} - for (i = 0; i < ab->num_radios; i++) { - pdev = &ab->pdevs[i]; - ar = pdev->ar; - if (!ar) - continue; +int ath12k_mac_allocate(struct ath12k_base *ab) +{ + int ret; - ieee80211_free_hw(ar->hw); - pdev->ar = NULL; - } + 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; } -- cgit v1.2.3 From d2b7a6e5fa1c92deabe77aa57ef16f599f3b4247 Mon Sep 17 00:00:00 2001 From: Karthikeyan Periyasamy Date: Sun, 14 Jan 2024 17:02:39 +0200 Subject: 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(-) (limited to 'drivers/net') 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; -- cgit v1.2.3 From d786c9f5fe3472ac102160c113a7bba8ec79a6c6 Mon Sep 17 00:00:00 2001 From: Karthikeyan Periyasamy Date: Sun, 14 Jan 2024 17:02:39 +0200 Subject: 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(-) (limited to 'drivers/net') 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); - - SET_IEEE80211_PERM_ADDR(hw, ar->mac_addr); - - SET_IEEE80211_DEV(hw, ab->dev); + 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_channels_rates(ar, - cap->supported_bands, - hw->wiphy->bands); + ret = ath12k_mac_setup_register(ar, &ht_cap, hw->wiphy->bands); if (ret) - goto err; + goto out; - ath12k_mac_setup_ht_vht_cap(ar, cap, &ht_cap); - ath12k_mac_setup_sband_iftype_data(ar, cap); + SET_IEEE80211_PERM_ADDR(hw, ar->mac_addr); + SET_IEEE80211_DEV(hw, ab->dev); 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 @@ err_free_if_combs: 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; -- cgit v1.2.3 From 3e141f0034d573f133fc3e73508949ba64461a4a Mon Sep 17 00:00:00 2001 From: Karthikeyan Periyasamy Date: Sun, 14 Jan 2024 17:02:40 +0200 Subject: 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(-) (limited to 'drivers/net') 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 @@ err_mon_del: 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; -- cgit v1.2.3 From ce20a10fdff41afbbc119e91cf3e2378d81e2eb0 Mon Sep 17 00:00:00 2001 From: Karthikeyan Periyasamy Date: Sun, 14 Jan 2024 17:02:40 +0200 Subject: 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(-) (limited to 'drivers/net') 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); } -- cgit v1.2.3 From 00c9b1a6d21d03b8fb74f1029c370dccce294dd5 Mon Sep 17 00:00:00 2001 From: Karthikeyan Periyasamy Date: Sun, 14 Jan 2024 17:02:40 +0200 Subject: 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(-) (limited to 'drivers/net') 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 @@ 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) +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; } -- cgit v1.2.3 From e1e275a699061fba965b5653a8f03d550bb5fe6e Mon Sep 17 00:00:00 2001 From: Karthikeyan Periyasamy Date: Sun, 14 Jan 2024 17:02:40 +0200 Subject: 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(-) (limited to 'drivers/net') 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 @@ err: 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; -- cgit v1.2.3 From 3bbc9c7429ff9e9c79c36add3742f7292d135b98 Mon Sep 17 00:00:00 2001 From: Karthikeyan Periyasamy Date: Sun, 14 Jan 2024 17:02:40 +0200 Subject: 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(-) (limited to 'drivers/net') 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) { -- cgit v1.2.3 From 92b30bb397869f94724b59d85f16e8de00fa9bc4 Mon Sep 17 00:00:00 2001 From: Karthikeyan Periyasamy Date: Sun, 14 Jan 2024 17:02:40 +0200 Subject: 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(-) (limited to 'drivers/net') 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, -- cgit v1.2.3 From d629b0c149c913d633ada52357069b8ac7fc81c6 Mon Sep 17 00:00:00 2001 From: Karthikeyan Periyasamy Date: Sun, 14 Jan 2024 17:02:41 +0200 Subject: 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(-) (limited to 'drivers/net') 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 @@ err_vdev_del: 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); } -- cgit v1.2.3 From 5b1b5dbfd6a6590606d7dbb99b0708be100a4acb Mon Sep 17 00:00:00 2001 From: Karthikeyan Periyasamy Date: Sun, 14 Jan 2024 17:02:41 +0200 Subject: 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(-) (limited to 'drivers/net') 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; } -- cgit v1.2.3 From b33dcbe8d53d1e57cfc9bc035f43a27af5b6a973 Mon Sep 17 00:00:00 2001 From: Karthikeyan Periyasamy Date: Sun, 14 Jan 2024 17:02:41 +0200 Subject: 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(-) (limited to 'drivers/net') 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, -- cgit v1.2.3 From 5bdfb8c9db223009d15a2379b87d16cc800d439a Mon Sep 17 00:00:00 2001 From: Karthikeyan Periyasamy Date: Sun, 14 Jan 2024 17:02:41 +0200 Subject: 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(-) (limited to 'drivers/net') 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 @@ unlock: 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)) -- cgit v1.2.3 From 9666ad011992b51da2a4623d20084a363a3a095e Mon Sep 17 00:00:00 2001 From: Jeff Johnson Date: Sun, 14 Jan 2024 17:02:42 +0200 Subject: 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(-) (limited to 'drivers/net') 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 { -- cgit v1.2.3 From 76fece36f17a535c75ebc83d026bacad1263fd37 Mon Sep 17 00:00:00 2001 From: Karthikeyan Periyasamy Date: Tue, 16 Jan 2024 14:33:07 +0200 Subject: 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(-) (limited to 'drivers/net') 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) -- cgit v1.2.3 From 53a65445c144f99a6769788d0c04b64cdbb497d4 Mon Sep 17 00:00:00 2001 From: Karthikeyan Periyasamy Date: Tue, 16 Jan 2024 14:33:07 +0200 Subject: 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(-) (limited to 'drivers/net') 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 @@ out: 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 -- cgit v1.2.3 From 49b88e5f3fa114ed187f876082aa5bc4349f5bc7 Mon Sep 17 00:00:00 2001 From: Karthikeyan Periyasamy Date: Wed, 17 Jan 2024 13:34:29 +0530 Subject: 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(-) (limited to 'drivers/net') 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); -- cgit v1.2.3 From 3422402bacd0322875be2e2a97a98e67d30c1b14 Mon Sep 17 00:00:00 2001 From: Karthikeyan Periyasamy Date: Wed, 17 Jan 2024 13:34:30 +0530 Subject: 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(-) (limited to 'drivers/net') 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); -- cgit v1.2.3 From bc2ef64931c263104532723e9d8d923cfb357ab6 Mon Sep 17 00:00:00 2001 From: Karthikeyan Periyasamy Date: Wed, 17 Jan 2024 13:34:31 +0530 Subject: 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(-) (limited to 'drivers/net') 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 * -- cgit v1.2.3 From 60b9376583217c8726be0a57d9ff71d52e9ce261 Mon Sep 17 00:00:00 2001 From: Baochen Qiang Date: Wed, 29 Nov 2023 10:04:12 +0800 Subject: 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(-) (limited to 'drivers/net') 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; -- cgit v1.2.3 From b0970f50839ecbb71d43914fe88ea7eeb3416a21 Mon Sep 17 00:00:00 2001 From: Baochen Qiang Date: Wed, 17 Jan 2024 14:05:30 +0200 Subject: 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(-) (limited to 'drivers/net') 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); -- cgit v1.2.3 From 955df16f2a4c3023753680925e71e099818c2329 Mon Sep 17 00:00:00 2001 From: Baochen Qiang Date: Wed, 17 Jan 2024 14:05:39 +0200 Subject: 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(-) (limited to 'drivers/net') 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); -- cgit v1.2.3 From b856f023b40fa7735ca19de433fc1307d69c36d0 Mon Sep 17 00:00:00 2001 From: Karthikeyan Periyasamy Date: Thu, 18 Jan 2024 06:33:19 +0530 Subject: 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(-) (limited to 'drivers/net') 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 @@ mic_fail: 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(); -- cgit v1.2.3 From 6db6e70a17f6fb3f2cfae31bb212a2179d0f6e6b Mon Sep 17 00:00:00 2001 From: Karthikeyan Periyasamy Date: Thu, 18 Jan 2024 07:58:56 +0200 Subject: 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 | 417 ++++++++++++++++++++++----------- drivers/net/wireless/ath/ath12k/mac.h | 4 +- drivers/net/wireless/ath/ath12k/reg.c | 3 +- 5 files changed, 335 insertions(+), 136 deletions(-) (limited to 'drivers/net') 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 @@ err_mon_del: 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 @@ exit: 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 @@ err: 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; + wiphy->max_ap_assoc_sta = ar->max_num_stations; + + cap = &pdev->cap; + + wiphy->available_antennas_rx = cap->rx_chain_mask; + wiphy->available_antennas_tx = cap->tx_chain_mask; + SET_IEEE80211_PERM_ADDR(hw, ar->mac_addr); SET_IEEE80211_DEV(hw, ab->dev); - ret = ath12k_mac_setup_iface_combinations(ar); + ret = ath12k_mac_setup_iface_combinations(ah); if (ret) { - ath12k_err(ar->ab, "failed to setup interface combinations: %d\n", ret); - goto err_setup_unregister; + ath12k_err(ab, "failed to setup interface combinations: %d\n", ret); + goto err_cleanup_unregister; } - wiphy->available_antennas_rx = cap->rx_chain_mask; - wiphy->available_antennas_tx = cap->tx_chain_mask; - - wiphy->interface_modes = ab->hw_params->interface_modes; + 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 @@ err_free_if_combs: 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); +err_cleanup_unregister: + ath12k_mac_cleanup_unregister(ar); +out: SET_IEEE80211_DEV(hw, NULL); -out: 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 @@ err_cleanup: 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; + + 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 = hw->priv; - ar->hw = hw; + 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, -- cgit v1.2.3 From 9f9df1a2535f6c890242b80d8538bd90ae540647 Mon Sep 17 00:00:00 2001 From: Baochen Qiang Date: Thu, 18 Jan 2024 07:53:48 +0200 Subject: 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(-) (limited to 'drivers/net') 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 @@ out: 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); -- cgit v1.2.3 From 1779487e72e0390d240df271be0005397d0110f3 Mon Sep 17 00:00:00 2001 From: Jeff Johnson Date: Thu, 18 Jan 2024 08:12:53 -0800 Subject: 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(-) (limited to 'drivers/net') 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), -- cgit v1.2.3 From 5f813b0447feef3a4883b66e600c7317a4d7d76b Mon Sep 17 00:00:00 2001 From: Jeff Johnson Date: Thu, 18 Jan 2024 08:12:54 -0800 Subject: 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(-) (limited to 'drivers/net') 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. -- cgit v1.2.3 From 75dd17fdef110d99a2613d1284d2863cfc7cf6e9 Mon Sep 17 00:00:00 2001 From: Jeff Johnson Date: Thu, 18 Jan 2024 08:12:55 -0800 Subject: 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(-) (limited to 'drivers/net') 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 -- cgit v1.2.3 From c80cc5cfefbaca35e019a26f31faa11031c13665 Mon Sep 17 00:00:00 2001 From: Jeff Johnson Date: Thu, 18 Jan 2024 08:12:56 -0800 Subject: 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(-) (limited to 'drivers/net') 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 -- cgit v1.2.3 From f020c30299323c206b9041dd478ac040dd828ec0 Mon Sep 17 00:00:00 2001 From: Jeff Johnson Date: Thu, 18 Jan 2024 08:12:57 -0800 Subject: 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(-) (limited to 'drivers/net') 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, -- cgit v1.2.3 From 67a48d937fac917947540c9f89630d472cd61fcb Mon Sep 17 00:00:00 2001 From: Sriram R Date: Wed, 17 Jan 2024 11:56:28 +0530 Subject: 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(-) (limited to 'drivers/net') 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++) { -- cgit v1.2.3 From dbd73acb22d85873ecca51fdb33a0e50d11e8021 Mon Sep 17 00:00:00 2001 From: Baochen Qiang Date: Tue, 23 Jan 2024 09:52:01 +0800 Subject: 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(-) (limited to 'drivers/net') 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) -- cgit v1.2.3 From 171203f0c4093dfe7e73ceb6c38033595f329f56 Mon Sep 17 00:00:00 2001 From: Baochen Qiang Date: Tue, 23 Jan 2024 10:56:57 +0800 Subject: 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(-) (limited to 'drivers/net') 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) { -- cgit v1.2.3 From 629642fa8b25b8dfecefc9e2177a44c009858da7 Mon Sep 17 00:00:00 2001 From: Baochen Qiang Date: Tue, 23 Jan 2024 10:56:58 +0800 Subject: 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(-) (limited to 'drivers/net') 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 @@ unlock: 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; -- cgit v1.2.3 From ce59902e56ea0477ad9bef0067d0e47b6c4d707d Mon Sep 17 00:00:00 2001 From: Baochen Qiang Date: Tue, 23 Jan 2024 10:56:59 +0800 Subject: 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(-) (limited to 'drivers/net') 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 @@ err_fallback: 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, -- cgit v1.2.3 From 9d5f28c1366f48efae7b1df0f622285519e74dce Mon Sep 17 00:00:00 2001 From: Baochen Qiang Date: Tue, 23 Jan 2024 10:57:00 +0800 Subject: 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(-) (limited to 'drivers/net') 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 @@ exit: 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; - - 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); - } + 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_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 || -- cgit v1.2.3 From 03d5110241eb3a7e25030e75b546f6f7a62d3007 Mon Sep 17 00:00:00 2001 From: Ayala Beker Date: Tue, 2 Jan 2024 21:35:35 +0200 Subject: wifi: mac80211_hwsim: handle TID to link mapping neg request Accept the request if all TIDs are mapped to the same link set, otherwise reject it. Signed-off-by: Ayala Beker Reviewed-by: Gregory Greenman Reviewed-by: Johannes Berg Signed-off-by: Miri Korenblit Link: https://msgid.link/20240102213313.dfa8e132d0cd.I5fbec1fef933980819ea39c1227f37d307ab1145@changeid Signed-off-by: Johannes Berg --- drivers/net/wireless/virtual/mac80211_hwsim.c | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) (limited to 'drivers/net') diff --git a/drivers/net/wireless/virtual/mac80211_hwsim.c b/drivers/net/wireless/virtual/mac80211_hwsim.c index a84340c2075f..e144cd30ae3f 100644 --- a/drivers/net/wireless/virtual/mac80211_hwsim.c +++ b/drivers/net/wireless/virtual/mac80211_hwsim.c @@ -2738,6 +2738,24 @@ static int mac80211_hwsim_get_survey(struct ieee80211_hw *hw, int idx, return 0; } +static enum ieee80211_neg_ttlm_res +mac80211_hwsim_can_neg_ttlm(struct ieee80211_hw *hw, struct ieee80211_vif *vif, + struct ieee80211_neg_ttlm *neg_ttlm) +{ + u32 i; + + /* For testing purposes, accept if all TIDs are mapped to the same links + * set, otherwise reject. + */ + for (i = 0; i < IEEE80211_TTLM_NUM_TIDS; i++) { + if (neg_ttlm->downlink[i] != neg_ttlm->uplink[i] || + neg_ttlm->downlink[i] != neg_ttlm->downlink[0]) + return NEG_TTLM_RES_REJECT; + } + + return NEG_TTLM_RES_ACCEPT; +} + #ifdef CONFIG_NL80211_TESTMODE /* * This section contains example code for using netlink @@ -3903,6 +3921,7 @@ static const struct ieee80211_ops mac80211_hwsim_mlo_ops = { .change_vif_links = mac80211_hwsim_change_vif_links, .change_sta_links = mac80211_hwsim_change_sta_links, .sta_state = mac80211_hwsim_sta_state, + .can_neg_ttlm = mac80211_hwsim_can_neg_ttlm, }; struct hwsim_new_radio_params { -- cgit v1.2.3 From 9362fabcede336d2e780c6ae44eff0f882349dd2 Mon Sep 17 00:00:00 2001 From: Ayala Beker Date: Tue, 2 Jan 2024 21:35:36 +0200 Subject: wifi: mac80211_hwsim: handle BSS_CHANGED_MLD_TTLM Same as in BSS_CHANGED_VALID_LINKS, set the active links to all the usable links. Signed-off-by: Ayala Beker Reviewed-by: Gregory Greenman Reviewed-by: Johannes Berg Signed-off-by: Miri Korenblit Link: https://msgid.link/20240102213313.3c28da3534e9.I76846c5dd693f930d4828e411c734639708b5a1a@changeid Signed-off-by: Johannes Berg --- drivers/net/wireless/virtual/mac80211_hwsim.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/virtual/mac80211_hwsim.c b/drivers/net/wireless/virtual/mac80211_hwsim.c index e144cd30ae3f..e080d1131f76 100644 --- a/drivers/net/wireless/virtual/mac80211_hwsim.c +++ b/drivers/net/wireless/virtual/mac80211_hwsim.c @@ -2462,7 +2462,7 @@ static void mac80211_hwsim_vif_info_changed(struct ieee80211_hw *hw, } if (vif->type == NL80211_IFTYPE_STATION && - changed & BSS_CHANGED_MLD_VALID_LINKS) { + changed & (BSS_CHANGED_MLD_VALID_LINKS | BSS_CHANGED_MLD_TTLM)) { u16 usable_links = ieee80211_vif_usable_links(vif); if (vif->active_links != usable_links) -- cgit v1.2.3 From 34b5ff4617fa1145eec5a1c62fa1ce6ac2fb0b28 Mon Sep 17 00:00:00 2001 From: Ilan Peer Date: Tue, 2 Jan 2024 21:35:38 +0200 Subject: wifi: mac80211_hwsim: Declare support for negotiated TTLM Advertise support for negotiated TTLM in AP mode for testing purposes. In addition, declare support for some extended capabilities that are globally advertised by mac80211. Signed-off-by: Ilan Peer Reviewed-by: Gregory Greenman Reviewed-by: Johannes Berg Signed-off-by: Miri Korenblit Link: https://msgid.link/20240102213313.3f54382f8449.I42b2f7c52f7574448cc8da3ad3db45075e4e0baa@changeid Signed-off-by: Johannes Berg --- drivers/net/wireless/virtual/mac80211_hwsim.c | 27 +++++++++++++++++++++++++++ 1 file changed, 27 insertions(+) (limited to 'drivers/net') diff --git a/drivers/net/wireless/virtual/mac80211_hwsim.c b/drivers/net/wireless/virtual/mac80211_hwsim.c index e080d1131f76..2b7c9368e96c 100644 --- a/drivers/net/wireless/virtual/mac80211_hwsim.c +++ b/drivers/net/wireless/virtual/mac80211_hwsim.c @@ -4984,6 +4984,29 @@ static void mac80211_hwsim_sband_capab(struct ieee80211_supported_band *sband) BIT(NL80211_IFTYPE_MESH_POINT) | \ BIT(NL80211_IFTYPE_OCB)) +static const u8 iftypes_ext_capa_ap[] = { + [0] = WLAN_EXT_CAPA1_EXT_CHANNEL_SWITCHING, + [2] = WLAN_EXT_CAPA3_MULTI_BSSID_SUPPORT, + [7] = WLAN_EXT_CAPA8_OPMODE_NOTIF | + WLAN_EXT_CAPA8_MAX_MSDU_IN_AMSDU_LSB, + [8] = WLAN_EXT_CAPA9_MAX_MSDU_IN_AMSDU_MSB, + [9] = WLAN_EXT_CAPA10_TWT_RESPONDER_SUPPORT, +}; + +#define MAC80211_HWSIM_MLD_CAPA_OPS FIELD_PREP_CONST( \ + IEEE80211_MLD_CAP_OP_TID_TO_LINK_MAP_NEG_SUPP, \ + IEEE80211_MLD_CAP_OP_TID_TO_LINK_MAP_NEG_SUPP_SAME) + +static const struct wiphy_iftype_ext_capab mac80211_hwsim_iftypes_ext_capa[] = { + { + .iftype = NL80211_IFTYPE_AP, + .extended_capabilities = iftypes_ext_capa_ap, + .extended_capabilities_mask = iftypes_ext_capa_ap, + .extended_capabilities_len = sizeof(iftypes_ext_capa_ap), + .mld_capa_and_ops = MAC80211_HWSIM_MLD_CAPA_OPS, + }, +}; + static int mac80211_hwsim_new_radio(struct genl_info *info, struct hwsim_new_radio_params *param) { @@ -5178,6 +5201,10 @@ static int mac80211_hwsim_new_radio(struct genl_info *info, ieee80211_hw_set(hw, SUPPORTS_DYNAMIC_PS); ieee80211_hw_set(hw, CONNECTION_MONITOR); ieee80211_hw_set(hw, AP_LINK_PS); + + hw->wiphy->iftype_ext_capab = mac80211_hwsim_iftypes_ext_capa; + hw->wiphy->num_iftype_ext_capab = + ARRAY_SIZE(mac80211_hwsim_iftypes_ext_capa); } else { ieee80211_hw_set(hw, HOST_BROADCAST_PS_BUFFERING); ieee80211_hw_set(hw, PS_NULLFUNC_STACK); -- cgit v1.2.3 From 6a19031da91515ebcc4ddaae87914bbcccede75e Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Tue, 2 Jan 2024 21:35:41 +0200 Subject: wifi: mac80211_hwsim: advertise AP-side EMLSR/EMLMR capa Advertise EMLSR and EMLMR capability on the AP side to be a better compliant AP MLD. Signed-off-by: Johannes Berg Reviewed-by: Ilan Peer Reviewed-by: Gregory Greenman Signed-off-by: Miri Korenblit Link: https://msgid.link/20240102213313.dc8786efa787.Ic460c13a91d770c208ac16d0b3e94941bab9b8eb@changeid Signed-off-by: Johannes Berg --- drivers/net/wireless/virtual/mac80211_hwsim.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'drivers/net') diff --git a/drivers/net/wireless/virtual/mac80211_hwsim.c b/drivers/net/wireless/virtual/mac80211_hwsim.c index 2b7c9368e96c..304dc96fc3bb 100644 --- a/drivers/net/wireless/virtual/mac80211_hwsim.c +++ b/drivers/net/wireless/virtual/mac80211_hwsim.c @@ -5003,6 +5003,8 @@ static const struct wiphy_iftype_ext_capab mac80211_hwsim_iftypes_ext_capa[] = { .extended_capabilities = iftypes_ext_capa_ap, .extended_capabilities_mask = iftypes_ext_capa_ap, .extended_capabilities_len = sizeof(iftypes_ext_capa_ap), + .eml_capabilities = IEEE80211_EML_CAP_EMLSR_SUPP | + IEEE80211_EML_CAP_EMLMR_SUPPORT, .mld_capa_and_ops = MAC80211_HWSIM_MLD_CAPA_OPS, }, }; -- cgit v1.2.3 From 2b3e35d98bcaad9218ec3d4ab91e93022f76b6dd Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Thu, 11 Jan 2024 18:17:39 +0200 Subject: wifi: mac80211_hwsim: advertise 15 simultaneous links Advertise MLD capabilities and operations in AP mode that say that up to 15 links are supported simultaneously. Signed-off-by: Johannes Berg Reviewed-by: Gregory Greenman Reviewed-by: Ilan Peer Signed-off-by: Miri Korenblit Link: https://msgid.link/20240111181514.52a1d48b67e6.Ie459df742944d24d6401683d54d2f3ac44834803@changeid Signed-off-by: Johannes Berg --- drivers/net/wireless/virtual/mac80211_hwsim.c | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/virtual/mac80211_hwsim.c b/drivers/net/wireless/virtual/mac80211_hwsim.c index 304dc96fc3bb..403d892c0468 100644 --- a/drivers/net/wireless/virtual/mac80211_hwsim.c +++ b/drivers/net/wireless/virtual/mac80211_hwsim.c @@ -4993,9 +4993,11 @@ static const u8 iftypes_ext_capa_ap[] = { [9] = WLAN_EXT_CAPA10_TWT_RESPONDER_SUPPORT, }; -#define MAC80211_HWSIM_MLD_CAPA_OPS FIELD_PREP_CONST( \ - IEEE80211_MLD_CAP_OP_TID_TO_LINK_MAP_NEG_SUPP, \ - IEEE80211_MLD_CAP_OP_TID_TO_LINK_MAP_NEG_SUPP_SAME) +#define MAC80211_HWSIM_MLD_CAPA_OPS \ + FIELD_PREP_CONST(IEEE80211_MLD_CAP_OP_TID_TO_LINK_MAP_NEG_SUPP, \ + IEEE80211_MLD_CAP_OP_TID_TO_LINK_MAP_NEG_SUPP_SAME) | \ + FIELD_PREP_CONST(IEEE80211_MLD_CAP_OP_MAX_SIMUL_LINKS, \ + IEEE80211_MLD_MAX_NUM_LINKS - 1) static const struct wiphy_iftype_ext_capab mac80211_hwsim_iftypes_ext_capa[] = { { -- cgit v1.2.3 From cf74ce02e394109e16efcb4f15a8e885e9a834a7 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Tue, 23 Jan 2024 20:08:09 +0200 Subject: wifi: iwlwifi: add kunit test for devinfo ordering We used to have a test built into the code for this internally, but now we can put that into kunit and let everyone run it, to verify the devinfo table ordering if it's changed. Signed-off-by: Johannes Berg Reviewed-by: Benjamin Berg Reviewed-by: Gregory Greenman Signed-off-by: Miri Korenblit Link: https://msgid.link/20240123200528.a4a8af7c091f.I0fb09083317b331168b99b8db39656a126a5cc4d@changeid Signed-off-by: Johannes Berg --- drivers/net/wireless/intel/iwlwifi/Kconfig | 9 ++++ drivers/net/wireless/intel/iwlwifi/Makefile | 2 + drivers/net/wireless/intel/iwlwifi/iwl-config.h | 10 ++++ drivers/net/wireless/intel/iwlwifi/iwl-drv.h | 9 ++++ drivers/net/wireless/intel/iwlwifi/pcie/drv.c | 11 ++++- drivers/net/wireless/intel/iwlwifi/tests/Makefile | 7 +++ drivers/net/wireless/intel/iwlwifi/tests/devinfo.c | 54 ++++++++++++++++++++++ drivers/net/wireless/intel/iwlwifi/tests/module.c | 10 ++++ 8 files changed, 110 insertions(+), 2 deletions(-) create mode 100644 drivers/net/wireless/intel/iwlwifi/tests/Makefile create mode 100644 drivers/net/wireless/intel/iwlwifi/tests/devinfo.c create mode 100644 drivers/net/wireless/intel/iwlwifi/tests/module.c (limited to 'drivers/net') diff --git a/drivers/net/wireless/intel/iwlwifi/Kconfig b/drivers/net/wireless/intel/iwlwifi/Kconfig index 20971304fdef..4b04865fc2c9 100644 --- a/drivers/net/wireless/intel/iwlwifi/Kconfig +++ b/drivers/net/wireless/intel/iwlwifi/Kconfig @@ -46,6 +46,15 @@ config IWLWIFI if IWLWIFI +config IWLWIFI_KUNIT_TESTS + tristate + depends on KUNIT + default KUNIT_ALL_TESTS + help + Enable this option for iwlwifi kunit tests. + + If unsure, say N. + config IWLWIFI_LEDS bool depends on LEDS_CLASS=y || LEDS_CLASS=MAC80211 diff --git a/drivers/net/wireless/intel/iwlwifi/Makefile b/drivers/net/wireless/intel/iwlwifi/Makefile index b983982aee45..3a2a25333d36 100644 --- a/drivers/net/wireless/intel/iwlwifi/Makefile +++ b/drivers/net/wireless/intel/iwlwifi/Makefile @@ -33,4 +33,6 @@ obj-$(CONFIG_IWLDVM) += dvm/ obj-$(CONFIG_IWLMVM) += mvm/ obj-$(CONFIG_IWLMEI) += mei/ +obj-$(CONFIG_IWLWIFI_KUNIT_TESTS) += tests/ + CFLAGS_iwl-devtrace.o := -I$(src) diff --git a/drivers/net/wireless/intel/iwlwifi/iwl-config.h b/drivers/net/wireless/intel/iwlwifi/iwl-config.h index ae6f1cd4d660..b3c6847cccf1 100644 --- a/drivers/net/wireless/intel/iwlwifi/iwl-config.h +++ b/drivers/net/wireless/intel/iwlwifi/iwl-config.h @@ -12,6 +12,7 @@ #include #include #include "iwl-csr.h" +#include "iwl-drv.h" enum iwl_device_family { IWL_DEVICE_FAMILY_UNDEFINED, @@ -471,6 +472,15 @@ struct iwl_dev_info { const char *name; }; +#if IS_ENABLED(CONFIG_IWLWIFI_KUNIT_TESTS) +extern const struct iwl_dev_info iwl_dev_info_table[]; +extern const unsigned int iwl_dev_info_table_size; +const struct iwl_dev_info * +iwl_pci_find_dev_info(u16 device, u16 subsystem_device, + u16 mac_type, u8 mac_step, u16 rf_type, u8 cdb, + u8 jacket, u8 rf_id, u8 no_160, u8 cores, u8 rf_step); +#endif + /* * This list declares the config structures for all devices. */ diff --git a/drivers/net/wireless/intel/iwlwifi/iwl-drv.h b/drivers/net/wireless/intel/iwlwifi/iwl-drv.h index 3d1a27ba35c6..6a1d31892417 100644 --- a/drivers/net/wireless/intel/iwlwifi/iwl-drv.h +++ b/drivers/net/wireless/intel/iwlwifi/iwl-drv.h @@ -6,6 +6,7 @@ #ifndef __iwl_drv_h__ #define __iwl_drv_h__ #include +#include /* for all modules */ #define DRV_NAME "iwlwifi" @@ -89,6 +90,14 @@ void iwl_drv_stop(struct iwl_drv *drv); #define IWL_EXPORT_SYMBOL(sym) #endif +#if IS_ENABLED(CONFIG_IWLWIFI_KUNIT_TESTS) +#define EXPORT_SYMBOL_IF_IWLWIFI_KUNIT(sym) EXPORT_SYMBOL_IF_KUNIT(sym) +#define VISIBLE_IF_IWLWIFI_KUNIT +#else +#define EXPORT_SYMBOL_IF_IWLWIFI_KUNIT(sym) +#define VISIBLE_IF_IWLWIFI_KUNIT static +#endif + /* max retry for init flow */ #define IWL_MAX_INIT_RETRY 2 diff --git a/drivers/net/wireless/intel/iwlwifi/pcie/drv.c b/drivers/net/wireless/intel/iwlwifi/pcie/drv.c index 2c9b98c8184b..cbae9503f4ba 100644 --- a/drivers/net/wireless/intel/iwlwifi/pcie/drv.c +++ b/drivers/net/wireless/intel/iwlwifi/pcie/drv.c @@ -526,7 +526,7 @@ MODULE_DEVICE_TABLE(pci, iwl_hw_card_ids); IWL_CFG_ANY, IWL_CFG_ANY, IWL_CFG_ANY, IWL_CFG_ANY, IWL_CFG_ANY, \ IWL_CFG_ANY, _cfg, _name) -static const struct iwl_dev_info iwl_dev_info_table[] = { +VISIBLE_IF_IWLWIFI_KUNIT const struct iwl_dev_info iwl_dev_info_table[] = { #if IS_ENABLED(CONFIG_IWLMVM) /* 9000 */ IWL_DEV_INFO(0x2526, 0x1550, iwl9260_2ac_cfg, iwl9260_killer_1550_name), @@ -1117,6 +1117,12 @@ static const struct iwl_dev_info iwl_dev_info_table[] = { iwl_cfg_sc, iwl_sc_name), #endif /* CONFIG_IWLMVM */ }; +EXPORT_SYMBOL_IF_IWLWIFI_KUNIT(iwl_dev_info_table); + +#if IS_ENABLED(CONFIG_IWLWIFI_KUNIT_TESTS) +const unsigned int iwl_dev_info_table_size = ARRAY_SIZE(iwl_dev_info_table); +EXPORT_SYMBOL_IF_IWLWIFI_KUNIT(iwl_dev_info_table_size); +#endif /* * Read rf id and cdb info from prph register and store it @@ -1236,7 +1242,7 @@ out: /* PCI registers */ #define PCI_CFG_RETRY_TIMEOUT 0x041 -static const struct iwl_dev_info * +VISIBLE_IF_IWLWIFI_KUNIT const struct iwl_dev_info * iwl_pci_find_dev_info(u16 device, u16 subsystem_device, u16 mac_type, u8 mac_step, u16 rf_type, u8 cdb, u8 jacket, u8 rf_id, u8 no_160, u8 cores, u8 rf_step) @@ -1299,6 +1305,7 @@ iwl_pci_find_dev_info(u16 device, u16 subsystem_device, return NULL; } +EXPORT_SYMBOL_IF_IWLWIFI_KUNIT(iwl_pci_find_dev_info); static int iwl_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent) { diff --git a/drivers/net/wireless/intel/iwlwifi/tests/Makefile b/drivers/net/wireless/intel/iwlwifi/tests/Makefile new file mode 100644 index 000000000000..5658471bdf0a --- /dev/null +++ b/drivers/net/wireless/intel/iwlwifi/tests/Makefile @@ -0,0 +1,7 @@ +# SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause + +iwlwifi-tests-y += module.o devinfo.o + +ccflags-y += -I$(srctree)/$(src)/../ + +obj-$(CONFIG_IWLWIFI_KUNIT_TESTS) += iwlwifi-tests.o diff --git a/drivers/net/wireless/intel/iwlwifi/tests/devinfo.c b/drivers/net/wireless/intel/iwlwifi/tests/devinfo.c new file mode 100644 index 000000000000..7aa47fce6e2d --- /dev/null +++ b/drivers/net/wireless/intel/iwlwifi/tests/devinfo.c @@ -0,0 +1,54 @@ +// SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause +/* + * KUnit tests for the iwlwifi device info table + * + * Copyright (C) 2023 Intel Corporation + */ +#include +#include "iwl-drv.h" +#include "iwl-config.h" + +MODULE_IMPORT_NS(EXPORTED_FOR_KUNIT_TESTING); + +static void iwl_pci_print_dev_info(const char *pfx, const struct iwl_dev_info *di) +{ + printk(KERN_DEBUG "%sdev=%.4x,subdev=%.4x,mac_type=%.4x,mac_step=%.4x,rf_type=%.4x,cdb=%d,jacket=%d,rf_id=%.2x,no_160=%d,cores=%.2x\n", + pfx, di->device, di->subdevice, di->mac_type, di->mac_step, + di->rf_type, di->cdb, di->jacket, di->rf_id, di->no_160, + di->cores); +} + +static void devinfo_table_order(struct kunit *test) +{ + int idx; + + for (idx = 0; idx < iwl_dev_info_table_size; idx++) { + const struct iwl_dev_info *di = &iwl_dev_info_table[idx]; + const struct iwl_dev_info *ret; + + ret = iwl_pci_find_dev_info(di->device, di->subdevice, + di->mac_type, di->mac_step, + di->rf_type, di->cdb, + di->jacket, di->rf_id, + di->no_160, di->cores, di->rf_step); + if (ret != di) { + iwl_pci_print_dev_info("searched: ", di); + iwl_pci_print_dev_info("found: ", ret); + KUNIT_FAIL(test, + "unusable entry at index %d (found index %d instead)\n", + idx, (int)(ret - iwl_dev_info_table)); + } + } +} + +static struct kunit_case devinfo_test_cases[] = { + KUNIT_CASE(devinfo_table_order), + {} +}; + +static struct kunit_suite iwlwifi_devinfo = { + .name = "iwlwifi-devinfo", + .test_cases = devinfo_test_cases, +}; + +kunit_test_suite(iwlwifi_devinfo); diff --git a/drivers/net/wireless/intel/iwlwifi/tests/module.c b/drivers/net/wireless/intel/iwlwifi/tests/module.c new file mode 100644 index 000000000000..0c54f818e5a7 --- /dev/null +++ b/drivers/net/wireless/intel/iwlwifi/tests/module.c @@ -0,0 +1,10 @@ +// SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause +/* + * Module boilerplate for the iwlwifi kunit module. + * + * Copyright (C) 2023 Intel Corporation + */ +#include + +MODULE_LICENSE("GPL"); +MODULE_DESCRIPTION("kunit tests for iwlwifi"); -- cgit v1.2.3 From 099a47dbe71b758e6875d0297467f2b8d23014df Mon Sep 17 00:00:00 2001 From: Mukesh Sisodiya Date: Tue, 23 Jan 2024 20:08:10 +0200 Subject: wifi: iwlwifi: Add support for new 802.11be device Add support for the new 802.11be device with limites capabilities: - 320 MHz isn't supported - MCSs 12 and 13 are not supported Signed-off-by: Mukesh Sisodiya Reviewed-by: Gregory Greenman Signed-off-by: Miri Korenblit Link: https://msgid.link/20240123200528.8529bd2acedf.I25dccb7bbeb21b8df2123fad51dde7fcf137a508@changeid Signed-off-by: Johannes Berg --- drivers/net/wireless/intel/iwlwifi/cfg/bz.c | 1 + drivers/net/wireless/intel/iwlwifi/fw/pnvm.c | 13 +++++++++++++ drivers/net/wireless/intel/iwlwifi/iwl-config.h | 4 ++++ drivers/net/wireless/intel/iwlwifi/iwl-nvm-parse.c | 16 ++++++++++++++-- drivers/net/wireless/intel/iwlwifi/iwl-trans.h | 2 ++ drivers/net/wireless/intel/iwlwifi/pcie/drv.c | 7 ++++++- 6 files changed, 40 insertions(+), 3 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/intel/iwlwifi/cfg/bz.c b/drivers/net/wireless/intel/iwlwifi/cfg/bz.c index 82da957adcf6..21fdaf8e0e0e 100644 --- a/drivers/net/wireless/intel/iwlwifi/cfg/bz.c +++ b/drivers/net/wireless/intel/iwlwifi/cfg/bz.c @@ -153,6 +153,7 @@ const struct iwl_cfg_trans_params iwl_bz_trans_cfg = { }; const char iwl_bz_name[] = "Intel(R) TBD Bz device"; +const char iwl_mtp_name[] = "Intel(R) Wi-Fi 7 BE202 160MHz"; const struct iwl_cfg iwl_cfg_bz = { .fw_name_mac = "bz", diff --git a/drivers/net/wireless/intel/iwlwifi/fw/pnvm.c b/drivers/net/wireless/intel/iwlwifi/fw/pnvm.c index 650e4bde9c17..d467ec0e3552 100644 --- a/drivers/net/wireless/intel/iwlwifi/fw/pnvm.c +++ b/drivers/net/wireless/intel/iwlwifi/fw/pnvm.c @@ -12,6 +12,8 @@ #include "fw/api/alive.h" #include "fw/uefi.h" +#define IWL_PNVM_REDUCED_CAP_BIT BIT(25) + struct iwl_pnvm_section { __le32 offset; const u8 data[]; @@ -173,6 +175,7 @@ static int iwl_pnvm_parse(struct iwl_trans *trans, const u8 *data, while (len >= sizeof(*tlv)) { u32 tlv_len, tlv_type; + u32 rf_type; len -= sizeof(*tlv); tlv = (const void *)data; @@ -201,6 +204,16 @@ static int iwl_pnvm_parse(struct iwl_trans *trans, const u8 *data, data += sizeof(*tlv) + ALIGN(tlv_len, 4); len -= ALIGN(tlv_len, 4); + trans->reduced_cap_sku = false; + rf_type = CSR_HW_RFID_TYPE(trans->hw_rf_id); + if ((trans->sku_id[0] & IWL_PNVM_REDUCED_CAP_BIT) && + rf_type == IWL_CFG_RF_TYPE_FM) + trans->reduced_cap_sku = true; + + IWL_DEBUG_FW(trans, + "Reduced SKU device %d\n", + trans->reduced_cap_sku); + if (trans->sku_id[0] == le32_to_cpu(sku_id->data[0]) && trans->sku_id[1] == le32_to_cpu(sku_id->data[1]) && trans->sku_id[2] == le32_to_cpu(sku_id->data[2])) { diff --git a/drivers/net/wireless/intel/iwlwifi/iwl-config.h b/drivers/net/wireless/intel/iwlwifi/iwl-config.h index b3c6847cccf1..97e73443316a 100644 --- a/drivers/net/wireless/intel/iwlwifi/iwl-config.h +++ b/drivers/net/wireless/intel/iwlwifi/iwl-config.h @@ -443,6 +443,9 @@ struct iwl_cfg { #define IWL_CFG_NO_160 0x1 #define IWL_CFG_160 0x0 +#define IWL_CFG_NO_320 0x1 +#define IWL_CFG_320 0x0 + #define IWL_CFG_CORES_BT 0x0 #define IWL_CFG_CORES_BT_GNSS 0x5 @@ -536,6 +539,7 @@ extern const char iwl_ax221_name[]; extern const char iwl_ax231_name[]; extern const char iwl_ax411_name[]; extern const char iwl_bz_name[]; +extern const char iwl_mtp_name[]; extern const char iwl_sc_name[]; #if IS_ENABLED(CONFIG_IWLDVM) extern const struct iwl_cfg iwl5300_agn_cfg; diff --git a/drivers/net/wireless/intel/iwlwifi/iwl-nvm-parse.c b/drivers/net/wireless/intel/iwlwifi/iwl-nvm-parse.c index 402896988686..3f62f10a7c37 100644 --- a/drivers/net/wireless/intel/iwlwifi/iwl-nvm-parse.c +++ b/drivers/net/wireless/intel/iwlwifi/iwl-nvm-parse.c @@ -892,8 +892,9 @@ iwl_nvm_fixup_sband_iftd(struct iwl_trans *trans, bool is_ap = iftype_data->types_mask & BIT(NL80211_IFTYPE_AP); bool no_320; - no_320 = !trans->trans_cfg->integrated && - trans->pcie_link_speed < PCI_EXP_LNKSTA_CLS_8_0GB; + no_320 = (!trans->trans_cfg->integrated && + trans->pcie_link_speed < PCI_EXP_LNKSTA_CLS_8_0GB) || + trans->reduced_cap_sku; if (!data->sku_cap_11be_enable || iwlwifi_mod_params.disable_11be) iftype_data->eht_cap.has_eht = false; @@ -1059,6 +1060,17 @@ iwl_nvm_fixup_sband_iftd(struct iwl_trans *trans, iftype_data->he_cap.he_cap_elem.phy_cap_info[7] &= ~IEEE80211_HE_PHY_CAP7_STBC_RX_ABOVE_80MHZ; } + + if (trans->reduced_cap_sku) { + memset(&iftype_data->eht_cap.eht_mcs_nss_supp.bw._320, 0, + sizeof(iftype_data->eht_cap.eht_mcs_nss_supp.bw._320)); + iftype_data->eht_cap.eht_mcs_nss_supp.bw._80.rx_tx_mcs13_max_nss = 0; + iftype_data->eht_cap.eht_mcs_nss_supp.bw._160.rx_tx_mcs13_max_nss = 0; + iftype_data->eht_cap.eht_cap_elem.phy_cap_info[8] &= + ~IEEE80211_EHT_PHY_CAP8_RX_4096QAM_WIDER_BW_DL_OFDMA; + iftype_data->eht_cap.eht_cap_elem.phy_cap_info[2] &= + ~IEEE80211_EHT_PHY_CAP2_SOUNDING_DIM_320MHZ_MASK; + } } static void iwl_init_he_hw_capab(struct iwl_trans *trans, diff --git a/drivers/net/wireless/intel/iwlwifi/iwl-trans.h b/drivers/net/wireless/intel/iwlwifi/iwl-trans.h index 5789a8735976..9e26c9eb6d83 100644 --- a/drivers/net/wireless/intel/iwlwifi/iwl-trans.h +++ b/drivers/net/wireless/intel/iwlwifi/iwl-trans.h @@ -1068,6 +1068,7 @@ struct iwl_trans_txqs { * @pcie_link_speed: current PCIe link speed (%PCI_EXP_LNKSTA_CLS_*), * only valid for discrete (not integrated) NICs * @invalid_tx_cmd: invalid TX command buffer + * @reduced_cap_sku: reduced capability supported SKU */ struct iwl_trans { bool csme_own; @@ -1090,6 +1091,7 @@ struct iwl_trans { u32 hw_id; char hw_id_str[52]; u32 sku_id[3]; + bool reduced_cap_sku; u8 rx_mpdu_cmd, rx_mpdu_cmd_hdr_size; diff --git a/drivers/net/wireless/intel/iwlwifi/pcie/drv.c b/drivers/net/wireless/intel/iwlwifi/pcie/drv.c index cbae9503f4ba..42680d8469f5 100644 --- a/drivers/net/wireless/intel/iwlwifi/pcie/drv.c +++ b/drivers/net/wireless/intel/iwlwifi/pcie/drv.c @@ -1008,8 +1008,13 @@ VISIBLE_IF_IWLWIFI_KUNIT const struct iwl_dev_info iwl_dev_info_table[] = { _IWL_DEV_INFO(IWL_CFG_ANY, IWL_CFG_ANY, IWL_CFG_MAC_TYPE_GL, IWL_CFG_ANY, IWL_CFG_RF_TYPE_FM, IWL_CFG_ANY, IWL_CFG_ANY, - IWL_CFG_ANY, IWL_CFG_ANY, IWL_CFG_NO_CDB, + IWL_CFG_320, IWL_CFG_ANY, IWL_CFG_NO_CDB, iwl_cfg_gl, iwl_bz_name), + _IWL_DEV_INFO(IWL_CFG_ANY, IWL_CFG_ANY, + IWL_CFG_MAC_TYPE_GL, IWL_CFG_ANY, + IWL_CFG_RF_TYPE_FM, IWL_CFG_ANY, IWL_CFG_ANY, + IWL_CFG_NO_320, IWL_CFG_ANY, IWL_CFG_NO_CDB, + iwl_cfg_gl, iwl_mtp_name), /* SoF with JF2 */ _IWL_DEV_INFO(IWL_CFG_ANY, IWL_CFG_ANY, -- cgit v1.2.3 From 47cde0942959ca11855e1aa5d66209d8625c2a2b Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Tue, 23 Jan 2024 20:08:12 +0200 Subject: wifi: iwlwifi: make TB reallocation a debug message There's no need to print this, it's a known issue and the workaround works just fine. Make the reallocation message just a debug message. Signed-off-by: Johannes Berg Reviewed-by: Gregory Greenman Signed-off-by: Miri Korenblit Link: https://msgid.link/20240123200528.329d5f2ee7f7.I0bfc6dde17fe2c738129f3aba746c6cba57589f9@changeid Signed-off-by: Johannes Berg --- drivers/net/wireless/intel/iwlwifi/queue/tx.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/intel/iwlwifi/queue/tx.c b/drivers/net/wireless/intel/iwlwifi/queue/tx.c index ca74b1b63cac..ba0419bc1765 100644 --- a/drivers/net/wireless/intel/iwlwifi/queue/tx.c +++ b/drivers/net/wireless/intel/iwlwifi/queue/tx.c @@ -271,9 +271,10 @@ static int iwl_txq_gen2_set_tb_with_wa(struct iwl_trans *trans, meta = NULL; goto unmap; } - IWL_WARN(trans, - "TB bug workaround: copied %d bytes from 0x%llx to 0x%llx\n", - len, (unsigned long long)oldphys, (unsigned long long)phys); + IWL_DEBUG_TX(trans, + "TB bug workaround: copied %d bytes from 0x%llx to 0x%llx\n", + len, (unsigned long long)oldphys, + (unsigned long long)phys); ret = 0; unmap: -- cgit v1.2.3 From 84ec2d2e960f33edcee7c47118e59dde72826843 Mon Sep 17 00:00:00 2001 From: Mukesh Sisodiya Date: Fri, 26 Jan 2024 09:00:30 +0200 Subject: wifi: iwlwifi: disable 160 MHz based on subsystem device ID The driver should not send 160 MHz BW support for 5 GHz band in HE if PCI subsystem device ID indicates no 160 MHz support. Signed-off-by: Mukesh Sisodiya Reviewed-by: Mordechay Goodstein Signed-off-by: Miri Korenblit Link: https://msgid.link/20240126085924.77c248ce6986.I558e8d0cf19dc862b1c4124df78a4cb690095bb2@changeid Signed-off-by: Johannes Berg --- drivers/net/wireless/intel/iwlwifi/iwl-nvm-parse.c | 4 ++++ drivers/net/wireless/intel/iwlwifi/iwl-trans.h | 3 ++- drivers/net/wireless/intel/iwlwifi/pcie/drv.c | 1 + 3 files changed, 7 insertions(+), 1 deletion(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/intel/iwlwifi/iwl-nvm-parse.c b/drivers/net/wireless/intel/iwlwifi/iwl-nvm-parse.c index 3f62f10a7c37..67c7cda073e8 100644 --- a/drivers/net/wireless/intel/iwlwifi/iwl-nvm-parse.c +++ b/drivers/net/wireless/intel/iwlwifi/iwl-nvm-parse.c @@ -1061,6 +1061,10 @@ iwl_nvm_fixup_sband_iftd(struct iwl_trans *trans, ~IEEE80211_HE_PHY_CAP7_STBC_RX_ABOVE_80MHZ; } + if (trans->no_160) + iftype_data->he_cap.he_cap_elem.phy_cap_info[0] &= + ~IEEE80211_HE_PHY_CAP0_CHANNEL_WIDTH_SET_160MHZ_IN_5G; + if (trans->reduced_cap_sku) { memset(&iftype_data->eht_cap.eht_mcs_nss_supp.bw._320, 0, sizeof(iftype_data->eht_cap.eht_mcs_nss_supp.bw._320)); diff --git a/drivers/net/wireless/intel/iwlwifi/iwl-trans.h b/drivers/net/wireless/intel/iwlwifi/iwl-trans.h index 9e26c9eb6d83..e3b76c682d76 100644 --- a/drivers/net/wireless/intel/iwlwifi/iwl-trans.h +++ b/drivers/net/wireless/intel/iwlwifi/iwl-trans.h @@ -1069,6 +1069,7 @@ struct iwl_trans_txqs { * only valid for discrete (not integrated) NICs * @invalid_tx_cmd: invalid TX command buffer * @reduced_cap_sku: reduced capability supported SKU + * @no_160: device not supporting 160 MHz */ struct iwl_trans { bool csme_own; @@ -1092,7 +1093,7 @@ struct iwl_trans { char hw_id_str[52]; u32 sku_id[3]; bool reduced_cap_sku; - + u8 no_160; u8 rx_mpdu_cmd, rx_mpdu_cmd_hdr_size; bool pm_support; diff --git a/drivers/net/wireless/intel/iwlwifi/pcie/drv.c b/drivers/net/wireless/intel/iwlwifi/pcie/drv.c index 42680d8469f5..c80b02503b41 100644 --- a/drivers/net/wireless/intel/iwlwifi/pcie/drv.c +++ b/drivers/net/wireless/intel/iwlwifi/pcie/drv.c @@ -1394,6 +1394,7 @@ static int iwl_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent) if (dev_info) { iwl_trans->cfg = dev_info->cfg; iwl_trans->name = dev_info->name; + iwl_trans->no_160 = dev_info->no_160 == IWL_CFG_NO_160; } #if IS_ENABLED(CONFIG_IWLMVM) -- cgit v1.2.3 From de0c2cdcb7eb8e08f3886b433277472d97af0f6e Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Tue, 23 Jan 2024 20:08:14 +0200 Subject: wifi: iwlwifi: mvm: limit EHT 320 MHz MCS for STEP URM If the STEP (the interface between MAC and PHY) is in URM (a lower speed mode) then we cannot use 320 MHz MCS > 9. Therefore, limit the MCS in our capabilities in this case. Note that this also limits the TX/rate scaling since that takes both TX and RX capabilities into account. Signed-off-by: Johannes Berg Reviewed-by: Gregory Greenman Signed-off-by: Miri Korenblit Link: https://msgid.link/20240123200528.02bae683b7fc.Id5efbb71d45da02c8c4e211d20396637ddd44da8@changeid Signed-off-by: Johannes Berg --- drivers/net/wireless/intel/iwlwifi/iwl-nvm-parse.c | 5 +++++ drivers/net/wireless/intel/iwlwifi/iwl-prph.h | 3 +++ drivers/net/wireless/intel/iwlwifi/iwl-trans.h | 4 +++- drivers/net/wireless/intel/iwlwifi/mvm/fw.c | 5 +++++ 4 files changed, 16 insertions(+), 1 deletion(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/intel/iwlwifi/iwl-nvm-parse.c b/drivers/net/wireless/intel/iwlwifi/iwl-nvm-parse.c index 67c7cda073e8..8e6ce484db87 100644 --- a/drivers/net/wireless/intel/iwlwifi/iwl-nvm-parse.c +++ b/drivers/net/wireless/intel/iwlwifi/iwl-nvm-parse.c @@ -1061,6 +1061,11 @@ iwl_nvm_fixup_sband_iftd(struct iwl_trans *trans, ~IEEE80211_HE_PHY_CAP7_STBC_RX_ABOVE_80MHZ; } + if (trans->step_urm) { + iftype_data->eht_cap.eht_mcs_nss_supp.bw._320.rx_tx_mcs11_max_nss = 0; + iftype_data->eht_cap.eht_mcs_nss_supp.bw._320.rx_tx_mcs13_max_nss = 0; + } + if (trans->no_160) iftype_data->he_cap.he_cap_elem.phy_cap_info[0] &= ~IEEE80211_HE_PHY_CAP0_CHANNEL_WIDTH_SET_160MHZ_IN_5G; diff --git a/drivers/net/wireless/intel/iwlwifi/iwl-prph.h b/drivers/net/wireless/intel/iwlwifi/iwl-prph.h index dd32c287b983..c1c7d44f421b 100644 --- a/drivers/net/wireless/intel/iwlwifi/iwl-prph.h +++ b/drivers/net/wireless/intel/iwlwifi/iwl-prph.h @@ -374,6 +374,9 @@ enum { #define CNVR_SCU_SD_REGS_SD_REG_ACTIVE_VDIG_MIRROR 0xA29938 #define CNVI_SCU_SEQ_DATA_DW9 0xA27488 +#define CNVI_PMU_STEP_FLOW 0xA2D588 +#define CNVI_PMU_STEP_FLOW_FORCE_URM BIT(2) + #define PREG_AUX_BUS_WPROT_0 0xA04CC0 /* device family 9000 WPROT register */ diff --git a/drivers/net/wireless/intel/iwlwifi/iwl-trans.h b/drivers/net/wireless/intel/iwlwifi/iwl-trans.h index e3b76c682d76..3047ffc24415 100644 --- a/drivers/net/wireless/intel/iwlwifi/iwl-trans.h +++ b/drivers/net/wireless/intel/iwlwifi/iwl-trans.h @@ -1070,6 +1070,7 @@ struct iwl_trans_txqs { * @invalid_tx_cmd: invalid TX command buffer * @reduced_cap_sku: reduced capability supported SKU * @no_160: device not supporting 160 MHz + * @step_urm: STEP is in URM, no support for MCS>9 in 320 MHz */ struct iwl_trans { bool csme_own; @@ -1093,7 +1094,8 @@ struct iwl_trans { char hw_id_str[52]; u32 sku_id[3]; bool reduced_cap_sku; - u8 no_160; + u8 no_160:1, step_urm:1; + u8 rx_mpdu_cmd, rx_mpdu_cmd_hdr_size; bool pm_support; diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/fw.c b/drivers/net/wireless/intel/iwlwifi/mvm/fw.c index 1252084662c6..b6acf4ade552 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/fw.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/fw.c @@ -677,6 +677,11 @@ static int iwl_run_unified_mvm_ucode(struct iwl_mvm *mvm) iwl_dbg_tlv_time_point(&mvm->fwrt, IWL_FW_INI_TIME_POINT_AFTER_ALIVE, NULL); + if (mvm->trans->trans_cfg->device_family == IWL_DEVICE_FAMILY_BZ) + mvm->trans->step_urm = !!(iwl_read_umac_prph(mvm->trans, + CNVI_PMU_STEP_FLOW) & + CNVI_PMU_STEP_FLOW_FORCE_URM); + /* Send init config command to mark that we are sending NVM access * commands */ -- cgit v1.2.3 From dfdfe4be183b27b278d78225d48b98b3c1ca6285 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Tue, 23 Jan 2024 20:08:15 +0200 Subject: wifi: iwlwifi: remove retry loops in start There's either the pldr_sync case, in which case we didn't want or do the retry loops anyway, or things will just continue to fail. Remove the retry loop that was added in a previous attempt to address the issue that was later (though still a bit broken) addressed by the pldr_sync case. Signed-off-by: Johannes Berg Reviewed-by: Gregory Greenman Signed-off-by: Miri Korenblit Link: https://msgid.link/20240123200528.f80a88a18799.I48f21eda090f4cc675f40e99eef69a986d21b500@changeid Signed-off-by: Johannes Berg --- drivers/net/wireless/intel/iwlwifi/iwl-drv.c | 28 ++++++++--------------- drivers/net/wireless/intel/iwlwifi/iwl-drv.h | 3 --- drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c | 10 +------- 3 files changed, 10 insertions(+), 31 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/intel/iwlwifi/iwl-drv.c b/drivers/net/wireless/intel/iwlwifi/iwl-drv.c index ffe2670720c9..8d562d0e87e4 100644 --- a/drivers/net/wireless/intel/iwlwifi/iwl-drv.c +++ b/drivers/net/wireless/intel/iwlwifi/iwl-drv.c @@ -1423,35 +1423,25 @@ _iwl_op_mode_start(struct iwl_drv *drv, struct iwlwifi_opmode_table *op) const struct iwl_op_mode_ops *ops = op->ops; struct dentry *dbgfs_dir = NULL; struct iwl_op_mode *op_mode = NULL; - int retry, max_retry = !!iwlwifi_mod_params.fw_restart * IWL_MAX_INIT_RETRY; /* also protects start/stop from racing against each other */ lockdep_assert_held(&iwlwifi_opmode_table_mtx); - for (retry = 0; retry <= max_retry; retry++) { - #ifdef CONFIG_IWLWIFI_DEBUGFS - drv->dbgfs_op_mode = debugfs_create_dir(op->name, - drv->dbgfs_drv); - dbgfs_dir = drv->dbgfs_op_mode; + drv->dbgfs_op_mode = debugfs_create_dir(op->name, + drv->dbgfs_drv); + dbgfs_dir = drv->dbgfs_op_mode; #endif - op_mode = ops->start(drv->trans, drv->trans->cfg, - &drv->fw, dbgfs_dir); - - if (op_mode) - return op_mode; - - if (test_bit(STATUS_TRANS_DEAD, &drv->trans->status)) - break; - - IWL_ERR(drv, "retry init count %d\n", retry); + op_mode = ops->start(drv->trans, drv->trans->cfg, + &drv->fw, dbgfs_dir); + if (op_mode) + return op_mode; #ifdef CONFIG_IWLWIFI_DEBUGFS - debugfs_remove_recursive(drv->dbgfs_op_mode); - drv->dbgfs_op_mode = NULL; + debugfs_remove_recursive(drv->dbgfs_op_mode); + drv->dbgfs_op_mode = NULL; #endif - } return NULL; } diff --git a/drivers/net/wireless/intel/iwlwifi/iwl-drv.h b/drivers/net/wireless/intel/iwlwifi/iwl-drv.h index 6a1d31892417..1549ff429549 100644 --- a/drivers/net/wireless/intel/iwlwifi/iwl-drv.h +++ b/drivers/net/wireless/intel/iwlwifi/iwl-drv.h @@ -98,9 +98,6 @@ void iwl_drv_stop(struct iwl_drv *drv); #define VISIBLE_IF_IWLWIFI_KUNIT static #endif -/* max retry for init flow */ -#define IWL_MAX_INIT_RETRY 2 - #define FW_NAME_PRE_BUFSIZE 64 struct iwl_trans; const char *iwl_drv_get_fwname_pre(struct iwl_trans *trans, char *buf); diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c b/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c index 7f13dff04b26..6bbcf4092f52 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c @@ -1195,14 +1195,12 @@ int iwl_mvm_mac_start(struct ieee80211_hw *hw) { struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw); int ret; - int retry, max_retry = 0; mutex_lock(&mvm->mutex); /* we are starting the mac not in error flow, and restart is enabled */ if (!test_bit(IWL_MVM_STATUS_HW_RESTART_REQUESTED, &mvm->status) && iwlwifi_mod_params.fw_restart) { - max_retry = IWL_MAX_INIT_RETRY; /* * This will prevent mac80211 recovery flows to trigger during * init failures @@ -1210,13 +1208,7 @@ int iwl_mvm_mac_start(struct ieee80211_hw *hw) set_bit(IWL_MVM_STATUS_STARTING, &mvm->status); } - for (retry = 0; retry <= max_retry; retry++) { - ret = __iwl_mvm_mac_start(mvm); - if (!ret || mvm->pldr_sync) - break; - - IWL_ERR(mvm, "mac start retry %d\n", retry); - } + ret = __iwl_mvm_mac_start(mvm); clear_bit(IWL_MVM_STATUS_STARTING, &mvm->status); mutex_unlock(&mvm->mutex); -- cgit v1.2.3 From 6c8ce23854b66db94d88e0957e531cb074806c16 Mon Sep 17 00:00:00 2001 From: Miri Korenblit Date: Tue, 23 Jan 2024 20:08:16 +0200 Subject: wifi: iwlwifi: change link id in time event to s8 Link ID in time event data is -1 when the time event is cleared. Change the type of the link ID in the time event data structure and in the affected function from unsigned to signed. Fixes: 135065837310 ("wifi: iwlwifi: support link_id in SESSION_PROTECTION cmd") Signed-off-by: Miri Korenblit Reviewed-by: Gregory Greenman Link: https://msgid.link/20240123200528.50d4941f946c.Iea990b118c69bc3e1eb61c1d134c9d470b3a17ac@changeid Signed-off-by: Johannes Berg --- drivers/net/wireless/intel/iwlwifi/mvm/mvm.h | 2 +- drivers/net/wireless/intel/iwlwifi/mvm/time-event.c | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h b/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h index 40627961b834..997f0395b97a 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h +++ b/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h @@ -121,7 +121,7 @@ struct iwl_mvm_time_event_data { * if the te is in the time event list or not (when id == TE_MAX) */ u32 id; - u8 link_id; + s8 link_id; }; /* Power management */ diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/time-event.c b/drivers/net/wireless/intel/iwlwifi/mvm/time-event.c index 218fdf1ed530..aceab96bcb97 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/time-event.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/time-event.c @@ -692,7 +692,7 @@ void iwl_mvm_protect_session(struct iwl_mvm *mvm, /* Determine whether mac or link id should be used, and validate the link id */ static int iwl_mvm_get_session_prot_id(struct iwl_mvm *mvm, struct ieee80211_vif *vif, - u32 link_id) + s8 link_id) { struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); int ver = iwl_fw_lookup_cmd_ver(mvm->fw, @@ -716,7 +716,7 @@ static int iwl_mvm_get_session_prot_id(struct iwl_mvm *mvm, static void iwl_mvm_cancel_session_protection(struct iwl_mvm *mvm, struct ieee80211_vif *vif, - u32 id, u32 link_id) + u32 id, s8 link_id) { int mac_link_id = iwl_mvm_get_session_prot_id(mvm, vif, link_id); struct iwl_mvm_session_prot_cmd cmd = { @@ -745,7 +745,7 @@ static bool __iwl_mvm_remove_time_event(struct iwl_mvm *mvm, struct ieee80211_vif *vif = te_data->vif; struct iwl_mvm_vif *mvmvif; enum nl80211_iftype iftype; - unsigned int link_id; + s8 link_id; if (!vif) return false; @@ -1296,7 +1296,7 @@ void iwl_mvm_schedule_session_protection(struct iwl_mvm *mvm, struct iwl_mvm_time_event_data *te_data = &mvmvif->time_event_data; const u16 notif[] = { WIDE_ID(MAC_CONF_GROUP, SESSION_PROTECTION_NOTIF) }; struct iwl_notification_wait wait_notif; - int mac_link_id = iwl_mvm_get_session_prot_id(mvm, vif, link_id); + int mac_link_id = iwl_mvm_get_session_prot_id(mvm, vif, (s8)link_id); struct iwl_mvm_session_prot_cmd cmd = { .id_and_color = cpu_to_le32(mac_link_id), .action = cpu_to_le32(FW_CTXT_ACTION_ADD), -- cgit v1.2.3 From 77b8b078440eb136efd03427404134e1d88dca50 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Tue, 23 Jan 2024 20:08:17 +0200 Subject: wifi: iwlwifi: nvm-parse: advertise common packet padding MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit We should - at least for now - advertise common nominal packet padding of 16µs instead of the more specific PPE thresholds. Signed-off-by: Johannes Berg Reviewed-by: Gregory Greenman Signed-off-by: Miri Korenblit Link: https://msgid.link/20240123200528.4312e176dfdc.Ide75980ff57257a31e86e6ac5948a8f97aaab577@changeid Signed-off-by: Johannes Berg --- drivers/net/wireless/intel/iwlwifi/iwl-nvm-parse.c | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/intel/iwlwifi/iwl-nvm-parse.c b/drivers/net/wireless/intel/iwlwifi/iwl-nvm-parse.c index 8e6ce484db87..a7152d65eefa 100644 --- a/drivers/net/wireless/intel/iwlwifi/iwl-nvm-parse.c +++ b/drivers/net/wireless/intel/iwlwifi/iwl-nvm-parse.c @@ -696,10 +696,11 @@ static const struct ieee80211_sband_iftype_data iwl_he_eht_capa[] = { IEEE80211_EHT_PHY_CAP4_POWER_BOOST_FACT_SUPP | IEEE80211_EHT_PHY_CAP4_EHT_MU_PPDU_4_EHT_LTF_08_GI, .phy_cap_info[5] = + FIELD_PREP_CONST(IEEE80211_EHT_PHY_CAP5_COMMON_NOMINAL_PKT_PAD_MASK, + IEEE80211_EHT_PHY_CAP5_COMMON_NOMINAL_PKT_PAD_16US) | IEEE80211_EHT_PHY_CAP5_NON_TRIG_CQI_FEEDBACK | IEEE80211_EHT_PHY_CAP5_TX_LESS_242_TONE_RU_SUPP | - IEEE80211_EHT_PHY_CAP5_RX_LESS_242_TONE_RU_SUPP | - IEEE80211_EHT_PHY_CAP5_PPE_THRESHOLD_PRESENT, + IEEE80211_EHT_PHY_CAP5_RX_LESS_242_TONE_RU_SUPP, .phy_cap_info[6] = IEEE80211_EHT_PHY_CAP6_MCS15_SUPP_MASK | IEEE80211_EHT_PHY_CAP6_EHT_DUP_6GHZ_SUPP, @@ -733,6 +734,9 @@ static const struct ieee80211_sband_iftype_data iwl_he_eht_capa[] = { /* * PPE thresholds for NSS = 2, and RU index bitmap set * to 0xc. + * Note: just for stating what we want, not present in + * the transmitted data due to not including + * IEEE80211_EHT_PHY_CAP5_PPE_THRESHOLD_PRESENT. */ .eht_ppe_thres = {0xc1, 0x0e, 0xe0 } }, @@ -801,7 +805,8 @@ static const struct ieee80211_sband_iftype_data iwl_he_eht_capa[] = { IEEE80211_EHT_PHY_CAP0_242_TONE_RU_GT20MHZ | IEEE80211_EHT_PHY_CAP0_NDP_4_EHT_LFT_32_GI, .phy_cap_info[5] = - IEEE80211_EHT_PHY_CAP5_PPE_THRESHOLD_PRESENT, + FIELD_PREP_CONST(IEEE80211_EHT_PHY_CAP5_COMMON_NOMINAL_PKT_PAD_MASK, + IEEE80211_EHT_PHY_CAP5_COMMON_NOMINAL_PKT_PAD_16US), }, /* For all MCS and bandwidth, set 2 NSS for both Tx and @@ -829,6 +834,9 @@ static const struct ieee80211_sband_iftype_data iwl_he_eht_capa[] = { /* * PPE thresholds for NSS = 2, and RU index bitmap set * to 0xc. + * Note: just for stating what we want, not present in + * the transmitted data due to not including + * IEEE80211_EHT_PHY_CAP5_PPE_THRESHOLD_PRESENT. */ .eht_ppe_thres = {0xc1, 0x0e, 0xe0 } }, -- cgit v1.2.3 From 22d9987c79cb8d1d04625cde5f63fc01abae2b6a Mon Sep 17 00:00:00 2001 From: Benjamin Berg Date: Tue, 23 Jan 2024 20:08:18 +0200 Subject: wifi: iwlwifi: skip affinity setting on non-SMP Without SMP the function is just a stub that returns an error code. Add a compile time check for CONFIG_SMP in the interest of not logging an error if setting affinity is not possible anyway. Signed-off-by: Benjamin Berg Reviewed-by: Gregory Greenman Reviewed-by: Johannes Berg Signed-off-by: Miri Korenblit Link: https://msgid.link/20240123200528.ed9094390731.Ic4e5e019c01fd4231b99cf4919af5d19d6353869@changeid Signed-off-by: Johannes Berg --- drivers/net/wireless/intel/iwlwifi/pcie/trans.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'drivers/net') diff --git a/drivers/net/wireless/intel/iwlwifi/pcie/trans.c b/drivers/net/wireless/intel/iwlwifi/pcie/trans.c index 63e13577aff8..b5756e168f49 100644 --- a/drivers/net/wireless/intel/iwlwifi/pcie/trans.c +++ b/drivers/net/wireless/intel/iwlwifi/pcie/trans.c @@ -1718,6 +1718,7 @@ enable_msi: static void iwl_pcie_irq_set_affinity(struct iwl_trans *trans) { +#if defined(CONFIG_SMP) int iter_rx_q, i, ret, cpu, offset; struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans); @@ -1738,6 +1739,7 @@ static void iwl_pcie_irq_set_affinity(struct iwl_trans *trans) "Failed to set affinity mask for IRQ %d\n", trans_pcie->msix_entries[i].vector); } +#endif } static int iwl_pcie_init_msix_handler(struct pci_dev *pdev, -- cgit v1.2.3 From 38d84aaed52832945887ae8618bed68c89a3bf81 Mon Sep 17 00:00:00 2001 From: Emmanuel Grumbach Date: Tue, 23 Jan 2024 20:08:20 +0200 Subject: wifi: iwlwifi: mvm: introduce PHY_CONTEXT_CMD_API_VER_5 This command version adds two news fields: sbb_bandwidth and sbb_ctrl_channel_loc They will be populated later. Signed-off-by: Emmanuel Grumbach Reviewed-by: Johannes Berg Reviewed-by: Gregory Greenman Signed-off-by: Miri Korenblit Link: https://msgid.link/20240123200528.82ab4140fff9.Icfba4819fe0b7ac8219ab671c632e25f5fbbaf6f@changeid Signed-off-by: Johannes Berg --- drivers/net/wireless/intel/iwlwifi/fw/api/phy-ctxt.h | 16 ++++++++++++++-- drivers/net/wireless/intel/iwlwifi/mvm/phy-ctxt.c | 2 +- 2 files changed, 15 insertions(+), 3 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/intel/iwlwifi/fw/api/phy-ctxt.h b/drivers/net/wireless/intel/iwlwifi/fw/api/phy-ctxt.h index 306ed88de463..205d0413e626 100644 --- a/drivers/net/wireless/intel/iwlwifi/fw/api/phy-ctxt.h +++ b/drivers/net/wireless/intel/iwlwifi/fw/api/phy-ctxt.h @@ -142,6 +142,8 @@ struct iwl_phy_context_cmd_v1 { * @lmac_id: the lmac id the phy context belongs to * @ci: channel info * @rxchain_info: ??? + * @sbb_bandwidth: 0 disabled, 1 - 40Mhz ... 4 - 320MHz + * @sbb_ctrl_channel_loc: location of the control channel * @dsp_cfg_flags: set to 0 * @reserved: reserved to align to 64 bit */ @@ -152,9 +154,19 @@ struct iwl_phy_context_cmd { /* PHY_CONTEXT_DATA_API_S_VER_3, PHY_CONTEXT_DATA_API_S_VER_4 */ struct iwl_fw_channel_info ci; __le32 lmac_id; - __le32 rxchain_info; /* reserved in _VER_4 */ + union { + __le32 rxchain_info; /* reserved in _VER_4 */ + struct { /* used for _VER_5 */ + u8 sbb_bandwidth; + u8 sbb_ctrl_channel_loc; + __le16 reserved; + } v5; + }; __le32 dsp_cfg_flags; __le32 reserved; -} __packed; /* PHY_CONTEXT_CMD_API_VER_3, PHY_CONTEXT_CMD_API_VER_4 */ +} __packed; /* PHY_CONTEXT_CMD_API_VER_3, + * PHY_CONTEXT_CMD_API_VER_4, + * PHY_CONTEXT_CMD_API_VER_5 + */ #endif /* __iwl_fw_api_phy_ctxt_h__ */ diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/phy-ctxt.c b/drivers/net/wireless/intel/iwlwifi/mvm/phy-ctxt.c index 334d1f59f6e4..8bf778503b74 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/phy-ctxt.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/phy-ctxt.c @@ -204,7 +204,7 @@ static int iwl_mvm_phy_ctxt_apply(struct iwl_mvm *mvm, int ret; int ver = iwl_fw_lookup_cmd_ver(mvm->fw, PHY_CONTEXT_CMD, 1); - if (ver == 3 || ver == 4) { + if (ver >= 3 && ver <= 5) { struct iwl_phy_context_cmd cmd = {}; /* Set the command header fields */ -- cgit v1.2.3 From 289f57bbef09b0a2385a5187274e37d76031de14 Mon Sep 17 00:00:00 2001 From: Gregory Greenman Date: Tue, 23 Jan 2024 20:08:21 +0200 Subject: wifi: iwlwifi: bump FW API to 87 for AX/BZ/SC devices Start supporting API version 87 for new devices. Signed-off-by: Gregory Greenman Signed-off-by: Miri Korenblit Link: https://msgid.link/20240123200528.14cc41da34c4.Ic867f979504c60c21c8182e9adccec9ffbadfe5b@changeid Signed-off-by: Johannes Berg --- drivers/net/wireless/intel/iwlwifi/cfg/ax210.c | 2 +- drivers/net/wireless/intel/iwlwifi/cfg/bz.c | 2 +- drivers/net/wireless/intel/iwlwifi/cfg/sc.c | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/intel/iwlwifi/cfg/ax210.c b/drivers/net/wireless/intel/iwlwifi/cfg/ax210.c index 134635c70ce8..02b727687fb8 100644 --- a/drivers/net/wireless/intel/iwlwifi/cfg/ax210.c +++ b/drivers/net/wireless/intel/iwlwifi/cfg/ax210.c @@ -10,7 +10,7 @@ #include "fw/api/txq.h" /* Highest firmware API version supported */ -#define IWL_AX210_UCODE_API_MAX 86 +#define IWL_AX210_UCODE_API_MAX 87 /* Lowest firmware API version supported */ #define IWL_AX210_UCODE_API_MIN 59 diff --git a/drivers/net/wireless/intel/iwlwifi/cfg/bz.c b/drivers/net/wireless/intel/iwlwifi/cfg/bz.c index 21fdaf8e0e0e..20799a0fbc07 100644 --- a/drivers/net/wireless/intel/iwlwifi/cfg/bz.c +++ b/drivers/net/wireless/intel/iwlwifi/cfg/bz.c @@ -10,7 +10,7 @@ #include "fw/api/txq.h" /* Highest firmware API version supported */ -#define IWL_BZ_UCODE_API_MAX 86 +#define IWL_BZ_UCODE_API_MAX 87 /* Lowest firmware API version supported */ #define IWL_BZ_UCODE_API_MIN 80 diff --git a/drivers/net/wireless/intel/iwlwifi/cfg/sc.c b/drivers/net/wireless/intel/iwlwifi/cfg/sc.c index 80eb9b499538..51b8f50d8795 100644 --- a/drivers/net/wireless/intel/iwlwifi/cfg/sc.c +++ b/drivers/net/wireless/intel/iwlwifi/cfg/sc.c @@ -10,7 +10,7 @@ #include "fw/api/txq.h" /* Highest firmware API version supported */ -#define IWL_SC_UCODE_API_MAX 86 +#define IWL_SC_UCODE_API_MAX 87 /* Lowest firmware API version supported */ #define IWL_SC_UCODE_API_MIN 82 -- cgit v1.2.3 From c4d32f2745c75c9041937767f0329f6f1051778b Mon Sep 17 00:00:00 2001 From: Miri Korenblit Date: Tue, 23 Jan 2024 20:08:22 +0200 Subject: wifi: iwlwifi: implement can_activate_links callback This callback checks if a given bitmap of active_links will be supported by the driver or not. Signed-off-by: Miri Korenblit Reviewed-by: Gregory Greenman Reviewed-by: Johannes Berg Link: https://msgid.link/20240123200528.a26fd48bfe3d.I03ae6b4c7fd24e8701660a68cec9403dc3469a0e@changeid Signed-off-by: Johannes Berg --- drivers/net/wireless/intel/iwlwifi/mvm/mld-mac80211.c | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/mld-mac80211.c b/drivers/net/wireless/intel/iwlwifi/mvm/mld-mac80211.c index 61170173f917..449229ced3bb 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/mld-mac80211.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/mld-mac80211.c @@ -253,9 +253,6 @@ __iwl_mvm_mld_assign_vif_chanctx(struct iwl_mvm *mvm, if (!rcu_access_pointer(link_conf->chanctx_conf)) n_active++; - if (n_active > iwl_mvm_max_active_links(mvm, vif)) - return -EOPNOTSUPP; - if (WARN_ON_ONCE(!mvmvif->link[link_id])) return -EINVAL; @@ -1121,17 +1118,12 @@ iwl_mvm_mld_change_vif_links(struct ieee80211_hw *hw, struct ieee80211_bss_conf *old[IEEE80211_MLD_MAX_NUM_LINKS]) { struct iwl_mvm_vif_link_info *new_link[IEEE80211_MLD_MAX_NUM_LINKS] = {}; - unsigned int n_active = iwl_mvm_mld_count_active_links(vif); struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw); u16 removed = old_links & ~new_links; u16 added = new_links & ~old_links; int err, i; - if (hweight16(new_links) > 1 && - n_active > iwl_mvm_max_active_links(mvm, vif)) - return -EOPNOTSUPP; - for (i = 0; i < IEEE80211_MLD_MAX_NUM_LINKS; i++) { int r; @@ -1223,6 +1215,15 @@ iwl_mvm_mld_change_sta_links(struct ieee80211_hw *hw, return ret; } +static bool iwl_mvm_mld_can_activate_links(struct ieee80211_hw *hw, + struct ieee80211_vif *vif, + u16 desired_links) +{ + struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw); + + return hweight16(desired_links) <= iwl_mvm_max_active_links(mvm, vif); +} + const struct ieee80211_ops iwl_mvm_mld_hw_ops = { .tx = iwl_mvm_mac_tx, .wake_tx_queue = iwl_mvm_mac_wake_tx_queue, @@ -1317,4 +1318,5 @@ const struct ieee80211_ops iwl_mvm_mld_hw_ops = { .change_vif_links = iwl_mvm_mld_change_vif_links, .change_sta_links = iwl_mvm_mld_change_sta_links, + .can_activate_links = iwl_mvm_mld_can_activate_links, }; -- cgit v1.2.3 From fdccafad7e9b49e75fb484c5aa29954d34f3c63a Mon Sep 17 00:00:00 2001 From: Miri Korenblit Date: Tue, 23 Jan 2024 20:08:23 +0200 Subject: wifi: iwlwifi: add support for a wiphy_work rx handler The wiphy_work infra ensures that the entire worker will run with the wiphy mutex. It is useful to have RX handlers running as a wiphy_work, when we don't want the handler to run in parallel with mac80211 work (to avoid races). For example - BT notification can disable eSR starting from the next patch. In ieee80211_set_active_links we first check that eSR is allowed, (drv_can_activate_links) and then activate it. If the BT notif was received after drv_can_activate_links (which returned true), and before the activation - eSR will be activated when it shouldn't. If BT notif is handled with the wiphy mutex, it can't run in parallel to ieee80211_set_active_links, which also holds that mutex. Add the necessary infrastructure here, for use in the next commit. Signed-off-by: Miri Korenblit Reviewed-by: Gregory Greenman Reviewed-by: Johannes Berg Link: https://msgid.link/20240123200528.ce83d16cdec8.I35ef53fa23f58b9ec17924099238b61deafcecd7@changeid Signed-off-by: Johannes Berg --- drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c | 1 + drivers/net/wireless/intel/iwlwifi/mvm/mvm.h | 3 ++ drivers/net/wireless/intel/iwlwifi/mvm/ops.c | 61 +++++++++++++++++++---- 3 files changed, 54 insertions(+), 11 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c b/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c index 6bbcf4092f52..406956574f52 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c @@ -1342,6 +1342,7 @@ void iwl_mvm_mac_stop(struct ieee80211_hw *hw) * discover that its list is now empty. */ cancel_work_sync(&mvm->async_handlers_wk); + wiphy_work_cancel(hw->wiphy, &mvm->async_handlers_wiphy_wk); } struct iwl_mvm_phy_ctxt *iwl_mvm_get_free_phy_ctxt(struct iwl_mvm *mvm) diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h b/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h index 997f0395b97a..af5c8b4bb5a6 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h +++ b/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h @@ -848,6 +848,9 @@ struct iwl_mvm { spinlock_t async_handlers_lock; struct work_struct async_handlers_wk; + /* For async rx handlers that require the wiphy lock */ + struct wiphy_work async_handlers_wiphy_wk; + struct work_struct roc_done_wk; unsigned long init_status; diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/ops.c b/drivers/net/wireless/intel/iwlwifi/mvm/ops.c index adbbe19aeae5..38a84a54ff78 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/ops.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/ops.c @@ -267,11 +267,15 @@ static void iwl_mvm_rx_thermal_dual_chain_req(struct iwl_mvm *mvm, * it will be called from a worker with mvm->mutex held. * @RX_HANDLER_ASYNC_UNLOCKED : in case the handler needs to lock the * mutex itself, it will be called from a worker without mvm->mutex held. + * @RX_HANDLER_ASYNC_LOCKED_WIPHY: If the handler needs to hold the wiphy lock + * and mvm->mutex. Will be handled with the wiphy_work queue infra + * instead of regular work queue. */ enum iwl_rx_handler_context { RX_HANDLER_SYNC, RX_HANDLER_ASYNC_LOCKED, RX_HANDLER_ASYNC_UNLOCKED, + RX_HANDLER_ASYNC_LOCKED_WIPHY, }; /** @@ -673,6 +677,8 @@ static const struct iwl_hcmd_arr iwl_mvm_groups[] = { /* this forward declaration can avoid to export the function */ static void iwl_mvm_async_handlers_wk(struct work_struct *wk); +static void iwl_mvm_async_handlers_wiphy_wk(struct wiphy *wiphy, + struct wiphy_work *work); static u32 iwl_mvm_min_backoff(struct iwl_mvm *mvm) { @@ -1265,6 +1271,8 @@ iwl_op_mode_mvm_start(struct iwl_trans *trans, const struct iwl_cfg *cfg, INIT_LIST_HEAD(&mvm->add_stream_txqs); spin_lock_init(&mvm->add_stream_lock); + wiphy_work_init(&mvm->async_handlers_wiphy_wk, + iwl_mvm_async_handlers_wiphy_wk); init_waitqueue_head(&mvm->rx_sync_waitq); mvm->queue_sync_state = 0; @@ -1551,35 +1559,62 @@ void iwl_mvm_async_handlers_purge(struct iwl_mvm *mvm) spin_unlock_bh(&mvm->async_handlers_lock); } -static void iwl_mvm_async_handlers_wk(struct work_struct *wk) +/* + * This function receives a bitmap of rx async handler contexts + * (&iwl_rx_handler_context) to handle, and runs only them + */ +static void iwl_mvm_async_handlers_by_context(struct iwl_mvm *mvm, + u8 contexts) { - struct iwl_mvm *mvm = - container_of(wk, struct iwl_mvm, async_handlers_wk); struct iwl_async_handler_entry *entry, *tmp; LIST_HEAD(local_list); - /* Ensure that we are not in stop flow (check iwl_mvm_mac_stop) */ - /* - * Sync with Rx path with a lock. Remove all the entries from this list, - * add them to a local one (lock free), and then handle them. + * Sync with Rx path with a lock. Remove all the entries of the + * wanted contexts from this list, add them to a local one (lock free), + * and then handle them. */ spin_lock_bh(&mvm->async_handlers_lock); - list_splice_init(&mvm->async_handlers_list, &local_list); + list_for_each_entry_safe(entry, tmp, &mvm->async_handlers_list, list) { + if (!(BIT(entry->context) & contexts)) + continue; + list_del(&entry->list); + list_add_tail(&entry->list, &local_list); + } spin_unlock_bh(&mvm->async_handlers_lock); list_for_each_entry_safe(entry, tmp, &local_list, list) { - if (entry->context == RX_HANDLER_ASYNC_LOCKED) + if (entry->context != RX_HANDLER_ASYNC_UNLOCKED) mutex_lock(&mvm->mutex); entry->fn(mvm, &entry->rxb); iwl_free_rxb(&entry->rxb); list_del(&entry->list); - if (entry->context == RX_HANDLER_ASYNC_LOCKED) + if (entry->context != RX_HANDLER_ASYNC_UNLOCKED) mutex_unlock(&mvm->mutex); kfree(entry); } } +static void iwl_mvm_async_handlers_wiphy_wk(struct wiphy *wiphy, + struct wiphy_work *wk) +{ + struct iwl_mvm *mvm = + container_of(wk, struct iwl_mvm, async_handlers_wiphy_wk); + u8 contexts = BIT(RX_HANDLER_ASYNC_LOCKED_WIPHY); + + iwl_mvm_async_handlers_by_context(mvm, contexts); +} + +static void iwl_mvm_async_handlers_wk(struct work_struct *wk) +{ + struct iwl_mvm *mvm = + container_of(wk, struct iwl_mvm, async_handlers_wk); + u8 contexts = BIT(RX_HANDLER_ASYNC_LOCKED) | + BIT(RX_HANDLER_ASYNC_UNLOCKED); + + iwl_mvm_async_handlers_by_context(mvm, contexts); +} + static inline void iwl_mvm_rx_check_trigger(struct iwl_mvm *mvm, struct iwl_rx_packet *pkt) { @@ -1659,7 +1694,11 @@ static void iwl_mvm_rx_common(struct iwl_mvm *mvm, spin_lock(&mvm->async_handlers_lock); list_add_tail(&entry->list, &mvm->async_handlers_list); spin_unlock(&mvm->async_handlers_lock); - schedule_work(&mvm->async_handlers_wk); + if (rx_h->context == RX_HANDLER_ASYNC_LOCKED_WIPHY) + wiphy_work_queue(mvm->hw->wiphy, + &mvm->async_handlers_wiphy_wk); + else + schedule_work(&mvm->async_handlers_wk); break; } } -- cgit v1.2.3 From 26f0dc8a705ae182eaa126cef0a9870d1a87a5ac Mon Sep 17 00:00:00 2001 From: Arend van Spriel Date: Sun, 28 Jan 2024 10:30:56 +0100 Subject: wifi: brcmfmac: add linefeed at end of file The following sparse warning was reported: drivers/net/wireless/broadcom/brcm80211/brcmfmac/fwil.c:432:49: warning: no newline at end of file Fixes: 31343230abb1 ("wifi: brcmfmac: export firmware interface functions") Reported-by: Jakub Kicinski Closes: https://lore.kernel.org/all/20240125165128.7e43a1f3@kernel.org/ Signed-off-by: Arend van Spriel Signed-off-by: Kalle Valo Link: https://msgid.link/20240128093057.164791-2-arend.vanspriel@broadcom.com --- drivers/net/wireless/broadcom/brcm80211/brcmfmac/fwil.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/fwil.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/fwil.c index bc1c6b5a6e31..6385a7db7f7d 100644 --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/fwil.c +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/fwil.c @@ -429,4 +429,4 @@ s32 brcmf_fil_xtlv_data_get(struct brcmf_if *ifp, const char *name, u16 id, mutex_unlock(&drvr->proto_block); return err; } -BRCMF_EXPORT_SYMBOL_GPL(brcmf_fil_xtlv_data_get); \ No newline at end of file +BRCMF_EXPORT_SYMBOL_GPL(brcmf_fil_xtlv_data_get); -- cgit v1.2.3 From 57b9426952c46f8d0aa7fad27fe55403fb28974f Mon Sep 17 00:00:00 2001 From: Ping-Ke Shih Date: Sun, 21 Jan 2024 15:18:23 +0800 Subject: wifi: rtw89: pci: update SER timer unit and timeout time Be higher resolution of SER timer unit from 32ms to 16ms to detect abnormal situation more accurately, and set hardware watchdog timer to 4ms. Signed-off-by: Ping-Ke Shih Signed-off-by: Kalle Valo Link: https://msgid.link/20240121071826.10159-2-pkshih@realtek.com --- drivers/net/wireless/realtek/rtw89/pci_be.c | 5 +++++ drivers/net/wireless/realtek/rtw89/reg.h | 3 +++ 2 files changed, 8 insertions(+) (limited to 'drivers/net') diff --git a/drivers/net/wireless/realtek/rtw89/pci_be.c b/drivers/net/wireless/realtek/rtw89/pci_be.c index 629ffa4bee91..5c9e39357773 100644 --- a/drivers/net/wireless/realtek/rtw89/pci_be.c +++ b/drivers/net/wireless/realtek/rtw89/pci_be.c @@ -105,6 +105,10 @@ static void rtw89_pci_ctrl_trxdma_pcie_be(struct rtw89_dev *rtwdev, val |= B_BE_STOP_AXI_MST; rtw89_write32(rtwdev, R_BE_HAXI_INIT_CFG1, val); + + if (io_en == MAC_AX_PCIE_ENABLE) + rtw89_write32_mask(rtwdev, R_BE_HAXI_MST_WDT_TIMEOUT_SEL_V1, + B_BE_HAXI_MST_WDT_TIMEOUT_SEL_MASK, 4); } static void rtw89_pci_clr_idx_all_be(struct rtw89_dev *rtwdev) @@ -257,6 +261,7 @@ static void rtw89_pci_ser_setting_be(struct rtw89_dev *rtwdev) rtw89_write32(rtwdev, R_BE_PL1_DBG_INFO, 0x0); rtw89_write32_set(rtwdev, R_BE_FWS1IMR, B_BE_PCIE_SER_TIMEOUT_INDIC_EN); rtw89_write32_set(rtwdev, R_BE_SER_PL1_CTRL, B_BE_PL1_SER_PL1_EN); + rtw89_write32_mask(rtwdev, R_BE_SER_PL1_CTRL, B_BE_PL1_TIMER_UNIT_MASK, 1); val32 = rtw89_read32(rtwdev, R_BE_REG_PL1_MASK); val32 |= B_BE_SER_PMU_IMR | B_BE_SER_L1SUB_IMR | B_BE_SER_PM_MASTER_IMR | diff --git a/drivers/net/wireless/realtek/rtw89/reg.h b/drivers/net/wireless/realtek/rtw89/reg.h index acc96d30d085..ec2559bde092 100644 --- a/drivers/net/wireless/realtek/rtw89/reg.h +++ b/drivers/net/wireless/realtek/rtw89/reg.h @@ -5800,6 +5800,9 @@ #define B_BE_STOP_CH1 BIT(1) #define B_BE_STOP_CH0 BIT(0) +#define R_BE_HAXI_MST_WDT_TIMEOUT_SEL_V1 0xB02C +#define B_BE_HAXI_MST_WDT_TIMEOUT_SEL_MASK GENMASK(4, 0) + #define R_BE_HAXI_IDCT_MSK 0xB0B8 #define B_BE_HAXI_RRESP_ERR_IDCT_MSK BIT(7) #define B_BE_HAXI_BRESP_ERR_IDCT_MSK BIT(6) -- cgit v1.2.3 From 26cdaee43dc5f9c9d0c5429b365b8f094afad717 Mon Sep 17 00:00:00 2001 From: Zong-Zhe Yang Date: Sun, 21 Jan 2024 15:18:24 +0800 Subject: wifi: rtw89: pci: interrupt v2 refine IMR for SER During SER (system error recovery), expect to deal with only ISR related to halt. So, refine IMR configuration. Signed-off-by: Zong-Zhe Yang Signed-off-by: Ping-Ke Shih Signed-off-by: Kalle Valo Link: https://msgid.link/20240121071826.10159-3-pkshih@realtek.com --- drivers/net/wireless/realtek/rtw89/pci.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/realtek/rtw89/pci.c b/drivers/net/wireless/realtek/rtw89/pci.c index 9943ed856248..8227dc55e818 100644 --- a/drivers/net/wireless/realtek/rtw89/pci.c +++ b/drivers/net/wireless/realtek/rtw89/pci.c @@ -705,7 +705,7 @@ void rtw89_pci_recognize_intrs_v2(struct rtw89_dev *rtwdev, rtw89_read32(rtwdev, R_BE_HISR0) & rtwpci->halt_c2h_intrs : 0; isrs->isrs[0] = isrs->ind_isrs & B_BE_HCI_AXIDMA_INT ? rtw89_read32(rtwdev, R_BE_HAXI_HISR00) & rtwpci->intrs[0] : 0; - isrs->isrs[1] = rtw89_read32(rtwdev, R_BE_PCIE_DMA_ISR); + isrs->isrs[1] = rtw89_read32(rtwdev, R_BE_PCIE_DMA_ISR) & rtwpci->intrs[1]; if (isrs->halt_c2h_isrs) rtw89_write32(rtwdev, R_BE_HISR0, isrs->halt_c2h_isrs); @@ -3452,8 +3452,7 @@ static void rtw89_pci_recovery_intr_mask_v2(struct rtw89_dev *rtwdev) rtwpci->ind_intrs = B_BE_HS0_IND_INT_EN0; rtwpci->halt_c2h_intrs = B_BE_HALT_C2H_INT_EN | B_BE_WDT_TIMEOUT_INT_EN; rtwpci->intrs[0] = 0; - rtwpci->intrs[1] = B_BE_PCIE_RX_RX0P2_IMR0_V1 | - B_BE_PCIE_RX_RPQ0_IMR0_V1; + rtwpci->intrs[1] = 0; } static void rtw89_pci_default_intr_mask_v2(struct rtw89_dev *rtwdev) -- cgit v1.2.3 From 0bc7d1d4e63cf31ff1b4396b0e2f0e3c76828d26 Mon Sep 17 00:00:00 2001 From: Ping-Ke Shih Date: Sun, 21 Jan 2024 15:18:25 +0800 Subject: wifi: rtw89: pci: validate RX tag for RXQ and RPQ PCI RX ring is a kind of read/write index ring, and DMA and ring index are asynchronous, so suddenly driver gets newer index ahead before DMA. To resolve this rare situation, we use a RX tag as helpers to make sure DMA is done. The RX tag is a 13-bit value, and range is from 1 ~ 0x1FFF, but 0 isn't used so should be skipped. Only enable this validation to coming WiFi 7 chips, because existing chips use different design and don't really meet this situation. Add missed rx_ring_eq_is_full for 8851BE by the way. Signed-off-by: Ping-Ke Shih Signed-off-by: Kalle Valo Link: https://msgid.link/20240121071826.10159-4-pkshih@realtek.com --- drivers/net/wireless/realtek/rtw89/pci.c | 60 +++++++++++++++++++++++--- drivers/net/wireless/realtek/rtw89/pci.h | 4 +- drivers/net/wireless/realtek/rtw89/rtw8851be.c | 2 + drivers/net/wireless/realtek/rtw89/rtw8852ae.c | 1 + drivers/net/wireless/realtek/rtw89/rtw8852be.c | 1 + drivers/net/wireless/realtek/rtw89/rtw8852ce.c | 1 + drivers/net/wireless/realtek/rtw89/rtw8922ae.c | 1 + 7 files changed, 63 insertions(+), 7 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/realtek/rtw89/pci.c b/drivers/net/wireless/realtek/rtw89/pci.c index 8227dc55e818..b51ec3cbc715 100644 --- a/drivers/net/wireless/realtek/rtw89/pci.c +++ b/drivers/net/wireless/realtek/rtw89/pci.c @@ -155,8 +155,8 @@ static void rtw89_pci_sync_skb_for_device(struct rtw89_dev *rtwdev, DMA_FROM_DEVICE); } -static int rtw89_pci_rxbd_info_update(struct rtw89_dev *rtwdev, - struct sk_buff *skb) +static void rtw89_pci_rxbd_info_update(struct rtw89_dev *rtwdev, + struct sk_buff *skb) { struct rtw89_pci_rxbd_info *rxbd_info; struct rtw89_pci_rx_info *rx_info = RTW89_PCI_RX_SKB_CB(skb); @@ -166,10 +166,58 @@ static int rtw89_pci_rxbd_info_update(struct rtw89_dev *rtwdev, rx_info->ls = le32_get_bits(rxbd_info->dword, RTW89_PCI_RXBD_LS); rx_info->len = le32_get_bits(rxbd_info->dword, RTW89_PCI_RXBD_WRITE_SIZE); rx_info->tag = le32_get_bits(rxbd_info->dword, RTW89_PCI_RXBD_TAG); +} + +static int rtw89_pci_validate_rx_tag(struct rtw89_dev *rtwdev, + struct rtw89_pci_rx_ring *rx_ring, + struct sk_buff *skb) +{ + struct rtw89_pci_rx_info *rx_info = RTW89_PCI_RX_SKB_CB(skb); + const struct rtw89_pci_info *info = rtwdev->pci_info; + u32 target_rx_tag; + + if (!info->check_rx_tag) + return 0; + + /* valid range is 1 ~ 0x1FFF */ + if (rx_ring->target_rx_tag == 0) + target_rx_tag = 1; + else + target_rx_tag = rx_ring->target_rx_tag; + + if (rx_info->tag != target_rx_tag) { + rtw89_debug(rtwdev, RTW89_DBG_UNEXP, "mismatch RX tag 0x%x 0x%x\n", + rx_info->tag, target_rx_tag); + return -EAGAIN; + } return 0; } +static +int rtw89_pci_sync_skb_for_device_and_validate_rx_info(struct rtw89_dev *rtwdev, + struct rtw89_pci_rx_ring *rx_ring, + struct sk_buff *skb) +{ + struct rtw89_pci_rx_info *rx_info = RTW89_PCI_RX_SKB_CB(skb); + int rx_tag_retry = 100; + int ret; + + do { + rtw89_pci_sync_skb_for_cpu(rtwdev, skb); + rtw89_pci_rxbd_info_update(rtwdev, skb); + + ret = rtw89_pci_validate_rx_tag(rtwdev, rx_ring, skb); + if (ret != -EAGAIN) + break; + } while (rx_tag_retry--); + + /* update target rx_tag for next RX */ + rx_ring->target_rx_tag = rx_info->tag + 1; + + return ret; +} + static void rtw89_pci_ctrl_txdma_ch_pcie(struct rtw89_dev *rtwdev, bool enable) { const struct rtw89_pci_info *info = rtwdev->pci_info; @@ -259,9 +307,8 @@ static u32 rtw89_pci_rxbd_deliver_skbs(struct rtw89_dev *rtwdev, skb_idx = rtw89_pci_get_rx_skb_idx(rtwdev, bd_ring); skb = rx_ring->buf[skb_idx]; - rtw89_pci_sync_skb_for_cpu(rtwdev, skb); - ret = rtw89_pci_rxbd_info_update(rtwdev, skb); + ret = rtw89_pci_sync_skb_for_device_and_validate_rx_info(rtwdev, rx_ring, skb); if (ret) { rtw89_err(rtwdev, "failed to update %d RXBD info: %d\n", bd_ring->wp, ret); @@ -549,9 +596,8 @@ static u32 rtw89_pci_release_tx_skbs(struct rtw89_dev *rtwdev, skb_idx = rtw89_pci_get_rx_skb_idx(rtwdev, bd_ring); skb = rx_ring->buf[skb_idx]; - rtw89_pci_sync_skb_for_cpu(rtwdev, skb); - ret = rtw89_pci_rxbd_info_update(rtwdev, skb); + ret = rtw89_pci_sync_skb_for_device_and_validate_rx_info(rtwdev, rx_ring, skb); if (ret) { rtw89_err(rtwdev, "failed to update %d RXBD info: %d\n", bd_ring->wp, ret); @@ -1550,6 +1596,7 @@ static void rtw89_pci_reset_trx_rings(struct rtw89_dev *rtwdev) bd_ring->rp = 0; rx_ring->diliver_skb = NULL; rx_ring->diliver_desc.ready = false; + rx_ring->target_rx_tag = 0; rtw89_write16(rtwdev, addr_num, bd_ring->len); rtw89_write32(rtwdev, addr_desa_l, bd_ring->dma); @@ -3213,6 +3260,7 @@ static int rtw89_pci_alloc_rx_ring(struct rtw89_dev *rtwdev, rx_ring->buf_sz = buf_sz; rx_ring->diliver_skb = NULL; rx_ring->diliver_desc.ready = false; + rx_ring->target_rx_tag = 0; for (i = 0; i < len; i++) { skb = dev_alloc_skb(buf_sz); diff --git a/drivers/net/wireless/realtek/rtw89/pci.h b/drivers/net/wireless/realtek/rtw89/pci.h index 1fb7c209fa0d..0543221b4c58 100644 --- a/drivers/net/wireless/realtek/rtw89/pci.h +++ b/drivers/net/wireless/realtek/rtw89/pci.h @@ -1235,6 +1235,7 @@ struct rtw89_pci_info { enum mac_ax_pcie_func_ctrl io_rcy_en; enum mac_ax_io_rcy_tmr io_rcy_tmr; bool rx_ring_eq_is_full; + bool check_rx_tag; u32 init_cfg_reg; u32 txhci_en_bit; @@ -1277,7 +1278,7 @@ struct rtw89_pci_tx_data { struct rtw89_pci_rx_info { dma_addr_t dma; - u32 fs:1, ls:1, tag:11, len:14; + u32 fs:1, ls:1, tag:13, len:14; }; #define RTW89_PCI_TXBD_OPTION_LS BIT(14) @@ -1406,6 +1407,7 @@ struct rtw89_pci_rx_ring { u32 buf_sz; struct sk_buff *diliver_skb; struct rtw89_rx_desc_info diliver_desc; + u32 target_rx_tag:13; }; struct rtw89_pci_isrs { diff --git a/drivers/net/wireless/realtek/rtw89/rtw8851be.c b/drivers/net/wireless/realtek/rtw89/rtw8851be.c index ade69bd30fc8..ca1374a71727 100644 --- a/drivers/net/wireless/realtek/rtw89/rtw8851be.c +++ b/drivers/net/wireless/realtek/rtw89/rtw8851be.c @@ -25,6 +25,8 @@ static const struct rtw89_pci_info rtw8851b_pci_info = { .autok_en = MAC_AX_PCIE_DISABLE, .io_rcy_en = MAC_AX_PCIE_DISABLE, .io_rcy_tmr = MAC_AX_IO_RCY_ANA_TMR_6MS, + .rx_ring_eq_is_full = false, + .check_rx_tag = false, .init_cfg_reg = R_AX_PCIE_INIT_CFG1, .txhci_en_bit = B_AX_TXHCI_EN, diff --git a/drivers/net/wireless/realtek/rtw89/rtw8852ae.c b/drivers/net/wireless/realtek/rtw89/rtw8852ae.c index f1e890bde049..7c6ffedb77e2 100644 --- a/drivers/net/wireless/realtek/rtw89/rtw8852ae.c +++ b/drivers/net/wireless/realtek/rtw89/rtw8852ae.c @@ -26,6 +26,7 @@ static const struct rtw89_pci_info rtw8852a_pci_info = { .io_rcy_en = MAC_AX_PCIE_DISABLE, .io_rcy_tmr = MAC_AX_IO_RCY_ANA_TMR_6MS, .rx_ring_eq_is_full = false, + .check_rx_tag = false, .init_cfg_reg = R_AX_PCIE_INIT_CFG1, .txhci_en_bit = B_AX_TXHCI_EN, diff --git a/drivers/net/wireless/realtek/rtw89/rtw8852be.c b/drivers/net/wireless/realtek/rtw89/rtw8852be.c index 920b20bbcfb7..ed71364e6437 100644 --- a/drivers/net/wireless/realtek/rtw89/rtw8852be.c +++ b/drivers/net/wireless/realtek/rtw89/rtw8852be.c @@ -26,6 +26,7 @@ static const struct rtw89_pci_info rtw8852b_pci_info = { .io_rcy_en = MAC_AX_PCIE_DISABLE, .io_rcy_tmr = MAC_AX_IO_RCY_ANA_TMR_6MS, .rx_ring_eq_is_full = false, + .check_rx_tag = false, .init_cfg_reg = R_AX_PCIE_INIT_CFG1, .txhci_en_bit = B_AX_TXHCI_EN, diff --git a/drivers/net/wireless/realtek/rtw89/rtw8852ce.c b/drivers/net/wireless/realtek/rtw89/rtw8852ce.c index 4592de3dbd94..583ea673a4f5 100644 --- a/drivers/net/wireless/realtek/rtw89/rtw8852ce.c +++ b/drivers/net/wireless/realtek/rtw89/rtw8852ce.c @@ -35,6 +35,7 @@ static const struct rtw89_pci_info rtw8852c_pci_info = { .io_rcy_en = MAC_AX_PCIE_ENABLE, .io_rcy_tmr = MAC_AX_IO_RCY_ANA_TMR_6MS, .rx_ring_eq_is_full = false, + .check_rx_tag = false, .init_cfg_reg = R_AX_HAXI_INIT_CFG1, .txhci_en_bit = B_AX_TXHCI_EN_V1, diff --git a/drivers/net/wireless/realtek/rtw89/rtw8922ae.c b/drivers/net/wireless/realtek/rtw89/rtw8922ae.c index 7b3d98d2c402..9f46fb166105 100644 --- a/drivers/net/wireless/realtek/rtw89/rtw8922ae.c +++ b/drivers/net/wireless/realtek/rtw89/rtw8922ae.c @@ -26,6 +26,7 @@ static const struct rtw89_pci_info rtw8922a_pci_info = { .io_rcy_en = MAC_AX_PCIE_ENABLE, .io_rcy_tmr = MAC_AX_IO_RCY_ANA_TMR_DEF, .rx_ring_eq_is_full = true, + .check_rx_tag = true, .init_cfg_reg = R_BE_HAXI_INIT_CFG1, .txhci_en_bit = B_BE_TXDMA_EN, -- cgit v1.2.3 From c108b4a50dd7650941d4f4ec5c161655a73711db Mon Sep 17 00:00:00 2001 From: Ping-Ke Shih Date: Sun, 21 Jan 2024 15:18:26 +0800 Subject: wifi: rtw89: pci: enlarge RX DMA buffer to consider size of RX descriptor Hardware puts RX descriptor and packet in RX DMA buffer, so it could be over one buffer size if packet size is 11454, and then it will be split into two segments. WiFi 7 chips use larger size of RX descriptor, so enlarge DMA buffer size according to RX descriptor to have better performance and simple flow. Signed-off-by: Ping-Ke Shih Signed-off-by: Kalle Valo Link: https://msgid.link/20240121071826.10159-5-pkshih@realtek.com --- drivers/net/wireless/realtek/rtw89/pci.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/realtek/rtw89/pci.h b/drivers/net/wireless/realtek/rtw89/pci.h index 0543221b4c58..532f78eaf6df 100644 --- a/drivers/net/wireless/realtek/rtw89/pci.h +++ b/drivers/net/wireless/realtek/rtw89/pci.h @@ -997,7 +997,7 @@ #define RTW89_PCI_TXWD_NUM_MAX 512 #define RTW89_PCI_TXWD_PAGE_SIZE 128 #define RTW89_PCI_ADDRINFO_MAX 4 -#define RTW89_PCI_RX_BUF_SIZE 11460 +#define RTW89_PCI_RX_BUF_SIZE (11454 + 40) /* +40 for rtw89_rxdesc_long_v2 */ #define RTW89_PCI_POLL_BDRAM_RST_CNT 100 #define RTW89_PCI_MULTITAG 8 -- cgit v1.2.3 From f8a7840e98a440f466954c0b9eed99a9f064a564 Mon Sep 17 00:00:00 2001 From: Ping-Ke Shih Date: Wed, 24 Jan 2024 11:36:32 +0800 Subject: wifi: rtw89: 8922a: hook handlers of TX/RX descriptors to chip_ops Hook implemented handlers to chip_ops, and fill packet frequency and signal strength to RX status from RX PPDU status packet. Signed-off-by: Ping-Ke Shih Signed-off-by: Kalle Valo Link: https://msgid.link/20240124033637.12330-2-pkshih@realtek.com --- drivers/net/wireless/realtek/rtw89/rtw8922a.c | 37 +++++++++++++++++++++++++++ 1 file changed, 37 insertions(+) (limited to 'drivers/net') diff --git a/drivers/net/wireless/realtek/rtw89/rtw8922a.c b/drivers/net/wireless/realtek/rtw89/rtw8922a.c index f34e2a8bff07..9c7465d0715b 100644 --- a/drivers/net/wireless/realtek/rtw89/rtw8922a.c +++ b/drivers/net/wireless/realtek/rtw89/rtw8922a.c @@ -1250,6 +1250,39 @@ static void rtw8922a_ctrl_nbtg_bt_tx(struct rtw89_dev *rtwdev, bool en, } } +static void rtw8922a_fill_freq_with_ppdu(struct rtw89_dev *rtwdev, + struct rtw89_rx_phy_ppdu *phy_ppdu, + struct ieee80211_rx_status *status) +{ + u8 chan_idx = phy_ppdu->chan_idx; + enum nl80211_band band; + u8 ch; + + if (chan_idx == 0) + return; + + rtw89_decode_chan_idx(rtwdev, chan_idx, &ch, &band); + status->freq = ieee80211_channel_to_frequency(ch, band); + status->band = band; +} + +static void rtw8922a_query_ppdu(struct rtw89_dev *rtwdev, + struct rtw89_rx_phy_ppdu *phy_ppdu, + struct ieee80211_rx_status *status) +{ + u8 path; + u8 *rx_power = phy_ppdu->rssi; + + status->signal = + RTW89_RSSI_RAW_TO_DBM(max(rx_power[RF_PATH_A], rx_power[RF_PATH_B])); + for (path = 0; path < rtwdev->chip->rf_path_num; path++) { + status->chains |= BIT(path); + status->chain_signal[path] = RTW89_RSSI_RAW_TO_DBM(rx_power[path]); + } + if (phy_ppdu->valid) + rtw8922a_fill_freq_with_ppdu(rtwdev, phy_ppdu, status); +} + static int rtw8922a_mac_enable_bb_rf(struct rtw89_dev *rtwdev) { rtw89_write8_set(rtwdev, R_BE_FEN_RST_ENABLE, @@ -1291,10 +1324,14 @@ static const struct rtw89_chip_ops rtw8922a_chip_ops = { .set_txpwr_ctrl = rtw8922a_set_txpwr_ctrl, .init_txpwr_unit = NULL, .ctrl_btg_bt_rx = rtw8922a_ctrl_btg_bt_rx, + .query_ppdu = rtw8922a_query_ppdu, .ctrl_nbtg_bt_tx = rtw8922a_ctrl_nbtg_bt_tx, .set_txpwr_ul_tb_offset = NULL, .pwr_on_func = rtw8922a_pwr_on_func, .pwr_off_func = rtw8922a_pwr_off_func, + .query_rxdesc = rtw89_core_query_rxdesc_v2, + .fill_txdesc = rtw89_core_fill_txdesc_v2, + .fill_txdesc_fwcmd = rtw89_core_fill_txdesc_fwcmd_v2, .h2c_dctl_sec_cam = rtw89_fw_h2c_dctl_sec_cam_v2, .h2c_default_cmac_tbl = rtw89_fw_h2c_default_cmac_tbl_g7, .h2c_assoc_cmac_tbl = rtw89_fw_h2c_assoc_cmac_tbl_g7, -- cgit v1.2.3 From b16daa62125e3f841a135c37dfd996cdf7e7960d Mon Sep 17 00:00:00 2001 From: Ping-Ke Shih Date: Wed, 24 Jan 2024 11:36:33 +0800 Subject: wifi: rtw89: 8922a: implement {stop,resume}_sch_tx and cfg_ppdu To set TX/RX path or set channel, we need these helpers to stop TX and restore settings. The sch_tx stands for scheduler TX channel, and the cfg_ppdu is to stop reporting PPDU status, so we should stop them during setting. Signed-off-by: Ping-Ke Shih Signed-off-by: Kalle Valo Link: https://msgid.link/20240124033637.12330-3-pkshih@realtek.com --- drivers/net/wireless/realtek/rtw89/mac.c | 5 +- drivers/net/wireless/realtek/rtw89/mac.h | 14 +++- drivers/net/wireless/realtek/rtw89/mac_be.c | 96 +++++++++++++++++++++++++++ drivers/net/wireless/realtek/rtw89/reg.h | 44 ++++++++++++ drivers/net/wireless/realtek/rtw89/rtw8922a.c | 2 + 5 files changed, 158 insertions(+), 3 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/realtek/rtw89/mac.c b/drivers/net/wireless/realtek/rtw89/mac.c index eb94e832e154..d1d16564a686 100644 --- a/drivers/net/wireless/realtek/rtw89/mac.c +++ b/drivers/net/wireless/realtek/rtw89/mac.c @@ -5205,7 +5205,8 @@ error: return false; } -int rtw89_mac_cfg_ppdu_status(struct rtw89_dev *rtwdev, u8 mac_idx, bool enable) +static +int rtw89_mac_cfg_ppdu_status_ax(struct rtw89_dev *rtwdev, u8 mac_idx, bool enable) { u32 reg = rtw89_mac_reg_by_idx(rtwdev, R_AX_PPDU_STAT, mac_idx); int ret; @@ -5228,7 +5229,6 @@ int rtw89_mac_cfg_ppdu_status(struct rtw89_dev *rtwdev, u8 mac_idx, bool enable) return 0; } -EXPORT_SYMBOL(rtw89_mac_cfg_ppdu_status); void rtw89_mac_update_rts_threshold(struct rtw89_dev *rtwdev, u8 mac_idx) { @@ -6179,6 +6179,7 @@ const struct rtw89_mac_gen_def rtw89_mac_gen_ax = { .bf_assoc = rtw89_mac_bf_assoc_ax, .typ_fltr_opt = rtw89_mac_typ_fltr_opt_ax, + .cfg_ppdu_status = rtw89_mac_cfg_ppdu_status_ax, .dle_mix_cfg = dle_mix_cfg_ax, .chk_dle_rdy = chk_dle_rdy_ax, diff --git a/drivers/net/wireless/realtek/rtw89/mac.h b/drivers/net/wireless/realtek/rtw89/mac.h index 181d03d1f78a..66bac01eb067 100644 --- a/drivers/net/wireless/realtek/rtw89/mac.h +++ b/drivers/net/wireless/realtek/rtw89/mac.h @@ -913,6 +913,7 @@ struct rtw89_mac_gen_def { enum rtw89_machdr_frame_type type, enum rtw89_mac_fwd_target fwd_target, u8 mac_idx); + int (*cfg_ppdu_status)(struct rtw89_dev *rtwdev, u8 mac_idx, bool enable); int (*dle_mix_cfg)(struct rtw89_dev *rtwdev, const struct rtw89_dle_mem *cfg); int (*chk_dle_rdy)(struct rtw89_dev *rtwdev, bool wde_or_ple); @@ -1138,9 +1139,20 @@ int rtw89_mac_stop_sch_tx(struct rtw89_dev *rtwdev, u8 mac_idx, u32 *tx_en, enum rtw89_sch_tx_sel sel); int rtw89_mac_stop_sch_tx_v1(struct rtw89_dev *rtwdev, u8 mac_idx, u32 *tx_en, enum rtw89_sch_tx_sel sel); +int rtw89_mac_stop_sch_tx_v2(struct rtw89_dev *rtwdev, u8 mac_idx, + u32 *tx_en, enum rtw89_sch_tx_sel sel); int rtw89_mac_resume_sch_tx(struct rtw89_dev *rtwdev, u8 mac_idx, u32 tx_en); int rtw89_mac_resume_sch_tx_v1(struct rtw89_dev *rtwdev, u8 mac_idx, u32 tx_en); -int rtw89_mac_cfg_ppdu_status(struct rtw89_dev *rtwdev, u8 mac_ids, bool enable); +int rtw89_mac_resume_sch_tx_v2(struct rtw89_dev *rtwdev, u8 mac_idx, u32 tx_en); + +static inline +int rtw89_mac_cfg_ppdu_status(struct rtw89_dev *rtwdev, u8 mac_idx, bool enable) +{ + const struct rtw89_mac_gen_def *mac = rtwdev->chip->mac_def; + + return mac->cfg_ppdu_status(rtwdev, mac_idx, enable); +} + void rtw89_mac_update_rts_threshold(struct rtw89_dev *rtwdev, u8 mac_idx); void rtw89_mac_flush_txq(struct rtw89_dev *rtwdev, u32 queues, bool drop); int rtw89_mac_coex_init(struct rtw89_dev *rtwdev, const struct rtw89_mac_ax_coex *coex); diff --git a/drivers/net/wireless/realtek/rtw89/mac_be.c b/drivers/net/wireless/realtek/rtw89/mac_be.c index 4befbe06cd15..f03d05a2f857 100644 --- a/drivers/net/wireless/realtek/rtw89/mac_be.c +++ b/drivers/net/wireless/realtek/rtw89/mac_be.c @@ -1718,6 +1718,101 @@ static int trx_init_be(struct rtw89_dev *rtwdev) return 0; } +static int rtw89_set_hw_sch_tx_en_v2(struct rtw89_dev *rtwdev, u8 mac_idx, + u32 tx_en, u32 tx_en_mask) +{ + u32 reg = rtw89_mac_reg_by_idx(rtwdev, R_BE_CTN_DRV_TXEN, mac_idx); + u32 val; + int ret; + + ret = rtw89_mac_check_mac_en(rtwdev, mac_idx, RTW89_CMAC_SEL); + if (ret) + return ret; + + val = rtw89_read32(rtwdev, reg); + val = (val & ~tx_en_mask) | (tx_en & tx_en_mask); + rtw89_write32(rtwdev, reg, val); + + return 0; +} + +int rtw89_mac_stop_sch_tx_v2(struct rtw89_dev *rtwdev, u8 mac_idx, + u32 *tx_en, enum rtw89_sch_tx_sel sel) +{ + int ret; + + *tx_en = rtw89_read32(rtwdev, + rtw89_mac_reg_by_idx(rtwdev, R_BE_CTN_DRV_TXEN, mac_idx)); + + switch (sel) { + case RTW89_SCH_TX_SEL_ALL: + ret = rtw89_set_hw_sch_tx_en_v2(rtwdev, mac_idx, 0, + B_BE_CTN_TXEN_ALL_MASK); + if (ret) + return ret; + break; + case RTW89_SCH_TX_SEL_HIQ: + ret = rtw89_set_hw_sch_tx_en_v2(rtwdev, mac_idx, + 0, B_BE_CTN_TXEN_HGQ); + if (ret) + return ret; + break; + case RTW89_SCH_TX_SEL_MG0: + ret = rtw89_set_hw_sch_tx_en_v2(rtwdev, mac_idx, + 0, B_BE_CTN_TXEN_MGQ); + if (ret) + return ret; + break; + case RTW89_SCH_TX_SEL_MACID: + ret = rtw89_set_hw_sch_tx_en_v2(rtwdev, mac_idx, 0, + B_BE_CTN_TXEN_ALL_MASK); + if (ret) + return ret; + break; + default: + return 0; + } + + return 0; +} +EXPORT_SYMBOL(rtw89_mac_stop_sch_tx_v2); + +int rtw89_mac_resume_sch_tx_v2(struct rtw89_dev *rtwdev, u8 mac_idx, u32 tx_en) +{ + int ret; + + ret = rtw89_set_hw_sch_tx_en_v2(rtwdev, mac_idx, tx_en, + B_BE_CTN_TXEN_ALL_MASK); + if (ret) + return ret; + + return 0; +} +EXPORT_SYMBOL(rtw89_mac_resume_sch_tx_v2); + +static +int rtw89_mac_cfg_ppdu_status_be(struct rtw89_dev *rtwdev, u8 mac_idx, bool enable) +{ + u32 reg = rtw89_mac_reg_by_idx(rtwdev, R_BE_PPDU_STAT, mac_idx); + int ret; + + ret = rtw89_mac_check_mac_en(rtwdev, mac_idx, RTW89_CMAC_SEL); + if (ret) + return ret; + + if (!enable) { + rtw89_write32_clr(rtwdev, reg, B_BE_PPDU_STAT_RPT_EN); + return 0; + } + + rtw89_write32_mask(rtwdev, R_BE_HW_PPDU_STATUS, B_BE_FWD_PPDU_STAT_MASK, 3); + rtw89_write32(rtwdev, reg, B_BE_PPDU_STAT_RPT_EN | B_BE_PPDU_MAC_INFO | + B_BE_APP_RX_CNT_RPT | B_BE_APP_PLCP_HDR_RPT | + B_BE_PPDU_STAT_RPT_CRC32 | B_BE_PPDU_STAT_RPT_DMA); + + return 0; +} + static bool rtw89_mac_get_txpwr_cr_be(struct rtw89_dev *rtwdev, enum rtw89_phy_idx phy_idx, u32 reg_base, u32 *cr) @@ -2239,6 +2334,7 @@ const struct rtw89_mac_gen_def rtw89_mac_gen_be = { .bf_assoc = rtw89_mac_bf_assoc_be, .typ_fltr_opt = rtw89_mac_typ_fltr_opt_be, + .cfg_ppdu_status = rtw89_mac_cfg_ppdu_status_be, .dle_mix_cfg = dle_mix_cfg_be, .chk_dle_rdy = chk_dle_rdy_be, diff --git a/drivers/net/wireless/realtek/rtw89/reg.h b/drivers/net/wireless/realtek/rtw89/reg.h index ec2559bde092..cdead0132d66 100644 --- a/drivers/net/wireless/realtek/rtw89/reg.h +++ b/drivers/net/wireless/realtek/rtw89/reg.h @@ -5502,6 +5502,14 @@ #define B_BE_DROP_NONDMA_PPDU BIT(2) #define B_BE_APPEND_FCS BIT(0) +#define R_BE_HW_PPDU_STATUS 0x9C30 +#define B_BE_FWD_RPKTTYPE_MASK GENMASK(31, 26) +#define B_BE_FWD_PPDU_PRTID_MASK GENMASK(25, 23) +#define B_BE_FWD_PPDU_FW_RLS BIT(22) +#define B_BE_FWD_PPDU_QUEID_MASK GENMASK(21, 16) +#define B_BE_FWD_OTHER_RPKT_MASK GENMASK(15, 8) +#define B_BE_FWD_PPDU_STAT_MASK GENMASK(7, 0) + #define R_BE_CUT_AMSDU_CTRL 0x9C94 #define B_BE_EN_CUT_AMSDU BIT(31) #define B_BE_CUT_AMSDU_CHKLEN_EN BIT(30) @@ -6143,6 +6151,28 @@ #define B_BE_SET_MUEDCATIMER_TF_0 BIT(4) #define B_BE_MUEDCA_EN_0 BIT(0) +#define R_BE_CTN_DRV_TXEN 0x10398 +#define R_BE_CTN_DRV_TXEN_C1 0x14398 +#define B_BE_CTN_TXEN_TWT_3 BIT(17) +#define B_BE_CTN_TXEN_TWT_2 BIT(16) +#define B_BE_CTN_TXEN_TWT_1 BIT(15) +#define B_BE_CTN_TXEN_TWT_0 BIT(14) +#define B_BE_CTN_TXEN_ULQ BIT(13) +#define B_BE_CTN_TXEN_BCNQ BIT(12) +#define B_BE_CTN_TXEN_HGQ BIT(11) +#define B_BE_CTN_TXEN_CPUMGQ BIT(10) +#define B_BE_CTN_TXEN_MGQ1 BIT(9) +#define B_BE_CTN_TXEN_MGQ BIT(8) +#define B_BE_CTN_TXEN_VO_1 BIT(7) +#define B_BE_CTN_TXEN_VI_1 BIT(6) +#define B_BE_CTN_TXEN_BK_1 BIT(5) +#define B_BE_CTN_TXEN_BE_1 BIT(4) +#define B_BE_CTN_TXEN_VO_0 BIT(3) +#define B_BE_CTN_TXEN_VI_0 BIT(2) +#define B_BE_CTN_TXEN_BK_0 BIT(1) +#define B_BE_CTN_TXEN_BE_0 BIT(0) +#define B_BE_CTN_TXEN_ALL_MASK GENMASK(17, 0) + #define R_BE_TB_CHK_CCA_NAV 0x103AC #define R_BE_TB_CHK_CCA_NAV_C1 0x143AC #define B_BE_TB_CHK_TX_NAV BIT(15) @@ -7144,6 +7174,20 @@ #define S_BE_BACAM_RST_ENT 1 #define S_BE_BACAM_RST_ALL 2 +#define R_BE_PPDU_STAT 0x11440 +#define R_BE_PPDU_STAT_C1 0x15440 +#define B_BE_STAT_IORST BIT(13) +#define B_BE_STAT_GCKDIS BIT(12) +#define B_BE_PPDU_STAT_WR_BW_MASK GENMASK(11, 10) +#define B_BE_PPDU_STAT_RPT_TRIG BIT(8) +#define B_BE_PPDU_STAT_RPT_DMA BIT(6) +#define B_BE_PPDU_STAT_RPT_CRC32 BIT(5) +#define B_BE_PPDU_STAT_RPT_ADDR BIT(4) +#define B_BE_APP_PLCP_HDR_RPT BIT(3) +#define B_BE_APP_RX_CNT_RPT BIT(2) +#define B_BE_PPDU_MAC_INFO BIT(1) +#define B_BE_PPDU_STAT_RPT_EN BIT(0) + #define R_BE_RX_SR_CTRL 0x1144A #define R_BE_RX_SR_CTRL_C1 0x1544A #define B_BE_SR_OP_MODE_MASK GENMASK(5, 4) diff --git a/drivers/net/wireless/realtek/rtw89/rtw8922a.c b/drivers/net/wireless/realtek/rtw89/rtw8922a.c index 9c7465d0715b..beac7bf0faff 100644 --- a/drivers/net/wireless/realtek/rtw89/rtw8922a.c +++ b/drivers/net/wireless/realtek/rtw89/rtw8922a.c @@ -1332,6 +1332,8 @@ static const struct rtw89_chip_ops rtw8922a_chip_ops = { .query_rxdesc = rtw89_core_query_rxdesc_v2, .fill_txdesc = rtw89_core_fill_txdesc_v2, .fill_txdesc_fwcmd = rtw89_core_fill_txdesc_fwcmd_v2, + .stop_sch_tx = rtw89_mac_stop_sch_tx_v2, + .resume_sch_tx = rtw89_mac_resume_sch_tx_v2, .h2c_dctl_sec_cam = rtw89_fw_h2c_dctl_sec_cam_v2, .h2c_default_cmac_tbl = rtw89_fw_h2c_default_cmac_tbl_g7, .h2c_assoc_cmac_tbl = rtw89_fw_h2c_assoc_cmac_tbl_g7, -- cgit v1.2.3 From 1ba63a8a752a76ebe4b26d80c6d25bd04484a9eb Mon Sep 17 00:00:00 2001 From: Ping-Ke Shih Date: Wed, 24 Jan 2024 11:36:34 +0800 Subject: wifi: rtw89: 8922a: add chip_ops::cfg_txrx_path This function is to set TX/RX path. Especially for 1SS rate, it can select to TX on one or two antenna. Before this operation, stop hardware to prevent transmitting/receiving unexpected packets. After that, restore settings and reset hardware to prevent it stays on abnormal state. Signed-off-by: Ping-Ke Shih Signed-off-by: Kalle Valo Link: https://msgid.link/20240124033637.12330-4-pkshih@realtek.com --- drivers/net/wireless/realtek/rtw89/reg.h | 24 ++ drivers/net/wireless/realtek/rtw89/rtw8922a.c | 279 ++++++++++++++++++++++ drivers/net/wireless/realtek/rtw89/rtw8922a_rfk.c | 33 +++ drivers/net/wireless/realtek/rtw89/rtw8922a_rfk.h | 12 + 4 files changed, 348 insertions(+) create mode 100644 drivers/net/wireless/realtek/rtw89/rtw8922a_rfk.c create mode 100644 drivers/net/wireless/realtek/rtw89/rtw8922a_rfk.h (limited to 'drivers/net') diff --git a/drivers/net/wireless/realtek/rtw89/reg.h b/drivers/net/wireless/realtek/rtw89/reg.h index cdead0132d66..d7217f2a26aa 100644 --- a/drivers/net/wireless/realtek/rtw89/reg.h +++ b/drivers/net/wireless/realtek/rtw89/reg.h @@ -7686,9 +7686,23 @@ #define B_SWSI_READ_ADDR_ADDR_V1 GENMASK(7, 0) #define B_SWSI_READ_ADDR_PATH_V1 GENMASK(10, 8) #define B_SWSI_READ_ADDR_V1 GENMASK(10, 0) +#define R_BRK_R 0x0418 +#define B_VHTMCS_LMT GENMASK(22, 21) +#define B_HTMCS_LMT GENMASK(9, 8) +#define R_BRK_EHT 0x0474 +#define B_RXEHT_NSS_MAX GENMASK(4, 2) +#define R_BRK_RXEHT 0x0478 +#define B_RXEHT_N_USER_MAX GENMASK(31, 24) +#define B_RXEHTTB_NSS_MAX GENMASK(16, 14) #define R_EN_SND_WO_NDP 0x047c #define R_EN_SND_WO_NDP_C1 0x147c #define B_EN_SND_WO_NDP BIT(1) +#define R_BRK_HE 0x0480 +#define B_TB_NSS_MAX GENMASK(25, 23) +#define B_NSS_MAX GENMASK(16, 14) +#define B_N_USR_MAX GENMASK(13, 6) +#define R_RXCCA_BE1 0x0520 +#define B_RXCCA_BE1_DIS BIT(0) #define R_UPD_CLK_ADC 0x0700 #define B_UPD_CLK_ADC_VAL GENMASK(26, 25) #define B_UPD_CLK_ADC_ON BIT(24) @@ -7735,6 +7749,7 @@ #define B_PMAC_RXMOD_MSK GENMASK(7, 4) #define R_MAC_SEL 0x09A4 #define B_MAC_SEL_OFDM_TRI_FILTER BIT(31) +#define B_MAC_SEL GENMASK(19, 17) #define B_MAC_SEL_PWR_EN BIT(16) #define B_MAC_SEL_DPD_EN BIT(10) #define B_MAC_SEL_MOD GENMASK(4, 2) @@ -7828,6 +7843,8 @@ #define R_CLK_GCK 0x1008 #define B_CLK_GCK GENMASK(24, 0) #define R_EDCCA_RPT_SEL_BE 0x10CC +#define R_ADC_FIFO_V1 0x10FC +#define B_ADC_FIFO_EN_V1 GENMASK(31, 24) #define R_S0_HW_SI_DIS 0x1200 #define B_S0_HW_SI_DIS_W_R_TRIG GENMASK(30, 28) #define R_P0_RXCK 0x12A0 @@ -8937,6 +8954,11 @@ #define R_IQK_DPK_PRST 0xE4AC #define R_IQK_DPK_PRST_C1 0xE5AC #define B_IQK_DPK_PRST BIT(27) +#define R_TXPWR_RSTA 0xE60C +#define B_TXPWR_RSTA BIT(16) +#define R_TSSI_PWR_P0 0xE610 +#define R_TSSI_PWR_P1 0xE710 +#define B_TSSI_CONT_EN BIT(3) #define R_TSSI_MAP_OFST_P0 0xE620 #define R_TSSI_MAP_OFST_P1 0xE720 #define B_TSSI_MAP_OFST_OFDM GENMASK(17, 9) @@ -8949,6 +8971,8 @@ #define R_TXAGC_REF1_P0 0xE62C #define R_TXAGC_REF1_P1 0xE72C #define B_TXAGC_REF1_CCK_CW GENMASK(8, 0) +#define R_TXPWR_RSTB 0xE70C +#define B_TXPWR_RSTB BIT(16) /* WiFi CPU local domain */ #define R_AX_WDT_CTRL 0x0040 diff --git a/drivers/net/wireless/realtek/rtw89/rtw8922a.c b/drivers/net/wireless/realtek/rtw89/rtw8922a.c index beac7bf0faff..2481f983b426 100644 --- a/drivers/net/wireless/realtek/rtw89/rtw8922a.c +++ b/drivers/net/wireless/realtek/rtw89/rtw8922a.c @@ -9,12 +9,15 @@ #include "phy.h" #include "reg.h" #include "rtw8922a.h" +#include "rtw8922a_rfk.h" #define RTW8922A_FW_FORMAT_MAX 0 #define RTW8922A_FW_BASENAME "rtw89/rtw8922a_fw" #define RTW8922A_MODULE_FIRMWARE \ RTW8922A_FW_BASENAME ".bin" +#define HE_N_USER_MAX_8922A 4 + static const struct rtw89_hfc_ch_cfg rtw8922a_hfc_chcfg_pcie[] = { {2, 1641, grp_0}, /* ACH 0 */ {2, 1641, grp_0}, /* ACH 1 */ @@ -1049,10 +1052,167 @@ static void rtw8922a_bb_postinit(struct rtw89_dev *rtwdev, enum rtw89_phy_idx ph rtw89_phy_write32_idx(rtwdev, R_UDP_COEEF, B_UDP_COEEF, 0x1, phy_idx); } +static void rtw8922a_bb_reset_en(struct rtw89_dev *rtwdev, enum rtw89_band band, + bool en, enum rtw89_phy_idx phy_idx) +{ + if (en) { + rtw89_phy_write32_idx(rtwdev, R_RSTB_ASYNC, B_RSTB_ASYNC_ALL, 1, phy_idx); + if (band == RTW89_BAND_2G) + rtw89_phy_write32_idx(rtwdev, R_RXCCA_BE1, + B_RXCCA_BE1_DIS, 0x0, phy_idx); + rtw89_phy_write32_idx(rtwdev, R_PD_CTRL, B_PD_HIT_DIS, 0x0, phy_idx); + } else { + rtw89_phy_write32_idx(rtwdev, R_RXCCA_BE1, B_RXCCA_BE1_DIS, 0x1, phy_idx); + rtw89_phy_write32_idx(rtwdev, R_PD_CTRL, B_PD_HIT_DIS, 0x1, phy_idx); + fsleep(1); + rtw89_phy_write32_idx(rtwdev, R_RSTB_ASYNC, B_RSTB_ASYNC_ALL, 0, phy_idx); + } +} + +static int rtw8922a_ctrl_tx_path_tmac(struct rtw89_dev *rtwdev, + enum rtw89_rf_path tx_path, + enum rtw89_phy_idx phy_idx) +{ + struct rtw89_reg2_def path_com_cr[] = { + {0x11A00, 0x21C86900}, + {0x11A04, 0x00E4E433}, + {0x11A08, 0x39390CC9}, + {0x11A0C, 0x4E433240}, + {0x11A10, 0x90CC900E}, + {0x11A14, 0x00240393}, + {0x11A18, 0x201C8600}, + }; + int ret = 0; + u32 reg; + int i; + + rtw89_phy_write32_idx(rtwdev, R_MAC_SEL, B_MAC_SEL, 0x0, phy_idx); + + if (phy_idx == RTW89_PHY_1 && !rtwdev->dbcc_en) + return 0; + + if (tx_path == RF_PATH_A) { + path_com_cr[0].data = 0x21C82900; + path_com_cr[1].data = 0x00E4E431; + path_com_cr[2].data = 0x39390C49; + path_com_cr[3].data = 0x4E431240; + path_com_cr[4].data = 0x90C4900E; + path_com_cr[6].data = 0x201C8200; + } else if (tx_path == RF_PATH_B) { + path_com_cr[0].data = 0x21C04900; + path_com_cr[1].data = 0x00E4E032; + path_com_cr[2].data = 0x39380C89; + path_com_cr[3].data = 0x4E032240; + path_com_cr[4].data = 0x80C8900E; + path_com_cr[6].data = 0x201C0400; + } else if (tx_path == RF_PATH_AB) { + path_com_cr[0].data = 0x21C86900; + path_com_cr[1].data = 0x00E4E433; + path_com_cr[2].data = 0x39390CC9; + path_com_cr[3].data = 0x4E433240; + path_com_cr[4].data = 0x90CC900E; + path_com_cr[6].data = 0x201C8600; + } else { + ret = -EINVAL; + } + + for (i = 0; i < ARRAY_SIZE(path_com_cr); i++) { + reg = rtw89_mac_reg_by_idx(rtwdev, path_com_cr[i].addr, phy_idx); + rtw89_write32(rtwdev, reg, path_com_cr[i].data); + } + + return ret; +} + static void rtw8922a_bb_reset(struct rtw89_dev *rtwdev, enum rtw89_phy_idx phy_idx) { } +static int rtw8922a_cfg_rx_nss_limit(struct rtw89_dev *rtwdev, u8 rx_nss, + enum rtw89_phy_idx phy_idx) +{ + if (rx_nss == 1) { + rtw89_phy_write32_idx(rtwdev, R_BRK_R, B_HTMCS_LMT, 0, phy_idx); + rtw89_phy_write32_idx(rtwdev, R_BRK_R, B_VHTMCS_LMT, 0, phy_idx); + rtw89_phy_write32_idx(rtwdev, R_BRK_HE, B_N_USR_MAX, + HE_N_USER_MAX_8922A, phy_idx); + rtw89_phy_write32_idx(rtwdev, R_BRK_HE, B_NSS_MAX, 0, phy_idx); + rtw89_phy_write32_idx(rtwdev, R_BRK_HE, B_TB_NSS_MAX, 0, phy_idx); + rtw89_phy_write32_idx(rtwdev, R_BRK_EHT, B_RXEHT_NSS_MAX, 0, phy_idx); + rtw89_phy_write32_idx(rtwdev, R_BRK_RXEHT, B_RXEHTTB_NSS_MAX, 0, + phy_idx); + rtw89_phy_write32_idx(rtwdev, R_BRK_RXEHT, B_RXEHT_N_USER_MAX, + HE_N_USER_MAX_8922A, phy_idx); + } else if (rx_nss == 2) { + rtw89_phy_write32_idx(rtwdev, R_BRK_R, B_HTMCS_LMT, 1, phy_idx); + rtw89_phy_write32_idx(rtwdev, R_BRK_R, B_VHTMCS_LMT, 1, phy_idx); + rtw89_phy_write32_idx(rtwdev, R_BRK_HE, B_N_USR_MAX, + HE_N_USER_MAX_8922A, phy_idx); + rtw89_phy_write32_idx(rtwdev, R_BRK_HE, B_NSS_MAX, 1, phy_idx); + rtw89_phy_write32_idx(rtwdev, R_BRK_HE, B_TB_NSS_MAX, 1, phy_idx); + rtw89_phy_write32_idx(rtwdev, R_BRK_EHT, B_RXEHT_NSS_MAX, 1, phy_idx); + rtw89_phy_write32_idx(rtwdev, R_BRK_RXEHT, B_RXEHTTB_NSS_MAX, 1, + phy_idx); + rtw89_phy_write32_idx(rtwdev, R_BRK_RXEHT, B_RXEHT_N_USER_MAX, + HE_N_USER_MAX_8922A, phy_idx); + } else { + return -EINVAL; + } + + return 0; +} + +static void rtw8922a_tssi_reset(struct rtw89_dev *rtwdev, + enum rtw89_rf_path path, + enum rtw89_phy_idx phy_idx) +{ + if (rtwdev->mlo_dbcc_mode == MLO_1_PLUS_1_1RF) { + if (phy_idx == RTW89_PHY_0) { + rtw89_phy_write32_mask(rtwdev, R_TXPWR_RSTA, B_TXPWR_RSTA, 0x0); + rtw89_phy_write32_mask(rtwdev, R_TXPWR_RSTA, B_TXPWR_RSTA, 0x1); + } else { + rtw89_phy_write32_mask(rtwdev, R_TXPWR_RSTB, B_TXPWR_RSTB, 0x0); + rtw89_phy_write32_mask(rtwdev, R_TXPWR_RSTB, B_TXPWR_RSTB, 0x1); + } + } else { + rtw89_phy_write32_mask(rtwdev, R_TXPWR_RSTA, B_TXPWR_RSTA, 0x0); + rtw89_phy_write32_mask(rtwdev, R_TXPWR_RSTA, B_TXPWR_RSTA, 0x1); + rtw89_phy_write32_mask(rtwdev, R_TXPWR_RSTB, B_TXPWR_RSTB, 0x0); + rtw89_phy_write32_mask(rtwdev, R_TXPWR_RSTB, B_TXPWR_RSTB, 0x1); + } +} + +static int rtw8922a_ctrl_rx_path_tmac(struct rtw89_dev *rtwdev, + enum rtw89_rf_path rx_path, + enum rtw89_phy_idx phy_idx) +{ + u8 rx_nss = (rx_path == RF_PATH_AB) ? 2 : 1; + + /* Set to 0 first to avoid abnormal EDCCA report */ + rtw89_phy_write32_idx(rtwdev, R_ANT_CHBW, B_ANT_RX_SG0, 0x0, phy_idx); + + if (rx_path == RF_PATH_A) { + rtw89_phy_write32_idx(rtwdev, R_ANT_CHBW, B_ANT_RX_SG0, 0x1, phy_idx); + rtw89_phy_write32_idx(rtwdev, R_FC0INV_SBW, B_RX_1RCCA, 1, phy_idx); + rtw8922a_cfg_rx_nss_limit(rtwdev, rx_nss, phy_idx); + rtw8922a_tssi_reset(rtwdev, rx_path, phy_idx); + } else if (rx_path == RF_PATH_B) { + rtw89_phy_write32_idx(rtwdev, R_ANT_CHBW, B_ANT_RX_SG0, 0x2, phy_idx); + rtw89_phy_write32_idx(rtwdev, R_FC0INV_SBW, B_RX_1RCCA, 2, phy_idx); + rtw8922a_cfg_rx_nss_limit(rtwdev, rx_nss, phy_idx); + rtw8922a_tssi_reset(rtwdev, rx_path, phy_idx); + } else if (rx_path == RF_PATH_AB) { + rtw89_phy_write32_idx(rtwdev, R_ANT_CHBW, B_ANT_RX_SG0, 0x3, phy_idx); + rtw89_phy_write32_idx(rtwdev, R_FC0INV_SBW, B_RX_1RCCA, 3, phy_idx); + rtw8922a_cfg_rx_nss_limit(rtwdev, rx_nss, phy_idx); + rtw8922a_tssi_reset(rtwdev, rx_path, phy_idx); + } else { + return -EINVAL; + } + + return 0; +} + static int rtw8922a_ctrl_mlo(struct rtw89_dev *rtwdev, enum rtw89_mlo_dbcc_mode mode) { const struct rtw89_chan *chan = rtw89_chan_get(rtwdev, RTW89_SUB_ENTITY_0); @@ -1130,6 +1290,85 @@ static void rtw8922a_set_channel(struct rtw89_dev *rtwdev, rtw8922a_set_channel_bb(rtwdev, chan, phy_idx); } +static void rtw8922a_dfs_en_idx(struct rtw89_dev *rtwdev, + enum rtw89_phy_idx phy_idx, enum rtw89_rf_path path, + bool en) +{ + u32 path_ofst = (path == RF_PATH_B) ? 0x100 : 0x0; + + if (en) + rtw89_phy_write32_idx(rtwdev, 0x2800 + path_ofst, BIT(1), 1, + phy_idx); + else + rtw89_phy_write32_idx(rtwdev, 0x2800 + path_ofst, BIT(1), 0, + phy_idx); +} + +static void rtw8922a_dfs_en(struct rtw89_dev *rtwdev, bool en, + enum rtw89_phy_idx phy_idx) +{ + rtw8922a_dfs_en_idx(rtwdev, phy_idx, RF_PATH_A, en); + rtw8922a_dfs_en_idx(rtwdev, phy_idx, RF_PATH_B, en); +} + +static void rtw8922a_adc_en_path(struct rtw89_dev *rtwdev, + enum rtw89_rf_path path, bool en) +{ + u32 val; + + val = rtw89_phy_read32_mask(rtwdev, R_ADC_FIFO_V1, B_ADC_FIFO_EN_V1); + + if (en) { + if (path == RF_PATH_A) + val &= ~0x1; + else + val &= ~0x2; + } else { + if (path == RF_PATH_A) + val |= 0x1; + else + val |= 0x2; + } + + rtw89_phy_write32_mask(rtwdev, R_ADC_FIFO_V1, B_ADC_FIFO_EN_V1, val); +} + +static void rtw8922a_adc_en(struct rtw89_dev *rtwdev, bool en, u8 phy_idx) +{ + if (rtwdev->mlo_dbcc_mode == MLO_1_PLUS_1_1RF) { + if (phy_idx == RTW89_PHY_0) + rtw8922a_adc_en_path(rtwdev, RF_PATH_A, en); + else + rtw8922a_adc_en_path(rtwdev, RF_PATH_B, en); + } else { + rtw8922a_adc_en_path(rtwdev, RF_PATH_A, en); + rtw8922a_adc_en_path(rtwdev, RF_PATH_B, en); + } +} + +static +void rtw8922a_hal_reset(struct rtw89_dev *rtwdev, + enum rtw89_phy_idx phy_idx, enum rtw89_mac_idx mac_idx, + enum rtw89_band band, u32 *tx_en, bool enter) +{ + if (enter) { + rtw89_chip_stop_sch_tx(rtwdev, mac_idx, tx_en, RTW89_SCH_TX_SEL_ALL); + rtw89_mac_cfg_ppdu_status(rtwdev, mac_idx, false); + rtw8922a_dfs_en(rtwdev, false, phy_idx); + rtw8922a_tssi_cont_en_phyidx(rtwdev, false, phy_idx); + rtw8922a_adc_en(rtwdev, false, phy_idx); + fsleep(40); + rtw8922a_bb_reset_en(rtwdev, band, false, phy_idx); + } else { + rtw89_mac_cfg_ppdu_status(rtwdev, mac_idx, true); + rtw8922a_adc_en(rtwdev, true, phy_idx); + rtw8922a_dfs_en(rtwdev, true, phy_idx); + rtw8922a_tssi_cont_en_phyidx(rtwdev, true, phy_idx); + rtw8922a_bb_reset_en(rtwdev, band, true, phy_idx); + rtw89_chip_resume_sch_tx(rtwdev, mac_idx, *tx_en); + } +} + static void rtw8922a_set_txpwr_ref(struct rtw89_dev *rtwdev, enum rtw89_phy_idx phy_idx) { @@ -1188,6 +1427,19 @@ static void rtw8922a_set_txpwr_ctrl(struct rtw89_dev *rtwdev, rtw8922a_set_txpwr_ref(rtwdev, phy_idx); } +static void rtw8922a_ctrl_trx_path(struct rtw89_dev *rtwdev, + enum rtw89_rf_path tx_path, u8 tx_nss, + enum rtw89_rf_path rx_path, u8 rx_nss) +{ + enum rtw89_phy_idx phy_idx; + + for (phy_idx = RTW89_PHY_0; phy_idx <= RTW89_PHY_1; phy_idx++) { + rtw8922a_ctrl_tx_path_tmac(rtwdev, tx_path, phy_idx); + rtw8922a_ctrl_rx_path_tmac(rtwdev, rx_path, phy_idx); + rtw8922a_cfg_rx_nss_limit(rtwdev, rx_nss, phy_idx); + } +} + static void rtw8922a_ctrl_nbtg_bt_tx(struct rtw89_dev *rtwdev, bool en, enum rtw89_phy_idx phy_idx) { @@ -1250,6 +1502,32 @@ static void rtw8922a_ctrl_nbtg_bt_tx(struct rtw89_dev *rtwdev, bool en, } } +static void rtw8922a_bb_cfg_txrx_path(struct rtw89_dev *rtwdev) +{ + const struct rtw89_chan *chan = rtw89_chan_get(rtwdev, RTW89_SUB_ENTITY_0); + enum rtw89_band band = chan->band_type; + struct rtw89_hal *hal = &rtwdev->hal; + u8 ntx_path = RF_PATH_AB; + u32 tx_en0, tx_en1; + + if (hal->antenna_tx == RF_A) + ntx_path = RF_PATH_A; + else if (hal->antenna_tx == RF_B) + ntx_path = RF_PATH_B; + + rtw8922a_hal_reset(rtwdev, RTW89_PHY_0, RTW89_MAC_0, band, &tx_en0, true); + if (rtwdev->dbcc_en) + rtw8922a_hal_reset(rtwdev, RTW89_PHY_1, RTW89_MAC_1, band, + &tx_en1, true); + + rtw8922a_ctrl_trx_path(rtwdev, ntx_path, 2, RF_PATH_AB, 2); + + rtw8922a_hal_reset(rtwdev, RTW89_PHY_0, RTW89_MAC_0, band, &tx_en0, false); + if (rtwdev->dbcc_en) + rtw8922a_hal_reset(rtwdev, RTW89_PHY_1, RTW89_MAC_1, band, + &tx_en0, false); +} + static void rtw8922a_fill_freq_with_ppdu(struct rtw89_dev *rtwdev, struct rtw89_rx_phy_ppdu *phy_ppdu, struct ieee80211_rx_status *status) @@ -1326,6 +1604,7 @@ static const struct rtw89_chip_ops rtw8922a_chip_ops = { .ctrl_btg_bt_rx = rtw8922a_ctrl_btg_bt_rx, .query_ppdu = rtw8922a_query_ppdu, .ctrl_nbtg_bt_tx = rtw8922a_ctrl_nbtg_bt_tx, + .cfg_txrx_path = rtw8922a_bb_cfg_txrx_path, .set_txpwr_ul_tb_offset = NULL, .pwr_on_func = rtw8922a_pwr_on_func, .pwr_off_func = rtw8922a_pwr_off_func, diff --git a/drivers/net/wireless/realtek/rtw89/rtw8922a_rfk.c b/drivers/net/wireless/realtek/rtw89/rtw8922a_rfk.c new file mode 100644 index 000000000000..e0e8048db739 --- /dev/null +++ b/drivers/net/wireless/realtek/rtw89/rtw8922a_rfk.c @@ -0,0 +1,33 @@ +// SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause +/* Copyright(c) 2023 Realtek Corporation + */ + +#include "debug.h" +#include "phy.h" +#include "reg.h" +#include "rtw8922a.h" +#include "rtw8922a_rfk.h" + +static void rtw8922a_tssi_cont_en(struct rtw89_dev *rtwdev, bool en, + enum rtw89_rf_path path) +{ + static const u32 tssi_trk_man[2] = {R_TSSI_PWR_P0, R_TSSI_PWR_P1}; + + if (en) + rtw89_phy_write32_mask(rtwdev, tssi_trk_man[path], B_TSSI_CONT_EN, 0); + else + rtw89_phy_write32_mask(rtwdev, tssi_trk_man[path], B_TSSI_CONT_EN, 1); +} + +void rtw8922a_tssi_cont_en_phyidx(struct rtw89_dev *rtwdev, bool en, u8 phy_idx) +{ + if (rtwdev->mlo_dbcc_mode == MLO_1_PLUS_1_1RF) { + if (phy_idx == RTW89_PHY_0) + rtw8922a_tssi_cont_en(rtwdev, en, RF_PATH_A); + else + rtw8922a_tssi_cont_en(rtwdev, en, RF_PATH_B); + } else { + rtw8922a_tssi_cont_en(rtwdev, en, RF_PATH_A); + rtw8922a_tssi_cont_en(rtwdev, en, RF_PATH_B); + } +} diff --git a/drivers/net/wireless/realtek/rtw89/rtw8922a_rfk.h b/drivers/net/wireless/realtek/rtw89/rtw8922a_rfk.h new file mode 100644 index 000000000000..fbd22de269e2 --- /dev/null +++ b/drivers/net/wireless/realtek/rtw89/rtw8922a_rfk.h @@ -0,0 +1,12 @@ +/* SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause */ +/* Copyright(c) 2023 Realtek Corporation + */ + +#ifndef __RTW89_8922A_RFK_H__ +#define __RTW89_8922A_RFK_H__ + +#include "core.h" + +void rtw8922a_tssi_cont_en_phyidx(struct rtw89_dev *rtwdev, bool en, u8 phy_idx); + +#endif -- cgit v1.2.3 From 88d1f9b22fab815dd8c27ccb06f30d4814eaa11a Mon Sep 17 00:00:00 2001 From: Ping-Ke Shih Date: Wed, 24 Jan 2024 11:36:35 +0800 Subject: wifi: rtw89: 8922a: add RF read/write v2 Implement indirect interface v2 to read/write RF registers via PHY registers for 8922A. Signed-off-by: Ping-Ke Shih Signed-off-by: Kalle Valo Link: https://msgid.link/20240124033637.12330-5-pkshih@realtek.com --- drivers/net/wireless/realtek/rtw89/phy.c | 125 ++++++++++++++++++++++++++ drivers/net/wireless/realtek/rtw89/phy.h | 4 + drivers/net/wireless/realtek/rtw89/reg.h | 15 ++++ drivers/net/wireless/realtek/rtw89/rtw8922a.c | 2 + 4 files changed, 146 insertions(+) (limited to 'drivers/net') diff --git a/drivers/net/wireless/realtek/rtw89/phy.c b/drivers/net/wireless/realtek/rtw89/phy.c index 7880fbaee092..f661be2f1287 100644 --- a/drivers/net/wireless/realtek/rtw89/phy.c +++ b/drivers/net/wireless/realtek/rtw89/phy.c @@ -796,6 +796,71 @@ u32 rtw89_phy_read_rf_v1(struct rtw89_dev *rtwdev, enum rtw89_rf_path rf_path, } EXPORT_SYMBOL(rtw89_phy_read_rf_v1); +static u32 rtw89_phy_read_full_rf_v2_a(struct rtw89_dev *rtwdev, + enum rtw89_rf_path rf_path, u32 addr) +{ + static const u16 r_addr_ofst[2] = {0x2C24, 0x2D24}; + static const u16 addr_ofst[2] = {0x2ADC, 0x2BDC}; + bool busy, done; + int ret; + u32 val; + + rtw89_phy_write32_mask(rtwdev, addr_ofst[rf_path], B_HWSI_ADD_CTL_MASK, 0x1); + ret = read_poll_timeout_atomic(rtw89_phy_read32_mask, busy, !busy, + 1, 3800, false, + rtwdev, r_addr_ofst[rf_path], B_HWSI_VAL_BUSY); + if (ret) { + rtw89_warn(rtwdev, "poll HWSI is busy\n"); + return INV_RF_DATA; + } + + rtw89_phy_write32_mask(rtwdev, addr_ofst[rf_path], B_HWSI_ADD_MASK, addr); + rtw89_phy_write32_mask(rtwdev, addr_ofst[rf_path], B_HWSI_ADD_RD, 0x1); + udelay(2); + + ret = read_poll_timeout_atomic(rtw89_phy_read32_mask, done, done, + 1, 3800, false, + rtwdev, r_addr_ofst[rf_path], B_HWSI_VAL_RDONE); + if (ret) { + rtw89_warn(rtwdev, "read HWSI is busy\n"); + val = INV_RF_DATA; + goto out; + } + + val = rtw89_phy_read32_mask(rtwdev, r_addr_ofst[rf_path], RFREG_MASK); +out: + rtw89_phy_write32_mask(rtwdev, addr_ofst[rf_path], B_HWSI_ADD_POLL_MASK, 0); + + return val; +} + +static u32 rtw89_phy_read_rf_v2_a(struct rtw89_dev *rtwdev, + enum rtw89_rf_path rf_path, u32 addr, u32 mask) +{ + u32 val; + + val = rtw89_phy_read_full_rf_v2_a(rtwdev, rf_path, addr); + + return (val & mask) >> __ffs(mask); +} + +u32 rtw89_phy_read_rf_v2(struct rtw89_dev *rtwdev, enum rtw89_rf_path rf_path, + u32 addr, u32 mask) +{ + bool ad_sel = u32_get_bits(addr, RTW89_RF_ADDR_ADSEL_MASK); + + if (rf_path >= rtwdev->chip->rf_path_num) { + rtw89_err(rtwdev, "unsupported rf path (%d)\n", rf_path); + return INV_RF_DATA; + } + + if (ad_sel) + return rtw89_phy_read_rf(rtwdev, rf_path, addr, mask); + else + return rtw89_phy_read_rf_v2_a(rtwdev, rf_path, addr, mask); +} +EXPORT_SYMBOL(rtw89_phy_read_rf_v2); + bool rtw89_phy_write_rf(struct rtw89_dev *rtwdev, enum rtw89_rf_path rf_path, u32 addr, u32 mask, u32 data) { @@ -875,6 +940,66 @@ bool rtw89_phy_write_rf_v1(struct rtw89_dev *rtwdev, enum rtw89_rf_path rf_path, } EXPORT_SYMBOL(rtw89_phy_write_rf_v1); +static +bool rtw89_phy_write_full_rf_v2_a(struct rtw89_dev *rtwdev, enum rtw89_rf_path rf_path, + u32 addr, u32 data) +{ + static const u32 addr_is_idle[2] = {0x2C24, 0x2D24}; + static const u32 addr_ofst[2] = {0x2AE0, 0x2BE0}; + bool busy; + u32 val; + int ret; + + ret = read_poll_timeout_atomic(rtw89_phy_read32_mask, busy, !busy, + 1, 3800, false, + rtwdev, addr_is_idle[rf_path], BIT(29)); + if (ret) { + rtw89_warn(rtwdev, "[%s] HWSI is busy\n", __func__); + return false; + } + + val = u32_encode_bits(addr, B_HWSI_DATA_ADDR) | + u32_encode_bits(data, B_HWSI_DATA_VAL); + + rtw89_phy_write32(rtwdev, addr_ofst[rf_path], val); + + return true; +} + +static +bool rtw89_phy_write_rf_a_v2(struct rtw89_dev *rtwdev, enum rtw89_rf_path rf_path, + u32 addr, u32 mask, u32 data) +{ + u32 val; + + if (mask == RFREG_MASK) { + val = data; + } else { + val = rtw89_phy_read_full_rf_v2_a(rtwdev, rf_path, addr); + val &= ~mask; + val |= (data << __ffs(mask)) & mask; + } + + return rtw89_phy_write_full_rf_v2_a(rtwdev, rf_path, addr, val); +} + +bool rtw89_phy_write_rf_v2(struct rtw89_dev *rtwdev, enum rtw89_rf_path rf_path, + u32 addr, u32 mask, u32 data) +{ + bool ad_sel = u32_get_bits(addr, RTW89_RF_ADDR_ADSEL_MASK); + + if (rf_path >= rtwdev->chip->rf_path_num) { + rtw89_err(rtwdev, "unsupported rf path (%d)\n", rf_path); + return INV_RF_DATA; + } + + if (ad_sel) + return rtw89_phy_write_rf(rtwdev, rf_path, addr, mask, data); + else + return rtw89_phy_write_rf_a_v2(rtwdev, rf_path, addr, mask, data); +} +EXPORT_SYMBOL(rtw89_phy_write_rf_v2); + static bool rtw89_chip_rf_v1(struct rtw89_dev *rtwdev) { return rtwdev->chip->ops->write_rf == rtw89_phy_write_rf_v1; diff --git a/drivers/net/wireless/realtek/rtw89/phy.h b/drivers/net/wireless/realtek/rtw89/phy.h index c05f724a84ce..13903ca1eaa9 100644 --- a/drivers/net/wireless/realtek/rtw89/phy.h +++ b/drivers/net/wireless/realtek/rtw89/phy.h @@ -781,10 +781,14 @@ u32 rtw89_phy_read_rf(struct rtw89_dev *rtwdev, enum rtw89_rf_path rf_path, u32 addr, u32 mask); u32 rtw89_phy_read_rf_v1(struct rtw89_dev *rtwdev, enum rtw89_rf_path rf_path, u32 addr, u32 mask); +u32 rtw89_phy_read_rf_v2(struct rtw89_dev *rtwdev, enum rtw89_rf_path rf_path, + u32 addr, u32 mask); bool rtw89_phy_write_rf(struct rtw89_dev *rtwdev, enum rtw89_rf_path rf_path, u32 addr, u32 mask, u32 data); bool rtw89_phy_write_rf_v1(struct rtw89_dev *rtwdev, enum rtw89_rf_path rf_path, u32 addr, u32 mask, u32 data); +bool rtw89_phy_write_rf_v2(struct rtw89_dev *rtwdev, enum rtw89_rf_path rf_path, + u32 addr, u32 mask, u32 data); void rtw89_phy_init_bb_reg(struct rtw89_dev *rtwdev); void rtw89_phy_init_rf_reg(struct rtw89_dev *rtwdev, bool noio); void rtw89_phy_config_rf_reg_v1(struct rtw89_dev *rtwdev, diff --git a/drivers/net/wireless/realtek/rtw89/reg.h b/drivers/net/wireless/realtek/rtw89/reg.h index d7217f2a26aa..95c06b98192c 100644 --- a/drivers/net/wireless/realtek/rtw89/reg.h +++ b/drivers/net/wireless/realtek/rtw89/reg.h @@ -7997,6 +7997,21 @@ #define B_AFEDAC1 GENMASK(2, 0) #define R_IQKDPK_HC 0x2AB8 #define B_IQKDPK_HC BIT(28) +#define R_HWSI_ADD0 0x2ADC +#define R_HWSI_ADD1 0x2BDC +#define B_HWSI_ADD_MASK GENMASK(11, 4) +#define B_HWSI_ADD_CTL_MASK GENMASK(2, 0) +#define B_HWSI_ADD_RD BIT(2) +#define B_HWSI_ADD_POLL_MASK GENMASK(1, 0) +#define B_HWSI_ADD_RUN BIT(1) +#define B_HWSI_ADD_BUSY BIT(0) +#define R_HWSI_DATA 0x2AE0 +#define B_HWSI_DATA_VAL GENMASK(27, 8) +#define B_HWSI_DATA_ADDR GENMASK(7, 0) +#define R_HWSI_VAL0 0x2C24 +#define R_HWSI_VAL1 0x2D24 +#define B_HWSI_VAL_RDONE BIT(31) +#define B_HWSI_VAL_BUSY BIT(29) #define R_P1_EN_SOUND_WO_NDP 0x2D7C #define B_P1_EN_SOUND_WO_NDP BIT(1) #define R_EDCCA_RPT_A_BE 0x2E38 diff --git a/drivers/net/wireless/realtek/rtw89/rtw8922a.c b/drivers/net/wireless/realtek/rtw89/rtw8922a.c index 2481f983b426..1c5ceb5564c3 100644 --- a/drivers/net/wireless/realtek/rtw89/rtw8922a.c +++ b/drivers/net/wireless/realtek/rtw89/rtw8922a.c @@ -1594,6 +1594,8 @@ static const struct rtw89_chip_ops rtw8922a_chip_ops = { .bb_postinit = rtw8922a_bb_postinit, .bb_reset = rtw8922a_bb_reset, .bb_sethw = rtw8922a_bb_sethw, + .read_rf = rtw89_phy_read_rf_v2, + .write_rf = rtw89_phy_write_rf_v2, .set_channel = rtw8922a_set_channel, .read_efuse = rtw8922a_read_efuse, .read_phycap = rtw8922a_read_phycap, -- cgit v1.2.3 From 1de97cd362c4080aab595b84bf0bff3ebc702446 Mon Sep 17 00:00:00 2001 From: Ping-Ke Shih Date: Wed, 24 Jan 2024 11:38:02 +0800 Subject: wifi: rtw89: 8922a: add chip_ops to get thermal value Get thermal value as a clue to do RF calibration if the delta is larger than a threshold, but 8922A doesn't need this, so we only read out the value when debugging to reduce IO. Signed-off-by: Ping-Ke Shih Signed-off-by: Kalle Valo Link: https://msgid.link/20240124033802.12508-1-pkshih@realtek.com --- drivers/net/wireless/realtek/rtw89/reg.h | 1 + drivers/net/wireless/realtek/rtw89/rtw8922a.c | 22 ++++++++++++++++++++++ 2 files changed, 23 insertions(+) (limited to 'drivers/net') diff --git a/drivers/net/wireless/realtek/rtw89/reg.h b/drivers/net/wireless/realtek/rtw89/reg.h index 95c06b98192c..addf11fc76d4 100644 --- a/drivers/net/wireless/realtek/rtw89/reg.h +++ b/drivers/net/wireless/realtek/rtw89/reg.h @@ -7468,6 +7468,7 @@ #define RR_LUTWD0_LB GENMASK(5, 0) #define RR_TM 0x42 #define RR_TM_TRI BIT(19) +#define RR_TM_VAL_V1 GENMASK(7, 0) #define RR_TM_VAL GENMASK(6, 1) #define RR_TM2 0x43 #define RR_TM2_OFF GENMASK(19, 16) diff --git a/drivers/net/wireless/realtek/rtw89/rtw8922a.c b/drivers/net/wireless/realtek/rtw89/rtw8922a.c index 1c5ceb5564c3..6de3c0f8d83a 100644 --- a/drivers/net/wireless/realtek/rtw89/rtw8922a.c +++ b/drivers/net/wireless/realtek/rtw89/rtw8922a.c @@ -1528,6 +1528,27 @@ static void rtw8922a_bb_cfg_txrx_path(struct rtw89_dev *rtwdev) &tx_en0, false); } +static u8 rtw8922a_get_thermal(struct rtw89_dev *rtwdev, enum rtw89_rf_path rf_path) +{ + struct rtw89_power_trim_info *info = &rtwdev->pwr_trim; + int th; + + /* read thermal only if debugging */ + if (!rtw89_debug_is_enabled(rtwdev, RTW89_DBG_CFO | RTW89_DBG_RFK_TRACK)) + return 80; + + rtw89_write_rf(rtwdev, rf_path, RR_TM, RR_TM_TRI, 0x1); + rtw89_write_rf(rtwdev, rf_path, RR_TM, RR_TM_TRI, 0x0); + rtw89_write_rf(rtwdev, rf_path, RR_TM, RR_TM_TRI, 0x1); + + fsleep(200); + + th = rtw89_read_rf(rtwdev, rf_path, RR_TM, RR_TM_VAL_V1); + th += (s8)info->thermal_trim[rf_path]; + + return clamp_t(int, th, 0, U8_MAX); +} + static void rtw8922a_fill_freq_with_ppdu(struct rtw89_dev *rtwdev, struct rtw89_rx_phy_ppdu *phy_ppdu, struct ieee80211_rx_status *status) @@ -1603,6 +1624,7 @@ static const struct rtw89_chip_ops rtw8922a_chip_ops = { .set_txpwr = rtw8922a_set_txpwr, .set_txpwr_ctrl = rtw8922a_set_txpwr_ctrl, .init_txpwr_unit = NULL, + .get_thermal = rtw8922a_get_thermal, .ctrl_btg_bt_rx = rtw8922a_ctrl_btg_bt_rx, .query_ppdu = rtw8922a_query_ppdu, .ctrl_nbtg_bt_tx = rtw8922a_ctrl_nbtg_bt_tx, -- cgit v1.2.3 From a6c759c8962b11fdc62ced6f70a3f6ed0a50e033 Mon Sep 17 00:00:00 2001 From: Ping-Ke Shih Date: Wed, 24 Jan 2024 11:38:13 +0800 Subject: wifi: rtw89: 8922a: set chip_ops FEM and GPIO to NULL The chip_ops::fem_setup is to get if a hardware module type contains PA and LNA that will affect how RF calibrations do. The chip_ops::rfe_gpio is to set GPIO PIN MUX according to hardware module type too. 8922A doesn't have these special module types yet, so leave them as NULL. Signed-off-by: Ping-Ke Shih Signed-off-by: Kalle Valo Link: https://msgid.link/20240124033813.12562-1-pkshih@realtek.com --- drivers/net/wireless/realtek/rtw89/rtw8922a.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'drivers/net') diff --git a/drivers/net/wireless/realtek/rtw89/rtw8922a.c b/drivers/net/wireless/realtek/rtw89/rtw8922a.c index 6de3c0f8d83a..aefad3f2e612 100644 --- a/drivers/net/wireless/realtek/rtw89/rtw8922a.c +++ b/drivers/net/wireless/realtek/rtw89/rtw8922a.c @@ -1620,6 +1620,8 @@ static const struct rtw89_chip_ops rtw8922a_chip_ops = { .set_channel = rtw8922a_set_channel, .read_efuse = rtw8922a_read_efuse, .read_phycap = rtw8922a_read_phycap, + .fem_setup = NULL, + .rfe_gpio = NULL, .power_trim = rtw8922a_power_trim, .set_txpwr = rtw8922a_set_txpwr, .set_txpwr_ctrl = rtw8922a_set_txpwr_ctrl, -- cgit v1.2.3 From b5d7020134d91ccb9ae763f738aaa466e37ac25a Mon Sep 17 00:00:00 2001 From: Po-Hao Huang Date: Fri, 26 Jan 2024 14:33:50 +0800 Subject: wifi: rtw89: update scan C2H messages for wifi 7 IC Add definition and parsing for wifi 7 extended fields. These fields include hardware index which is current reporting, timestamp and self defined sequences for debug purposes. Signed-off-by: Po-Hao Huang Signed-off-by: Ping-Ke Shih Signed-off-by: Kalle Valo Link: https://msgid.link/20240126063356.17857-2-pkshih@realtek.com --- drivers/net/wireless/realtek/rtw89/fw.h | 5 +++++ drivers/net/wireless/realtek/rtw89/mac.c | 24 ++++++++++++++++++++---- 2 files changed, 25 insertions(+), 4 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/realtek/rtw89/fw.h b/drivers/net/wireless/realtek/rtw89/fw.h index a3df701bdc6e..2c94d82d384c 100644 --- a/drivers/net/wireless/realtek/rtw89/fw.h +++ b/drivers/net/wireless/realtek/rtw89/fw.h @@ -3309,6 +3309,11 @@ struct rtw89_c2h_scanofld { #define RTW89_C2H_SCANOFLD_W5_TX_FAIL GENMASK(3, 0) #define RTW89_C2H_SCANOFLD_W5_AIR_DENSITY GENMASK(7, 4) #define RTW89_C2H_SCANOFLD_W5_BAND GENMASK(25, 24) +#define RTW89_C2H_SCANOFLD_W5_MAC_IDX BIT(26) +#define RTW89_C2H_SCANOFLD_W6_SW_DEF GENMASK(7, 0) +#define RTW89_C2H_SCANOFLD_W6_EXPECT_PERIOD GENMASK(15, 8) +#define RTW89_C2H_SCANOFLD_W6_FW_DEF GENMASK(23, 16) +#define RTW89_C2H_SCANOFLD_W7_REPORT_TSF GENMASK(31, 0) #define RTW89_GET_MAC_C2H_MCC_RCV_ACK_GROUP(c2h) \ le32_get_bits(*((const __le32 *)(c2h) + 2), GENMASK(1, 0)) diff --git a/drivers/net/wireless/realtek/rtw89/mac.c b/drivers/net/wireless/realtek/rtw89/mac.c index d1d16564a686..247c566b851a 100644 --- a/drivers/net/wireless/realtek/rtw89/mac.c +++ b/drivers/net/wireless/realtek/rtw89/mac.c @@ -4686,8 +4686,9 @@ rtw89_mac_c2h_scanofld_rsp(struct rtw89_dev *rtwdev, struct sk_buff *skb, struct ieee80211_vif *vif = rtwdev->scan_info.scanning_vif; struct rtw89_vif *rtwvif = vif_to_rtwvif_safe(vif); struct rtw89_chan new; - u8 reason, status, tx_fail, band, actual_period; - u32 last_chan = rtwdev->scan_info.last_chan_idx; + u8 reason, status, tx_fail, band, actual_period, expect_period; + u32 last_chan = rtwdev->scan_info.last_chan_idx, report_tsf; + u8 mac_idx, sw_def, fw_def; u16 chan; int ret; @@ -4700,15 +4701,29 @@ rtw89_mac_c2h_scanofld_rsp(struct rtw89_dev *rtwdev, struct sk_buff *skb, reason = le32_get_bits(c2h->w2, RTW89_C2H_SCANOFLD_W2_RSN); band = le32_get_bits(c2h->w5, RTW89_C2H_SCANOFLD_W5_BAND); actual_period = le32_get_bits(c2h->w2, RTW89_C2H_SCANOFLD_W2_PERIOD); + mac_idx = le32_get_bits(c2h->w5, RTW89_C2H_SCANOFLD_W5_MAC_IDX); + if (!(rtwdev->chip->support_bands & BIT(NL80211_BAND_6GHZ))) band = chan > 14 ? RTW89_BAND_5G : RTW89_BAND_2G; rtw89_debug(rtwdev, RTW89_DBG_HW_SCAN, - "band: %d, chan: %d, reason: %d, status: %d, tx_fail: %d, actual: %d\n", - band, chan, reason, status, tx_fail, actual_period); + "mac_idx[%d] band: %d, chan: %d, reason: %d, status: %d, tx_fail: %d, actual: %d\n", + mac_idx, band, chan, reason, status, tx_fail, actual_period); + + if (rtwdev->chip->chip_gen == RTW89_CHIP_BE) { + sw_def = le32_get_bits(c2h->w6, RTW89_C2H_SCANOFLD_W6_SW_DEF); + expect_period = le32_get_bits(c2h->w6, RTW89_C2H_SCANOFLD_W6_EXPECT_PERIOD); + fw_def = le32_get_bits(c2h->w6, RTW89_C2H_SCANOFLD_W6_FW_DEF); + report_tsf = le32_get_bits(c2h->w7, RTW89_C2H_SCANOFLD_W7_REPORT_TSF); + + rtw89_debug(rtwdev, RTW89_DBG_HW_SCAN, + "sw_def: %d, fw_def: %d, tsf: %x, expect: %d\n", + sw_def, fw_def, report_tsf, expect_period); + } switch (reason) { + case RTW89_SCAN_LEAVE_OP_NOTIFY: case RTW89_SCAN_LEAVE_CH_NOTIFY: if (rtw89_is_op_chan(rtwdev, band, chan)) { rtw89_mac_enable_beacon_for_ap_vifs(rtwdev, false); @@ -4727,6 +4742,7 @@ rtw89_mac_c2h_scanofld_rsp(struct rtw89_dev *rtwdev, struct sk_buff *skb, rtw89_hw_scan_complete(rtwdev, vif, rtwdev->scan_info.abort); } break; + case RTW89_SCAN_ENTER_OP_NOTIFY: case RTW89_SCAN_ENTER_CH_NOTIFY: if (rtw89_is_op_chan(rtwdev, band, chan)) { rtw89_assign_entity_chan(rtwdev, rtwvif->sub_entity_idx, -- cgit v1.2.3 From ac54faf507e5d2776a7dca2c13665745d4490cd5 Mon Sep 17 00:00:00 2001 From: Po-Hao Huang Date: Fri, 26 Jan 2024 14:33:51 +0800 Subject: wifi: rtw89: debug: add FW log component for scan This allows scan related logs when FW log debug mode is on. Signed-off-by: Po-Hao Huang Signed-off-by: Ping-Ke Shih Signed-off-by: Kalle Valo Link: https://msgid.link/20240126063356.17857-3-pkshih@realtek.com --- drivers/net/wireless/realtek/rtw89/fw.c | 8 ++++++-- drivers/net/wireless/realtek/rtw89/fw.h | 1 + 2 files changed, 7 insertions(+), 2 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/realtek/rtw89/fw.c b/drivers/net/wireless/realtek/rtw89/fw.c index e49360e29faf..43fe9333d3e7 100644 --- a/drivers/net/wireless/realtek/rtw89/fw.c +++ b/drivers/net/wireless/realtek/rtw89/fw.c @@ -1829,10 +1829,14 @@ fail: int rtw89_fw_h2c_fw_log(struct rtw89_dev *rtwdev, bool enable) { struct sk_buff *skb; - u32 comp = enable ? BIT(RTW89_FW_LOG_COMP_INIT) | BIT(RTW89_FW_LOG_COMP_TASK) | - BIT(RTW89_FW_LOG_COMP_PS) | BIT(RTW89_FW_LOG_COMP_ERROR) : 0; + u32 comp = 0; int ret; + if (enable) + comp = BIT(RTW89_FW_LOG_COMP_INIT) | BIT(RTW89_FW_LOG_COMP_TASK) | + BIT(RTW89_FW_LOG_COMP_PS) | BIT(RTW89_FW_LOG_COMP_ERROR) | + BIT(RTW89_FW_LOG_COMP_SCAN); + skb = rtw89_fw_h2c_alloc_skb_with_hdr(rtwdev, H2C_LOG_CFG_LEN); if (!skb) { rtw89_err(rtwdev, "failed to alloc skb for fw log cfg\n"); diff --git a/drivers/net/wireless/realtek/rtw89/fw.h b/drivers/net/wireless/realtek/rtw89/fw.h index 2c94d82d384c..cb5b7bf88177 100644 --- a/drivers/net/wireless/realtek/rtw89/fw.h +++ b/drivers/net/wireless/realtek/rtw89/fw.h @@ -149,6 +149,7 @@ enum rtw89_fw_log_comp { RTW89_FW_LOG_COMP_TWT, RTW89_FW_LOG_COMP_RF, RTW89_FW_LOG_COMP_MCC = 20, + RTW89_FW_LOG_COMP_SCAN = 28, }; enum rtw89_pkt_offload_op { -- cgit v1.2.3 From a412920b70199c07504ea9e937b00f07916a541a Mon Sep 17 00:00:00 2001 From: Po-Hao Huang Date: Fri, 26 Jan 2024 14:33:52 +0800 Subject: wifi: rtw89: prepare scan leaf functions for wifi 7 ICs The channel field slightly differs between WiFi 6 and WiFi 7. So we prepare some required functions in advance, this doesn't change existing wifi 6 ICs behavior. This H2C prepares the channel list to be scanned for. With layout as the following: +--------+--------------------+-------------------+-----------------------+ | header | number of channels | channel info size | channel_info * number | +--------+--------------------+-------------------+-----------------------+ Signed-off-by: Po-Hao Huang Signed-off-by: Ping-Ke Shih Signed-off-by: Kalle Valo Link: https://msgid.link/20240126063356.17857-4-pkshih@realtek.com --- drivers/net/wireless/realtek/rtw89/fw.c | 220 +++++++++++++++++++++++++++- drivers/net/wireless/realtek/rtw89/fw.h | 79 +++++++++- drivers/net/wireless/realtek/rtw89/mac.c | 2 + drivers/net/wireless/realtek/rtw89/mac.h | 3 + drivers/net/wireless/realtek/rtw89/mac_be.c | 2 + 5 files changed, 302 insertions(+), 4 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/realtek/rtw89/fw.c b/drivers/net/wireless/realtek/rtw89/fw.c index 43fe9333d3e7..ea308244b303 100644 --- a/drivers/net/wireless/realtek/rtw89/fw.c +++ b/drivers/net/wireless/realtek/rtw89/fw.c @@ -4078,6 +4078,102 @@ int rtw89_fw_h2c_scan_list_offload(struct rtw89_dev *rtwdev, int ch_num, return 0; } +int rtw89_fw_h2c_scan_list_offload_be(struct rtw89_dev *rtwdev, int ch_num, + struct list_head *chan_list) +{ + struct rtw89_wait_info *wait = &rtwdev->mac.fw_ofld_wait; + struct rtw89_h2c_chinfo_elem_be *elem; + struct rtw89_mac_chinfo_be *ch_info; + struct rtw89_h2c_chinfo *h2c; + struct sk_buff *skb; + unsigned int cond; + int skb_len; + int ret; + + static_assert(sizeof(*elem) == RTW89_MAC_CHINFO_SIZE); + + skb_len = struct_size(h2c, elem, ch_num); + skb = rtw89_fw_h2c_alloc_skb_with_hdr(rtwdev, skb_len); + if (!skb) { + rtw89_err(rtwdev, "failed to alloc skb for h2c scan list\n"); + return -ENOMEM; + } + + skb_put(skb, sizeof(*h2c)); + h2c = (struct rtw89_h2c_chinfo *)skb->data; + + h2c->ch_num = ch_num; + h2c->elem_size = sizeof(*elem) / 4; /* in unit of 4 bytes */ + h2c->arg = u8_encode_bits(RTW89_PHY_0, RTW89_H2C_CHINFO_ARG_MAC_IDX_MASK); + + list_for_each_entry(ch_info, chan_list, list) { + elem = (struct rtw89_h2c_chinfo_elem_be *)skb_put(skb, sizeof(*elem)); + + elem->w0 = le32_encode_bits(ch_info->period, RTW89_H2C_CHINFO_BE_W0_PERIOD) | + le32_encode_bits(ch_info->dwell_time, RTW89_H2C_CHINFO_BE_W0_DWELL) | + le32_encode_bits(ch_info->central_ch, + RTW89_H2C_CHINFO_BE_W0_CENTER_CH) | + le32_encode_bits(ch_info->pri_ch, RTW89_H2C_CHINFO_BE_W0_PRI_CH); + + elem->w1 = le32_encode_bits(ch_info->bw, RTW89_H2C_CHINFO_BE_W1_BW) | + le32_encode_bits(ch_info->ch_band, RTW89_H2C_CHINFO_BE_W1_CH_BAND) | + le32_encode_bits(ch_info->dfs_ch, RTW89_H2C_CHINFO_BE_W1_DFS) | + le32_encode_bits(ch_info->pause_data, + RTW89_H2C_CHINFO_BE_W1_PAUSE_DATA) | + le32_encode_bits(ch_info->tx_null, RTW89_H2C_CHINFO_BE_W1_TX_NULL) | + le32_encode_bits(ch_info->rand_seq_num, + RTW89_H2C_CHINFO_BE_W1_RANDOM) | + le32_encode_bits(ch_info->notify_action, + RTW89_H2C_CHINFO_BE_W1_NOTIFY) | + le32_encode_bits(ch_info->probe_id != 0xff ? 1 : 0, + RTW89_H2C_CHINFO_BE_W1_PROBE) | + le32_encode_bits(ch_info->leave_crit, + RTW89_H2C_CHINFO_BE_W1_EARLY_LEAVE_CRIT) | + le32_encode_bits(ch_info->chkpt_timer, + RTW89_H2C_CHINFO_BE_W1_CHKPT_TIMER); + + elem->w2 = le32_encode_bits(ch_info->leave_time, + RTW89_H2C_CHINFO_BE_W2_EARLY_LEAVE_TIME) | + le32_encode_bits(ch_info->leave_th, + RTW89_H2C_CHINFO_BE_W2_EARLY_LEAVE_TH) | + le32_encode_bits(ch_info->tx_pkt_ctrl, + RTW89_H2C_CHINFO_BE_W2_TX_PKT_CTRL); + + elem->w3 = le32_encode_bits(ch_info->pkt_id[0], RTW89_H2C_CHINFO_BE_W3_PKT0) | + le32_encode_bits(ch_info->pkt_id[1], RTW89_H2C_CHINFO_BE_W3_PKT1) | + le32_encode_bits(ch_info->pkt_id[2], RTW89_H2C_CHINFO_BE_W3_PKT2) | + le32_encode_bits(ch_info->pkt_id[3], RTW89_H2C_CHINFO_BE_W3_PKT3); + + elem->w4 = le32_encode_bits(ch_info->pkt_id[4], RTW89_H2C_CHINFO_BE_W4_PKT4) | + le32_encode_bits(ch_info->pkt_id[5], RTW89_H2C_CHINFO_BE_W4_PKT5) | + le32_encode_bits(ch_info->pkt_id[6], RTW89_H2C_CHINFO_BE_W4_PKT6) | + le32_encode_bits(ch_info->pkt_id[7], RTW89_H2C_CHINFO_BE_W4_PKT7); + + elem->w5 = le32_encode_bits(ch_info->sw_def, RTW89_H2C_CHINFO_BE_W5_SW_DEF) | + le32_encode_bits(ch_info->fw_probe0_ssids, + RTW89_H2C_CHINFO_BE_W5_FW_PROBE0_SSIDS); + + elem->w6 = le32_encode_bits(ch_info->fw_probe0_shortssids, + RTW89_H2C_CHINFO_BE_W6_FW_PROBE0_SHORTSSIDS) | + le32_encode_bits(ch_info->fw_probe0_bssids, + RTW89_H2C_CHINFO_BE_W6_FW_PROBE0_BSSIDS); + } + + rtw89_h2c_pkt_set_hdr(rtwdev, skb, FWCMD_TYPE_H2C, + H2C_CAT_MAC, H2C_CL_MAC_FW_OFLD, + H2C_FUNC_ADD_SCANOFLD_CH, 1, 1, skb_len); + + cond = RTW89_SCANOFLD_WAIT_COND_ADD_CH; + + ret = rtw89_h2c_tx_and_wait(rtwdev, skb, wait, cond); + if (ret) { + rtw89_debug(rtwdev, RTW89_DBG_FW, "failed to add scan ofld ch\n"); + return ret; + } + + return 0; +} + int rtw89_fw_h2c_scan_offload(struct rtw89_dev *rtwdev, struct rtw89_scan_option *option, struct rtw89_vif *rtwvif) @@ -4769,8 +4865,66 @@ static void rtw89_hw_scan_add_chan(struct rtw89_dev *rtwdev, int chan_type, } } -static int rtw89_hw_scan_add_chan_list(struct rtw89_dev *rtwdev, - struct rtw89_vif *rtwvif, bool connected) +static void rtw89_hw_scan_add_chan_be(struct rtw89_dev *rtwdev, int chan_type, + int ssid_num, + struct rtw89_mac_chinfo_be *ch_info) +{ + struct rtw89_hw_scan_info *scan_info = &rtwdev->scan_info; + struct ieee80211_vif *vif = rtwdev->scan_info.scanning_vif; + struct rtw89_vif *rtwvif = (struct rtw89_vif *)vif->drv_priv; + struct cfg80211_scan_request *req = rtwvif->scan_req; + struct rtw89_pktofld_info *info; + u8 band, probe_count = 0, i; + + ch_info->notify_action = RTW89_SCANOFLD_DEBUG_MASK; + ch_info->dfs_ch = chan_type == RTW89_CHAN_DFS; + ch_info->bw = RTW89_SCAN_WIDTH; + ch_info->tx_null = false; + ch_info->pause_data = false; + ch_info->probe_id = RTW89_SCANOFLD_PKT_NONE; + + if (ssid_num) { + band = rtw89_hw_to_nl80211_band(ch_info->ch_band); + + list_for_each_entry(info, &scan_info->pkt_list[band], list) { + if (info->channel_6ghz && + ch_info->pri_ch != info->channel_6ghz) + continue; + ch_info->pkt_id[probe_count++] = info->id; + if (probe_count >= RTW89_SCANOFLD_MAX_SSID) + break; + } + } + + if (ch_info->ch_band == RTW89_BAND_6G) { + if ((ssid_num == 1 && req->ssids[0].ssid_len == 0) || + !ch_info->is_psc) { + ch_info->probe_id = RTW89_SCANOFLD_PKT_NONE; + if (!req->duration_mandatory) + ch_info->period -= RTW89_DWELL_TIME_6G; + } + } + + for (i = probe_count; i < RTW89_SCANOFLD_MAX_SSID; i++) + ch_info->pkt_id[i] = RTW89_SCANOFLD_PKT_NONE; + + switch (chan_type) { + case RTW89_CHAN_DFS: + if (ch_info->ch_band != RTW89_BAND_6G) + ch_info->period = + max_t(u8, ch_info->period, RTW89_DFS_CHAN_TIME); + ch_info->dwell_time = RTW89_DWELL_TIME; + break; + case RTW89_CHAN_ACTIVE: + break; + default: + rtw89_warn(rtwdev, "Channel type out of bound\n"); + break; + } +} + +int rtw89_hw_scan_add_chan_list(struct rtw89_dev *rtwdev, + struct rtw89_vif *rtwvif, bool connected) { struct cfg80211_scan_request *req = rtwvif->scan_req; struct rtw89_mac_chinfo *ch_info, *tmp; @@ -4846,9 +5000,69 @@ out: return ret; } +int rtw89_hw_scan_add_chan_list_be(struct rtw89_dev *rtwdev, + struct rtw89_vif *rtwvif, bool connected) +{ + struct cfg80211_scan_request *req = rtwvif->scan_req; + struct rtw89_mac_chinfo_be *ch_info, *tmp; + struct ieee80211_channel *channel; + struct list_head chan_list; + enum rtw89_chan_type type; + int list_len, ret; + bool random_seq; + u32 idx; + + random_seq = !!(req->flags & NL80211_SCAN_FLAG_RANDOM_SN); + INIT_LIST_HEAD(&chan_list); + + for (idx = rtwdev->scan_info.last_chan_idx, list_len = 0; + idx < req->n_channels && list_len < RTW89_SCAN_LIST_LIMIT; + idx++, list_len++) { + channel = req->channels[idx]; + ch_info = kzalloc(sizeof(*ch_info), GFP_KERNEL); + if (!ch_info) { + ret = -ENOMEM; + goto out; + } + + if (req->duration_mandatory) + ch_info->period = req->duration; + else if (channel->band == NL80211_BAND_6GHZ) + ch_info->period = RTW89_CHANNEL_TIME_6G + RTW89_DWELL_TIME_6G; + else + ch_info->period = RTW89_CHANNEL_TIME; + + ch_info->ch_band = rtw89_nl80211_to_hw_band(channel->band); + ch_info->central_ch = channel->hw_value; + ch_info->pri_ch = channel->hw_value; + ch_info->rand_seq_num = random_seq; + ch_info->is_psc = cfg80211_channel_is_psc(channel); + + if (channel->flags & (IEEE80211_CHAN_RADAR | IEEE80211_CHAN_NO_IR)) + type = RTW89_CHAN_DFS; + else + type = RTW89_CHAN_ACTIVE; + rtw89_hw_scan_add_chan_be(rtwdev, type, req->n_ssids, ch_info); + + list_add_tail(&ch_info->list, &chan_list); + } + + rtwdev->scan_info.last_chan_idx = idx; + ret = rtw89_fw_h2c_scan_list_offload_be(rtwdev, list_len, &chan_list); + +out: + list_for_each_entry_safe(ch_info, tmp, &chan_list, list) { + list_del(&ch_info->list); + kfree(ch_info); + } + + return ret; +} + static int rtw89_hw_scan_prehandle(struct rtw89_dev *rtwdev, struct rtw89_vif *rtwvif, bool connected) { + const struct rtw89_mac_gen_def *mac = rtwdev->chip->mac_def; int ret; ret = rtw89_hw_scan_update_probe_req(rtwdev, rtwvif); @@ -4856,7 +5070,7 @@ static int rtw89_hw_scan_prehandle(struct rtw89_dev *rtwdev, rtw89_err(rtwdev, "Update probe request failed\n"); goto out; } - ret = rtw89_hw_scan_add_chan_list(rtwdev, rtwvif, connected); + ret = mac->add_chan_list(rtwdev, rtwvif, connected); out: return ret; } diff --git a/drivers/net/wireless/realtek/rtw89/fw.h b/drivers/net/wireless/realtek/rtw89/fw.h index cb5b7bf88177..132809ea05bf 100644 --- a/drivers/net/wireless/realtek/rtw89/fw.h +++ b/drivers/net/wireless/realtek/rtw89/fw.h @@ -297,6 +297,34 @@ struct rtw89_mac_chinfo { bool is_psc; }; +struct rtw89_mac_chinfo_be { + u8 period; + u8 dwell_time; + u8 central_ch; + u8 pri_ch; + u8 bw:3; + u8 ch_band:2; + u8 dfs_ch:1; + u8 pause_data:1; + u8 tx_null:1; + u8 rand_seq_num:1; + u8 notify_action:5; + u8 probe_id; + u8 leave_crit; + u8 chkpt_timer; + u8 leave_time; + u8 leave_th; + u16 tx_pkt_ctrl; + u8 pkt_id[RTW89_SCANOFLD_MAX_SSID]; + u8 sw_def; + u16 fw_probe0_ssids; + u16 fw_probe0_shortssids; + u16 fw_probe0_bssids; + + struct list_head list; + bool is_psc; +}; + struct rtw89_scan_option { bool enable; bool target_ch_mode; @@ -2708,14 +2736,57 @@ struct rtw89_h2c_chinfo_elem { #define RTW89_H2C_CHINFO_W3_PKT7 GENMASK(31, 24) #define RTW89_H2C_CHINFO_W4_POWER_IDX GENMASK(15, 0) +struct rtw89_h2c_chinfo_elem_be { + __le32 w0; + __le32 w1; + __le32 w2; + __le32 w3; + __le32 w4; + __le32 w5; + __le32 w6; +} __packed; + +#define RTW89_H2C_CHINFO_BE_W0_PERIOD GENMASK(7, 0) +#define RTW89_H2C_CHINFO_BE_W0_DWELL GENMASK(15, 8) +#define RTW89_H2C_CHINFO_BE_W0_CENTER_CH GENMASK(23, 16) +#define RTW89_H2C_CHINFO_BE_W0_PRI_CH GENMASK(31, 24) +#define RTW89_H2C_CHINFO_BE_W1_BW GENMASK(2, 0) +#define RTW89_H2C_CHINFO_BE_W1_CH_BAND GENMASK(4, 3) +#define RTW89_H2C_CHINFO_BE_W1_DFS BIT(5) +#define RTW89_H2C_CHINFO_BE_W1_PAUSE_DATA BIT(6) +#define RTW89_H2C_CHINFO_BE_W1_TX_NULL BIT(7) +#define RTW89_H2C_CHINFO_BE_W1_RANDOM BIT(8) +#define RTW89_H2C_CHINFO_BE_W1_NOTIFY GENMASK(13, 9) +#define RTW89_H2C_CHINFO_BE_W1_PROBE BIT(14) +#define RTW89_H2C_CHINFO_BE_W1_EARLY_LEAVE_CRIT GENMASK(17, 15) +#define RTW89_H2C_CHINFO_BE_W1_CHKPT_TIMER GENMASK(31, 24) +#define RTW89_H2C_CHINFO_BE_W2_EARLY_LEAVE_TIME GENMASK(7, 0) +#define RTW89_H2C_CHINFO_BE_W2_EARLY_LEAVE_TH GENMASK(15, 8) +#define RTW89_H2C_CHINFO_BE_W2_TX_PKT_CTRL GENMASK(31, 16) +#define RTW89_H2C_CHINFO_BE_W3_PKT0 GENMASK(7, 0) +#define RTW89_H2C_CHINFO_BE_W3_PKT1 GENMASK(15, 8) +#define RTW89_H2C_CHINFO_BE_W3_PKT2 GENMASK(23, 16) +#define RTW89_H2C_CHINFO_BE_W3_PKT3 GENMASK(31, 24) +#define RTW89_H2C_CHINFO_BE_W4_PKT4 GENMASK(7, 0) +#define RTW89_H2C_CHINFO_BE_W4_PKT5 GENMASK(15, 8) +#define RTW89_H2C_CHINFO_BE_W4_PKT6 GENMASK(23, 16) +#define RTW89_H2C_CHINFO_BE_W4_PKT7 GENMASK(31, 24) +#define RTW89_H2C_CHINFO_BE_W5_SW_DEF GENMASK(7, 0) +#define RTW89_H2C_CHINFO_BE_W5_FW_PROBE0_SSIDS GENMASK(31, 16) +#define RTW89_H2C_CHINFO_BE_W6_FW_PROBE0_SHORTSSIDS GENMASK(15, 0) +#define RTW89_H2C_CHINFO_BE_W6_FW_PROBE0_BSSIDS GENMASK(31, 16) + struct rtw89_h2c_chinfo { u8 ch_num; u8 elem_size; + u8 arg; u8 rsvd0; - u8 rsvd1; struct rtw89_h2c_chinfo_elem elem[] __counted_by(ch_num); } __packed; +#define RTW89_H2C_CHINFO_ARG_MAC_IDX_MASK BIT(0) +#define RTW89_H2C_CHINFO_ARG_APPEND_MASK BIT(1) + struct rtw89_h2c_scanofld { __le32 w0; __le32 w1; @@ -3933,6 +4004,8 @@ int rtw89_fw_h2c_add_pkt_offload(struct rtw89_dev *rtwdev, u8 *id, struct sk_buff *skb_ofld); int rtw89_fw_h2c_scan_list_offload(struct rtw89_dev *rtwdev, int ch_num, struct list_head *chan_list); +int rtw89_fw_h2c_scan_list_offload_be(struct rtw89_dev *rtwdev, int ch_num, + struct list_head *chan_list); int rtw89_fw_h2c_scan_offload(struct rtw89_dev *rtwdev, struct rtw89_scan_option *opt, struct rtw89_vif *vif); @@ -3975,6 +4048,10 @@ void rtw89_hw_scan_complete(struct rtw89_dev *rtwdev, struct ieee80211_vif *vif, int rtw89_hw_scan_offload(struct rtw89_dev *rtwdev, struct ieee80211_vif *vif, bool enable); void rtw89_hw_scan_abort(struct rtw89_dev *rtwdev, struct ieee80211_vif *vif); +int rtw89_hw_scan_add_chan_list(struct rtw89_dev *rtwdev, + struct rtw89_vif *rtwvif, bool connected); +int rtw89_hw_scan_add_chan_list_be(struct rtw89_dev *rtwdev, + struct rtw89_vif *rtwvif, bool connected); int rtw89_fw_h2c_trigger_cpu_exception(struct rtw89_dev *rtwdev); int rtw89_fw_h2c_pkt_drop(struct rtw89_dev *rtwdev, const struct rtw89_pkt_drop_params *params); diff --git a/drivers/net/wireless/realtek/rtw89/mac.c b/drivers/net/wireless/realtek/rtw89/mac.c index 247c566b851a..0bb38f401760 100644 --- a/drivers/net/wireless/realtek/rtw89/mac.c +++ b/drivers/net/wireless/realtek/rtw89/mac.c @@ -6225,5 +6225,7 @@ const struct rtw89_mac_gen_def rtw89_mac_gen_ax = { .dump_err_status = rtw89_mac_dump_err_status_ax, .is_txq_empty = mac_is_txq_empty_ax, + + .add_chan_list = rtw89_hw_scan_add_chan_list, }; EXPORT_SYMBOL(rtw89_mac_gen_ax); diff --git a/drivers/net/wireless/realtek/rtw89/mac.h b/drivers/net/wireless/realtek/rtw89/mac.h index 66bac01eb067..7d7fbd18491e 100644 --- a/drivers/net/wireless/realtek/rtw89/mac.h +++ b/drivers/net/wireless/realtek/rtw89/mac.h @@ -953,6 +953,9 @@ struct rtw89_mac_gen_def { enum mac_ax_err_info err); bool (*is_txq_empty)(struct rtw89_dev *rtwdev); + + int (*add_chan_list)(struct rtw89_dev *rtwdev, + struct rtw89_vif *rtwvif, bool connected); }; extern const struct rtw89_mac_gen_def rtw89_mac_gen_ax; diff --git a/drivers/net/wireless/realtek/rtw89/mac_be.c b/drivers/net/wireless/realtek/rtw89/mac_be.c index f03d05a2f857..2213451740e0 100644 --- a/drivers/net/wireless/realtek/rtw89/mac_be.c +++ b/drivers/net/wireless/realtek/rtw89/mac_be.c @@ -2364,5 +2364,7 @@ const struct rtw89_mac_gen_def rtw89_mac_gen_be = { .dump_err_status = rtw89_mac_dump_err_status_be, .is_txq_empty = mac_is_txq_empty_be, + + .add_chan_list = rtw89_hw_scan_add_chan_list_be, }; EXPORT_SYMBOL(rtw89_mac_gen_be); -- cgit v1.2.3 From 4ba24331c973eb1df0d3b67b0e3f8b7cde7765a7 Mon Sep 17 00:00:00 2001 From: Po-Hao Huang Date: Fri, 26 Jan 2024 14:33:53 +0800 Subject: wifi: rtw89: 8922a: add ieee80211_ops::hw_scan This adds support for hardware scan after FW version 0.34.35. Currently we only support scanning on single hardware band and support of dual band scan will be added in the future. Adjust the current flow to make driver compatible with different generation ICs. Signed-off-by: Po-Hao Huang Signed-off-by: Ping-Ke Shih Signed-off-by: Kalle Valo Link: https://msgid.link/20240126063356.17857-5-pkshih@realtek.com --- drivers/net/wireless/realtek/rtw89/core.h | 39 ++++++ drivers/net/wireless/realtek/rtw89/fw.c | 178 +++++++++++++++++++++++++++- drivers/net/wireless/realtek/rtw89/fw.h | 86 +++++++++++++- drivers/net/wireless/realtek/rtw89/mac.c | 15 ++- drivers/net/wireless/realtek/rtw89/mac.h | 3 + drivers/net/wireless/realtek/rtw89/mac_be.c | 1 + 6 files changed, 314 insertions(+), 8 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/realtek/rtw89/core.h b/drivers/net/wireless/realtek/rtw89/core.h index c86b46e7964f..30cc77ac78c5 100644 --- a/drivers/net/wireless/realtek/rtw89/core.h +++ b/drivers/net/wireless/realtek/rtw89/core.h @@ -3258,6 +3258,45 @@ enum rtw89_mlo_dbcc_mode { DBCC_LEGACY = 0xffffffff, }; +enum rtw89_scan_be_operation { + RTW89_SCAN_OP_STOP, + RTW89_SCAN_OP_START, + RTW89_SCAN_OP_SETPARM, + RTW89_SCAN_OP_GETRPT, + RTW89_SCAN_OP_NUM +}; + +enum rtw89_scan_be_mode { + RTW89_SCAN_MODE_SA, + RTW89_SCAN_MODE_MACC, + RTW89_SCAN_MODE_NUM +}; + +enum rtw89_scan_be_opmode { + RTW89_SCAN_OPMODE_NONE, + RTW89_SCAN_OPMODE_TBTT, + RTW89_SCAN_OPMODE_INTV, + RTW89_SCAN_OPMODE_CNT, + RTW89_SCAN_OPMODE_NUM, +}; + +struct rtw89_scan_option { + bool enable; + bool target_ch_mode; + u8 num_macc_role; + u8 num_opch; + u8 repeat; + u16 norm_pd; + u16 slow_pd; + u16 norm_cy; + u8 opch_end; + u64 prohib_chan; + enum rtw89_phy_idx band; + enum rtw89_scan_be_operation operation; + enum rtw89_scan_be_mode scan_mode; + enum rtw89_mlo_dbcc_mode mlo_mode; +}; + enum rtw89_qta_mode { RTW89_QTA_SCC, RTW89_QTA_DLFW, diff --git a/drivers/net/wireless/realtek/rtw89/fw.c b/drivers/net/wireless/realtek/rtw89/fw.c index ea308244b303..7a0671e4ef2c 100644 --- a/drivers/net/wireless/realtek/rtw89/fw.c +++ b/drivers/net/wireless/realtek/rtw89/fw.c @@ -459,6 +459,7 @@ static const struct __fw_feat_cfg fw_feat_tbl[] = { __CFG_FW_FEAT(RTL8852C, ge, 0, 27, 56, 10, BEACON_FILTER), __CFG_FW_FEAT(RTL8922A, ge, 0, 34, 30, 0, CRASH_TRIGGER), __CFG_FW_FEAT(RTL8922A, ge, 0, 34, 11, 0, MACID_PAUSE_SLEEP), + __CFG_FW_FEAT(RTL8922A, ge, 0, 34, 35, 0, SCAN_OFFLOAD), }; static void rtw89_fw_iterate_feature_cfg(struct rtw89_fw_info *fw, @@ -4236,6 +4237,169 @@ int rtw89_fw_h2c_scan_offload(struct rtw89_dev *rtwdev, return 0; } +static void rtw89_scan_get_6g_disabled_chan(struct rtw89_dev *rtwdev, + struct rtw89_scan_option *option) +{ + struct ieee80211_supported_band *sband; + struct ieee80211_channel *chan; + u8 i, idx; + + sband = rtwdev->hw->wiphy->bands[NL80211_BAND_6GHZ]; + + for (i = 0; i < sband->n_channels; i++) { + chan = &sband->channels[i]; + if (chan->flags & IEEE80211_CHAN_DISABLED) { + idx = (chan->hw_value - 1) / 4; + option->prohib_chan |= BIT(idx); + } + } +} + +int rtw89_fw_h2c_scan_offload_be(struct rtw89_dev *rtwdev, + struct rtw89_scan_option *option, + struct rtw89_vif *rtwvif) +{ + struct rtw89_hw_scan_info *scan_info = &rtwdev->scan_info; + struct rtw89_wait_info *wait = &rtwdev->mac.fw_ofld_wait; + struct rtw89_h2c_scanofld_be_macc_role *macc_role; + struct rtw89_chan *op = &scan_info->op_chan; + struct rtw89_h2c_scanofld_be_opch *opch; + struct rtw89_h2c_scanofld_be *h2c; + struct sk_buff *skb; + u8 macc_role_size = sizeof(*macc_role) * option->num_macc_role; + u8 opch_size = sizeof(*opch) * option->num_opch; + u8 probe_id[NUM_NL80211_BANDS]; + unsigned int cond; + void *ptr; + int ret; + u32 len; + u8 i; + + rtw89_scan_get_6g_disabled_chan(rtwdev, option); + + len = sizeof(*h2c) + macc_role_size + opch_size; + skb = rtw89_fw_h2c_alloc_skb_with_hdr(rtwdev, len); + if (!skb) { + rtw89_err(rtwdev, "failed to alloc skb for h2c scan offload\n"); + return -ENOMEM; + } + + skb_put(skb, len); + h2c = (struct rtw89_h2c_scanofld_be *)skb->data; + ptr = skb->data; + + h2c->w0 = le32_encode_bits(option->operation, RTW89_H2C_SCANOFLD_BE_W0_OP) | + le32_encode_bits(option->scan_mode, + RTW89_H2C_SCANOFLD_BE_W0_SCAN_MODE) | + le32_encode_bits(option->repeat, RTW89_H2C_SCANOFLD_BE_W0_REPEAT) | + le32_encode_bits(true, RTW89_H2C_SCANOFLD_BE_W0_NOTIFY_END) | + le32_encode_bits(true, RTW89_H2C_SCANOFLD_BE_W0_LEARN_CH) | + le32_encode_bits(rtwvif->mac_id, RTW89_H2C_SCANOFLD_BE_W0_MACID) | + le32_encode_bits(rtwvif->port, RTW89_H2C_SCANOFLD_BE_W0_PORT) | + le32_encode_bits(option->band, RTW89_H2C_SCANOFLD_BE_W0_BAND); + + h2c->w1 = le32_encode_bits(option->num_macc_role, RTW89_H2C_SCANOFLD_BE_W1_NUM_MACC_ROLE) | + le32_encode_bits(option->num_opch, RTW89_H2C_SCANOFLD_BE_W1_NUM_OP) | + le32_encode_bits(option->norm_pd, RTW89_H2C_SCANOFLD_BE_W1_NORM_PD); + + h2c->w2 = le32_encode_bits(option->slow_pd, RTW89_H2C_SCANOFLD_BE_W2_SLOW_PD) | + le32_encode_bits(option->norm_cy, RTW89_H2C_SCANOFLD_BE_W2_NORM_CY) | + le32_encode_bits(option->opch_end, RTW89_H2C_SCANOFLD_BE_W2_OPCH_END); + + h2c->w3 = le32_encode_bits(0, RTW89_H2C_SCANOFLD_BE_W3_NUM_SSID) | + le32_encode_bits(0, RTW89_H2C_SCANOFLD_BE_W3_NUM_SHORT_SSID) | + le32_encode_bits(0, RTW89_H2C_SCANOFLD_BE_W3_NUM_BSSID) | + le32_encode_bits(probe_id[NL80211_BAND_2GHZ], RTW89_H2C_SCANOFLD_BE_W3_PROBEID); + + h2c->w4 = le32_encode_bits(probe_id[NL80211_BAND_5GHZ], + RTW89_H2C_SCANOFLD_BE_W4_PROBE_5G) | + le32_encode_bits(probe_id[NL80211_BAND_6GHZ], + RTW89_H2C_SCANOFLD_BE_W4_PROBE_6G) | + le32_encode_bits(0, RTW89_H2C_SCANOFLD_BE_W4_DELAY_START); + + h2c->w5 = le32_encode_bits(option->mlo_mode, RTW89_H2C_SCANOFLD_BE_W5_MLO_MODE); + + h2c->w6 = le32_encode_bits(option->prohib_chan, + RTW89_H2C_SCANOFLD_BE_W6_CHAN_PROHIB_LOW); + h2c->w7 = le32_encode_bits(option->prohib_chan >> 32, + RTW89_H2C_SCANOFLD_BE_W7_CHAN_PROHIB_HIGH); + ptr += sizeof(*h2c); + + for (i = 0; i < option->num_macc_role; i++) { + macc_role = (struct rtw89_h2c_scanofld_be_macc_role *)&h2c->role[i]; + macc_role->w0 = + le32_encode_bits(0, RTW89_H2C_SCANOFLD_BE_MACC_ROLE_W0_BAND) | + le32_encode_bits(0, RTW89_H2C_SCANOFLD_BE_MACC_ROLE_W0_PORT) | + le32_encode_bits(0, RTW89_H2C_SCANOFLD_BE_MACC_ROLE_W0_MACID) | + le32_encode_bits(0, RTW89_H2C_SCANOFLD_BE_MACC_ROLE_W0_OPCH_END); + ptr += sizeof(*macc_role); + } + + for (i = 0; i < option->num_opch; i++) { + opch = ptr; + opch->w0 = le32_encode_bits(rtwvif->mac_id, + RTW89_H2C_SCANOFLD_BE_OPCH_W0_MACID) | + le32_encode_bits(option->band, + RTW89_H2C_SCANOFLD_BE_OPCH_W0_BAND) | + le32_encode_bits(rtwvif->port, + RTW89_H2C_SCANOFLD_BE_OPCH_W0_PORT) | + le32_encode_bits(RTW89_SCAN_OPMODE_INTV, + RTW89_H2C_SCANOFLD_BE_OPCH_W0_POLICY) | + le32_encode_bits(true, + RTW89_H2C_SCANOFLD_BE_OPCH_W0_TXNULL) | + le32_encode_bits(RTW89_OFF_CHAN_TIME / 10, + RTW89_H2C_SCANOFLD_BE_OPCH_W0_POLICY_VAL); + + opch->w1 = le32_encode_bits(RTW89_CHANNEL_TIME, + RTW89_H2C_SCANOFLD_BE_OPCH_W1_DURATION) | + le32_encode_bits(op->band_type, + RTW89_H2C_SCANOFLD_BE_OPCH_W1_CH_BAND) | + le32_encode_bits(op->band_width, + RTW89_H2C_SCANOFLD_BE_OPCH_W1_BW) | + le32_encode_bits(0x3, + RTW89_H2C_SCANOFLD_BE_OPCH_W1_NOTIFY) | + le32_encode_bits(op->primary_channel, + RTW89_H2C_SCANOFLD_BE_OPCH_W1_PRI_CH) | + le32_encode_bits(op->channel, + RTW89_H2C_SCANOFLD_BE_OPCH_W1_CENTRAL_CH); + + opch->w2 = le32_encode_bits(0, + RTW89_H2C_SCANOFLD_BE_OPCH_W2_PKTS_CTRL) | + le32_encode_bits(0, + RTW89_H2C_SCANOFLD_BE_OPCH_W2_SW_DEF) | + le32_encode_bits(2, + RTW89_H2C_SCANOFLD_BE_OPCH_W2_SS); + + opch->w3 = le32_encode_bits(RTW89_SCANOFLD_PKT_NONE, + RTW89_H2C_SCANOFLD_BE_OPCH_W3_PKT0) | + le32_encode_bits(RTW89_SCANOFLD_PKT_NONE, + RTW89_H2C_SCANOFLD_BE_OPCH_W3_PKT1) | + le32_encode_bits(RTW89_SCANOFLD_PKT_NONE, + RTW89_H2C_SCANOFLD_BE_OPCH_W3_PKT2) | + le32_encode_bits(RTW89_SCANOFLD_PKT_NONE, + RTW89_H2C_SCANOFLD_BE_OPCH_W3_PKT3); + ptr += sizeof(*opch); + } + + rtw89_h2c_pkt_set_hdr(rtwdev, skb, FWCMD_TYPE_H2C, + H2C_CAT_MAC, H2C_CL_MAC_FW_OFLD, + H2C_FUNC_SCANOFLD_BE, 1, 1, + len); + + if (option->enable) + cond = RTW89_SCANOFLD_BE_WAIT_COND_START; + else + cond = RTW89_SCANOFLD_BE_WAIT_COND_STOP; + + ret = rtw89_h2c_tx_and_wait(rtwdev, skb, wait, cond); + if (ret) { + rtw89_debug(rtwdev, RTW89_DBG_FW, "failed to scan be ofld\n"); + return ret; + } + + return 0; +} + int rtw89_fw_h2c_rf_reg(struct rtw89_dev *rtwdev, struct rtw89_fw_h2c_rf_reg_info *info, u16 len, u8 page) @@ -5173,6 +5337,7 @@ static bool rtw89_is_any_vif_connected_or_connecting(struct rtw89_dev *rtwdev) int rtw89_hw_scan_offload(struct rtw89_dev *rtwdev, struct ieee80211_vif *vif, bool enable) { + const struct rtw89_mac_gen_def *mac = rtwdev->chip->mac_def; struct rtw89_scan_option opt = {0}; struct rtw89_vif *rtwvif; bool connected; @@ -5190,7 +5355,18 @@ int rtw89_hw_scan_offload(struct rtw89_dev *rtwdev, struct ieee80211_vif *vif, if (ret) goto out; } - ret = rtw89_fw_h2c_scan_offload(rtwdev, &opt, rtwvif); + + if (rtwdev->chip->chip_gen == RTW89_CHIP_BE) { + opt.operation = enable ? RTW89_SCAN_OP_START : RTW89_SCAN_OP_STOP; + opt.scan_mode = RTW89_SCAN_MODE_SA; + opt.band = RTW89_PHY_0; + opt.num_macc_role = 0; + opt.mlo_mode = rtwdev->mlo_dbcc_mode; + opt.num_opch = connected ? 1 : 0; + opt.opch_end = connected ? 0 : RTW89_CHAN_INVALID; + } + + ret = mac->scan_offload(rtwdev, &opt, rtwvif); out: return ret; } diff --git a/drivers/net/wireless/realtek/rtw89/fw.h b/drivers/net/wireless/realtek/rtw89/fw.h index 132809ea05bf..08b8f6d75065 100644 --- a/drivers/net/wireless/realtek/rtw89/fw.h +++ b/drivers/net/wireless/realtek/rtw89/fw.h @@ -266,6 +266,7 @@ struct rtw89_fw_macid_pause_sleep_grp { #define RTW89_SCANOFLD_MAX_IE_LEN 512 #define RTW89_SCANOFLD_PKT_NONE 0xFF #define RTW89_SCANOFLD_DEBUG_MASK 0x1F +#define RTW89_CHAN_INVALID 0xFF #define RTW89_MAC_CHINFO_SIZE 28 #define RTW89_SCAN_LIST_GUARD 4 #define RTW89_SCAN_LIST_LIMIT \ @@ -325,11 +326,6 @@ struct rtw89_mac_chinfo_be { bool is_psc; }; -struct rtw89_scan_option { - bool enable; - bool target_ch_mode; -}; - struct rtw89_pktofld_info { struct list_head list; u8 id; @@ -2814,6 +2810,79 @@ struct rtw89_h2c_scanofld { #define RTW89_H2C_SCANOFLD_W2_NORM_PD GENMASK(15, 0) #define RTW89_H2C_SCANOFLD_W2_SLOW_PD GENMASK(23, 16) +struct rtw89_h2c_scanofld_be_macc_role { + __le32 w0; +} __packed; + +#define RTW89_H2C_SCANOFLD_BE_MACC_ROLE_W0_BAND GENMASK(1, 0) +#define RTW89_H2C_SCANOFLD_BE_MACC_ROLE_W0_PORT GENMASK(4, 2) +#define RTW89_H2C_SCANOFLD_BE_MACC_ROLE_W0_MACID GENMASK(23, 8) +#define RTW89_H2C_SCANOFLD_BE_MACC_ROLE_W0_OPCH_END GENMASK(31, 24) + +struct rtw89_h2c_scanofld_be_opch { + __le32 w0; + __le32 w1; + __le32 w2; + __le32 w3; +} __packed; + +#define RTW89_H2C_SCANOFLD_BE_OPCH_W0_MACID GENMASK(15, 0) +#define RTW89_H2C_SCANOFLD_BE_OPCH_W0_BAND GENMASK(17, 16) +#define RTW89_H2C_SCANOFLD_BE_OPCH_W0_PORT GENMASK(20, 18) +#define RTW89_H2C_SCANOFLD_BE_OPCH_W0_POLICY GENMASK(22, 21) +#define RTW89_H2C_SCANOFLD_BE_OPCH_W0_TXNULL BIT(23) +#define RTW89_H2C_SCANOFLD_BE_OPCH_W0_POLICY_VAL GENMASK(31, 24) +#define RTW89_H2C_SCANOFLD_BE_OPCH_W1_DURATION GENMASK(7, 0) +#define RTW89_H2C_SCANOFLD_BE_OPCH_W1_CH_BAND GENMASK(9, 8) +#define RTW89_H2C_SCANOFLD_BE_OPCH_W1_BW GENMASK(12, 10) +#define RTW89_H2C_SCANOFLD_BE_OPCH_W1_NOTIFY GENMASK(14, 13) +#define RTW89_H2C_SCANOFLD_BE_OPCH_W1_PRI_CH GENMASK(23, 16) +#define RTW89_H2C_SCANOFLD_BE_OPCH_W1_CENTRAL_CH GENMASK(31, 24) +#define RTW89_H2C_SCANOFLD_BE_OPCH_W2_PKTS_CTRL GENMASK(7, 0) +#define RTW89_H2C_SCANOFLD_BE_OPCH_W2_SW_DEF GENMASK(15, 8) +#define RTW89_H2C_SCANOFLD_BE_OPCH_W2_SS GENMASK(18, 16) +#define RTW89_H2C_SCANOFLD_BE_OPCH_W3_PKT0 GENMASK(7, 0) +#define RTW89_H2C_SCANOFLD_BE_OPCH_W3_PKT1 GENMASK(15, 8) +#define RTW89_H2C_SCANOFLD_BE_OPCH_W3_PKT2 GENMASK(23, 16) +#define RTW89_H2C_SCANOFLD_BE_OPCH_W3_PKT3 GENMASK(31, 24) + +struct rtw89_h2c_scanofld_be { + __le32 w0; + __le32 w1; + __le32 w2; + __le32 w3; + __le32 w4; + __le32 w5; + __le32 w6; + __le32 w7; + struct rtw89_h2c_scanofld_be_macc_role role[]; +} __packed; + +#define RTW89_H2C_SCANOFLD_BE_W0_OP GENMASK(1, 0) +#define RTW89_H2C_SCANOFLD_BE_W0_SCAN_MODE GENMASK(3, 2) +#define RTW89_H2C_SCANOFLD_BE_W0_REPEAT GENMASK(5, 4) +#define RTW89_H2C_SCANOFLD_BE_W0_NOTIFY_END BIT(6) +#define RTW89_H2C_SCANOFLD_BE_W0_LEARN_CH BIT(7) +#define RTW89_H2C_SCANOFLD_BE_W0_MACID GENMASK(23, 8) +#define RTW89_H2C_SCANOFLD_BE_W0_PORT GENMASK(26, 24) +#define RTW89_H2C_SCANOFLD_BE_W0_BAND GENMASK(28, 27) +#define RTW89_H2C_SCANOFLD_BE_W1_NUM_MACC_ROLE GENMASK(7, 0) +#define RTW89_H2C_SCANOFLD_BE_W1_NUM_OP GENMASK(15, 8) +#define RTW89_H2C_SCANOFLD_BE_W1_NORM_PD GENMASK(31, 16) +#define RTW89_H2C_SCANOFLD_BE_W2_SLOW_PD GENMASK(15, 0) +#define RTW89_H2C_SCANOFLD_BE_W2_NORM_CY GENMASK(23, 16) +#define RTW89_H2C_SCANOFLD_BE_W2_OPCH_END GENMASK(31, 24) +#define RTW89_H2C_SCANOFLD_BE_W3_NUM_SSID GENMASK(7, 0) +#define RTW89_H2C_SCANOFLD_BE_W3_NUM_SHORT_SSID GENMASK(15, 8) +#define RTW89_H2C_SCANOFLD_BE_W3_NUM_BSSID GENMASK(23, 16) +#define RTW89_H2C_SCANOFLD_BE_W3_PROBEID GENMASK(31, 24) +#define RTW89_H2C_SCANOFLD_BE_W4_PROBE_5G GENMASK(7, 0) +#define RTW89_H2C_SCANOFLD_BE_W4_PROBE_6G GENMASK(15, 8) +#define RTW89_H2C_SCANOFLD_BE_W4_DELAY_START GENMASK(31, 16) +#define RTW89_H2C_SCANOFLD_BE_W5_MLO_MODE GENMASK(31, 0) +#define RTW89_H2C_SCANOFLD_BE_W6_CHAN_PROHIB_LOW GENMASK(31, 0) +#define RTW89_H2C_SCANOFLD_BE_W7_CHAN_PROHIB_HIGH GENMASK(31, 0) + static inline void RTW89_SET_FWCMD_P2P_MACID(void *cmd, u32 val) { le32p_replace_bits((__le32 *)cmd, val, GENMASK(7, 0)); @@ -3773,6 +3842,7 @@ enum rtw89_fw_ofld_h2c_func { H2C_FUNC_OFLD_RSSI = 0x1f, H2C_FUNC_OFLD_TP = 0x20, H2C_FUNC_MAC_MACID_PAUSE_SLEEP = 0x28, + H2C_FUNC_SCANOFLD_BE = 0x2c, NUM_OF_RTW89_FW_OFLD_H2C_FUNC, }; @@ -3788,6 +3858,9 @@ enum rtw89_fw_ofld_h2c_func { #define RTW89_SCANOFLD_WAIT_COND_START RTW89_FW_OFLD_WAIT_COND(0, H2C_FUNC_SCANOFLD) #define RTW89_SCANOFLD_WAIT_COND_STOP RTW89_FW_OFLD_WAIT_COND(1, H2C_FUNC_SCANOFLD) +#define RTW89_SCANOFLD_BE_WAIT_COND_START RTW89_FW_OFLD_WAIT_COND(0, H2C_FUNC_SCANOFLD_BE) +#define RTW89_SCANOFLD_BE_WAIT_COND_STOP RTW89_FW_OFLD_WAIT_COND(1, H2C_FUNC_SCANOFLD_BE) + /* CLASS 10 - Security CAM */ #define H2C_CL_MAC_SEC_CAM 0xa @@ -4009,6 +4082,9 @@ int rtw89_fw_h2c_scan_list_offload_be(struct rtw89_dev *rtwdev, int ch_num, int rtw89_fw_h2c_scan_offload(struct rtw89_dev *rtwdev, struct rtw89_scan_option *opt, struct rtw89_vif *vif); +int rtw89_fw_h2c_scan_offload_be(struct rtw89_dev *rtwdev, + struct rtw89_scan_option *opt, + struct rtw89_vif *vif); int rtw89_fw_h2c_rf_reg(struct rtw89_dev *rtwdev, struct rtw89_fw_h2c_rf_reg_info *info, u16 len, u8 page); diff --git a/drivers/net/wireless/realtek/rtw89/mac.c b/drivers/net/wireless/realtek/rtw89/mac.c index 0bb38f401760..96a98774c322 100644 --- a/drivers/net/wireless/realtek/rtw89/mac.c +++ b/drivers/net/wireless/realtek/rtw89/mac.c @@ -4867,6 +4867,9 @@ rtw89_mac_c2h_done_ack(struct rtw89_dev *rtwdev, struct sk_buff *skb_c2h, u32 le case H2C_FUNC_SCANOFLD: cond = RTW89_SCANOFLD_WAIT_COND_START; break; + case H2C_FUNC_SCANOFLD_BE: + cond = RTW89_SCANOFLD_BE_WAIT_COND_START; + break; } data.err = !!h2c_return; @@ -5116,14 +5119,21 @@ static void rtw89_mac_c2h_scanofld_rsp_atomic(struct rtw89_dev *rtwdev, (const struct rtw89_c2h_scanofld *)skb->data; struct rtw89_wait_info *fw_ofld_wait = &rtwdev->mac.fw_ofld_wait; struct rtw89_completion_data data = {}; + unsigned int cond; u8 status, reason; status = le32_get_bits(c2h->w2, RTW89_C2H_SCANOFLD_W2_STATUS); reason = le32_get_bits(c2h->w2, RTW89_C2H_SCANOFLD_W2_RSN); data.err = status != RTW89_SCAN_STATUS_SUCCESS; - if (reason == RTW89_SCAN_END_SCAN_NOTIFY) - rtw89_complete_cond(fw_ofld_wait, RTW89_SCANOFLD_WAIT_COND_STOP, &data); + if (reason == RTW89_SCAN_END_SCAN_NOTIFY) { + if (rtwdev->chip->chip_gen == RTW89_CHIP_BE) + cond = RTW89_SCANOFLD_BE_WAIT_COND_STOP; + else + cond = RTW89_SCANOFLD_WAIT_COND_STOP; + + rtw89_complete_cond(fw_ofld_wait, cond, &data); + } } bool rtw89_mac_c2h_chk_atomic(struct rtw89_dev *rtwdev, struct sk_buff *c2h, @@ -6227,5 +6237,6 @@ const struct rtw89_mac_gen_def rtw89_mac_gen_ax = { .is_txq_empty = mac_is_txq_empty_ax, .add_chan_list = rtw89_hw_scan_add_chan_list, + .scan_offload = rtw89_fw_h2c_scan_offload, }; EXPORT_SYMBOL(rtw89_mac_gen_ax); diff --git a/drivers/net/wireless/realtek/rtw89/mac.h b/drivers/net/wireless/realtek/rtw89/mac.h index 7d7fbd18491e..8968892175c1 100644 --- a/drivers/net/wireless/realtek/rtw89/mac.h +++ b/drivers/net/wireless/realtek/rtw89/mac.h @@ -956,6 +956,9 @@ struct rtw89_mac_gen_def { int (*add_chan_list)(struct rtw89_dev *rtwdev, struct rtw89_vif *rtwvif, bool connected); + int (*scan_offload)(struct rtw89_dev *rtwdev, + struct rtw89_scan_option *option, + struct rtw89_vif *rtwvif); }; extern const struct rtw89_mac_gen_def rtw89_mac_gen_ax; diff --git a/drivers/net/wireless/realtek/rtw89/mac_be.c b/drivers/net/wireless/realtek/rtw89/mac_be.c index 2213451740e0..7369514189b8 100644 --- a/drivers/net/wireless/realtek/rtw89/mac_be.c +++ b/drivers/net/wireless/realtek/rtw89/mac_be.c @@ -2366,5 +2366,6 @@ const struct rtw89_mac_gen_def rtw89_mac_gen_be = { .is_txq_empty = mac_is_txq_empty_be, .add_chan_list = rtw89_hw_scan_add_chan_list_be, + .scan_offload = rtw89_fw_h2c_scan_offload_be, }; EXPORT_SYMBOL(rtw89_mac_gen_be); -- cgit v1.2.3 From e58e3117019cfa732706211c151fd94d8fb08ce3 Mon Sep 17 00:00:00 2001 From: Chin-Yen Lee Date: Fri, 26 Jan 2024 14:33:54 +0800 Subject: wifi: rtw89: add new H2C for PS mode in 802.11be chip Because 802.11be chip support MLO mode, driver needs to send new H2C to pass more connected channel information to firmware, to ensure PS mode work fine. Signed-off-by: Chin-Yen Lee Signed-off-by: Ping-Ke Shih Signed-off-by: Kalle Valo Link: https://msgid.link/20240126063356.17857-6-pkshih@realtek.com --- drivers/net/wireless/realtek/rtw89/fw.c | 44 +++++++++++++++++++++++++++++++++ drivers/net/wireless/realtek/rtw89/fw.h | 16 ++++++++++++ drivers/net/wireless/realtek/rtw89/ps.c | 7 +++--- 3 files changed, 64 insertions(+), 3 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/realtek/rtw89/fw.c b/drivers/net/wireless/realtek/rtw89/fw.c index 7a0671e4ef2c..2f3f2b503507 100644 --- a/drivers/net/wireless/realtek/rtw89/fw.c +++ b/drivers/net/wireless/realtek/rtw89/fw.c @@ -2036,6 +2036,50 @@ fail: return ret; } +int rtw89_fw_h2c_lps_ch_info(struct rtw89_dev *rtwdev, struct rtw89_vif *rtwvif) +{ + const struct rtw89_chan *chan = rtw89_chan_get(rtwdev, + rtwvif->sub_entity_idx); + const struct rtw89_chip_info *chip = rtwdev->chip; + struct rtw89_h2c_lps_ch_info *h2c; + u32 len = sizeof(*h2c); + struct sk_buff *skb; + int ret; + + if (chip->chip_gen != RTW89_CHIP_BE) + return 0; + + skb = rtw89_fw_h2c_alloc_skb_with_hdr(rtwdev, len); + if (!skb) { + rtw89_err(rtwdev, "failed to alloc skb for h2c lps_ch_info\n"); + return -ENOMEM; + } + skb_put(skb, len); + h2c = (struct rtw89_h2c_lps_ch_info *)skb->data; + + h2c->info[0].central_ch = chan->channel; + h2c->info[0].pri_ch = chan->primary_channel; + h2c->info[0].band = chan->band_type; + h2c->info[0].bw = chan->band_width; + h2c->mlo_dbcc_mode_lps = cpu_to_le32(MLO_2_PLUS_0_1RF); + + rtw89_h2c_pkt_set_hdr(rtwdev, skb, FWCMD_TYPE_H2C, + H2C_CAT_OUTSRC, H2C_CL_OUTSRC_DM, + H2C_FUNC_FW_LPS_CH_INFO, 0, 0, len); + + ret = rtw89_h2c_tx(rtwdev, skb, false); + if (ret) { + rtw89_err(rtwdev, "failed to send h2c\n"); + goto fail; + } + + return 0; +fail: + dev_kfree_skb_any(skb); + + return ret; +} + #define H2C_P2P_ACT_LEN 20 int rtw89_fw_h2c_p2p_act(struct rtw89_dev *rtwdev, struct ieee80211_vif *vif, struct ieee80211_p2p_noa_desc *desc, diff --git a/drivers/net/wireless/realtek/rtw89/fw.h b/drivers/net/wireless/realtek/rtw89/fw.h index 08b8f6d75065..c5c801e9ce3c 100644 --- a/drivers/net/wireless/realtek/rtw89/fw.h +++ b/drivers/net/wireless/realtek/rtw89/fw.h @@ -1974,6 +1974,17 @@ static inline void SET_LPS_PARM_LASTRPWM(void *h2c, u32 val) le32p_replace_bits((__le32 *)(h2c) + 1, val, GENMASK(15, 8)); } +struct rtw89_h2c_lps_ch_info { + struct { + u8 pri_ch; + u8 central_ch; + u8 bw; + u8 band; + } __packed info[2]; + + __le32 mlo_dbcc_mode_lps; +} __packed; + static inline void RTW89_SET_FWCMD_CPU_EXCEPTION_TYPE(void *cmd, u32 val) { le32p_replace_bits((__le32 *)cmd, val, GENMASK(31, 0)); @@ -3896,6 +3907,9 @@ enum rtw89_mcc_h2c_func { #define H2C_CL_OUTSRC_RA 0x1 #define H2C_FUNC_OUTSRC_RA_MACIDCFG 0x0 +#define H2C_CL_OUTSRC_DM 0x2 +#define H2C_FUNC_FW_LPS_CH_INFO 0xb + #define H2C_CL_OUTSRC_RF_REG_A 0x8 #define H2C_CL_OUTSRC_RF_REG_B 0x9 #define H2C_CL_OUTSRC_RF_FW_NOTIFY 0xa @@ -4110,6 +4124,8 @@ int rtw89_fw_h2c_init_ba_cam_users(struct rtw89_dev *rtwdev, u8 users, int rtw89_fw_h2c_lps_parm(struct rtw89_dev *rtwdev, struct rtw89_lps_parm *lps_param); +int rtw89_fw_h2c_lps_ch_info(struct rtw89_dev *rtwdev, + struct rtw89_vif *rtwvif); struct sk_buff *rtw89_fw_h2c_alloc_skb_with_hdr(struct rtw89_dev *rtwdev, u32 len); struct sk_buff *rtw89_fw_h2c_alloc_skb_no_hdr(struct rtw89_dev *rtwdev, u32 len); int rtw89_fw_msg_reg(struct rtw89_dev *rtwdev, diff --git a/drivers/net/wireless/realtek/rtw89/ps.c b/drivers/net/wireless/realtek/rtw89/ps.c index 917c01e5e9ed..be1dcd9eb955 100644 --- a/drivers/net/wireless/realtek/rtw89/ps.c +++ b/drivers/net/wireless/realtek/rtw89/ps.c @@ -83,16 +83,17 @@ void __rtw89_leave_ps_mode(struct rtw89_dev *rtwdev) rtw89_ps_power_mode_change(rtwdev, false); } -static void __rtw89_enter_lps(struct rtw89_dev *rtwdev, u8 mac_id) +static void __rtw89_enter_lps(struct rtw89_dev *rtwdev, struct rtw89_vif *rtwvif) { struct rtw89_lps_parm lps_param = { - .macid = mac_id, + .macid = rtwvif->mac_id, .psmode = RTW89_MAC_AX_PS_MODE_LEGACY, .lastrpwm = RTW89_LAST_RPWM_PS, }; rtw89_btc_ntfy_radio_state(rtwdev, BTC_RFCTRL_FW_CTRL); rtw89_fw_h2c_lps_parm(rtwdev, &lps_param); + rtw89_fw_h2c_lps_ch_info(rtwdev, rtwvif); } static void __rtw89_leave_lps(struct rtw89_dev *rtwdev, u8 mac_id) @@ -123,7 +124,7 @@ void rtw89_enter_lps(struct rtw89_dev *rtwdev, struct rtw89_vif *rtwvif, if (test_and_set_bit(RTW89_FLAG_LEISURE_PS, rtwdev->flags)) return; - __rtw89_enter_lps(rtwdev, rtwvif->mac_id); + __rtw89_enter_lps(rtwdev, rtwvif); if (ps_mode) __rtw89_enter_ps_mode(rtwdev, rtwvif); } -- cgit v1.2.3 From f651300cd8849a3703892fe5efd397c7a44a7f60 Mon Sep 17 00:00:00 2001 From: Chin-Yen Lee Date: Fri, 26 Jan 2024 14:33:55 +0800 Subject: wifi: rtw89: update ps_state register for chips with different generation The ps_state register is used for driver to check if the WiFi chip leave power save mode successfully. The register is changed for new generation, so update it. Signed-off-by: Chin-Yen Lee Signed-off-by: Ping-Ke Shih Signed-off-by: Kalle Valo Link: https://msgid.link/20240126063356.17857-7-pkshih@realtek.com --- drivers/net/wireless/realtek/rtw89/mac.c | 1 + drivers/net/wireless/realtek/rtw89/mac.h | 1 + drivers/net/wireless/realtek/rtw89/mac_be.c | 1 + drivers/net/wireless/realtek/rtw89/ps.c | 3 ++- drivers/net/wireless/realtek/rtw89/reg.h | 3 +++ 5 files changed, 8 insertions(+), 1 deletion(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/realtek/rtw89/mac.c b/drivers/net/wireless/realtek/rtw89/mac.c index 96a98774c322..dbf2d6fe4ea7 100644 --- a/drivers/net/wireless/realtek/rtw89/mac.c +++ b/drivers/net/wireless/realtek/rtw89/mac.c @@ -6184,6 +6184,7 @@ const struct rtw89_mac_gen_def rtw89_mac_gen_ax = { .rx_fltr = R_AX_RX_FLTR_OPT, .port_base = &rtw89_port_base_ax, .agg_len_ht = R_AX_AGG_LEN_HT_0, + .ps_status = R_AX_PPWRBIT_SETTING, .muedca_ctrl = { .addr = R_AX_MUEDCA_EN, diff --git a/drivers/net/wireless/realtek/rtw89/mac.h b/drivers/net/wireless/realtek/rtw89/mac.h index 8968892175c1..b3fe4cab6d3a 100644 --- a/drivers/net/wireless/realtek/rtw89/mac.h +++ b/drivers/net/wireless/realtek/rtw89/mac.h @@ -894,6 +894,7 @@ struct rtw89_mac_gen_def { u32 rx_fltr; const struct rtw89_port_reg *port_base; u32 agg_len_ht; + u32 ps_status; struct rtw89_reg_def muedca_ctrl; struct rtw89_reg_def bfee_ctrl; diff --git a/drivers/net/wireless/realtek/rtw89/mac_be.c b/drivers/net/wireless/realtek/rtw89/mac_be.c index 7369514189b8..13e6fa7a3ae8 100644 --- a/drivers/net/wireless/realtek/rtw89/mac_be.c +++ b/drivers/net/wireless/realtek/rtw89/mac_be.c @@ -2313,6 +2313,7 @@ const struct rtw89_mac_gen_def rtw89_mac_gen_be = { .rx_fltr = R_BE_RX_FLTR_OPT, .port_base = &rtw89_port_base_be, .agg_len_ht = R_BE_AGG_LEN_HT_0, + .ps_status = R_BE_WMTX_POWER_BE_BIT_CTL, .muedca_ctrl = { .addr = R_BE_MUEDCA_EN, diff --git a/drivers/net/wireless/realtek/rtw89/ps.c b/drivers/net/wireless/realtek/rtw89/ps.c index be1dcd9eb955..31290d8cb7f7 100644 --- a/drivers/net/wireless/realtek/rtw89/ps.c +++ b/drivers/net/wireless/realtek/rtw89/ps.c @@ -14,6 +14,7 @@ static int rtw89_fw_leave_lps_check(struct rtw89_dev *rtwdev, u8 macid) { + const struct rtw89_mac_gen_def *mac = rtwdev->chip->mac_def; u32 pwr_en_bit = 0xE; u32 chk_msk = pwr_en_bit << (4 * macid); u32 polling; @@ -21,7 +22,7 @@ static int rtw89_fw_leave_lps_check(struct rtw89_dev *rtwdev, u8 macid) ret = read_poll_timeout_atomic(rtw89_read32_mask, polling, !polling, 1000, 50000, false, rtwdev, - R_AX_PPWRBIT_SETTING, chk_msk); + mac->ps_status, chk_msk); if (ret) { rtw89_info(rtwdev, "rtw89: failed to leave lps state\n"); return -EBUSY; diff --git a/drivers/net/wireless/realtek/rtw89/reg.h b/drivers/net/wireless/realtek/rtw89/reg.h index addf11fc76d4..bd7bdd216e5f 100644 --- a/drivers/net/wireless/realtek/rtw89/reg.h +++ b/drivers/net/wireless/realtek/rtw89/reg.h @@ -6794,6 +6794,9 @@ #define B_BE_UPD_HGQMD BIT(1) #define B_BE_UPD_TIMIE BIT(0) +#define R_BE_WMTX_POWER_BE_BIT_CTL 0x10E0C +#define R_BE_WMTX_POWER_BE_BIT_CTL_C1 0x14E0C + #define R_BE_WMTX_TCR_BE_4 0x10E2C #define R_BE_WMTX_TCR_BE_4_C1 0x14E2C #define B_BE_UL_EHT_MUMIMO_LTF_MODE BIT(30) -- cgit v1.2.3 From f1abee76dba829ada6e30ac640443e81bde2f878 Mon Sep 17 00:00:00 2001 From: Po-Hao Huang Date: Fri, 26 Jan 2024 14:33:56 +0800 Subject: wifi: rtw89: 8922a: add more fields to beacon H2C command to support multi-links To support multi-links beacon, it needs more fields. But currently we still only support legacy AP mode. Only update struct to fit expected size of firmware. Signed-off-by: Po-Hao Huang Signed-off-by: Ping-Ke Shih Signed-off-by: Kalle Valo Link: https://msgid.link/20240126063356.17857-8-pkshih@realtek.com --- drivers/net/wireless/realtek/rtw89/fw.h | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) (limited to 'drivers/net') diff --git a/drivers/net/wireless/realtek/rtw89/fw.h b/drivers/net/wireless/realtek/rtw89/fw.h index c5c801e9ce3c..ae69e455cd64 100644 --- a/drivers/net/wireless/realtek/rtw89/fw.h +++ b/drivers/net/wireless/realtek/rtw89/fw.h @@ -1730,6 +1730,24 @@ struct rtw89_h2c_bcn_upd_be { __le32 w9; __le32 w10; __le32 w11; + __le32 w12; + __le32 w13; + __le32 w14; + __le32 w15; + __le32 w16; + __le32 w17; + __le32 w18; + __le32 w19; + __le32 w20; + __le32 w21; + __le32 w22; + __le32 w23; + __le32 w24; + __le32 w25; + __le32 w26; + __le32 w27; + __le32 w28; + __le32 w29; } __packed; #define RTW89_H2C_BCN_UPD_BE_W0_PORT GENMASK(7, 0) -- cgit v1.2.3 From 17903a283593c1dbf9da041f836004163ca30f7b Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Wed, 31 Jan 2024 10:10:07 +0300 Subject: wifi: rtl8xxxu: fix error messages The first parameter of WARN_ONCE() is a condition so this code will end up printing the function name instead of the proper message. Fixes: 3ff7a05996f9 ("wifi: rtl8xxxu: support setting bssid register for multiple interfaces") Signed-off-by: Dan Carpenter Reviewed-by: Ping-Ke Shih Signed-off-by: Kalle Valo Link: https://msgid.link/7b144531-a8da-4725-8911-9b614a525a35@moroto.mountain --- drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_core.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_core.c b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_core.c index 3b954c2fe448..bd6fd3120562 100644 --- a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_core.c +++ b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_core.c @@ -3593,7 +3593,7 @@ static int rtl8xxxu_set_mac(struct rtl8xxxu_priv *priv, int port_num) reg = REG_MACID1; break; default: - WARN_ONCE("%s: invalid port_num\n", __func__); + WARN_ONCE(1, "%s: invalid port_num\n", __func__); return -EINVAL; } @@ -3618,7 +3618,7 @@ static int rtl8xxxu_set_bssid(struct rtl8xxxu_priv *priv, const u8 *bssid, int p reg = REG_BSSID1; break; default: - WARN_ONCE("%s: invalid port_num\n", __func__); + WARN_ONCE(1, "%s: invalid port_num\n", __func__); return -EINVAL; } -- cgit v1.2.3 From 10159a45666bf127afe8d7c654351d542e7fcb42 Mon Sep 17 00:00:00 2001 From: Miri Korenblit Date: Wed, 31 Jan 2024 22:56:32 +0200 Subject: wifi: iwlwifi: disable eSR when BT is active eSR should be disabled when BT Coex is active and: - LB link is the primary link. - LB link is the secondary link and the predicted BT penalty (the wifi loss rate caused by BT interference) is higher than a given threshold. If one of the conditions above is no longer true then re-enable eSR. In order to implement this, add support for version 5 of BT_PROFILE_NOTIFICATION, in which the bt penalty is provided by FW. Signed-off-by: Miri Korenblit Reviewed-by: Gregory Greenman Link: https://msgid.link/20240131225342.b922b6485af8.I7d808ce535a7372aca9cb85c045755e6788a4904@changeid Signed-off-by: Johannes Berg --- drivers/net/wireless/intel/iwlwifi/fw/api/coex.h | 14 ++- drivers/net/wireless/intel/iwlwifi/mvm/coex.c | 124 +++++++++++++++++++++ drivers/net/wireless/intel/iwlwifi/mvm/constants.h | 3 + .../net/wireless/intel/iwlwifi/mvm/mld-mac80211.c | 107 +++++++++++++++++- drivers/net/wireless/intel/iwlwifi/mvm/mvm.h | 21 +++- drivers/net/wireless/intel/iwlwifi/mvm/ops.c | 5 +- drivers/net/wireless/intel/iwlwifi/mvm/rx.c | 13 ++- 7 files changed, 275 insertions(+), 12 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/intel/iwlwifi/fw/api/coex.h b/drivers/net/wireless/intel/iwlwifi/fw/api/coex.h index 3e81e9369224..bc27e15488f5 100644 --- a/drivers/net/wireless/intel/iwlwifi/fw/api/coex.h +++ b/drivers/net/wireless/intel/iwlwifi/fw/api/coex.h @@ -1,5 +1,6 @@ /* SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause */ /* + * Copyright (C) 2023 Intel Corporation * Copyright (C) 2013-2014, 2018-2019 Intel Corporation * Copyright (C) 2013-2014 Intel Mobile Communications GmbH * Copyright (C) 2017 Intel Deutschland GmbH @@ -170,7 +171,11 @@ enum iwl_bt_ci_compliance { * @bt_activity_grading: the activity of BT &enum iwl_bt_activity_grading * @ttc_status: is TTC enabled - one bit per PHY * @rrc_status: is RRC enabled - one bit per PHY - * @reserved: reserved + * The following fields are only for version 5, and are reserved in version 4: + * @wifi_loss_low_rssi: The predicted lost WiFi rate (% of air time that BT is + * utilizing) when the RSSI is low (<= -65 dBm) + * @wifi_loss_mid_high_rssi: The predicted lost WiFi rate (% of air time that + * BT is utilizing) when the RSSI is mid/high (>= -65 dBm) */ struct iwl_bt_coex_profile_notif { __le32 mbox_msg[4]; @@ -182,7 +187,10 @@ struct iwl_bt_coex_profile_notif { __le32 bt_activity_grading; u8 ttc_status; u8 rrc_status; - __le16 reserved; -} __packed; /* BT_COEX_PROFILE_NTFY_API_S_VER_4 */ + u8 wifi_loss_low_rssi; + u8 wifi_loss_mid_high_rssi; +} __packed; /* BT_COEX_PROFILE_NTFY_API_S_VER_4 + * BT_COEX_PROFILE_NTFY_API_S_VER_5 + */ #endif /* __iwl_fw_api_coex_h__ */ diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/coex.c b/drivers/net/wireless/intel/iwlwifi/mvm/coex.c index 9fe1761691ec..d26075e3e6ad 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/coex.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/coex.c @@ -252,6 +252,124 @@ static void iwl_mvm_bt_coex_tcm_based_ci(struct iwl_mvm *mvm, swap(data->primary, data->secondary); } +static void iwl_mvm_bt_coex_enable_esr(struct iwl_mvm *mvm, + struct ieee80211_vif *vif, bool enable) +{ + struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); + int link_id; + + lockdep_assert_held(&mvm->mutex); + + if (!vif->cfg.assoc || !ieee80211_vif_is_mld(vif)) + return; + + /* Done already */ + if (mvmvif->bt_coex_esr_disabled == !enable) + return; + + mvmvif->bt_coex_esr_disabled = !enable; + + /* Nothing to do */ + if (mvmvif->esr_active == enable) + return; + + if (enable) { + /* Try to re-enable eSR*/ + iwl_mvm_mld_select_links(mvm, vif, false); + return; + } + + /* + * Find the primary link, as we want to switch to it and drop the + * secondary one. + */ + link_id = iwl_mvm_mld_get_primary_link(mvm, vif, vif->active_links); + WARN_ON(link_id < 0); + + ieee80211_set_active_links_async(vif, + vif->active_links & BIT(link_id)); +} + +/* + * This function receives the LB link id and checks if eSR should be + * enabled or disabled (due to BT coex) + */ +bool +iwl_mvm_bt_coex_calculate_esr_mode(struct iwl_mvm *mvm, + struct ieee80211_vif *vif, + int link_id, int primary_link) +{ + struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); + struct iwl_mvm_vif_link_info *link_info = mvmvif->link[link_id]; + bool have_wifi_loss_rate = + iwl_fw_lookup_notif_ver(mvm->fw, LEGACY_GROUP, + BT_PROFILE_NOTIFICATION, 0) > 4; + s8 link_rssi = 0; + u8 wifi_loss_rate; + + lockdep_assert_held(&mvm->mutex); + + if (mvm->last_bt_notif.wifi_loss_low_rssi == BT_OFF) + return true; + + /* If LB link is the primary one we should always disable eSR */ + if (link_id == primary_link) + return false; + + /* The feature is not supported */ + if (!have_wifi_loss_rate) + return true; + + /* + * We might not have a link_info when checking whether we can + * (re)enable eSR - the LB link might not exist yet + */ + if (link_info) + link_rssi = (s8)link_info->beacon_stats.avg_signal; + + /* + * In case we don't know the RSSI - take the lower wifi loss, + * so we will more likely enter eSR, and if RSSI is low - + * we will get an update on this and exit eSR. + */ + if (!link_rssi) + wifi_loss_rate = mvm->last_bt_notif.wifi_loss_mid_high_rssi; + + else if (!mvmvif->bt_coex_esr_disabled) + /* RSSI needs to get really low to disable eSR... */ + wifi_loss_rate = + link_rssi <= -IWL_MVM_BT_COEX_DISABLE_ESR_THRESH ? + mvm->last_bt_notif.wifi_loss_low_rssi : + mvm->last_bt_notif.wifi_loss_mid_high_rssi; + else + /* ...And really high before we enable it back */ + wifi_loss_rate = + link_rssi <= -IWL_MVM_BT_COEX_ENABLE_ESR_THRESH ? + mvm->last_bt_notif.wifi_loss_low_rssi : + mvm->last_bt_notif.wifi_loss_mid_high_rssi; + + return wifi_loss_rate <= IWL_MVM_BT_COEX_WIFI_LOSS_THRESH; +} + +void iwl_mvm_bt_coex_update_vif_esr(struct iwl_mvm *mvm, + struct ieee80211_vif *vif, + int link_id) +{ + unsigned long usable_links = ieee80211_vif_usable_links(vif); + int primary_link = iwl_mvm_mld_get_primary_link(mvm, vif, + usable_links); + bool enable; + + /* Not assoc, not MLD vif or only one usable link */ + if (primary_link < 0) + return; + + enable = iwl_mvm_bt_coex_calculate_esr_mode(mvm, vif, link_id, + primary_link); + + iwl_mvm_bt_coex_enable_esr(mvm, vif, enable); +} + static void iwl_mvm_bt_notif_per_link(struct iwl_mvm *mvm, struct ieee80211_vif *vif, struct iwl_bt_iterator_data *data, @@ -297,6 +415,8 @@ static void iwl_mvm_bt_notif_per_link(struct iwl_mvm *mvm, return; } + iwl_mvm_bt_coex_update_vif_esr(mvm, vif, link_id); + if (fw_has_capa(&mvm->fw->ucode_capa, IWL_UCODE_TLV_CAPA_COEX_SCHEMA_2)) min_ag_for_static_smps = BT_VERY_HIGH_TRAFFIC; else @@ -432,6 +552,10 @@ static void iwl_mvm_bt_notif_iterator(void *_data, u8 *mac, return; } + /* When BT is off this will be 0 */ + if (data->notif->wifi_loss_low_rssi == BT_OFF) + iwl_mvm_bt_coex_enable_esr(mvm, vif, true); + for (link_id = 0; link_id < IEEE80211_MLD_MAX_NUM_LINKS; link_id++) iwl_mvm_bt_notif_per_link(mvm, vif, data, link_id); } diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/constants.h b/drivers/net/wireless/intel/iwlwifi/mvm/constants.h index c832068b5718..f5122c4678a1 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/constants.h +++ b/drivers/net/wireless/intel/iwlwifi/mvm/constants.h @@ -11,6 +11,9 @@ #include "fw-api.h" #define IWL_MVM_UAPSD_NOAGG_BSSIDS_NUM 20 +#define IWL_MVM_BT_COEX_DISABLE_ESR_THRESH 69 +#define IWL_MVM_BT_COEX_ENABLE_ESR_THRESH 63 +#define IWL_MVM_BT_COEX_WIFI_LOSS_THRESH 0 #define IWL_MVM_DEFAULT_PS_TX_DATA_TIMEOUT (100 * USEC_PER_MSEC) #define IWL_MVM_DEFAULT_PS_RX_DATA_TIMEOUT (100 * USEC_PER_MSEC) diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/mld-mac80211.c b/drivers/net/wireless/intel/iwlwifi/mvm/mld-mac80211.c index 449229ced3bb..2b879eeecc8c 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/mld-mac80211.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/mld-mac80211.c @@ -603,6 +603,7 @@ static int iwl_mvm_mld_mac_sta_state(struct ieee80211_hw *hw, struct iwl_mvm_link_sel_data { u8 link_id; enum nl80211_band band; + enum nl80211_chan_width width; bool active; }; @@ -655,6 +656,7 @@ void iwl_mvm_mld_select_links(struct iwl_mvm *mvm, struct ieee80211_vif *vif, data[n_data].link_id = link_id; data[n_data].band = link_conf->chandef.chan->band; + data[n_data].width = link_conf->chandef.width; data[n_data].active = vif->active_links & BIT(link_id); n_data++; } @@ -1215,13 +1217,116 @@ iwl_mvm_mld_change_sta_links(struct ieee80211_hw *hw, return ret; } +/* + * This function receives a subset of the usable links bitmap and + * returns the primary link id, and -1 if such link doesn't exist + * (e.g. non-MLO connection) or wasn't found. + */ +int iwl_mvm_mld_get_primary_link(struct iwl_mvm *mvm, + struct ieee80211_vif *vif, + unsigned long usable_links) +{ + struct iwl_mvm_link_sel_data data[IEEE80211_MLD_MAX_NUM_LINKS]; + u8 link_id, n_data = 0; + + if (!ieee80211_vif_is_mld(vif) || !vif->cfg.assoc) + return -1; + + for_each_set_bit(link_id, &usable_links, IEEE80211_MLD_MAX_NUM_LINKS) { + struct ieee80211_bss_conf *link_conf = + link_conf_dereference_protected(vif, link_id); + + if (WARN_ON_ONCE(!link_conf)) + continue; + + data[n_data].link_id = link_id; + data[n_data].band = link_conf->chandef.chan->band; + data[n_data].width = link_conf->chandef.width; + data[n_data].active = true; + n_data++; + } + + if (n_data <= 1) + return -1; + + /* The logic should be modified to handle more than 2 links */ + WARN_ON_ONCE(n_data > 2); + + /* Primary link is the link with the wider bandwidth or higher band */ + if (data[0].width > data[1].width) + return data[0].link_id; + if (data[0].width < data[1].width) + return data[1].link_id; + if (data[0].band >= data[1].band) + return data[0].link_id; + + return data[1].link_id; +} + +/* + * This function receives a bitmap of usable links and check if we can enter + * eSR on those links. + */ +static bool iwl_mvm_can_enter_esr(struct iwl_mvm *mvm, + struct ieee80211_vif *vif, + unsigned long desired_links) +{ + struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); + int primary_link = iwl_mvm_mld_get_primary_link(mvm, vif, + desired_links); + bool ret = true; + int link_id; + + if (primary_link < 0) + return false; + + for_each_set_bit(link_id, &desired_links, IEEE80211_MLD_MAX_NUM_LINKS) { + struct ieee80211_bss_conf *link_conf = + link_conf_dereference_protected(vif, link_id); + + if (WARN_ON_ONCE(!link_conf)) + continue; + + /* BT Coex effects eSR mode only if one of the link is on LB */ + if (link_conf->chandef.chan->band != NL80211_BAND_2GHZ) + continue; + + ret = iwl_mvm_bt_coex_calculate_esr_mode(mvm, vif, link_id, + primary_link); + // Mark eSR as disabled for the next time + if (!ret) + mvmvif->bt_coex_esr_disabled = true; + break; + } + + return ret; +} + static bool iwl_mvm_mld_can_activate_links(struct ieee80211_hw *hw, struct ieee80211_vif *vif, u16 desired_links) { struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw); + int n_links = hweight16(desired_links); + bool ret = true; + + if (n_links <= 1) + return true; - return hweight16(desired_links) <= iwl_mvm_max_active_links(mvm, vif); + mutex_lock(&mvm->mutex); + + /* Check if HW supports the wanted number of links */ + if (n_links > iwl_mvm_max_active_links(mvm, vif)) { + ret = false; + goto unlock; + } + + /* If it is an eSR device, check that we can enter eSR */ + if (iwl_mvm_is_esr_supported(mvm->fwrt.trans)) + ret = iwl_mvm_can_enter_esr(mvm, vif, desired_links); +unlock: + mutex_unlock(&mvm->mutex); + return ret; } const struct ieee80211_ops iwl_mvm_mld_hw_ops = { diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h b/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h index af5c8b4bb5a6..9a89b91519db 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h +++ b/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h @@ -359,6 +359,7 @@ struct iwl_mvm_vif_link_info { * @pm_enabled - indicate if MAC power management is allowed * @monitor_active: indicates that monitor context is configured, and that the * interface should get quota etc. + * @bt_coex_esr_disabled: indicates if esr is disabled due to bt coex * @low_latency: bit flags for low latency * see enum &iwl_mvm_low_latency_cause for causes. * @low_latency_actual: boolean, indicates low latency is set, @@ -389,6 +390,7 @@ struct iwl_mvm_vif { bool pm_enabled; bool monitor_active; bool esr_active; + bool bt_coex_esr_disabled; u8 low_latency: 6; u8 low_latency_actual: 1; @@ -1570,13 +1572,17 @@ static inline int iwl_mvm_max_active_links(struct iwl_mvm *mvm, struct ieee80211_vif *vif) { struct iwl_trans *trans = mvm->fwrt.trans; + struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); + + lockdep_assert_held(&mvm->mutex); if (vif->type == NL80211_IFTYPE_AP) return mvm->fw->ucode_capa.num_beacons; - if (iwl_mvm_is_esr_supported(trans) || - (CSR_HW_RFID_TYPE(trans->hw_rf_id) == IWL_CFG_RF_TYPE_FM && - CSR_HW_RFID_IS_CDB(trans->hw_rf_id))) + if ((iwl_mvm_is_esr_supported(trans) && + !mvmvif->bt_coex_esr_disabled) || + ((CSR_HW_RFID_TYPE(trans->hw_rf_id) == IWL_CFG_RF_TYPE_FM && + CSR_HW_RFID_IS_CDB(trans->hw_rf_id)))) return IWL_MVM_FW_MAX_ACTIVE_LINKS_NUM; return 1; @@ -2119,6 +2125,12 @@ bool iwl_mvm_bt_coex_is_tpc_allowed(struct iwl_mvm *mvm, u8 iwl_mvm_bt_coex_get_single_ant_msk(struct iwl_mvm *mvm, u8 enabled_ants); u8 iwl_mvm_bt_coex_tx_prio(struct iwl_mvm *mvm, struct ieee80211_hdr *hdr, struct ieee80211_tx_info *info, u8 ac); +bool iwl_mvm_bt_coex_calculate_esr_mode(struct iwl_mvm *mvm, + struct ieee80211_vif *vif, + int link_id, int primary_link); +void iwl_mvm_bt_coex_update_vif_esr(struct iwl_mvm *mvm, + struct ieee80211_vif *vif, + int link_id); /* beacon filtering */ #ifdef CONFIG_IWLWIFI_DEBUGFS @@ -2733,4 +2745,7 @@ bool iwl_mvm_enable_fils(struct iwl_mvm *mvm, struct ieee80211_chanctx_conf *ctx); void iwl_mvm_mld_select_links(struct iwl_mvm *mvm, struct ieee80211_vif *vif, bool valid_links_changed); +int iwl_mvm_mld_get_primary_link(struct iwl_mvm *mvm, + struct ieee80211_vif *vif, + unsigned long usable_links); #endif /* __IWL_MVM_H__ */ diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/ops.c b/drivers/net/wireless/intel/iwlwifi/mvm/ops.c index 38a84a54ff78..871274eea26f 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/ops.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/ops.c @@ -320,7 +320,8 @@ static const struct iwl_rx_handlers iwl_mvm_rx_handlers[] = { struct iwl_tlc_update_notif), RX_HANDLER(BT_PROFILE_NOTIFICATION, iwl_mvm_rx_bt_coex_notif, - RX_HANDLER_ASYNC_LOCKED, struct iwl_bt_coex_profile_notif), + RX_HANDLER_ASYNC_LOCKED_WIPHY, + struct iwl_bt_coex_profile_notif), RX_HANDLER_NO_SIZE(BEACON_NOTIFICATION, iwl_mvm_rx_beacon_notif, RX_HANDLER_ASYNC_LOCKED), RX_HANDLER_NO_SIZE(STATISTICS_NOTIFICATION, iwl_mvm_rx_statistics, @@ -328,7 +329,7 @@ static const struct iwl_rx_handlers iwl_mvm_rx_handlers[] = { RX_HANDLER_GRP(STATISTICS_GROUP, STATISTICS_OPER_NOTIF, iwl_mvm_handle_rx_system_oper_stats, - RX_HANDLER_ASYNC_LOCKED, + RX_HANDLER_ASYNC_LOCKED_WIPHY, struct iwl_system_statistics_notif_oper), RX_HANDLER_GRP(STATISTICS_GROUP, STATISTICS_OPER_PART1_NOTIF, iwl_mvm_handle_rx_system_oper_part1_stats, diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/rx.c b/drivers/net/wireless/intel/iwlwifi/mvm/rx.c index 8caa971770c6..72df41996464 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/rx.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/rx.c @@ -841,6 +841,7 @@ iwl_mvm_stat_iterator_all_links(struct iwl_mvm *mvm, struct iwl_stats_ntfy_per_link *link_stats; struct ieee80211_bss_conf *bss_conf; struct iwl_mvm_vif *mvmvif; + struct iwl_mvm_vif_link_info *link_info; int link_id; int sig; @@ -857,20 +858,26 @@ iwl_mvm_stat_iterator_all_links(struct iwl_mvm *mvm, continue; mvmvif = iwl_mvm_vif_from_mac80211(bss_conf->vif); - if (!mvmvif || !mvmvif->link[link_id]) + link_info = mvmvif->link[link_id]; + if (!link_info) continue; link_stats = &per_link[fw_link_id]; - mvmvif->link[link_id]->beacon_stats.num_beacons = + link_info->beacon_stats.num_beacons = le32_to_cpu(link_stats->beacon_counter); /* we basically just use the u8 to store 8 bits and then treat * it as a s8 whenever we take it out to a different type. */ - mvmvif->link[link_id]->beacon_stats.avg_signal = + link_info->beacon_stats.avg_signal = -le32_to_cpu(link_stats->beacon_average_energy); + if (link_info->phy_ctxt && + link_info->phy_ctxt->channel->band == NL80211_BAND_2GHZ) + iwl_mvm_bt_coex_update_vif_esr(mvm, bss_conf->vif, + link_id); + /* make sure that beacon statistics don't go backwards with TCM * request to clear statistics */ -- cgit v1.2.3 From 619a900f279800876e425ce4ef41c4e493bdf7d4 Mon Sep 17 00:00:00 2001 From: Ilan Peer Date: Wed, 31 Jan 2024 23:08:16 +0200 Subject: wifi: iwlwifi: mvm: Add support for removing responder TKs When removing a PASN station, the TK must be removed before the station is removed as otherwise the FW would assert. To handle this, store the key configuration, and use it to remove the key when the station is removed. Signed-off-by: Ilan Peer Reviewed-by: Gregory Greenman Signed-off-by: Miri Korenblit Link: https://msgid.link/20240131230734.3e6364730c04.Ia76dc4a9d399f1f68ac6b157d844b63f74d5159f@changeid Signed-off-by: Johannes Berg --- drivers/net/wireless/intel/iwlwifi/mvm/ftm-responder.c | 11 +++++++++-- drivers/net/wireless/intel/iwlwifi/mvm/mld-key.c | 15 +++++++++++++++ drivers/net/wireless/intel/iwlwifi/mvm/mvm.h | 4 ++++ drivers/net/wireless/intel/iwlwifi/mvm/sta.c | 15 ++++----------- drivers/net/wireless/intel/iwlwifi/mvm/sta.h | 3 ++- 5 files changed, 34 insertions(+), 14 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/ftm-responder.c b/drivers/net/wireless/intel/iwlwifi/mvm/ftm-responder.c index 8f10590f9cdd..f72ca38d7c0e 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/ftm-responder.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/ftm-responder.c @@ -12,6 +12,9 @@ struct iwl_mvm_pasn_sta { struct list_head list; struct iwl_mvm_int_sta int_sta; u8 addr[ETH_ALEN]; + + /* must be last as it followed by buffer holding the key */ + struct ieee80211_key_conf keyconf; }; struct iwl_mvm_pasn_hltk_data { @@ -303,6 +306,10 @@ static void iwl_mvm_resp_del_pasn_sta(struct iwl_mvm *mvm, { list_del(&sta->list); + if (sta->keyconf.keylen) + iwl_mvm_sec_key_del_pasn(mvm, vif, BIT(sta->int_sta.sta_id), + &sta->keyconf); + if (iwl_mvm_has_mld_api(mvm->fw)) iwl_mvm_mld_rm_sta_id(mvm, sta->int_sta.sta_id); else @@ -352,12 +359,12 @@ int iwl_mvm_ftm_respoder_add_pasn_sta(struct iwl_mvm *mvm, } if (tk && tk_len) { - sta = kzalloc(sizeof(*sta), GFP_KERNEL); + sta = kzalloc(sizeof(*sta) + tk_len, GFP_KERNEL); if (!sta) return -ENOBUFS; ret = iwl_mvm_add_pasn_sta(mvm, vif, &sta->int_sta, addr, - cipher, tk, tk_len); + cipher, tk, tk_len, &sta->keyconf); if (ret) { kfree(sta); return ret; diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/mld-key.c b/drivers/net/wireless/intel/iwlwifi/mvm/mld-key.c index ea3e9e9c6e26..a1ce08a5527c 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/mld-key.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/mld-key.c @@ -335,6 +335,21 @@ static int _iwl_mvm_sec_key_del(struct iwl_mvm *mvm, return ret; } +int iwl_mvm_sec_key_del_pasn(struct iwl_mvm *mvm, + struct ieee80211_vif *vif, + u32 sta_mask, + struct ieee80211_key_conf *keyconf) +{ + u32 key_flags = iwl_mvm_get_sec_flags(mvm, vif, NULL, keyconf) | + IWL_SEC_KEY_FLAG_MFP; + + if (WARN_ON(!sta_mask)) + return -EINVAL; + + return __iwl_mvm_sec_key_del(mvm, sta_mask, key_flags, keyconf->keyidx, + 0); +} + int iwl_mvm_sec_key_del(struct iwl_mvm *mvm, struct ieee80211_vif *vif, struct ieee80211_sta *sta, diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h b/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h index 9a89b91519db..e148ef02ff73 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h +++ b/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h @@ -2402,6 +2402,10 @@ int iwl_mvm_sec_key_del(struct iwl_mvm *mvm, struct ieee80211_vif *vif, struct ieee80211_sta *sta, struct ieee80211_key_conf *keyconf); +int iwl_mvm_sec_key_del_pasn(struct iwl_mvm *mvm, + struct ieee80211_vif *vif, + u32 sta_mask, + struct ieee80211_key_conf *keyconf); void iwl_mvm_sec_key_remove_ap(struct iwl_mvm *mvm, struct ieee80211_vif *vif, struct iwl_mvm_vif_link_info *link, diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/sta.c b/drivers/net/wireless/intel/iwlwifi/mvm/sta.c index 2a3ca9785974..d57fcbe4f8ac 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/sta.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/sta.c @@ -4298,12 +4298,12 @@ u16 iwl_mvm_tid_queued(struct iwl_mvm *mvm, struct iwl_mvm_tid_data *tid_data) int iwl_mvm_add_pasn_sta(struct iwl_mvm *mvm, struct ieee80211_vif *vif, struct iwl_mvm_int_sta *sta, u8 *addr, u32 cipher, - u8 *key, u32 key_len) + u8 *key, u32 key_len, + struct ieee80211_key_conf *keyconf) { int ret; u16 queue; struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); - struct ieee80211_key_conf *keyconf; unsigned int wdg_timeout = iwl_mvm_get_wd_timeout(mvm, vif, false, false); bool mld = iwl_mvm_has_mld_api(mvm->fw); @@ -4328,12 +4328,6 @@ int iwl_mvm_add_pasn_sta(struct iwl_mvm *mvm, struct ieee80211_vif *vif, if (ret) goto out; - keyconf = kzalloc(sizeof(*keyconf) + key_len, GFP_KERNEL); - if (!keyconf) { - ret = -ENOBUFS; - goto out; - } - keyconf->cipher = cipher; memcpy(keyconf->key, key, key_len); keyconf->keylen = key_len; @@ -4354,10 +4348,9 @@ int iwl_mvm_add_pasn_sta(struct iwl_mvm *mvm, struct ieee80211_vif *vif, 0, NULL, 0, 0, true); } - kfree(keyconf); - return 0; out: - iwl_mvm_dealloc_int_sta(mvm, sta); + if (ret) + iwl_mvm_dealloc_int_sta(mvm, sta); return ret; } diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/sta.h b/drivers/net/wireless/intel/iwlwifi/mvm/sta.h index b33a0ce096d4..4668f413abd3 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/sta.h +++ b/drivers/net/wireless/intel/iwlwifi/mvm/sta.h @@ -574,7 +574,8 @@ void iwl_mvm_csa_client_absent(struct iwl_mvm *mvm, struct ieee80211_vif *vif); void iwl_mvm_add_new_dqa_stream_wk(struct work_struct *wk); int iwl_mvm_add_pasn_sta(struct iwl_mvm *mvm, struct ieee80211_vif *vif, struct iwl_mvm_int_sta *sta, u8 *addr, u32 cipher, - u8 *key, u32 key_len); + u8 *key, u32 key_len, + struct ieee80211_key_conf *key_conf_out); void iwl_mvm_cancel_channel_switch(struct iwl_mvm *mvm, struct ieee80211_vif *vif, u32 id); -- cgit v1.2.3 From 91380f768d7f6e3d003755defa792e9a00a1444a Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Sun, 28 Jan 2024 08:53:48 +0200 Subject: wifi: iwlwifi: mvm: report beacon protection failures Andrei reports that we just silently drop beacons after we report the key counters, but never report to userspace, so wpa_supplicant cannot send the WNM action frame. Fix that. Fixes: b1fdc2505abc ("iwlwifi: mvm: advertise BIGTK client support if available") Reported-by: Andrei Otcheretianski Signed-off-by: Johannes Berg Reviewed-by: Gregory Greenman Signed-off-by: Miri Korenblit Link: https://msgid.link/20240128084842.7d855442cdce.Iba90b26f893dc8c49bfb8be65373cd0a138af12c@changeid Signed-off-by: Johannes Berg --- drivers/net/wireless/intel/iwlwifi/mvm/rxmq.c | 26 +++++++++++++++----------- 1 file changed, 15 insertions(+), 11 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/rxmq.c b/drivers/net/wireless/intel/iwlwifi/mvm/rxmq.c index 886d00098528..451af501c7a1 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/rxmq.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/rxmq.c @@ -282,6 +282,7 @@ static int iwl_mvm_rx_mgmt_prot(struct ieee80211_sta *sta, u32 status, struct ieee80211_rx_status *stats) { + struct wireless_dev *wdev; struct iwl_mvm_sta *mvmsta; struct iwl_mvm_vif *mvmvif; u8 keyid; @@ -303,9 +304,15 @@ static int iwl_mvm_rx_mgmt_prot(struct ieee80211_sta *sta, if (!ieee80211_is_beacon(hdr->frame_control)) return 0; + if (!sta) + return -1; + + mvmsta = iwl_mvm_sta_from_mac80211(sta); + mvmvif = iwl_mvm_vif_from_mac80211(mvmsta->vif); + /* key mismatch - will also report !MIC_OK but we shouldn't count it */ if (!(status & IWL_RX_MPDU_STATUS_KEY_VALID)) - return -1; + goto report; /* good cases */ if (likely(status & IWL_RX_MPDU_STATUS_MIC_OK && @@ -314,13 +321,6 @@ static int iwl_mvm_rx_mgmt_prot(struct ieee80211_sta *sta, return 0; } - if (!sta) - return -1; - - mvmsta = iwl_mvm_sta_from_mac80211(sta); - - mvmvif = iwl_mvm_vif_from_mac80211(mvmsta->vif); - /* * both keys will have the same cipher and MIC length, use * whichever one is available @@ -329,11 +329,11 @@ static int iwl_mvm_rx_mgmt_prot(struct ieee80211_sta *sta, if (!key) { key = rcu_dereference(mvmvif->bcn_prot.keys[1]); if (!key) - return -1; + goto report; } if (len < key->icv_len + IEEE80211_GMAC_PN_LEN + 2) - return -1; + goto report; /* get the real key ID */ keyid = frame[len - key->icv_len - IEEE80211_GMAC_PN_LEN - 2]; @@ -347,7 +347,7 @@ static int iwl_mvm_rx_mgmt_prot(struct ieee80211_sta *sta, return -1; key = rcu_dereference(mvmvif->bcn_prot.keys[keyid - 6]); if (!key) - return -1; + goto report; } /* Report status to mac80211 */ @@ -355,6 +355,10 @@ static int iwl_mvm_rx_mgmt_prot(struct ieee80211_sta *sta, ieee80211_key_mic_failure(key); else if (status & IWL_RX_MPDU_STATUS_REPLAY_ERROR) ieee80211_key_replay(key); +report: + wdev = ieee80211_vif_to_wdev(mvmsta->vif); + if (wdev->netdev) + cfg80211_rx_unprot_mlme_mgmt(wdev->netdev, (void *)hdr, len); return -1; } -- cgit v1.2.3 From 7255263962ae6a41c73e44fb3520072ef74492a7 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Sun, 28 Jan 2024 08:53:49 +0200 Subject: wifi: iwlwifi: mvm: d3: disconnect on GTK rekey failure If there was a rekey failure during D3 when firmware is handling the GTK rekeying, and it decided that we should wake up, then there was an issue in the connection and we don't necessarily have the right keys, so we should disconnect. Signed-off-by: Johannes Berg Reviewed-by: Emmanuel Grumbach Reviewed-by: Gregory Greenman Signed-off-by: Miri Korenblit Link: https://msgid.link/20240128084842.944af193d479.I5ef9f1f0e048d44d7158615d071b793d69eceb75@changeid Signed-off-by: Johannes Berg --- drivers/net/wireless/intel/iwlwifi/mvm/d3.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/d3.c b/drivers/net/wireless/intel/iwlwifi/mvm/d3.c index 4582afb149d7..61aeb7f6604b 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/d3.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/d3.c @@ -1462,7 +1462,8 @@ static void iwl_mvm_report_wakeup_reasons(struct iwl_mvm *mvm, status->pattern_number; if (reasons & (IWL_WOWLAN_WAKEUP_BY_DISCONNECTION_ON_MISSED_BEACON | - IWL_WOWLAN_WAKEUP_BY_DISCONNECTION_ON_DEAUTH)) + IWL_WOWLAN_WAKEUP_BY_DISCONNECTION_ON_DEAUTH | + IWL_WOWLAN_WAKEUP_BY_GTK_REKEY_FAILURE)) wakeup.disconnect = true; if (reasons & IWL_WOWLAN_WAKEUP_BY_GTK_REKEY_FAILURE) -- cgit v1.2.3 From 8a41c017409198dd4de5a4c522cd5ae4810a5911 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Sun, 28 Jan 2024 08:53:50 +0200 Subject: wifi: iwlwifi: fix some kernel-doc issues Add return descriptions, move description contents after (parameter) sections and fix short descriptions. Signed-off-by: Johannes Berg Reviewed-by: Gregory Greenman Signed-off-by: Miri Korenblit Link: https://msgid.link/20240128084842.02ac00f67239.I4ad17097badfcbb82ccdb8c126f61a6f3170798e@changeid Signed-off-by: Johannes Berg --- drivers/net/wireless/intel/iwlwifi/fw/dbg.c | 15 +++++++++------ drivers/net/wireless/intel/iwlwifi/iwl-eeprom-parse.c | 2 +- drivers/net/wireless/intel/iwlwifi/mvm/ops.c | 4 ++-- drivers/net/wireless/intel/iwlwifi/mvm/rs.c | 2 ++ drivers/net/wireless/intel/iwlwifi/mvm/utils.c | 2 ++ 5 files changed, 16 insertions(+), 9 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/intel/iwlwifi/fw/dbg.c b/drivers/net/wireless/intel/iwlwifi/fw/dbg.c index e27774e7ed74..05e220173fa1 100644 --- a/drivers/net/wireless/intel/iwlwifi/fw/dbg.c +++ b/drivers/net/wireless/intel/iwlwifi/fw/dbg.c @@ -1728,10 +1728,12 @@ iwl_dump_ini_mem_fill_header(struct iwl_fw_runtime *fwrt, /** * mask_apply_and_normalize - applies mask on val and normalize the result * - * The normalization is based on the first set bit in the mask - * * @val: value * @mask: mask to apply and to normalize with + * + * The normalization is based on the first set bit in the mask + * + * Returns: the extracted value */ static u32 mask_apply_and_normalize(u32 val, u32 mask) { @@ -2200,15 +2202,16 @@ struct iwl_dump_ini_mem_ops { }; /** - * iwl_dump_ini_mem - * - * Creates a dump tlv and copy a memory region into it. - * Returns the size of the current dump tlv or 0 if failed + * iwl_dump_ini_mem - dump memory region * * @fwrt: fw runtime struct * @list: list to add the dump tlv to * @reg_data: memory region * @ops: memory dump operations + * + * Creates a dump tlv and copy a memory region into it. + * + * Returns: the size of the current dump tlv or 0 if failed */ static u32 iwl_dump_ini_mem(struct iwl_fw_runtime *fwrt, struct list_head *list, struct iwl_dump_ini_region_data *reg_data, diff --git a/drivers/net/wireless/intel/iwlwifi/iwl-eeprom-parse.c b/drivers/net/wireless/intel/iwlwifi/iwl-eeprom-parse.c index 5aab64c63a13..2b290fab1ef2 100644 --- a/drivers/net/wireless/intel/iwlwifi/iwl-eeprom-parse.c +++ b/drivers/net/wireless/intel/iwlwifi/iwl-eeprom-parse.c @@ -270,7 +270,7 @@ enum iwl_eeprom_enhanced_txpwr_flags { }; /** - * struct iwl_eeprom_enhanced_txpwr + * struct iwl_eeprom_enhanced_txpwr - enhanced regulatory TX power limits * @flags: entry flags * @channel: channel number * @chain_a_max: chain a max power in 1/2 dBm diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/ops.c b/drivers/net/wireless/intel/iwlwifi/mvm/ops.c index 871274eea26f..20054a0c7892 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/ops.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/ops.c @@ -259,7 +259,7 @@ static void iwl_mvm_rx_thermal_dual_chain_req(struct iwl_mvm *mvm, } /** - * enum iwl_rx_handler_context context for Rx handler + * enum iwl_rx_handler_context: context for Rx handler * @RX_HANDLER_SYNC : this means that it will be called in the Rx path * which can't acquire mvm->mutex. * @RX_HANDLER_ASYNC_LOCKED : If the handler needs to hold mvm->mutex @@ -279,7 +279,7 @@ enum iwl_rx_handler_context { }; /** - * struct iwl_rx_handlers handler for FW notification + * struct iwl_rx_handlers: handler for FW notification * @cmd_id: command id * @min_size: minimum size to expect for the notification * @context: see &iwl_rx_handler_context diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/rs.c b/drivers/net/wireless/intel/iwlwifi/mvm/rs.c index 481d68cbbbd8..a8c4e354e2ce 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/rs.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/rs.c @@ -4161,6 +4161,8 @@ static int rs_drv_tx_protection(struct iwl_mvm *mvm, struct iwl_mvm_sta *mvmsta, * @mvm: The mvm component * @mvmsta: The station * @enable: Enable Tx protection? + * + * Returns: an error code */ int iwl_mvm_tx_protection(struct iwl_mvm *mvm, struct iwl_mvm_sta *mvmsta, bool enable) diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/utils.c b/drivers/net/wireless/intel/iwlwifi/mvm/utils.c index 91286018a69d..ab56ff87c6f9 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/utils.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/utils.c @@ -249,6 +249,8 @@ u8 iwl_mvm_next_antenna(struct iwl_mvm *mvm, u8 valid, u8 last_idx) * This is the special case in which init is set and we call a callback in * this case to clear the state indicating that station creation is in * progress. + * + * Returns: an error code indicating success or failure */ int iwl_mvm_send_lq_cmd(struct iwl_mvm *mvm, struct iwl_lq_cmd *lq) { -- cgit v1.2.3 From 2f72c759fdd413bbfd8888af8e31312b34d2be33 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Sun, 28 Jan 2024 08:53:51 +0200 Subject: wifi: iwlwifi: dbg-tlv: avoid extra allocation/copy In iwl_dbg_tlv_alloc_trigger() the code makes a copy just to modify it and pass it to another function to make a copy again. Change the API to return the copy so the adjustment can be done without another copy. Signed-off-by: Johannes Berg Reviewed-by: Gregory Greenman Signed-off-by: Miri Korenblit Link: https://msgid.link/20240128084842.075c8b9f7030.Id5a61e1a87a9c6932727fb4e2c9b54ed6070362a@changeid Signed-off-by: Johannes Berg --- drivers/net/wireless/intel/iwlwifi/iwl-dbg-tlv.c | 49 +++++++++++++----------- 1 file changed, 27 insertions(+), 22 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/intel/iwlwifi/iwl-dbg-tlv.c b/drivers/net/wireless/intel/iwlwifi/iwl-dbg-tlv.c index 72075720969c..7b145b417810 100644 --- a/drivers/net/wireless/intel/iwlwifi/iwl-dbg-tlv.c +++ b/drivers/net/wireless/intel/iwlwifi/iwl-dbg-tlv.c @@ -64,21 +64,22 @@ dbg_ver_table[IWL_DBG_TLV_TYPE_NUM] = { [IWL_DBG_TLV_TYPE_CONF_SET] = {.min_ver = 1, .max_ver = 1,}, }; -static int iwl_dbg_tlv_add(const struct iwl_ucode_tlv *tlv, - struct list_head *list) +/* add a new TLV node, returning it so it can be modified */ +static struct iwl_ucode_tlv *iwl_dbg_tlv_add(const struct iwl_ucode_tlv *tlv, + struct list_head *list) { u32 len = le32_to_cpu(tlv->length); struct iwl_dbg_tlv_node *node; node = kzalloc(sizeof(*node) + len, GFP_KERNEL); if (!node) - return -ENOMEM; + return NULL; memcpy(&node->tlv, tlv, sizeof(node->tlv)); memcpy(node->tlv.data, tlv->data, len); list_add_tail(&node->list, list); - return 0; + return &node->tlv; } static bool iwl_dbg_tlv_ver_support(const struct iwl_ucode_tlv *tlv) @@ -106,7 +107,9 @@ static int iwl_dbg_tlv_alloc_debug_info(struct iwl_trans *trans, IWL_DEBUG_FW(trans, "WRT: Loading debug cfg: %s\n", debug_info->debug_cfg_name); - return iwl_dbg_tlv_add(tlv, &trans->dbg.debug_info_tlv_list); + if (!iwl_dbg_tlv_add(tlv, &trans->dbg.debug_info_tlv_list)) + return -ENOMEM; + return 0; } static int iwl_dbg_tlv_alloc_buf_alloc(struct iwl_trans *trans, @@ -175,7 +178,9 @@ static int iwl_dbg_tlv_alloc_hcmd(struct iwl_trans *trans, return -EINVAL; } - return iwl_dbg_tlv_add(tlv, &trans->dbg.time_point[tp].hcmd_list); + if (!iwl_dbg_tlv_add(tlv, &trans->dbg.time_point[tp].hcmd_list)) + return -ENOMEM; + return 0; } static int iwl_dbg_tlv_alloc_region(struct iwl_trans *trans, @@ -246,11 +251,9 @@ static int iwl_dbg_tlv_alloc_trigger(struct iwl_trans *trans, const struct iwl_ucode_tlv *tlv) { const struct iwl_fw_ini_trigger_tlv *trig = (const void *)tlv->data; - struct iwl_fw_ini_trigger_tlv *dup_trig; u32 tp = le32_to_cpu(trig->time_point); u32 rf = le32_to_cpu(trig->reset_fw); - struct iwl_ucode_tlv *dup = NULL; - int ret; + struct iwl_ucode_tlv *new_tlv; if (le32_to_cpu(tlv->length) < sizeof(*trig)) return -EINVAL; @@ -267,20 +270,18 @@ static int iwl_dbg_tlv_alloc_trigger(struct iwl_trans *trans, "WRT: time point %u for trigger TLV with reset_fw %u\n", tp, rf); trans->dbg.last_tp_resetfw = 0xFF; + + new_tlv = iwl_dbg_tlv_add(tlv, &trans->dbg.time_point[tp].trig_list); + if (!new_tlv) + return -ENOMEM; + if (!le32_to_cpu(trig->occurrences)) { - dup = kmemdup(tlv, sizeof(*tlv) + le32_to_cpu(tlv->length), - GFP_KERNEL); - if (!dup) - return -ENOMEM; - dup_trig = (void *)dup->data; - dup_trig->occurrences = cpu_to_le32(-1); - tlv = dup; - } + struct iwl_fw_ini_trigger_tlv *new_trig = (void *)new_tlv->data; - ret = iwl_dbg_tlv_add(tlv, &trans->dbg.time_point[tp].trig_list); - kfree(dup); + new_trig->occurrences = cpu_to_le32(-1); + } - return ret; + return 0; } static int iwl_dbg_tlv_config_set(struct iwl_trans *trans, @@ -304,7 +305,9 @@ static int iwl_dbg_tlv_config_set(struct iwl_trans *trans, return -EINVAL; } - return iwl_dbg_tlv_add(tlv, &trans->dbg.time_point[tp].config_list); + if (!iwl_dbg_tlv_add(tlv, &trans->dbg.time_point[tp].config_list)) + return -ENOMEM; + return 0; } static int (*dbg_tlv_alloc[])(struct iwl_trans *trans, @@ -1148,7 +1151,9 @@ iwl_dbg_tlv_add_active_trigger(struct iwl_fw_runtime *fwrt, if (!match) { IWL_DEBUG_FW(fwrt, "WRT: Enabling trigger (time point %u)\n", le32_to_cpu(trig->time_point)); - return iwl_dbg_tlv_add(trig_tlv, trig_list); + if (!iwl_dbg_tlv_add(trig_tlv, trig_list)) + return -ENOMEM; + return 0; } return iwl_dbg_tlv_override_trig_node(fwrt, trig_tlv, match); -- cgit v1.2.3 From 1722c83f8fbba56c03e0ac597a242c8b0ef4d62c Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Sun, 28 Jan 2024 08:53:52 +0200 Subject: wifi: iwlwifi: dbg-tlv: use struct_size() for allocation This is effectively the same since we don't even have a multiplication, but better captures what happens with the length. Signed-off-by: Johannes Berg Reviewed-by: Gregory Greenman Signed-off-by: Miri Korenblit Link: https://msgid.link/20240128084842.f301641eb916.I66b7b48a526377d682eecef874373bf3a01076c8@changeid Signed-off-by: Johannes Berg --- drivers/net/wireless/intel/iwlwifi/iwl-dbg-tlv.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/intel/iwlwifi/iwl-dbg-tlv.c b/drivers/net/wireless/intel/iwlwifi/iwl-dbg-tlv.c index 7b145b417810..989b100ce6ab 100644 --- a/drivers/net/wireless/intel/iwlwifi/iwl-dbg-tlv.c +++ b/drivers/net/wireless/intel/iwlwifi/iwl-dbg-tlv.c @@ -71,7 +71,7 @@ static struct iwl_ucode_tlv *iwl_dbg_tlv_add(const struct iwl_ucode_tlv *tlv, u32 len = le32_to_cpu(tlv->length); struct iwl_dbg_tlv_node *node; - node = kzalloc(sizeof(*node) + len, GFP_KERNEL); + node = kzalloc(struct_size(node, tlv.data, len), GFP_KERNEL); if (!node) return NULL; -- cgit v1.2.3 From ea1d166fae14e05d49ffb0ea9fcd4658f8d3dcea Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Sun, 28 Jan 2024 08:53:53 +0200 Subject: wifi: iwlwifi: dbg-tlv: ensure NUL termination The iwl_fw_ini_debug_info_tlv is used as a string, so we must ensure the string is terminated correctly before using it. Fixes: a9248de42464 ("iwlwifi: dbg_ini: add TLV allocation new API support") Signed-off-by: Johannes Berg Reviewed-by: Gregory Greenman Signed-off-by: Miri Korenblit Link: https://msgid.link/20240128084842.be15e858ee89.Ibff93429cf999eafc7b26f3eef4c055dc84984a0@changeid Signed-off-by: Johannes Berg --- drivers/net/wireless/intel/iwlwifi/iwl-dbg-tlv.c | 6 ++++++ 1 file changed, 6 insertions(+) (limited to 'drivers/net') diff --git a/drivers/net/wireless/intel/iwlwifi/iwl-dbg-tlv.c b/drivers/net/wireless/intel/iwlwifi/iwl-dbg-tlv.c index 989b100ce6ab..6cfcf1c14eaf 100644 --- a/drivers/net/wireless/intel/iwlwifi/iwl-dbg-tlv.c +++ b/drivers/net/wireless/intel/iwlwifi/iwl-dbg-tlv.c @@ -104,6 +104,12 @@ static int iwl_dbg_tlv_alloc_debug_info(struct iwl_trans *trans, if (le32_to_cpu(tlv->length) != sizeof(*debug_info)) return -EINVAL; + /* we use this as a string, ensure input was NUL terminated */ + if (strnlen(debug_info->debug_cfg_name, + sizeof(debug_info->debug_cfg_name)) == + sizeof(debug_info->debug_cfg_name)) + return -EINVAL; + IWL_DEBUG_FW(trans, "WRT: Loading debug cfg: %s\n", debug_info->debug_cfg_name); -- cgit v1.2.3 From ec06e9b95944563964170d9e30278361bb26fd3a Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Sun, 28 Jan 2024 08:53:54 +0200 Subject: wifi: iwlwifi: fw: dbg: ensure correct config name sizes This hard-codes the size, but it's not obvious why that's correct. Use sizeof() and cross-check the two structs. Signed-off-by: Johannes Berg Reviewed-by: Gregory Greenman Signed-off-by: Miri Korenblit Link: https://msgid.link/20240128084842.58fcdea2ace7.I49cb1d7bdbea12085aada0c96ef42fcbcb3d2b38@changeid Signed-off-by: Johannes Berg --- drivers/net/wireless/intel/iwlwifi/fw/dbg.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/intel/iwlwifi/fw/dbg.c b/drivers/net/wireless/intel/iwlwifi/fw/dbg.c index 05e220173fa1..b877a2cd4005 100644 --- a/drivers/net/wireless/intel/iwlwifi/fw/dbg.c +++ b/drivers/net/wireless/intel/iwlwifi/fw/dbg.c @@ -2430,9 +2430,12 @@ static u32 iwl_dump_ini_info(struct iwl_fw_runtime *fwrt, struct iwl_fw_ini_debug_info_tlv *debug_info = (void *)node->tlv.data; + BUILD_BUG_ON(sizeof(cfg_name->cfg_name) != + sizeof(debug_info->debug_cfg_name)); + cfg_name->image_type = debug_info->image_type; cfg_name->cfg_name_len = - cpu_to_le32(IWL_FW_INI_MAX_CFG_NAME); + cpu_to_le32(sizeof(cfg_name->cfg_name)); memcpy(cfg_name->cfg_name, debug_info->debug_cfg_name, sizeof(cfg_name->cfg_name)); cfg_name++; -- cgit v1.2.3 From 296f3e926716ded8dc29e349d2b042b362f96515 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Sun, 28 Jan 2024 08:53:55 +0200 Subject: wifi: iwlwifi: acpi: fix WPFC reading The code reading the WPFC table needs to take into account the domain type (first element in the package), shouldn't leak the memory if it fails, and has a bad comment. Fix all these issues. Fixes: c4c954547755 ("wifi: iwlwifi: implement WPFC ACPI table loading") Reported-by: Miri Korenblit Signed-off-by: Johannes Berg Reviewed-by: Gregory Greenman Gregory Link: https://msgid.link/20240128084842.2afeb476b62d.I200568dc42a277e21c12be99d5aaa39b009d45da@changeid Signed-off-by: Johannes Berg --- drivers/net/wireless/intel/iwlwifi/fw/acpi.c | 10 +++++----- drivers/net/wireless/intel/iwlwifi/fw/acpi.h | 2 +- 2 files changed, 6 insertions(+), 6 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/intel/iwlwifi/fw/acpi.c b/drivers/net/wireless/intel/iwlwifi/fw/acpi.c index b96f30d11644..72a0a9565371 100644 --- a/drivers/net/wireless/intel/iwlwifi/fw/acpi.c +++ b/drivers/net/wireless/intel/iwlwifi/fw/acpi.c @@ -1293,7 +1293,6 @@ void iwl_acpi_get_phy_filters(struct iwl_fw_runtime *fwrt, if (IS_ERR(data)) return; - /* try to read wtas table revision 1 or revision 0*/ wifi_pkg = iwl_acpi_get_wifi_pkg(fwrt->dev, data, ACPI_WPFC_WIFI_DATA_SIZE, &tbl_rev); @@ -1303,13 +1302,14 @@ void iwl_acpi_get_phy_filters(struct iwl_fw_runtime *fwrt, if (tbl_rev != 0) goto out_free; - BUILD_BUG_ON(ARRAY_SIZE(filters->filter_cfg_chains) != ACPI_WPFC_WIFI_DATA_SIZE); + BUILD_BUG_ON(ARRAY_SIZE(filters->filter_cfg_chains) != + ACPI_WPFC_WIFI_DATA_SIZE - 1); for (i = 0; i < ARRAY_SIZE(filters->filter_cfg_chains); i++) { - if (wifi_pkg->package.elements[i].type != ACPI_TYPE_INTEGER) - return; + if (wifi_pkg->package.elements[i + 1].type != ACPI_TYPE_INTEGER) + goto out_free; tmp.filter_cfg_chains[i] = - cpu_to_le32(wifi_pkg->package.elements[i].integer.value); + cpu_to_le32(wifi_pkg->package.elements[i + 1].integer.value); } IWL_DEBUG_RADIO(fwrt, "Loaded WPFC filter config from ACPI\n"); diff --git a/drivers/net/wireless/intel/iwlwifi/fw/acpi.h b/drivers/net/wireless/intel/iwlwifi/fw/acpi.h index e9277f6f3582..39106ccb4b9b 100644 --- a/drivers/net/wireless/intel/iwlwifi/fw/acpi.h +++ b/drivers/net/wireless/intel/iwlwifi/fw/acpi.h @@ -56,7 +56,7 @@ #define ACPI_EWRD_WIFI_DATA_SIZE_REV2 ((ACPI_SAR_PROFILE_NUM - 1) * \ ACPI_SAR_NUM_CHAINS_REV2 * \ ACPI_SAR_NUM_SUB_BANDS_REV2 + 3) -#define ACPI_WPFC_WIFI_DATA_SIZE 4 /* 4 filter config words */ +#define ACPI_WPFC_WIFI_DATA_SIZE 5 /* domain and 4 filter config words */ /* revision 0 and 1 are identical, except for the semantics in the FW */ #define ACPI_GEO_NUM_BANDS_REV0 2 -- cgit v1.2.3 From e50a88e5cb8792cc416866496288c5f4d1eb4b1f Mon Sep 17 00:00:00 2001 From: Emmanuel Grumbach Date: Sun, 28 Jan 2024 08:53:56 +0200 Subject: wifi: iwlwifi: mvm: disconnect station vifs if recovery failed This will allow to reconnect immediately instead of leaving the connection in a limbo state. Signed-off-by: Emmanuel Grumbach Reviewed-by: Gregory Greenman Signed-off-by: Miri Korenblit Link: https://msgid.link/20240128084842.e90531cd3a36.Iebdc9483983c0d8497f9dcf9d79ec37332a5fdcc@changeid Signed-off-by: Johannes Berg --- drivers/net/wireless/intel/iwlwifi/mvm/fw.c | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/fw.c b/drivers/net/wireless/intel/iwlwifi/mvm/fw.c index b6acf4ade552..175024170357 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/fw.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/fw.c @@ -1504,6 +1504,13 @@ void iwl_mvm_get_acpi_tables(struct iwl_mvm *mvm) #endif /* CONFIG_ACPI */ +static void iwl_mvm_disconnect_iterator(void *data, u8 *mac, + struct ieee80211_vif *vif) +{ + if (vif->type == NL80211_IFTYPE_STATION) + ieee80211_hw_restart_disconnect(vif); +} + void iwl_mvm_send_recovery_cmd(struct iwl_mvm *mvm, u32 flags) { u32 error_log_size = mvm->fw->ucode_capa.error_log_size; @@ -1548,10 +1555,15 @@ void iwl_mvm_send_recovery_cmd(struct iwl_mvm *mvm, u32 flags) /* skb respond is only relevant in ERROR_RECOVERY_UPDATE_DB */ if (flags & ERROR_RECOVERY_UPDATE_DB) { resp = le32_to_cpu(*(__le32 *)host_cmd.resp_pkt->data); - if (resp) + if (resp) { IWL_ERR(mvm, "Failed to send recovery cmd blob was invalid %d\n", resp); + + ieee80211_iterate_interfaces(mvm->hw, 0, + iwl_mvm_disconnect_iterator, + mvm); + } } } -- cgit v1.2.3 From d3b2c6c65bfd3b9616084e91bd0d402964ea7cef Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Sun, 28 Jan 2024 08:53:58 +0200 Subject: wifi: iwlwifi: mvm: initialize rates in FW earlier When connecting to an AP, we currently initialize the rate control only after associating. Since we now use firmware to assign rates to auth/assoc frames rather than using the data in the station and the firmware doesn't know, they're transmitted using low mandatory rates. However, if the AP advertised only higher supported rates we want to use them to be nicer (it still must receive mandatory rates though), so send the information to the firmware earlier to have it know about it and be able to use it. Fixes: 499d02790495 ("wifi: iwlwifi: Use FW rate for non-data frames") Signed-off-by: Johannes Berg Signed-off-by: Miri Korenblit Link: https://msgid.link/20240128084842.ed7ab1c859c2.I4b4d4fc3905c8d8470fc0fee4648f25c950c9bb7@changeid Signed-off-by: Johannes Berg --- drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c | 13 +++++++++++++ 1 file changed, 13 insertions(+) (limited to 'drivers/net') diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c b/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c index 406956574f52..40b8f5a5ccf1 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c @@ -3686,6 +3686,19 @@ iwl_mvm_sta_state_notexist_to_none(struct iwl_mvm *mvm, if (vif->type == NL80211_IFTYPE_STATION && !sta->tdls) mvmvif->ap_sta = sta; + /* + * Initialize the rates here already - this really tells + * the firmware only what the supported legacy rates are + * (may be) since it's initialized already from what the + * AP advertised in the beacon/probe response. This will + * allow the firmware to send auth/assoc frames with one + * of the supported rates already, rather than having to + * use a mandatory rate. + * If we're the AP, we'll just assume mandatory rates at + * this point, but we know nothing about the STA anyway. + */ + iwl_mvm_rs_rate_init_all_links(mvm, vif, sta); + return 0; } -- cgit v1.2.3 From ebe8f41319fabee020736220942d79c1644bea85 Mon Sep 17 00:00:00 2001 From: Miri Korenblit Date: Sun, 28 Jan 2024 08:53:59 +0200 Subject: wifi: iwlwifi: implement GLAI ACPI table loading All the regulatory tables from BIOS are going to be loaded (preferably) from the UEFI instead of the ACPI. There is a security issue with the fact that anyone can add these UEFI variables. The solution for that is to have a lock for all WIFI GUID UEFI variables, and only if the UEFI variables are locked then we can read it. The status of the lock (unlocked, locked, test mode) is indicated in a ACPI table: Guid Lock ACPI Indicator. Load this table so the driver knows whether to read from UEFI or not Signed-off-by: Miri Korenblit Reviewed-by: Gregory Greenman Link: https://msgid.link/20240128084842.53994809fbdd.I1bd10aafc387bc04f375e386861ee2bcb82f0a61@changeid Signed-off-by: Johannes Berg --- drivers/net/wireless/intel/iwlwifi/fw/acpi.c | 35 +++++++++++++++++++++++++ drivers/net/wireless/intel/iwlwifi/fw/acpi.h | 13 ++++++++- drivers/net/wireless/intel/iwlwifi/fw/runtime.h | 4 +++ drivers/net/wireless/intel/iwlwifi/mvm/fw.c | 2 ++ 4 files changed, 53 insertions(+), 1 deletion(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/intel/iwlwifi/fw/acpi.c b/drivers/net/wireless/intel/iwlwifi/fw/acpi.c index 72a0a9565371..dd68d382d7de 100644 --- a/drivers/net/wireless/intel/iwlwifi/fw/acpi.c +++ b/drivers/net/wireless/intel/iwlwifi/fw/acpi.c @@ -1318,3 +1318,38 @@ out_free: kfree(data); } IWL_EXPORT_SYMBOL(iwl_acpi_get_phy_filters); + +void iwl_acpi_get_guid_lock_status(struct iwl_fw_runtime *fwrt) +{ + union acpi_object *wifi_pkg, *data; + int tbl_rev; + + data = iwl_acpi_get_object(fwrt->dev, ACPI_GLAI_METHOD); + if (IS_ERR(data)) + return; + + wifi_pkg = iwl_acpi_get_wifi_pkg(fwrt->dev, data, + ACPI_GLAI_WIFI_DATA_SIZE, + &tbl_rev); + if (IS_ERR(wifi_pkg)) + goto out_free; + + if (tbl_rev != 0) { + IWL_DEBUG_RADIO(fwrt, "Invalid GLAI revision: %d\n", tbl_rev); + goto out_free; + } + + if (wifi_pkg->package.elements[1].type != ACPI_TYPE_INTEGER || + wifi_pkg->package.elements[1].integer.value > ACPI_GLAI_MAX_STATUS) + goto out_free; + + fwrt->uefi_tables_lock_status = + wifi_pkg->package.elements[1].integer.value; + + IWL_DEBUG_RADIO(fwrt, + "Loaded UEFI WIFI GUID lock status: %d from ACPI\n", + fwrt->uefi_tables_lock_status); +out_free: + kfree(data); +} +IWL_EXPORT_SYMBOL(iwl_acpi_get_guid_lock_status); diff --git a/drivers/net/wireless/intel/iwlwifi/fw/acpi.h b/drivers/net/wireless/intel/iwlwifi/fw/acpi.h index 39106ccb4b9b..7b3c6fca7591 100644 --- a/drivers/net/wireless/intel/iwlwifi/fw/acpi.h +++ b/drivers/net/wireless/intel/iwlwifi/fw/acpi.h @@ -25,6 +25,7 @@ #define ACPI_PPAG_METHOD "PPAG" #define ACPI_WTAS_METHOD "WTAS" #define ACPI_WPFC_METHOD "WPFC" +#define ACPI_GLAI_METHOD "GLAI" #define ACPI_WIFI_DOMAIN (0x07) @@ -66,7 +67,12 @@ #define ACPI_WRDD_WIFI_DATA_SIZE 2 #define ACPI_SPLC_WIFI_DATA_SIZE 2 #define ACPI_ECKV_WIFI_DATA_SIZE 2 - +/* + * One element for domain type, + * and one for the status + */ +#define ACPI_GLAI_WIFI_DATA_SIZE 2 +#define ACPI_GLAI_MAX_STATUS 2 /* * TAS size: 1 elelment for type, * 1 element for enabled field, @@ -237,6 +243,8 @@ bool iwl_acpi_is_ppag_approved(struct iwl_fw_runtime *fwrt); void iwl_acpi_get_phy_filters(struct iwl_fw_runtime *fwrt, struct iwl_phy_specific_cfg *filters); +void iwl_acpi_get_guid_lock_status(struct iwl_fw_runtime *fwrt); + #else /* CONFIG_ACPI */ static inline void *iwl_acpi_get_dsm_object(struct device *dev, int rev, @@ -331,6 +339,9 @@ static inline void iwl_acpi_get_phy_filters(struct iwl_fw_runtime *fwrt, { } +static inline void iwl_acpi_get_guid_lock_status(struct iwl_fw_runtime *fwrt) +{ +} #endif /* CONFIG_ACPI */ #endif /* __iwl_fw_acpi__ */ diff --git a/drivers/net/wireless/intel/iwlwifi/fw/runtime.h b/drivers/net/wireless/intel/iwlwifi/fw/runtime.h index 357727774db9..1ec2bcdf92b8 100644 --- a/drivers/net/wireless/intel/iwlwifi/fw/runtime.h +++ b/drivers/net/wireless/intel/iwlwifi/fw/runtime.h @@ -100,6 +100,9 @@ struct iwl_txf_iter_data { * @dump: debug dump data * @uats_enabled: VLP or AFC AP is enabled * @uats_table: AP type table + * @uefi_tables_lock_status: The status of the WIFI GUID UEFI variables lock: + * 0: Unlocked, 1 and 2: Locked. + * Only read the UEFI variables if locked. */ struct iwl_fw_runtime { struct iwl_trans *trans; @@ -175,6 +178,7 @@ struct iwl_fw_runtime { u8 reduced_power_flags; bool uats_enabled; struct iwl_uats_table_cmd uats_table; + u8 uefi_tables_lock_status; #endif }; diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/fw.c b/drivers/net/wireless/intel/iwlwifi/mvm/fw.c index 175024170357..a6db290923cd 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/fw.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/fw.c @@ -1402,6 +1402,8 @@ void iwl_mvm_get_acpi_tables(struct iwl_mvm *mvm) { int ret; + iwl_acpi_get_guid_lock_status(&mvm->fwrt); + /* read PPAG table */ ret = iwl_acpi_get_ppag_table(&mvm->fwrt); if (ret < 0) { -- cgit v1.2.3 From a6dfe1e74403082e43b1f5ed49c0044eeb93da6c Mon Sep 17 00:00:00 2001 From: Miri Korenblit Date: Sun, 28 Jan 2024 08:54:00 +0200 Subject: wifi: iwlwifi: cleanup uefi variables loading Extract the logic that is common to all variables loading to a function. Signed-off-by: Miri Korenblit Reviewed-by: Gregory Greenman Link: https://msgid.link/20240128084842.454f32c4bcfe.I4835fe657475ac28ef6aef4d292fac63c6ce9a34@changeid Signed-off-by: Johannes Berg --- drivers/net/wireless/intel/iwlwifi/fw/uefi.c | 128 +++++++++++---------------- 1 file changed, 51 insertions(+), 77 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/intel/iwlwifi/fw/uefi.c b/drivers/net/wireless/intel/iwlwifi/fw/uefi.c index 2964c5fb11e9..9c432d7b3674 100644 --- a/drivers/net/wireless/intel/iwlwifi/fw/uefi.c +++ b/drivers/net/wireless/intel/iwlwifi/fw/uefi.c @@ -76,6 +76,42 @@ void *iwl_uefi_get_pnvm(struct iwl_trans *trans, size_t *len) return data; } +static +void *iwl_uefi_get_verified_variable(struct iwl_trans *trans, + efi_char16_t *uefi_var_name, + char *var_name, + unsigned int expected_size, + unsigned long *size) +{ + void *var; + unsigned long var_size; + + var = iwl_uefi_get_variable(uefi_var_name, &IWL_EFI_VAR_GUID, + &var_size); + + if (IS_ERR(var)) { + IWL_DEBUG_RADIO(trans, + "%s UEFI variable not found 0x%lx\n", var_name, + PTR_ERR(var)); + return var; + } + + if (var_size < expected_size) { + IWL_DEBUG_RADIO(trans, + "Invalid %s UEFI variable len (%lu)\n", + var_name, var_size); + kfree(var); + return ERR_PTR(-EINVAL); + } + + IWL_DEBUG_RADIO(trans, "%s from UEFI with size %lu\n", var_name, + var_size); + + if (size) + *size = var_size; + return var; +} + int iwl_uefi_handle_tlv_mem_desc(struct iwl_trans *trans, const u8 *data, u32 tlv_len, struct iwl_pnvm_image *pnvm_data) { @@ -230,26 +266,13 @@ u8 *iwl_uefi_get_reduced_power(struct iwl_trans *trans, size_t *len) unsigned long package_size; u8 *data; - package = iwl_uefi_get_variable(IWL_UEFI_REDUCED_POWER_NAME, - &IWL_EFI_VAR_GUID, &package_size); - - if (IS_ERR(package)) { - IWL_DEBUG_FW(trans, - "Reduced Power UEFI variable not found 0x%lx (len %lu)\n", - PTR_ERR(package), package_size); + package = iwl_uefi_get_verified_variable(trans, + IWL_UEFI_REDUCED_POWER_NAME, + "Reduced Power", + sizeof(*package), + &package_size); + if (IS_ERR(package)) return ERR_CAST(package); - } - - if (package_size < sizeof(*package)) { - IWL_DEBUG_FW(trans, - "Invalid Reduced Power UEFI variable len (%lu)\n", - package_size); - kfree(package); - return ERR_PTR(-EINVAL); - } - - IWL_DEBUG_FW(trans, "Read reduced power from UEFI with size %lu\n", - package_size); IWL_DEBUG_FW(trans, "rev %d, total_size %d, n_skus %d\n", package->rev, package->total_size, package->n_skus); @@ -283,32 +306,15 @@ static int iwl_uefi_step_parse(struct uefi_cnv_common_step_data *common_step_dat void iwl_uefi_get_step_table(struct iwl_trans *trans) { struct uefi_cnv_common_step_data *data; - unsigned long package_size; int ret; if (trans->trans_cfg->device_family < IWL_DEVICE_FAMILY_AX210) return; - data = iwl_uefi_get_variable(IWL_UEFI_STEP_NAME, &IWL_EFI_VAR_GUID, - &package_size); - - if (IS_ERR(data)) { - IWL_DEBUG_FW(trans, - "STEP UEFI variable not found 0x%lx\n", - PTR_ERR(data)); - return; - } - - if (package_size < sizeof(*data)) { - IWL_DEBUG_FW(trans, - "Invalid STEP table UEFI variable len (%lu)\n", - package_size); - kfree(data); + data = iwl_uefi_get_verified_variable(trans, IWL_UEFI_STEP_NAME, + "STEP", sizeof(*data), NULL); + if (IS_ERR(data)) return; - } - - IWL_DEBUG_FW(trans, "Read STEP from UEFI with size %lu\n", - package_size); ret = iwl_uefi_step_parse(data, trans); if (ret < 0) @@ -355,31 +361,15 @@ void iwl_uefi_get_sgom_table(struct iwl_trans *trans, struct iwl_fw_runtime *fwrt) { struct uefi_cnv_wlan_sgom_data *data; - unsigned long package_size; int ret; if (!fwrt->geo_enabled) return; - data = iwl_uefi_get_variable(IWL_UEFI_SGOM_NAME, &IWL_EFI_VAR_GUID, - &package_size); - if (IS_ERR(data)) { - IWL_DEBUG_FW(trans, - "SGOM UEFI variable not found 0x%lx\n", - PTR_ERR(data)); + data = iwl_uefi_get_verified_variable(trans, IWL_UEFI_SGOM_NAME, + "SGOM", sizeof(*data), NULL); + if (IS_ERR(data)) return; - } - - if (package_size < sizeof(*data)) { - IWL_DEBUG_FW(trans, - "Invalid SGOM table UEFI variable len (%lu)\n", - package_size); - kfree(data); - return; - } - - IWL_DEBUG_FW(trans, "Read SGOM from UEFI with size %lu\n", - package_size); ret = iwl_uefi_sgom_parse(data, fwrt); if (ret < 0) @@ -404,28 +394,12 @@ int iwl_uefi_get_uats_table(struct iwl_trans *trans, struct iwl_fw_runtime *fwrt) { struct uefi_cnv_wlan_uats_data *data; - unsigned long package_size; int ret; - data = iwl_uefi_get_variable(IWL_UEFI_UATS_NAME, &IWL_EFI_VAR_GUID, - &package_size); - if (IS_ERR(data)) { - IWL_DEBUG_FW(trans, - "UATS UEFI variable not found 0x%lx\n", - PTR_ERR(data)); + data = iwl_uefi_get_verified_variable(trans, IWL_UEFI_UATS_NAME, + "UATS", sizeof(*data), NULL); + if (IS_ERR(data)) return -EINVAL; - } - - if (package_size < sizeof(*data)) { - IWL_DEBUG_FW(trans, - "Invalid UATS table UEFI variable len (%lu)\n", - package_size); - kfree(data); - return -EINVAL; - } - - IWL_DEBUG_FW(trans, "Read UATS from UEFI with size %lu\n", - package_size); ret = iwl_uefi_uats_parse(data, fwrt); if (ret < 0) { -- cgit v1.2.3 From c8d8f3911135921ace8e939ea0956b55f74bf8a0 Mon Sep 17 00:00:00 2001 From: Miri Korenblit Date: Mon, 29 Jan 2024 21:21:49 +0200 Subject: wifi: iwlwifi: fix EWRD table validity check EWRD ACPI table contains up to 3 additional sar profiles. According to the BIOS spec, the table contains a n_profile variable indicating how many additional profiles exist in the table. Currently we check that n_profiles is not <= 0. But according to the BIOS spec, 0 is a valid value, and it can't be < 0 anyway because we receive that from ACPI as an unsigned integer. Fixes: 39c1a9728f93 ("iwlwifi: refactor the SAR tables from mvm to acpi") Signed-off-by: Miri Korenblit Reviewed-by: Gregory Greenman Link: https://msgid.link/20240129211905.448ea2f40814.Iffd2aadf8e8693e6cb599bee0406a800a0c1e081@changeid Signed-off-by: Johannes Berg --- drivers/net/wireless/intel/iwlwifi/fw/acpi.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/intel/iwlwifi/fw/acpi.c b/drivers/net/wireless/intel/iwlwifi/fw/acpi.c index dd68d382d7de..9be91e6a9882 100644 --- a/drivers/net/wireless/intel/iwlwifi/fw/acpi.c +++ b/drivers/net/wireless/intel/iwlwifi/fw/acpi.c @@ -767,7 +767,7 @@ read_table: * from index 1, so the maximum value allowed here is * ACPI_SAR_PROFILES_NUM - 1. */ - if (n_profiles <= 0 || n_profiles >= ACPI_SAR_PROFILE_NUM) { + if (n_profiles >= ACPI_SAR_PROFILE_NUM) { ret = -EINVAL; goto out_free; } -- cgit v1.2.3 From 8001849921028775eafb5263feadf49e821e9ecf Mon Sep 17 00:00:00 2001 From: Ayala Beker Date: Mon, 29 Jan 2024 21:21:50 +0200 Subject: wifi: iwlwifi: mvm: add support for TID to link mapping neg request Add support for handling TID to link mapping negotiation request and decide whether to accept it or not. Accept the request if all TIDs are mapped to the same link set, otherwise reject it. Signed-off-by: Ayala Beker Reviewed-by: Johannes Berg Reviewed-by: Gregory Greenman Signed-off-by: Miri Korenblit Link: https://msgid.link/20240129211905.aab9819c378d.Icf6b79a362763e2e8b85959471f303b586617242@changeid Signed-off-by: Johannes Berg --- drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c | 5 +++++ drivers/net/wireless/intel/iwlwifi/mvm/mld-mac80211.c | 19 +++++++++++++++++++ 2 files changed, 24 insertions(+) (limited to 'drivers/net') diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c b/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c index 40b8f5a5ccf1..fa8d14421999 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c @@ -263,6 +263,9 @@ static const u8 tm_if_types_ext_capa_sta[] = { __bf_shf(IEEE80211_EML_CAP_EMLSR_PADDING_DELAY) | \ IEEE80211_EML_CAP_EMLSR_TRANSITION_DELAY_64US << \ __bf_shf(IEEE80211_EML_CAP_EMLSR_TRANSITION_DELAY)) +#define IWL_MVM_MLD_CAPA_OPS FIELD_PREP_CONST( \ + IEEE80211_MLD_CAP_OP_TID_TO_LINK_MAP_NEG_SUPP, \ + IEEE80211_MLD_CAP_OP_TID_TO_LINK_MAP_NEG_SUPP_SAME) static const struct wiphy_iftype_ext_capab add_iftypes_ext_capa[] = { { @@ -272,6 +275,7 @@ static const struct wiphy_iftype_ext_capab add_iftypes_ext_capa[] = { .extended_capabilities_len = sizeof(he_if_types_ext_capa_sta), /* relevant only if EHT is supported */ .eml_capabilities = IWL_MVM_EMLSR_CAPA, + .mld_capa_and_ops = IWL_MVM_MLD_CAPA_OPS, }, { .iftype = NL80211_IFTYPE_STATION, @@ -280,6 +284,7 @@ static const struct wiphy_iftype_ext_capab add_iftypes_ext_capa[] = { .extended_capabilities_len = sizeof(tm_if_types_ext_capa_sta), /* relevant only if EHT is supported */ .eml_capabilities = IWL_MVM_EMLSR_CAPA, + .mld_capa_and_ops = IWL_MVM_MLD_CAPA_OPS, }, }; diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/mld-mac80211.c b/drivers/net/wireless/intel/iwlwifi/mvm/mld-mac80211.c index 2b879eeecc8c..5bac39b75e6c 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/mld-mac80211.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/mld-mac80211.c @@ -1329,6 +1329,24 @@ unlock: return ret; } +static enum ieee80211_neg_ttlm_res +iwl_mvm_mld_can_neg_ttlm(struct ieee80211_hw *hw, struct ieee80211_vif *vif, + struct ieee80211_neg_ttlm *neg_ttlm) +{ + u16 map; + u8 i; + + /* Verify all TIDs are mapped to the same links set */ + map = neg_ttlm->downlink[0]; + for (i = 0; i < IEEE80211_TTLM_NUM_TIDS; i++) { + if (neg_ttlm->downlink[i] != neg_ttlm->uplink[i] || + neg_ttlm->uplink[i] != map) + return NEG_TTLM_RES_REJECT; + } + + return NEG_TTLM_RES_ACCEPT; +} + const struct ieee80211_ops iwl_mvm_mld_hw_ops = { .tx = iwl_mvm_mac_tx, .wake_tx_queue = iwl_mvm_mac_wake_tx_queue, @@ -1424,4 +1442,5 @@ const struct ieee80211_ops iwl_mvm_mld_hw_ops = { .change_vif_links = iwl_mvm_mld_change_vif_links, .change_sta_links = iwl_mvm_mld_change_sta_links, .can_activate_links = iwl_mvm_mld_can_activate_links, + .can_neg_ttlm = iwl_mvm_mld_can_neg_ttlm, }; -- cgit v1.2.3 From 0c769cb6b9f364423c255f117774c9ecd5bf23ea Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Mon, 29 Jan 2024 21:21:51 +0200 Subject: wifi: iwlwifi: mvm: d3: fix IPN byte order The IPN is reported by the firmware in 6 bytes little endian, but mac80211 expects big endian so it can do memcmp() on it. We used to store this as a u64 which was filled in the right way, but never used. When implementing that it's used, we changed it to just be 6 bytes, but lost the conversion. Add it back. Fixes: 04f78e242fff ("wifi: iwlwifi: mvm: Add support for IGTK in D3 resume flow") Signed-off-by: Johannes Berg Reviewed-by: Gregory Greenman Signed-off-by: Miri Korenblit Link: https://msgid.link/20240129211905.138ed8a698e3.I1b66c386e45b5392696424ec636474bff86fd5ef@changeid Signed-off-by: Johannes Berg --- drivers/net/wireless/intel/iwlwifi/mvm/d3.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/d3.c b/drivers/net/wireless/intel/iwlwifi/mvm/d3.c index 61aeb7f6604b..6ab9def2c670 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/d3.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/d3.c @@ -2194,7 +2194,10 @@ static void iwl_mvm_convert_gtk_v3(struct iwl_wowlan_status_data *status, static void iwl_mvm_convert_igtk(struct iwl_wowlan_status_data *status, struct iwl_wowlan_igtk_status *data) { + int i; + BUILD_BUG_ON(sizeof(status->igtk.key) < sizeof(data->key)); + BUILD_BUG_ON(sizeof(status->igtk.ipn) != sizeof(data->ipn)); if (!data->key_len) return; @@ -2206,7 +2209,10 @@ static void iwl_mvm_convert_igtk(struct iwl_wowlan_status_data *status, + WOWLAN_IGTK_MIN_INDEX; memcpy(status->igtk.key, data->key, sizeof(data->key)); - memcpy(status->igtk.ipn, data->ipn, sizeof(data->ipn)); + + /* mac80211 expects big endian for memcmp() to work, convert */ + for (i = 0; i < sizeof(data->ipn); i++) + status->igtk.ipn[i] = data->ipn[sizeof(data->ipn) - i - 1]; } static void iwl_mvm_convert_bigtk(struct iwl_wowlan_status_data *status, -- cgit v1.2.3 From 64a06679e680d163d91b4642227244184c29ca02 Mon Sep 17 00:00:00 2001 From: Colin Ian King Date: Mon, 29 Jan 2024 21:21:52 +0200 Subject: wifi: iwlwifi: Fix spelling mistake "SESION" -> "SESSION" There is a spelling mistake in a WARN message. Fix it. Signed-off-by: Colin Ian King Reviewed-by: Gregory Greenman Signed-off-by: Miri Korenblit Link: https://msgid.link/20240129211905.ff31e9385d29.I3a224e6a9294fdec431919fb4ec9315801e77454@changeid Signed-off-by: Johannes Berg --- drivers/net/wireless/intel/iwlwifi/mvm/time-event.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/time-event.c b/drivers/net/wireless/intel/iwlwifi/mvm/time-event.c index aceab96bcb97..703ccdd4d967 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/time-event.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/time-event.c @@ -929,7 +929,7 @@ void iwl_mvm_rx_session_protect_notif(struct iwl_mvm *mvm, if (WARN(ver > 2 && mvmvif->time_event_data.link_id >= 0 && mvmvif->time_event_data.link_id != notif_link_id, - "SESION_PROTECTION_NOTIF was received for link %u, while the current time event is on link %u\n", + "SESSION_PROTECTION_NOTIF was received for link %u, while the current time event is on link %u\n", notif_link_id, mvmvif->time_event_data.link_id)) goto out_unlock; -- cgit v1.2.3 From bc197d3c400f48ce7d9402c968ceeb5680e5b639 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Mon, 29 Jan 2024 21:21:53 +0200 Subject: wifi: iwlwifi: mvm: don't set trigger frame padding in AP mode This field is reserved in AP mode, don't set any bits in it. Signed-off-by: Johannes Berg Reviewed-by: Gregory Greenman Signed-off-by: Miri Korenblit Link: https://msgid.link/20240129211905.f5eeb717212e.I60fa4843a8634922281580b925db2c2699e3a7bc@changeid Signed-off-by: Johannes Berg --- drivers/net/wireless/intel/iwlwifi/iwl-nvm-parse.c | 1 - 1 file changed, 1 deletion(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/intel/iwlwifi/iwl-nvm-parse.c b/drivers/net/wireless/intel/iwlwifi/iwl-nvm-parse.c index a7152d65eefa..0b2b0c320cb0 100644 --- a/drivers/net/wireless/intel/iwlwifi/iwl-nvm-parse.c +++ b/drivers/net/wireless/intel/iwlwifi/iwl-nvm-parse.c @@ -749,7 +749,6 @@ static const struct ieee80211_sband_iftype_data iwl_he_eht_capa[] = { .mac_cap_info[0] = IEEE80211_HE_MAC_CAP0_HTC_HE, .mac_cap_info[1] = - IEEE80211_HE_MAC_CAP1_TF_MAC_PAD_DUR_16US | IEEE80211_HE_MAC_CAP1_MULTI_TID_AGG_RX_QOS_8, .mac_cap_info[3] = IEEE80211_HE_MAC_CAP3_OMI_CONTROL, -- cgit v1.2.3 From f639602a58e7564dd091c7c0793f61042bad9bb6 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Mon, 29 Jan 2024 21:21:54 +0200 Subject: wifi: iwlwifi: always have 'uats_enabled' We check this in code that'd be complicated to put under ifdef (CONFIG_ACPI), so just always have 'uats_enabled'. Fixes: 4a9bb5b4d949 ("wifi: iwlwifi: fw: Add support for UATS table in UHB") Signed-off-by: Johannes Berg Reviewed-by: Mukesh Sisodiya Reviewed-by: Gregory Greenman Signed-off-by: Miri Korenblit Link: https://msgid.link/20240129211905.bdc5fb20f00a.I902d801d79873c5c9cd51cef8e8226e2acefe88d@changeid Signed-off-by: Johannes Berg --- drivers/net/wireless/intel/iwlwifi/fw/runtime.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/intel/iwlwifi/fw/runtime.h b/drivers/net/wireless/intel/iwlwifi/fw/runtime.h index 1ec2bcdf92b8..048830bb09f2 100644 --- a/drivers/net/wireless/intel/iwlwifi/fw/runtime.h +++ b/drivers/net/wireless/intel/iwlwifi/fw/runtime.h @@ -176,10 +176,10 @@ struct iwl_fw_runtime { struct iwl_sar_offset_mapping_cmd sgom_table; bool sgom_enabled; u8 reduced_power_flags; - bool uats_enabled; struct iwl_uats_table_cmd uats_table; u8 uefi_tables_lock_status; #endif + bool uats_enabled; }; void iwl_fw_runtime_init(struct iwl_fw_runtime *fwrt, struct iwl_trans *trans, -- cgit v1.2.3 From 137d33ac476489645e4a67d66d3abf930cecb419 Mon Sep 17 00:00:00 2001 From: Ilan Peer Date: Mon, 29 Jan 2024 21:21:55 +0200 Subject: wifi: iwlwifi: mvm: Fix FTM initiator flags When secure LTF is used MFP must also be set. Signed-off-by: Ilan Peer Reviewed-by: Avraham Stern Reviewed-by: Gregory Greenman Signed-off-by: Miri Korenblit Link: https://msgid.link/20240129211905.6cad71069e87.I7f9fd5239cfd2244f155f88419980e6e91d00ff2@changeid Signed-off-by: Johannes Berg --- drivers/net/wireless/intel/iwlwifi/mvm/ftm-initiator.c | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/ftm-initiator.c b/drivers/net/wireless/intel/iwlwifi/mvm/ftm-initiator.c index 233ae81884a0..4863a3c74640 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/ftm-initiator.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/ftm-initiator.c @@ -1,7 +1,7 @@ // SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause /* * Copyright (C) 2015-2017 Intel Deutschland GmbH - * Copyright (C) 2018-2022 Intel Corporation + * Copyright (C) 2018-2023 Intel Corporation */ #include #include @@ -821,9 +821,10 @@ iwl_mvm_ftm_put_target_v8(struct iwl_mvm *mvm, struct ieee80211_vif *vif, * If secure LTF is turned off, replace the flag with PMF only */ flags = le32_to_cpu(target->initiator_ap_flags); - if ((flags & IWL_INITIATOR_AP_FLAGS_SECURED) && - !IWL_MVM_FTM_INITIATOR_SECURE_LTF) { - flags &= ~IWL_INITIATOR_AP_FLAGS_SECURED; + if (flags & IWL_INITIATOR_AP_FLAGS_SECURED) { + if (!IWL_MVM_FTM_INITIATOR_SECURE_LTF) + flags &= ~IWL_INITIATOR_AP_FLAGS_SECURED; + flags |= IWL_INITIATOR_AP_FLAGS_PMF; target->initiator_ap_flags = cpu_to_le32(flags); } -- cgit v1.2.3 From 51eb17b8d5597250fea513050c26a53f2ff183b2 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Mon, 29 Jan 2024 21:21:57 +0200 Subject: wifi: iwlwifi: remove Gl A-step remnants The IWL_DEVICE_GL_A macro is no longer used, and couldn't be, so remove it. Signed-off-by: Johannes Berg Reviewed-by: Gregory Greenman Signed-off-by: Miri Korenblit Link: https://msgid.link/20240129211905.8929a06c3a55.I3c21305e4b7fa3aba938bc860269e848fe262e88@changeid Signed-off-by: Johannes Berg --- drivers/net/wireless/intel/iwlwifi/cfg/bz.c | 4 ---- 1 file changed, 4 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/intel/iwlwifi/cfg/bz.c b/drivers/net/wireless/intel/iwlwifi/cfg/bz.c index 20799a0fbc07..b0b003a6a46e 100644 --- a/drivers/net/wireless/intel/iwlwifi/cfg/bz.c +++ b/drivers/net/wireless/intel/iwlwifi/cfg/bz.c @@ -129,10 +129,6 @@ static const struct iwl_base_params iwl_bz_base_params = { IWL_DEVICE_BZ_COMMON, \ .ht_params = &iwl_22000_ht_params -#define IWL_DEVICE_GL_A \ - IWL_DEVICE_BZ_COMMON, \ - .ht_params = &iwl_gl_a_ht_params - /* * This size was picked according to 8 MSDUs inside 512 A-MSDUs in an * A-MPDU, with additional overhead to account for processing time. -- cgit v1.2.3 From 3d869feacb74309e4f1cb69572df16ec9862012c Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Mon, 29 Jan 2024 21:21:58 +0200 Subject: wifi: iwlwifi: mvm: use FW rate for non-data only on new devices With MLO connections we need to let the firmware pick the rate as we don't know the link the frame might be transmitted on (in some cases we do know, but we'd rather always use the FW and find bugs.) We _did_ end up finding bugs and fixing them, but older devices likely won't get fixed as we don't have a need for this there, they cannot support MLO. Thus, go back to picking a rate on the host for the relevant frames on older (pre-Bz) devices. Fixes: 499d02790495 ("wifi: iwlwifi: Use FW rate for non-data frames") Signed-off-by: Johannes Berg Signed-off-by: Miri Korenblit Link: https://msgid.link/20240129211905.e59056d0a8cc.Iccc4c5c1753921d3d85241ede812a150fb05b898@changeid Signed-off-by: Johannes Berg --- drivers/net/wireless/intel/iwlwifi/mvm/tx.c | 33 +++++++++++++++++++++++++---- 1 file changed, 29 insertions(+), 4 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/tx.c b/drivers/net/wireless/intel/iwlwifi/mvm/tx.c index db986bfc4dc3..79eb6394e5a7 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/tx.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/tx.c @@ -520,6 +520,31 @@ static void iwl_mvm_set_tx_cmd_crypto(struct iwl_mvm *mvm, } } +static bool iwl_mvm_use_host_rate(struct iwl_mvm *mvm, + struct iwl_mvm_sta *mvmsta, + struct ieee80211_hdr *hdr, + struct ieee80211_tx_info *info) +{ + if (unlikely(!mvmsta)) + return true; + + if (unlikely(info->control.flags & IEEE80211_TX_CTRL_RATE_INJECT)) + return true; + + if (likely(ieee80211_is_data(hdr->frame_control) && + mvmsta->sta_state >= IEEE80211_STA_AUTHORIZED)) + return false; + + /* + * Not a data frame, use host rate if on an old device that + * can't possibly be doing MLO (firmware may be selecting a + * bad rate), if we might be doing MLO we need to let FW pick + * (since we don't necesarily know the link), but FW rate + * selection was fixed. + */ + return mvm->trans->trans_cfg->device_family < IWL_DEVICE_FAMILY_BZ; +} + /* * Allocates and sets the Tx cmd the driver data pointers in the skb */ @@ -556,12 +581,12 @@ iwl_mvm_set_tx_params(struct iwl_mvm *mvm, struct sk_buff *skb, flags |= IWL_TX_FLAGS_ENCRYPT_DIS; /* - * For data and mgmt packets rate info comes from the fw. Only + * For data and mgmt packets rate info comes from the fw (for + * new devices, older FW is somewhat broken for this). Only * set rate/antenna for injected frames with fixed rate, or - * when no sta is given. + * when no sta is given, or with older firmware. */ - if (unlikely(!sta || - info->control.flags & IEEE80211_TX_CTRL_RATE_INJECT)) { + if (unlikely(iwl_mvm_use_host_rate(mvm, mvmsta, hdr, info))) { flags |= IWL_TX_FLAGS_CMD_RATE; rate_n_flags = iwl_mvm_get_tx_rate_n_flags(mvm, info, sta, -- cgit v1.2.3 From 0fcdf55fced7121c43fa576433986f1c04115b73 Mon Sep 17 00:00:00 2001 From: Emmanuel Grumbach Date: Mon, 29 Jan 2024 21:21:59 +0200 Subject: wifi: iwlwifi: mvm: fix the TLC command after ADD_STA ADD_STA resets the link quality data inside the firmware. This is not supposed to happen and has been fixed for newer devices. For older devices (AX201 and down), this makes us send frames with rates that are not in the TLC table. Fixes: 5a86dcb4a908 ("wifi: iwlwifi: mvm: update station's MFP flag after association") Signed-off-by: Emmanuel Grumbach Reviewed-by: Johannes Berg Signed-off-by: Miri Korenblit Link: https://msgid.link/20240129211905.1deca7eaff14.I597abd7aab36fdab4aa8311a48c98a3d5bd433ba@changeid Signed-off-by: Johannes Berg --- drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c b/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c index fa8d14421999..36a5932d75a6 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c @@ -3802,13 +3802,17 @@ iwl_mvm_sta_state_assoc_to_authorized(struct iwl_mvm *mvm, mvm_sta->authorized = true; - iwl_mvm_rs_rate_init_all_links(mvm, vif, sta); - /* MFP is set by default before the station is authorized. * Clear it here in case it's not used. */ - if (!sta->mfp) - return callbacks->update_sta(mvm, vif, sta); + if (!sta->mfp) { + int ret = callbacks->update_sta(mvm, vif, sta); + + if (ret) + return ret; + } + + iwl_mvm_rs_rate_init_all_links(mvm, vif, sta); return 0; } -- cgit v1.2.3 From 6770eee75148ba10c0c051885379714773e00b48 Mon Sep 17 00:00:00 2001 From: Mukesh Sisodiya Date: Mon, 29 Jan 2024 21:22:00 +0200 Subject: wifi: iwlwifi: pcie: Add the PCI device id for new hardware Add the support for a new PCI device id. Signed-off-by: Mukesh Sisodiya Reviewed-by: Gregory Greenman Signed-off-by: Miri Korenblit Link: https://msgid.link/20240129211905.fde32107e0a3.I597cff4f340e4bed12b7568a0ad504bd4b2c1cf8@changeid Signed-off-by: Johannes Berg --- drivers/net/wireless/intel/iwlwifi/pcie/drv.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers/net') diff --git a/drivers/net/wireless/intel/iwlwifi/pcie/drv.c b/drivers/net/wireless/intel/iwlwifi/pcie/drv.c index c80b02503b41..bbc8dc390bdc 100644 --- a/drivers/net/wireless/intel/iwlwifi/pcie/drv.c +++ b/drivers/net/wireless/intel/iwlwifi/pcie/drv.c @@ -502,6 +502,7 @@ static const struct pci_device_id iwl_hw_card_ids[] = { /* Bz devices */ {IWL_PCI_DEVICE(0x2727, PCI_ANY_ID, iwl_bz_trans_cfg)}, + {IWL_PCI_DEVICE(0x272D, PCI_ANY_ID, iwl_bz_trans_cfg)}, {IWL_PCI_DEVICE(0x272b, PCI_ANY_ID, iwl_bz_trans_cfg)}, {IWL_PCI_DEVICE(0xA840, PCI_ANY_ID, iwl_bz_trans_cfg)}, {IWL_PCI_DEVICE(0x7740, PCI_ANY_ID, iwl_bz_trans_cfg)}, -- cgit v1.2.3 From c289f5cd6978af1bd14c1b7c230aaa011e1b3b5d Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Mon, 29 Jan 2024 21:22:01 +0200 Subject: wifi: iwlwifi: mvm: support SPP A-MSDUs If the firmware has the necessary support, enable SPP A-MSDUs. Signed-off-by: Johannes Berg Signed-off-by: Daniel Gabay Reviewed-by: Gregory Greenman Signed-off-by: Miri Korenblit Link: https://msgid.link/20240129211905.15e4570e471f.I87cf284d3b19bb9f5558f0f33afaace6d6492acb@changeid Signed-off-by: Johannes Berg --- drivers/net/wireless/intel/iwlwifi/fw/api/sta.h | 4 +++- drivers/net/wireless/intel/iwlwifi/fw/file.h | 3 +++ drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c | 5 +++++ drivers/net/wireless/intel/iwlwifi/mvm/mld-key.c | 3 +++ drivers/net/wireless/intel/iwlwifi/mvm/sta.c | 3 +++ 5 files changed, 17 insertions(+), 1 deletion(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/intel/iwlwifi/fw/api/sta.h b/drivers/net/wireless/intel/iwlwifi/fw/api/sta.h index d62fed543276..d7f8a276b683 100644 --- a/drivers/net/wireless/intel/iwlwifi/fw/api/sta.h +++ b/drivers/net/wireless/intel/iwlwifi/fw/api/sta.h @@ -1,6 +1,6 @@ /* SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause */ /* - * Copyright (C) 2012-2014, 2018-2021 Intel Corporation + * Copyright (C) 2012-2014, 2018-2021, 2023 Intel Corporation * Copyright (C) 2013-2014 Intel Mobile Communications GmbH * Copyright (C) 2016-2017 Intel Deutschland GmbH */ @@ -109,6 +109,7 @@ enum iwl_sta_flags { * @STA_KEY_FLG_EN_MSK: mask for encryption algorithmi value * @STA_KEY_FLG_WEP_KEY_MAP: wep is either a group key (0 - legacy WEP) or from * station info array (1 - n 1X mode) + * @STA_KEY_FLG_AMSDU_SPP: SPP (signaling and payload protected) A-MSDU * @STA_KEY_FLG_KEYID_MSK: the index of the key * @STA_KEY_FLG_KEYID_POS: key index bit position * @STA_KEY_NOT_VALID: key is invalid @@ -129,6 +130,7 @@ enum iwl_sta_key_flag { STA_KEY_FLG_EN_MSK = (7 << 0), STA_KEY_FLG_WEP_KEY_MAP = BIT(3), + STA_KEY_FLG_AMSDU_SPP = BIT(7), STA_KEY_FLG_KEYID_POS = 8, STA_KEY_FLG_KEYID_MSK = (3 << STA_KEY_FLG_KEYID_POS), STA_KEY_NOT_VALID = BIT(11), diff --git a/drivers/net/wireless/intel/iwlwifi/fw/file.h b/drivers/net/wireless/intel/iwlwifi/fw/file.h index bfc39bd5bbc6..b216da7d95fc 100644 --- a/drivers/net/wireless/intel/iwlwifi/fw/file.h +++ b/drivers/net/wireless/intel/iwlwifi/fw/file.h @@ -383,6 +383,8 @@ typedef unsigned int __bitwise iwl_ucode_tlv_capa_t; * channels even when these are not enabled. * @IWL_UCODE_TLV_CAPA_DUMP_COMPLETE_SUPPORT: Support for indicating dump collection * complete to FW. + * @IWL_UCODE_TLV_CAPA_SPP_AMSDU_SUPPORT: Support SPP (signaling and payload + * protected) A-MSDU. * * @NUM_IWL_UCODE_TLV_CAPA: number of bits used */ @@ -468,6 +470,7 @@ enum iwl_ucode_tlv_capa { IWL_UCODE_TLV_CAPA_PSC_CHAN_SUPPORT = (__force iwl_ucode_tlv_capa_t)98, IWL_UCODE_TLV_CAPA_BIGTK_SUPPORT = (__force iwl_ucode_tlv_capa_t)100, + IWL_UCODE_TLV_CAPA_SPP_AMSDU_SUPPORT = (__force iwl_ucode_tlv_capa_t)103, IWL_UCODE_TLV_CAPA_DRAM_FRAG_SUPPORT = (__force iwl_ucode_tlv_capa_t)104, IWL_UCODE_TLV_CAPA_DUMP_COMPLETE_SUPPORT = (__force iwl_ucode_tlv_capa_t)105, IWL_UCODE_TLV_CAPA_SYNCED_TIME = (__force iwl_ucode_tlv_capa_t)106, diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c b/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c index 36a5932d75a6..0cee752584d9 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c @@ -495,6 +495,11 @@ int iwl_mvm_mac_setup_register(struct iwl_mvm *mvm) IWL_UCODE_TLV_CAPA_TIME_SYNC_BOTH_FTM_TM)) hw->wiphy->hw_timestamp_max_peers = 1; + if (fw_has_capa(&mvm->fw->ucode_capa, + IWL_UCODE_TLV_CAPA_SPP_AMSDU_SUPPORT)) + wiphy_ext_feature_set(hw->wiphy, + NL80211_EXT_FEATURE_SPP_AMSDU_SUPPORT); + ieee80211_hw_set(hw, SINGLE_SCAN_ON_ALL_BANDS); hw->wiphy->features |= NL80211_FEATURE_SCHED_SCAN_RANDOM_MAC_ADDR | diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/mld-key.c b/drivers/net/wireless/intel/iwlwifi/mvm/mld-key.c index a1ce08a5527c..bbd37a95d4c8 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/mld-key.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/mld-key.c @@ -104,6 +104,9 @@ u32 iwl_mvm_get_sec_flags(struct iwl_mvm *mvm, (keyconf->keyidx == 4 || keyconf->keyidx == 5))) flags |= IWL_SEC_KEY_FLAG_MFP; + if (keyconf->flags & IEEE80211_KEY_FLAG_SPP_AMSDU) + flags |= IWL_SEC_KEY_FLAG_SPP_AMSDU; + return flags; } diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/sta.c b/drivers/net/wireless/intel/iwlwifi/mvm/sta.c index d57fcbe4f8ac..8ffbb8efda73 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/sta.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/sta.c @@ -3559,6 +3559,9 @@ static int iwl_mvm_send_sta_key(struct iwl_mvm *mvm, key_flags = cpu_to_le16(keyidx); key_flags |= cpu_to_le16(STA_KEY_FLG_WEP_KEY_MAP); + if (key->flags & IEEE80211_KEY_FLAG_SPP_AMSDU) + key_flags |= cpu_to_le16(STA_KEY_FLG_AMSDU_SPP); + switch (key->cipher) { case WLAN_CIPHER_SUITE_TKIP: key_flags |= cpu_to_le16(STA_KEY_FLG_TKIP); -- cgit v1.2.3 From 65d3333e4d4f35853aa2991324206e1cb17b81d7 Mon Sep 17 00:00:00 2001 From: Daniel Gabay Date: Mon, 29 Jan 2024 21:22:02 +0200 Subject: wifi: iwlwifi: mvm: log dropped packets due to MIC error When we drop frames due to MIC error we want to have something printed in the logger (this won't be printed by default). Signed-off-by: Daniel Gabay Reviewed-by: Gregory Greenman Signed-off-by: Miri Korenblit Link: https://msgid.link/20240129211905.41b0abbf1fd2.Ib6ec6a48ec7bebe769d1e1c1df96380a758a0975@changeid Signed-off-by: Johannes Berg --- drivers/net/wireless/intel/iwlwifi/mvm/rxmq.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/rxmq.c b/drivers/net/wireless/intel/iwlwifi/mvm/rxmq.c index 451af501c7a1..67062fe40152 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/rxmq.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/rxmq.c @@ -401,8 +401,11 @@ static int iwl_mvm_rx_crypto(struct iwl_mvm *mvm, struct ieee80211_sta *sta, case IWL_RX_MPDU_STATUS_SEC_GCM: BUILD_BUG_ON(IEEE80211_CCMP_PN_LEN != IEEE80211_GCMP_PN_LEN); /* alg is CCM: check MIC only */ - if (!(status & IWL_RX_MPDU_STATUS_MIC_OK)) + if (!(status & IWL_RX_MPDU_STATUS_MIC_OK)) { + IWL_DEBUG_DROP(mvm, + "Dropping packet, bad MIC (CCM/GCM)\n"); return -1; + } stats->flag |= RX_FLAG_DECRYPTED | RX_FLAG_MIC_STRIPPED; *crypt_len = IEEE80211_CCMP_HDR_LEN; -- cgit v1.2.3 From ce1fa3adc007ce3fd6beb8f4d733e00daa64c6c0 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Mon, 29 Jan 2024 21:22:03 +0200 Subject: wifi: iwlwifi: mvm: refactor duplicate chanctx condition Refactor the check for using a chanctx's def vs. min_def, to have the same in both places and reuse it later. Signed-off-by: Johannes Berg Signed-off-by: Miri Korenblit Link: https://msgid.link/20240129211905.6fcde4051adf.I343934874612d21727ed167accaa967958b2c25b@changeid Signed-off-by: Johannes Berg --- drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c | 12 ++++-------- drivers/net/wireless/intel/iwlwifi/mvm/mvm.h | 13 +++++++++++++ 2 files changed, 17 insertions(+), 8 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c b/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c index 0cee752584d9..4bc25d4a87b6 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c @@ -4808,8 +4808,8 @@ static void iwl_mvm_ftm_responder_chanctx_iter(void *_data, u8 *mac, data->responder = true; } -static bool iwl_mvm_is_ftm_responder_chanctx(struct iwl_mvm *mvm, - struct ieee80211_chanctx_conf *ctx) +bool iwl_mvm_is_ftm_responder_chanctx(struct iwl_mvm *mvm, + struct ieee80211_chanctx_conf *ctx) { struct iwl_mvm_ftm_responder_iter_data data = { .responder = false, @@ -4828,9 +4828,7 @@ static int __iwl_mvm_add_chanctx(struct iwl_mvm *mvm, { u16 *phy_ctxt_id = (u16 *)ctx->drv_priv; struct iwl_mvm_phy_ctxt *phy_ctxt; - bool use_def = iwl_mvm_is_ftm_responder_chanctx(mvm, ctx) || - iwl_mvm_enable_fils(mvm, ctx); - struct cfg80211_chan_def *def = use_def ? &ctx->def : &ctx->min_def; + struct cfg80211_chan_def *def = iwl_mvm_chanctx_def(mvm, ctx); int ret; lockdep_assert_held(&mvm->mutex); @@ -4896,9 +4894,7 @@ void iwl_mvm_change_chanctx(struct ieee80211_hw *hw, struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw); u16 *phy_ctxt_id = (u16 *)ctx->drv_priv; struct iwl_mvm_phy_ctxt *phy_ctxt = &mvm->phy_ctxts[*phy_ctxt_id]; - bool use_def = iwl_mvm_is_ftm_responder_chanctx(mvm, ctx) || - iwl_mvm_enable_fils(mvm, ctx); - struct cfg80211_chan_def *def = use_def ? &ctx->def : &ctx->min_def; + struct cfg80211_chan_def *def = iwl_mvm_chanctx_def(mvm, ctx); if (WARN_ONCE((phy_ctxt->ref > 1) && (changed & ~(IEEE80211_CHANCTX_CHANGE_WIDTH | diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h b/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h index e148ef02ff73..d414007c4755 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h +++ b/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h @@ -2752,4 +2752,17 @@ void iwl_mvm_mld_select_links(struct iwl_mvm *mvm, struct ieee80211_vif *vif, int iwl_mvm_mld_get_primary_link(struct iwl_mvm *mvm, struct ieee80211_vif *vif, unsigned long usable_links); + +bool iwl_mvm_is_ftm_responder_chanctx(struct iwl_mvm *mvm, + struct ieee80211_chanctx_conf *ctx); + +static inline struct cfg80211_chan_def * +iwl_mvm_chanctx_def(struct iwl_mvm *mvm, struct ieee80211_chanctx_conf *ctx) +{ + bool use_def = iwl_mvm_is_ftm_responder_chanctx(mvm, ctx) || + iwl_mvm_enable_fils(mvm, ctx); + + return use_def ? &ctx->def : &ctx->min_def; +} + #endif /* __IWL_MVM_H__ */ -- cgit v1.2.3 From c868a189ecfe8cc0b3173c2eaa7f0b659326c151 Mon Sep 17 00:00:00 2001 From: Miri Korenblit Date: Wed, 31 Jan 2024 10:24:34 +0200 Subject: wifi: iwlwifi: read BIOS PNVM only for non-Intel SKU The driver is supposed to read the PNVM from BIOS only for non-Intel SKUs. For Intel SKUs the OEM ID will be 0. Read BIOS PNVM only when a non-Intel SKU is indicated. Fixes: b99e32cbfdf6 ("wifi: iwlwifi: Take loading and setting of pnvm image out of parsing part") Signed-off-by: Miri Korenblit Reviewed-by: Gregory Greenman Link: https://msgid.link/20240131091413.3625cf1223d3.Ieffda5f506713b1c979388dd7a0e1c1a0145cfca@changeid Signed-off-by: Johannes Berg --- drivers/net/wireless/intel/iwlwifi/fw/pnvm.c | 30 +++++++++++++++++----------- 1 file changed, 18 insertions(+), 12 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/intel/iwlwifi/fw/pnvm.c b/drivers/net/wireless/intel/iwlwifi/fw/pnvm.c index d467ec0e3552..053174f00e49 100644 --- a/drivers/net/wireless/intel/iwlwifi/fw/pnvm.c +++ b/drivers/net/wireless/intel/iwlwifi/fw/pnvm.c @@ -268,21 +268,27 @@ static u8 *iwl_get_pnvm_image(struct iwl_trans *trans_p, size_t *len) struct pnvm_sku_package *package; u8 *image = NULL; - /* First attempt to get the PNVM from BIOS */ - package = iwl_uefi_get_pnvm(trans_p, len); - if (!IS_ERR_OR_NULL(package)) { - if (*len >= sizeof(*package)) { - /* we need only the data */ - *len -= sizeof(*package); - image = kmemdup(package->data, *len, GFP_KERNEL); + /* Get PNVM from BIOS for non-Intel SKU */ + if (trans_p->sku_id[2]) { + package = iwl_uefi_get_pnvm(trans_p, len); + if (!IS_ERR_OR_NULL(package)) { + if (*len >= sizeof(*package)) { + /* we need only the data */ + *len -= sizeof(*package); + image = kmemdup(package->data, + *len, GFP_KERNEL); + } + /* + * free package regardless of whether kmemdup + * succeeded + */ + kfree(package); + if (image) + return image; } - /* free package regardless of whether kmemdup succeeded */ - kfree(package); - if (image) - return image; } - /* If it's not available, try from the filesystem */ + /* If it's not available, or for Intel SKU, try from the filesystem */ if (iwl_pnvm_get_from_fs(trans_p, &image, len)) return NULL; return image; -- cgit v1.2.3 From 8c9bef26e98b71b18afe8de6212b750c4e9f9ecf Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Wed, 31 Jan 2024 10:24:35 +0200 Subject: wifi: iwlwifi: mvm: d3: implement suspend with MLO When using MLO, we need to have only a single link active when entering suspend and of course most of the code also needs to be adjusted to not use deflink, apart from older code that's not used with MLO-capable firmware. Implement that. Note that the link selection currently prefers the "best" link, which might really not be the best for D3, but that can be fixed later once we agree. Signed-off-by: Johannes Berg Reviewed-by: Gregory Greenman Signed-off-by: Miri Korenblit Link: https://msgid.link/20240131091413.38f0fd4d2db0.I27c7a1d08aecc5da0af2c351212f22e92ed70219@changeid Signed-off-by: Johannes Berg --- drivers/net/wireless/intel/iwlwifi/mvm/d3.c | 79 ++++++++++++++++++++--------- 1 file changed, 54 insertions(+), 25 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/d3.c b/drivers/net/wireless/intel/iwlwifi/mvm/d3.c index 6ab9def2c670..6396fbde03c4 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/d3.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/d3.c @@ -450,9 +450,9 @@ static void iwl_mvm_wowlan_get_rsc_v5_data(struct ieee80211_hw *hw, } static int iwl_mvm_wowlan_config_rsc_tsc(struct iwl_mvm *mvm, - struct ieee80211_vif *vif) + struct ieee80211_vif *vif, + struct iwl_mvm_vif_link_info *mvm_link) { - struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); int ver = iwl_fw_lookup_cmd_ver(mvm->fw, WOWLAN_TSC_RSC_PARAM, IWL_FW_CMD_VER_UNKNOWN); int ret; @@ -470,7 +470,7 @@ static int iwl_mvm_wowlan_config_rsc_tsc(struct iwl_mvm *mvm, for (i = 0; i < ARRAY_SIZE(data.rsc->mcast_key_id_map); i++) data.rsc->mcast_key_id_map[i] = IWL_MCAST_KEY_MAP_INVALID; - data.rsc->sta_id = cpu_to_le32(mvmvif->deflink.ap_sta_id); + data.rsc->sta_id = cpu_to_le32(mvm_link->ap_sta_id); ieee80211_iter_keys(mvm->hw, vif, iwl_mvm_wowlan_get_rsc_v5_data, @@ -494,7 +494,7 @@ static int iwl_mvm_wowlan_config_rsc_tsc(struct iwl_mvm *mvm, if (ver == 4) { size = sizeof(*data.rsc_tsc); data.rsc_tsc->sta_id = - cpu_to_le32(mvmvif->deflink.ap_sta_id); + cpu_to_le32(mvm_link->ap_sta_id); } else { /* ver == 2 || ver == IWL_FW_CMD_VER_UNKNOWN */ size = sizeof(data.rsc_tsc->params); @@ -668,10 +668,9 @@ static int iwl_mvm_send_patterns_v1(struct iwl_mvm *mvm, } static int iwl_mvm_send_patterns(struct iwl_mvm *mvm, - struct ieee80211_vif *vif, + struct iwl_mvm_vif_link_info *mvm_link, struct cfg80211_wowlan *wowlan) { - struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); struct iwl_wowlan_patterns_cmd *pattern_cmd; struct iwl_host_cmd cmd = { .id = WOWLAN_PATTERNS, @@ -693,7 +692,7 @@ static int iwl_mvm_send_patterns(struct iwl_mvm *mvm, pattern_cmd->n_patterns = wowlan->n_patterns; if (ver >= 3) - pattern_cmd->sta_id = mvmvif->deflink.ap_sta_id; + pattern_cmd->sta_id = mvm_link->ap_sta_id; for (i = 0; i < wowlan->n_patterns; i++) { int mask_len = DIV_ROUND_UP(wowlan->patterns[i].pattern_len, 8); @@ -730,7 +729,8 @@ static int iwl_mvm_d3_reprogram(struct iwl_mvm *mvm, struct ieee80211_vif *vif, struct iwl_time_quota_data *quota; u32 status; - if (WARN_ON_ONCE(iwl_mvm_is_cdb_supported(mvm))) + if (WARN_ON_ONCE(iwl_mvm_is_cdb_supported(mvm) || + ieee80211_vif_is_mld(vif))) return -EINVAL; /* add back the PHY */ @@ -987,7 +987,8 @@ iwl_mvm_get_wowlan_config(struct iwl_mvm *mvm, } static int iwl_mvm_wowlan_config_key_params(struct iwl_mvm *mvm, - struct ieee80211_vif *vif) + struct ieee80211_vif *vif, + struct iwl_mvm_vif_link_info *mvm_link) { bool unified = fw_has_capa(&mvm->fw->ucode_capa, IWL_UCODE_TLV_CAPA_CNSLDTD_D3_D0_IMG); @@ -1016,7 +1017,7 @@ static int iwl_mvm_wowlan_config_key_params(struct iwl_mvm *mvm, return -EIO; } - ret = iwl_mvm_wowlan_config_rsc_tsc(mvm, vif); + ret = iwl_mvm_wowlan_config_rsc_tsc(mvm, vif, mvm_link); if (ret) return ret; @@ -1030,7 +1031,7 @@ static int iwl_mvm_wowlan_config_key_params(struct iwl_mvm *mvm, if (ver == 2) { size = sizeof(tkip_data.tkip); tkip_data.tkip.sta_id = - cpu_to_le32(mvmvif->deflink.ap_sta_id); + cpu_to_le32(mvm_link->ap_sta_id); } else if (ver == 1 || ver == IWL_FW_CMD_VER_UNKNOWN) { size = sizeof(struct iwl_wowlan_tkip_params_cmd_ver_1); } else { @@ -1079,7 +1080,7 @@ static int iwl_mvm_wowlan_config_key_params(struct iwl_mvm *mvm, kek_kck_cmd.kek_len = cpu_to_le16(mvmvif->rekey_data.kek_len); kek_kck_cmd.replay_ctr = mvmvif->rekey_data.replay_ctr; kek_kck_cmd.akm = cpu_to_le32(mvmvif->rekey_data.akm); - kek_kck_cmd.sta_id = cpu_to_le32(mvmvif->deflink.ap_sta_id); + kek_kck_cmd.sta_id = cpu_to_le32(mvm_link->ap_sta_id); if (cmd_ver == 4) { cmd_size = sizeof(struct iwl_wowlan_kek_kck_material_cmd_v4); @@ -1112,6 +1113,7 @@ iwl_mvm_wowlan_config(struct iwl_mvm *mvm, struct cfg80211_wowlan *wowlan, struct iwl_wowlan_config_cmd *wowlan_config_cmd, struct ieee80211_vif *vif, struct iwl_mvm_vif *mvmvif, + struct iwl_mvm_vif_link_info *mvm_link, struct ieee80211_sta *ap_sta) { int ret; @@ -1130,7 +1132,7 @@ iwl_mvm_wowlan_config(struct iwl_mvm *mvm, return ret; } - ret = iwl_mvm_wowlan_config_key_params(mvm, vif); + ret = iwl_mvm_wowlan_config_key_params(mvm, vif, mvm_link); if (ret) return ret; @@ -1142,7 +1144,7 @@ iwl_mvm_wowlan_config(struct iwl_mvm *mvm, if (fw_has_api(&mvm->fw->ucode_capa, IWL_UCODE_TLV_API_WOWLAN_TCP_SYN_WAKE)) - ret = iwl_mvm_send_patterns(mvm, vif, wowlan); + ret = iwl_mvm_send_patterns(mvm, mvm_link, wowlan); else ret = iwl_mvm_send_patterns_v1(mvm, wowlan); if (ret) @@ -1223,6 +1225,7 @@ static int __iwl_mvm_suspend(struct ieee80211_hw *hw, struct ieee80211_vif *vif = NULL; struct iwl_mvm_vif *mvmvif = NULL; struct ieee80211_sta *ap_sta = NULL; + struct iwl_mvm_vif_link_info *mvm_link; struct iwl_d3_manager_config d3_cfg_cmd_data = { /* * Program the minimum sleep time to 10 seconds, as many @@ -1237,7 +1240,7 @@ static int __iwl_mvm_suspend(struct ieee80211_hw *hw, .data[0] = &d3_cfg_cmd_data, .len[0] = sizeof(d3_cfg_cmd_data), }; - int ret; + int ret, primary_link; int len __maybe_unused; bool unified_image = fw_has_capa(&mvm->fw->ucode_capa, IWL_UCODE_TLV_CAPA_CNSLDTD_D3_D0_IMG); @@ -1251,21 +1254,44 @@ static int __iwl_mvm_suspend(struct ieee80211_hw *hw, return -EINVAL; } + vif = iwl_mvm_get_bss_vif(mvm); + if (IS_ERR_OR_NULL(vif)) + return 1; + + if (ieee80211_vif_is_mld(vif) && vif->cfg.assoc) { + /* + * Select the 'best' link. May need to revisit, it seems + * better to not optimize for throughput but rather range, + * reliability and power here - and select 2.4 GHz ... + */ + primary_link = + iwl_mvm_mld_get_primary_link(mvm, vif, + vif->active_links); + + if (WARN_ONCE(primary_link < 0, "no primary link in 0x%x\n", + vif->active_links)) + primary_link = __ffs(vif->active_links); + + ret = ieee80211_set_active_links(vif, BIT(primary_link)); + if (ret) + return ret; + } else { + primary_link = 0; + } + mutex_lock(&mvm->mutex); set_bit(IWL_MVM_STATUS_IN_D3, &mvm->status); synchronize_net(); - vif = iwl_mvm_get_bss_vif(mvm); - if (IS_ERR_OR_NULL(vif)) { - ret = 1; - goto out_noreset; - } - mvmvif = iwl_mvm_vif_from_mac80211(vif); - if (mvmvif->deflink.ap_sta_id == IWL_MVM_INVALID_STA) { + mvm_link = mvmvif->link[primary_link]; + if (WARN_ON_ONCE(!mvm_link)) + return -EINVAL; + + if (mvm_link->ap_sta_id == IWL_MVM_INVALID_STA) { /* if we're not associated, this must be netdetect */ if (!wowlan->nd_config) { ret = 1; @@ -1281,10 +1307,10 @@ static int __iwl_mvm_suspend(struct ieee80211_hw *hw, } else { struct iwl_wowlan_config_cmd wowlan_config_cmd = {}; - wowlan_config_cmd.sta_id = mvmvif->deflink.ap_sta_id; + wowlan_config_cmd.sta_id = mvm_link->ap_sta_id; ap_sta = rcu_dereference_protected( - mvm->fw_id_to_mac_id[mvmvif->deflink.ap_sta_id], + mvm->fw_id_to_mac_id[mvm_link->ap_sta_id], lockdep_is_held(&mvm->mutex)); if (IS_ERR_OR_NULL(ap_sta)) { ret = -EINVAL; @@ -1296,7 +1322,7 @@ static int __iwl_mvm_suspend(struct ieee80211_hw *hw, if (ret) goto out_noreset; ret = iwl_mvm_wowlan_config(mvm, wowlan, &wowlan_config_cmd, - vif, mvmvif, ap_sta); + vif, mvmvif, mvm_link, ap_sta); if (ret) goto out; @@ -2846,6 +2872,9 @@ iwl_mvm_choose_query_wakeup_reasons(struct iwl_mvm *mvm, u8 sta_id = mvm->net_detect ? IWL_MVM_INVALID_STA : mvmvif->deflink.ap_sta_id; + /* bug - FW with MLO has status notification */ + WARN_ON(ieee80211_vif_is_mld(vif)); + d3_data->status = iwl_mvm_send_wowlan_get_status(mvm, sta_id); } -- cgit v1.2.3 From 760cfa5bbd3bdd5ca2b36ca447d69788651ab17b Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Wed, 31 Jan 2024 10:24:36 +0200 Subject: wifi: iwlwifi: mvm: check AP supports EMLSR Before using EMLSR check the AP actually advertises support for it, otherwise reject the link activation. Signed-off-by: Johannes Berg Reviewed-by: Gregory Greenman Signed-off-by: Miri Korenblit Link: https://msgid.link/20240131091413.edaac352488d.Ic3533afc6848591e8977391ae39c144d5e794d26@changeid Signed-off-by: Johannes Berg --- drivers/net/wireless/intel/iwlwifi/mvm/mld-mac80211.c | 3 +++ 1 file changed, 3 insertions(+) (limited to 'drivers/net') diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/mld-mac80211.c b/drivers/net/wireless/intel/iwlwifi/mvm/mld-mac80211.c index 5bac39b75e6c..d3c6eb83cd73 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/mld-mac80211.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/mld-mac80211.c @@ -1280,6 +1280,9 @@ static bool iwl_mvm_can_enter_esr(struct iwl_mvm *mvm, if (primary_link < 0) return false; + if (!(vif->cfg.eml_cap & IEEE80211_EML_CAP_EMLSR_SUPP)) + return false; + for_each_set_bit(link_id, &desired_links, IEEE80211_MLD_MAX_NUM_LINKS) { struct ieee80211_bss_conf *link_conf = link_conf_dereference_protected(vif, link_id); -- cgit v1.2.3 From 2594e4d9e1a2d79bf7bb262974abaf5ef153e371 Mon Sep 17 00:00:00 2001 From: Miri Korenblit Date: Wed, 31 Jan 2024 10:24:37 +0200 Subject: wifi: iwlwifi: prepare for reading SAR tables from UEFI The driver will support reading BIOS tables from UEFI too. Refactor the SAR tables (WRDS, EWRD, WGDS) flows: 1. Move all the SAR logic/definitions that is common to both UEFI and ACPI to a new file - regulatory.h/c. 2. Rename the relevant functions/definitions so it will be clear which is ACPI specific and which is for both ACPI and UEFI 3. Rename the function that copies the stored tables into the different commands structures, so will be clear what these functions do. Signed-off-by: Miri Korenblit Reviewed-by: Gregory Greenman Link: https://msgid.link/20240131091413.429a9baff34a.I040460348aa1b43609be3a317b86722d6be71c28@changeid Signed-off-by: Johannes Berg --- drivers/net/wireless/intel/iwlwifi/Makefile | 1 + drivers/net/wireless/intel/iwlwifi/fw/acpi.c | 165 +++------------------ drivers/net/wireless/intel/iwlwifi/fw/acpi.h | 55 +------ drivers/net/wireless/intel/iwlwifi/fw/regulatory.c | 132 +++++++++++++++++ drivers/net/wireless/intel/iwlwifi/fw/regulatory.h | 90 +++++++++++ drivers/net/wireless/intel/iwlwifi/fw/runtime.h | 7 +- drivers/net/wireless/intel/iwlwifi/mvm/fw.c | 32 ++-- 7 files changed, 273 insertions(+), 209 deletions(-) create mode 100644 drivers/net/wireless/intel/iwlwifi/fw/regulatory.c create mode 100644 drivers/net/wireless/intel/iwlwifi/fw/regulatory.h (limited to 'drivers/net') diff --git a/drivers/net/wireless/intel/iwlwifi/Makefile b/drivers/net/wireless/intel/iwlwifi/Makefile index 3a2a25333d36..8bb94a4c12cd 100644 --- a/drivers/net/wireless/intel/iwlwifi/Makefile +++ b/drivers/net/wireless/intel/iwlwifi/Makefile @@ -18,6 +18,7 @@ iwlwifi-objs += queue/tx.o iwlwifi-objs += fw/img.o fw/notif-wait.o fw/rs.o iwlwifi-objs += fw/dbg.o fw/pnvm.o fw/dump.o +iwlwifi-objs += fw/regulatory.o iwlwifi-$(CONFIG_IWLMVM) += fw/paging.o fw/smem.o fw/init.o iwlwifi-$(CONFIG_ACPI) += fw/acpi.o iwlwifi-$(CONFIG_EFI) += fw/uefi.o diff --git a/drivers/net/wireless/intel/iwlwifi/fw/acpi.c b/drivers/net/wireless/intel/iwlwifi/fw/acpi.c index 9be91e6a9882..401aca31704c 100644 --- a/drivers/net/wireless/intel/iwlwifi/fw/acpi.c +++ b/drivers/net/wireless/intel/iwlwifi/fw/acpi.c @@ -501,9 +501,10 @@ out_free: } IWL_EXPORT_SYMBOL(iwl_acpi_get_eckv); -static int iwl_sar_set_profile(union acpi_object *table, - struct iwl_sar_profile *profile, - bool enabled, u8 num_chains, u8 num_sub_bands) +static int iwl_acpi_sar_set_profile(union acpi_object *table, + struct iwl_sar_profile *profile, + bool enabled, u8 num_chains, + u8 num_sub_bands) { int i, j, idx = 0; @@ -511,8 +512,8 @@ static int iwl_sar_set_profile(union acpi_object *table, * The table from ACPI is flat, but we store it in a * structured array. */ - for (i = 0; i < ACPI_SAR_NUM_CHAINS_REV2; i++) { - for (j = 0; j < ACPI_SAR_NUM_SUB_BANDS_REV2; j++) { + for (i = 0; i < BIOS_SAR_MAX_CHAINS_PER_PROFILE; i++) { + for (j = 0; j < BIOS_SAR_MAX_SUB_BANDS_NUM; j++) { /* if we don't have the values, use the default */ if (i >= num_chains || j >= num_sub_bands) { profile->chains[i].subbands[j] = 0; @@ -535,73 +536,7 @@ static int iwl_sar_set_profile(union acpi_object *table, return 0; } -static int iwl_sar_fill_table(struct iwl_fw_runtime *fwrt, - __le16 *per_chain, u32 n_subbands, - int prof_a, int prof_b) -{ - int profs[ACPI_SAR_NUM_CHAINS_REV0] = { prof_a, prof_b }; - int i, j; - - for (i = 0; i < ACPI_SAR_NUM_CHAINS_REV0; i++) { - struct iwl_sar_profile *prof; - - /* don't allow SAR to be disabled (profile 0 means disable) */ - if (profs[i] == 0) - return -EPERM; - - /* we are off by one, so allow up to ACPI_SAR_PROFILE_NUM */ - if (profs[i] > ACPI_SAR_PROFILE_NUM) - return -EINVAL; - - /* profiles go from 1 to 4, so decrement to access the array */ - prof = &fwrt->sar_profiles[profs[i] - 1]; - - /* if the profile is disabled, do nothing */ - if (!prof->enabled) { - IWL_DEBUG_RADIO(fwrt, "SAR profile %d is disabled.\n", - profs[i]); - /* - * if one of the profiles is disabled, we - * ignore all of them and return 1 to - * differentiate disabled from other failures. - */ - return 1; - } - - IWL_DEBUG_INFO(fwrt, - "SAR EWRD: chain %d profile index %d\n", - i, profs[i]); - IWL_DEBUG_RADIO(fwrt, " Chain[%d]:\n", i); - for (j = 0; j < n_subbands; j++) { - per_chain[i * n_subbands + j] = - cpu_to_le16(prof->chains[i].subbands[j]); - IWL_DEBUG_RADIO(fwrt, " Band[%d] = %d * .125dBm\n", - j, prof->chains[i].subbands[j]); - } - } - - return 0; -} - -int iwl_sar_select_profile(struct iwl_fw_runtime *fwrt, - __le16 *per_chain, u32 n_tables, u32 n_subbands, - int prof_a, int prof_b) -{ - int i, ret = 0; - - for (i = 0; i < n_tables; i++) { - ret = iwl_sar_fill_table(fwrt, - &per_chain[i * n_subbands * ACPI_SAR_NUM_CHAINS_REV0], - n_subbands, prof_a, prof_b); - if (ret) - break; - } - - return ret; -} -IWL_EXPORT_SYMBOL(iwl_sar_select_profile); - -int iwl_sar_get_wrds_table(struct iwl_fw_runtime *fwrt) +int iwl_acpi_get_wrds_table(struct iwl_fw_runtime *fwrt) { union acpi_object *wifi_pkg, *table, *data; int ret, tbl_rev; @@ -680,16 +615,16 @@ read_table: /* The profile from WRDS is officially profile 1, but goes * into sar_profiles[0] (because we don't have a profile 0). */ - ret = iwl_sar_set_profile(table, &fwrt->sar_profiles[0], - flags & IWL_SAR_ENABLE_MSK, - num_chains, num_sub_bands); + ret = iwl_acpi_sar_set_profile(table, &fwrt->sar_profiles[0], + flags & IWL_SAR_ENABLE_MSK, + num_chains, num_sub_bands); out_free: kfree(data); return ret; } -IWL_EXPORT_SYMBOL(iwl_sar_get_wrds_table); +IWL_EXPORT_SYMBOL(iwl_acpi_get_wrds_table); -int iwl_sar_get_ewrd_table(struct iwl_fw_runtime *fwrt) +int iwl_acpi_get_ewrd_table(struct iwl_fw_runtime *fwrt) { union acpi_object *wifi_pkg, *data; bool enabled; @@ -767,7 +702,7 @@ read_table: * from index 1, so the maximum value allowed here is * ACPI_SAR_PROFILES_NUM - 1. */ - if (n_profiles >= ACPI_SAR_PROFILE_NUM) { + if (n_profiles >= BIOS_SAR_MAX_PROFILE_NUM) { ret = -EINVAL; goto out_free; } @@ -776,13 +711,15 @@ read_table: pos = 3; for (i = 0; i < n_profiles; i++) { + union acpi_object *table = &wifi_pkg->package.elements[pos]; /* The EWRD profiles officially go from 2 to 4, but we * save them in sar_profiles[1-3] (because we don't * have profile 0). So in the array we start from 1. */ - ret = iwl_sar_set_profile(&wifi_pkg->package.elements[pos], - &fwrt->sar_profiles[i + 1], enabled, - num_chains, num_sub_bands); + ret = iwl_acpi_sar_set_profile(table, + &fwrt->sar_profiles[i + 1], + enabled, num_chains, + num_sub_bands); if (ret < 0) break; @@ -794,9 +731,9 @@ out_free: kfree(data); return ret; } -IWL_EXPORT_SYMBOL(iwl_sar_get_ewrd_table); +IWL_EXPORT_SYMBOL(iwl_acpi_get_ewrd_table); -int iwl_sar_get_wgds_table(struct iwl_fw_runtime *fwrt) +int iwl_acpi_get_wgds_table(struct iwl_fw_runtime *fwrt) { union acpi_object *wifi_pkg, *data; int i, j, k, ret, tbl_rev; @@ -897,7 +834,7 @@ int iwl_sar_get_wgds_table(struct iwl_fw_runtime *fwrt) read_table: fwrt->geo_rev = tbl_rev; for (i = 0; i < num_profiles; i++) { - for (j = 0; j < ACPI_GEO_NUM_BANDS_REV2; j++) { + for (j = 0; j < BIOS_GEO_MAX_NUM_BANDS; j++) { union acpi_object *entry; /* @@ -921,7 +858,7 @@ read_table: entry->integer.value; } - for (k = 0; k < ACPI_GEO_NUM_CHAINS; k++) { + for (k = 0; k < BIOS_GEO_NUM_CHAINS; k++) { /* same here as above */ if (j >= num_bands) { fwrt->geo_profiles[i].bands[j].chains[k] = @@ -949,63 +886,7 @@ out_free: kfree(data); return ret; } -IWL_EXPORT_SYMBOL(iwl_sar_get_wgds_table); - -bool iwl_sar_geo_support(struct iwl_fw_runtime *fwrt) -{ - /* - * The PER_CHAIN_LIMIT_OFFSET_CMD command is not supported on - * earlier firmware versions. Unfortunately, we don't have a - * TLV API flag to rely on, so rely on the major version which - * is in the first byte of ucode_ver. This was implemented - * initially on version 38 and then backported to 17. It was - * also backported to 29, but only for 7265D devices. The - * intention was to have it in 36 as well, but not all 8000 - * family got this feature enabled. The 8000 family is the - * only one using version 36, so skip this version entirely. - */ - return IWL_UCODE_SERIAL(fwrt->fw->ucode_ver) >= 38 || - (IWL_UCODE_SERIAL(fwrt->fw->ucode_ver) == 17 && - fwrt->trans->hw_rev != CSR_HW_REV_TYPE_3160) || - (IWL_UCODE_SERIAL(fwrt->fw->ucode_ver) == 29 && - ((fwrt->trans->hw_rev & CSR_HW_REV_TYPE_MSK) == - CSR_HW_REV_TYPE_7265D)); -} -IWL_EXPORT_SYMBOL(iwl_sar_geo_support); - -int iwl_sar_geo_init(struct iwl_fw_runtime *fwrt, - struct iwl_per_chain_offset *table, - u32 n_bands, u32 n_profiles) -{ - int i, j; - - if (!fwrt->geo_enabled) - return -ENODATA; - - if (!iwl_sar_geo_support(fwrt)) - return -EOPNOTSUPP; - - for (i = 0; i < n_profiles; i++) { - for (j = 0; j < n_bands; j++) { - struct iwl_per_chain_offset *chain = - &table[i * n_bands + j]; - - chain->max_tx_power = - cpu_to_le16(fwrt->geo_profiles[i].bands[j].max); - chain->chain_a = fwrt->geo_profiles[i].bands[j].chains[0]; - chain->chain_b = fwrt->geo_profiles[i].bands[j].chains[1]; - IWL_DEBUG_RADIO(fwrt, - "SAR geographic profile[%d] Band[%d]: chain A = %d chain B = %d max_tx_power = %d\n", - i, j, - fwrt->geo_profiles[i].bands[j].chains[0], - fwrt->geo_profiles[i].bands[j].chains[1], - fwrt->geo_profiles[i].bands[j].max); - } - } - - return 0; -} -IWL_EXPORT_SYMBOL(iwl_sar_geo_init); +IWL_EXPORT_SYMBOL(iwl_acpi_get_wgds_table); __le32 iwl_acpi_get_lari_config_bitmap(struct iwl_fw_runtime *fwrt) { diff --git a/drivers/net/wireless/intel/iwlwifi/fw/acpi.h b/drivers/net/wireless/intel/iwlwifi/fw/acpi.h index 7b3c6fca7591..ba7626543b70 100644 --- a/drivers/net/wireless/intel/iwlwifi/fw/acpi.h +++ b/drivers/net/wireless/intel/iwlwifi/fw/acpi.h @@ -62,7 +62,6 @@ /* revision 0 and 1 are identical, except for the semantics in the FW */ #define ACPI_GEO_NUM_BANDS_REV0 2 #define ACPI_GEO_NUM_BANDS_REV2 3 -#define ACPI_GEO_NUM_CHAINS 2 #define ACPI_WRDD_WIFI_DATA_SIZE 2 #define ACPI_SPLC_WIFI_DATA_SIZE 2 @@ -111,26 +110,6 @@ * turn a superset of revision 0. So we can store all revisions * inside revision 2, which is what we represent here. */ -struct iwl_sar_profile_chain { - u8 subbands[ACPI_SAR_NUM_SUB_BANDS_REV2]; -}; - -struct iwl_sar_profile { - bool enabled; - struct iwl_sar_profile_chain chains[ACPI_SAR_NUM_CHAINS_REV2]; -}; - -/* Same thing as with SAR, all revisions fit in revision 2 */ -struct iwl_geo_profile_band { - u8 max; - u8 chains[ACPI_GEO_NUM_CHAINS]; -}; - -struct iwl_geo_profile { - struct iwl_geo_profile_band bands[ACPI_GEO_NUM_BANDS_REV2]; -}; - -/* Same thing as with SAR, all revisions fit in revision 2 */ struct iwl_ppag_chain { s8 subbands[ACPI_SAR_NUM_SUB_BANDS_REV2]; }; @@ -212,21 +191,11 @@ u64 iwl_acpi_get_pwr_limit(struct device *dev); */ int iwl_acpi_get_eckv(struct device *dev, u32 *extl_clk); -int iwl_sar_select_profile(struct iwl_fw_runtime *fwrt, - __le16 *per_chain, u32 n_tables, u32 n_subbands, - int prof_a, int prof_b); - -int iwl_sar_get_wrds_table(struct iwl_fw_runtime *fwrt); - -int iwl_sar_get_ewrd_table(struct iwl_fw_runtime *fwrt); +int iwl_acpi_get_wrds_table(struct iwl_fw_runtime *fwrt); -int iwl_sar_get_wgds_table(struct iwl_fw_runtime *fwrt); +int iwl_acpi_get_ewrd_table(struct iwl_fw_runtime *fwrt); -bool iwl_sar_geo_support(struct iwl_fw_runtime *fwrt); - -int iwl_sar_geo_init(struct iwl_fw_runtime *fwrt, - struct iwl_per_chain_offset *table, - u32 n_bands, u32 n_profiles); +int iwl_acpi_get_wgds_table(struct iwl_fw_runtime *fwrt); int iwl_acpi_get_tas(struct iwl_fw_runtime *fwrt, union iwl_tas_config_cmd *cmd, int fw_ver); @@ -280,33 +249,21 @@ static inline int iwl_acpi_get_eckv(struct device *dev, u32 *extl_clk) return -ENOENT; } -static inline int iwl_sar_select_profile(struct iwl_fw_runtime *fwrt, - __le16 *per_chain, u32 n_tables, u32 n_subbands, - int prof_a, int prof_b) -{ - return -ENOENT; -} - -static inline int iwl_sar_get_wrds_table(struct iwl_fw_runtime *fwrt) +static inline int iwl_acpi_get_wrds_table(struct iwl_fw_runtime *fwrt) { return -ENOENT; } -static inline int iwl_sar_get_ewrd_table(struct iwl_fw_runtime *fwrt) +static inline int iwl_acpi_get_ewrd_table(struct iwl_fw_runtime *fwrt) { return -ENOENT; } -static inline int iwl_sar_get_wgds_table(struct iwl_fw_runtime *fwrt) +static inline int iwl_acpi_get_wgds_table(struct iwl_fw_runtime *fwrt) { return 1; } -static inline bool iwl_sar_geo_support(struct iwl_fw_runtime *fwrt) -{ - return false; -} - static inline int iwl_acpi_get_tas(struct iwl_fw_runtime *fwrt, union iwl_tas_config_cmd *cmd, int fw_ver) { diff --git a/drivers/net/wireless/intel/iwlwifi/fw/regulatory.c b/drivers/net/wireless/intel/iwlwifi/fw/regulatory.c new file mode 100644 index 000000000000..58290bf64f42 --- /dev/null +++ b/drivers/net/wireless/intel/iwlwifi/fw/regulatory.c @@ -0,0 +1,132 @@ +// SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause +/* + * Copyright (C) 2023 Intel Corporation + */ +#include "iwl-drv.h" +#include "iwl-debug.h" +#include "regulatory.h" +#include "fw/runtime.h" + +bool iwl_sar_geo_support(struct iwl_fw_runtime *fwrt) +{ + /* + * The PER_CHAIN_LIMIT_OFFSET_CMD command is not supported on + * earlier firmware versions. Unfortunately, we don't have a + * TLV API flag to rely on, so rely on the major version which + * is in the first byte of ucode_ver. This was implemented + * initially on version 38 and then backported to 17. It was + * also backported to 29, but only for 7265D devices. The + * intention was to have it in 36 as well, but not all 8000 + * family got this feature enabled. The 8000 family is the + * only one using version 36, so skip this version entirely. + */ + return IWL_UCODE_SERIAL(fwrt->fw->ucode_ver) >= 38 || + (IWL_UCODE_SERIAL(fwrt->fw->ucode_ver) == 17 && + fwrt->trans->hw_rev != CSR_HW_REV_TYPE_3160) || + (IWL_UCODE_SERIAL(fwrt->fw->ucode_ver) == 29 && + ((fwrt->trans->hw_rev & CSR_HW_REV_TYPE_MSK) == + CSR_HW_REV_TYPE_7265D)); +} +IWL_EXPORT_SYMBOL(iwl_sar_geo_support); + +int iwl_sar_geo_fill_table(struct iwl_fw_runtime *fwrt, + struct iwl_per_chain_offset *table, + u32 n_bands, u32 n_profiles) +{ + int i, j; + + if (!fwrt->geo_enabled) + return -ENODATA; + + if (!iwl_sar_geo_support(fwrt)) + return -EOPNOTSUPP; + + for (i = 0; i < n_profiles; i++) { + for (j = 0; j < n_bands; j++) { + struct iwl_per_chain_offset *chain = + &table[i * n_bands + j]; + + chain->max_tx_power = + cpu_to_le16(fwrt->geo_profiles[i].bands[j].max); + chain->chain_a = + fwrt->geo_profiles[i].bands[j].chains[0]; + chain->chain_b = + fwrt->geo_profiles[i].bands[j].chains[1]; + IWL_DEBUG_RADIO(fwrt, + "SAR geographic profile[%d] Band[%d]: chain A = %d chain B = %d max_tx_power = %d\n", + i, j, + fwrt->geo_profiles[i].bands[j].chains[0], + fwrt->geo_profiles[i].bands[j].chains[1], + fwrt->geo_profiles[i].bands[j].max); + } + } + + return 0; +} +IWL_EXPORT_SYMBOL(iwl_sar_geo_fill_table); + +static int iwl_sar_fill_table(struct iwl_fw_runtime *fwrt, + __le16 *per_chain, u32 n_subbands, + int prof_a, int prof_b) +{ + int profs[BIOS_SAR_NUM_CHAINS] = { prof_a, prof_b }; + int i, j; + + for (i = 0; i < BIOS_SAR_NUM_CHAINS; i++) { + struct iwl_sar_profile *prof; + + /* don't allow SAR to be disabled (profile 0 means disable) */ + if (profs[i] == 0) + return -EPERM; + + /* we are off by one, so allow up to BIOS_SAR_MAX_PROFILE_NUM */ + if (profs[i] > BIOS_SAR_MAX_PROFILE_NUM) + return -EINVAL; + + /* profiles go from 1 to 4, so decrement to access the array */ + prof = &fwrt->sar_profiles[profs[i] - 1]; + + /* if the profile is disabled, do nothing */ + if (!prof->enabled) { + IWL_DEBUG_RADIO(fwrt, "SAR profile %d is disabled.\n", + profs[i]); + /* + * if one of the profiles is disabled, we + * ignore all of them and return 1 to + * differentiate disabled from other failures. + */ + return 1; + } + + IWL_DEBUG_INFO(fwrt, + "SAR EWRD: chain %d profile index %d\n", + i, profs[i]); + IWL_DEBUG_RADIO(fwrt, " Chain[%d]:\n", i); + for (j = 0; j < n_subbands; j++) { + per_chain[i * n_subbands + j] = + cpu_to_le16(prof->chains[i].subbands[j]); + IWL_DEBUG_RADIO(fwrt, " Band[%d] = %d * .125dBm\n", + j, prof->chains[i].subbands[j]); + } + } + + return 0; +} + +int iwl_sar_fill_profile(struct iwl_fw_runtime *fwrt, + __le16 *per_chain, u32 n_tables, u32 n_subbands, + int prof_a, int prof_b) +{ + int i, ret = 0; + + for (i = 0; i < n_tables; i++) { + ret = iwl_sar_fill_table(fwrt, + &per_chain[i * n_subbands * BIOS_SAR_NUM_CHAINS], + n_subbands, prof_a, prof_b); + if (ret) + break; + } + + return ret; +} +IWL_EXPORT_SYMBOL(iwl_sar_fill_profile); diff --git a/drivers/net/wireless/intel/iwlwifi/fw/regulatory.h b/drivers/net/wireless/intel/iwlwifi/fw/regulatory.h new file mode 100644 index 000000000000..650430f21510 --- /dev/null +++ b/drivers/net/wireless/intel/iwlwifi/fw/regulatory.h @@ -0,0 +1,90 @@ +/* SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause */ +/* + * Copyright (C) 2023 Intel Corporation + */ + +#ifndef __fw_regulatory_h__ +#define __fw_regulatory_h__ + +#include "fw/img.h" +#include "fw/api/commands.h" +#include "fw/api/power.h" +#include "fw/api/phy.h" +#include "fw/api/nvm-reg.h" +#include "fw/api/config.h" +#include "fw/img.h" +#include "iwl-trans.h" + +#define BIOS_SAR_MAX_PROFILE_NUM 4 +/* + * Each SAR profile has (up to, depends on the table revision) 4 chains: + * chain A, chain B, chain A when in CDB, chain B when in CDB + */ +#define BIOS_SAR_MAX_CHAINS_PER_PROFILE 4 +#define BIOS_SAR_NUM_CHAINS 2 +#define BIOS_SAR_MAX_SUB_BANDS_NUM 11 + +#define BIOS_GEO_NUM_CHAINS 2 +#define BIOS_GEO_MAX_NUM_BANDS 3 +#define BIOS_GEO_MAX_PROFILE_NUM 8 +#define BIOS_GEO_MIN_PROFILE_NUM 3 + +#define IWL_SAR_ENABLE_MSK BIT(0) + +/* + * The profile for revision 2 is a superset of revision 1, which is in + * turn a superset of revision 0. So we can store all revisions + * inside revision 2, which is what we represent here. + */ + +/* + * struct iwl_sar_profile_chain - per-chain values of a SAR profile + * @subbands: the SAR value for each subband + */ +struct iwl_sar_profile_chain { + u8 subbands[BIOS_SAR_MAX_SUB_BANDS_NUM]; +}; + +/* + * struct iwl_sar_profile - SAR profile from SAR tables + * @enabled: whether the profile is enabled or not + * @chains: per-chain SAR values + */ +struct iwl_sar_profile { + bool enabled; + struct iwl_sar_profile_chain chains[BIOS_SAR_MAX_CHAINS_PER_PROFILE]; +}; + +/* Same thing as with SAR, all revisions fit in revision 2 */ + +/* + * struct iwl_geo_profile_band - per-band geo SAR offsets + * @max: the max tx power allowed for the band + * @chains: SAR offsets values for each chain + */ +struct iwl_geo_profile_band { + u8 max; + u8 chains[BIOS_GEO_NUM_CHAINS]; +}; + +/* + * struct iwl_geo_profile - geo profile + * @bands: per-band table of the SAR offsets + */ +struct iwl_geo_profile { + struct iwl_geo_profile_band bands[BIOS_GEO_MAX_NUM_BANDS]; +}; + +struct iwl_fw_runtime; + +bool iwl_sar_geo_support(struct iwl_fw_runtime *fwrt); + +int iwl_sar_geo_fill_table(struct iwl_fw_runtime *fwrt, + struct iwl_per_chain_offset *table, + u32 n_bands, u32 n_profiles); + +int iwl_sar_fill_profile(struct iwl_fw_runtime *fwrt, + __le16 *per_chain, u32 n_tables, u32 n_subbands, + int prof_a, int prof_b); + +#endif /* __fw_regulatory_h__ */ diff --git a/drivers/net/wireless/intel/iwlwifi/fw/runtime.h b/drivers/net/wireless/intel/iwlwifi/fw/runtime.h index 048830bb09f2..08734f48443e 100644 --- a/drivers/net/wireless/intel/iwlwifi/fw/runtime.h +++ b/drivers/net/wireless/intel/iwlwifi/fw/runtime.h @@ -14,6 +14,7 @@ #include "fw/api/power.h" #include "iwl-eeprom-parse.h" #include "fw/acpi.h" +#include "fw/regulatory.h" struct iwl_fw_runtime_ops { void (*dump_start)(void *ctx); @@ -103,6 +104,8 @@ struct iwl_txf_iter_data { * @uefi_tables_lock_status: The status of the WIFI GUID UEFI variables lock: * 0: Unlocked, 1 and 2: Locked. * Only read the UEFI variables if locked. + * @sar_profiles: sar profiles as read from WRDS/EWRD BIOS tables + * @geo_profiles: geographic profiles as read from WGDS BIOS table */ struct iwl_fw_runtime { struct iwl_trans *trans; @@ -162,10 +165,10 @@ struct iwl_fw_runtime { bool tpc_enabled; #endif /* CONFIG_IWLWIFI_DEBUGFS */ #ifdef CONFIG_ACPI - struct iwl_sar_profile sar_profiles[ACPI_SAR_PROFILE_NUM]; + struct iwl_sar_profile sar_profiles[BIOS_SAR_MAX_PROFILE_NUM]; u8 sar_chain_a_profile; u8 sar_chain_b_profile; - struct iwl_geo_profile geo_profiles[ACPI_NUM_GEO_PROFILES_REV3]; + struct iwl_geo_profile geo_profiles[BIOS_GEO_MAX_PROFILE_NUM]; u32 geo_rev; u32 geo_num_profiles; bool geo_enabled; diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/fw.c b/drivers/net/wireless/intel/iwlwifi/mvm/fw.c index a6db290923cd..f8ab31f9d109 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/fw.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/fw.c @@ -936,9 +936,9 @@ int iwl_mvm_sar_select_profile(struct iwl_mvm *mvm, int prof_a, int prof_b) /* all structs have the same common part, add it */ len += sizeof(cmd.common); - ret = iwl_sar_select_profile(&mvm->fwrt, per_chain, - IWL_NUM_CHAIN_TABLES, - n_subbands, prof_a, prof_b); + ret = iwl_sar_fill_profile(&mvm->fwrt, per_chain, + IWL_NUM_CHAIN_TABLES, + n_subbands, prof_a, prof_b); /* return on error or if the profile is disabled (positive number) */ if (ret) @@ -994,7 +994,7 @@ int iwl_mvm_get_sar_geo_profile(struct iwl_mvm *mvm) resp = (void *)cmd.resp_pkt->data; ret = le32_to_cpu(resp->profile_idx); - if (WARN_ON(ret > ACPI_NUM_GEO_PROFILES_REV3)) + if (WARN_ON(ret > BIOS_GEO_MAX_PROFILE_NUM)) ret = -EIO; iwl_free_resp(&cmd); @@ -1028,24 +1028,24 @@ static int iwl_mvm_sar_geo_init(struct iwl_mvm *mvm) if (cmd_ver == 5) { len = sizeof(cmd.v5); n_bands = ARRAY_SIZE(cmd.v5.table[0]); - n_profiles = ACPI_NUM_GEO_PROFILES_REV3; + n_profiles = BIOS_GEO_MAX_PROFILE_NUM; } else if (cmd_ver == 4) { len = sizeof(cmd.v4); n_bands = ARRAY_SIZE(cmd.v4.table[0]); - n_profiles = ACPI_NUM_GEO_PROFILES_REV3; + n_profiles = BIOS_GEO_MAX_PROFILE_NUM; } else if (cmd_ver == 3) { len = sizeof(cmd.v3); n_bands = ARRAY_SIZE(cmd.v3.table[0]); - n_profiles = ACPI_NUM_GEO_PROFILES; + n_profiles = BIOS_GEO_MIN_PROFILE_NUM; } else if (fw_has_api(&mvm->fwrt.fw->ucode_capa, IWL_UCODE_TLV_API_SAR_TABLE_VER)) { len = sizeof(cmd.v2); n_bands = ARRAY_SIZE(cmd.v2.table[0]); - n_profiles = ACPI_NUM_GEO_PROFILES; + n_profiles = BIOS_GEO_MIN_PROFILE_NUM; } else { len = sizeof(cmd.v1); n_bands = ARRAY_SIZE(cmd.v1.table[0]); - n_profiles = ACPI_NUM_GEO_PROFILES; + n_profiles = BIOS_GEO_MIN_PROFILE_NUM; } BUILD_BUG_ON(offsetof(struct iwl_geo_tx_power_profiles_cmd_v1, table) != @@ -1057,8 +1057,8 @@ static int iwl_mvm_sar_geo_init(struct iwl_mvm *mvm) offsetof(struct iwl_geo_tx_power_profiles_cmd_v4, table) != offsetof(struct iwl_geo_tx_power_profiles_cmd_v5, table)); /* the table is at the same position for all versions, so set use v1 */ - ret = iwl_sar_geo_init(&mvm->fwrt, &cmd.v1.table[0][0], - n_bands, n_profiles); + ret = iwl_sar_geo_fill_table(&mvm->fwrt, &cmd.v1.table[0][0], + n_bands, n_profiles); /* * It is a valid scenario to not support SAR, or miss wgds table, @@ -1076,7 +1076,7 @@ static int iwl_mvm_sar_geo_init(struct iwl_mvm *mvm) * element name is misleading, as it doesn't contain the table * revision number, but whether the South Korea variation * should be used. - * This must be done after calling iwl_sar_geo_init(). + * This must be done after calling iwl_sar_geo_fill_table(). */ if (cmd_ver == 5) cmd.v5.table_revision = cpu_to_le32(sk); @@ -1413,7 +1413,7 @@ void iwl_mvm_get_acpi_tables(struct iwl_mvm *mvm) } /* read SAR tables */ - ret = iwl_sar_get_wrds_table(&mvm->fwrt); + ret = iwl_acpi_get_wrds_table(&mvm->fwrt); if (ret < 0) { IWL_DEBUG_RADIO(mvm, "WRDS SAR BIOS table invalid or unavailable. (%d)\n", @@ -1422,7 +1422,7 @@ void iwl_mvm_get_acpi_tables(struct iwl_mvm *mvm) * If not available, don't fail and don't bother with EWRD and * WGDS */ - if (!iwl_sar_get_wgds_table(&mvm->fwrt)) { + if (!iwl_acpi_get_wgds_table(&mvm->fwrt)) { /* * If basic SAR is not available, we check for WGDS, * which should *not* be available either. If it is @@ -1433,7 +1433,7 @@ void iwl_mvm_get_acpi_tables(struct iwl_mvm *mvm) } } else { - ret = iwl_sar_get_ewrd_table(&mvm->fwrt); + ret = iwl_acpi_get_ewrd_table(&mvm->fwrt); /* if EWRD is not available, we can still use * WRDS, so don't fail */ if (ret < 0) @@ -1443,7 +1443,7 @@ void iwl_mvm_get_acpi_tables(struct iwl_mvm *mvm) /* read geo SAR table */ if (iwl_sar_geo_support(&mvm->fwrt)) { - ret = iwl_sar_get_wgds_table(&mvm->fwrt); + ret = iwl_acpi_get_wgds_table(&mvm->fwrt); if (ret < 0) IWL_DEBUG_RADIO(mvm, "Geo SAR BIOS table invalid or unavailable. (%d)\n", -- cgit v1.2.3 From c0a3dfc1ce955732ae8cd301a052f2277aa55436 Mon Sep 17 00:00:00 2001 From: Miri Korenblit Date: Wed, 31 Jan 2024 10:24:38 +0200 Subject: wifi: iwlwifi: cleanup sending PER_CHAIN_LIMIT_OFFSET_CMD iwl_geo_tx_power_profiles_cmd::table_revision indicates whether to use South Korea scheme or not. We use South Korea scheme if the revision of WGDS table is 1. We used to read the WGDS table from ACPI inside iwl_sar_geo_fill_table(), so we had to set table_revision only after the call to it. This added an extra if...else for each cmd version. But it has been a while since we moved the BIOS tables reading to INIT stage, and iwl_sar_geo_fill_table() is now only copying the previously stored table to the cmd structure. Set the table_revision before the call to iwl_sar_geo_fill_table() and avoid that extra if...else. Signed-off-by: Miri Korenblit Reviewed-by: Gregory Greenman Link: https://msgid.link/20240131091413.17a2384d4535.I306570874f1da0c6345066ebbf74a04b6c8aeb37@changeid Signed-off-by: Johannes Berg --- drivers/net/wireless/intel/iwlwifi/mvm/fw.c | 31 +++++++++-------------------- 1 file changed, 9 insertions(+), 22 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/fw.c b/drivers/net/wireless/intel/iwlwifi/mvm/fw.c index f8ab31f9d109..f964452ba433 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/fw.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/fw.c @@ -1008,7 +1008,7 @@ static int iwl_mvm_sar_geo_init(struct iwl_mvm *mvm) u16 len; u32 n_bands; u32 n_profiles; - u32 sk = 0; + __le32 sk = cpu_to_le32(0); int ret; u8 cmd_ver = iwl_fw_lookup_cmd_ver(mvm->fw, cmd_id, IWL_FW_CMD_VER_UNKNOWN); @@ -1025,23 +1025,31 @@ static int iwl_mvm_sar_geo_init(struct iwl_mvm *mvm) /* the ops field is at the same spot for all versions, so set in v1 */ cmd.v1.ops = cpu_to_le32(IWL_PER_CHAIN_OFFSET_SET_TABLES); + /* Only set to South Korea if the table revision is 1 */ + if (mvm->fwrt.geo_rev == 1) + sk = cpu_to_le32(1); + if (cmd_ver == 5) { len = sizeof(cmd.v5); n_bands = ARRAY_SIZE(cmd.v5.table[0]); n_profiles = BIOS_GEO_MAX_PROFILE_NUM; + cmd.v5.table_revision = sk; } else if (cmd_ver == 4) { len = sizeof(cmd.v4); n_bands = ARRAY_SIZE(cmd.v4.table[0]); n_profiles = BIOS_GEO_MAX_PROFILE_NUM; + cmd.v4.table_revision = sk; } else if (cmd_ver == 3) { len = sizeof(cmd.v3); n_bands = ARRAY_SIZE(cmd.v3.table[0]); n_profiles = BIOS_GEO_MIN_PROFILE_NUM; + cmd.v3.table_revision = sk; } else if (fw_has_api(&mvm->fwrt.fw->ucode_capa, IWL_UCODE_TLV_API_SAR_TABLE_VER)) { len = sizeof(cmd.v2); n_bands = ARRAY_SIZE(cmd.v2.table[0]); n_profiles = BIOS_GEO_MIN_PROFILE_NUM; + cmd.v2.table_revision = sk; } else { len = sizeof(cmd.v1); n_bands = ARRAY_SIZE(cmd.v1.table[0]); @@ -1067,27 +1075,6 @@ static int iwl_mvm_sar_geo_init(struct iwl_mvm *mvm) if (ret) return 0; - /* Only set to South Korea if the table revision is 1 */ - if (mvm->fwrt.geo_rev == 1) - sk = 1; - - /* - * Set the table_revision to South Korea (1) or not (0). The - * element name is misleading, as it doesn't contain the table - * revision number, but whether the South Korea variation - * should be used. - * This must be done after calling iwl_sar_geo_fill_table(). - */ - if (cmd_ver == 5) - cmd.v5.table_revision = cpu_to_le32(sk); - else if (cmd_ver == 4) - cmd.v4.table_revision = cpu_to_le32(sk); - else if (cmd_ver == 3) - cmd.v3.table_revision = cpu_to_le32(sk); - else if (fw_has_api(&mvm->fwrt.fw->ucode_capa, - IWL_UCODE_TLV_API_SAR_TABLE_VER)) - cmd.v2.table_revision = cpu_to_le32(sk); - return iwl_mvm_send_cmd_pdu(mvm, cmd_id, 0, len, &cmd); } -- cgit v1.2.3 From 427661e4c48887ea2a226cd972e574ae7686fb95 Mon Sep 17 00:00:00 2001 From: Miri Korenblit Date: Wed, 31 Jan 2024 10:24:39 +0200 Subject: wifi: iwlwifi: read SAR tables from UEFI All the regulatory tables will be read from UEFI, and only if it doesn't exist - they will be read from ACPI. Read SAR tables (WRDS, EWRD and WGDS) from UEFI. Signed-off-by: Miri Korenblit Reviewed-by: Gregory Greenman Link: https://msgid.link/20240131091413.533b687e1efb.Icb316291e593c8d53f41fdea2d083367dc97e3c4@changeid Signed-off-by: Johannes Berg --- drivers/net/wireless/intel/iwlwifi/fw/acpi.c | 5 +- drivers/net/wireless/intel/iwlwifi/fw/acpi.h | 3 + drivers/net/wireless/intel/iwlwifi/fw/regulatory.c | 17 ++++ drivers/net/wireless/intel/iwlwifi/fw/regulatory.h | 6 ++ drivers/net/wireless/intel/iwlwifi/fw/runtime.h | 4 +- drivers/net/wireless/intel/iwlwifi/fw/uefi.c | 108 +++++++++++++++++++++ drivers/net/wireless/intel/iwlwifi/fw/uefi.h | 77 ++++++++++++++- drivers/net/wireless/intel/iwlwifi/mvm/fw.c | 97 ++++++++---------- drivers/net/wireless/intel/iwlwifi/mvm/mvm.h | 2 +- drivers/net/wireless/intel/iwlwifi/mvm/ops.c | 2 +- 10 files changed, 255 insertions(+), 66 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/intel/iwlwifi/fw/acpi.c b/drivers/net/wireless/intel/iwlwifi/fw/acpi.c index 401aca31704c..4e638287e9a4 100644 --- a/drivers/net/wireless/intel/iwlwifi/fw/acpi.c +++ b/drivers/net/wireless/intel/iwlwifi/fw/acpi.c @@ -622,7 +622,6 @@ out_free: kfree(data); return ret; } -IWL_EXPORT_SYMBOL(iwl_acpi_get_wrds_table); int iwl_acpi_get_ewrd_table(struct iwl_fw_runtime *fwrt) { @@ -731,7 +730,6 @@ out_free: kfree(data); return ret; } -IWL_EXPORT_SYMBOL(iwl_acpi_get_ewrd_table); int iwl_acpi_get_wgds_table(struct iwl_fw_runtime *fwrt) { @@ -748,7 +746,7 @@ int iwl_acpi_get_wgds_table(struct iwl_fw_runtime *fwrt) .revisions = BIT(3), .bands = ACPI_GEO_NUM_BANDS_REV2, .profiles = ACPI_NUM_GEO_PROFILES_REV3, - .min_profiles = 3, + .min_profiles = BIOS_GEO_MIN_PROFILE_NUM, }, { .revisions = BIT(2), @@ -886,7 +884,6 @@ out_free: kfree(data); return ret; } -IWL_EXPORT_SYMBOL(iwl_acpi_get_wgds_table); __le32 iwl_acpi_get_lari_config_bitmap(struct iwl_fw_runtime *fwrt) { diff --git a/drivers/net/wireless/intel/iwlwifi/fw/acpi.h b/drivers/net/wireless/intel/iwlwifi/fw/acpi.h index ba7626543b70..3498deec58a5 100644 --- a/drivers/net/wireless/intel/iwlwifi/fw/acpi.h +++ b/drivers/net/wireless/intel/iwlwifi/fw/acpi.h @@ -105,6 +105,9 @@ #define IWL_SAR_ENABLE_MSK BIT(0) #define IWL_REDUCE_POWER_FLAGS_POS 1 +/* The Inidcator whether UEFI WIFI GUID tables are locked is read from ACPI */ +#define UEFI_WIFI_GUID_UNLOCKED 0 + /* * The profile for revision 2 is a superset of revision 1, which is in * turn a superset of revision 0. So we can store all revisions diff --git a/drivers/net/wireless/intel/iwlwifi/fw/regulatory.c b/drivers/net/wireless/intel/iwlwifi/fw/regulatory.c index 58290bf64f42..862d8b8b0fc9 100644 --- a/drivers/net/wireless/intel/iwlwifi/fw/regulatory.c +++ b/drivers/net/wireless/intel/iwlwifi/fw/regulatory.c @@ -6,6 +6,23 @@ #include "iwl-debug.h" #include "regulatory.h" #include "fw/runtime.h" +#include "fw/uefi.h" + +#define IWL_BIOS_TABLE_LOADER(__name) \ +int iwl_bios_get_ ## __name ## _table(struct iwl_fw_runtime *fwrt) \ +{ \ + int ret = -ENOENT; \ + if (fwrt->uefi_tables_lock_status > UEFI_WIFI_GUID_UNLOCKED) \ + ret = iwl_uefi_get_ ## __name ## _table(fwrt); \ + if (ret < 0) \ + ret = iwl_acpi_get_ ## __name ## _table(fwrt); \ + return ret; \ +} \ +IWL_EXPORT_SYMBOL(iwl_bios_get_ ## __name ## _table) + +IWL_BIOS_TABLE_LOADER(wrds); +IWL_BIOS_TABLE_LOADER(ewrd); +IWL_BIOS_TABLE_LOADER(wgds); bool iwl_sar_geo_support(struct iwl_fw_runtime *fwrt) { diff --git a/drivers/net/wireless/intel/iwlwifi/fw/regulatory.h b/drivers/net/wireless/intel/iwlwifi/fw/regulatory.h index 650430f21510..73c6122e7626 100644 --- a/drivers/net/wireless/intel/iwlwifi/fw/regulatory.h +++ b/drivers/net/wireless/intel/iwlwifi/fw/regulatory.h @@ -87,4 +87,10 @@ int iwl_sar_fill_profile(struct iwl_fw_runtime *fwrt, __le16 *per_chain, u32 n_tables, u32 n_subbands, int prof_a, int prof_b); +int iwl_bios_get_wrds_table(struct iwl_fw_runtime *fwrt); + +int iwl_bios_get_ewrd_table(struct iwl_fw_runtime *fwrt); + +int iwl_bios_get_wgds_table(struct iwl_fw_runtime *fwrt); + #endif /* __fw_regulatory_h__ */ diff --git a/drivers/net/wireless/intel/iwlwifi/fw/runtime.h b/drivers/net/wireless/intel/iwlwifi/fw/runtime.h index 08734f48443e..e55248b6b4c2 100644 --- a/drivers/net/wireless/intel/iwlwifi/fw/runtime.h +++ b/drivers/net/wireless/intel/iwlwifi/fw/runtime.h @@ -164,21 +164,21 @@ struct iwl_fw_runtime { #ifdef CONFIG_IWLWIFI_DEBUGFS bool tpc_enabled; #endif /* CONFIG_IWLWIFI_DEBUGFS */ -#ifdef CONFIG_ACPI struct iwl_sar_profile sar_profiles[BIOS_SAR_MAX_PROFILE_NUM]; u8 sar_chain_a_profile; u8 sar_chain_b_profile; + u8 reduced_power_flags; struct iwl_geo_profile geo_profiles[BIOS_GEO_MAX_PROFILE_NUM]; u32 geo_rev; u32 geo_num_profiles; bool geo_enabled; +#ifdef CONFIG_ACPI struct iwl_ppag_chain ppag_chains[IWL_NUM_CHAIN_LIMITS]; u32 ppag_flags; u32 ppag_ver; bool ppag_table_valid; struct iwl_sar_offset_mapping_cmd sgom_table; bool sgom_enabled; - u8 reduced_power_flags; struct iwl_uats_table_cmd uats_table; u8 uefi_tables_lock_status; #endif diff --git a/drivers/net/wireless/intel/iwlwifi/fw/uefi.c b/drivers/net/wireless/intel/iwlwifi/fw/uefi.c index 9c432d7b3674..a777cd4c70f7 100644 --- a/drivers/net/wireless/intel/iwlwifi/fw/uefi.c +++ b/drivers/net/wireless/intel/iwlwifi/fw/uefi.c @@ -413,3 +413,111 @@ int iwl_uefi_get_uats_table(struct iwl_trans *trans, } IWL_EXPORT_SYMBOL(iwl_uefi_get_uats_table); #endif /* CONFIG_ACPI */ + +static void iwl_uefi_set_sar_profile(struct iwl_fw_runtime *fwrt, + struct uefi_sar_profile *uefi_sar_prof, + u8 prof_index, bool enabled) +{ + memcpy(&fwrt->sar_profiles[prof_index].chains, uefi_sar_prof, + sizeof(struct uefi_sar_profile)); + + fwrt->sar_profiles[prof_index].enabled = enabled & IWL_SAR_ENABLE_MSK; +} + +int iwl_uefi_get_wrds_table(struct iwl_fw_runtime *fwrt) +{ + struct uefi_cnv_var_wrds *data; + int ret = 0; + + data = iwl_uefi_get_verified_variable(fwrt->trans, IWL_UEFI_WRDS_NAME, + "WRDS", sizeof(*data), NULL); + if (IS_ERR(data)) + return -EINVAL; + + if (data->revision != IWL_UEFI_WRDS_REVISION) { + ret = -EINVAL; + IWL_DEBUG_RADIO(fwrt, "Unsupported UEFI WRDS revision:%d\n", + data->revision); + goto out; + } + + /* The profile from WRDS is officially profile 1, but goes + * into sar_profiles[0] (because we don't have a profile 0). + */ + iwl_uefi_set_sar_profile(fwrt, &data->sar_profile, 0, data->mode); +out: + kfree(data); + return ret; +} + +int iwl_uefi_get_ewrd_table(struct iwl_fw_runtime *fwrt) +{ + struct uefi_cnv_var_ewrd *data; + int i, ret = 0; + + data = iwl_uefi_get_verified_variable(fwrt->trans, IWL_UEFI_EWRD_NAME, + "EWRD", sizeof(*data), NULL); + if (IS_ERR(data)) + return -EINVAL; + + if (data->revision != IWL_UEFI_EWRD_REVISION) { + ret = -EINVAL; + IWL_DEBUG_RADIO(fwrt, "Unsupported UEFI EWRD revision:%d\n", + data->revision); + goto out; + } + + if (data->num_profiles >= BIOS_SAR_MAX_PROFILE_NUM) { + ret = -EINVAL; + goto out; + } + + for (i = 0; i < data->num_profiles; i++) + /* The EWRD profiles officially go from 2 to 4, but we + * save them in sar_profiles[1-3] (because we don't + * have profile 0). So in the array we start from 1. + */ + iwl_uefi_set_sar_profile(fwrt, &data->sar_profiles[i], i + 1, + data->mode); + +out: + kfree(data); + return ret; +} + +int iwl_uefi_get_wgds_table(struct iwl_fw_runtime *fwrt) +{ + struct uefi_cnv_var_wgds *data; + int i, ret = 0; + + data = iwl_uefi_get_verified_variable(fwrt->trans, IWL_UEFI_WGDS_NAME, + "WGDS", sizeof(*data), NULL); + if (IS_ERR(data)) + return -EINVAL; + + if (data->revision != IWL_UEFI_WGDS_REVISION) { + ret = -EINVAL; + IWL_DEBUG_RADIO(fwrt, "Unsupported UEFI WGDS revision:%d\n", + data->revision); + goto out; + } + + if (data->num_profiles < BIOS_GEO_MIN_PROFILE_NUM || + data->num_profiles > BIOS_GEO_MAX_PROFILE_NUM) { + ret = -EINVAL; + IWL_DEBUG_RADIO(fwrt, "Invalid number of profiles in WGDS: %d\n", + data->num_profiles); + goto out; + } + + fwrt->geo_rev = data->revision; + for (i = 0; i < data->num_profiles; i++) + memcpy(&fwrt->geo_profiles[i], &data->geo_profiles[i], + sizeof(struct iwl_geo_profile)); + + fwrt->geo_num_profiles = data->num_profiles; + fwrt->geo_enabled = true; +out: + kfree(data); + return ret; +} diff --git a/drivers/net/wireless/intel/iwlwifi/fw/uefi.h b/drivers/net/wireless/intel/iwlwifi/fw/uefi.h index bf61a8df1225..3141fca047c6 100644 --- a/drivers/net/wireless/intel/iwlwifi/fw/uefi.h +++ b/drivers/net/wireless/intel/iwlwifi/fw/uefi.h @@ -5,15 +5,24 @@ #ifndef __iwl_fw_uefi__ #define __iwl_fw_uefi__ +#include "fw/regulatory.h" + #define IWL_UEFI_OEM_PNVM_NAME L"UefiCnvWlanOemSignedPnvm" #define IWL_UEFI_REDUCED_POWER_NAME L"UefiCnvWlanReducedPower" #define IWL_UEFI_SGOM_NAME L"UefiCnvWlanSarGeoOffsetMapping" #define IWL_UEFI_STEP_NAME L"UefiCnvCommonSTEP" #define IWL_UEFI_UATS_NAME L"CnvUefiWlanUATS" +#define IWL_UEFI_WRDS_NAME L"UefiCnvWlanWRDS" +#define IWL_UEFI_EWRD_NAME L"UefiCnvWlanEWRD" +#define IWL_UEFI_WGDS_NAME L"UefiCnvWlanWGDS" #define IWL_SGOM_MAP_SIZE 339 #define IWL_UATS_MAP_SIZE 339 +#define IWL_UEFI_WRDS_REVISION 2 +#define IWL_UEFI_EWRD_REVISION 2 +#define IWL_UEFI_WGDS_REVISION 3 + struct pnvm_sku_package { u8 rev; u32 total_size; @@ -41,6 +50,55 @@ struct uefi_cnv_common_step_data { u8 radio2; } __packed; +/* + * struct uefi_sar_profile - a SAR profile as defined in UEFI + * + * @chains: a per-chain table of SAR values + */ +struct uefi_sar_profile { + struct iwl_sar_profile_chain chains[BIOS_SAR_MAX_CHAINS_PER_PROFILE]; +} __packed; + +/* + * struct uefi_cnv_var_wrds - WRDS table as defined in UEFI + * + * @revision: the revision of the table + * @mode: is WRDS enbaled/disabled + * @sar_profile: sar profile #1 + */ +struct uefi_cnv_var_wrds { + u8 revision; + u32 mode; + struct uefi_sar_profile sar_profile; +} __packed; + +/* + * struct uefi_cnv_var_ewrd - EWRD table as defined in UEFI + * @revision: the revision of the table + * @mode: is WRDS enbaled/disabled + * @num_profiles: how many additional profiles we have in this table (0-3) + * @sar_profiles: the additional SAR profiles (#2-#4) + */ +struct uefi_cnv_var_ewrd { + u8 revision; + u32 mode; + u32 num_profiles; + struct uefi_sar_profile sar_profiles[BIOS_SAR_MAX_PROFILE_NUM - 1]; +} __packed; + +/* + * struct uefi_cnv_var_wgds - WGDS table as defined in UEFI + * @revision: the revision of the table + * @num_profiles: the number of geo profiles we have in the table. + * The first 3 are mandatory, and can have up to 8. + * @geo_profiles: a per-profile table of the offsets to add to SAR values. + */ +struct uefi_cnv_var_wgds { + u8 revision; + u8 num_profiles; + struct iwl_geo_profile geo_profiles[BIOS_GEO_MAX_PROFILE_NUM]; +} __packed; + /* * This is known to be broken on v4.19 and to work on v5.4. Until we * figure out why this is the case and how to make it work, simply @@ -55,6 +113,9 @@ int iwl_uefi_reduce_power_parse(struct iwl_trans *trans, void iwl_uefi_get_step_table(struct iwl_trans *trans); int iwl_uefi_handle_tlv_mem_desc(struct iwl_trans *trans, const u8 *data, u32 tlv_len, struct iwl_pnvm_image *pnvm_data); +int iwl_uefi_get_wrds_table(struct iwl_fw_runtime *fwrt); +int iwl_uefi_get_ewrd_table(struct iwl_fw_runtime *fwrt); +int iwl_uefi_get_wgds_table(struct iwl_fw_runtime *fwrt); #else /* CONFIG_EFI */ static inline void *iwl_uefi_get_pnvm(struct iwl_trans *trans, size_t *len) { @@ -85,6 +146,21 @@ iwl_uefi_handle_tlv_mem_desc(struct iwl_trans *trans, const u8 *data, { return 0; } + +static inline int iwl_uefi_get_wrds_table(struct iwl_fw_runtime *fwrt) +{ + return -ENOENT; +} + +static inline int iwl_uefi_get_ewrd_table(struct iwl_fw_runtime *fwrt) +{ + return -ENOENT; +} + +static inline int iwl_uefi_get_wgds_table(struct iwl_fw_runtime *fwrt) +{ + return -ENOENT; +} #endif /* CONFIG_EFI */ #if defined(CONFIG_EFI) && defined(CONFIG_ACPI) @@ -103,6 +179,5 @@ int iwl_uefi_get_uats_table(struct iwl_trans *trans, { return 0; } - #endif #endif /* __iwl_fw_uefi__ */ diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/fw.c b/drivers/net/wireless/intel/iwlwifi/mvm/fw.c index f964452ba433..c2267e0bd08e 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/fw.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/fw.c @@ -16,6 +16,7 @@ #include "fw/acpi.h" #include "fw/pnvm.h" #include "fw/uefi.h" +#include "fw/regulatory.h" #include "mvm.h" #include "fw/dbg.h" @@ -895,7 +896,6 @@ static int iwl_mvm_config_ltr(struct iwl_mvm *mvm) sizeof(cmd), &cmd); } -#ifdef CONFIG_ACPI int iwl_mvm_sar_select_profile(struct iwl_mvm *mvm, int prof_a, int prof_b) { u32 cmd_id = REDUCE_TX_POWER_CMD; @@ -1078,6 +1078,8 @@ static int iwl_mvm_sar_geo_init(struct iwl_mvm *mvm) return iwl_mvm_send_cmd_pdu(mvm, cmd_id, 0, len, &cmd); } +#ifdef CONFIG_ACPI + int iwl_mvm_ppag_send_cmd(struct iwl_mvm *mvm) { union iwl_ppag_table_cmd cmd; @@ -1385,7 +1387,39 @@ static void iwl_mvm_lari_cfg(struct iwl_mvm *mvm) mvm->fwrt.uats_enabled = TRUE; } -void iwl_mvm_get_acpi_tables(struct iwl_mvm *mvm) +#else /* CONFIG_ACPI */ + +int iwl_mvm_ppag_send_cmd(struct iwl_mvm *mvm) +{ + return -ENOENT; +} + +static int iwl_mvm_ppag_init(struct iwl_mvm *mvm) +{ + return 0; +} + +static void iwl_mvm_tas_init(struct iwl_mvm *mvm) +{ +} + +static void iwl_mvm_lari_cfg(struct iwl_mvm *mvm) +{ +} + +bool iwl_mvm_is_vendor_in_approved_list(void) +{ + return false; +} + +static u8 iwl_mvm_eval_dsm_rfi(struct iwl_mvm *mvm) +{ + return DSM_VALUE_RFI_DISABLE; +} + +#endif /* CONFIG_ACPI */ + +void iwl_mvm_get_bios_tables(struct iwl_mvm *mvm) { int ret; @@ -1400,7 +1434,7 @@ void iwl_mvm_get_acpi_tables(struct iwl_mvm *mvm) } /* read SAR tables */ - ret = iwl_acpi_get_wrds_table(&mvm->fwrt); + ret = iwl_bios_get_wrds_table(&mvm->fwrt); if (ret < 0) { IWL_DEBUG_RADIO(mvm, "WRDS SAR BIOS table invalid or unavailable. (%d)\n", @@ -1409,7 +1443,7 @@ void iwl_mvm_get_acpi_tables(struct iwl_mvm *mvm) * If not available, don't fail and don't bother with EWRD and * WGDS */ - if (!iwl_acpi_get_wgds_table(&mvm->fwrt)) { + if (!iwl_bios_get_wgds_table(&mvm->fwrt)) { /* * If basic SAR is not available, we check for WGDS, * which should *not* be available either. If it is @@ -1420,7 +1454,7 @@ void iwl_mvm_get_acpi_tables(struct iwl_mvm *mvm) } } else { - ret = iwl_acpi_get_ewrd_table(&mvm->fwrt); + ret = iwl_bios_get_ewrd_table(&mvm->fwrt); /* if EWRD is not available, we can still use * WRDS, so don't fail */ if (ret < 0) @@ -1430,7 +1464,7 @@ void iwl_mvm_get_acpi_tables(struct iwl_mvm *mvm) /* read geo SAR table */ if (iwl_sar_geo_support(&mvm->fwrt)) { - ret = iwl_acpi_get_wgds_table(&mvm->fwrt); + ret = iwl_bios_get_wgds_table(&mvm->fwrt); if (ret < 0) IWL_DEBUG_RADIO(mvm, "Geo SAR BIOS table invalid or unavailable. (%d)\n", @@ -1441,57 +1475,6 @@ void iwl_mvm_get_acpi_tables(struct iwl_mvm *mvm) iwl_acpi_get_phy_filters(&mvm->fwrt, &mvm->phy_filters); } -#else /* CONFIG_ACPI */ - -inline int iwl_mvm_sar_select_profile(struct iwl_mvm *mvm, - int prof_a, int prof_b) -{ - return 1; -} - -inline int iwl_mvm_get_sar_geo_profile(struct iwl_mvm *mvm) -{ - return -ENOENT; -} - -static int iwl_mvm_sar_geo_init(struct iwl_mvm *mvm) -{ - return 0; -} - -int iwl_mvm_ppag_send_cmd(struct iwl_mvm *mvm) -{ - return -ENOENT; -} - -static int iwl_mvm_ppag_init(struct iwl_mvm *mvm) -{ - return 0; -} - -static void iwl_mvm_tas_init(struct iwl_mvm *mvm) -{ -} - -static void iwl_mvm_lari_cfg(struct iwl_mvm *mvm) -{ -} - -bool iwl_mvm_is_vendor_in_approved_list(void) -{ - return false; -} - -static u8 iwl_mvm_eval_dsm_rfi(struct iwl_mvm *mvm) -{ - return DSM_VALUE_RFI_DISABLE; -} - -void iwl_mvm_get_acpi_tables(struct iwl_mvm *mvm) -{ -} - -#endif /* CONFIG_ACPI */ static void iwl_mvm_disconnect_iterator(void *data, u8 *mac, struct ieee80211_vif *vif) diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h b/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h index d414007c4755..14f4cf8a67c7 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h +++ b/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h @@ -2381,7 +2381,7 @@ u64 iwl_mvm_ptp_get_adj_time(struct iwl_mvm *mvm, u64 base_time); int iwl_mvm_sar_select_profile(struct iwl_mvm *mvm, int prof_a, int prof_b); int iwl_mvm_get_sar_geo_profile(struct iwl_mvm *mvm); int iwl_mvm_ppag_send_cmd(struct iwl_mvm *mvm); -void iwl_mvm_get_acpi_tables(struct iwl_mvm *mvm); +void iwl_mvm_get_bios_tables(struct iwl_mvm *mvm); #ifdef CONFIG_IWLWIFI_DEBUGFS void iwl_mvm_link_sta_add_debugfs(struct ieee80211_hw *hw, struct ieee80211_vif *vif, diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/ops.c b/drivers/net/wireless/intel/iwlwifi/mvm/ops.c index 20054a0c7892..1b41318e1e55 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/ops.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/ops.c @@ -1201,7 +1201,7 @@ iwl_op_mode_mvm_start(struct iwl_trans *trans, const struct iwl_cfg *cfg, iwl_fw_runtime_init(&mvm->fwrt, trans, fw, &iwl_mvm_fwrt_ops, mvm, &iwl_mvm_sanitize_ops, mvm, dbgfs_dir); - iwl_mvm_get_acpi_tables(mvm); + iwl_mvm_get_bios_tables(mvm); iwl_uefi_get_sgom_table(trans, &mvm->fwrt); iwl_uefi_get_step_table(trans); -- cgit v1.2.3 From be3a8cbb1ca7d6737bfff9ea9ca260958f4bf6f0 Mon Sep 17 00:00:00 2001 From: Miri Korenblit Date: Wed, 31 Jan 2024 10:24:40 +0200 Subject: wifi: iwlwifi: small cleanups in PPAG table flows 1. The name of iwl_read_ppag_table is misleading, as this function only fills the command structure from the previously read table. Rename it. 2. Don't initialize fwrt::ppag_flags to 0 as the entire fwrt is zeroed in the INIT stage anyway. 3. Don't filter out the reserved bits from fwrt::ppag_flags when printing it, as it is already done in 'read-from-bios' flow. Signed-off-by: Miri Korenblit Reviewed-by: Gregory Greenman Link: https://msgid.link/20240131091413.48acf340e817.I810e457b80015c1931d96d3e13c849f0339723c3@changeid Signed-off-by: Johannes Berg --- drivers/net/wireless/intel/iwlwifi/fw/acpi.c | 10 +++++----- drivers/net/wireless/intel/iwlwifi/fw/acpi.h | 8 +++++--- drivers/net/wireless/intel/iwlwifi/mvm/fw.c | 2 +- 3 files changed, 11 insertions(+), 9 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/intel/iwlwifi/fw/acpi.c b/drivers/net/wireless/intel/iwlwifi/fw/acpi.c index 4e638287e9a4..d2689d93da0c 100644 --- a/drivers/net/wireless/intel/iwlwifi/fw/acpi.c +++ b/drivers/net/wireless/intel/iwlwifi/fw/acpi.c @@ -956,7 +956,6 @@ int iwl_acpi_get_ppag_table(struct iwl_fw_runtime *fwrt) int idx = 2; u8 cmd_ver; - fwrt->ppag_flags = 0; fwrt->ppag_table_valid = false; data = iwl_acpi_get_object(fwrt->dev, ACPI_PPAG_METHOD); @@ -1057,7 +1056,8 @@ out_free: } IWL_EXPORT_SYMBOL(iwl_acpi_get_ppag_table); -int iwl_read_ppag_table(struct iwl_fw_runtime *fwrt, union iwl_ppag_table_cmd *cmd, +int iwl_fill_ppag_table(struct iwl_fw_runtime *fwrt, + union iwl_ppag_table_cmd *cmd, int *cmd_size) { u8 cmd_ver; @@ -1117,7 +1117,7 @@ int iwl_read_ppag_table(struct iwl_fw_runtime *fwrt, union iwl_ppag_table_cmd *c /* ppag mode */ IWL_DEBUG_RADIO(fwrt, "PPAG MODE bits were read from bios: %d\n", - cmd->v1.flags & cpu_to_le32(ACPI_PPAG_MASK)); + cmd->v1.flags); if ((cmd_ver == 1 && !fw_has_capa(&fwrt->fw->ucode_capa, IWL_UCODE_TLV_CAPA_PPAG_CHINA_BIOS_SUPPORT)) || (cmd_ver == 2 && fwrt->ppag_ver == 2)) { @@ -1129,7 +1129,7 @@ int iwl_read_ppag_table(struct iwl_fw_runtime *fwrt, union iwl_ppag_table_cmd *c IWL_DEBUG_RADIO(fwrt, "PPAG MODE bits going to be sent: %d\n", - cmd->v1.flags & cpu_to_le32(ACPI_PPAG_MASK)); + cmd->v1.flags); for (i = 0; i < IWL_NUM_CHAIN_LIMITS; i++) { for (j = 0; j < num_sub_bands; j++) { @@ -1143,7 +1143,7 @@ int iwl_read_ppag_table(struct iwl_fw_runtime *fwrt, union iwl_ppag_table_cmd *c return 0; } -IWL_EXPORT_SYMBOL(iwl_read_ppag_table); +IWL_EXPORT_SYMBOL(iwl_fill_ppag_table); bool iwl_acpi_is_ppag_approved(struct iwl_fw_runtime *fwrt) { diff --git a/drivers/net/wireless/intel/iwlwifi/fw/acpi.h b/drivers/net/wireless/intel/iwlwifi/fw/acpi.h index 3498deec58a5..ef927d74bc7c 100644 --- a/drivers/net/wireless/intel/iwlwifi/fw/acpi.h +++ b/drivers/net/wireless/intel/iwlwifi/fw/acpi.h @@ -207,7 +207,8 @@ __le32 iwl_acpi_get_lari_config_bitmap(struct iwl_fw_runtime *fwrt); int iwl_acpi_get_ppag_table(struct iwl_fw_runtime *fwrt); -int iwl_read_ppag_table(struct iwl_fw_runtime *fwrt, union iwl_ppag_table_cmd *cmd, +int iwl_fill_ppag_table(struct iwl_fw_runtime *fwrt, + union iwl_ppag_table_cmd *cmd, int *cmd_size); bool iwl_acpi_is_ppag_approved(struct iwl_fw_runtime *fwrt); @@ -283,8 +284,9 @@ static inline int iwl_acpi_get_ppag_table(struct iwl_fw_runtime *fwrt) return -ENOENT; } -static inline int iwl_read_ppag_table(struct iwl_fw_runtime *fwrt, - union iwl_ppag_table_cmd *cmd, int *cmd_size) +static inline int iwl_fill_ppag_table(struct iwl_fw_runtime *fwrt, + union iwl_ppag_table_cmd *cmd, + int *cmd_size) { return -ENOENT; } diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/fw.c b/drivers/net/wireless/intel/iwlwifi/mvm/fw.c index c2267e0bd08e..d52fc3119972 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/fw.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/fw.c @@ -1085,7 +1085,7 @@ int iwl_mvm_ppag_send_cmd(struct iwl_mvm *mvm) union iwl_ppag_table_cmd cmd; int ret, cmd_size; - ret = iwl_read_ppag_table(&mvm->fwrt, &cmd, &cmd_size); + ret = iwl_fill_ppag_table(&mvm->fwrt, &cmd, &cmd_size); /* Not supporting PPAG table is a valid scenario */ if (ret < 0) return 0; -- cgit v1.2.3 From 09059c6764a8870ff7515c2d78ecbea7fbcffc23 Mon Sep 17 00:00:00 2001 From: Miri Korenblit Date: Wed, 31 Jan 2024 10:24:41 +0200 Subject: wifi: iwlwifi: prepare for reading PPAG table from UEFI As PPAG table is going to be read from UEFI, there are some cleanups required: Move functions/definitions that are common to both UEFI and ACPI to regulatory.h/c. In addition, rename the functions/macros names so it will be clear which one is ACPI specific, and which is common for ACPI and UEFI. Signed-off-by: Miri Korenblit Reviewed-by: Gregory Greenman Link: https://msgid.link/20240131091413.25623670b422.I8132af7517e4faf0ea8cbeb2efe9651edd319b98@changeid Signed-off-by: Johannes Berg --- drivers/net/wireless/intel/iwlwifi/fw/acpi.c | 172 +-------------------- drivers/net/wireless/intel/iwlwifi/fw/acpi.h | 35 ----- drivers/net/wireless/intel/iwlwifi/fw/regulatory.c | 161 +++++++++++++++++++ drivers/net/wireless/intel/iwlwifi/fw/regulatory.h | 20 +++ drivers/net/wireless/intel/iwlwifi/mvm/fw.c | 2 +- 5 files changed, 187 insertions(+), 203 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/intel/iwlwifi/fw/acpi.c b/drivers/net/wireless/intel/iwlwifi/fw/acpi.c index d2689d93da0c..9b0ecfc087ab 100644 --- a/drivers/net/wireless/intel/iwlwifi/fw/acpi.c +++ b/drivers/net/wireless/intel/iwlwifi/fw/acpi.c @@ -4,7 +4,6 @@ * Copyright (C) 2019-2023 Intel Corporation */ #include -#include #include "iwl-drv.h" #include "iwl-debug.h" #include "acpi.h" @@ -20,63 +19,6 @@ const guid_t iwl_rfi_guid = GUID_INIT(0x7266172C, 0x220B, 0x4B29, 0xDD, 0x26, 0xB5, 0xFD); IWL_EXPORT_SYMBOL(iwl_rfi_guid); -static const struct dmi_system_id dmi_ppag_approved_list[] = { - { .ident = "HP", - .matches = { - DMI_MATCH(DMI_SYS_VENDOR, "HP"), - }, - }, - { .ident = "SAMSUNG", - .matches = { - DMI_MATCH(DMI_SYS_VENDOR, "SAMSUNG ELECTRONICS CO., LTD"), - }, - }, - { .ident = "MSFT", - .matches = { - DMI_MATCH(DMI_SYS_VENDOR, "Microsoft Corporation"), - }, - }, - { .ident = "ASUS", - .matches = { - DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."), - }, - }, - { .ident = "GOOGLE-HP", - .matches = { - DMI_MATCH(DMI_SYS_VENDOR, "Google"), - DMI_MATCH(DMI_BOARD_VENDOR, "HP"), - }, - }, - { .ident = "GOOGLE-ASUS", - .matches = { - DMI_MATCH(DMI_SYS_VENDOR, "Google"), - DMI_MATCH(DMI_BOARD_VENDOR, "ASUSTek COMPUTER INC."), - }, - }, - { .ident = "GOOGLE-SAMSUNG", - .matches = { - DMI_MATCH(DMI_SYS_VENDOR, "Google"), - DMI_MATCH(DMI_BOARD_VENDOR, "SAMSUNG ELECTRONICS CO., LTD"), - }, - }, - { .ident = "DELL", - .matches = { - DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."), - }, - }, - { .ident = "DELL", - .matches = { - DMI_MATCH(DMI_SYS_VENDOR, "Alienware"), - }, - }, - { .ident = "RAZER", - .matches = { - DMI_MATCH(DMI_SYS_VENDOR, "Razer"), - }, - }, - {} -}; - static int iwl_acpi_get_handle(struct device *dev, acpi_string method, acpi_handle *ret_handle) { @@ -1002,7 +944,7 @@ read_table: goto out_free; } - fwrt->ppag_flags = flags->integer.value & ACPI_PPAG_MASK; + fwrt->ppag_flags = flags->integer.value & IWL_PPAG_ETSI_CHINA_MASK; cmd_ver = iwl_fw_lookup_cmd_ver(fwrt->fw, WIDE_ID(PHY_OPS_GROUP, PER_PLATFORM_ANT_GAIN_CMD), @@ -1036,11 +978,11 @@ read_table: if (cmd_ver >= 4) continue; if ((j == 0 && - (fwrt->ppag_chains[i].subbands[j] > ACPI_PPAG_MAX_LB || - fwrt->ppag_chains[i].subbands[j] < ACPI_PPAG_MIN_LB)) || + (fwrt->ppag_chains[i].subbands[j] > IWL_PPAG_MAX_LB || + fwrt->ppag_chains[i].subbands[j] < IWL_PPAG_MIN_LB)) || (j != 0 && - (fwrt->ppag_chains[i].subbands[j] > ACPI_PPAG_MAX_HB || - fwrt->ppag_chains[i].subbands[j] < ACPI_PPAG_MIN_HB))) { + (fwrt->ppag_chains[i].subbands[j] > IWL_PPAG_MAX_HB || + fwrt->ppag_chains[i].subbands[j] < IWL_PPAG_MIN_HB))) { ret = -EINVAL; goto out_free; } @@ -1056,110 +998,6 @@ out_free: } IWL_EXPORT_SYMBOL(iwl_acpi_get_ppag_table); -int iwl_fill_ppag_table(struct iwl_fw_runtime *fwrt, - union iwl_ppag_table_cmd *cmd, - int *cmd_size) -{ - u8 cmd_ver; - int i, j, num_sub_bands; - s8 *gain; - - /* many firmware images for JF lie about this */ - if (CSR_HW_RFID_TYPE(fwrt->trans->hw_rf_id) == - CSR_HW_RFID_TYPE(CSR_HW_RF_ID_TYPE_JF)) - return -EOPNOTSUPP; - - if (!fw_has_capa(&fwrt->fw->ucode_capa, IWL_UCODE_TLV_CAPA_SET_PPAG)) { - IWL_DEBUG_RADIO(fwrt, - "PPAG capability not supported by FW, command not sent.\n"); - return -EINVAL; - } - - cmd_ver = iwl_fw_lookup_cmd_ver(fwrt->fw, - WIDE_ID(PHY_OPS_GROUP, - PER_PLATFORM_ANT_GAIN_CMD), - IWL_FW_CMD_VER_UNKNOWN); - if (!fwrt->ppag_table_valid || (cmd_ver <= 3 && !fwrt->ppag_flags)) { - IWL_DEBUG_RADIO(fwrt, "PPAG not enabled, command not sent.\n"); - return -EINVAL; - } - - /* The 'flags' field is the same in v1 and in v2 so we can just - * use v1 to access it. - */ - cmd->v1.flags = cpu_to_le32(fwrt->ppag_flags); - - IWL_DEBUG_RADIO(fwrt, "PPAG cmd ver is %d\n", cmd_ver); - if (cmd_ver == 1) { - num_sub_bands = IWL_NUM_SUB_BANDS_V1; - gain = cmd->v1.gain[0]; - *cmd_size = sizeof(cmd->v1); - if (fwrt->ppag_ver == 1 || fwrt->ppag_ver == 2) { - /* in this case FW supports revision 0 */ - IWL_DEBUG_RADIO(fwrt, - "PPAG table rev is %d, send truncated table\n", - fwrt->ppag_ver); - } - } else if (cmd_ver >= 2 && cmd_ver <= 4) { - num_sub_bands = IWL_NUM_SUB_BANDS_V2; - gain = cmd->v2.gain[0]; - *cmd_size = sizeof(cmd->v2); - if (fwrt->ppag_ver == 0) { - /* in this case FW supports revisions 1 or 2 */ - IWL_DEBUG_RADIO(fwrt, - "PPAG table rev is 0, send padded table\n"); - } - } else { - IWL_DEBUG_RADIO(fwrt, "Unsupported PPAG command version\n"); - return -EINVAL; - } - - /* ppag mode */ - IWL_DEBUG_RADIO(fwrt, - "PPAG MODE bits were read from bios: %d\n", - cmd->v1.flags); - if ((cmd_ver == 1 && !fw_has_capa(&fwrt->fw->ucode_capa, - IWL_UCODE_TLV_CAPA_PPAG_CHINA_BIOS_SUPPORT)) || - (cmd_ver == 2 && fwrt->ppag_ver == 2)) { - cmd->v1.flags &= cpu_to_le32(IWL_PPAG_ETSI_MASK); - IWL_DEBUG_RADIO(fwrt, "masking ppag China bit\n"); - } else { - IWL_DEBUG_RADIO(fwrt, "isn't masking ppag China bit\n"); - } - - IWL_DEBUG_RADIO(fwrt, - "PPAG MODE bits going to be sent: %d\n", - cmd->v1.flags); - - for (i = 0; i < IWL_NUM_CHAIN_LIMITS; i++) { - for (j = 0; j < num_sub_bands; j++) { - gain[i * num_sub_bands + j] = - fwrt->ppag_chains[i].subbands[j]; - IWL_DEBUG_RADIO(fwrt, - "PPAG table: chain[%d] band[%d]: gain = %d\n", - i, j, gain[i * num_sub_bands + j]); - } - } - - return 0; -} -IWL_EXPORT_SYMBOL(iwl_fill_ppag_table); - -bool iwl_acpi_is_ppag_approved(struct iwl_fw_runtime *fwrt) -{ - - if (!dmi_check_system(dmi_ppag_approved_list)) { - IWL_DEBUG_RADIO(fwrt, - "System vendor '%s' is not in the approved list, disabling PPAG.\n", - dmi_get_system_info(DMI_SYS_VENDOR)); - fwrt->ppag_flags = 0; - return false; - } - - return true; -} -IWL_EXPORT_SYMBOL(iwl_acpi_is_ppag_approved); - void iwl_acpi_get_phy_filters(struct iwl_fw_runtime *fwrt, struct iwl_phy_specific_cfg *filters) { diff --git a/drivers/net/wireless/intel/iwlwifi/fw/acpi.h b/drivers/net/wireless/intel/iwlwifi/fw/acpi.h index ef927d74bc7c..ca3587e9f856 100644 --- a/drivers/net/wireless/intel/iwlwifi/fw/acpi.h +++ b/drivers/net/wireless/intel/iwlwifi/fw/acpi.h @@ -94,29 +94,12 @@ #define ACPI_PPAG_WIFI_DATA_SIZE_V2 ((IWL_NUM_CHAIN_LIMITS * \ IWL_NUM_SUB_BANDS_V2) + 2) -/* PPAG gain value bounds in 1/8 dBm */ -#define ACPI_PPAG_MIN_LB -16 -#define ACPI_PPAG_MAX_LB 24 -#define ACPI_PPAG_MIN_HB -16 -#define ACPI_PPAG_MAX_HB 40 -#define ACPI_PPAG_MASK 3 -#define IWL_PPAG_ETSI_MASK BIT(0) - #define IWL_SAR_ENABLE_MSK BIT(0) #define IWL_REDUCE_POWER_FLAGS_POS 1 /* The Inidcator whether UEFI WIFI GUID tables are locked is read from ACPI */ #define UEFI_WIFI_GUID_UNLOCKED 0 -/* - * The profile for revision 2 is a superset of revision 1, which is in - * turn a superset of revision 0. So we can store all revisions - * inside revision 2, which is what we represent here. - */ -struct iwl_ppag_chain { - s8 subbands[ACPI_SAR_NUM_SUB_BANDS_REV2]; -}; - enum iwl_dsm_funcs_rev_0 { DSM_FUNC_QUERY = 0, DSM_FUNC_DISABLE_SRD = 1, @@ -207,12 +190,6 @@ __le32 iwl_acpi_get_lari_config_bitmap(struct iwl_fw_runtime *fwrt); int iwl_acpi_get_ppag_table(struct iwl_fw_runtime *fwrt); -int iwl_fill_ppag_table(struct iwl_fw_runtime *fwrt, - union iwl_ppag_table_cmd *cmd, - int *cmd_size); - -bool iwl_acpi_is_ppag_approved(struct iwl_fw_runtime *fwrt); - void iwl_acpi_get_phy_filters(struct iwl_fw_runtime *fwrt, struct iwl_phy_specific_cfg *filters); @@ -284,18 +261,6 @@ static inline int iwl_acpi_get_ppag_table(struct iwl_fw_runtime *fwrt) return -ENOENT; } -static inline int iwl_fill_ppag_table(struct iwl_fw_runtime *fwrt, - union iwl_ppag_table_cmd *cmd, - int *cmd_size) -{ - return -ENOENT; -} - -static inline bool iwl_acpi_is_ppag_approved(struct iwl_fw_runtime *fwrt) -{ - return false; -} - static inline void iwl_acpi_get_phy_filters(struct iwl_fw_runtime *fwrt, struct iwl_phy_specific_cfg *filters) { diff --git a/drivers/net/wireless/intel/iwlwifi/fw/regulatory.c b/drivers/net/wireless/intel/iwlwifi/fw/regulatory.c index 862d8b8b0fc9..2393c8a8e288 100644 --- a/drivers/net/wireless/intel/iwlwifi/fw/regulatory.c +++ b/drivers/net/wireless/intel/iwlwifi/fw/regulatory.c @@ -2,6 +2,7 @@ /* * Copyright (C) 2023 Intel Corporation */ +#include #include "iwl-drv.h" #include "iwl-debug.h" #include "regulatory.h" @@ -24,6 +25,63 @@ IWL_BIOS_TABLE_LOADER(wrds); IWL_BIOS_TABLE_LOADER(ewrd); IWL_BIOS_TABLE_LOADER(wgds); +static const struct dmi_system_id dmi_ppag_approved_list[] = { + { .ident = "HP", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "HP"), + }, + }, + { .ident = "SAMSUNG", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "SAMSUNG ELECTRONICS CO., LTD"), + }, + }, + { .ident = "MSFT", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "Microsoft Corporation"), + }, + }, + { .ident = "ASUS", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."), + }, + }, + { .ident = "GOOGLE-HP", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "Google"), + DMI_MATCH(DMI_BOARD_VENDOR, "HP"), + }, + }, + { .ident = "GOOGLE-ASUS", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "Google"), + DMI_MATCH(DMI_BOARD_VENDOR, "ASUSTek COMPUTER INC."), + }, + }, + { .ident = "GOOGLE-SAMSUNG", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "Google"), + DMI_MATCH(DMI_BOARD_VENDOR, "SAMSUNG ELECTRONICS CO., LTD"), + }, + }, + { .ident = "DELL", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."), + }, + }, + { .ident = "DELL", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "Alienware"), + }, + }, + { .ident = "RAZER", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "Razer"), + }, + }, + {} +}; + bool iwl_sar_geo_support(struct iwl_fw_runtime *fwrt) { /* @@ -147,3 +205,106 @@ int iwl_sar_fill_profile(struct iwl_fw_runtime *fwrt, return ret; } IWL_EXPORT_SYMBOL(iwl_sar_fill_profile); + +int iwl_fill_ppag_table(struct iwl_fw_runtime *fwrt, + union iwl_ppag_table_cmd *cmd, int *cmd_size) +{ + u8 cmd_ver; + int i, j, num_sub_bands; + s8 *gain; + + /* many firmware images for JF lie about this */ + if (CSR_HW_RFID_TYPE(fwrt->trans->hw_rf_id) == + CSR_HW_RFID_TYPE(CSR_HW_RF_ID_TYPE_JF)) + return -EOPNOTSUPP; + + if (!fw_has_capa(&fwrt->fw->ucode_capa, IWL_UCODE_TLV_CAPA_SET_PPAG)) { + IWL_DEBUG_RADIO(fwrt, + "PPAG capability not supported by FW, command not sent.\n"); + return -EINVAL; + } + + cmd_ver = iwl_fw_lookup_cmd_ver(fwrt->fw, + WIDE_ID(PHY_OPS_GROUP, + PER_PLATFORM_ANT_GAIN_CMD), + IWL_FW_CMD_VER_UNKNOWN); + if (!fwrt->ppag_table_valid || (cmd_ver <= 3 && !fwrt->ppag_flags)) { + IWL_DEBUG_RADIO(fwrt, "PPAG not enabled, command not sent.\n"); + return -EINVAL; + } + + /* The 'flags' field is the same in v1 and in v2 so we can just + * use v1 to access it. + */ + cmd->v1.flags = cpu_to_le32(fwrt->ppag_flags); + + IWL_DEBUG_RADIO(fwrt, "PPAG cmd ver is %d\n", cmd_ver); + if (cmd_ver == 1) { + num_sub_bands = IWL_NUM_SUB_BANDS_V1; + gain = cmd->v1.gain[0]; + *cmd_size = sizeof(cmd->v1); + if (fwrt->ppag_ver == 1 || fwrt->ppag_ver == 2) { + /* in this case FW supports revision 0 */ + IWL_DEBUG_RADIO(fwrt, + "PPAG table rev is %d, send truncated table\n", + fwrt->ppag_ver); + } + } else if (cmd_ver >= 2 && cmd_ver <= 4) { + num_sub_bands = IWL_NUM_SUB_BANDS_V2; + gain = cmd->v2.gain[0]; + *cmd_size = sizeof(cmd->v2); + if (fwrt->ppag_ver == 0) { + /* in this case FW supports revisions 1 or 2 */ + IWL_DEBUG_RADIO(fwrt, + "PPAG table rev is 0, send padded table\n"); + } + } else { + IWL_DEBUG_RADIO(fwrt, "Unsupported PPAG command version\n"); + return -EINVAL; + } + + /* ppag mode */ + IWL_DEBUG_RADIO(fwrt, + "PPAG MODE bits were read from bios: %d\n", + cmd->v1.flags); + if ((cmd_ver == 1 && + !fw_has_capa(&fwrt->fw->ucode_capa, + IWL_UCODE_TLV_CAPA_PPAG_CHINA_BIOS_SUPPORT)) || + (cmd_ver == 2 && fwrt->ppag_ver == 2)) { + cmd->v1.flags &= cpu_to_le32(IWL_PPAG_ETSI_MASK); + IWL_DEBUG_RADIO(fwrt, "masking ppag China bit\n"); + } else { + IWL_DEBUG_RADIO(fwrt, "isn't masking ppag China bit\n"); + } + + IWL_DEBUG_RADIO(fwrt, + "PPAG MODE bits going to be sent: %d\n", + cmd->v1.flags); + + for (i = 0; i < IWL_NUM_CHAIN_LIMITS; i++) { + for (j = 0; j < num_sub_bands; j++) { + gain[i * num_sub_bands + j] = + fwrt->ppag_chains[i].subbands[j]; + IWL_DEBUG_RADIO(fwrt, + "PPAG table: chain[%d] band[%d]: gain = %d\n", + i, j, gain[i * num_sub_bands + j]); + } + } + + return 0; +} +IWL_EXPORT_SYMBOL(iwl_fill_ppag_table); + +bool iwl_is_ppag_approved(struct iwl_fw_runtime *fwrt) +{ + if (!dmi_check_system(dmi_ppag_approved_list)) { + IWL_DEBUG_RADIO(fwrt, + "System vendor '%s' is not in the approved list, disabling PPAG.\n", + dmi_get_system_info(DMI_SYS_VENDOR)); + fwrt->ppag_flags = 0; + return false; + } + + return true; +} +IWL_EXPORT_SYMBOL(iwl_is_ppag_approved); diff --git a/drivers/net/wireless/intel/iwlwifi/fw/regulatory.h b/drivers/net/wireless/intel/iwlwifi/fw/regulatory.h index 73c6122e7626..63f650cb6517 100644 --- a/drivers/net/wireless/intel/iwlwifi/fw/regulatory.h +++ b/drivers/net/wireless/intel/iwlwifi/fw/regulatory.h @@ -31,6 +31,15 @@ #define IWL_SAR_ENABLE_MSK BIT(0) +/* PPAG gain value bounds in 1/8 dBm */ +#define IWL_PPAG_MIN_LB -16 +#define IWL_PPAG_MAX_LB 24 +#define IWL_PPAG_MIN_HB -16 +#define IWL_PPAG_MAX_HB 40 + +#define IWL_PPAG_ETSI_CHINA_MASK 3 +#define IWL_PPAG_ETSI_MASK BIT(0) + /* * The profile for revision 2 is a superset of revision 1, which is in * turn a superset of revision 0. So we can store all revisions @@ -75,6 +84,11 @@ struct iwl_geo_profile { struct iwl_geo_profile_band bands[BIOS_GEO_MAX_NUM_BANDS]; }; +/* Same thing as with SAR, all revisions fit in revision 2 */ +struct iwl_ppag_chain { + s8 subbands[BIOS_SAR_MAX_SUB_BANDS_NUM]; +}; + struct iwl_fw_runtime; bool iwl_sar_geo_support(struct iwl_fw_runtime *fwrt); @@ -87,6 +101,12 @@ int iwl_sar_fill_profile(struct iwl_fw_runtime *fwrt, __le16 *per_chain, u32 n_tables, u32 n_subbands, int prof_a, int prof_b); +int iwl_fill_ppag_table(struct iwl_fw_runtime *fwrt, + union iwl_ppag_table_cmd *cmd, + int *cmd_size); + +bool iwl_is_ppag_approved(struct iwl_fw_runtime *fwrt); + int iwl_bios_get_wrds_table(struct iwl_fw_runtime *fwrt); int iwl_bios_get_ewrd_table(struct iwl_fw_runtime *fwrt); diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/fw.c b/drivers/net/wireless/intel/iwlwifi/mvm/fw.c index d52fc3119972..1d759fe7d12d 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/fw.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/fw.c @@ -1104,7 +1104,7 @@ int iwl_mvm_ppag_send_cmd(struct iwl_mvm *mvm) static int iwl_mvm_ppag_init(struct iwl_mvm *mvm) { /* no need to read the table, done in INIT stage */ - if (!(iwl_acpi_is_ppag_approved(&mvm->fwrt))) + if (!(iwl_is_ppag_approved(&mvm->fwrt))) return 0; return iwl_mvm_ppag_send_cmd(mvm); -- cgit v1.2.3 From 8408e83e16bb4d1d8f0ccf6937cae0357478ec50 Mon Sep 17 00:00:00 2001 From: Miri Korenblit Date: Wed, 31 Jan 2024 10:24:42 +0200 Subject: wifi: iwlwifi: validate PPAG table when sent to FW We used to check enablement/validity of the PPAG table while reading it from BIOS. For newer FWs this checks were offloaded, and the driver needs to send the PPAG table anyway. The desicion whether the table needs to be validated before sending it is FW related and shouln't be in 'read-from-bios' flow. Move it to 'send-to-fw' flow instead. This will also help to avoid code duplication of checking validity in both ACPI and UEFI caes. Signed-off-by: Miri Korenblit Reviewed-by: Gregory Greenman Link: https://msgid.link/20240131091413.7043b4087dda.I5a189f9a349556b84a79597fe1e46ffa93664df9@changeid Signed-off-by: Johannes Berg --- drivers/net/wireless/intel/iwlwifi/fw/acpi.c | 28 ------------------- drivers/net/wireless/intel/iwlwifi/fw/regulatory.c | 32 ++++++++++++++++++++-- drivers/net/wireless/intel/iwlwifi/fw/runtime.h | 1 - 3 files changed, 29 insertions(+), 32 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/intel/iwlwifi/fw/acpi.c b/drivers/net/wireless/intel/iwlwifi/fw/acpi.c index 9b0ecfc087ab..b029e88501a1 100644 --- a/drivers/net/wireless/intel/iwlwifi/fw/acpi.c +++ b/drivers/net/wireless/intel/iwlwifi/fw/acpi.c @@ -896,9 +896,6 @@ int iwl_acpi_get_ppag_table(struct iwl_fw_runtime *fwrt) union acpi_object *wifi_pkg, *data, *flags; int i, j, ret, tbl_rev, num_sub_bands = 0; int idx = 2; - u8 cmd_ver; - - fwrt->ppag_table_valid = false; data = iwl_acpi_get_object(fwrt->dev, ACPI_PPAG_METHOD); if (IS_ERR(data)) @@ -945,18 +942,6 @@ read_table: } fwrt->ppag_flags = flags->integer.value & IWL_PPAG_ETSI_CHINA_MASK; - cmd_ver = iwl_fw_lookup_cmd_ver(fwrt->fw, - WIDE_ID(PHY_OPS_GROUP, - PER_PLATFORM_ANT_GAIN_CMD), - IWL_FW_CMD_VER_UNKNOWN); - if (cmd_ver == IWL_FW_CMD_VER_UNKNOWN) { - ret = -EINVAL; - goto out_free; - } - if (!fwrt->ppag_flags && cmd_ver <= 3) { - ret = 0; - goto out_free; - } /* * read, verify gain values and save them into the PPAG table. @@ -974,22 +959,9 @@ read_table: } fwrt->ppag_chains[i].subbands[j] = ent->integer.value; - /* from ver 4 the fw deals with out of range values */ - if (cmd_ver >= 4) - continue; - if ((j == 0 && - (fwrt->ppag_chains[i].subbands[j] > IWL_PPAG_MAX_LB || - fwrt->ppag_chains[i].subbands[j] < IWL_PPAG_MIN_LB)) || - (j != 0 && - (fwrt->ppag_chains[i].subbands[j] > IWL_PPAG_MAX_HB || - fwrt->ppag_chains[i].subbands[j] < IWL_PPAG_MIN_HB))) { - ret = -EINVAL; - goto out_free; - } } } - fwrt->ppag_table_valid = true; ret = 0; out_free: diff --git a/drivers/net/wireless/intel/iwlwifi/fw/regulatory.c b/drivers/net/wireless/intel/iwlwifi/fw/regulatory.c index 2393c8a8e288..3d42ea1ec5fd 100644 --- a/drivers/net/wireless/intel/iwlwifi/fw/regulatory.c +++ b/drivers/net/wireless/intel/iwlwifi/fw/regulatory.c @@ -206,12 +206,28 @@ int iwl_sar_fill_profile(struct iwl_fw_runtime *fwrt, } IWL_EXPORT_SYMBOL(iwl_sar_fill_profile); +static bool iwl_ppag_value_valid(struct iwl_fw_runtime *fwrt, int chain, + int subband) +{ + s8 ppag_val = fwrt->ppag_chains[chain].subbands[subband]; + + if ((subband == 0 && + (ppag_val > IWL_PPAG_MAX_LB || ppag_val < IWL_PPAG_MIN_LB)) || + (subband != 0 && + (ppag_val > IWL_PPAG_MAX_HB || ppag_val < IWL_PPAG_MIN_HB))) { + IWL_DEBUG_RADIO(fwrt, "Invalid PPAG value: %d\n", ppag_val); + return false; + } + return true; +} + int iwl_fill_ppag_table(struct iwl_fw_runtime *fwrt, union iwl_ppag_table_cmd *cmd, int *cmd_size) { u8 cmd_ver; int i, j, num_sub_bands; s8 *gain; + bool send_ppag_always; /* many firmware images for JF lie about this */ if (CSR_HW_RFID_TYPE(fwrt->trans->hw_rf_id) == @@ -226,9 +242,15 @@ int iwl_fill_ppag_table(struct iwl_fw_runtime *fwrt, cmd_ver = iwl_fw_lookup_cmd_ver(fwrt->fw, WIDE_ID(PHY_OPS_GROUP, - PER_PLATFORM_ANT_GAIN_CMD), - IWL_FW_CMD_VER_UNKNOWN); - if (!fwrt->ppag_table_valid || (cmd_ver <= 3 && !fwrt->ppag_flags)) { + PER_PLATFORM_ANT_GAIN_CMD), 1); + /* + * Starting from ver 4, driver needs to send the PPAG CMD regradless + * if PPAG is enabled/disabled or valid/invalid. + */ + send_ppag_always = cmd_ver > 3; + + /* Don't send PPAG if it is disabled */ + if (!send_ppag_always && !fwrt->ppag_flags) { IWL_DEBUG_RADIO(fwrt, "PPAG not enabled, command not sent.\n"); return -EINVAL; } @@ -283,6 +305,10 @@ int iwl_fill_ppag_table(struct iwl_fw_runtime *fwrt, for (i = 0; i < IWL_NUM_CHAIN_LIMITS; i++) { for (j = 0; j < num_sub_bands; j++) { + if (!send_ppag_always && + !iwl_ppag_value_valid(fwrt, i, j)) + return -EINVAL; + gain[i * num_sub_bands + j] = fwrt->ppag_chains[i].subbands[j]; IWL_DEBUG_RADIO(fwrt, diff --git a/drivers/net/wireless/intel/iwlwifi/fw/runtime.h b/drivers/net/wireless/intel/iwlwifi/fw/runtime.h index e55248b6b4c2..d129782f2be4 100644 --- a/drivers/net/wireless/intel/iwlwifi/fw/runtime.h +++ b/drivers/net/wireless/intel/iwlwifi/fw/runtime.h @@ -176,7 +176,6 @@ struct iwl_fw_runtime { struct iwl_ppag_chain ppag_chains[IWL_NUM_CHAIN_LIMITS]; u32 ppag_flags; u32 ppag_ver; - bool ppag_table_valid; struct iwl_sar_offset_mapping_cmd sgom_table; bool sgom_enabled; struct iwl_uats_table_cmd uats_table; -- cgit v1.2.3 From bc8d0a4528f167742ecb511ba663795235e9d15c Mon Sep 17 00:00:00 2001 From: Miri Korenblit Date: Wed, 31 Jan 2024 10:24:43 +0200 Subject: wifi: iwlwifi: read PPAG table from UEFI Try to read the PPAG table from UEFI first, and if the WIFI UEFI tables are unlocked or the table doesn't exist - try to read it from ACPI Signed-off-by: Miri Korenblit Reviewed-by: Gregory Greenman Link: https://msgid.link/20240131091413.6516da09aec1.I0dcaf0b6d8857417ba1318467a28da5d0d7d7f27@changeid Signed-off-by: Johannes Berg --- drivers/net/wireless/intel/iwlwifi/fw/acpi.c | 1 - drivers/net/wireless/intel/iwlwifi/fw/regulatory.c | 1 + drivers/net/wireless/intel/iwlwifi/fw/regulatory.h | 1 + drivers/net/wireless/intel/iwlwifi/fw/runtime.h | 2 +- drivers/net/wireless/intel/iwlwifi/fw/uefi.c | 29 ++++++++++++++++++++++ drivers/net/wireless/intel/iwlwifi/fw/uefi.h | 22 ++++++++++++++++ drivers/net/wireless/intel/iwlwifi/mvm/fw.c | 16 +++--------- 7 files changed, 57 insertions(+), 15 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/intel/iwlwifi/fw/acpi.c b/drivers/net/wireless/intel/iwlwifi/fw/acpi.c index b029e88501a1..c150a66eed07 100644 --- a/drivers/net/wireless/intel/iwlwifi/fw/acpi.c +++ b/drivers/net/wireless/intel/iwlwifi/fw/acpi.c @@ -968,7 +968,6 @@ out_free: kfree(data); return ret; } -IWL_EXPORT_SYMBOL(iwl_acpi_get_ppag_table); void iwl_acpi_get_phy_filters(struct iwl_fw_runtime *fwrt, struct iwl_phy_specific_cfg *filters) diff --git a/drivers/net/wireless/intel/iwlwifi/fw/regulatory.c b/drivers/net/wireless/intel/iwlwifi/fw/regulatory.c index 3d42ea1ec5fd..fb4df1ff061d 100644 --- a/drivers/net/wireless/intel/iwlwifi/fw/regulatory.c +++ b/drivers/net/wireless/intel/iwlwifi/fw/regulatory.c @@ -24,6 +24,7 @@ IWL_EXPORT_SYMBOL(iwl_bios_get_ ## __name ## _table) IWL_BIOS_TABLE_LOADER(wrds); IWL_BIOS_TABLE_LOADER(ewrd); IWL_BIOS_TABLE_LOADER(wgds); +IWL_BIOS_TABLE_LOADER(ppag); static const struct dmi_system_id dmi_ppag_approved_list[] = { { .ident = "HP", diff --git a/drivers/net/wireless/intel/iwlwifi/fw/regulatory.h b/drivers/net/wireless/intel/iwlwifi/fw/regulatory.h index 63f650cb6517..954ba83d0277 100644 --- a/drivers/net/wireless/intel/iwlwifi/fw/regulatory.h +++ b/drivers/net/wireless/intel/iwlwifi/fw/regulatory.h @@ -113,4 +113,5 @@ int iwl_bios_get_ewrd_table(struct iwl_fw_runtime *fwrt); int iwl_bios_get_wgds_table(struct iwl_fw_runtime *fwrt); +int iwl_bios_get_ppag_table(struct iwl_fw_runtime *fwrt); #endif /* __fw_regulatory_h__ */ diff --git a/drivers/net/wireless/intel/iwlwifi/fw/runtime.h b/drivers/net/wireless/intel/iwlwifi/fw/runtime.h index d129782f2be4..9bcf04987d8b 100644 --- a/drivers/net/wireless/intel/iwlwifi/fw/runtime.h +++ b/drivers/net/wireless/intel/iwlwifi/fw/runtime.h @@ -172,10 +172,10 @@ struct iwl_fw_runtime { u32 geo_rev; u32 geo_num_profiles; bool geo_enabled; -#ifdef CONFIG_ACPI struct iwl_ppag_chain ppag_chains[IWL_NUM_CHAIN_LIMITS]; u32 ppag_flags; u32 ppag_ver; +#ifdef CONFIG_ACPI struct iwl_sar_offset_mapping_cmd sgom_table; bool sgom_enabled; struct iwl_uats_table_cmd uats_table; diff --git a/drivers/net/wireless/intel/iwlwifi/fw/uefi.c b/drivers/net/wireless/intel/iwlwifi/fw/uefi.c index a777cd4c70f7..f8092622d988 100644 --- a/drivers/net/wireless/intel/iwlwifi/fw/uefi.c +++ b/drivers/net/wireless/intel/iwlwifi/fw/uefi.c @@ -521,3 +521,32 @@ out: kfree(data); return ret; } + +int iwl_uefi_get_ppag_table(struct iwl_fw_runtime *fwrt) +{ + struct uefi_cnv_var_ppag *data; + int ret = 0; + + data = iwl_uefi_get_verified_variable(fwrt->trans, IWL_UEFI_PPAG_NAME, + "PPAG", sizeof(*data), NULL); + if (IS_ERR(data)) + return -EINVAL; + + if (data->revision < IWL_UEFI_MIN_PPAG_REV || + data->revision > IWL_UEFI_MAX_PPAG_REV) { + ret = -EINVAL; + IWL_DEBUG_RADIO(fwrt, "Unsupported UEFI PPAG revision:%d\n", + data->revision); + goto out; + } + + fwrt->ppag_ver = data->revision; + fwrt->ppag_flags = data->ppag_modes & IWL_PPAG_ETSI_CHINA_MASK; + + BUILD_BUG_ON(sizeof(fwrt->ppag_chains) != sizeof(data->ppag_chains)); + memcpy(&fwrt->ppag_chains, &data->ppag_chains, + sizeof(data->ppag_chains)); +out: + kfree(data); + return ret; +} diff --git a/drivers/net/wireless/intel/iwlwifi/fw/uefi.h b/drivers/net/wireless/intel/iwlwifi/fw/uefi.h index 3141fca047c6..a2e6eb21de82 100644 --- a/drivers/net/wireless/intel/iwlwifi/fw/uefi.h +++ b/drivers/net/wireless/intel/iwlwifi/fw/uefi.h @@ -15,6 +15,7 @@ #define IWL_UEFI_WRDS_NAME L"UefiCnvWlanWRDS" #define IWL_UEFI_EWRD_NAME L"UefiCnvWlanEWRD" #define IWL_UEFI_WGDS_NAME L"UefiCnvWlanWGDS" +#define IWL_UEFI_PPAG_NAME L"UefiCnvWlanPPAG" #define IWL_SGOM_MAP_SIZE 339 #define IWL_UATS_MAP_SIZE 339 @@ -22,6 +23,8 @@ #define IWL_UEFI_WRDS_REVISION 2 #define IWL_UEFI_EWRD_REVISION 2 #define IWL_UEFI_WGDS_REVISION 3 +#define IWL_UEFI_MIN_PPAG_REV 1 +#define IWL_UEFI_MAX_PPAG_REV 3 struct pnvm_sku_package { u8 rev; @@ -99,6 +102,19 @@ struct uefi_cnv_var_wgds { struct iwl_geo_profile geo_profiles[BIOS_GEO_MAX_PROFILE_NUM]; } __packed; +/* + * struct uefi_cnv_var_ppag - PPAG table as defined in UEFI + * @revision: the revision of the table + * @ppag_modes: bit 0 - PPAG is enabled/disabled in ETSI, + * bit 1 - PPAG is enabled/disabled in China + * @ppag_chains: the PPAG values per chain and band + */ +struct uefi_cnv_var_ppag { + u8 revision; + u32 ppag_modes; + struct iwl_ppag_chain ppag_chains[IWL_NUM_CHAIN_LIMITS]; +} __packed; + /* * This is known to be broken on v4.19 and to work on v5.4. Until we * figure out why this is the case and how to make it work, simply @@ -116,6 +132,7 @@ int iwl_uefi_handle_tlv_mem_desc(struct iwl_trans *trans, const u8 *data, int iwl_uefi_get_wrds_table(struct iwl_fw_runtime *fwrt); int iwl_uefi_get_ewrd_table(struct iwl_fw_runtime *fwrt); int iwl_uefi_get_wgds_table(struct iwl_fw_runtime *fwrt); +int iwl_uefi_get_ppag_table(struct iwl_fw_runtime *fwrt); #else /* CONFIG_EFI */ static inline void *iwl_uefi_get_pnvm(struct iwl_trans *trans, size_t *len) { @@ -161,6 +178,11 @@ static inline int iwl_uefi_get_wgds_table(struct iwl_fw_runtime *fwrt) { return -ENOENT; } + +static inline int iwl_uefi_get_ppag_table(struct iwl_fw_runtime *fwrt) +{ + return -ENOENT; +} #endif /* CONFIG_EFI */ #if defined(CONFIG_EFI) && defined(CONFIG_ACPI) diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/fw.c b/drivers/net/wireless/intel/iwlwifi/mvm/fw.c index 1d759fe7d12d..0a820dbeef23 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/fw.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/fw.c @@ -1078,8 +1078,6 @@ static int iwl_mvm_sar_geo_init(struct iwl_mvm *mvm) return iwl_mvm_send_cmd_pdu(mvm, cmd_id, 0, len, &cmd); } -#ifdef CONFIG_ACPI - int iwl_mvm_ppag_send_cmd(struct iwl_mvm *mvm) { union iwl_ppag_table_cmd cmd; @@ -1110,6 +1108,8 @@ static int iwl_mvm_ppag_init(struct iwl_mvm *mvm) return iwl_mvm_ppag_send_cmd(mvm); } +#ifdef CONFIG_ACPI + static const struct dmi_system_id dmi_tas_approved_list[] = { { .ident = "HP", .matches = { @@ -1389,16 +1389,6 @@ static void iwl_mvm_lari_cfg(struct iwl_mvm *mvm) #else /* CONFIG_ACPI */ -int iwl_mvm_ppag_send_cmd(struct iwl_mvm *mvm) -{ - return -ENOENT; -} - -static int iwl_mvm_ppag_init(struct iwl_mvm *mvm) -{ - return 0; -} - static void iwl_mvm_tas_init(struct iwl_mvm *mvm) { } @@ -1426,7 +1416,7 @@ void iwl_mvm_get_bios_tables(struct iwl_mvm *mvm) iwl_acpi_get_guid_lock_status(&mvm->fwrt); /* read PPAG table */ - ret = iwl_acpi_get_ppag_table(&mvm->fwrt); + ret = iwl_bios_get_ppag_table(&mvm->fwrt); if (ret < 0) { IWL_DEBUG_RADIO(mvm, "PPAG BIOS table invalid or unavailable. (%d)\n", -- cgit v1.2.3 From e1c54d6377348fa2f7e216f53426f1b5fb9a59b1 Mon Sep 17 00:00:00 2001 From: Miri Korenblit Date: Wed, 31 Jan 2024 10:24:44 +0200 Subject: wifi: iwlwifi: don't check TAS block list size twice Currenltly we check the validity of this variable twice. Remove the second check. Signed-off-by: Miri Korenblit Reviewed-by: Gregory Greenman Link: https://msgid.link/20240131091413.2234490624c4.I6399b652a3c83afff1b0b5f114604d15892ee01e@changeid Signed-off-by: Johannes Berg --- drivers/net/wireless/intel/iwlwifi/fw/acpi.c | 6 ------ 1 file changed, 6 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/intel/iwlwifi/fw/acpi.c b/drivers/net/wireless/intel/iwlwifi/fw/acpi.c index c150a66eed07..d88a9df20abe 100644 --- a/drivers/net/wireless/intel/iwlwifi/fw/acpi.c +++ b/drivers/net/wireless/intel/iwlwifi/fw/acpi.c @@ -317,12 +317,6 @@ int iwl_acpi_get_tas(struct iwl_fw_runtime *fwrt, cmd->v4.block_list_size = cpu_to_le32(block_list_size); IWL_DEBUG_RADIO(fwrt, "TAS array size %u\n", block_list_size); - if (block_list_size > APCI_WTAS_BLACK_LIST_MAX) { - IWL_DEBUG_RADIO(fwrt, "TAS invalid array size value %u\n", - block_list_size); - ret = -EINVAL; - goto out_free; - } for (i = 0; i < block_list_size; i++) { u32 country; -- cgit v1.2.3 From ad5a85d8fdd346ecc34217e3bd713bf0b519912d Mon Sep 17 00:00:00 2001 From: Miri Korenblit Date: Wed, 31 Jan 2024 10:24:45 +0200 Subject: wifi: iwlwifi: prepare for reading TAS table from UEFI We are going to support reading BIOS tables from UEFI too, Refactor the TAS table flow: 1. Rename and move the common code to the regulatory.h/c files. 2. Remove the IWL_TAS_BLOCK_LIST_MAX, as we can use IWL_WTAS_BLACK_LIST_MAX instead. Signed-off-by: Miri Korenblit Reviewed-by: Gregory Greenman Link: https://msgid.link/20240131091413.0c2197cf1feb.Ib0e83d5bd3f4d5cfa9c3d2925317ba49377d257f@changeid Signed-off-by: Johannes Berg --- drivers/net/wireless/intel/iwlwifi/fw/acpi.c | 19 +---- drivers/net/wireless/intel/iwlwifi/fw/acpi.h | 11 +-- .../net/wireless/intel/iwlwifi/fw/api/nvm-reg.h | 8 +- drivers/net/wireless/intel/iwlwifi/fw/regulatory.c | 91 ++++++++++++++++++++++ drivers/net/wireless/intel/iwlwifi/fw/regulatory.h | 15 +++- drivers/net/wireless/intel/iwlwifi/mvm/debugfs.c | 4 +- drivers/net/wireless/intel/iwlwifi/mvm/fw.c | 70 +---------------- drivers/net/wireless/intel/iwlwifi/mvm/mvm.h | 1 - 8 files changed, 118 insertions(+), 101 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/intel/iwlwifi/fw/acpi.c b/drivers/net/wireless/intel/iwlwifi/fw/acpi.c index d88a9df20abe..4fd9c6f768e6 100644 --- a/drivers/net/wireless/intel/iwlwifi/fw/acpi.c +++ b/drivers/net/wireless/intel/iwlwifi/fw/acpi.c @@ -273,22 +273,9 @@ int iwl_acpi_get_tas(struct iwl_fw_runtime *fwrt, ACPI_TYPE_INTEGER) { u32 tas_selection = (u32)wifi_pkg->package.elements[1].integer.value; - u16 override_iec = - (tas_selection & ACPI_WTAS_OVERRIDE_IEC_MSK) >> ACPI_WTAS_OVERRIDE_IEC_POS; - u16 enabled_iec = (tas_selection & ACPI_WTAS_ENABLE_IEC_MSK) >> - ACPI_WTAS_ENABLE_IEC_POS; - u8 usa_tas_uhb = (tas_selection & ACPI_WTAS_USA_UHB_MSK) >> ACPI_WTAS_USA_UHB_POS; - - enabled = tas_selection & ACPI_WTAS_ENABLED_MSK; - if (fw_ver <= 3) { - cmd->v3.override_tas_iec = cpu_to_le16(override_iec); - cmd->v3.enable_tas_iec = cpu_to_le16(enabled_iec); - } else { - cmd->v4.usa_tas_uhb_allowed = usa_tas_uhb; - cmd->v4.override_tas_iec = (u8)override_iec; - cmd->v4.enable_tas_iec = (u8)enabled_iec; - } + enabled = iwl_parse_tas_selection(fwrt, cmd, fw_ver, + tas_selection); } else if (tbl_rev == 0 && wifi_pkg->package.elements[1].type == ACPI_TYPE_INTEGER) { @@ -307,7 +294,7 @@ int iwl_acpi_get_tas(struct iwl_fw_runtime *fwrt, IWL_DEBUG_RADIO(fwrt, "Reading TAS table revision %d\n", tbl_rev); if (wifi_pkg->package.elements[2].type != ACPI_TYPE_INTEGER || wifi_pkg->package.elements[2].integer.value > - APCI_WTAS_BLACK_LIST_MAX) { + IWL_WTAS_BLACK_LIST_MAX) { IWL_DEBUG_RADIO(fwrt, "TAS invalid array size %llu\n", wifi_pkg->package.elements[2].integer.value); ret = -EINVAL; diff --git a/drivers/net/wireless/intel/iwlwifi/fw/acpi.h b/drivers/net/wireless/intel/iwlwifi/fw/acpi.h index ca3587e9f856..319158ab36c4 100644 --- a/drivers/net/wireless/intel/iwlwifi/fw/acpi.h +++ b/drivers/net/wireless/intel/iwlwifi/fw/acpi.h @@ -78,16 +78,7 @@ * 1 element for block list size, * 16 elements for block list array */ -#define APCI_WTAS_BLACK_LIST_MAX 16 -#define ACPI_WTAS_WIFI_DATA_SIZE (3 + APCI_WTAS_BLACK_LIST_MAX) -#define ACPI_WTAS_ENABLED_MSK 0x1 -#define ACPI_WTAS_OVERRIDE_IEC_MSK 0x2 -#define ACPI_WTAS_ENABLE_IEC_MSK 0x4 -#define ACPI_WTAS_OVERRIDE_IEC_POS 0x1 -#define ACPI_WTAS_ENABLE_IEC_POS 0x2 -#define ACPI_WTAS_USA_UHB_MSK BIT(16) -#define ACPI_WTAS_USA_UHB_POS 16 - +#define ACPI_WTAS_WIFI_DATA_SIZE (3 + IWL_WTAS_BLACK_LIST_MAX) #define ACPI_PPAG_WIFI_DATA_SIZE_V1 ((IWL_NUM_CHAIN_LIMITS * \ IWL_NUM_SUB_BANDS_V1) + 2) diff --git a/drivers/net/wireless/intel/iwlwifi/fw/api/nvm-reg.h b/drivers/net/wireless/intel/iwlwifi/fw/api/nvm-reg.h index 7ec959244ffc..c93a0665b040 100644 --- a/drivers/net/wireless/intel/iwlwifi/fw/api/nvm-reg.h +++ b/drivers/net/wireless/intel/iwlwifi/fw/api/nvm-reg.h @@ -7,6 +7,7 @@ #ifndef __iwl_fw_api_nvm_reg_h__ #define __iwl_fw_api_nvm_reg_h__ +#include "fw/regulatory.h" /** * enum iwl_regulatory_and_nvm_subcmd_ids - regulatory/NVM commands */ @@ -438,7 +439,6 @@ enum iwl_mcc_source { MCC_SOURCE_GETTING_MCC_TEST_MODE = 0x11, }; -#define IWL_TAS_BLOCK_LIST_MAX 16 /** * struct iwl_tas_config_cmd_v2 - configures the TAS * @block_list_size: size of relevant field in block_list_array @@ -446,7 +446,7 @@ enum iwl_mcc_source { */ struct iwl_tas_config_cmd_v2 { __le32 block_list_size; - __le32 block_list_array[IWL_TAS_BLOCK_LIST_MAX]; + __le32 block_list_array[IWL_WTAS_BLACK_LIST_MAX]; } __packed; /* TAS_CONFIG_CMD_API_S_VER_2 */ /** @@ -459,7 +459,7 @@ struct iwl_tas_config_cmd_v2 { */ struct iwl_tas_config_cmd_v3 { __le32 block_list_size; - __le32 block_list_array[IWL_TAS_BLOCK_LIST_MAX]; + __le32 block_list_array[IWL_WTAS_BLACK_LIST_MAX]; __le16 override_tas_iec; __le16 enable_tas_iec; } __packed; /* TAS_CONFIG_CMD_API_S_VER_3 */ @@ -476,7 +476,7 @@ struct iwl_tas_config_cmd_v3 { */ struct iwl_tas_config_cmd_v4 { __le32 block_list_size; - __le32 block_list_array[IWL_TAS_BLOCK_LIST_MAX]; + __le32 block_list_array[IWL_WTAS_BLACK_LIST_MAX]; u8 override_tas_iec; u8 enable_tas_iec; u8 usa_tas_uhb_allowed; diff --git a/drivers/net/wireless/intel/iwlwifi/fw/regulatory.c b/drivers/net/wireless/intel/iwlwifi/fw/regulatory.c index fb4df1ff061d..570d8e74f839 100644 --- a/drivers/net/wireless/intel/iwlwifi/fw/regulatory.c +++ b/drivers/net/wireless/intel/iwlwifi/fw/regulatory.c @@ -3,6 +3,7 @@ * Copyright (C) 2023 Intel Corporation */ #include +#include "fw/api/nvm-reg.h" #include "iwl-drv.h" #include "iwl-debug.h" #include "regulatory.h" @@ -83,6 +84,62 @@ static const struct dmi_system_id dmi_ppag_approved_list[] = { {} }; +static const struct dmi_system_id dmi_tas_approved_list[] = { + { .ident = "HP", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "HP"), + }, + }, + { .ident = "SAMSUNG", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "SAMSUNG ELECTRONICS CO., LTD"), + }, + }, + { .ident = "LENOVO", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"), + }, + }, + { .ident = "DELL", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."), + }, + }, + { .ident = "MSFT", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "Microsoft Corporation"), + }, + }, + { .ident = "Acer", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "Acer"), + }, + }, + { .ident = "ASUS", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."), + }, + }, + { .ident = "GOOGLE-HP", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "Google"), + DMI_MATCH(DMI_BOARD_VENDOR, "HP"), + }, + }, + { .ident = "MSI", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "Micro-Star International Co., Ltd."), + }, + }, + { .ident = "Honor", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "HONOR"), + }, + }, + /* keep last */ + {} +}; + bool iwl_sar_geo_support(struct iwl_fw_runtime *fwrt) { /* @@ -335,3 +392,37 @@ bool iwl_is_ppag_approved(struct iwl_fw_runtime *fwrt) return true; } IWL_EXPORT_SYMBOL(iwl_is_ppag_approved); + +bool iwl_is_tas_approved(void) +{ + return dmi_check_system(dmi_tas_approved_list); +} +IWL_EXPORT_SYMBOL(iwl_is_tas_approved); + +int iwl_parse_tas_selection(struct iwl_fw_runtime *fwrt, + union iwl_tas_config_cmd *cmd, int fw_ver, + const u32 tas_selection) +{ + u8 override_iec = u32_get_bits(tas_selection, + IWL_WTAS_OVERRIDE_IEC_MSK); + u8 enabled_iec = u32_get_bits(tas_selection, IWL_WTAS_ENABLE_IEC_MSK); + u8 usa_tas_uhb = u32_get_bits(tas_selection, IWL_WTAS_USA_UHB_MSK); + int enabled = tas_selection & IWL_WTAS_ENABLED_MSK; + + IWL_DEBUG_RADIO(fwrt, "TAS selection as read from BIOS: 0x%x\n", + tas_selection); + + if (fw_ver < 3) + return enabled; + + if (fw_ver == 3) { + cmd->v3.override_tas_iec = cpu_to_le16(override_iec); + cmd->v3.enable_tas_iec = cpu_to_le16(enabled_iec); + } else { + cmd->v4.usa_tas_uhb_allowed = usa_tas_uhb; + cmd->v4.override_tas_iec = override_iec; + cmd->v4.enable_tas_iec = enabled_iec; + } + + return enabled; +} diff --git a/drivers/net/wireless/intel/iwlwifi/fw/regulatory.h b/drivers/net/wireless/intel/iwlwifi/fw/regulatory.h index 954ba83d0277..a2d9d7807833 100644 --- a/drivers/net/wireless/intel/iwlwifi/fw/regulatory.h +++ b/drivers/net/wireless/intel/iwlwifi/fw/regulatory.h @@ -10,7 +10,6 @@ #include "fw/api/commands.h" #include "fw/api/power.h" #include "fw/api/phy.h" -#include "fw/api/nvm-reg.h" #include "fw/api/config.h" #include "fw/img.h" #include "iwl-trans.h" @@ -40,6 +39,12 @@ #define IWL_PPAG_ETSI_CHINA_MASK 3 #define IWL_PPAG_ETSI_MASK BIT(0) +#define IWL_WTAS_BLACK_LIST_MAX 16 +#define IWL_WTAS_ENABLED_MSK 0x1 +#define IWL_WTAS_OVERRIDE_IEC_MSK 0x2 +#define IWL_WTAS_ENABLE_IEC_MSK 0x4 +#define IWL_WTAS_USA_UHB_MSK BIT(16) + /* * The profile for revision 2 is a superset of revision 1, which is in * turn a superset of revision 0. So we can store all revisions @@ -91,6 +96,8 @@ struct iwl_ppag_chain { struct iwl_fw_runtime; +union iwl_tas_config_cmd; + bool iwl_sar_geo_support(struct iwl_fw_runtime *fwrt); int iwl_sar_geo_fill_table(struct iwl_fw_runtime *fwrt, @@ -107,6 +114,12 @@ int iwl_fill_ppag_table(struct iwl_fw_runtime *fwrt, bool iwl_is_ppag_approved(struct iwl_fw_runtime *fwrt); +bool iwl_is_tas_approved(void); + +int iwl_parse_tas_selection(struct iwl_fw_runtime *fwrt, + union iwl_tas_config_cmd *cmd, int fw_ver, + const u32 tas_selection); + int iwl_bios_get_wrds_table(struct iwl_fw_runtime *fwrt); int iwl_bios_get_ewrd_table(struct iwl_fw_runtime *fwrt); diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/debugfs.c b/drivers/net/wireless/intel/iwlwifi/mvm/debugfs.c index edc8204f7c0e..d67986e157a2 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/debugfs.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/debugfs.c @@ -877,14 +877,14 @@ static ssize_t iwl_dbgfs_tas_get_status_read(struct file *file, le16_to_cpu(rsp->curr_mcc)); pos += scnprintf(pos, endpos - pos, "Block list entries:"); - for (i = 0; i < APCI_WTAS_BLACK_LIST_MAX; i++) + for (i = 0; i < IWL_WTAS_BLACK_LIST_MAX; i++) pos += scnprintf(pos, endpos - pos, " 0x%x", le16_to_cpu(rsp->block_list[i])); pos += scnprintf(pos, endpos - pos, "\nOEM name: %s\n", dmi_get_system_info(DMI_SYS_VENDOR)); pos += scnprintf(pos, endpos - pos, "\tVendor In Approved List: %s\n", - iwl_mvm_is_vendor_in_approved_list() ? "YES" : "NO"); + iwl_is_tas_approved() ? "YES" : "NO"); pos += scnprintf(pos, endpos - pos, "\tDo TAS Support Dual Radio?: %s\n", rsp->in_dual_radio ? "TRUE" : "FALSE"); diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/fw.c b/drivers/net/wireless/intel/iwlwifi/mvm/fw.c index 0a820dbeef23..e848b041e995 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/fw.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/fw.c @@ -1110,66 +1110,7 @@ static int iwl_mvm_ppag_init(struct iwl_mvm *mvm) #ifdef CONFIG_ACPI -static const struct dmi_system_id dmi_tas_approved_list[] = { - { .ident = "HP", - .matches = { - DMI_MATCH(DMI_SYS_VENDOR, "HP"), - }, - }, - { .ident = "SAMSUNG", - .matches = { - DMI_MATCH(DMI_SYS_VENDOR, "SAMSUNG ELECTRONICS CO., LTD"), - }, - }, - { .ident = "LENOVO", - .matches = { - DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"), - }, - }, - { .ident = "DELL", - .matches = { - DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."), - }, - }, - { .ident = "MSFT", - .matches = { - DMI_MATCH(DMI_SYS_VENDOR, "Microsoft Corporation"), - }, - }, - { .ident = "Acer", - .matches = { - DMI_MATCH(DMI_SYS_VENDOR, "Acer"), - }, - }, - { .ident = "ASUS", - .matches = { - DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."), - }, - }, - { .ident = "GOOGLE-HP", - .matches = { - DMI_MATCH(DMI_SYS_VENDOR, "Google"), - DMI_MATCH(DMI_BOARD_VENDOR, "HP"), - }, - }, - { .ident = "MSI", - .matches = { - DMI_MATCH(DMI_SYS_VENDOR, "Micro-Star International Co., Ltd."), - }, - }, - { .ident = "Honor", - .matches = { - DMI_MATCH(DMI_SYS_VENDOR, "HONOR"), - }, - }, - /* keep last */ - {} -}; -bool iwl_mvm_is_vendor_in_approved_list(void) -{ - return dmi_check_system(dmi_tas_approved_list); -} static bool iwl_mvm_add_to_tas_block_list(__le32 *list, __le32 *le_size, unsigned int mcc) { @@ -1177,7 +1118,7 @@ static bool iwl_mvm_add_to_tas_block_list(__le32 *list, __le32 *le_size, unsigne u32 size = le32_to_cpu(*le_size); /* Verify that there is room for another country */ - if (size >= IWL_TAS_BLOCK_LIST_MAX) + if (size >= IWL_WTAS_BLACK_LIST_MAX) return false; for (i = 0; i < size; i++) { @@ -1198,7 +1139,7 @@ static void iwl_mvm_tas_init(struct iwl_mvm *mvm) int cmd_size, fw_ver; BUILD_BUG_ON(ARRAY_SIZE(cmd.v3.block_list_array) < - APCI_WTAS_BLACK_LIST_MAX); + IWL_WTAS_BLACK_LIST_MAX); if (!fw_has_capa(&mvm->fw->ucode_capa, IWL_UCODE_TLV_CAPA_TAS_CFG)) { IWL_DEBUG_RADIO(mvm, "TAS not enabled in FW\n"); @@ -1219,7 +1160,7 @@ static void iwl_mvm_tas_init(struct iwl_mvm *mvm) if (ret == 0) return; - if (!iwl_mvm_is_vendor_in_approved_list()) { + if (!iwl_is_tas_approved()) { IWL_DEBUG_RADIO(mvm, "System vendor '%s' is not in the approved list, disabling TAS in US and Canada.\n", dmi_get_system_info(DMI_SYS_VENDOR)); @@ -1397,11 +1338,6 @@ static void iwl_mvm_lari_cfg(struct iwl_mvm *mvm) { } -bool iwl_mvm_is_vendor_in_approved_list(void) -{ - return false; -} - static u8 iwl_mvm_eval_dsm_rfi(struct iwl_mvm *mvm) { return DSM_VALUE_RFI_DISABLE; diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h b/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h index 14f4cf8a67c7..c76ce6b1fa72 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h +++ b/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h @@ -2620,7 +2620,6 @@ static inline bool iwl_mvm_mei_filter_scan(struct iwl_mvm *mvm, void iwl_mvm_send_roaming_forbidden_event(struct iwl_mvm *mvm, struct ieee80211_vif *vif, bool forbidden); -bool iwl_mvm_is_vendor_in_approved_list(void); /* Callbacks for ieee80211_ops */ void iwl_mvm_mac_tx(struct ieee80211_hw *hw, -- cgit v1.2.3 From 3bc67e7c18cd69e88b801336cfe2a4dc7b4981a4 Mon Sep 17 00:00:00 2001 From: Miri Korenblit Date: Wed, 31 Jan 2024 10:24:46 +0200 Subject: wifi: iwlwifi: separate TAS 'read-from-BIOS' and 'send-to-FW' flows Currently the TAS 'read-from-BIOS' flow receives the command struct and the version of it as read from FW TLVs, and fills the command accordingly. This seems wrong, we should have the 'read-from-BIOS' flow (iwl_acpi_get_tas in iwlwifi) reading/parsing/validating the table from BIOS, and the 'send-to-FW' flow (iwl_mvm_tas_init) doing all the FW versioning checks and cmd filling. Move the cmd filling to the 'send-to-fw' flow. Signed-off-by: Miri Korenblit Reviewed-by: Gregory Greenman Link: https://msgid.link/20240131091413.24df27772a71.I57b702af4feb3f38dc21d52593c25de4b1999e4b@changeid Signed-off-by: Johannes Berg --- drivers/net/wireless/intel/iwlwifi/fw/acpi.c | 8 ++-- drivers/net/wireless/intel/iwlwifi/fw/acpi.h | 5 ++- .../net/wireless/intel/iwlwifi/fw/api/nvm-reg.h | 24 +++++------ drivers/net/wireless/intel/iwlwifi/fw/regulatory.c | 19 +++------ drivers/net/wireless/intel/iwlwifi/fw/regulatory.h | 12 ++++-- drivers/net/wireless/intel/iwlwifi/mvm/fw.c | 47 ++++++++++++++-------- 6 files changed, 62 insertions(+), 53 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/intel/iwlwifi/fw/acpi.c b/drivers/net/wireless/intel/iwlwifi/fw/acpi.c index 4fd9c6f768e6..0abb954f3056 100644 --- a/drivers/net/wireless/intel/iwlwifi/fw/acpi.c +++ b/drivers/net/wireless/intel/iwlwifi/fw/acpi.c @@ -251,7 +251,7 @@ iwl_acpi_get_wifi_pkg(struct device *dev, int iwl_acpi_get_tas(struct iwl_fw_runtime *fwrt, - union iwl_tas_config_cmd *cmd, int fw_ver) + struct iwl_tas_data *tas_data) { union acpi_object *wifi_pkg, *data; int ret, tbl_rev, i, block_list_size, enabled; @@ -274,7 +274,7 @@ int iwl_acpi_get_tas(struct iwl_fw_runtime *fwrt, u32 tas_selection = (u32)wifi_pkg->package.elements[1].integer.value; - enabled = iwl_parse_tas_selection(fwrt, cmd, fw_ver, + enabled = iwl_parse_tas_selection(fwrt, tas_data, tas_selection); } else if (tbl_rev == 0 && @@ -301,7 +301,7 @@ int iwl_acpi_get_tas(struct iwl_fw_runtime *fwrt, goto out_free; } block_list_size = wifi_pkg->package.elements[2].integer.value; - cmd->v4.block_list_size = cpu_to_le32(block_list_size); + tas_data->block_list_size = cpu_to_le32(block_list_size); IWL_DEBUG_RADIO(fwrt, "TAS array size %u\n", block_list_size); @@ -317,7 +317,7 @@ int iwl_acpi_get_tas(struct iwl_fw_runtime *fwrt, } country = wifi_pkg->package.elements[3 + i].integer.value; - cmd->v4.block_list_array[i] = cpu_to_le32(country); + tas_data->block_list_array[i] = cpu_to_le32(country); IWL_DEBUG_RADIO(fwrt, "TAS block list country %d\n", country); } diff --git a/drivers/net/wireless/intel/iwlwifi/fw/acpi.h b/drivers/net/wireless/intel/iwlwifi/fw/acpi.h index 319158ab36c4..0ce9a33bbb77 100644 --- a/drivers/net/wireless/intel/iwlwifi/fw/acpi.h +++ b/drivers/net/wireless/intel/iwlwifi/fw/acpi.h @@ -7,6 +7,7 @@ #define __iwl_fw_acpi__ #include +#include "fw/regulatory.h" #include "fw/api/commands.h" #include "fw/api/power.h" #include "fw/api/phy.h" @@ -175,7 +176,7 @@ int iwl_acpi_get_ewrd_table(struct iwl_fw_runtime *fwrt); int iwl_acpi_get_wgds_table(struct iwl_fw_runtime *fwrt); int iwl_acpi_get_tas(struct iwl_fw_runtime *fwrt, - union iwl_tas_config_cmd *cmd, int fw_ver); + struct iwl_tas_data *data); __le32 iwl_acpi_get_lari_config_bitmap(struct iwl_fw_runtime *fwrt); @@ -237,7 +238,7 @@ static inline int iwl_acpi_get_wgds_table(struct iwl_fw_runtime *fwrt) } static inline int iwl_acpi_get_tas(struct iwl_fw_runtime *fwrt, - union iwl_tas_config_cmd *cmd, int fw_ver) + struct iwl_tas_data *data) { return -ENOENT; } diff --git a/drivers/net/wireless/intel/iwlwifi/fw/api/nvm-reg.h b/drivers/net/wireless/intel/iwlwifi/fw/api/nvm-reg.h index c93a0665b040..8c886569f01e 100644 --- a/drivers/net/wireless/intel/iwlwifi/fw/api/nvm-reg.h +++ b/drivers/net/wireless/intel/iwlwifi/fw/api/nvm-reg.h @@ -440,34 +440,29 @@ enum iwl_mcc_source { }; /** - * struct iwl_tas_config_cmd_v2 - configures the TAS + * struct iwl_tas_config_cmd_common - configures the TAS. + * This is also the v2 structure. * @block_list_size: size of relevant field in block_list_array * @block_list_array: list of countries where TAS must be disabled */ -struct iwl_tas_config_cmd_v2 { +struct iwl_tas_config_cmd_common { __le32 block_list_size; __le32 block_list_array[IWL_WTAS_BLACK_LIST_MAX]; } __packed; /* TAS_CONFIG_CMD_API_S_VER_2 */ /** * struct iwl_tas_config_cmd_v3 - configures the TAS - * @block_list_size: size of relevant field in block_list_array - * @block_list_array: list of countries where TAS must be disabled * @override_tas_iec: indicates whether to override default value of IEC regulatory * @enable_tas_iec: in case override_tas_iec is set - * indicates whether IEC regulatory is enabled or disabled */ struct iwl_tas_config_cmd_v3 { - __le32 block_list_size; - __le32 block_list_array[IWL_WTAS_BLACK_LIST_MAX]; __le16 override_tas_iec; __le16 enable_tas_iec; } __packed; /* TAS_CONFIG_CMD_API_S_VER_3 */ /** * struct iwl_tas_config_cmd_v3 - configures the TAS - * @block_list_size: size of relevant field in block_list_array - * @block_list_array: list of countries where TAS must be disabled * @override_tas_iec: indicates whether to override default value of IEC regulatory * @enable_tas_iec: in case override_tas_iec is set - * indicates whether IEC regulatory is enabled or disabled @@ -475,19 +470,20 @@ struct iwl_tas_config_cmd_v3 { * @reserved: reserved */ struct iwl_tas_config_cmd_v4 { - __le32 block_list_size; - __le32 block_list_array[IWL_WTAS_BLACK_LIST_MAX]; u8 override_tas_iec; u8 enable_tas_iec; u8 usa_tas_uhb_allowed; u8 reserved; } __packed; /* TAS_CONFIG_CMD_API_S_VER_4 */ -union iwl_tas_config_cmd { - struct iwl_tas_config_cmd_v2 v2; - struct iwl_tas_config_cmd_v3 v3; - struct iwl_tas_config_cmd_v4 v4; +struct iwl_tas_config_cmd { + struct iwl_tas_config_cmd_common common; + union { + struct iwl_tas_config_cmd_v3 v3; + struct iwl_tas_config_cmd_v4 v4; + }; }; + /** * enum iwl_lari_config_masks - bit masks for the various LARI config operations * @LARI_CONFIG_DISABLE_11AC_UKRAINE_MSK: disable 11ac in ukraine diff --git a/drivers/net/wireless/intel/iwlwifi/fw/regulatory.c b/drivers/net/wireless/intel/iwlwifi/fw/regulatory.c index 570d8e74f839..20154b0fb7e6 100644 --- a/drivers/net/wireless/intel/iwlwifi/fw/regulatory.c +++ b/drivers/net/wireless/intel/iwlwifi/fw/regulatory.c @@ -3,7 +3,6 @@ * Copyright (C) 2023 Intel Corporation */ #include -#include "fw/api/nvm-reg.h" #include "iwl-drv.h" #include "iwl-debug.h" #include "regulatory.h" @@ -400,11 +399,11 @@ bool iwl_is_tas_approved(void) IWL_EXPORT_SYMBOL(iwl_is_tas_approved); int iwl_parse_tas_selection(struct iwl_fw_runtime *fwrt, - union iwl_tas_config_cmd *cmd, int fw_ver, + struct iwl_tas_data *tas_data, const u32 tas_selection) { u8 override_iec = u32_get_bits(tas_selection, - IWL_WTAS_OVERRIDE_IEC_MSK); + IWL_WTAS_OVERRIDE_IEC_MSK); u8 enabled_iec = u32_get_bits(tas_selection, IWL_WTAS_ENABLE_IEC_MSK); u8 usa_tas_uhb = u32_get_bits(tas_selection, IWL_WTAS_USA_UHB_MSK); int enabled = tas_selection & IWL_WTAS_ENABLED_MSK; @@ -412,17 +411,9 @@ int iwl_parse_tas_selection(struct iwl_fw_runtime *fwrt, IWL_DEBUG_RADIO(fwrt, "TAS selection as read from BIOS: 0x%x\n", tas_selection); - if (fw_ver < 3) - return enabled; - - if (fw_ver == 3) { - cmd->v3.override_tas_iec = cpu_to_le16(override_iec); - cmd->v3.enable_tas_iec = cpu_to_le16(enabled_iec); - } else { - cmd->v4.usa_tas_uhb_allowed = usa_tas_uhb; - cmd->v4.override_tas_iec = override_iec; - cmd->v4.enable_tas_iec = enabled_iec; - } + tas_data->usa_tas_uhb_allowed = usa_tas_uhb; + tas_data->override_tas_iec = override_iec; + tas_data->enable_tas_iec = enabled_iec; return enabled; } diff --git a/drivers/net/wireless/intel/iwlwifi/fw/regulatory.h b/drivers/net/wireless/intel/iwlwifi/fw/regulatory.h index a2d9d7807833..53bd82417cc3 100644 --- a/drivers/net/wireless/intel/iwlwifi/fw/regulatory.h +++ b/drivers/net/wireless/intel/iwlwifi/fw/regulatory.h @@ -94,9 +94,15 @@ struct iwl_ppag_chain { s8 subbands[BIOS_SAR_MAX_SUB_BANDS_NUM]; }; -struct iwl_fw_runtime; +struct iwl_tas_data { + __le32 block_list_size; + __le32 block_list_array[IWL_WTAS_BLACK_LIST_MAX]; + u8 override_tas_iec; + u8 enable_tas_iec; + u8 usa_tas_uhb_allowed; +}; -union iwl_tas_config_cmd; +struct iwl_fw_runtime; bool iwl_sar_geo_support(struct iwl_fw_runtime *fwrt); @@ -117,7 +123,7 @@ bool iwl_is_ppag_approved(struct iwl_fw_runtime *fwrt); bool iwl_is_tas_approved(void); int iwl_parse_tas_selection(struct iwl_fw_runtime *fwrt, - union iwl_tas_config_cmd *cmd, int fw_ver, + struct iwl_tas_data *tas_data, const u32 tas_selection); int iwl_bios_get_wrds_table(struct iwl_fw_runtime *fwrt); diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/fw.c b/drivers/net/wireless/intel/iwlwifi/mvm/fw.c index e848b041e995..0f36eddb3143 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/fw.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/fw.c @@ -1135,10 +1135,13 @@ static void iwl_mvm_tas_init(struct iwl_mvm *mvm) { u32 cmd_id = WIDE_ID(REGULATORY_AND_NVM_GROUP, TAS_CONFIG); int ret; - union iwl_tas_config_cmd cmd = {}; + struct iwl_tas_data data = {}; + struct iwl_tas_config_cmd cmd = {}; int cmd_size, fw_ver; - BUILD_BUG_ON(ARRAY_SIZE(cmd.v3.block_list_array) < + BUILD_BUG_ON(ARRAY_SIZE(data.block_list_array) != + IWL_WTAS_BLACK_LIST_MAX); + BUILD_BUG_ON(ARRAY_SIZE(cmd.common.block_list_array) != IWL_WTAS_BLACK_LIST_MAX); if (!fw_has_capa(&mvm->fw->ucode_capa, IWL_UCODE_TLV_CAPA_TAS_CFG)) { @@ -1146,10 +1149,7 @@ static void iwl_mvm_tas_init(struct iwl_mvm *mvm) return; } - fw_ver = iwl_fw_lookup_cmd_ver(mvm->fw, cmd_id, - IWL_FW_CMD_VER_UNKNOWN); - - ret = iwl_acpi_get_tas(&mvm->fwrt, &cmd, fw_ver); + ret = iwl_acpi_get_tas(&mvm->fwrt, &data); if (ret < 0) { IWL_DEBUG_RADIO(mvm, "TAS table invalid or unavailable. (%d)\n", @@ -1164,12 +1164,12 @@ static void iwl_mvm_tas_init(struct iwl_mvm *mvm) IWL_DEBUG_RADIO(mvm, "System vendor '%s' is not in the approved list, disabling TAS in US and Canada.\n", dmi_get_system_info(DMI_SYS_VENDOR)); - if ((!iwl_mvm_add_to_tas_block_list(cmd.v4.block_list_array, - &cmd.v4.block_list_size, - IWL_MCC_US)) || - (!iwl_mvm_add_to_tas_block_list(cmd.v4.block_list_array, - &cmd.v4.block_list_size, - IWL_MCC_CANADA))) { + if ((!iwl_mvm_add_to_tas_block_list(data.block_list_array, + &data.block_list_size, + IWL_MCC_US)) || + (!iwl_mvm_add_to_tas_block_list(data.block_list_array, + &data.block_list_size, + IWL_MCC_CANADA))) { IWL_DEBUG_RADIO(mvm, "Unable to add US/Canada to TAS block list, disabling TAS\n"); return; @@ -1180,10 +1180,25 @@ static void iwl_mvm_tas_init(struct iwl_mvm *mvm) dmi_get_system_info(DMI_SYS_VENDOR)); } - /* v4 is the same size as v3, so no need to differentiate here */ - cmd_size = fw_ver < 3 ? - sizeof(struct iwl_tas_config_cmd_v2) : - sizeof(struct iwl_tas_config_cmd_v3); + fw_ver = iwl_fw_lookup_cmd_ver(mvm->fw, cmd_id, + IWL_FW_CMD_VER_UNKNOWN); + + memcpy(&cmd.common, &data, sizeof(struct iwl_tas_config_cmd_common)); + + /* Set v3 or v4 specific parts. will be trunctated for fw_ver < 3 */ + if (fw_ver == 4) { + cmd.v4.override_tas_iec = data.override_tas_iec; + cmd.v4.enable_tas_iec = data.enable_tas_iec; + cmd.v4.usa_tas_uhb_allowed = data.usa_tas_uhb_allowed; + } else { + cmd.v3.override_tas_iec = cpu_to_le16(data.override_tas_iec); + cmd.v3.enable_tas_iec = cpu_to_le16(data.enable_tas_iec); + } + + cmd_size = sizeof(struct iwl_tas_config_cmd_common); + if (fw_ver >= 3) + /* v4 is the same size as v3 */ + cmd_size += sizeof(struct iwl_tas_config_cmd_v3); ret = iwl_mvm_send_cmd_pdu(mvm, cmd_id, 0, cmd_size, &cmd); if (ret < 0) -- cgit v1.2.3 From 084e0452a42b1d4ccde601cc1873a4ee9d8a4cbb Mon Sep 17 00:00:00 2001 From: Miri Korenblit Date: Wed, 31 Jan 2024 10:24:47 +0200 Subject: wifi: iwlwifi: read WTAS table from UEFI Try to read the WTAS table from UEFI first, and if the WIFI UEFI tables are unlocked or the table doesn't exist - try to read it from ACPI. Signed-off-by: Miri Korenblit Reviewed-by: Gregory Greenman Link: https://msgid.link/20240131091413.45e6ff7b5063.Id3aec70887e14533b10d564f32c0cf5f2a14b792@changeid [move uefi_tables_lock_status outside ifdef to fix build errors] Signed-off-by: Johannes Berg --- drivers/net/wireless/intel/iwlwifi/fw/acpi.c | 6 +-- drivers/net/wireless/intel/iwlwifi/fw/acpi.h | 8 ++-- drivers/net/wireless/intel/iwlwifi/fw/regulatory.c | 32 ++++++++++----- drivers/net/wireless/intel/iwlwifi/fw/regulatory.h | 4 ++ drivers/net/wireless/intel/iwlwifi/fw/runtime.h | 2 +- drivers/net/wireless/intel/iwlwifi/fw/uefi.c | 48 ++++++++++++++++++++++ drivers/net/wireless/intel/iwlwifi/fw/uefi.h | 23 +++++++++++ drivers/net/wireless/intel/iwlwifi/mvm/fw.c | 12 ++---- 8 files changed, 106 insertions(+), 29 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/intel/iwlwifi/fw/acpi.c b/drivers/net/wireless/intel/iwlwifi/fw/acpi.c index 0abb954f3056..170c840c321a 100644 --- a/drivers/net/wireless/intel/iwlwifi/fw/acpi.c +++ b/drivers/net/wireless/intel/iwlwifi/fw/acpi.c @@ -249,9 +249,8 @@ iwl_acpi_get_wifi_pkg(struct device *dev, tbl_rev); } - -int iwl_acpi_get_tas(struct iwl_fw_runtime *fwrt, - struct iwl_tas_data *tas_data) +int iwl_acpi_get_tas_table(struct iwl_fw_runtime *fwrt, + struct iwl_tas_data *tas_data) { union acpi_object *wifi_pkg, *data; int ret, tbl_rev, i, block_list_size, enabled; @@ -326,7 +325,6 @@ out_free: kfree(data); return ret; } -IWL_EXPORT_SYMBOL(iwl_acpi_get_tas); int iwl_acpi_get_mcc(struct device *dev, char *mcc) { diff --git a/drivers/net/wireless/intel/iwlwifi/fw/acpi.h b/drivers/net/wireless/intel/iwlwifi/fw/acpi.h index 0ce9a33bbb77..61bfdaa467d4 100644 --- a/drivers/net/wireless/intel/iwlwifi/fw/acpi.h +++ b/drivers/net/wireless/intel/iwlwifi/fw/acpi.h @@ -175,8 +175,8 @@ int iwl_acpi_get_ewrd_table(struct iwl_fw_runtime *fwrt); int iwl_acpi_get_wgds_table(struct iwl_fw_runtime *fwrt); -int iwl_acpi_get_tas(struct iwl_fw_runtime *fwrt, - struct iwl_tas_data *data); +int iwl_acpi_get_tas_table(struct iwl_fw_runtime *fwrt, + struct iwl_tas_data *data); __le32 iwl_acpi_get_lari_config_bitmap(struct iwl_fw_runtime *fwrt); @@ -237,8 +237,8 @@ static inline int iwl_acpi_get_wgds_table(struct iwl_fw_runtime *fwrt) return 1; } -static inline int iwl_acpi_get_tas(struct iwl_fw_runtime *fwrt, - struct iwl_tas_data *data) +static inline int iwl_acpi_get_tas_table(struct iwl_fw_runtime *fwrt, + struct iwl_tas_data *data) { return -ENOENT; } diff --git a/drivers/net/wireless/intel/iwlwifi/fw/regulatory.c b/drivers/net/wireless/intel/iwlwifi/fw/regulatory.c index 20154b0fb7e6..4cf22e280dfc 100644 --- a/drivers/net/wireless/intel/iwlwifi/fw/regulatory.c +++ b/drivers/net/wireless/intel/iwlwifi/fw/regulatory.c @@ -9,22 +9,32 @@ #include "fw/runtime.h" #include "fw/uefi.h" -#define IWL_BIOS_TABLE_LOADER(__name) \ -int iwl_bios_get_ ## __name ## _table(struct iwl_fw_runtime *fwrt) \ -{ \ +#define GET_BIOS_TABLE(__name, ...) \ +do { \ int ret = -ENOENT; \ if (fwrt->uefi_tables_lock_status > UEFI_WIFI_GUID_UNLOCKED) \ - ret = iwl_uefi_get_ ## __name ## _table(fwrt); \ + ret = iwl_uefi_get_ ## __name(__VA_ARGS__); \ if (ret < 0) \ - ret = iwl_acpi_get_ ## __name ## _table(fwrt); \ + ret = iwl_acpi_get_ ## __name(__VA_ARGS__); \ return ret; \ -} \ -IWL_EXPORT_SYMBOL(iwl_bios_get_ ## __name ## _table) +} while (0) -IWL_BIOS_TABLE_LOADER(wrds); -IWL_BIOS_TABLE_LOADER(ewrd); -IWL_BIOS_TABLE_LOADER(wgds); -IWL_BIOS_TABLE_LOADER(ppag); +#define IWL_BIOS_TABLE_LOADER(__name) \ +int iwl_bios_get_ ## __name(struct iwl_fw_runtime *fwrt) \ +{GET_BIOS_TABLE(__name, fwrt); } \ +IWL_EXPORT_SYMBOL(iwl_bios_get_ ## __name) + +#define IWL_BIOS_TABLE_LOADER_DATA(__name, data_type) \ +int iwl_bios_get_ ## __name(struct iwl_fw_runtime *fwrt, \ + data_type * data) \ +{GET_BIOS_TABLE(__name, fwrt, data); } \ +IWL_EXPORT_SYMBOL(iwl_bios_get_ ## __name) + +IWL_BIOS_TABLE_LOADER(wrds_table); +IWL_BIOS_TABLE_LOADER(ewrd_table); +IWL_BIOS_TABLE_LOADER(wgds_table); +IWL_BIOS_TABLE_LOADER(ppag_table); +IWL_BIOS_TABLE_LOADER_DATA(tas_table, struct iwl_tas_data); static const struct dmi_system_id dmi_ppag_approved_list[] = { { .ident = "HP", diff --git a/drivers/net/wireless/intel/iwlwifi/fw/regulatory.h b/drivers/net/wireless/intel/iwlwifi/fw/regulatory.h index 53bd82417cc3..7719ee764c55 100644 --- a/drivers/net/wireless/intel/iwlwifi/fw/regulatory.h +++ b/drivers/net/wireless/intel/iwlwifi/fw/regulatory.h @@ -133,4 +133,8 @@ int iwl_bios_get_ewrd_table(struct iwl_fw_runtime *fwrt); int iwl_bios_get_wgds_table(struct iwl_fw_runtime *fwrt); int iwl_bios_get_ppag_table(struct iwl_fw_runtime *fwrt); + +int iwl_bios_get_tas_table(struct iwl_fw_runtime *fwrt, + struct iwl_tas_data *data); + #endif /* __fw_regulatory_h__ */ diff --git a/drivers/net/wireless/intel/iwlwifi/fw/runtime.h b/drivers/net/wireless/intel/iwlwifi/fw/runtime.h index 9bcf04987d8b..16d9ea6dd386 100644 --- a/drivers/net/wireless/intel/iwlwifi/fw/runtime.h +++ b/drivers/net/wireless/intel/iwlwifi/fw/runtime.h @@ -179,8 +179,8 @@ struct iwl_fw_runtime { struct iwl_sar_offset_mapping_cmd sgom_table; bool sgom_enabled; struct iwl_uats_table_cmd uats_table; - u8 uefi_tables_lock_status; #endif + u8 uefi_tables_lock_status; bool uats_enabled; }; diff --git a/drivers/net/wireless/intel/iwlwifi/fw/uefi.c b/drivers/net/wireless/intel/iwlwifi/fw/uefi.c index f8092622d988..d6cbfe6c5a17 100644 --- a/drivers/net/wireless/intel/iwlwifi/fw/uefi.c +++ b/drivers/net/wireless/intel/iwlwifi/fw/uefi.c @@ -550,3 +550,51 @@ out: kfree(data); return ret; } + +int iwl_uefi_get_tas_table(struct iwl_fw_runtime *fwrt, + struct iwl_tas_data *tas_data) +{ + struct uefi_cnv_var_wtas *uefi_tas; + int ret = 0, enabled, i; + + uefi_tas = iwl_uefi_get_verified_variable(fwrt->trans, IWL_UEFI_WTAS_NAME, + "WTAS", sizeof(*uefi_tas), NULL); + if (IS_ERR(uefi_tas)) + return -EINVAL; + + if (uefi_tas->revision != IWL_UEFI_WTAS_REVISION) { + ret = -EINVAL; + IWL_DEBUG_RADIO(fwrt, "Unsupported UEFI WTAS revision:%d\n", + uefi_tas->revision); + goto out; + } + + enabled = iwl_parse_tas_selection(fwrt, tas_data, + uefi_tas->tas_selection); + if (!enabled) { + IWL_DEBUG_RADIO(fwrt, "TAS not enabled\n"); + ret = 0; + goto out; + } + + IWL_DEBUG_RADIO(fwrt, "Reading TAS table revision %d\n", + uefi_tas->revision); + if (uefi_tas->black_list_size > IWL_WTAS_BLACK_LIST_MAX) { + IWL_DEBUG_RADIO(fwrt, "TAS invalid array size %d\n", + uefi_tas->black_list_size); + ret = -EINVAL; + goto out; + } + tas_data->block_list_size = cpu_to_le32(uefi_tas->black_list_size); + IWL_DEBUG_RADIO(fwrt, "TAS array size %u\n", uefi_tas->black_list_size); + + for (i = 0; i < uefi_tas->black_list_size; i++) { + tas_data->block_list_array[i] = + cpu_to_le32(uefi_tas->black_list[i]); + IWL_DEBUG_RADIO(fwrt, "TAS block list country %d\n", + uefi_tas->black_list[i]); + } +out: + kfree(uefi_tas); + return ret; +} diff --git a/drivers/net/wireless/intel/iwlwifi/fw/uefi.h b/drivers/net/wireless/intel/iwlwifi/fw/uefi.h index a2e6eb21de82..f849a485d0a9 100644 --- a/drivers/net/wireless/intel/iwlwifi/fw/uefi.h +++ b/drivers/net/wireless/intel/iwlwifi/fw/uefi.h @@ -16,6 +16,7 @@ #define IWL_UEFI_EWRD_NAME L"UefiCnvWlanEWRD" #define IWL_UEFI_WGDS_NAME L"UefiCnvWlanWGDS" #define IWL_UEFI_PPAG_NAME L"UefiCnvWlanPPAG" +#define IWL_UEFI_WTAS_NAME L"UefiCnvWlanWTAS" #define IWL_SGOM_MAP_SIZE 339 #define IWL_UATS_MAP_SIZE 339 @@ -25,6 +26,7 @@ #define IWL_UEFI_WGDS_REVISION 3 #define IWL_UEFI_MIN_PPAG_REV 1 #define IWL_UEFI_MAX_PPAG_REV 3 +#define IWL_UEFI_WTAS_REVISION 1 struct pnvm_sku_package { u8 rev; @@ -115,6 +117,19 @@ struct uefi_cnv_var_ppag { struct iwl_ppag_chain ppag_chains[IWL_NUM_CHAIN_LIMITS]; } __packed; +/* struct uefi_cnv_var_wtas - WTAS tabled as defined in UEFI + * @revision: the revision of the table + * @tas_selection: different options of TAS enablement. + * @black_list_size: the number of defined entried in the black list + * @black_list: a list of countries that are not allowed to use the TAS feature + */ +struct uefi_cnv_var_wtas { + u8 revision; + u32 tas_selection; + u8 black_list_size; + u16 black_list[IWL_WTAS_BLACK_LIST_MAX]; +} __packed; + /* * This is known to be broken on v4.19 and to work on v5.4. Until we * figure out why this is the case and how to make it work, simply @@ -133,6 +148,8 @@ int iwl_uefi_get_wrds_table(struct iwl_fw_runtime *fwrt); int iwl_uefi_get_ewrd_table(struct iwl_fw_runtime *fwrt); int iwl_uefi_get_wgds_table(struct iwl_fw_runtime *fwrt); int iwl_uefi_get_ppag_table(struct iwl_fw_runtime *fwrt); +int iwl_uefi_get_tas_table(struct iwl_fw_runtime *fwrt, + struct iwl_tas_data *data); #else /* CONFIG_EFI */ static inline void *iwl_uefi_get_pnvm(struct iwl_trans *trans, size_t *len) { @@ -183,6 +200,12 @@ static inline int iwl_uefi_get_ppag_table(struct iwl_fw_runtime *fwrt) { return -ENOENT; } + +static inline int iwl_uefi_get_tas_table(struct iwl_fw_runtime *fwrt, + struct iwl_tas_data *data) +{ + return -ENOENT; +} #endif /* CONFIG_EFI */ #if defined(CONFIG_EFI) && defined(CONFIG_ACPI) diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/fw.c b/drivers/net/wireless/intel/iwlwifi/mvm/fw.c index 0f36eddb3143..72f8a6cf20c7 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/fw.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/fw.c @@ -1108,10 +1108,6 @@ static int iwl_mvm_ppag_init(struct iwl_mvm *mvm) return iwl_mvm_ppag_send_cmd(mvm); } -#ifdef CONFIG_ACPI - - - static bool iwl_mvm_add_to_tas_block_list(__le32 *list, __le32 *le_size, unsigned int mcc) { int i; @@ -1149,7 +1145,7 @@ static void iwl_mvm_tas_init(struct iwl_mvm *mvm) return; } - ret = iwl_acpi_get_tas(&mvm->fwrt, &data); + ret = iwl_bios_get_tas_table(&mvm->fwrt, &data); if (ret < 0) { IWL_DEBUG_RADIO(mvm, "TAS table invalid or unavailable. (%d)\n", @@ -1205,6 +1201,8 @@ static void iwl_mvm_tas_init(struct iwl_mvm *mvm) IWL_DEBUG_RADIO(mvm, "failed to send TAS_CONFIG (%d)\n", ret); } +#ifdef CONFIG_ACPI + static u8 iwl_mvm_eval_dsm_rfi(struct iwl_mvm *mvm) { u8 value; @@ -1345,10 +1343,6 @@ static void iwl_mvm_lari_cfg(struct iwl_mvm *mvm) #else /* CONFIG_ACPI */ -static void iwl_mvm_tas_init(struct iwl_mvm *mvm) -{ -} - static void iwl_mvm_lari_cfg(struct iwl_mvm *mvm) { } -- cgit v1.2.3 From 7d366663b7d84ecdb52ba141c1cafd4f3c73e0ff Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Mon, 29 Jan 2024 20:00:02 +0100 Subject: wifi: mac80211_hwsim: add control to skip beacons To test certain beacon loss scenarios it can be useful to simply not send a couple of beacons. Add a simple debugfs file (per vif) to skip sending the beacons. They're still fully prepared etc. so their DTIM count etc. will appear as if they were simply corrupt over the air or otherwise not received. Reviewed-by: Jeff Johnson Link: https://msgid.link/20240129200001.a267383709e6.I36f427d17c3478a7df46e205716f5ebc9b35a918@changeid Signed-off-by: Johannes Berg --- drivers/net/wireless/virtual/mac80211_hwsim.c | 28 ++++++++++++++++++++++++++- 1 file changed, 27 insertions(+), 1 deletion(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/virtual/mac80211_hwsim.c b/drivers/net/wireless/virtual/mac80211_hwsim.c index 403d892c0468..3adc11bcaf12 100644 --- a/drivers/net/wireless/virtual/mac80211_hwsim.c +++ b/drivers/net/wireless/virtual/mac80211_hwsim.c @@ -213,6 +213,7 @@ static const struct ieee80211_regdomain *hwsim_world_regdom_custom[] = { struct hwsim_vif_priv { u32 magic; + u32 skip_beacons; u8 bssid[ETH_ALEN]; bool assoc; bool bcn_en; @@ -2128,6 +2129,16 @@ static int mac80211_hwsim_add_interface(struct ieee80211_hw *hw, return 0; } +#ifdef CONFIG_MAC80211_DEBUGFS +static void mac80211_hwsim_vif_add_debugfs(struct ieee80211_hw *hw, + struct ieee80211_vif *vif) +{ + struct hwsim_vif_priv *vp = (void *)vif->drv_priv; + + debugfs_create_u32("skip_beacons", 0600, vif->debugfs_dir, + &vp->skip_beacons); +} +#endif static int mac80211_hwsim_change_interface(struct ieee80211_hw *hw, struct ieee80211_vif *vif, @@ -2193,12 +2204,19 @@ static void __mac80211_hwsim_beacon_tx(struct ieee80211_bss_conf *link_conf, struct ieee80211_vif *vif, struct sk_buff *skb) { + struct hwsim_vif_priv *vp = (void *)vif->drv_priv; struct ieee80211_tx_info *info; struct ieee80211_rate *txrate; struct ieee80211_mgmt *mgmt; /* TODO: get MCS */ int bitrate = 100; + if (vp->skip_beacons) { + vp->skip_beacons--; + dev_kfree_skb(skb); + return; + } + info = IEEE80211_SKB_CB(skb); if (ieee80211_hw_check(hw, SUPPORTS_RC_TABLE)) ieee80211_get_tx_rates(vif, NULL, skb, @@ -3857,6 +3875,13 @@ out: return err; } +#ifdef CONFIG_MAC80211_DEBUGFS +#define HWSIM_DEBUGFS_OPS \ + .vif_add_debugfs = mac80211_hwsim_vif_add_debugfs, +#else +#define HWSIM_DEBUGFS_OPS +#endif + #define HWSIM_COMMON_OPS \ .tx = mac80211_hwsim_tx, \ .wake_tx_queue = ieee80211_handle_wake_tx_queue, \ @@ -3881,7 +3906,8 @@ out: .get_et_stats = mac80211_hwsim_get_et_stats, \ .get_et_strings = mac80211_hwsim_get_et_strings, \ .start_pmsr = mac80211_hwsim_start_pmsr, \ - .abort_pmsr = mac80211_hwsim_abort_pmsr, + .abort_pmsr = mac80211_hwsim_abort_pmsr, \ + HWSIM_DEBUGFS_OPS #define HWSIM_NON_MLO_OPS \ .sta_add = mac80211_hwsim_sta_add, \ -- cgit v1.2.3 From 358ddc7bfa980888b69b406a7c4ce0a5b0ac5c30 Mon Sep 17 00:00:00 2001 From: Miri Korenblit Date: Mon, 29 Jan 2024 20:00:52 +0100 Subject: wifi: mac80211_hwsim: enable all links only in MLO The existing code is enabling all usable links when moving to authorized state, but this should happen only for MLO connections. Fix this. Signed-off-by: Miri Korenblit Link: https://msgid.link/20240129200054.f5459f6c29c8.I397814449e17950fcf882ef44a1e790a71aa1dce@changeid Signed-off-by: Johannes Berg --- drivers/net/wireless/virtual/mac80211_hwsim.c | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/virtual/mac80211_hwsim.c b/drivers/net/wireless/virtual/mac80211_hwsim.c index 3adc11bcaf12..a06a462d38f0 100644 --- a/drivers/net/wireless/virtual/mac80211_hwsim.c +++ b/drivers/net/wireless/virtual/mac80211_hwsim.c @@ -4,7 +4,7 @@ * Copyright (c) 2008, Jouni Malinen * Copyright (c) 2011, Javier Lopez * Copyright (c) 2016 - 2017 Intel Deutschland GmbH - * Copyright (C) 2018 - 2023 Intel Corporation + * Copyright (C) 2018 - 2024 Intel Corporation */ /* @@ -2671,10 +2671,11 @@ static int mac80211_hwsim_sta_state(struct ieee80211_hw *hw, return mac80211_hwsim_sta_add(hw, vif, sta); /* - * when client is authorized (AP station marked as such), - * enable all links + * in an MLO connection, when client is authorized + * (AP station marked as such), enable all links */ - if (vif->type == NL80211_IFTYPE_STATION && + if (ieee80211_vif_is_mld(vif) && + vif->type == NL80211_IFTYPE_STATION && new_state == IEEE80211_STA_AUTHORIZED && !sta->tdls) ieee80211_set_active_links_async(vif, ieee80211_vif_usable_links(vif)); -- cgit v1.2.3 From d10fb5ecc82211691264156bbf8b8a988d57944e Mon Sep 17 00:00:00 2001 From: Emmanuel Grumbach Date: Wed, 31 Jan 2024 21:38:16 +0100 Subject: iwlwifi: fw: fix more kernel-doc warnings Fix some more kernel-doc warnings in FW API definitions. Signed-off-by: Emmanuel Grumbach Link: https://msgid.link/20240131213817.9f30c6529216.I69e98612c6c81cf1b7bd480d8041b5d3e25610d3@changeid Signed-off-by: Johannes Berg --- drivers/net/wireless/intel/iwlwifi/fw/api/d3.h | 2 +- drivers/net/wireless/intel/iwlwifi/fw/api/datapath.h | 2 +- drivers/net/wireless/intel/iwlwifi/fw/api/debug.h | 2 +- drivers/net/wireless/intel/iwlwifi/fw/api/location.h | 1 + drivers/net/wireless/intel/iwlwifi/fw/api/tx.h | 4 ++++ 5 files changed, 8 insertions(+), 3 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/intel/iwlwifi/fw/api/d3.h b/drivers/net/wireless/intel/iwlwifi/fw/api/d3.h index ea99d41040d2..d2a74beed3a1 100644 --- a/drivers/net/wireless/intel/iwlwifi/fw/api/d3.h +++ b/drivers/net/wireless/intel/iwlwifi/fw/api/d3.h @@ -324,7 +324,7 @@ struct iwl_wowlan_patterns_cmd { u8 n_patterns; /** - * @n_patterns: sta_id + * @sta_id: sta_id */ u8 sta_id; diff --git a/drivers/net/wireless/intel/iwlwifi/fw/api/datapath.h b/drivers/net/wireless/intel/iwlwifi/fw/api/datapath.h index 751b596ea1a5..0f7903c5a4df 100644 --- a/drivers/net/wireless/intel/iwlwifi/fw/api/datapath.h +++ b/drivers/net/wireless/intel/iwlwifi/fw/api/datapath.h @@ -101,7 +101,7 @@ enum iwl_data_path_subcmd_ids { RX_NO_DATA_NOTIF = 0xF5, /** - * @THERMAL_DUAL_CHAIN_DISABLE_REQ: firmware request for SMPS mode, + * @THERMAL_DUAL_CHAIN_REQUEST: firmware request for SMPS mode, * &struct iwl_thermal_dual_chain_request */ THERMAL_DUAL_CHAIN_REQUEST = 0xF6, diff --git a/drivers/net/wireless/intel/iwlwifi/fw/api/debug.h b/drivers/net/wireless/intel/iwlwifi/fw/api/debug.h index 798731ecbefd..a4b54488e0fc 100644 --- a/drivers/net/wireless/intel/iwlwifi/fw/api/debug.h +++ b/drivers/net/wireless/intel/iwlwifi/fw/api/debug.h @@ -394,7 +394,7 @@ struct iwl_buf_alloc_cmd { * * @first_word: magic word value * @second_word: magic word value - * @framfrags: DRAM fragmentaion detail + * @dram_frags: DRAM fragmentaion detail */ struct iwl_dram_info { __le32 first_word; diff --git a/drivers/net/wireless/intel/iwlwifi/fw/api/location.h b/drivers/net/wireless/intel/iwlwifi/fw/api/location.h index b044990c7b87..25530a29317e 100644 --- a/drivers/net/wireless/intel/iwlwifi/fw/api/location.h +++ b/drivers/net/wireless/intel/iwlwifi/fw/api/location.h @@ -630,6 +630,7 @@ enum iwl_location_frame_format { * @IWL_LOCATION_BW_20MHZ: 20MHz * @IWL_LOCATION_BW_40MHZ: 40MHz * @IWL_LOCATION_BW_80MHZ: 80MHz + * @IWL_LOCATION_BW_160MHZ: 160MHz */ enum iwl_location_bw { IWL_LOCATION_BW_20MHZ, diff --git a/drivers/net/wireless/intel/iwlwifi/fw/api/tx.h b/drivers/net/wireless/intel/iwlwifi/fw/api/tx.h index 842360b1e995..d9e4c75403b8 100644 --- a/drivers/net/wireless/intel/iwlwifi/fw/api/tx.h +++ b/drivers/net/wireless/intel/iwlwifi/fw/api/tx.h @@ -76,6 +76,8 @@ enum iwl_tx_flags { * to a secured STA * @IWL_TX_FLAGS_HIGH_PRI: high priority frame (like EAPOL) - can affect rate * selection, retry limits and BT kill + * @IWL_TX_FLAGS_RTS: firmware used an RTS + * @IWL_TX_FLAGS_CTS: firmware used CTS-to-self */ enum iwl_tx_cmd_flags { IWL_TX_FLAGS_CMD_RATE = BIT(0), @@ -884,6 +886,7 @@ struct iwl_tx_path_flush_cmd { /** * struct iwl_flush_queue_info - virtual flush queue info + * @tid: the tid to flush * @queue_num: virtual queue id * @read_before_flush: read pointer before flush * @read_after_flush: read pointer after flush @@ -897,6 +900,7 @@ struct iwl_flush_queue_info { /** * struct iwl_tx_path_flush_cmd_rsp -- queue/FIFO flush command response + * @sta_id: the station for which the queue was flushed * @num_flushed_queues: number of queues in queues array * @queues: all flushed queues */ -- cgit v1.2.3 From 3ec064e0a2cb667eceea7410d2ce7945a186beb2 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Wed, 31 Jan 2024 22:00:39 +0100 Subject: wifi: iwlwifi: remove unused function prototype Saw this while going through the code, this function hasn't existed for a while now; remove it. Link: https://msgid.link/20240131220039.6fdb8cbf4814.I6c46065b836cafd93df676dd88c99a626a25bf46@changeid Signed-off-by: Johannes Berg --- drivers/net/wireless/intel/iwlwifi/fw/dbg.h | 2 -- 1 file changed, 2 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/intel/iwlwifi/fw/dbg.h b/drivers/net/wireless/intel/iwlwifi/fw/dbg.h index eb38c686b5cb..98d56e778d99 100644 --- a/drivers/net/wireless/intel/iwlwifi/fw/dbg.h +++ b/drivers/net/wireless/intel/iwlwifi/fw/dbg.h @@ -306,8 +306,6 @@ static inline void iwl_fw_error_collect(struct iwl_fw_runtime *fwrt, bool sync) _iwl_dbg_tlv_time_point(fwrt, tp_id, NULL, sync); } -void iwl_fw_error_print_fseq_regs(struct iwl_fw_runtime *fwrt); - static inline void iwl_fwrt_update_fw_versions(struct iwl_fw_runtime *fwrt, struct iwl_lmac_alive *lmac, struct iwl_umac_alive *umac) -- cgit v1.2.3 From f74f397afe2b7a1e2f8a0a3384006e36fb940f87 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Wed, 31 Jan 2024 22:02:27 +0100 Subject: wifi: iwlwifi: api: clean up some kernel-doc/typos Add some kernel-doc for a union, and fix a couple of typos I noticed looking through this. Link: https://msgid.link/20240131220227.7fd507f09bb1.I278edc9a3d5de7fddcd84009a93c494c42686b68@changeid Signed-off-by: Johannes Berg --- drivers/net/wireless/intel/iwlwifi/fw/api/mac-cfg.h | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/intel/iwlwifi/fw/api/mac-cfg.h b/drivers/net/wireless/intel/iwlwifi/fw/api/mac-cfg.h index f15e6d64c298..362161369884 100644 --- a/drivers/net/wireless/intel/iwlwifi/fw/api/mac-cfg.h +++ b/drivers/net/wireless/intel/iwlwifi/fw/api/mac-cfg.h @@ -242,9 +242,9 @@ struct iwl_mac_low_latency_cmd { * @esr_transition_timeout: the timeout required by the AP for the * eSR transition. * Available only from version 2 of the command. - * This values comes from the EMLSR transition delay in the EML + * This value comes from the EMLSR transition delay in the EML * Capabilities subfield. - * @medium_sync_delay: the value as it appeasr in P802.11be_D2.2 Figure 9-1002j. + * @medium_sync_delay: the value as it appears in P802.11be_D2.2 Figure 9-1002j. * @assoc_id: unique ID assigned by the AP during association * @reserved1: alignment * @data_policy: see &enum iwl_mac_data_policy @@ -317,7 +317,6 @@ enum iwl_mac_config_filter_flags { * If the NIC is not ACK_ENABLED it may use the EOF-bit in first non-0 * len delim to determine if AGG or single. * @client: client mac data - * @go_ibss: mac data for go or ibss * @p2p_dev: mac data for p2p device */ struct iwl_mac_config_cmd { -- cgit v1.2.3 From a51d1cf5ad64a17230cf90e1770d363c5cbc0d5c Mon Sep 17 00:00:00 2001 From: Miri Korenblit Date: Thu, 1 Feb 2024 16:17:25 +0200 Subject: wifi: iwlwifi: prepare for reading SPLC from UEFI As the iwl_bios_get_x() functions are now generated using a macro, and this macro requires the all iwl_acpi_get_x() to have the same prototype, change iwl_acpi_get_pwr_limit() to return a int and the actuall power limit will be filled in a pointer function parameter. Signed-off-by: Miri Korenblit Reviewed-by: Gregory Greenman Link: https://msgid.link/20240201155157.4cce81198afe.Ice8b1b97a68da9ec7b5a4799ddb668642198e1af@changeid Signed-off-by: Johannes Berg --- drivers/net/wireless/intel/iwlwifi/fw/acpi.c | 23 ++++++++++------------- drivers/net/wireless/intel/iwlwifi/fw/acpi.h | 6 ++++-- drivers/net/wireless/intel/iwlwifi/mvm/ops.c | 2 +- 3 files changed, 15 insertions(+), 16 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/intel/iwlwifi/fw/acpi.c b/drivers/net/wireless/intel/iwlwifi/fw/acpi.c index 170c840c321a..d6e7de2543b2 100644 --- a/drivers/net/wireless/intel/iwlwifi/fw/acpi.c +++ b/drivers/net/wireless/intel/iwlwifi/fw/acpi.c @@ -362,31 +362,28 @@ out_free: } IWL_EXPORT_SYMBOL(iwl_acpi_get_mcc); -u64 iwl_acpi_get_pwr_limit(struct device *dev) +int iwl_acpi_get_pwr_limit(struct iwl_fw_runtime *fwrt, u64 *dflt_pwr_limit) { union acpi_object *data, *wifi_pkg; - u64 dflt_pwr_limit; - int tbl_rev; + int tbl_rev, ret = -EINVAL; - data = iwl_acpi_get_object(dev, ACPI_SPLC_METHOD); - if (IS_ERR(data)) { - dflt_pwr_limit = 0; + *dflt_pwr_limit = 0; + data = iwl_acpi_get_object(fwrt->dev, ACPI_SPLC_METHOD); + if (IS_ERR(data)) goto out; - } - wifi_pkg = iwl_acpi_get_wifi_pkg(dev, data, + wifi_pkg = iwl_acpi_get_wifi_pkg(fwrt->dev, data, ACPI_SPLC_WIFI_DATA_SIZE, &tbl_rev); if (IS_ERR(wifi_pkg) || tbl_rev != 0 || - wifi_pkg->package.elements[1].integer.value != ACPI_TYPE_INTEGER) { - dflt_pwr_limit = 0; + wifi_pkg->package.elements[1].integer.value != ACPI_TYPE_INTEGER) goto out_free; - } - dflt_pwr_limit = wifi_pkg->package.elements[1].integer.value; + *dflt_pwr_limit = wifi_pkg->package.elements[1].integer.value; + ret = 0; out_free: kfree(data); out: - return dflt_pwr_limit; + return ret; } IWL_EXPORT_SYMBOL(iwl_acpi_get_pwr_limit); diff --git a/drivers/net/wireless/intel/iwlwifi/fw/acpi.h b/drivers/net/wireless/intel/iwlwifi/fw/acpi.h index 61bfdaa467d4..f0ed7174a951 100644 --- a/drivers/net/wireless/intel/iwlwifi/fw/acpi.h +++ b/drivers/net/wireless/intel/iwlwifi/fw/acpi.h @@ -156,7 +156,7 @@ int iwl_acpi_get_dsm_u32(struct device *dev, int rev, int func, */ int iwl_acpi_get_mcc(struct device *dev, char *mcc); -u64 iwl_acpi_get_pwr_limit(struct device *dev); +int iwl_acpi_get_pwr_limit(struct iwl_fw_runtime *fwrt, u64 *dflt_pwr_limit); /* * iwl_acpi_get_eckv - read external clock validation from ACPI, if available @@ -212,8 +212,10 @@ static inline int iwl_acpi_get_mcc(struct device *dev, char *mcc) return -ENOENT; } -static inline u64 iwl_acpi_get_pwr_limit(struct device *dev) +static inline int iwl_acpi_get_pwr_limit(struct iwl_fw_runtime *fwrt, + u64 *dflt_pwr_limit) { + *dflt_pwr_limit = 0; return 0; } diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/ops.c b/drivers/net/wireless/intel/iwlwifi/mvm/ops.c index 1b41318e1e55..0e7b66a20b7c 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/ops.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/ops.c @@ -689,7 +689,7 @@ static u32 iwl_mvm_min_backoff(struct iwl_mvm *mvm) if (!backoff) return 0; - dflt_pwr_limit = iwl_acpi_get_pwr_limit(mvm->dev); + iwl_acpi_get_pwr_limit(&mvm->fwrt, &dflt_pwr_limit); while (backoff->pwr) { if (dflt_pwr_limit >= backoff->pwr) -- cgit v1.2.3 From 18f523654d4943c87da3ec512dad74828be764e4 Mon Sep 17 00:00:00 2001 From: Miri Korenblit Date: Thu, 1 Feb 2024 16:17:26 +0200 Subject: wifi: iwlwifi: read SPLC from UEFI Try to read the SPLC table from UEFI first, and if the WIFI UEFI tables are unlocked or the table doesn't exist - try to read it from ACPI Signed-off-by: Miri Korenblit Reviewed-by: Gregory Greenman Link: https://msgid.link/20240201155157.3d9d835b6edb.I7ea262df9431ced787b77c87149c6d7bddb7e7d6@changeid Signed-off-by: Johannes Berg --- drivers/net/wireless/intel/iwlwifi/fw/acpi.c | 1 - drivers/net/wireless/intel/iwlwifi/fw/regulatory.c | 2 ++ drivers/net/wireless/intel/iwlwifi/fw/regulatory.h | 2 ++ drivers/net/wireless/intel/iwlwifi/fw/uefi.c | 23 ++++++++++++++++++++++ drivers/net/wireless/intel/iwlwifi/fw/uefi.h | 21 ++++++++++++++++++++ drivers/net/wireless/intel/iwlwifi/mvm/ops.c | 2 +- 6 files changed, 49 insertions(+), 2 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/intel/iwlwifi/fw/acpi.c b/drivers/net/wireless/intel/iwlwifi/fw/acpi.c index d6e7de2543b2..e74745f939ae 100644 --- a/drivers/net/wireless/intel/iwlwifi/fw/acpi.c +++ b/drivers/net/wireless/intel/iwlwifi/fw/acpi.c @@ -385,7 +385,6 @@ out_free: out: return ret; } -IWL_EXPORT_SYMBOL(iwl_acpi_get_pwr_limit); int iwl_acpi_get_eckv(struct device *dev, u32 *extl_clk) { diff --git a/drivers/net/wireless/intel/iwlwifi/fw/regulatory.c b/drivers/net/wireless/intel/iwlwifi/fw/regulatory.c index 4cf22e280dfc..452c7cc49c27 100644 --- a/drivers/net/wireless/intel/iwlwifi/fw/regulatory.c +++ b/drivers/net/wireless/intel/iwlwifi/fw/regulatory.c @@ -35,6 +35,8 @@ IWL_BIOS_TABLE_LOADER(ewrd_table); IWL_BIOS_TABLE_LOADER(wgds_table); IWL_BIOS_TABLE_LOADER(ppag_table); IWL_BIOS_TABLE_LOADER_DATA(tas_table, struct iwl_tas_data); +IWL_BIOS_TABLE_LOADER_DATA(pwr_limit, u64); + static const struct dmi_system_id dmi_ppag_approved_list[] = { { .ident = "HP", diff --git a/drivers/net/wireless/intel/iwlwifi/fw/regulatory.h b/drivers/net/wireless/intel/iwlwifi/fw/regulatory.h index 7719ee764c55..b391c6fc3bcc 100644 --- a/drivers/net/wireless/intel/iwlwifi/fw/regulatory.h +++ b/drivers/net/wireless/intel/iwlwifi/fw/regulatory.h @@ -137,4 +137,6 @@ int iwl_bios_get_ppag_table(struct iwl_fw_runtime *fwrt); int iwl_bios_get_tas_table(struct iwl_fw_runtime *fwrt, struct iwl_tas_data *data); +int iwl_bios_get_pwr_limit(struct iwl_fw_runtime *fwrt, + u64 *dflt_pwr_limit); #endif /* __fw_regulatory_h__ */ diff --git a/drivers/net/wireless/intel/iwlwifi/fw/uefi.c b/drivers/net/wireless/intel/iwlwifi/fw/uefi.c index d6cbfe6c5a17..5ec82205be12 100644 --- a/drivers/net/wireless/intel/iwlwifi/fw/uefi.c +++ b/drivers/net/wireless/intel/iwlwifi/fw/uefi.c @@ -598,3 +598,26 @@ out: kfree(uefi_tas); return ret; } + +int iwl_uefi_get_pwr_limit(struct iwl_fw_runtime *fwrt, + u64 *dflt_pwr_limit) +{ + struct uefi_cnv_var_splc *data; + int ret = 0; + + data = iwl_uefi_get_verified_variable(fwrt->trans, IWL_UEFI_SPLC_NAME, + "SPLC", sizeof(*data), NULL); + if (IS_ERR(data)) + return -EINVAL; + + if (data->revision != IWL_UEFI_SPLC_REVISION) { + ret = -EINVAL; + IWL_DEBUG_RADIO(fwrt, "Unsupported UEFI SPLC revision:%d\n", + data->revision); + goto out; + } + *dflt_pwr_limit = data->default_pwr_limit; +out: + kfree(data); + return ret; +} diff --git a/drivers/net/wireless/intel/iwlwifi/fw/uefi.h b/drivers/net/wireless/intel/iwlwifi/fw/uefi.h index f849a485d0a9..4cf3af576920 100644 --- a/drivers/net/wireless/intel/iwlwifi/fw/uefi.h +++ b/drivers/net/wireless/intel/iwlwifi/fw/uefi.h @@ -17,6 +17,8 @@ #define IWL_UEFI_WGDS_NAME L"UefiCnvWlanWGDS" #define IWL_UEFI_PPAG_NAME L"UefiCnvWlanPPAG" #define IWL_UEFI_WTAS_NAME L"UefiCnvWlanWTAS" +#define IWL_UEFI_SPLC_NAME L"UefiCnvWlanSPLC" + #define IWL_SGOM_MAP_SIZE 339 #define IWL_UATS_MAP_SIZE 339 @@ -27,6 +29,7 @@ #define IWL_UEFI_MIN_PPAG_REV 1 #define IWL_UEFI_MAX_PPAG_REV 3 #define IWL_UEFI_WTAS_REVISION 1 +#define IWL_UEFI_SPLC_REVISION 0 struct pnvm_sku_package { u8 rev; @@ -130,6 +133,15 @@ struct uefi_cnv_var_wtas { u16 black_list[IWL_WTAS_BLACK_LIST_MAX]; } __packed; +/* struct uefi_cnv_var_splc - SPLC tabled as defined in UEFI + * @revision: the revision of the table + * @default_pwr_limit: The default maximum power per device + */ +struct uefi_cnv_var_splc { + u8 revision; + u32 default_pwr_limit; +} __packed; + /* * This is known to be broken on v4.19 and to work on v5.4. Until we * figure out why this is the case and how to make it work, simply @@ -150,6 +162,8 @@ int iwl_uefi_get_wgds_table(struct iwl_fw_runtime *fwrt); int iwl_uefi_get_ppag_table(struct iwl_fw_runtime *fwrt); int iwl_uefi_get_tas_table(struct iwl_fw_runtime *fwrt, struct iwl_tas_data *data); +int iwl_uefi_get_pwr_limit(struct iwl_fw_runtime *fwrt, + u64 *dflt_pwr_limit); #else /* CONFIG_EFI */ static inline void *iwl_uefi_get_pnvm(struct iwl_trans *trans, size_t *len) { @@ -206,6 +220,13 @@ static inline int iwl_uefi_get_tas_table(struct iwl_fw_runtime *fwrt, { return -ENOENT; } + +static inline int iwl_uefi_get_pwr_limit(struct iwl_fw_runtime *fwrt, + u64 *dflt_pwr_limit) +{ + *dflt_pwr_limit = 0; + return 0; +} #endif /* CONFIG_EFI */ #if defined(CONFIG_EFI) && defined(CONFIG_ACPI) diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/ops.c b/drivers/net/wireless/intel/iwlwifi/mvm/ops.c index 0e7b66a20b7c..747fc91ef8d0 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/ops.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/ops.c @@ -689,7 +689,7 @@ static u32 iwl_mvm_min_backoff(struct iwl_mvm *mvm) if (!backoff) return 0; - iwl_acpi_get_pwr_limit(&mvm->fwrt, &dflt_pwr_limit); + iwl_bios_get_pwr_limit(&mvm->fwrt, &dflt_pwr_limit); while (backoff->pwr) { if (dflt_pwr_limit >= backoff->pwr) -- cgit v1.2.3 From 61ff84440c402ad3e0c3989b3bef99f0db5e6766 Mon Sep 17 00:00:00 2001 From: Emmanuel Grumbach Date: Thu, 1 Feb 2024 16:17:27 +0200 Subject: wifi: iwlwifi: mvm: don't send NDPs for new tx devices New tx devices may have issues sending NDPs from the host. Send a CQM event instead. If the AP is really gone, we will get a beacon loss and disconnect. Signed-off-by: Emmanuel Grumbach Reviewed-by: Gregory Greenman Reviewed-by: Berg, Johannes Signed-off-by: Miri Korenblit Link: https://msgid.link/20240201155157.e95d53448e94.I0ec92f1ca56a62cd8c13390b9fe60e9a7e9411c7@changeid Signed-off-by: Johannes Berg --- drivers/net/wireless/intel/iwlwifi/mvm/mac-ctxt.c | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/mac-ctxt.c b/drivers/net/wireless/intel/iwlwifi/mvm/mac-ctxt.c index c4f96125cf33..bcf78ccba8c1 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/mac-ctxt.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/mac-ctxt.c @@ -1626,10 +1626,14 @@ void iwl_mvm_rx_missed_beacons_notif(struct iwl_mvm *mvm, * TODO: the threshold should be adjusted based on latency conditions, * and/or in case of a CS flow on one of the other AP vifs. */ - if (rx_missed_bcon > IWL_MVM_MISSED_BEACONS_THRESHOLD_LONG) + if (rx_missed_bcon > IWL_MVM_MISSED_BEACONS_THRESHOLD_LONG) { iwl_mvm_connection_loss(mvm, vif, "missed beacons"); - else if (rx_missed_bcon_since_rx > IWL_MVM_MISSED_BEACONS_THRESHOLD) - ieee80211_beacon_loss(vif); + } else if (rx_missed_bcon_since_rx > IWL_MVM_MISSED_BEACONS_THRESHOLD) { + if (!iwl_mvm_has_new_tx_api(mvm)) + ieee80211_beacon_loss(vif); + else + ieee80211_cqm_beacon_loss_notify(vif, GFP_ATOMIC); + } iwl_dbg_tlv_time_point(&mvm->fwrt, IWL_FW_INI_TIME_POINT_MISSED_BEACONS, &tp_data); -- cgit v1.2.3 From dd273e8a22f9302c499ae4248c95a212fccd6811 Mon Sep 17 00:00:00 2001 From: Ayala Beker Date: Thu, 1 Feb 2024 16:17:28 +0200 Subject: wifi: iwlwifi: mvm: use fast balance scan in case of an active P2P GO Set fast balance scan in case of active P2P GO, regardless of the BSS DTIM interval. This will increase the chances of scheduler to successfully schedule out-of-channel events. Signed-off-by: Ayala Beker Reviewed-by: Ilan Peer Signed-off-by: Miri Korenblit Link: https://msgid.link/20240201155157.310a00388e11.Ib136140dffa8704e68ff14e8fb69d35b97057171@changeid Signed-off-by: Johannes Berg --- drivers/net/wireless/intel/iwlwifi/mvm/scan.c | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/scan.c b/drivers/net/wireless/intel/iwlwifi/mvm/scan.c index 7b6f1cdca067..f3e3986b4c72 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/scan.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/scan.c @@ -241,13 +241,11 @@ iwl_mvm_scan_type _iwl_mvm_get_scan_type(struct iwl_mvm *mvm, return IWL_SCAN_TYPE_FRAGMENTED; /* - * in case of DCM with GO where BSS DTIM interval < 220msec - * set all scan requests as fast-balance scan + * in case of DCM with P2P GO set all scan requests as + * fast-balance scan */ if (vif && vif->type == NL80211_IFTYPE_STATION && - data.is_dcm_with_p2p_go && - ((vif->bss_conf.beacon_int * - vif->bss_conf.dtim_period) < 220)) + data.is_dcm_with_p2p_go) return IWL_SCAN_TYPE_FAST_BALANCE; } -- cgit v1.2.3 From 4dde4ff0eadd6cde43aa5f39fbea36355f9f6e44 Mon Sep 17 00:00:00 2001 From: Shaul Triebitz Date: Thu, 1 Feb 2024 16:17:29 +0200 Subject: wifi: iwlwifi: support link command version 2 In version 2, listen_lmac becomes reserved. Signed-off-by: Shaul Triebitz Signed-off-by: Miri Korenblit Link: https://msgid.link/20240201155157.df1890aba2fd.Icad9ba10f8bab770adc6a559b2c7bff5cccbffe9@changeid Signed-off-by: Johannes Berg --- drivers/net/wireless/intel/iwlwifi/fw/api/mac-cfg.h | 18 ++++++++++++------ drivers/net/wireless/intel/iwlwifi/mvm/link.c | 10 ++++++++-- 2 files changed, 20 insertions(+), 8 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/intel/iwlwifi/fw/api/mac-cfg.h b/drivers/net/wireless/intel/iwlwifi/fw/api/mac-cfg.h index 362161369884..200362e5ceca 100644 --- a/drivers/net/wireless/intel/iwlwifi/fw/api/mac-cfg.h +++ b/drivers/net/wireless/intel/iwlwifi/fw/api/mac-cfg.h @@ -446,6 +446,7 @@ enum iwl_link_ctx_flags { * @listen_lmac: indicates whether the link should be allocated on the Listen * Lmac or on the Main Lmac. Cannot be changed on an active Link. * Relevant only for eSR. + * @reserved1: in version 2, listen_lmac became reserved * @cck_rates: basic rates available for CCK * @ofdm_rates: basic rates available for OFDM * @cck_short_preamble: 1 for enabling short preamble, 0 otherwise @@ -471,10 +472,10 @@ enum iwl_link_ctx_flags { * @bssid_index: index of the associated VAP * @bss_color: 11ax AP ID that is used in the HE SIG-A to mark inter BSS frame * @spec_link_id: link_id as the AP knows it - * @reserved: alignment + * @reserved2: alignment * @ibss_bssid_addr: bssid for ibss * @reserved_for_ibss_bssid_addr: reserved - * @reserved1: reserved for future use + * @reserved3: reserved for future use */ struct iwl_link_config_cmd { __le32 action; @@ -485,7 +486,10 @@ struct iwl_link_config_cmd { __le16 reserved_for_local_link_addr; __le32 modify_mask; __le32 active; - __le32 listen_lmac; + union { + __le32 listen_lmac; + __le32 reserved1; + }; __le32 cck_rates; __le32 ofdm_rates; __le32 cck_short_preamble; @@ -511,11 +515,13 @@ struct iwl_link_config_cmd { u8 bssid_index; u8 bss_color; u8 spec_link_id; - u8 reserved; + u8 reserved2; u8 ibss_bssid_addr[6]; __le16 reserved_for_ibss_bssid_addr; - __le32 reserved1[8]; -} __packed; /* LINK_CONTEXT_CONFIG_CMD_API_S_VER_1 */ + __le32 reserved3[8]; +} __packed; /* LINK_CONTEXT_CONFIG_CMD_API_S_VER_1 and + * LINK_CONTEXT_CONFIG_CMD_API_S_VER_2 + */ /* Currently FW supports link ids in the range 0-3 and can have * at most two active links for each vif. diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/link.c b/drivers/net/wireless/intel/iwlwifi/mvm/link.c index be48b0fc9cb6..f3fcef9034ef 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/link.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/link.c @@ -53,6 +53,8 @@ int iwl_mvm_add_link(struct iwl_mvm *mvm, struct ieee80211_vif *vif, unsigned int link_id = link_conf->link_id; struct iwl_mvm_vif_link_info *link_info = mvmvif->link[link_id]; struct iwl_link_config_cmd cmd = {}; + unsigned int cmd_id = WIDE_ID(MAC_CONF_GROUP, LINK_CONFIG_CMD); + u8 cmd_ver = iwl_fw_lookup_cmd_ver(mvm->fw, cmd_id, 1); if (WARN_ON_ONCE(!link_info)) return -EINVAL; @@ -84,7 +86,8 @@ int iwl_mvm_add_link(struct iwl_mvm *mvm, struct ieee80211_vif *vif, if (vif->type == NL80211_IFTYPE_ADHOC && link_conf->bssid) memcpy(cmd.ibss_bssid_addr, link_conf->bssid, ETH_ALEN); - cmd.listen_lmac = cpu_to_le32(link_info->listen_lmac); + if (cmd_ver < 2) + cmd.listen_lmac = cpu_to_le32(link_info->listen_lmac); return iwl_mvm_link_cmd_send(mvm, &cmd, FW_CTXT_ACTION_ADD); } @@ -100,6 +103,8 @@ int iwl_mvm_link_changed(struct iwl_mvm *mvm, struct ieee80211_vif *vif, struct iwl_link_config_cmd cmd = {}; u32 ht_flag, flags = 0, flags_mask = 0; int ret; + unsigned int cmd_id = WIDE_ID(MAC_CONF_GROUP, LINK_CONFIG_CMD); + u8 cmd_ver = iwl_fw_lookup_cmd_ver(mvm->fw, cmd_id, 1); if (WARN_ON_ONCE(!link_info || link_info->fw_link_id == IWL_MVM_FW_LINK_ID_INVALID)) @@ -224,7 +229,8 @@ send_cmd: cmd.flags = cpu_to_le32(flags); cmd.flags_mask = cpu_to_le32(flags_mask); cmd.spec_link_id = link_conf->link_id; - cmd.listen_lmac = cpu_to_le32(link_info->listen_lmac); + if (cmd_ver < 2) + cmd.listen_lmac = cpu_to_le32(link_info->listen_lmac); ret = iwl_mvm_link_cmd_send(mvm, &cmd, FW_CTXT_ACTION_MODIFY); if (!ret && (changes & LINK_CONTEXT_MODIFY_ACTIVE)) -- cgit v1.2.3 From 669761e897a4fc87ae0e4625590f2a396a87a3d1 Mon Sep 17 00:00:00 2001 From: Miri Korenblit Date: Thu, 1 Feb 2024 16:17:31 +0200 Subject: wifi: iwlwifi: read WRDD table from UEFI Try to read the WRDD table from UEFI first, and if the WIFI UEFI tables are unlocked or the table doesn't exist - try to read it from ACPI. Change iwl_acpi_get_mcc() to receive fwrt as argument so it will be the same as all iwl_acpi_get_x() functions, so it could be generated by the macro. Signed-off-by: Miri Korenblit Reviewed-by: Gregory Greenman Link: https://msgid.link/20240201155157.5d52eeb109f7.I4d81700a7ae7fe2dfee14e363de358be59de7823@changeid Signed-off-by: Johannes Berg --- drivers/net/wireless/intel/iwlwifi/fw/acpi.c | 8 +++--- drivers/net/wireless/intel/iwlwifi/fw/acpi.h | 6 ++--- drivers/net/wireless/intel/iwlwifi/fw/regulatory.c | 1 + drivers/net/wireless/intel/iwlwifi/fw/regulatory.h | 2 ++ drivers/net/wireless/intel/iwlwifi/fw/uefi.c | 31 ++++++++++++++++++++++ drivers/net/wireless/intel/iwlwifi/fw/uefi.h | 19 +++++++++++++ drivers/net/wireless/intel/iwlwifi/mvm/nvm.c | 2 +- 7 files changed, 61 insertions(+), 8 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/intel/iwlwifi/fw/acpi.c b/drivers/net/wireless/intel/iwlwifi/fw/acpi.c index e74745f939ae..ad04d0ebf081 100644 --- a/drivers/net/wireless/intel/iwlwifi/fw/acpi.c +++ b/drivers/net/wireless/intel/iwlwifi/fw/acpi.c @@ -326,17 +326,18 @@ out_free: return ret; } -int iwl_acpi_get_mcc(struct device *dev, char *mcc) +int iwl_acpi_get_mcc(struct iwl_fw_runtime *fwrt, char *mcc) { union acpi_object *wifi_pkg, *data; u32 mcc_val; int ret, tbl_rev; - data = iwl_acpi_get_object(dev, ACPI_WRDD_METHOD); + data = iwl_acpi_get_object(fwrt->dev, ACPI_WRDD_METHOD); if (IS_ERR(data)) return PTR_ERR(data); - wifi_pkg = iwl_acpi_get_wifi_pkg(dev, data, ACPI_WRDD_WIFI_DATA_SIZE, + wifi_pkg = iwl_acpi_get_wifi_pkg(fwrt->dev, data, + ACPI_WRDD_WIFI_DATA_SIZE, &tbl_rev); if (IS_ERR(wifi_pkg)) { ret = PTR_ERR(wifi_pkg); @@ -360,7 +361,6 @@ out_free: kfree(data); return ret; } -IWL_EXPORT_SYMBOL(iwl_acpi_get_mcc); int iwl_acpi_get_pwr_limit(struct iwl_fw_runtime *fwrt, u64 *dflt_pwr_limit) { diff --git a/drivers/net/wireless/intel/iwlwifi/fw/acpi.h b/drivers/net/wireless/intel/iwlwifi/fw/acpi.h index f0ed7174a951..1cb9271158e7 100644 --- a/drivers/net/wireless/intel/iwlwifi/fw/acpi.h +++ b/drivers/net/wireless/intel/iwlwifi/fw/acpi.h @@ -149,12 +149,12 @@ int iwl_acpi_get_dsm_u32(struct device *dev, int rev, int func, /** * iwl_acpi_get_mcc - read MCC from ACPI, if available * - * @dev: the struct device + * @fwrt: the fw runtime struct * @mcc: output buffer (3 bytes) that will get the MCC * * This function tries to read the current MCC from ACPI if available. */ -int iwl_acpi_get_mcc(struct device *dev, char *mcc); +int iwl_acpi_get_mcc(struct iwl_fw_runtime *fwrt, char *mcc); int iwl_acpi_get_pwr_limit(struct iwl_fw_runtime *fwrt, u64 *dflt_pwr_limit); @@ -207,7 +207,7 @@ static inline int iwl_acpi_get_dsm_u32(struct device *dev, int rev, int func, return -ENOENT; } -static inline int iwl_acpi_get_mcc(struct device *dev, char *mcc) +static inline int iwl_acpi_get_mcc(struct iwl_fw_runtime *fwrt, char *mcc) { return -ENOENT; } diff --git a/drivers/net/wireless/intel/iwlwifi/fw/regulatory.c b/drivers/net/wireless/intel/iwlwifi/fw/regulatory.c index 452c7cc49c27..65022b1c1511 100644 --- a/drivers/net/wireless/intel/iwlwifi/fw/regulatory.c +++ b/drivers/net/wireless/intel/iwlwifi/fw/regulatory.c @@ -36,6 +36,7 @@ IWL_BIOS_TABLE_LOADER(wgds_table); IWL_BIOS_TABLE_LOADER(ppag_table); IWL_BIOS_TABLE_LOADER_DATA(tas_table, struct iwl_tas_data); IWL_BIOS_TABLE_LOADER_DATA(pwr_limit, u64); +IWL_BIOS_TABLE_LOADER_DATA(mcc, char); static const struct dmi_system_id dmi_ppag_approved_list[] = { diff --git a/drivers/net/wireless/intel/iwlwifi/fw/regulatory.h b/drivers/net/wireless/intel/iwlwifi/fw/regulatory.h index b391c6fc3bcc..f75ca5f7faaf 100644 --- a/drivers/net/wireless/intel/iwlwifi/fw/regulatory.h +++ b/drivers/net/wireless/intel/iwlwifi/fw/regulatory.h @@ -139,4 +139,6 @@ int iwl_bios_get_tas_table(struct iwl_fw_runtime *fwrt, int iwl_bios_get_pwr_limit(struct iwl_fw_runtime *fwrt, u64 *dflt_pwr_limit); + +int iwl_bios_get_mcc(struct iwl_fw_runtime *fwrt, char *mcc); #endif /* __fw_regulatory_h__ */ diff --git a/drivers/net/wireless/intel/iwlwifi/fw/uefi.c b/drivers/net/wireless/intel/iwlwifi/fw/uefi.c index 5ec82205be12..cd897ad504d6 100644 --- a/drivers/net/wireless/intel/iwlwifi/fw/uefi.c +++ b/drivers/net/wireless/intel/iwlwifi/fw/uefi.c @@ -621,3 +621,34 @@ out: kfree(data); return ret; } + +int iwl_uefi_get_mcc(struct iwl_fw_runtime *fwrt, char *mcc) +{ + struct uefi_cnv_var_wrdd *data; + int ret = 0; + + data = iwl_uefi_get_verified_variable(fwrt->trans, IWL_UEFI_WRDD_NAME, + "WRDD", sizeof(*data), NULL); + if (IS_ERR(data)) + return -EINVAL; + + if (data->revision != IWL_UEFI_WRDD_REVISION) { + ret = -EINVAL; + IWL_DEBUG_RADIO(fwrt, "Unsupported UEFI WRDD revision:%d\n", + data->revision); + goto out; + } + + if (data->mcc != UEFI_MCC_CHINA) { + ret = -EINVAL; + IWL_DEBUG_RADIO(fwrt, "UEFI WRDD is supported only for CN\n"); + goto out; + } + + mcc[0] = (data->mcc >> 8) & 0xff; + mcc[1] = data->mcc & 0xff; + mcc[2] = '\0'; +out: + kfree(data); + return ret; +} diff --git a/drivers/net/wireless/intel/iwlwifi/fw/uefi.h b/drivers/net/wireless/intel/iwlwifi/fw/uefi.h index 4cf3af576920..62bbd5c992b9 100644 --- a/drivers/net/wireless/intel/iwlwifi/fw/uefi.h +++ b/drivers/net/wireless/intel/iwlwifi/fw/uefi.h @@ -18,6 +18,7 @@ #define IWL_UEFI_PPAG_NAME L"UefiCnvWlanPPAG" #define IWL_UEFI_WTAS_NAME L"UefiCnvWlanWTAS" #define IWL_UEFI_SPLC_NAME L"UefiCnvWlanSPLC" +#define IWL_UEFI_WRDD_NAME L"UefiCnvWlanWRDD" #define IWL_SGOM_MAP_SIZE 339 @@ -30,6 +31,7 @@ #define IWL_UEFI_MAX_PPAG_REV 3 #define IWL_UEFI_WTAS_REVISION 1 #define IWL_UEFI_SPLC_REVISION 0 +#define IWL_UEFI_WRDD_REVISION 0 struct pnvm_sku_package { u8 rev; @@ -142,6 +144,17 @@ struct uefi_cnv_var_splc { u32 default_pwr_limit; } __packed; +#define UEFI_MCC_CHINA 0x434e + +/* struct uefi_cnv_var_wrdd - WRDD table as defined in UEFI + * @revision: the revision of the table + * @mcc: country identifier as defined in ISO/IEC 3166-1 Alpha 2 code + */ +struct uefi_cnv_var_wrdd { + u8 revision; + u32 mcc; +} __packed; + /* * This is known to be broken on v4.19 and to work on v5.4. Until we * figure out why this is the case and how to make it work, simply @@ -164,6 +177,7 @@ int iwl_uefi_get_tas_table(struct iwl_fw_runtime *fwrt, struct iwl_tas_data *data); int iwl_uefi_get_pwr_limit(struct iwl_fw_runtime *fwrt, u64 *dflt_pwr_limit); +int iwl_uefi_get_mcc(struct iwl_fw_runtime *fwrt, char *mcc); #else /* CONFIG_EFI */ static inline void *iwl_uefi_get_pnvm(struct iwl_trans *trans, size_t *len) { @@ -227,6 +241,11 @@ static inline int iwl_uefi_get_pwr_limit(struct iwl_fw_runtime *fwrt, *dflt_pwr_limit = 0; return 0; } + +static inline int iwl_uefi_get_mcc(struct iwl_fw_runtime *fwrt, char *mcc) +{ + return -ENOENT; +} #endif /* CONFIG_EFI */ #if defined(CONFIG_EFI) && defined(CONFIG_ACPI) diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/nvm.c b/drivers/net/wireless/intel/iwlwifi/mvm/nvm.c index c0dd441e800e..ae8177222881 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/nvm.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/nvm.c @@ -590,7 +590,7 @@ int iwl_mvm_init_mcc(struct iwl_mvm *mvm) return -EIO; if (iwl_mvm_is_wifi_mcc_supported(mvm) && - !iwl_acpi_get_mcc(mvm->dev, mcc)) { + !iwl_bios_get_mcc(&mvm->fwrt, mcc)) { kfree(regd); regd = iwl_mvm_get_regdomain(mvm->hw->wiphy, mcc, MCC_SOURCE_BIOS, NULL); -- cgit v1.2.3 From 20935f3e646e687f32f044d9d75a4a8637c086db Mon Sep 17 00:00:00 2001 From: Miri Korenblit Date: Thu, 1 Feb 2024 16:17:32 +0200 Subject: wifi: iwlwifi: read ECKV table from UEFI Try to read the ECKV table from UEFI first, and if the WIFI UEFI tables are unlocked or the table doesn't exist - try to read it from ACPI. Change iwl_acpi_get_eckv() to receive fwrt as argument so it will be the same as all iwl_acpi_get_x() functions, so it could be generated by the macro. While at it - move the reading of ECKV to INIT stage. There is no reason to read it each time we load the FW. Signed-off-by: Miri Korenblit Reviewed-by: Gregory Greenman Link: https://msgid.link/20240201155157.d4937cc00727.I36e5fc7f7850229b9b377c80b5203aa47137c97c@changeid Signed-off-by: Johannes Berg --- drivers/net/wireless/intel/iwlwifi/fw/acpi.c | 8 ++++---- drivers/net/wireless/intel/iwlwifi/fw/acpi.h | 6 +++--- drivers/net/wireless/intel/iwlwifi/fw/regulatory.c | 1 + drivers/net/wireless/intel/iwlwifi/fw/regulatory.h | 1 + drivers/net/wireless/intel/iwlwifi/fw/uefi.c | 22 ++++++++++++++++++++++ drivers/net/wireless/intel/iwlwifi/fw/uefi.h | 17 +++++++++++++++++ drivers/net/wireless/intel/iwlwifi/mvm/fw.c | 6 +++--- 7 files changed, 51 insertions(+), 10 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/intel/iwlwifi/fw/acpi.c b/drivers/net/wireless/intel/iwlwifi/fw/acpi.c index ad04d0ebf081..7b422ebe2241 100644 --- a/drivers/net/wireless/intel/iwlwifi/fw/acpi.c +++ b/drivers/net/wireless/intel/iwlwifi/fw/acpi.c @@ -386,16 +386,17 @@ out: return ret; } -int iwl_acpi_get_eckv(struct device *dev, u32 *extl_clk) +int iwl_acpi_get_eckv(struct iwl_fw_runtime *fwrt, u32 *extl_clk) { union acpi_object *wifi_pkg, *data; int ret, tbl_rev; - data = iwl_acpi_get_object(dev, ACPI_ECKV_METHOD); + data = iwl_acpi_get_object(fwrt->dev, ACPI_ECKV_METHOD); if (IS_ERR(data)) return PTR_ERR(data); - wifi_pkg = iwl_acpi_get_wifi_pkg(dev, data, ACPI_ECKV_WIFI_DATA_SIZE, + wifi_pkg = iwl_acpi_get_wifi_pkg(fwrt->dev, data, + ACPI_ECKV_WIFI_DATA_SIZE, &tbl_rev); if (IS_ERR(wifi_pkg)) { ret = PTR_ERR(wifi_pkg); @@ -416,7 +417,6 @@ out_free: kfree(data); return ret; } -IWL_EXPORT_SYMBOL(iwl_acpi_get_eckv); static int iwl_acpi_sar_set_profile(union acpi_object *table, struct iwl_sar_profile *profile, diff --git a/drivers/net/wireless/intel/iwlwifi/fw/acpi.h b/drivers/net/wireless/intel/iwlwifi/fw/acpi.h index 1cb9271158e7..ac6655c1f777 100644 --- a/drivers/net/wireless/intel/iwlwifi/fw/acpi.h +++ b/drivers/net/wireless/intel/iwlwifi/fw/acpi.h @@ -161,13 +161,13 @@ int iwl_acpi_get_pwr_limit(struct iwl_fw_runtime *fwrt, u64 *dflt_pwr_limit); /* * iwl_acpi_get_eckv - read external clock validation from ACPI, if available * - * @dev: the struct device + * @fwrt: the fw runtime struct * @extl_clk: output var (2 bytes) that will get the clk indication. * * This function tries to read the external clock indication * from ACPI if available. */ -int iwl_acpi_get_eckv(struct device *dev, u32 *extl_clk); +int iwl_acpi_get_eckv(struct iwl_fw_runtime *fwrt, u32 *extl_clk); int iwl_acpi_get_wrds_table(struct iwl_fw_runtime *fwrt); @@ -219,7 +219,7 @@ static inline int iwl_acpi_get_pwr_limit(struct iwl_fw_runtime *fwrt, return 0; } -static inline int iwl_acpi_get_eckv(struct device *dev, u32 *extl_clk) +static inline int iwl_acpi_get_eckv(struct iwl_fw_runtime *fwrt, u32 *extl_clk) { return -ENOENT; } diff --git a/drivers/net/wireless/intel/iwlwifi/fw/regulatory.c b/drivers/net/wireless/intel/iwlwifi/fw/regulatory.c index 65022b1c1511..bb07fbfd81eb 100644 --- a/drivers/net/wireless/intel/iwlwifi/fw/regulatory.c +++ b/drivers/net/wireless/intel/iwlwifi/fw/regulatory.c @@ -37,6 +37,7 @@ IWL_BIOS_TABLE_LOADER(ppag_table); IWL_BIOS_TABLE_LOADER_DATA(tas_table, struct iwl_tas_data); IWL_BIOS_TABLE_LOADER_DATA(pwr_limit, u64); IWL_BIOS_TABLE_LOADER_DATA(mcc, char); +IWL_BIOS_TABLE_LOADER_DATA(eckv, u32); static const struct dmi_system_id dmi_ppag_approved_list[] = { diff --git a/drivers/net/wireless/intel/iwlwifi/fw/regulatory.h b/drivers/net/wireless/intel/iwlwifi/fw/regulatory.h index f75ca5f7faaf..ec408c06235d 100644 --- a/drivers/net/wireless/intel/iwlwifi/fw/regulatory.h +++ b/drivers/net/wireless/intel/iwlwifi/fw/regulatory.h @@ -141,4 +141,5 @@ int iwl_bios_get_pwr_limit(struct iwl_fw_runtime *fwrt, u64 *dflt_pwr_limit); int iwl_bios_get_mcc(struct iwl_fw_runtime *fwrt, char *mcc); +int iwl_bios_get_eckv(struct iwl_fw_runtime *fwrt, u32 *ext_clk); #endif /* __fw_regulatory_h__ */ diff --git a/drivers/net/wireless/intel/iwlwifi/fw/uefi.c b/drivers/net/wireless/intel/iwlwifi/fw/uefi.c index cd897ad504d6..4454fae84d1f 100644 --- a/drivers/net/wireless/intel/iwlwifi/fw/uefi.c +++ b/drivers/net/wireless/intel/iwlwifi/fw/uefi.c @@ -652,3 +652,25 @@ out: kfree(data); return ret; } + +int iwl_uefi_get_eckv(struct iwl_fw_runtime *fwrt, u32 *extl_clk) +{ + struct uefi_cnv_var_eckv *data; + int ret = 0; + + data = iwl_uefi_get_verified_variable(fwrt->trans, IWL_UEFI_ECKV_NAME, + "ECKV", sizeof(*data), NULL); + if (IS_ERR(data)) + return -EINVAL; + + if (data->revision != IWL_UEFI_ECKV_REVISION) { + ret = -EINVAL; + IWL_DEBUG_RADIO(fwrt, "Unsupported UEFI WRDD revision:%d\n", + data->revision); + goto out; + } + *extl_clk = data->ext_clock_valid; +out: + kfree(data); + return ret; +} diff --git a/drivers/net/wireless/intel/iwlwifi/fw/uefi.h b/drivers/net/wireless/intel/iwlwifi/fw/uefi.h index 62bbd5c992b9..723933b0b2f1 100644 --- a/drivers/net/wireless/intel/iwlwifi/fw/uefi.h +++ b/drivers/net/wireless/intel/iwlwifi/fw/uefi.h @@ -19,6 +19,7 @@ #define IWL_UEFI_WTAS_NAME L"UefiCnvWlanWTAS" #define IWL_UEFI_SPLC_NAME L"UefiCnvWlanSPLC" #define IWL_UEFI_WRDD_NAME L"UefiCnvWlanWRDD" +#define IWL_UEFI_ECKV_NAME L"UefiCnvWlanECKV" #define IWL_SGOM_MAP_SIZE 339 @@ -32,6 +33,7 @@ #define IWL_UEFI_WTAS_REVISION 1 #define IWL_UEFI_SPLC_REVISION 0 #define IWL_UEFI_WRDD_REVISION 0 +#define IWL_UEFI_ECKV_REVISION 0 struct pnvm_sku_package { u8 rev; @@ -155,6 +157,15 @@ struct uefi_cnv_var_wrdd { u32 mcc; } __packed; +/* struct uefi_cnv_var_eckv - ECKV table as defined in UEFI + * @revision: the revision of the table + * @ext_clock_valid: indicates if external 32KHz clock is valid + */ +struct uefi_cnv_var_eckv { + u8 revision; + u32 ext_clock_valid; +} __packed; + /* * This is known to be broken on v4.19 and to work on v5.4. Until we * figure out why this is the case and how to make it work, simply @@ -178,6 +189,7 @@ int iwl_uefi_get_tas_table(struct iwl_fw_runtime *fwrt, int iwl_uefi_get_pwr_limit(struct iwl_fw_runtime *fwrt, u64 *dflt_pwr_limit); int iwl_uefi_get_mcc(struct iwl_fw_runtime *fwrt, char *mcc); +int iwl_uefi_get_eckv(struct iwl_fw_runtime *fwrt, u32 *extl_clk); #else /* CONFIG_EFI */ static inline void *iwl_uefi_get_pnvm(struct iwl_trans *trans, size_t *len) { @@ -246,6 +258,11 @@ static inline int iwl_uefi_get_mcc(struct iwl_fw_runtime *fwrt, char *mcc) { return -ENOENT; } + +static inline int iwl_uefi_get_eckv(struct iwl_fw_runtime *fwrt, u32 *extl_clk) +{ + return -ENOENT; +} #endif /* CONFIG_EFI */ #if defined(CONFIG_EFI) && defined(CONFIG_ACPI) diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/fw.c b/drivers/net/wireless/intel/iwlwifi/mvm/fw.c index 72f8a6cf20c7..fea2e8a5102d 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/fw.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/fw.c @@ -1409,6 +1409,9 @@ void iwl_mvm_get_bios_tables(struct iwl_mvm *mvm) } iwl_acpi_get_phy_filters(&mvm->fwrt, &mvm->phy_filters); + + if (iwl_bios_get_eckv(&mvm->fwrt, &mvm->ext_clock_valid)) + IWL_DEBUG_RADIO(mvm, "ECKV table doesn't exist in BIOS\n"); } static void iwl_mvm_disconnect_iterator(void *data, u8 *mac, @@ -1705,9 +1708,6 @@ int iwl_mvm_up(struct iwl_mvm *mvm) if (!mvm->ptp_data.ptp_clock) iwl_mvm_ptp_init(mvm); - if (iwl_acpi_get_eckv(mvm->dev, &mvm->ext_clock_valid)) - IWL_DEBUG_INFO(mvm, "ECKV table doesn't exist in BIOS\n"); - ret = iwl_mvm_ppag_init(mvm); if (ret) goto error; -- cgit v1.2.3 From dc2b94a111e0fb3779a86dd8d303ad842880f869 Mon Sep 17 00:00:00 2001 From: Miri Korenblit Date: Thu, 1 Feb 2024 16:17:33 +0200 Subject: wifi: iwlwifi: rfi: use a single DSM function for all RFI configurations RFI configuration moved from internal guid to the wifi guid, DSM function 11. Update reading RFI configuration from BIOS. Signed-off-by: Anjaneyulu Signed-off-by: Miri Korenblit Reviewed-by: Gregory Greenman Link: https://msgid.link/20240201155157.f4e62435310d.I4f9b6860dd8e3c7ae1f816be5ff8b5967eee266f@changeid Signed-off-by: Johannes Berg --- drivers/net/wireless/intel/iwlwifi/fw/acpi.c | 5 ---- drivers/net/wireless/intel/iwlwifi/fw/acpi.h | 14 ++++----- drivers/net/wireless/intel/iwlwifi/mvm/fw.c | 43 +++++++++++++++++----------- 3 files changed, 32 insertions(+), 30 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/intel/iwlwifi/fw/acpi.c b/drivers/net/wireless/intel/iwlwifi/fw/acpi.c index 7b422ebe2241..6f9ead79978a 100644 --- a/drivers/net/wireless/intel/iwlwifi/fw/acpi.c +++ b/drivers/net/wireless/intel/iwlwifi/fw/acpi.c @@ -14,11 +14,6 @@ const guid_t iwl_guid = GUID_INIT(0xF21202BF, 0x8F78, 0x4DC6, 0x8E, 0x28, 0x5A, 0xDE); IWL_EXPORT_SYMBOL(iwl_guid); -const guid_t iwl_rfi_guid = GUID_INIT(0x7266172C, 0x220B, 0x4B29, - 0x81, 0x4F, 0x75, 0xE4, - 0xDD, 0x26, 0xB5, 0xFD); -IWL_EXPORT_SYMBOL(iwl_rfi_guid); - static int iwl_acpi_get_handle(struct device *dev, acpi_string method, acpi_handle *ret_handle) { diff --git a/drivers/net/wireless/intel/iwlwifi/fw/acpi.h b/drivers/net/wireless/intel/iwlwifi/fw/acpi.h index ac6655c1f777..e6d68ab83ba9 100644 --- a/drivers/net/wireless/intel/iwlwifi/fw/acpi.h +++ b/drivers/net/wireless/intel/iwlwifi/fw/acpi.h @@ -103,6 +103,7 @@ enum iwl_dsm_funcs_rev_0 { DSM_FUNC_ACTIVATE_CHANNEL = 8, DSM_FUNC_FORCE_DISABLE_CHANNELS = 9, DSM_FUNC_ENERGY_DETECTION_THRESHOLD = 10, + DSM_FUNC_RFI_CONFIG = 11 }; enum iwl_dsm_values_srd { @@ -119,16 +120,14 @@ enum iwl_dsm_values_indonesia { DSM_VALUE_INDONESIA_MAX }; -/* DSM RFI uses a different GUID, so need separate definitions */ - -#define DSM_RFI_FUNC_ENABLE 3 - enum iwl_dsm_values_rfi { - DSM_VALUE_RFI_ENABLE, - DSM_VALUE_RFI_DISABLE, - DSM_VALUE_RFI_MAX + DSM_VALUE_RFI_DLVR_DISABLE = BIT(0), + DSM_VALUE_RFI_DDR_DISABLE = BIT(1), }; +#define DSM_VALUE_RFI_DISABLE (DSM_VALUE_RFI_DLVR_DISABLE |\ + DSM_VALUE_RFI_DDR_DISABLE) + enum iwl_dsm_masks_reg { DSM_MASK_CHINA_22_REG = BIT(2) }; @@ -138,7 +137,6 @@ enum iwl_dsm_masks_reg { struct iwl_fw_runtime; extern const guid_t iwl_guid; -extern const guid_t iwl_rfi_guid; int iwl_acpi_get_dsm_u8(struct device *dev, int rev, int func, const guid_t *guid, u8 *value); diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/fw.c b/drivers/net/wireless/intel/iwlwifi/mvm/fw.c index fea2e8a5102d..e9b5dc7ee8c7 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/fw.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/fw.c @@ -1203,28 +1203,37 @@ static void iwl_mvm_tas_init(struct iwl_mvm *mvm) #ifdef CONFIG_ACPI -static u8 iwl_mvm_eval_dsm_rfi(struct iwl_mvm *mvm) +static bool iwl_mvm_eval_dsm_rfi(struct iwl_mvm *mvm) { - u8 value; - int ret = iwl_acpi_get_dsm_u8(mvm->fwrt.dev, 0, DSM_RFI_FUNC_ENABLE, - &iwl_rfi_guid, &value); + u8 value = 0; + /* default behaviour is disabled */ + bool bios_enable_rfi = false; + int ret = iwl_acpi_get_dsm_u8(mvm->fwrt.dev, 0, + DSM_FUNC_RFI_CONFIG, &iwl_guid, + &value); if (ret < 0) { IWL_DEBUG_RADIO(mvm, "Failed to get DSM RFI, ret=%d\n", ret); + return bios_enable_rfi; + } - } else if (value >= DSM_VALUE_RFI_MAX) { - IWL_DEBUG_RADIO(mvm, "DSM RFI got invalid value, ret=%d\n", - value); - - } else if (value == DSM_VALUE_RFI_ENABLE) { + value &= DSM_VALUE_RFI_DISABLE; + /* RFI BIOS CONFIG value can be 0 or 3 only. + * i.e 0 means DDR and DLVR enabled. 3 means DDR and DLVR disabled. + * 1 and 2 are invalid BIOS configurations, So, it's not possible to + * disable ddr/dlvr separately. + */ + if (!value) { IWL_DEBUG_RADIO(mvm, "DSM RFI is evaluated to enable\n"); - return DSM_VALUE_RFI_ENABLE; + bios_enable_rfi = true; + } else if (value == DSM_VALUE_RFI_DISABLE) { + IWL_DEBUG_RADIO(mvm, "DSM RFI is evaluated to disable\n"); + } else { + IWL_DEBUG_RADIO(mvm, + "DSM RFI got invalid value, value=%d\n", value); } - IWL_DEBUG_RADIO(mvm, "DSM RFI is disabled\n"); - - /* default behaviour is disabled */ - return DSM_VALUE_RFI_DISABLE; + return bios_enable_rfi; } static void iwl_mvm_lari_cfg(struct iwl_mvm *mvm) @@ -1347,9 +1356,9 @@ static void iwl_mvm_lari_cfg(struct iwl_mvm *mvm) { } -static u8 iwl_mvm_eval_dsm_rfi(struct iwl_mvm *mvm) +static bool iwl_mvm_eval_dsm_rfi(struct iwl_mvm *mvm) { - return DSM_VALUE_RFI_DISABLE; + return false; } #endif /* CONFIG_ACPI */ @@ -1727,7 +1736,7 @@ int iwl_mvm_up(struct iwl_mvm *mvm) iwl_mvm_uats_init(mvm); if (iwl_rfi_supported(mvm)) { - if (iwl_mvm_eval_dsm_rfi(mvm) == DSM_VALUE_RFI_ENABLE) + if (iwl_mvm_eval_dsm_rfi(mvm)) iwl_rfi_send_config_cmd(mvm, NULL); } -- cgit v1.2.3 From b97ada404c4eecb90c79fd884cdc09022d549d20 Mon Sep 17 00:00:00 2001 From: Miri Korenblit Date: Thu, 1 Feb 2024 16:17:34 +0200 Subject: wifi: iwlwifi: take send-DSM-to-FW flows out of ACPI ifdef These functions shouldn't be ACPI_CONFIG dependent, as they don't access the ACPI. The functions that really access ACPI - already handle the case that CONFIG_ACPI is not set. Signed-off-by: Miri Korenblit Reviewed-by: Gregory Greenman Link: https://msgid.link/20240201155157.1412e6d561f8.I84f67478d01b576457e1bf489fbcb044adfda6fe@changeid Signed-off-by: Johannes Berg --- drivers/net/wireless/intel/iwlwifi/fw/acpi.h | 5 ----- drivers/net/wireless/intel/iwlwifi/mvm/fw.c | 15 --------------- 2 files changed, 20 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/intel/iwlwifi/fw/acpi.h b/drivers/net/wireless/intel/iwlwifi/fw/acpi.h index e6d68ab83ba9..8b64888052ad 100644 --- a/drivers/net/wireless/intel/iwlwifi/fw/acpi.h +++ b/drivers/net/wireless/intel/iwlwifi/fw/acpi.h @@ -243,11 +243,6 @@ static inline int iwl_acpi_get_tas_table(struct iwl_fw_runtime *fwrt, return -ENOENT; } -static inline __le32 iwl_acpi_get_lari_config_bitmap(struct iwl_fw_runtime *fwrt) -{ - return 0; -} - static inline int iwl_acpi_get_ppag_table(struct iwl_fw_runtime *fwrt) { return -ENOENT; diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/fw.c b/drivers/net/wireless/intel/iwlwifi/mvm/fw.c index e9b5dc7ee8c7..77464620eafc 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/fw.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/fw.c @@ -1201,8 +1201,6 @@ static void iwl_mvm_tas_init(struct iwl_mvm *mvm) IWL_DEBUG_RADIO(mvm, "failed to send TAS_CONFIG (%d)\n", ret); } -#ifdef CONFIG_ACPI - static bool iwl_mvm_eval_dsm_rfi(struct iwl_mvm *mvm) { u8 value = 0; @@ -1350,19 +1348,6 @@ static void iwl_mvm_lari_cfg(struct iwl_mvm *mvm) mvm->fwrt.uats_enabled = TRUE; } -#else /* CONFIG_ACPI */ - -static void iwl_mvm_lari_cfg(struct iwl_mvm *mvm) -{ -} - -static bool iwl_mvm_eval_dsm_rfi(struct iwl_mvm *mvm) -{ - return false; -} - -#endif /* CONFIG_ACPI */ - void iwl_mvm_get_bios_tables(struct iwl_mvm *mvm) { int ret; -- cgit v1.2.3 From 091d89428f18ac8e67b4032dfa305e957040bdd9 Mon Sep 17 00:00:00 2001 From: Miri Korenblit Date: Thu, 1 Feb 2024 16:17:35 +0200 Subject: wifi: iwlwifi: simplify getting DSM from ACPI As DSMs are going to be read from UEFI too, we need a unified API to get DSMs for both ACPI and UEFI. The difference in getting DSM in each one of these methods (ACPI, UEFI) is in the GUID, revision (0 for ACPI, 4 for UEFI), and size of the DSM values (8 or 32 for ACPI, 32 for UEFI). Therefore, change the iwl_acpi_get_dsm_x() to iwl_acpi_get_dsm() which determines the GUID, revision (these two are the same for all WiFi DSMs), and size (based on a func-to-size mapping) internally. While at it, fix DSM_FUNC_RFI_CONFIG to expect a 32-bit value (as defined in Intel BIOS spec) and not a 8-bit one. Signed-off-by: Miri Korenblit Reviewed-by: Gregory Greenman Link: https://msgid.link/20240201155157.1bcd7072a7a5.I344ee0a11abbc27da0c693187d1b8bee653aaeef@changeid Signed-off-by: Johannes Berg --- drivers/net/wireless/intel/iwlwifi/fw/acpi.c | 89 +++++++++++++----------- drivers/net/wireless/intel/iwlwifi/fw/acpi.h | 33 ++++----- drivers/net/wireless/intel/iwlwifi/mvm/debugfs.c | 4 +- drivers/net/wireless/intel/iwlwifi/mvm/fw.c | 32 +++------ 4 files changed, 73 insertions(+), 85 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/intel/iwlwifi/fw/acpi.c b/drivers/net/wireless/intel/iwlwifi/fw/acpi.c index 6f9ead79978a..22b21bbc294f 100644 --- a/drivers/net/wireless/intel/iwlwifi/fw/acpi.c +++ b/drivers/net/wireless/intel/iwlwifi/fw/acpi.c @@ -12,7 +12,22 @@ const guid_t iwl_guid = GUID_INIT(0xF21202BF, 0x8F78, 0x4DC6, 0xA5, 0xB3, 0x1F, 0x73, 0x8E, 0x28, 0x5A, 0xDE); -IWL_EXPORT_SYMBOL(iwl_guid); + +static const size_t acpi_dsm_size[DSM_FUNC_NUM_FUNCS] = { + [DSM_FUNC_QUERY] = sizeof(u32), + [DSM_FUNC_DISABLE_SRD] = sizeof(u8), + [DSM_FUNC_ENABLE_INDONESIA_5G2] = sizeof(u8), + [DSM_FUNC_ENABLE_6E] = sizeof(u32), + [DSM_FUNC_REGULATORY_CONFIG] = sizeof(u32), + /* Not supported in driver */ + [5] = (size_t)0, + [DSM_FUNC_11AX_ENABLEMENT] = sizeof(u32), + [DSM_FUNC_ENABLE_UNII4_CHAN] = sizeof(u32), + [DSM_FUNC_ACTIVATE_CHANNEL] = sizeof(u32), + [DSM_FUNC_FORCE_DISABLE_CHANNELS] = sizeof(u32), + [DSM_FUNC_ENERGY_DETECTION_THRESHOLD] = sizeof(u32), + [DSM_FUNC_RFI_CONFIG] = sizeof(u32), +}; static int iwl_acpi_get_handle(struct device *dev, acpi_string method, acpi_handle *ret_handle) @@ -137,46 +152,42 @@ out: } /* - * Evaluate a DSM with no arguments and a u8 return value, + * This function receives a DSM function number, calculates its expected size + * according to Intel BIOS spec, and fills in the value in a 32-bit field. + * In case the expected size is smaller than 32-bit, padding will be added. */ -int iwl_acpi_get_dsm_u8(struct device *dev, int rev, int func, - const guid_t *guid, u8 *value) +int iwl_acpi_get_dsm(struct iwl_fw_runtime *fwrt, + enum iwl_dsm_funcs_rev_0 func, u32 *value) { + size_t expected_size; + u64 tmp; int ret; - u64 val; - ret = iwl_acpi_get_dsm_integer(dev, rev, func, - guid, &val, sizeof(u8)); + BUILD_BUG_ON(ARRAY_SIZE(acpi_dsm_size) != DSM_FUNC_NUM_FUNCS); - if (ret < 0) - return ret; + if (WARN_ON(func >= ARRAY_SIZE(acpi_dsm_size))) + return -EINVAL; - /* cast val (u64) to be u8 */ - *value = (u8)val; - return 0; -} -IWL_EXPORT_SYMBOL(iwl_acpi_get_dsm_u8); + expected_size = acpi_dsm_size[func]; -/* - * Evaluate a DSM with no arguments and a u32 return value, - */ -int iwl_acpi_get_dsm_u32(struct device *dev, int rev, int func, - const guid_t *guid, u32 *value) -{ - int ret; - u64 val; - - ret = iwl_acpi_get_dsm_integer(dev, rev, func, - guid, &val, sizeof(u32)); + /* Currently all ACPI DSMs are either 8-bit or 32-bit */ + if (expected_size != sizeof(u8) && expected_size != sizeof(u32)) + return -EOPNOTSUPP; - if (ret < 0) + ret = iwl_acpi_get_dsm_integer(fwrt->dev, ACPI_DSM_REV, func, + &iwl_guid, &tmp, expected_size); + if (ret) return ret; - /* cast val (u64) to be u32 */ - *value = (u32)val; + if ((expected_size == sizeof(u8) && tmp != (u8)tmp) || + (expected_size == sizeof(u32) && tmp != (u32)tmp)) + IWL_DEBUG_RADIO(fwrt, + "DSM value overflows the expected size, truncating\n"); + *value = (u32)tmp; + return 0; } -IWL_EXPORT_SYMBOL(iwl_acpi_get_dsm_u32); +IWL_EXPORT_SYMBOL(iwl_acpi_get_dsm); static union acpi_object * iwl_acpi_get_wifi_pkg_range(struct device *dev, @@ -800,7 +811,6 @@ out_free: __le32 iwl_acpi_get_lari_config_bitmap(struct iwl_fw_runtime *fwrt) { int ret; - u8 value; u32 val; __le32 config_bitmap = 0; @@ -813,11 +823,10 @@ __le32 iwl_acpi_get_lari_config_bitmap(struct iwl_fw_runtime *fwrt) case IWL_CFG_RF_TYPE_HR2: case IWL_CFG_RF_TYPE_JF1: case IWL_CFG_RF_TYPE_JF2: - ret = iwl_acpi_get_dsm_u8(fwrt->dev, 0, - DSM_FUNC_ENABLE_INDONESIA_5G2, - &iwl_guid, &value); + ret = iwl_acpi_get_dsm(fwrt, DSM_FUNC_ENABLE_INDONESIA_5G2, + &val); - if (!ret && value == DSM_VALUE_INDONESIA_ENABLE) + if (!ret && val == DSM_VALUE_INDONESIA_ENABLE) config_bitmap |= cpu_to_le32(LARI_CONFIG_ENABLE_5G2_IN_INDONESIA_MSK); break; @@ -828,14 +837,12 @@ __le32 iwl_acpi_get_lari_config_bitmap(struct iwl_fw_runtime *fwrt) /* ** Evaluate func 'DSM_FUNC_DISABLE_SRD' */ - ret = iwl_acpi_get_dsm_u8(fwrt->dev, 0, - DSM_FUNC_DISABLE_SRD, - &iwl_guid, &value); + ret = iwl_acpi_get_dsm(fwrt, DSM_FUNC_DISABLE_SRD, &val); if (!ret) { - if (value == DSM_VALUE_SRD_PASSIVE) + if (val == DSM_VALUE_SRD_PASSIVE) config_bitmap |= cpu_to_le32(LARI_CONFIG_CHANGE_ETSI_TO_PASSIVE_MSK); - else if (value == DSM_VALUE_SRD_DISABLE) + else if (val == DSM_VALUE_SRD_DISABLE) config_bitmap |= cpu_to_le32(LARI_CONFIG_CHANGE_ETSI_TO_DISABLED_MSK); } @@ -845,9 +852,7 @@ __le32 iwl_acpi_get_lari_config_bitmap(struct iwl_fw_runtime *fwrt) /* ** Evaluate func 'DSM_FUNC_REGULATORY_CONFIG' */ - ret = iwl_acpi_get_dsm_u32(fwrt->dev, 0, - DSM_FUNC_REGULATORY_CONFIG, - &iwl_guid, &val); + ret = iwl_acpi_get_dsm(fwrt, DSM_FUNC_REGULATORY_CONFIG, &val); /* * China 2022 enable if the BIOS object does not exist or * if it is enabled in BIOS. diff --git a/drivers/net/wireless/intel/iwlwifi/fw/acpi.h b/drivers/net/wireless/intel/iwlwifi/fw/acpi.h index 8b64888052ad..d84952f90444 100644 --- a/drivers/net/wireless/intel/iwlwifi/fw/acpi.h +++ b/drivers/net/wireless/intel/iwlwifi/fw/acpi.h @@ -92,6 +92,8 @@ /* The Inidcator whether UEFI WIFI GUID tables are locked is read from ACPI */ #define UEFI_WIFI_GUID_UNLOCKED 0 +#define ACPI_DSM_REV 0 + enum iwl_dsm_funcs_rev_0 { DSM_FUNC_QUERY = 0, DSM_FUNC_DISABLE_SRD = 1, @@ -103,7 +105,8 @@ enum iwl_dsm_funcs_rev_0 { DSM_FUNC_ACTIVATE_CHANNEL = 8, DSM_FUNC_FORCE_DISABLE_CHANNELS = 9, DSM_FUNC_ENERGY_DETECTION_THRESHOLD = 10, - DSM_FUNC_RFI_CONFIG = 11 + DSM_FUNC_RFI_CONFIG = 11, + DSM_FUNC_NUM_FUNCS = 12, }; enum iwl_dsm_values_srd { @@ -138,12 +141,6 @@ struct iwl_fw_runtime; extern const guid_t iwl_guid; -int iwl_acpi_get_dsm_u8(struct device *dev, int rev, int func, - const guid_t *guid, u8 *value); - -int iwl_acpi_get_dsm_u32(struct device *dev, int rev, int func, - const guid_t *guid, u32 *value); - /** * iwl_acpi_get_mcc - read MCC from ACPI, if available * @@ -185,6 +182,9 @@ void iwl_acpi_get_phy_filters(struct iwl_fw_runtime *fwrt, void iwl_acpi_get_guid_lock_status(struct iwl_fw_runtime *fwrt); +int iwl_acpi_get_dsm(struct iwl_fw_runtime *fwrt, + enum iwl_dsm_funcs_rev_0 func, u32 *value); + #else /* CONFIG_ACPI */ static inline void *iwl_acpi_get_dsm_object(struct device *dev, int rev, @@ -193,18 +193,6 @@ static inline void *iwl_acpi_get_dsm_object(struct device *dev, int rev, return ERR_PTR(-ENOENT); } -static inline int iwl_acpi_get_dsm_u8(struct device *dev, int rev, int func, - const guid_t *guid, u8 *value) -{ - return -ENOENT; -} - -static inline int iwl_acpi_get_dsm_u32(struct device *dev, int rev, int func, - const guid_t *guid, u32 *value) -{ - return -ENOENT; -} - static inline int iwl_acpi_get_mcc(struct iwl_fw_runtime *fwrt, char *mcc) { return -ENOENT; @@ -256,6 +244,13 @@ static inline void iwl_acpi_get_phy_filters(struct iwl_fw_runtime *fwrt, static inline void iwl_acpi_get_guid_lock_status(struct iwl_fw_runtime *fwrt) { } + +static inline int iwl_acpi_get_dsm(struct iwl_fw_runtime *fwrt, + enum iwl_dsm_funcs_rev_0 func, + u32 *value) +{ + return -ENOENT; +} #endif /* CONFIG_ACPI */ #endif /* __iwl_fw_acpi__ */ diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/debugfs.c b/drivers/net/wireless/intel/iwlwifi/mvm/debugfs.c index d67986e157a2..6f33f791648e 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/debugfs.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/debugfs.c @@ -391,9 +391,7 @@ static ssize_t iwl_dbgfs_wifi_6e_enable_read(struct file *file, char buf[12]; u32 value; - err = iwl_acpi_get_dsm_u32(mvm->fwrt.dev, 0, - DSM_FUNC_ENABLE_6E, - &iwl_guid, &value); + err = iwl_acpi_get_dsm(&mvm->fwrt, DSM_FUNC_ENABLE_6E, &value); if (err) return err; diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/fw.c b/drivers/net/wireless/intel/iwlwifi/mvm/fw.c index 77464620eafc..f8d7f23741bf 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/fw.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/fw.c @@ -1203,12 +1203,11 @@ static void iwl_mvm_tas_init(struct iwl_mvm *mvm) static bool iwl_mvm_eval_dsm_rfi(struct iwl_mvm *mvm) { - u8 value = 0; + u32 value = 0; /* default behaviour is disabled */ bool bios_enable_rfi = false; - int ret = iwl_acpi_get_dsm_u8(mvm->fwrt.dev, 0, - DSM_FUNC_RFI_CONFIG, &iwl_guid, - &value); + int ret = iwl_acpi_get_dsm(&mvm->fwrt, DSM_FUNC_RFI_CONFIG, &value); + if (ret < 0) { IWL_DEBUG_RADIO(mvm, "Failed to get DSM RFI, ret=%d\n", ret); @@ -1245,41 +1244,32 @@ static void iwl_mvm_lari_cfg(struct iwl_mvm *mvm) cmd.config_bitmap = iwl_acpi_get_lari_config_bitmap(&mvm->fwrt); - ret = iwl_acpi_get_dsm_u32(mvm->fwrt.dev, 0, DSM_FUNC_11AX_ENABLEMENT, - &iwl_guid, &value); + ret = iwl_acpi_get_dsm(&mvm->fwrt, DSM_FUNC_11AX_ENABLEMENT, &value); if (!ret) cmd.oem_11ax_allow_bitmap = cpu_to_le32(value); - ret = iwl_acpi_get_dsm_u32(mvm->fwrt.dev, 0, - DSM_FUNC_ENABLE_UNII4_CHAN, - &iwl_guid, &value); + ret = iwl_acpi_get_dsm(&mvm->fwrt, DSM_FUNC_ENABLE_UNII4_CHAN, &value); if (!ret) cmd.oem_unii4_allow_bitmap = cpu_to_le32(value); - ret = iwl_acpi_get_dsm_u32(mvm->fwrt.dev, 0, - DSM_FUNC_ACTIVATE_CHANNEL, - &iwl_guid, &value); + ret = iwl_acpi_get_dsm(&mvm->fwrt, DSM_FUNC_ACTIVATE_CHANNEL, &value); if (!ret) { if (cmd_ver < 8) value &= ~ACTIVATE_5G2_IN_WW_MASK; cmd.chan_state_active_bitmap = cpu_to_le32(value); } - ret = iwl_acpi_get_dsm_u32(mvm->fwrt.dev, 0, - DSM_FUNC_ENABLE_6E, - &iwl_guid, &value); + ret = iwl_acpi_get_dsm(&mvm->fwrt, DSM_FUNC_ENABLE_6E, &value); if (!ret) cmd.oem_uhb_allow_bitmap = cpu_to_le32(value); - ret = iwl_acpi_get_dsm_u32(mvm->fwrt.dev, 0, - DSM_FUNC_FORCE_DISABLE_CHANNELS, - &iwl_guid, &value); + ret = iwl_acpi_get_dsm(&mvm->fwrt, DSM_FUNC_FORCE_DISABLE_CHANNELS, + &value); if (!ret) cmd.force_disable_channels_bitmap = cpu_to_le32(value); - ret = iwl_acpi_get_dsm_u32(mvm->fwrt.dev, 0, - DSM_FUNC_ENERGY_DETECTION_THRESHOLD, - &iwl_guid, &value); + ret = iwl_acpi_get_dsm(&mvm->fwrt, DSM_FUNC_ENERGY_DETECTION_THRESHOLD, + &value); if (!ret) cmd.edt_bitmap = cpu_to_le32(value); -- cgit v1.2.3 From dc4fe7500e7a1a1ab56a7708ac9be4c90fd12174 Mon Sep 17 00:00:00 2001 From: Miri Korenblit Date: Thu, 1 Feb 2024 16:17:36 +0200 Subject: wifi: iwlwifi: prepare for reading DSM from UEFI Move all the common items (functions, enumerations and mcaros) to regulatory.h/c files, and rename it to a common name. Signed-off-by: Miri Korenblit Reviewed-by: Gregory Greenman Link: https://msgid.link/20240201155157.eae9bcbc0023.If1175f3143d6369076669ddd5d6ad4df0ee00659@changeid Signed-off-by: Johannes Berg --- drivers/net/wireless/intel/iwlwifi/fw/acpi.c | 60 +--------------------- drivers/net/wireless/intel/iwlwifi/fw/acpi.h | 48 +---------------- drivers/net/wireless/intel/iwlwifi/fw/regulatory.c | 49 ++++++++++++++++++ drivers/net/wireless/intel/iwlwifi/fw/regulatory.h | 44 ++++++++++++++++ drivers/net/wireless/intel/iwlwifi/mvm/fw.c | 2 +- 5 files changed, 97 insertions(+), 106 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/intel/iwlwifi/fw/acpi.c b/drivers/net/wireless/intel/iwlwifi/fw/acpi.c index 22b21bbc294f..357047223686 100644 --- a/drivers/net/wireless/intel/iwlwifi/fw/acpi.c +++ b/drivers/net/wireless/intel/iwlwifi/fw/acpi.c @@ -157,7 +157,7 @@ out: * In case the expected size is smaller than 32-bit, padding will be added. */ int iwl_acpi_get_dsm(struct iwl_fw_runtime *fwrt, - enum iwl_dsm_funcs_rev_0 func, u32 *value) + enum iwl_dsm_funcs func, u32 *value) { size_t expected_size; u64 tmp; @@ -808,64 +808,6 @@ out_free: return ret; } -__le32 iwl_acpi_get_lari_config_bitmap(struct iwl_fw_runtime *fwrt) -{ - int ret; - u32 val; - __le32 config_bitmap = 0; - - /* - * Evaluate func 'DSM_FUNC_ENABLE_INDONESIA_5G2'. - * Setting config_bitmap Indonesia bit is valid only for HR/JF. - */ - switch (CSR_HW_RFID_TYPE(fwrt->trans->hw_rf_id)) { - case IWL_CFG_RF_TYPE_HR1: - case IWL_CFG_RF_TYPE_HR2: - case IWL_CFG_RF_TYPE_JF1: - case IWL_CFG_RF_TYPE_JF2: - ret = iwl_acpi_get_dsm(fwrt, DSM_FUNC_ENABLE_INDONESIA_5G2, - &val); - - if (!ret && val == DSM_VALUE_INDONESIA_ENABLE) - config_bitmap |= - cpu_to_le32(LARI_CONFIG_ENABLE_5G2_IN_INDONESIA_MSK); - break; - default: - break; - } - - /* - ** Evaluate func 'DSM_FUNC_DISABLE_SRD' - */ - ret = iwl_acpi_get_dsm(fwrt, DSM_FUNC_DISABLE_SRD, &val); - if (!ret) { - if (val == DSM_VALUE_SRD_PASSIVE) - config_bitmap |= - cpu_to_le32(LARI_CONFIG_CHANGE_ETSI_TO_PASSIVE_MSK); - else if (val == DSM_VALUE_SRD_DISABLE) - config_bitmap |= - cpu_to_le32(LARI_CONFIG_CHANGE_ETSI_TO_DISABLED_MSK); - } - - if (fw_has_capa(&fwrt->fw->ucode_capa, - IWL_UCODE_TLV_CAPA_CHINA_22_REG_SUPPORT)) { - /* - ** Evaluate func 'DSM_FUNC_REGULATORY_CONFIG' - */ - ret = iwl_acpi_get_dsm(fwrt, DSM_FUNC_REGULATORY_CONFIG, &val); - /* - * China 2022 enable if the BIOS object does not exist or - * if it is enabled in BIOS. - */ - if (ret < 0 || val & DSM_MASK_CHINA_22_REG) - config_bitmap |= - cpu_to_le32(LARI_CONFIG_ENABLE_CHINA_22_REG_SUPPORT_MSK); - } - - return config_bitmap; -} -IWL_EXPORT_SYMBOL(iwl_acpi_get_lari_config_bitmap); - int iwl_acpi_get_ppag_table(struct iwl_fw_runtime *fwrt) { union acpi_object *wifi_pkg, *data, *flags; diff --git a/drivers/net/wireless/intel/iwlwifi/fw/acpi.h b/drivers/net/wireless/intel/iwlwifi/fw/acpi.h index d84952f90444..9cb101776884 100644 --- a/drivers/net/wireless/intel/iwlwifi/fw/acpi.h +++ b/drivers/net/wireless/intel/iwlwifi/fw/acpi.h @@ -94,47 +94,6 @@ #define ACPI_DSM_REV 0 -enum iwl_dsm_funcs_rev_0 { - DSM_FUNC_QUERY = 0, - DSM_FUNC_DISABLE_SRD = 1, - DSM_FUNC_ENABLE_INDONESIA_5G2 = 2, - DSM_FUNC_ENABLE_6E = 3, - DSM_FUNC_REGULATORY_CONFIG = 4, - DSM_FUNC_11AX_ENABLEMENT = 6, - DSM_FUNC_ENABLE_UNII4_CHAN = 7, - DSM_FUNC_ACTIVATE_CHANNEL = 8, - DSM_FUNC_FORCE_DISABLE_CHANNELS = 9, - DSM_FUNC_ENERGY_DETECTION_THRESHOLD = 10, - DSM_FUNC_RFI_CONFIG = 11, - DSM_FUNC_NUM_FUNCS = 12, -}; - -enum iwl_dsm_values_srd { - DSM_VALUE_SRD_ACTIVE, - DSM_VALUE_SRD_PASSIVE, - DSM_VALUE_SRD_DISABLE, - DSM_VALUE_SRD_MAX -}; - -enum iwl_dsm_values_indonesia { - DSM_VALUE_INDONESIA_DISABLE, - DSM_VALUE_INDONESIA_ENABLE, - DSM_VALUE_INDONESIA_RESERVED, - DSM_VALUE_INDONESIA_MAX -}; - -enum iwl_dsm_values_rfi { - DSM_VALUE_RFI_DLVR_DISABLE = BIT(0), - DSM_VALUE_RFI_DDR_DISABLE = BIT(1), -}; - -#define DSM_VALUE_RFI_DISABLE (DSM_VALUE_RFI_DLVR_DISABLE |\ - DSM_VALUE_RFI_DDR_DISABLE) - -enum iwl_dsm_masks_reg { - DSM_MASK_CHINA_22_REG = BIT(2) -}; - #ifdef CONFIG_ACPI struct iwl_fw_runtime; @@ -173,8 +132,6 @@ int iwl_acpi_get_wgds_table(struct iwl_fw_runtime *fwrt); int iwl_acpi_get_tas_table(struct iwl_fw_runtime *fwrt, struct iwl_tas_data *data); -__le32 iwl_acpi_get_lari_config_bitmap(struct iwl_fw_runtime *fwrt); - int iwl_acpi_get_ppag_table(struct iwl_fw_runtime *fwrt); void iwl_acpi_get_phy_filters(struct iwl_fw_runtime *fwrt, @@ -183,7 +140,7 @@ void iwl_acpi_get_phy_filters(struct iwl_fw_runtime *fwrt, void iwl_acpi_get_guid_lock_status(struct iwl_fw_runtime *fwrt); int iwl_acpi_get_dsm(struct iwl_fw_runtime *fwrt, - enum iwl_dsm_funcs_rev_0 func, u32 *value); + enum iwl_dsm_funcs func, u32 *value); #else /* CONFIG_ACPI */ @@ -246,8 +203,7 @@ static inline void iwl_acpi_get_guid_lock_status(struct iwl_fw_runtime *fwrt) } static inline int iwl_acpi_get_dsm(struct iwl_fw_runtime *fwrt, - enum iwl_dsm_funcs_rev_0 func, - u32 *value) + enum iwl_dsm_funcs func, u32 *value) { return -ENOENT; } diff --git a/drivers/net/wireless/intel/iwlwifi/fw/regulatory.c b/drivers/net/wireless/intel/iwlwifi/fw/regulatory.c index bb07fbfd81eb..3260f21fd2e0 100644 --- a/drivers/net/wireless/intel/iwlwifi/fw/regulatory.c +++ b/drivers/net/wireless/intel/iwlwifi/fw/regulatory.c @@ -431,3 +431,52 @@ int iwl_parse_tas_selection(struct iwl_fw_runtime *fwrt, return enabled; } + +__le32 iwl_get_lari_config_bitmap(struct iwl_fw_runtime *fwrt) +{ + int ret; + u32 val; + __le32 config_bitmap = 0; + + switch (CSR_HW_RFID_TYPE(fwrt->trans->hw_rf_id)) { + case IWL_CFG_RF_TYPE_HR1: + case IWL_CFG_RF_TYPE_HR2: + case IWL_CFG_RF_TYPE_JF1: + case IWL_CFG_RF_TYPE_JF2: + ret = iwl_acpi_get_dsm(fwrt, DSM_FUNC_ENABLE_INDONESIA_5G2, + &val); + + if (!ret && val == DSM_VALUE_INDONESIA_ENABLE) + config_bitmap |= + cpu_to_le32(LARI_CONFIG_ENABLE_5G2_IN_INDONESIA_MSK); + break; + default: + break; + } + + ret = iwl_acpi_get_dsm(fwrt, DSM_FUNC_DISABLE_SRD, &val); + if (!ret) { + if (val == DSM_VALUE_SRD_PASSIVE) + config_bitmap |= + cpu_to_le32(LARI_CONFIG_CHANGE_ETSI_TO_PASSIVE_MSK); + else if (val == DSM_VALUE_SRD_DISABLE) + config_bitmap |= + cpu_to_le32(LARI_CONFIG_CHANGE_ETSI_TO_DISABLED_MSK); + } + + if (fw_has_capa(&fwrt->fw->ucode_capa, + IWL_UCODE_TLV_CAPA_CHINA_22_REG_SUPPORT)) { + ret = iwl_acpi_get_dsm(fwrt, DSM_FUNC_REGULATORY_CONFIG, + &val); + /* + * China 2022 enable if the BIOS object does not exist or + * if it is enabled in BIOS. + */ + if (ret < 0 || val & DSM_MASK_CHINA_22_REG) + config_bitmap |= + cpu_to_le32(LARI_CONFIG_ENABLE_CHINA_22_REG_SUPPORT_MSK); + } + + return config_bitmap; +} +IWL_EXPORT_SYMBOL(iwl_get_lari_config_bitmap); diff --git a/drivers/net/wireless/intel/iwlwifi/fw/regulatory.h b/drivers/net/wireless/intel/iwlwifi/fw/regulatory.h index ec408c06235d..da49ed7325d6 100644 --- a/drivers/net/wireless/intel/iwlwifi/fw/regulatory.h +++ b/drivers/net/wireless/intel/iwlwifi/fw/regulatory.h @@ -102,6 +102,48 @@ struct iwl_tas_data { u8 usa_tas_uhb_allowed; }; +/* For DSM revision 0 and 4 */ +enum iwl_dsm_funcs { + DSM_FUNC_QUERY = 0, + DSM_FUNC_DISABLE_SRD = 1, + DSM_FUNC_ENABLE_INDONESIA_5G2 = 2, + DSM_FUNC_ENABLE_6E = 3, + DSM_FUNC_REGULATORY_CONFIG = 4, + DSM_FUNC_11AX_ENABLEMENT = 6, + DSM_FUNC_ENABLE_UNII4_CHAN = 7, + DSM_FUNC_ACTIVATE_CHANNEL = 8, + DSM_FUNC_FORCE_DISABLE_CHANNELS = 9, + DSM_FUNC_ENERGY_DETECTION_THRESHOLD = 10, + DSM_FUNC_RFI_CONFIG = 11, + DSM_FUNC_NUM_FUNCS = 12, +}; + +enum iwl_dsm_values_srd { + DSM_VALUE_SRD_ACTIVE, + DSM_VALUE_SRD_PASSIVE, + DSM_VALUE_SRD_DISABLE, + DSM_VALUE_SRD_MAX +}; + +enum iwl_dsm_values_indonesia { + DSM_VALUE_INDONESIA_DISABLE, + DSM_VALUE_INDONESIA_ENABLE, + DSM_VALUE_INDONESIA_RESERVED, + DSM_VALUE_INDONESIA_MAX +}; + +enum iwl_dsm_values_rfi { + DSM_VALUE_RFI_DLVR_DISABLE = BIT(0), + DSM_VALUE_RFI_DDR_DISABLE = BIT(1), +}; + +#define DSM_VALUE_RFI_DISABLE (DSM_VALUE_RFI_DLVR_DISABLE |\ + DSM_VALUE_RFI_DDR_DISABLE) + +enum iwl_dsm_masks_reg { + DSM_MASK_CHINA_22_REG = BIT(2) +}; + struct iwl_fw_runtime; bool iwl_sar_geo_support(struct iwl_fw_runtime *fwrt); @@ -142,4 +184,6 @@ int iwl_bios_get_pwr_limit(struct iwl_fw_runtime *fwrt, int iwl_bios_get_mcc(struct iwl_fw_runtime *fwrt, char *mcc); int iwl_bios_get_eckv(struct iwl_fw_runtime *fwrt, u32 *ext_clk); + +__le32 iwl_get_lari_config_bitmap(struct iwl_fw_runtime *fwrt); #endif /* __fw_regulatory_h__ */ diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/fw.c b/drivers/net/wireless/intel/iwlwifi/mvm/fw.c index f8d7f23741bf..a05a5f403ae5 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/fw.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/fw.c @@ -1242,7 +1242,7 @@ static void iwl_mvm_lari_cfg(struct iwl_mvm *mvm) WIDE_ID(REGULATORY_AND_NVM_GROUP, LARI_CONFIG_CHANGE), 1); - cmd.config_bitmap = iwl_acpi_get_lari_config_bitmap(&mvm->fwrt); + cmd.config_bitmap = iwl_get_lari_config_bitmap(&mvm->fwrt); ret = iwl_acpi_get_dsm(&mvm->fwrt, DSM_FUNC_11AX_ENABLEMENT, &value); if (!ret) -- cgit v1.2.3 From fc7214c3c986142758ae9d2cd456c98e48547b5e Mon Sep 17 00:00:00 2001 From: Miri Korenblit Date: Thu, 1 Feb 2024 16:17:37 +0200 Subject: wifi: iwlwifi: read DSM functions from UEFI For each DSM function, try to first read it from the UEFI. If the UEFI WIFI GUID is unclocked, or the DSM function in UEFI is invalid/unavailable - read it from ACPI. Signed-off-by: Miri Korenblit Reviewed-by: Gregory Greenman Link: https://msgid.link/20240201155157.27dd626ce2bd.Ib90bab74a9d56deb2362edb712294360e4ddae5b@changeid Signed-off-by: Johannes Berg --- drivers/net/wireless/intel/iwlwifi/fw/acpi.c | 1 - drivers/net/wireless/intel/iwlwifi/fw/regulatory.c | 13 +++++++-- drivers/net/wireless/intel/iwlwifi/fw/regulatory.h | 3 ++ drivers/net/wireless/intel/iwlwifi/fw/uefi.c | 33 ++++++++++++++++++++++ drivers/net/wireless/intel/iwlwifi/fw/uefi.h | 21 ++++++++++++++ drivers/net/wireless/intel/iwlwifi/mvm/debugfs.c | 2 +- drivers/net/wireless/intel/iwlwifi/mvm/fw.c | 14 ++++----- 7 files changed, 75 insertions(+), 12 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/intel/iwlwifi/fw/acpi.c b/drivers/net/wireless/intel/iwlwifi/fw/acpi.c index 357047223686..9afb1b1d6aea 100644 --- a/drivers/net/wireless/intel/iwlwifi/fw/acpi.c +++ b/drivers/net/wireless/intel/iwlwifi/fw/acpi.c @@ -187,7 +187,6 @@ int iwl_acpi_get_dsm(struct iwl_fw_runtime *fwrt, return 0; } -IWL_EXPORT_SYMBOL(iwl_acpi_get_dsm); static union acpi_object * iwl_acpi_get_wifi_pkg_range(struct device *dev, diff --git a/drivers/net/wireless/intel/iwlwifi/fw/regulatory.c b/drivers/net/wireless/intel/iwlwifi/fw/regulatory.c index 3260f21fd2e0..a42775141952 100644 --- a/drivers/net/wireless/intel/iwlwifi/fw/regulatory.c +++ b/drivers/net/wireless/intel/iwlwifi/fw/regulatory.c @@ -443,7 +443,7 @@ __le32 iwl_get_lari_config_bitmap(struct iwl_fw_runtime *fwrt) case IWL_CFG_RF_TYPE_HR2: case IWL_CFG_RF_TYPE_JF1: case IWL_CFG_RF_TYPE_JF2: - ret = iwl_acpi_get_dsm(fwrt, DSM_FUNC_ENABLE_INDONESIA_5G2, + ret = iwl_bios_get_dsm(fwrt, DSM_FUNC_ENABLE_INDONESIA_5G2, &val); if (!ret && val == DSM_VALUE_INDONESIA_ENABLE) @@ -454,7 +454,7 @@ __le32 iwl_get_lari_config_bitmap(struct iwl_fw_runtime *fwrt) break; } - ret = iwl_acpi_get_dsm(fwrt, DSM_FUNC_DISABLE_SRD, &val); + ret = iwl_bios_get_dsm(fwrt, DSM_FUNC_DISABLE_SRD, &val); if (!ret) { if (val == DSM_VALUE_SRD_PASSIVE) config_bitmap |= @@ -466,7 +466,7 @@ __le32 iwl_get_lari_config_bitmap(struct iwl_fw_runtime *fwrt) if (fw_has_capa(&fwrt->fw->ucode_capa, IWL_UCODE_TLV_CAPA_CHINA_22_REG_SUPPORT)) { - ret = iwl_acpi_get_dsm(fwrt, DSM_FUNC_REGULATORY_CONFIG, + ret = iwl_bios_get_dsm(fwrt, DSM_FUNC_REGULATORY_CONFIG, &val); /* * China 2022 enable if the BIOS object does not exist or @@ -480,3 +480,10 @@ __le32 iwl_get_lari_config_bitmap(struct iwl_fw_runtime *fwrt) return config_bitmap; } IWL_EXPORT_SYMBOL(iwl_get_lari_config_bitmap); + +int iwl_bios_get_dsm(struct iwl_fw_runtime *fwrt, enum iwl_dsm_funcs func, + u32 *value) +{ + GET_BIOS_TABLE(dsm, fwrt, func, value); +} +IWL_EXPORT_SYMBOL(iwl_bios_get_dsm); diff --git a/drivers/net/wireless/intel/iwlwifi/fw/regulatory.h b/drivers/net/wireless/intel/iwlwifi/fw/regulatory.h index da49ed7325d6..52389f82cbb9 100644 --- a/drivers/net/wireless/intel/iwlwifi/fw/regulatory.h +++ b/drivers/net/wireless/intel/iwlwifi/fw/regulatory.h @@ -186,4 +186,7 @@ int iwl_bios_get_mcc(struct iwl_fw_runtime *fwrt, char *mcc); int iwl_bios_get_eckv(struct iwl_fw_runtime *fwrt, u32 *ext_clk); __le32 iwl_get_lari_config_bitmap(struct iwl_fw_runtime *fwrt); + +int iwl_bios_get_dsm(struct iwl_fw_runtime *fwrt, enum iwl_dsm_funcs func, + u32 *value); #endif /* __fw_regulatory_h__ */ diff --git a/drivers/net/wireless/intel/iwlwifi/fw/uefi.c b/drivers/net/wireless/intel/iwlwifi/fw/uefi.c index 4454fae84d1f..fe6d0141cd5b 100644 --- a/drivers/net/wireless/intel/iwlwifi/fw/uefi.c +++ b/drivers/net/wireless/intel/iwlwifi/fw/uefi.c @@ -674,3 +674,36 @@ out: kfree(data); return ret; } + +int iwl_uefi_get_dsm(struct iwl_fw_runtime *fwrt, enum iwl_dsm_funcs func, + u32 *value) +{ + struct uefi_cnv_var_general_cfg *data; + int ret = EINVAL; + + /* Not supported function index */ + if (func >= DSM_FUNC_NUM_FUNCS || func == 5) + return -EOPNOTSUPP; + + data = iwl_uefi_get_verified_variable(fwrt->trans, IWL_UEFI_DSM_NAME, + "DSM", sizeof(*data), NULL); + if (IS_ERR(data)) + return -EINVAL; + + if (data->revision != IWL_UEFI_DSM_REVISION) { + IWL_DEBUG_RADIO(fwrt, "Unsupported UEFI DSM revision:%d\n", + data->revision); + goto out; + } + + if (ARRAY_SIZE(data->functions) != UEFI_MAX_DSM_FUNCS) { + IWL_DEBUG_RADIO(fwrt, "Invalid size of DSM functions array\n"); + goto out; + } + + *value = data->functions[func]; + ret = 0; +out: + kfree(data); + return ret; +} diff --git a/drivers/net/wireless/intel/iwlwifi/fw/uefi.h b/drivers/net/wireless/intel/iwlwifi/fw/uefi.h index 723933b0b2f1..1f7c3f4c2901 100644 --- a/drivers/net/wireless/intel/iwlwifi/fw/uefi.h +++ b/drivers/net/wireless/intel/iwlwifi/fw/uefi.h @@ -20,6 +20,7 @@ #define IWL_UEFI_SPLC_NAME L"UefiCnvWlanSPLC" #define IWL_UEFI_WRDD_NAME L"UefiCnvWlanWRDD" #define IWL_UEFI_ECKV_NAME L"UefiCnvWlanECKV" +#define IWL_UEFI_DSM_NAME L"UefiCnvWlanGeneralCfg" #define IWL_SGOM_MAP_SIZE 339 @@ -34,6 +35,7 @@ #define IWL_UEFI_SPLC_REVISION 0 #define IWL_UEFI_WRDD_REVISION 0 #define IWL_UEFI_ECKV_REVISION 0 +#define IWL_UEFI_DSM_REVISION 4 struct pnvm_sku_package { u8 rev; @@ -166,6 +168,17 @@ struct uefi_cnv_var_eckv { u32 ext_clock_valid; } __packed; +#define UEFI_MAX_DSM_FUNCS 32 + +/* struct uefi_cnv_var_general_cfg - DSM-like table as defined in UEFI + * @revision: the revision of the table + * @functions: payload of the different DSM functions + */ +struct uefi_cnv_var_general_cfg { + u8 revision; + u32 functions[UEFI_MAX_DSM_FUNCS]; +} __packed; + /* * This is known to be broken on v4.19 and to work on v5.4. Until we * figure out why this is the case and how to make it work, simply @@ -190,6 +203,8 @@ int iwl_uefi_get_pwr_limit(struct iwl_fw_runtime *fwrt, u64 *dflt_pwr_limit); int iwl_uefi_get_mcc(struct iwl_fw_runtime *fwrt, char *mcc); int iwl_uefi_get_eckv(struct iwl_fw_runtime *fwrt, u32 *extl_clk); +int iwl_uefi_get_dsm(struct iwl_fw_runtime *fwrt, enum iwl_dsm_funcs func, + u32 *value); #else /* CONFIG_EFI */ static inline void *iwl_uefi_get_pnvm(struct iwl_trans *trans, size_t *len) { @@ -263,6 +278,12 @@ static inline int iwl_uefi_get_eckv(struct iwl_fw_runtime *fwrt, u32 *extl_clk) { return -ENOENT; } + +static inline int iwl_uefi_get_dsm(struct iwl_fw_runtime *fwrt, + enum iwl_dsm_funcs func, u32 *value) +{ + return -ENOENT; +} #endif /* CONFIG_EFI */ #if defined(CONFIG_EFI) && defined(CONFIG_ACPI) diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/debugfs.c b/drivers/net/wireless/intel/iwlwifi/mvm/debugfs.c index 6f33f791648e..1ba3a559c1d6 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/debugfs.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/debugfs.c @@ -391,7 +391,7 @@ static ssize_t iwl_dbgfs_wifi_6e_enable_read(struct file *file, char buf[12]; u32 value; - err = iwl_acpi_get_dsm(&mvm->fwrt, DSM_FUNC_ENABLE_6E, &value); + err = iwl_bios_get_dsm(&mvm->fwrt, DSM_FUNC_ENABLE_6E, &value); if (err) return err; diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/fw.c b/drivers/net/wireless/intel/iwlwifi/mvm/fw.c index a05a5f403ae5..738e90a4fe2f 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/fw.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/fw.c @@ -1206,7 +1206,7 @@ static bool iwl_mvm_eval_dsm_rfi(struct iwl_mvm *mvm) u32 value = 0; /* default behaviour is disabled */ bool bios_enable_rfi = false; - int ret = iwl_acpi_get_dsm(&mvm->fwrt, DSM_FUNC_RFI_CONFIG, &value); + int ret = iwl_bios_get_dsm(&mvm->fwrt, DSM_FUNC_RFI_CONFIG, &value); if (ret < 0) { @@ -1244,31 +1244,31 @@ static void iwl_mvm_lari_cfg(struct iwl_mvm *mvm) cmd.config_bitmap = iwl_get_lari_config_bitmap(&mvm->fwrt); - ret = iwl_acpi_get_dsm(&mvm->fwrt, DSM_FUNC_11AX_ENABLEMENT, &value); + ret = iwl_bios_get_dsm(&mvm->fwrt, DSM_FUNC_11AX_ENABLEMENT, &value); if (!ret) cmd.oem_11ax_allow_bitmap = cpu_to_le32(value); - ret = iwl_acpi_get_dsm(&mvm->fwrt, DSM_FUNC_ENABLE_UNII4_CHAN, &value); + ret = iwl_bios_get_dsm(&mvm->fwrt, DSM_FUNC_ENABLE_UNII4_CHAN, &value); if (!ret) cmd.oem_unii4_allow_bitmap = cpu_to_le32(value); - ret = iwl_acpi_get_dsm(&mvm->fwrt, DSM_FUNC_ACTIVATE_CHANNEL, &value); + ret = iwl_bios_get_dsm(&mvm->fwrt, DSM_FUNC_ACTIVATE_CHANNEL, &value); if (!ret) { if (cmd_ver < 8) value &= ~ACTIVATE_5G2_IN_WW_MASK; cmd.chan_state_active_bitmap = cpu_to_le32(value); } - ret = iwl_acpi_get_dsm(&mvm->fwrt, DSM_FUNC_ENABLE_6E, &value); + ret = iwl_bios_get_dsm(&mvm->fwrt, DSM_FUNC_ENABLE_6E, &value); if (!ret) cmd.oem_uhb_allow_bitmap = cpu_to_le32(value); - ret = iwl_acpi_get_dsm(&mvm->fwrt, DSM_FUNC_FORCE_DISABLE_CHANNELS, + ret = iwl_bios_get_dsm(&mvm->fwrt, DSM_FUNC_FORCE_DISABLE_CHANNELS, &value); if (!ret) cmd.force_disable_channels_bitmap = cpu_to_le32(value); - ret = iwl_acpi_get_dsm(&mvm->fwrt, DSM_FUNC_ENERGY_DETECTION_THRESHOLD, + ret = iwl_bios_get_dsm(&mvm->fwrt, DSM_FUNC_ENERGY_DETECTION_THRESHOLD, &value); if (!ret) cmd.edt_bitmap = cpu_to_le32(value); -- cgit v1.2.3 From c1b393a7dc237505088129945a85b570af8742da Mon Sep 17 00:00:00 2001 From: Emmanuel Grumbach Date: Thu, 1 Feb 2024 16:17:38 +0200 Subject: wifi: iwlwifi: mvm: don't send BT_COEX_CI command on new devices AX210 and above have this logic offloaded in the firmware and it just ignores the command coming from the driver. Stop sending it. Signed-off-by: Emmanuel Grumbach Signed-off-by: Miri Korenblit Link: https://msgid.link/20240201155157.4e3e0b52f98b.I7e9481050921d95c38f5a21ccc47112b3698e859@changeid Signed-off-by: Johannes Berg --- drivers/net/wireless/intel/iwlwifi/mvm/coex.c | 5 +++++ 1 file changed, 5 insertions(+) (limited to 'drivers/net') diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/coex.c b/drivers/net/wireless/intel/iwlwifi/mvm/coex.c index d26075e3e6ad..2c34c55ca5f4 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/coex.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/coex.c @@ -578,6 +578,11 @@ static void iwl_mvm_bt_coex_notif_handle(struct iwl_mvm *mvm) mvm->hw, IEEE80211_IFACE_ITER_NORMAL, iwl_mvm_bt_notif_iterator, &data); + if (mvm->trans->trans_cfg->device_family >= IWL_DEVICE_FAMILY_AX210) { + rcu_read_unlock(); + return; + } + iwl_mvm_bt_coex_tcm_based_ci(mvm, &data); if (data.primary) { -- cgit v1.2.3 From 12e1a6a5b038bcf2c58fd356758710180222e5bc Mon Sep 17 00:00:00 2001 From: Miri Korenblit Date: Thu, 1 Feb 2024 16:17:40 +0200 Subject: wifi: iwlwifi: bump FW API to 88 for AX/BZ/SC devices Start supporting API version 88 for new devices. Signed-off-by: Miri Korenblit Reviewed-by: Gregory Greenman Link: https://msgid.link/20240201155157.e35556d3f956.I6543857041a33e2b35e67eecf648c9cc6972e60a@changeid Signed-off-by: Johannes Berg --- drivers/net/wireless/intel/iwlwifi/cfg/ax210.c | 2 +- drivers/net/wireless/intel/iwlwifi/cfg/bz.c | 2 +- drivers/net/wireless/intel/iwlwifi/cfg/sc.c | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/intel/iwlwifi/cfg/ax210.c b/drivers/net/wireless/intel/iwlwifi/cfg/ax210.c index 02b727687fb8..456c7fff60a0 100644 --- a/drivers/net/wireless/intel/iwlwifi/cfg/ax210.c +++ b/drivers/net/wireless/intel/iwlwifi/cfg/ax210.c @@ -10,7 +10,7 @@ #include "fw/api/txq.h" /* Highest firmware API version supported */ -#define IWL_AX210_UCODE_API_MAX 87 +#define IWL_AX210_UCODE_API_MAX 88 /* Lowest firmware API version supported */ #define IWL_AX210_UCODE_API_MIN 59 diff --git a/drivers/net/wireless/intel/iwlwifi/cfg/bz.c b/drivers/net/wireless/intel/iwlwifi/cfg/bz.c index b0b003a6a46e..c858f355701e 100644 --- a/drivers/net/wireless/intel/iwlwifi/cfg/bz.c +++ b/drivers/net/wireless/intel/iwlwifi/cfg/bz.c @@ -10,7 +10,7 @@ #include "fw/api/txq.h" /* Highest firmware API version supported */ -#define IWL_BZ_UCODE_API_MAX 87 +#define IWL_BZ_UCODE_API_MAX 88 /* Lowest firmware API version supported */ #define IWL_BZ_UCODE_API_MIN 80 diff --git a/drivers/net/wireless/intel/iwlwifi/cfg/sc.c b/drivers/net/wireless/intel/iwlwifi/cfg/sc.c index 51b8f50d8795..e0679093ed8e 100644 --- a/drivers/net/wireless/intel/iwlwifi/cfg/sc.c +++ b/drivers/net/wireless/intel/iwlwifi/cfg/sc.c @@ -10,7 +10,7 @@ #include "fw/api/txq.h" /* Highest firmware API version supported */ -#define IWL_SC_UCODE_API_MAX 87 +#define IWL_SC_UCODE_API_MAX 88 /* Lowest firmware API version supported */ #define IWL_SC_UCODE_API_MIN 82 -- cgit v1.2.3 From 5932ad87828b267649d750869c89c0f1a3873477 Mon Sep 17 00:00:00 2001 From: Shaul Triebitz Date: Thu, 1 Feb 2024 16:17:41 +0200 Subject: wifi: iwlwifi: mvm: make functions public In the following patch, iwl_mvm_roc_duration_and_delay and iwl_mvm_roc_add_cmd will be called also from time-event.c. Move then there (where they more belong) and make then public. Signed-off-by: Shaul Triebitz Signed-off-by: Miri Korenblit Link: https://msgid.link/20240201155157.3edafc4d59aa.Ic68e90758bcad9ae00e0aa602101842dac60e1a1@changeid Signed-off-by: Johannes Berg --- drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c | 80 ---------------------- drivers/net/wireless/intel/iwlwifi/mvm/mvm.h | 8 +++ .../net/wireless/intel/iwlwifi/mvm/time-event.c | 80 ++++++++++++++++++++++ 3 files changed, 88 insertions(+), 80 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c b/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c index 4bc25d4a87b6..31cb2e313a05 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c @@ -4427,44 +4427,6 @@ static bool iwl_mvm_rx_aux_roc(struct iwl_notif_wait_data *notif_wait, return true; } -#define AUX_ROC_MIN_DURATION MSEC_TO_TU(100) -#define AUX_ROC_MIN_DELAY MSEC_TO_TU(200) -#define AUX_ROC_MAX_DELAY MSEC_TO_TU(600) -#define AUX_ROC_SAFETY_BUFFER MSEC_TO_TU(20) -#define AUX_ROC_MIN_SAFETY_BUFFER MSEC_TO_TU(10) - -static void iwl_mvm_roc_duration_and_delay(struct ieee80211_vif *vif, - u32 duration_ms, - u32 *duration_tu, - u32 *delay) -{ - u32 dtim_interval = vif->bss_conf.dtim_period * - vif->bss_conf.beacon_int; - - *delay = AUX_ROC_MIN_DELAY; - *duration_tu = MSEC_TO_TU(duration_ms); - - /* - * If we are associated we want the delay time to be at least one - * dtim interval so that the FW can wait until after the DTIM and - * then start the time event, this will potentially allow us to - * remain off-channel for the max duration. - * Since we want to use almost a whole dtim interval we would also - * like the delay to be for 2-3 dtim intervals, in case there are - * other time events with higher priority. - */ - if (vif->cfg.assoc) { - *delay = min_t(u32, dtim_interval * 3, AUX_ROC_MAX_DELAY); - /* We cannot remain off-channel longer than the DTIM interval */ - if (dtim_interval <= *duration_tu) { - *duration_tu = dtim_interval - AUX_ROC_SAFETY_BUFFER; - if (*duration_tu <= AUX_ROC_MIN_DURATION) - *duration_tu = dtim_interval - - AUX_ROC_MIN_SAFETY_BUFFER; - } - } -} - static int iwl_mvm_send_aux_roc_cmd(struct iwl_mvm *mvm, struct ieee80211_channel *channel, struct ieee80211_vif *vif, @@ -4562,48 +4524,6 @@ static int iwl_mvm_send_aux_roc_cmd(struct iwl_mvm *mvm, return res; } -static int iwl_mvm_roc_add_cmd(struct iwl_mvm *mvm, - struct ieee80211_channel *channel, - struct ieee80211_vif *vif, - int duration, u32 activity) -{ - int res; - u32 duration_tu, delay; - struct iwl_roc_req roc_req = { - .action = cpu_to_le32(FW_CTXT_ACTION_ADD), - .activity = cpu_to_le32(activity), - .sta_id = cpu_to_le32(mvm->aux_sta.sta_id), - }; - - lockdep_assert_held(&mvm->mutex); - - /* Set the channel info data */ - iwl_mvm_set_chan_info(mvm, &roc_req.channel_info, - channel->hw_value, - iwl_mvm_phy_band_from_nl80211(channel->band), - IWL_PHY_CHANNEL_MODE20, 0); - - iwl_mvm_roc_duration_and_delay(vif, duration, &duration_tu, - &delay); - roc_req.duration = cpu_to_le32(duration_tu); - roc_req.max_delay = cpu_to_le32(delay); - - IWL_DEBUG_TE(mvm, - "\t(requested = %ums, max_delay = %ums)\n", - duration, delay); - IWL_DEBUG_TE(mvm, - "Requesting to remain on channel %u for %utu\n", - channel->hw_value, duration_tu); - - /* Set the node address */ - memcpy(roc_req.node_addr, vif->addr, ETH_ALEN); - - res = iwl_mvm_send_cmd_pdu(mvm, WIDE_ID(MAC_CONF_GROUP, ROC_CMD), - 0, sizeof(roc_req), &roc_req); - - return res; -} - static int iwl_mvm_add_aux_sta_for_hs20(struct iwl_mvm *mvm, u32 lmac_id) { int ret = 0; diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h b/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h index c76ce6b1fa72..eb30c299a71e 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h +++ b/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h @@ -2764,4 +2764,12 @@ iwl_mvm_chanctx_def(struct iwl_mvm *mvm, struct ieee80211_chanctx_conf *ctx) return use_def ? &ctx->def : &ctx->min_def; } +void iwl_mvm_roc_duration_and_delay(struct ieee80211_vif *vif, + u32 duration_ms, + u32 *duration_tu, + u32 *delay); +int iwl_mvm_roc_add_cmd(struct iwl_mvm *mvm, + struct ieee80211_channel *channel, + struct ieee80211_vif *vif, + int duration, u32 activity); #endif /* __IWL_MVM_H__ */ diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/time-event.c b/drivers/net/wireless/intel/iwlwifi/mvm/time-event.c index 703ccdd4d967..60ec5ca6927c 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/time-event.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/time-event.c @@ -986,6 +986,86 @@ void iwl_mvm_rx_session_protect_notif(struct iwl_mvm *mvm, rcu_read_unlock(); } +#define AUX_ROC_MIN_DURATION MSEC_TO_TU(100) +#define AUX_ROC_MIN_DELAY MSEC_TO_TU(200) +#define AUX_ROC_MAX_DELAY MSEC_TO_TU(600) +#define AUX_ROC_SAFETY_BUFFER MSEC_TO_TU(20) +#define AUX_ROC_MIN_SAFETY_BUFFER MSEC_TO_TU(10) + +void iwl_mvm_roc_duration_and_delay(struct ieee80211_vif *vif, + u32 duration_ms, + u32 *duration_tu, + u32 *delay) +{ + u32 dtim_interval = vif->bss_conf.dtim_period * + vif->bss_conf.beacon_int; + + *delay = AUX_ROC_MIN_DELAY; + *duration_tu = MSEC_TO_TU(duration_ms); + + /* + * If we are associated we want the delay time to be at least one + * dtim interval so that the FW can wait until after the DTIM and + * then start the time event, this will potentially allow us to + * remain off-channel for the max duration. + * Since we want to use almost a whole dtim interval we would also + * like the delay to be for 2-3 dtim intervals, in case there are + * other time events with higher priority. + */ + if (vif->cfg.assoc) { + *delay = min_t(u32, dtim_interval * 3, AUX_ROC_MAX_DELAY); + /* We cannot remain off-channel longer than the DTIM interval */ + if (dtim_interval <= *duration_tu) { + *duration_tu = dtim_interval - AUX_ROC_SAFETY_BUFFER; + if (*duration_tu <= AUX_ROC_MIN_DURATION) + *duration_tu = dtim_interval - + AUX_ROC_MIN_SAFETY_BUFFER; + } + } +} + +int iwl_mvm_roc_add_cmd(struct iwl_mvm *mvm, + struct ieee80211_channel *channel, + struct ieee80211_vif *vif, + int duration, u32 activity) +{ + int res; + u32 duration_tu, delay; + struct iwl_roc_req roc_req = { + .action = cpu_to_le32(FW_CTXT_ACTION_ADD), + .activity = cpu_to_le32(activity), + .sta_id = cpu_to_le32(mvm->aux_sta.sta_id), + }; + + lockdep_assert_held(&mvm->mutex); + + /* Set the channel info data */ + iwl_mvm_set_chan_info(mvm, &roc_req.channel_info, + channel->hw_value, + iwl_mvm_phy_band_from_nl80211(channel->band), + IWL_PHY_CHANNEL_MODE20, 0); + + iwl_mvm_roc_duration_and_delay(vif, duration, &duration_tu, + &delay); + roc_req.duration = cpu_to_le32(duration_tu); + roc_req.max_delay = cpu_to_le32(delay); + + IWL_DEBUG_TE(mvm, + "\t(requested = %ums, max_delay = %ums)\n", + duration, delay); + IWL_DEBUG_TE(mvm, + "Requesting to remain on channel %u for %utu\n", + channel->hw_value, duration_tu); + + /* Set the node address */ + memcpy(roc_req.node_addr, vif->addr, ETH_ALEN); + + res = iwl_mvm_send_cmd_pdu(mvm, WIDE_ID(MAC_CONF_GROUP, ROC_CMD), + 0, sizeof(roc_req), &roc_req); + + return res; +} + static int iwl_mvm_start_p2p_roc_session_protection(struct iwl_mvm *mvm, struct ieee80211_vif *vif, -- cgit v1.2.3 From 5f9c1f8f9adaf32e4e39fcf260d4fc20dbfb77c9 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Sun, 4 Feb 2024 10:48:18 +0100 Subject: wifi: iwlwifi: fw: fix compile w/o CONFIG_ACPI The user of this function passes a pointer to a value that doesn't exist when compiled w/o CONFIG_ACPI. Since we don't need the value then, make the non-ACPI version a macro to allow it to still build. Reported-by: kernel test robot Closes: https://lore.kernel.org/oe-kbuild-all/202402031454.syX4cSGN-lkp@intel.com/ Fixes: c4c954547755 ("wifi: iwlwifi: implement WPFC ACPI table loading") Signed-off-by: Johannes Berg --- drivers/net/wireless/intel/iwlwifi/fw/acpi.h | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/intel/iwlwifi/fw/acpi.h b/drivers/net/wireless/intel/iwlwifi/fw/acpi.h index 9cb101776884..1d32b82f73db 100644 --- a/drivers/net/wireless/intel/iwlwifi/fw/acpi.h +++ b/drivers/net/wireless/intel/iwlwifi/fw/acpi.h @@ -193,10 +193,8 @@ static inline int iwl_acpi_get_ppag_table(struct iwl_fw_runtime *fwrt) return -ENOENT; } -static inline void iwl_acpi_get_phy_filters(struct iwl_fw_runtime *fwrt, - struct iwl_phy_specific_cfg *filters) -{ -} +/* macro since the second argument doesn't always exist */ +#define iwl_acpi_get_phy_filters(fwrt, filters) do { } while (0) static inline void iwl_acpi_get_guid_lock_status(struct iwl_fw_runtime *fwrt) { -- cgit v1.2.3 From 4c60c8054dd8a36091aab585569c8d12a0085bd9 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Sun, 4 Feb 2024 10:53:18 +0100 Subject: wifi: iwlwifi: fw: fix compiler warning for NULL string print When the system is compiled without CONFIG_DMI, the function here statically returns NULL, leading to a compiler warning. Catch that and print "" in that case. While at it, fix some indentation in the function. Reported-by: kernel test robot Closes: https://lore.kernel.org/oe-kbuild-all/202402030641.zUTuACYV-lkp@intel.com/ Fixes: 09059c6764a8 ("wifi: iwlwifi: prepare for reading PPAG table from UEFI") Signed-off-by: Johannes Berg --- drivers/net/wireless/intel/iwlwifi/fw/regulatory.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/intel/iwlwifi/fw/regulatory.c b/drivers/net/wireless/intel/iwlwifi/fw/regulatory.c index a42775141952..21b90278d1f2 100644 --- a/drivers/net/wireless/intel/iwlwifi/fw/regulatory.c +++ b/drivers/net/wireless/intel/iwlwifi/fw/regulatory.c @@ -397,9 +397,9 @@ bool iwl_is_ppag_approved(struct iwl_fw_runtime *fwrt) if (!dmi_check_system(dmi_ppag_approved_list)) { IWL_DEBUG_RADIO(fwrt, "System vendor '%s' is not in the approved list, disabling PPAG.\n", - dmi_get_system_info(DMI_SYS_VENDOR)); - fwrt->ppag_flags = 0; - return false; + dmi_get_system_info(DMI_SYS_VENDOR) ?: ""); + fwrt->ppag_flags = 0; + return false; } return true; -- cgit v1.2.3 From 6256760f37baa2e4bf34dcbef69d7450460df9bd Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Sun, 4 Feb 2024 10:56:27 +0100 Subject: wifi: iwlwifi: mvm: fix warnings from dmi_get_system_info() dmi_get_system_info() will statically return NULL when the kernel is compiled without CONFIG_DMI, leading to compiler warnings. Fix that by printing "" in that case. Fixes: c3f40c3e0273 ("iwlwifi: mvm: add US/CA to TAS block list if OEM isn't allowed") Fixes: 9457077df49e ("wifi: iwlwifi: mvm: Add debugfs to get TAS status") Signed-off-by: Johannes Berg --- drivers/net/wireless/intel/iwlwifi/mvm/debugfs.c | 2 +- drivers/net/wireless/intel/iwlwifi/mvm/fw.c | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/debugfs.c b/drivers/net/wireless/intel/iwlwifi/mvm/debugfs.c index 1ba3a559c1d6..79f4ac8cbc72 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/debugfs.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/debugfs.c @@ -880,7 +880,7 @@ static ssize_t iwl_dbgfs_tas_get_status_read(struct file *file, le16_to_cpu(rsp->block_list[i])); pos += scnprintf(pos, endpos - pos, "\nOEM name: %s\n", - dmi_get_system_info(DMI_SYS_VENDOR)); + dmi_get_system_info(DMI_SYS_VENDOR) ?: ""); pos += scnprintf(pos, endpos - pos, "\tVendor In Approved List: %s\n", iwl_is_tas_approved() ? "YES" : "NO"); pos += scnprintf(pos, endpos - pos, diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/fw.c b/drivers/net/wireless/intel/iwlwifi/mvm/fw.c index 738e90a4fe2f..b596a1a83750 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/fw.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/fw.c @@ -1159,7 +1159,7 @@ static void iwl_mvm_tas_init(struct iwl_mvm *mvm) if (!iwl_is_tas_approved()) { IWL_DEBUG_RADIO(mvm, "System vendor '%s' is not in the approved list, disabling TAS in US and Canada.\n", - dmi_get_system_info(DMI_SYS_VENDOR)); + dmi_get_system_info(DMI_SYS_VENDOR) ?: ""); if ((!iwl_mvm_add_to_tas_block_list(data.block_list_array, &data.block_list_size, IWL_MCC_US)) || @@ -1173,7 +1173,7 @@ static void iwl_mvm_tas_init(struct iwl_mvm *mvm) } else { IWL_DEBUG_RADIO(mvm, "System vendor '%s' is in the approved list.\n", - dmi_get_system_info(DMI_SYS_VENDOR)); + dmi_get_system_info(DMI_SYS_VENDOR) ?: ""); } fw_ver = iwl_fw_lookup_cmd_ver(mvm->fw, cmd_id, -- cgit v1.2.3 From 5f0e4aede01cb01fa633171f0533affd25328c3a Mon Sep 17 00:00:00 2001 From: Zhipeng Lu Date: Fri, 26 Jan 2024 15:53:34 +0800 Subject: wifi: libertas: fix some memleaks in lbs_allocate_cmd_buffer() In the for statement of lbs_allocate_cmd_buffer(), if the allocation of cmdarray[i].cmdbuf fails, both cmdarray and cmdarray[i].cmdbuf needs to be freed. Otherwise, there will be memleaks in lbs_allocate_cmd_buffer(). Fixes: 876c9d3aeb98 ("[PATCH] Marvell Libertas 8388 802.11b/g USB driver") Signed-off-by: Zhipeng Lu Signed-off-by: Kalle Valo Link: https://msgid.link/20240126075336.2825608-1-alexious@zju.edu.cn --- drivers/net/wireless/marvell/libertas/cmd.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/marvell/libertas/cmd.c b/drivers/net/wireless/marvell/libertas/cmd.c index 104d2b6dc9af..5a525da434c2 100644 --- a/drivers/net/wireless/marvell/libertas/cmd.c +++ b/drivers/net/wireless/marvell/libertas/cmd.c @@ -1132,7 +1132,7 @@ int lbs_allocate_cmd_buffer(struct lbs_private *priv) if (!cmdarray[i].cmdbuf) { lbs_deb_host("ALLOC_CMD_BUF: ptempvirtualaddr is NULL\n"); ret = -1; - goto done; + goto free_cmd_array; } } @@ -1140,8 +1140,17 @@ int lbs_allocate_cmd_buffer(struct lbs_private *priv) init_waitqueue_head(&cmdarray[i].cmdwait_q); lbs_cleanup_and_insert_cmd(priv, &cmdarray[i]); } - ret = 0; + return 0; +free_cmd_array: + for (i = 0; i < LBS_NUM_CMD_BUFFERS; i++) { + if (cmdarray[i].cmdbuf) { + kfree(cmdarray[i].cmdbuf); + cmdarray[i].cmdbuf = NULL; + } + } + kfree(priv->cmd_array); + priv->cmd_array = NULL; done: return ret; } -- cgit v1.2.3 From 1209f487d452ff7e822dec30661fd6b5163fb8cf Mon Sep 17 00:00:00 2001 From: Chun Qiu Date: Mon, 29 Jan 2024 13:30:30 +0800 Subject: wifi: rtl8xxxu: Add TP-Link TL-WN823N V2 TP-Link TL-WN823N V2 (2357:0135) is based on rtl8192fu and has been tested to work with the rtl8xxxu driver. Signed-off-by: Chun Qiu Signed-off-by: Kalle Valo Link: https://msgid.link/20240129053030.16369-1-cqca@cock.lu --- drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_core.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_core.c b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_core.c index bd6fd3120562..125f03354ceb 100644 --- a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_core.c +++ b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_core.c @@ -7734,7 +7734,7 @@ static int rtl8xxxu_probe(struct usb_interface *interface, untested = 0; break; case 0x2357: - if (id->idProduct == 0x0109) + if (id->idProduct == 0x0109 || id->idProduct == 0x0135) untested = 0; break; case 0x0b05: @@ -8027,6 +8027,9 @@ static const struct usb_device_id dev_table[] = { .driver_info = (unsigned long)&rtl8192fu_fops}, {USB_DEVICE_AND_INTERFACE_INFO(USB_VENDOR_ID_REALTEK, 0x318b, 0xff, 0xff, 0xff), .driver_info = (unsigned long)&rtl8192fu_fops}, +/* TP-Link TL-WN823N V2 */ +{USB_DEVICE_AND_INTERFACE_INFO(0x2357, 0x0135, 0xff, 0xff, 0xff), + .driver_info = (unsigned long)&rtl8192fu_fops}, #ifdef CONFIG_RTL8XXXU_UNTESTED /* Still supported by rtlwifi */ {USB_DEVICE_AND_INTERFACE_INFO(USB_VENDOR_ID_REALTEK, 0x8176, 0xff, 0xff, 0xff), -- cgit v1.2.3 From 2b59c9c30b9cbbb9807abcb2eca0a45ce40611df Mon Sep 17 00:00:00 2001 From: Kalle Valo Date: Tue, 30 Jan 2024 17:15:53 +0200 Subject: wifi: zd1211rw: remove __nocast from zd_addr_t Sparse warns: drivers/net/wireless/zydas/zd1211rw/zd_usb.c:383:24: warning: implicit cast from nocast type drivers/net/wireless/zydas/zd1211rw/zd_usb.c:419:24: warning: implicit cast from nocast type This is an ancient driver which has not have any meaningfuli changes for a long time and hopefully removed soon. So just remove the __nocast to get rid of the sparse warnings. Compile tested only. Signed-off-by: Kalle Valo Link: https://msgid.link/20240130151556.2315951-2-kvalo@kernel.org --- drivers/net/wireless/zydas/zd1211rw/zd_def.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/zydas/zd1211rw/zd_def.h b/drivers/net/wireless/zydas/zd1211rw/zd_def.h index 8ca2d0aab170..2f55e8deee82 100644 --- a/drivers/net/wireless/zydas/zd1211rw/zd_def.h +++ b/drivers/net/wireless/zydas/zd1211rw/zd_def.h @@ -12,7 +12,7 @@ #include #include -typedef u16 __nocast zd_addr_t; +typedef u16 zd_addr_t; #define dev_printk_f(level, dev, fmt, args...) \ dev_printk(level, dev, "%s() " fmt, __func__, ##args) -- cgit v1.2.3 From 0583e5acaf43644c4d4f476979c18bf1a034639f Mon Sep 17 00:00:00 2001 From: Kalle Valo Date: Tue, 30 Jan 2024 17:15:54 +0200 Subject: wifi: rsi: fix restricted __le32 degrades to integer sparse warnings drivers/net/wireless/rsi/rsi_91x_usb.c:235:27: warning: restricted __le32 degrades to integer drivers/net/wireless/rsi/rsi_91x_usb.c:236:27: warning: restricted __le32 degrades to integer drivers/net/wireless/rsi/rsi_91x_usb.c:237:27: warning: restricted __le32 degrades to integer drivers/net/wireless/rsi/rsi_91x_usb.c:238:27: warning: restricted __le32 degrades to integer drivers/net/wireless/rsi/rsi_91x_usb.c:244:36: warning: restricted __le32 degrades to integer drivers/net/wireless/rsi/rsi_91x_usb.c:245:35: warning: restricted __le32 degrades to integer These cpu_to_le32() are not making sense. With usb_reg_buf we handle the values byte at a time to make sure usb_reg_buf is in little endian so no need to convert anything. And usb_control_msg() expects to have the values in native endian anyway. So just remove these so they are not spamming our logs. Compile tested only. Signed-off-by: Kalle Valo Link: https://msgid.link/20240130151556.2315951-3-kvalo@kernel.org --- drivers/net/wireless/rsi/rsi_91x_usb.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/rsi/rsi_91x_usb.c b/drivers/net/wireless/rsi/rsi_91x_usb.c index 10a465686439..dccc139cabb2 100644 --- a/drivers/net/wireless/rsi/rsi_91x_usb.c +++ b/drivers/net/wireless/rsi/rsi_91x_usb.c @@ -232,17 +232,17 @@ static int rsi_usb_reg_write(struct usb_device *usbdev, if (!usb_reg_buf) return status; - usb_reg_buf[0] = (cpu_to_le32(value) & 0x00ff); - usb_reg_buf[1] = (cpu_to_le32(value) & 0xff00) >> 8; - usb_reg_buf[2] = (cpu_to_le32(value) & 0x00ff0000) >> 16; - usb_reg_buf[3] = (cpu_to_le32(value) & 0xff000000) >> 24; + usb_reg_buf[0] = value & 0x00ff; + usb_reg_buf[1] = (value & 0xff00) >> 8; + usb_reg_buf[2] = (value & 0x00ff0000) >> 16; + usb_reg_buf[3] = (value & 0xff000000) >> 24; status = usb_control_msg(usbdev, usb_sndctrlpipe(usbdev, 0), USB_VENDOR_REGISTER_WRITE, RSI_USB_REQ_OUT, - ((cpu_to_le32(reg) & 0xffff0000) >> 16), - (cpu_to_le32(reg) & 0xffff), + (reg & 0xffff0000) >> 16, + reg & 0xffff, (void *)usb_reg_buf, len, USB_CTRL_SET_TIMEOUT); -- cgit v1.2.3 From 7ceade653429c1c6af387d4039199eeae3b685c1 Mon Sep 17 00:00:00 2001 From: Kalle Valo Date: Tue, 30 Jan 2024 17:15:55 +0200 Subject: wifi: cw1200: fix __le16 sparse warnings Sparse warns: drivers/net/wireless/st/cw1200/cw1200_spi.c:83:17: got restricted __le16 [usertype] drivers/net/wireless/st/cw1200/cw1200_spi.c:148:17: warning: incorrect type in assignment (different base types) drivers/net/wireless/st/cw1200/cw1200_spi.c:148:17: expected unsigned short [addressable] [assigned] [usertype] regaddr drivers/net/wireless/st/cw1200/cw1200_spi.c:148:17: got restricted __le16 [usertype] These cpu_to_le16() calls are not really making any sense to me. On a big endian system we first convert regaddr from big to little using cpu_to_le16() but immediately after we convert them back to big endian? So just remove them. Compile tested only. Signed-off-by: Kalle Valo Link: https://msgid.link/20240130151556.2315951-4-kvalo@kernel.org --- drivers/net/wireless/st/cw1200/cw1200_spi.c | 6 ------ 1 file changed, 6 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/st/cw1200/cw1200_spi.c b/drivers/net/wireless/st/cw1200/cw1200_spi.c index c82c0688b549..b27b57fc25bc 100644 --- a/drivers/net/wireless/st/cw1200/cw1200_spi.c +++ b/drivers/net/wireless/st/cw1200/cw1200_spi.c @@ -79,9 +79,6 @@ static int cw1200_spi_memcpy_fromio(struct hwbus_priv *self, pr_info("READ : %04d from 0x%02x (%04x)\n", count, addr, regaddr); #endif - /* Header is LE16 */ - regaddr = cpu_to_le16(regaddr); - /* We have to byteswap if the SPI bus is limited to 8b operation or we are running on a Big Endian system */ @@ -144,9 +141,6 @@ static int cw1200_spi_memcpy_toio(struct hwbus_priv *self, pr_info("WRITE: %04d to 0x%02x (%04x)\n", count, addr, regaddr); #endif - /* Header is LE16 */ - regaddr = cpu_to_le16(regaddr); - /* We have to byteswap if the SPI bus is limited to 8b operation or we are running on a Big Endian system */ -- cgit v1.2.3 From 04e9c8af8b2d9b51febb522c1f2dae7521dbc154 Mon Sep 17 00:00:00 2001 From: Linus Walleij Date: Wed, 31 Jan 2024 23:37:21 +0100 Subject: wifi: ti: wlcore: sdio: Drop unused include The file is including the legacy GPIO header but is not using any symbols from it, drop the header. Signed-off-by: Linus Walleij Signed-off-by: Kalle Valo Link: https://msgid.link/20240131-descriptors-wireless-v1-2-e1c7c5d68746@linaro.org --- drivers/net/wireless/ti/wlcore/sdio.c | 1 - 1 file changed, 1 deletion(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/ti/wlcore/sdio.c b/drivers/net/wireless/ti/wlcore/sdio.c index f0686635db46..45dcc7b400c3 100644 --- a/drivers/net/wireless/ti/wlcore/sdio.c +++ b/drivers/net/wireless/ti/wlcore/sdio.c @@ -16,7 +16,6 @@ #include #include #include -#include #include #include #include -- cgit v1.2.3 From b303de763b638f4a8703651944e7a724739dba74 Mon Sep 17 00:00:00 2001 From: Linus Walleij Date: Wed, 31 Jan 2024 23:37:22 +0100 Subject: wifi: brcmsmac: Drop legacy header The driver is using all the modern abstractions to obtain and use GPIOs and the legacy header is unused, so drop it. Fixes: a8e59744e16b ("gpiolib: split linux/gpio/driver.h out of linux/gpio.h") Signed-off-by: Linus Walleij Signed-off-by: Kalle Valo Link: https://msgid.link/20240131-descriptors-wireless-v1-3-e1c7c5d68746@linaro.org --- drivers/net/wireless/broadcom/brcm80211/brcmsmac/led.c | 1 - 1 file changed, 1 deletion(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmsmac/led.c b/drivers/net/wireless/broadcom/brcm80211/brcmsmac/led.c index 89c8829528c2..9540a05247c2 100644 --- a/drivers/net/wireless/broadcom/brcm80211/brcmsmac/led.c +++ b/drivers/net/wireless/broadcom/brcm80211/brcmsmac/led.c @@ -1,7 +1,6 @@ // SPDX-License-Identifier: GPL-2.0 #include #include -#include #include #include #include -- cgit v1.2.3 From 163857d995312a7b5fe3039ce0145b84cc7673b1 Mon Sep 17 00:00:00 2001 From: Linus Walleij Date: Wed, 31 Jan 2024 23:37:23 +0100 Subject: wifi: mwifiex: Drop unused headers The mwifiex driver include two legacy GPIO headers but does not use symbols from any of them. The driver does contain some "gpio" handling code, but this is some custom GPIO interface, not the Linux GPIO. Signed-off-by: Linus Walleij Signed-off-by: Kalle Valo Link: https://msgid.link/20240131-descriptors-wireless-v1-4-e1c7c5d68746@linaro.org --- drivers/net/wireless/marvell/mwifiex/main.h | 2 -- 1 file changed, 2 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/marvell/mwifiex/main.h b/drivers/net/wireless/marvell/mwifiex/main.h index 318b42b1896f..175882485a19 100644 --- a/drivers/net/wireless/marvell/mwifiex/main.h +++ b/drivers/net/wireless/marvell/mwifiex/main.h @@ -28,11 +28,9 @@ #include #include #include -#include #include #include #include -#include #include #include #include -- cgit v1.2.3 From d8da5a213812cb0092854f586aa26735b59be85b Mon Sep 17 00:00:00 2001 From: Linus Walleij Date: Wed, 31 Jan 2024 23:37:24 +0100 Subject: wifi: plfxlc: Drop unused include The driver includes the legacy GPIO header but does not use any symbols from it. Drop the include. Signed-off-by: Linus Walleij Signed-off-by: Kalle Valo Link: https://msgid.link/20240131-descriptors-wireless-v1-5-e1c7c5d68746@linaro.org --- drivers/net/wireless/purelifi/plfxlc/mac.c | 1 - 1 file changed, 1 deletion(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/purelifi/plfxlc/mac.c b/drivers/net/wireless/purelifi/plfxlc/mac.c index 506d2f31efb5..6f5857d09af0 100644 --- a/drivers/net/wireless/purelifi/plfxlc/mac.c +++ b/drivers/net/wireless/purelifi/plfxlc/mac.c @@ -7,7 +7,6 @@ #include #include #include -#include #include #include -- cgit v1.2.3 From 2719a9e7156c4b3983b43db467c1ff96801bda99 Mon Sep 17 00:00:00 2001 From: Linus Walleij Date: Wed, 31 Jan 2024 23:37:25 +0100 Subject: wifi: cw1200: Convert to GPIO descriptors The CW1200 uses two GPIOs to control the powerup and reset pins, get these from GPIO descriptors instead of being passed as platform data from boardfiles. The RESET line will need to be marked as active low as we will let gpiolib handle the polarity inversion. The SDIO case is a bit special since the "card" need to be powered up before it gets detected on the SDIO bus and properly probed. Fix this by using board-specific GPIOs assigned to device "NULL". There are currently no in-tree users. Signed-off-by: Linus Walleij Signed-off-by: Kalle Valo Link: https://msgid.link/20240131-descriptors-wireless-v1-6-e1c7c5d68746@linaro.org --- drivers/net/wireless/st/cw1200/cw1200_sdio.c | 42 +++++++++------- drivers/net/wireless/st/cw1200/cw1200_spi.c | 71 ++++++++++++++++------------ include/linux/platform_data/net-cw1200.h | 4 -- 3 files changed, 65 insertions(+), 52 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/st/cw1200/cw1200_sdio.c b/drivers/net/wireless/st/cw1200/cw1200_sdio.c index 4c30b5772ce0..00c4731d8f8e 100644 --- a/drivers/net/wireless/st/cw1200/cw1200_sdio.c +++ b/drivers/net/wireless/st/cw1200/cw1200_sdio.c @@ -8,7 +8,7 @@ #include #include -#include +#include #include #include #include @@ -178,12 +178,15 @@ static int cw1200_sdio_irq_unsubscribe(struct hwbus_priv *self) return ret; } +/* Like the rest of the driver, this only supports one device per system */ +static struct gpio_desc *cw1200_reset; +static struct gpio_desc *cw1200_powerup; + static int cw1200_sdio_off(const struct cw1200_platform_data_sdio *pdata) { - if (pdata->reset) { - gpio_set_value(pdata->reset, 0); + if (cw1200_reset) { + gpiod_set_value(cw1200_reset, 0); msleep(30); /* Min is 2 * CLK32K cycles */ - gpio_free(pdata->reset); } if (pdata->power_ctrl) @@ -196,16 +199,21 @@ static int cw1200_sdio_off(const struct cw1200_platform_data_sdio *pdata) static int cw1200_sdio_on(const struct cw1200_platform_data_sdio *pdata) { - /* Ensure I/Os are pulled low */ - if (pdata->reset) { - gpio_request(pdata->reset, "cw1200_wlan_reset"); - gpio_direction_output(pdata->reset, 0); + /* Ensure I/Os are pulled low (reset is active low) */ + cw1200_reset = devm_gpiod_get_optional(NULL, "reset", GPIOD_OUT_HIGH); + if (IS_ERR(cw1200_reset)) { + pr_err("could not get CW1200 SDIO reset GPIO\n"); + return PTR_ERR(cw1200_reset); } - if (pdata->powerup) { - gpio_request(pdata->powerup, "cw1200_wlan_powerup"); - gpio_direction_output(pdata->powerup, 0); + gpiod_set_consumer_name(cw1200_reset, "cw1200_wlan_reset"); + cw1200_powerup = devm_gpiod_get_optional(NULL, "powerup", GPIOD_OUT_LOW); + if (IS_ERR(cw1200_powerup)) { + pr_err("could not get CW1200 SDIO powerup GPIO\n"); + return PTR_ERR(cw1200_powerup); } - if (pdata->reset || pdata->powerup) + gpiod_set_consumer_name(cw1200_powerup, "cw1200_wlan_powerup"); + + if (cw1200_reset || cw1200_powerup) msleep(10); /* Settle time? */ /* Enable 3v3 and 1v8 to hardware */ @@ -226,13 +234,13 @@ static int cw1200_sdio_on(const struct cw1200_platform_data_sdio *pdata) } /* Enable POWERUP signal */ - if (pdata->powerup) { - gpio_set_value(pdata->powerup, 1); + if (cw1200_powerup) { + gpiod_set_value(cw1200_powerup, 1); msleep(250); /* or more..? */ } - /* Enable RSTn signal */ - if (pdata->reset) { - gpio_set_value(pdata->reset, 1); + /* Deassert RSTn signal, note active low */ + if (cw1200_reset) { + gpiod_set_value(cw1200_reset, 0); msleep(50); /* Or more..? */ } return 0; diff --git a/drivers/net/wireless/st/cw1200/cw1200_spi.c b/drivers/net/wireless/st/cw1200/cw1200_spi.c index b27b57fc25bc..fb3aafcafe18 100644 --- a/drivers/net/wireless/st/cw1200/cw1200_spi.c +++ b/drivers/net/wireless/st/cw1200/cw1200_spi.c @@ -11,7 +11,7 @@ */ #include -#include +#include #include #include #include @@ -38,6 +38,8 @@ struct hwbus_priv { const struct cw1200_platform_data_spi *pdata; spinlock_t lock; /* Serialize all bus operations */ wait_queue_head_t wq; + struct gpio_desc *reset; + struct gpio_desc *powerup; int claimed; }; @@ -269,12 +271,12 @@ static void cw1200_spi_irq_unsubscribe(struct hwbus_priv *self) free_irq(self->func->irq, self); } -static int cw1200_spi_off(const struct cw1200_platform_data_spi *pdata) +static int cw1200_spi_off(struct hwbus_priv *self, const struct cw1200_platform_data_spi *pdata) { - if (pdata->reset) { - gpio_set_value(pdata->reset, 0); + if (self->reset) { + /* Assert RESET, note active low */ + gpiod_set_value(self->reset, 1); msleep(30); /* Min is 2 * CLK32K cycles */ - gpio_free(pdata->reset); } if (pdata->power_ctrl) @@ -285,18 +287,12 @@ static int cw1200_spi_off(const struct cw1200_platform_data_spi *pdata) return 0; } -static int cw1200_spi_on(const struct cw1200_platform_data_spi *pdata) +static int cw1200_spi_on(struct hwbus_priv *self, const struct cw1200_platform_data_spi *pdata) { /* Ensure I/Os are pulled low */ - if (pdata->reset) { - gpio_request(pdata->reset, "cw1200_wlan_reset"); - gpio_direction_output(pdata->reset, 0); - } - if (pdata->powerup) { - gpio_request(pdata->powerup, "cw1200_wlan_powerup"); - gpio_direction_output(pdata->powerup, 0); - } - if (pdata->reset || pdata->powerup) + gpiod_direction_output(self->reset, 1); /* Active low */ + gpiod_direction_output(self->powerup, 0); + if (self->reset || self->powerup) msleep(10); /* Settle time? */ /* Enable 3v3 and 1v8 to hardware */ @@ -317,13 +313,13 @@ static int cw1200_spi_on(const struct cw1200_platform_data_spi *pdata) } /* Enable POWERUP signal */ - if (pdata->powerup) { - gpio_set_value(pdata->powerup, 1); + if (self->powerup) { + gpiod_set_value(self->powerup, 1); msleep(250); /* or more..? */ } - /* Enable RSTn signal */ - if (pdata->reset) { - gpio_set_value(pdata->reset, 1); + /* Assert RSTn signal, note active low */ + if (self->reset) { + gpiod_set_value(self->reset, 0); msleep(50); /* Or more..? */ } return 0; @@ -375,20 +371,33 @@ static int cw1200_spi_probe(struct spi_device *func) spi_get_chipselect(func, 0), func->mode, func->bits_per_word, func->max_speed_hz); - if (cw1200_spi_on(plat_data)) { + self = devm_kzalloc(&func->dev, sizeof(*self), GFP_KERNEL); + if (!self) { + pr_err("Can't allocate SPI hwbus_priv."); + return -ENOMEM; + } + + /* Request reset asserted */ + self->reset = devm_gpiod_get_optional(&func->dev, "reset", GPIOD_OUT_HIGH); + if (IS_ERR(self->reset)) + return dev_err_probe(&func->dev, PTR_ERR(self->reset), + "could not get reset GPIO\n"); + gpiod_set_consumer_name(self->reset, "cw1200_wlan_reset"); + + self->powerup = devm_gpiod_get_optional(&func->dev, "powerup", GPIOD_OUT_LOW); + if (IS_ERR(self->powerup)) + return dev_err_probe(&func->dev, PTR_ERR(self->powerup), + "could not get powerup GPIO\n"); + gpiod_set_consumer_name(self->reset, "cw1200_wlan_powerup"); + + if (cw1200_spi_on(self, plat_data)) { pr_err("spi_on() failed!\n"); - return -1; + return -ENODEV; } if (spi_setup(func)) { pr_err("spi_setup() failed!\n"); - return -1; - } - - self = devm_kzalloc(&func->dev, sizeof(*self), GFP_KERNEL); - if (!self) { - pr_err("Can't allocate SPI hwbus_priv."); - return -ENOMEM; + return -ENODEV; } self->pdata = plat_data; @@ -410,7 +419,7 @@ static int cw1200_spi_probe(struct spi_device *func) if (status) { cw1200_spi_irq_unsubscribe(self); - cw1200_spi_off(plat_data); + cw1200_spi_off(self, plat_data); } return status; @@ -428,7 +437,7 @@ static void cw1200_spi_disconnect(struct spi_device *func) self->core = NULL; } } - cw1200_spi_off(dev_get_platdata(&func->dev)); + cw1200_spi_off(self, dev_get_platdata(&func->dev)); } static int __maybe_unused cw1200_spi_suspend(struct device *dev) diff --git a/include/linux/platform_data/net-cw1200.h b/include/linux/platform_data/net-cw1200.h index c510734405bb..89d0ec6f7d46 100644 --- a/include/linux/platform_data/net-cw1200.h +++ b/include/linux/platform_data/net-cw1200.h @@ -14,8 +14,6 @@ struct cw1200_platform_data_spi { /* All others are optional */ bool have_5ghz; - int reset; /* GPIO to RSTn signal (0 disables) */ - int powerup; /* GPIO to POWERUP signal (0 disables) */ int (*power_ctrl)(const struct cw1200_platform_data_spi *pdata, bool enable); /* Control 3v3 / 1v8 supply */ int (*clk_ctrl)(const struct cw1200_platform_data_spi *pdata, @@ -30,8 +28,6 @@ struct cw1200_platform_data_sdio { /* All others are optional */ bool have_5ghz; bool no_nptb; /* SDIO hardware does not support non-power-of-2-blocksizes */ - int reset; /* GPIO to RSTn signal (0 disables) */ - int powerup; /* GPIO to POWERUP signal (0 disables) */ int irq; /* IRQ line or 0 to use SDIO IRQ */ int (*power_ctrl)(const struct cw1200_platform_data_sdio *pdata, bool enable); /* Control 3v3 / 1v8 supply */ -- cgit v1.2.3 From bed41a344426a407ba5e103b2877a2e560e72229 Mon Sep 17 00:00:00 2001 From: David Lechner Date: Thu, 1 Feb 2024 14:12:47 -0600 Subject: wifi: wilc1000: remove setting msg.spi Calling spi_sync() unconditionally sets the spi field of struct spi_message. Therefore setting msg.spi = spi before calling spi_sync() has no effect and can be removed. (spi_message_add_tail() does not access this field.) Signed-off-by: David Lechner Signed-off-by: Kalle Valo Link: https://msgid.link/20240201201248.2334798-2-dlechner@baylibre.com --- drivers/net/wireless/microchip/wilc1000/spi.c | 4 ---- 1 file changed, 4 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/microchip/wilc1000/spi.c b/drivers/net/wireless/microchip/wilc1000/spi.c index 77b4cdff73c3..7eb0f8a421a3 100644 --- a/drivers/net/wireless/microchip/wilc1000/spi.c +++ b/drivers/net/wireless/microchip/wilc1000/spi.c @@ -300,7 +300,6 @@ static int wilc_spi_tx(struct wilc *wilc, u8 *b, u32 len) memset(&msg, 0, sizeof(msg)); spi_message_init(&msg); - msg.spi = spi; spi_message_add_tail(&tr, &msg); ret = spi_sync(spi, &msg); @@ -343,7 +342,6 @@ static int wilc_spi_rx(struct wilc *wilc, u8 *rb, u32 rlen) memset(&msg, 0, sizeof(msg)); spi_message_init(&msg); - msg.spi = spi; spi_message_add_tail(&tr, &msg); ret = spi_sync(spi, &msg); @@ -381,8 +379,6 @@ static int wilc_spi_tx_rx(struct wilc *wilc, u8 *wb, u8 *rb, u32 rlen) memset(&msg, 0, sizeof(msg)); spi_message_init(&msg); - msg.spi = spi; - spi_message_add_tail(&tr, &msg); ret = spi_sync(spi, &msg); if (ret < 0) -- cgit v1.2.3 From ad1c86e92698fa524078abc83a0709ccca06dbcd Mon Sep 17 00:00:00 2001 From: Ping-Ke Shih Date: Fri, 2 Feb 2024 11:06:32 +0800 Subject: wifi: rtw89: rfk: add a completion to wait RF calibration report from C2H event The RF calibrations should be executed one by one, so add a completion to ensure one is finish before next. The report from C2H event contains state and optional version, and we only check the state for now. We also care about the time a RF calibration takes, so record start time before asking firmware to do calibration and get the delta time when receiving report. Consider SER recovery, we can't receive C2H event, use half of argument 'ms' as fixed delay that is 2 times of measured maximum time of calibrations. Signed-off-by: Ping-Ke Shih Signed-off-by: Kalle Valo Link: https://msgid.link/20240202030642.108385-2-pkshih@realtek.com --- drivers/net/wireless/realtek/rtw89/core.c | 1 + drivers/net/wireless/realtek/rtw89/core.h | 16 ++++++++++ drivers/net/wireless/realtek/rtw89/fw.h | 6 ++++ drivers/net/wireless/realtek/rtw89/phy.c | 52 +++++++++++++++++++++++++++++++ drivers/net/wireless/realtek/rtw89/phy.h | 3 ++ 5 files changed, 78 insertions(+) (limited to 'drivers/net') diff --git a/drivers/net/wireless/realtek/rtw89/core.c b/drivers/net/wireless/realtek/rtw89/core.c index 260da86bf04a..c6c3e0c0bf84 100644 --- a/drivers/net/wireless/realtek/rtw89/core.c +++ b/drivers/net/wireless/realtek/rtw89/core.c @@ -4205,6 +4205,7 @@ int rtw89_core_init(struct rtw89_dev *rtwdev) INIT_WORK(&btc->icmp_notify_work, rtw89_btc_ntfy_icmp_packet_work); init_completion(&rtwdev->fw.req.completion); + init_completion(&rtwdev->rfk_wait.completion); schedule_work(&rtwdev->load_firmware_work); diff --git a/drivers/net/wireless/realtek/rtw89/core.h b/drivers/net/wireless/realtek/rtw89/core.h index 30cc77ac78c5..d88a6b9bc4e9 100644 --- a/drivers/net/wireless/realtek/rtw89/core.h +++ b/drivers/net/wireless/realtek/rtw89/core.h @@ -4252,6 +4252,21 @@ struct rtw89_phy_stat { struct rtw89_pkt_stat last_pkt_stat; }; +enum rtw89_rfk_report_state { + RTW89_RFK_STATE_START = 0x0, + RTW89_RFK_STATE_OK = 0x1, + RTW89_RFK_STATE_FAIL = 0x2, + RTW89_RFK_STATE_TIMEOUT = 0x3, + RTW89_RFK_STATE_H2C_CMD_ERR = 0x4, +}; + +struct rtw89_rfk_wait_info { + struct completion completion; + ktime_t start_time; + enum rtw89_rfk_report_state state; + u8 version; +}; + #define RTW89_DACK_PATH_NR 2 #define RTW89_DACK_IDX_NR 2 #define RTW89_DACK_MSBK_NR 16 @@ -4944,6 +4959,7 @@ struct rtw89_dev { DECLARE_BITMAP(pkt_offload, RTW89_MAX_PKT_OFLD_NUM); struct rtw89_phy_stat phystat; + struct rtw89_rfk_wait_info rfk_wait; struct rtw89_dack_info dack; struct rtw89_iqk_info iqk; struct rtw89_dpk_info dpk; diff --git a/drivers/net/wireless/realtek/rtw89/fw.h b/drivers/net/wireless/realtek/rtw89/fw.h index ae69e455cd64..9a2c50c35f2a 100644 --- a/drivers/net/wireless/realtek/rtw89/fw.h +++ b/drivers/net/wireless/realtek/rtw89/fw.h @@ -4013,6 +4013,12 @@ struct rtw89_c2h_rf_txgapk_rpt_log { u8 rsv1; } __packed; +struct rtw89_c2h_rfk_report { + struct rtw89_c2h_hdr hdr; + u8 state; /* enum rtw89_rfk_report_state */ + u8 version; +} __packed; + #define RTW89_FW_RSVD_PLE_SIZE 0x800 #define RTW89_FW_BACKTRACE_INFO_SIZE 8 diff --git a/drivers/net/wireless/realtek/rtw89/phy.c b/drivers/net/wireless/realtek/rtw89/phy.c index f661be2f1287..3de61c0d7b03 100644 --- a/drivers/net/wireless/realtek/rtw89/phy.c +++ b/drivers/net/wireless/realtek/rtw89/phy.c @@ -2834,9 +2834,61 @@ void (* const rtw89_phy_c2h_rfk_log_handler[])(struct rtw89_dev *rtwdev, [RTW89_PHY_C2H_RFK_LOG_FUNC_TXGAPK] = rtw89_phy_c2h_rfk_log_txgapk, }; +void rtw89_phy_rfk_report_prep(struct rtw89_dev *rtwdev) +{ + struct rtw89_rfk_wait_info *wait = &rtwdev->rfk_wait; + + wait->state = RTW89_RFK_STATE_START; + wait->start_time = ktime_get(); + reinit_completion(&wait->completion); +} + +int rtw89_phy_rfk_report_wait(struct rtw89_dev *rtwdev, const char *rfk_name, + unsigned int ms) +{ + struct rtw89_rfk_wait_info *wait = &rtwdev->rfk_wait; + unsigned long time_left; + + /* Since we can't receive C2H event during SER, use a fixed delay. */ + if (test_bit(RTW89_FLAG_SER_HANDLING, rtwdev->flags)) { + fsleep(1000 * ms / 2); + goto out; + } + + time_left = wait_for_completion_timeout(&wait->completion, + msecs_to_jiffies(ms)); + if (time_left == 0) { + rtw89_warn(rtwdev, "failed to wait RF %s\n", rfk_name); + return -ETIMEDOUT; + } else if (wait->state != RTW89_RFK_STATE_OK) { + rtw89_warn(rtwdev, "failed to do RF %s result from state %d\n", + rfk_name, wait->state); + return -EFAULT; + } + +out: + rtw89_debug(rtwdev, RTW89_DBG_RFK, "RF %s takes %lld ms to complete\n", + rfk_name, ktime_ms_delta(ktime_get(), wait->start_time)); + + return 0; +} + static void rtw89_phy_c2h_rfk_report_state(struct rtw89_dev *rtwdev, struct sk_buff *c2h, u32 len) { + const struct rtw89_c2h_rfk_report *report = + (const struct rtw89_c2h_rfk_report *)c2h->data; + struct rtw89_rfk_wait_info *wait = &rtwdev->rfk_wait; + + wait->state = report->state; + wait->version = report->version; + + complete(&wait->completion); + + rtw89_debug(rtwdev, RTW89_DBG_RFK, + "RFK report state %d with version %d (%*ph)\n", + wait->state, wait->version, + (int)(len - sizeof(report->hdr)), &report->state); } static diff --git a/drivers/net/wireless/realtek/rtw89/phy.h b/drivers/net/wireless/realtek/rtw89/phy.h index 13903ca1eaa9..df915cb0833f 100644 --- a/drivers/net/wireless/realtek/rtw89/phy.h +++ b/drivers/net/wireless/realtek/rtw89/phy.h @@ -885,6 +885,9 @@ void rtw89_phy_rate_pattern_vif(struct rtw89_dev *rtwdev, bool rtw89_phy_c2h_chk_atomic(struct rtw89_dev *rtwdev, u8 class, u8 func); void rtw89_phy_c2h_handle(struct rtw89_dev *rtwdev, struct sk_buff *skb, u32 len, u8 class, u8 func); +void rtw89_phy_rfk_report_prep(struct rtw89_dev *rtwdev); +int rtw89_phy_rfk_report_wait(struct rtw89_dev *rtwdev, const char *rfk_name, + unsigned int ms); void rtw89_phy_cfo_track(struct rtw89_dev *rtwdev); void rtw89_phy_cfo_track_work(struct work_struct *work); void rtw89_phy_cfo_parse(struct rtw89_dev *rtwdev, s16 cfo_val, -- cgit v1.2.3 From 80f47f82f3191b5d2530ad510814b4afab121672 Mon Sep 17 00:00:00 2001 From: Ping-Ke Shih Date: Fri, 2 Feb 2024 11:06:33 +0800 Subject: wifi: rtw89: rfk: send channel information to firmware for RF calibrations We are going to do RF calibrations in firmware, so driver needs to provide channel information for calibrations, which can do the same things as they did in driver. Signed-off-by: Ping-Ke Shih Signed-off-by: Kalle Valo Link: https://msgid.link/20240202030642.108385-3-pkshih@realtek.com --- drivers/net/wireless/realtek/rtw89/core.h | 11 +++-- drivers/net/wireless/realtek/rtw89/fw.c | 73 +++++++++++++++++++++++++++++++ drivers/net/wireless/realtek/rtw89/fw.h | 42 ++++++++++++++++++ drivers/net/wireless/realtek/rtw89/reg.h | 2 + 4 files changed, 124 insertions(+), 4 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/realtek/rtw89/core.h b/drivers/net/wireless/realtek/rtw89/core.h index d88a6b9bc4e9..e049f7b5168b 100644 --- a/drivers/net/wireless/realtek/rtw89/core.h +++ b/drivers/net/wireless/realtek/rtw89/core.h @@ -4282,15 +4282,18 @@ struct rtw89_dack_info { bool msbk_timeout[RTW89_DACK_PATH_NR]; }; -#define RTW89_IQK_CHS_NR 2 -#define RTW89_IQK_PATH_NR 4 +#define RTW89_RFK_CHS_NR 3 struct rtw89_rfk_mcc_info { - u8 ch[RTW89_IQK_CHS_NR]; - u8 band[RTW89_IQK_CHS_NR]; + u8 ch[RTW89_RFK_CHS_NR]; + u8 band[RTW89_RFK_CHS_NR]; + u8 bw[RTW89_RFK_CHS_NR]; u8 table_idx; }; +#define RTW89_IQK_CHS_NR 2 +#define RTW89_IQK_PATH_NR 4 + struct rtw89_lck_info { u8 thermal[RF_PATH_MAX]; }; diff --git a/drivers/net/wireless/realtek/rtw89/fw.c b/drivers/net/wireless/realtek/rtw89/fw.c index 2f3f2b503507..5bd3d08a5d25 100644 --- a/drivers/net/wireless/realtek/rtw89/fw.c +++ b/drivers/net/wireless/realtek/rtw89/fw.c @@ -4520,6 +4520,79 @@ fail: } EXPORT_SYMBOL(rtw89_fw_h2c_rf_ntfy_mcc); +int rtw89_fw_h2c_rf_pre_ntfy(struct rtw89_dev *rtwdev, + enum rtw89_phy_idx phy_idx) +{ + struct rtw89_rfk_mcc_info *rfk_mcc = &rtwdev->rfk_mcc; + struct rtw89_fw_h2c_rfk_pre_info *h2c; + u8 tbl_sel = rfk_mcc->table_idx; + u32 len = sizeof(*h2c); + struct sk_buff *skb; + u8 tbl, path; + u32 val32; + int ret; + + skb = rtw89_fw_h2c_alloc_skb_with_hdr(rtwdev, len); + if (!skb) { + rtw89_err(rtwdev, "failed to alloc skb for h2c rfk_pre_ntfy\n"); + return -ENOMEM; + } + skb_put(skb, len); + h2c = (struct rtw89_fw_h2c_rfk_pre_info *)skb->data; + + h2c->mlo_mode = cpu_to_le32(rtwdev->mlo_dbcc_mode); + + BUILD_BUG_ON(NUM_OF_RTW89_FW_RFK_TBL > RTW89_RFK_CHS_NR); + + for (tbl = 0; tbl < NUM_OF_RTW89_FW_RFK_TBL; tbl++) { + for (path = 0; path < NUM_OF_RTW89_FW_RFK_PATH; path++) { + h2c->dbcc.ch[path][tbl] = cpu_to_le32(rfk_mcc->ch[tbl]); + h2c->dbcc.band[path][tbl] = cpu_to_le32(rfk_mcc->band[tbl]); + } + } + + for (path = 0; path < NUM_OF_RTW89_FW_RFK_PATH; path++) { + h2c->tbl.cur_ch[path] = cpu_to_le32(rfk_mcc->ch[tbl_sel]); + h2c->tbl.cur_band[path] = cpu_to_le32(rfk_mcc->band[tbl_sel]); + } + + h2c->phy_idx = cpu_to_le32(phy_idx); + h2c->cur_band = cpu_to_le32(rfk_mcc->band[tbl_sel]); + h2c->cur_bw = cpu_to_le32(rfk_mcc->bw[tbl_sel]); + h2c->cur_center_ch = cpu_to_le32(rfk_mcc->ch[tbl_sel]); + + val32 = rtw89_phy_read32_mask(rtwdev, R_COEF_SEL, B_COEF_SEL_IQC_V1); + h2c->ktbl_sel0 = cpu_to_le32(val32); + val32 = rtw89_phy_read32_mask(rtwdev, R_COEF_SEL_C1, B_COEF_SEL_IQC_V1); + h2c->ktbl_sel1 = cpu_to_le32(val32); + val32 = rtw89_read_rf(rtwdev, RF_PATH_A, RR_CFGCH, RFREG_MASK); + h2c->rfmod0 = cpu_to_le32(val32); + val32 = rtw89_read_rf(rtwdev, RF_PATH_B, RR_CFGCH, RFREG_MASK); + h2c->rfmod1 = cpu_to_le32(val32); + + if (rtw89_is_mlo_1_1(rtwdev)) + h2c->mlo_1_1 = cpu_to_le32(1); + + h2c->rfe_type = cpu_to_le32(rtwdev->efuse.rfe_type); + + rtw89_h2c_pkt_set_hdr(rtwdev, skb, FWCMD_TYPE_H2C, + H2C_CAT_OUTSRC, H2C_CL_OUTSRC_RF_FW_RFK, + H2C_FUNC_RFK_PRE_NOTIFY, 0, 0, + len); + + ret = rtw89_h2c_tx(rtwdev, skb, false); + if (ret) { + rtw89_err(rtwdev, "failed to send h2c\n"); + goto fail; + } + + return 0; +fail: + dev_kfree_skb_any(skb); + + return ret; +} + int rtw89_fw_h2c_raw_with_hdr(struct rtw89_dev *rtwdev, u8 h2c_class, u8 h2c_func, u8 *buf, u16 len, bool rack, bool dack) diff --git a/drivers/net/wireless/realtek/rtw89/fw.h b/drivers/net/wireless/realtek/rtw89/fw.h index 9a2c50c35f2a..d9316b66ab76 100644 --- a/drivers/net/wireless/realtek/rtw89/fw.h +++ b/drivers/net/wireless/realtek/rtw89/fw.h @@ -3932,6 +3932,11 @@ enum rtw89_mcc_h2c_func { #define H2C_CL_OUTSRC_RF_REG_B 0x9 #define H2C_CL_OUTSRC_RF_FW_NOTIFY 0xa #define H2C_FUNC_OUTSRC_RF_GET_MCCCH 0x2 +#define H2C_CL_OUTSRC_RF_FW_RFK 0xb + +enum rtw89_rfk_offload_h2c_func { + H2C_FUNC_RFK_PRE_NOTIFY = 0x8, +}; struct rtw89_fw_h2c_rf_get_mccch { __le32 ch_0; @@ -3942,6 +3947,41 @@ struct rtw89_fw_h2c_rf_get_mccch { __le32 current_band_type; } __packed; +#define NUM_OF_RTW89_FW_RFK_PATH 2 +#define NUM_OF_RTW89_FW_RFK_TBL 3 + +struct rtw89_fw_h2c_rfk_pre_info { + struct { + __le32 ch[NUM_OF_RTW89_FW_RFK_PATH][NUM_OF_RTW89_FW_RFK_TBL]; + __le32 band[NUM_OF_RTW89_FW_RFK_PATH][NUM_OF_RTW89_FW_RFK_TBL]; + } __packed dbcc; + + __le32 mlo_mode; + struct { + __le32 cur_ch[NUM_OF_RTW89_FW_RFK_PATH]; + __le32 cur_band[NUM_OF_RTW89_FW_RFK_PATH]; + } __packed tbl; + + __le32 phy_idx; + __le32 cur_band; + __le32 cur_bw; + __le32 cur_center_ch; + + __le32 ktbl_sel0; + __le32 ktbl_sel1; + __le32 rfmod0; + __le32 rfmod1; + + __le32 mlo_1_1; + __le32 rfe_type; + __le32 drv_mode; + + struct { + __le32 ch[NUM_OF_RTW89_FW_RFK_PATH]; + __le32 band[NUM_OF_RTW89_FW_RFK_PATH]; + } __packed mlo; +} __packed; + enum rtw89_rf_log_type { RTW89_RF_RUN_LOG = 0, RTW89_RF_RPT_LOG = 1, @@ -4127,6 +4167,8 @@ int rtw89_fw_h2c_rf_reg(struct rtw89_dev *rtwdev, struct rtw89_fw_h2c_rf_reg_info *info, u16 len, u8 page); int rtw89_fw_h2c_rf_ntfy_mcc(struct rtw89_dev *rtwdev); +int rtw89_fw_h2c_rf_pre_ntfy(struct rtw89_dev *rtwdev, + enum rtw89_phy_idx phy_idx); int rtw89_fw_h2c_raw_with_hdr(struct rtw89_dev *rtwdev, u8 h2c_class, u8 h2c_func, u8 *buf, u16 len, bool rack, bool dack); diff --git a/drivers/net/wireless/realtek/rtw89/reg.h b/drivers/net/wireless/realtek/rtw89/reg.h index bd7bdd216e5f..9f209f068679 100644 --- a/drivers/net/wireless/realtek/rtw89/reg.h +++ b/drivers/net/wireless/realtek/rtw89/reg.h @@ -8730,7 +8730,9 @@ #define B_PRT_COM_RXBB_V1 GENMASK(4, 0) #define B_PRT_COM_DONE BIT(0) #define R_COEF_SEL 0x8104 +#define R_COEF_SEL_C1 0x8204 #define B_COEF_SEL_IQC BIT(0) +#define B_COEF_SEL_IQC_V1 GENMASK(1, 0) #define B_COEF_SEL_MDPD BIT(8) #define R_CFIR_SYS 0x8120 #define R_IQK_RES 0x8124 -- cgit v1.2.3 From 9c66da3b19b5526b00bdd9ca2ef20560be21291f Mon Sep 17 00:00:00 2001 From: Ping-Ke Shih Date: Fri, 2 Feb 2024 11:06:34 +0800 Subject: wifi: rtw89: rfk: add H2C command to trigger IQK IQ signal calibration is a basic and important calibration to yield good RF performance. Do this calibration on AP channel if we are going to connect. During scanning phase, it transmits with low data rate, so without IQK RF performance is still acceptable. Signed-off-by: Ping-Ke Shih Signed-off-by: Kalle Valo Link: https://msgid.link/20240202030642.108385-4-pkshih@realtek.com --- drivers/net/wireless/realtek/rtw89/fw.c | 35 +++++++++++++++++++++++++++++++++ drivers/net/wireless/realtek/rtw89/fw.h | 7 +++++++ 2 files changed, 42 insertions(+) (limited to 'drivers/net') diff --git a/drivers/net/wireless/realtek/rtw89/fw.c b/drivers/net/wireless/realtek/rtw89/fw.c index 5bd3d08a5d25..d2c166ee5c89 100644 --- a/drivers/net/wireless/realtek/rtw89/fw.c +++ b/drivers/net/wireless/realtek/rtw89/fw.c @@ -4593,6 +4593,41 @@ fail: return ret; } +int rtw89_fw_h2c_rf_iqk(struct rtw89_dev *rtwdev, enum rtw89_phy_idx phy_idx) +{ + struct rtw89_h2c_rf_iqk *h2c; + u32 len = sizeof(*h2c); + struct sk_buff *skb; + int ret; + + skb = rtw89_fw_h2c_alloc_skb_with_hdr(rtwdev, len); + if (!skb) { + rtw89_err(rtwdev, "failed to alloc skb for h2c RF IQK\n"); + return -ENOMEM; + } + skb_put(skb, len); + h2c = (struct rtw89_h2c_rf_iqk *)skb->data; + + h2c->phy_idx = cpu_to_le32(phy_idx); + h2c->dbcc = cpu_to_le32(rtwdev->dbcc_en); + + rtw89_h2c_pkt_set_hdr(rtwdev, skb, FWCMD_TYPE_H2C, + H2C_CAT_OUTSRC, H2C_CL_OUTSRC_RF_FW_RFK, + H2C_FUNC_RFK_IQK_OFFLOAD, 0, 0, len); + + ret = rtw89_h2c_tx(rtwdev, skb, false); + if (ret) { + rtw89_err(rtwdev, "failed to send h2c\n"); + goto fail; + } + + return 0; +fail: + dev_kfree_skb_any(skb); + + return ret; +} + int rtw89_fw_h2c_raw_with_hdr(struct rtw89_dev *rtwdev, u8 h2c_class, u8 h2c_func, u8 *buf, u16 len, bool rack, bool dack) diff --git a/drivers/net/wireless/realtek/rtw89/fw.h b/drivers/net/wireless/realtek/rtw89/fw.h index d9316b66ab76..e9c7f9532b0b 100644 --- a/drivers/net/wireless/realtek/rtw89/fw.h +++ b/drivers/net/wireless/realtek/rtw89/fw.h @@ -3935,6 +3935,7 @@ enum rtw89_mcc_h2c_func { #define H2C_CL_OUTSRC_RF_FW_RFK 0xb enum rtw89_rfk_offload_h2c_func { + H2C_FUNC_RFK_IQK_OFFLOAD = 0x1, H2C_FUNC_RFK_PRE_NOTIFY = 0x8, }; @@ -3982,6 +3983,11 @@ struct rtw89_fw_h2c_rfk_pre_info { } __packed mlo; } __packed; +struct rtw89_h2c_rf_iqk { + __le32 phy_idx; + __le32 dbcc; +} __packed; + enum rtw89_rf_log_type { RTW89_RF_RUN_LOG = 0, RTW89_RF_RPT_LOG = 1, @@ -4169,6 +4175,7 @@ int rtw89_fw_h2c_rf_reg(struct rtw89_dev *rtwdev, int rtw89_fw_h2c_rf_ntfy_mcc(struct rtw89_dev *rtwdev); int rtw89_fw_h2c_rf_pre_ntfy(struct rtw89_dev *rtwdev, enum rtw89_phy_idx phy_idx); +int rtw89_fw_h2c_rf_iqk(struct rtw89_dev *rtwdev, enum rtw89_phy_idx phy_idx); int rtw89_fw_h2c_raw_with_hdr(struct rtw89_dev *rtwdev, u8 h2c_class, u8 h2c_func, u8 *buf, u16 len, bool rack, bool dack); -- cgit v1.2.3 From 32919a0438946170bd944c557833186514c399f3 Mon Sep 17 00:00:00 2001 From: Ping-Ke Shih Date: Fri, 2 Feb 2024 11:06:35 +0800 Subject: wifi: rtw89: rfk: add H2C command to trigger RX DCK RX DCK is receiver DC calibration. This will calibrate DC offset to reflect correct received signal strength indicator, so mechanisms like CCA can have normalized values. Signed-off-by: Ping-Ke Shih Signed-off-by: Kalle Valo Link: https://msgid.link/20240202030642.108385-5-pkshih@realtek.com --- drivers/net/wireless/realtek/rtw89/fw.c | 43 +++++++++++++++++++++++++++++++++ drivers/net/wireless/realtek/rtw89/fw.h | 13 ++++++++++ 2 files changed, 56 insertions(+) (limited to 'drivers/net') diff --git a/drivers/net/wireless/realtek/rtw89/fw.c b/drivers/net/wireless/realtek/rtw89/fw.c index d2c166ee5c89..f1239b00479d 100644 --- a/drivers/net/wireless/realtek/rtw89/fw.c +++ b/drivers/net/wireless/realtek/rtw89/fw.c @@ -4628,6 +4628,49 @@ fail: return ret; } +int rtw89_fw_h2c_rf_rxdck(struct rtw89_dev *rtwdev, enum rtw89_phy_idx phy_idx) +{ + const struct rtw89_chan *chan = rtw89_chan_get(rtwdev, + RTW89_SUB_ENTITY_0); + struct rtw89_h2c_rf_rxdck *h2c; + u32 len = sizeof(*h2c); + struct sk_buff *skb; + int ret; + + skb = rtw89_fw_h2c_alloc_skb_with_hdr(rtwdev, len); + if (!skb) { + rtw89_err(rtwdev, "failed to alloc skb for h2c RF RXDCK\n"); + return -ENOMEM; + } + skb_put(skb, len); + h2c = (struct rtw89_h2c_rf_rxdck *)skb->data; + + h2c->len = len; + h2c->phy = phy_idx; + h2c->is_afe = false; + h2c->kpath = RF_AB; + h2c->cur_band = chan->band_type; + h2c->cur_bw = chan->band_width; + h2c->cur_ch = chan->channel; + h2c->rxdck_dbg_en = rtw89_debug_is_enabled(rtwdev, RTW89_DBG_RFK); + + rtw89_h2c_pkt_set_hdr(rtwdev, skb, FWCMD_TYPE_H2C, + H2C_CAT_OUTSRC, H2C_CL_OUTSRC_RF_FW_RFK, + H2C_FUNC_RFK_RXDCK_OFFLOAD, 0, 0, len); + + ret = rtw89_h2c_tx(rtwdev, skb, false); + if (ret) { + rtw89_err(rtwdev, "failed to send h2c\n"); + goto fail; + } + + return 0; +fail: + dev_kfree_skb_any(skb); + + return ret; +} + int rtw89_fw_h2c_raw_with_hdr(struct rtw89_dev *rtwdev, u8 h2c_class, u8 h2c_func, u8 *buf, u16 len, bool rack, bool dack) diff --git a/drivers/net/wireless/realtek/rtw89/fw.h b/drivers/net/wireless/realtek/rtw89/fw.h index e9c7f9532b0b..7e803abe47c6 100644 --- a/drivers/net/wireless/realtek/rtw89/fw.h +++ b/drivers/net/wireless/realtek/rtw89/fw.h @@ -3936,6 +3936,7 @@ enum rtw89_mcc_h2c_func { enum rtw89_rfk_offload_h2c_func { H2C_FUNC_RFK_IQK_OFFLOAD = 0x1, + H2C_FUNC_RFK_RXDCK_OFFLOAD = 0x6, H2C_FUNC_RFK_PRE_NOTIFY = 0x8, }; @@ -3988,6 +3989,17 @@ struct rtw89_h2c_rf_iqk { __le32 dbcc; } __packed; +struct rtw89_h2c_rf_rxdck { + u8 len; + u8 phy; + u8 is_afe; + u8 kpath; + u8 cur_band; + u8 cur_bw; + u8 cur_ch; + u8 rxdck_dbg_en; +} __packed; + enum rtw89_rf_log_type { RTW89_RF_RUN_LOG = 0, RTW89_RF_RPT_LOG = 1, @@ -4176,6 +4188,7 @@ int rtw89_fw_h2c_rf_ntfy_mcc(struct rtw89_dev *rtwdev); int rtw89_fw_h2c_rf_pre_ntfy(struct rtw89_dev *rtwdev, enum rtw89_phy_idx phy_idx); int rtw89_fw_h2c_rf_iqk(struct rtw89_dev *rtwdev, enum rtw89_phy_idx phy_idx); +int rtw89_fw_h2c_rf_rxdck(struct rtw89_dev *rtwdev, enum rtw89_phy_idx phy_idx); int rtw89_fw_h2c_raw_with_hdr(struct rtw89_dev *rtwdev, u8 h2c_class, u8 h2c_func, u8 *buf, u16 len, bool rack, bool dack); -- cgit v1.2.3 From b835141be5a94c3f170107c1f5446a4a7b204ac6 Mon Sep 17 00:00:00 2001 From: Ping-Ke Shih Date: Fri, 2 Feb 2024 11:06:36 +0800 Subject: wifi: rtw89: rfk: add H2C command to trigger DPK DPK is short for digital pre-distortion calibration. It can adjusts digital waveform according to PA linear characteristics dynamically to enhance TX EVM. Signed-off-by: Ping-Ke Shih Signed-off-by: Kalle Valo Link: https://msgid.link/20240202030642.108385-6-pkshih@realtek.com --- drivers/net/wireless/realtek/rtw89/fw.c | 43 +++++++++++++++++++++++++++++++++ drivers/net/wireless/realtek/rtw89/fw.h | 13 ++++++++++ 2 files changed, 56 insertions(+) (limited to 'drivers/net') diff --git a/drivers/net/wireless/realtek/rtw89/fw.c b/drivers/net/wireless/realtek/rtw89/fw.c index f1239b00479d..1218bab049c3 100644 --- a/drivers/net/wireless/realtek/rtw89/fw.c +++ b/drivers/net/wireless/realtek/rtw89/fw.c @@ -4628,6 +4628,49 @@ fail: return ret; } +int rtw89_fw_h2c_rf_dpk(struct rtw89_dev *rtwdev, enum rtw89_phy_idx phy_idx) +{ + const struct rtw89_chan *chan = rtw89_chan_get(rtwdev, + RTW89_SUB_ENTITY_0); + struct rtw89_h2c_rf_dpk *h2c; + u32 len = sizeof(*h2c); + struct sk_buff *skb; + int ret; + + skb = rtw89_fw_h2c_alloc_skb_with_hdr(rtwdev, len); + if (!skb) { + rtw89_err(rtwdev, "failed to alloc skb for h2c RF DPK\n"); + return -ENOMEM; + } + skb_put(skb, len); + h2c = (struct rtw89_h2c_rf_dpk *)skb->data; + + h2c->len = len; + h2c->phy = phy_idx; + h2c->dpk_enable = true; + h2c->kpath = RF_AB; + h2c->cur_band = chan->band_type; + h2c->cur_bw = chan->band_width; + h2c->cur_ch = chan->channel; + h2c->dpk_dbg_en = rtw89_debug_is_enabled(rtwdev, RTW89_DBG_RFK); + + rtw89_h2c_pkt_set_hdr(rtwdev, skb, FWCMD_TYPE_H2C, + H2C_CAT_OUTSRC, H2C_CL_OUTSRC_RF_FW_RFK, + H2C_FUNC_RFK_DPK_OFFLOAD, 0, 0, len); + + ret = rtw89_h2c_tx(rtwdev, skb, false); + if (ret) { + rtw89_err(rtwdev, "failed to send h2c\n"); + goto fail; + } + + return 0; +fail: + dev_kfree_skb_any(skb); + + return ret; +} + int rtw89_fw_h2c_rf_rxdck(struct rtw89_dev *rtwdev, enum rtw89_phy_idx phy_idx) { const struct rtw89_chan *chan = rtw89_chan_get(rtwdev, diff --git a/drivers/net/wireless/realtek/rtw89/fw.h b/drivers/net/wireless/realtek/rtw89/fw.h index 7e803abe47c6..f48d21a772aa 100644 --- a/drivers/net/wireless/realtek/rtw89/fw.h +++ b/drivers/net/wireless/realtek/rtw89/fw.h @@ -3936,6 +3936,7 @@ enum rtw89_mcc_h2c_func { enum rtw89_rfk_offload_h2c_func { H2C_FUNC_RFK_IQK_OFFLOAD = 0x1, + H2C_FUNC_RFK_DPK_OFFLOAD = 0x3, H2C_FUNC_RFK_RXDCK_OFFLOAD = 0x6, H2C_FUNC_RFK_PRE_NOTIFY = 0x8, }; @@ -3989,6 +3990,17 @@ struct rtw89_h2c_rf_iqk { __le32 dbcc; } __packed; +struct rtw89_h2c_rf_dpk { + u8 len; + u8 phy; + u8 dpk_enable; + u8 kpath; + u8 cur_band; + u8 cur_bw; + u8 cur_ch; + u8 dpk_dbg_en; +} __packed; + struct rtw89_h2c_rf_rxdck { u8 len; u8 phy; @@ -4188,6 +4200,7 @@ int rtw89_fw_h2c_rf_ntfy_mcc(struct rtw89_dev *rtwdev); int rtw89_fw_h2c_rf_pre_ntfy(struct rtw89_dev *rtwdev, enum rtw89_phy_idx phy_idx); int rtw89_fw_h2c_rf_iqk(struct rtw89_dev *rtwdev, enum rtw89_phy_idx phy_idx); +int rtw89_fw_h2c_rf_dpk(struct rtw89_dev *rtwdev, enum rtw89_phy_idx phy_idx); int rtw89_fw_h2c_rf_rxdck(struct rtw89_dev *rtwdev, enum rtw89_phy_idx phy_idx); int rtw89_fw_h2c_raw_with_hdr(struct rtw89_dev *rtwdev, u8 h2c_class, u8 h2c_func, u8 *buf, u16 len, -- cgit v1.2.3 From 1a0cba5dc983048ec0e13615b97c87a8882dff36 Mon Sep 17 00:00:00 2001 From: Ping-Ke Shih Date: Fri, 2 Feb 2024 11:06:37 +0800 Subject: wifi: rtw89: rfk: add H2C command to trigger DACK DACK (digital-to-analog converters calibration) is used to calibrate DAC to output signals with expected quality. Signed-off-by: Ping-Ke Shih Signed-off-by: Kalle Valo Link: https://msgid.link/20240202030642.108385-7-pkshih@realtek.com --- drivers/net/wireless/realtek/rtw89/fw.c | 36 +++++++++++++++++++++++++++++++++ drivers/net/wireless/realtek/rtw89/fw.h | 8 ++++++++ 2 files changed, 44 insertions(+) (limited to 'drivers/net') diff --git a/drivers/net/wireless/realtek/rtw89/fw.c b/drivers/net/wireless/realtek/rtw89/fw.c index 1218bab049c3..5b6693ffa290 100644 --- a/drivers/net/wireless/realtek/rtw89/fw.c +++ b/drivers/net/wireless/realtek/rtw89/fw.c @@ -4671,6 +4671,42 @@ fail: return ret; } +int rtw89_fw_h2c_rf_dack(struct rtw89_dev *rtwdev, enum rtw89_phy_idx phy_idx) +{ + struct rtw89_h2c_rf_dack *h2c; + u32 len = sizeof(*h2c); + struct sk_buff *skb; + int ret; + + skb = rtw89_fw_h2c_alloc_skb_with_hdr(rtwdev, len); + if (!skb) { + rtw89_err(rtwdev, "failed to alloc skb for h2c RF DACK\n"); + return -ENOMEM; + } + skb_put(skb, len); + h2c = (struct rtw89_h2c_rf_dack *)skb->data; + + h2c->len = cpu_to_le32(len); + h2c->phy = cpu_to_le32(phy_idx); + h2c->type = cpu_to_le32(0); + + rtw89_h2c_pkt_set_hdr(rtwdev, skb, FWCMD_TYPE_H2C, + H2C_CAT_OUTSRC, H2C_CL_OUTSRC_RF_FW_RFK, + H2C_FUNC_RFK_DACK_OFFLOAD, 0, 0, len); + + ret = rtw89_h2c_tx(rtwdev, skb, false); + if (ret) { + rtw89_err(rtwdev, "failed to send h2c\n"); + goto fail; + } + + return 0; +fail: + dev_kfree_skb_any(skb); + + return ret; +} + int rtw89_fw_h2c_rf_rxdck(struct rtw89_dev *rtwdev, enum rtw89_phy_idx phy_idx) { const struct rtw89_chan *chan = rtw89_chan_get(rtwdev, diff --git a/drivers/net/wireless/realtek/rtw89/fw.h b/drivers/net/wireless/realtek/rtw89/fw.h index f48d21a772aa..0fdc62fdd25a 100644 --- a/drivers/net/wireless/realtek/rtw89/fw.h +++ b/drivers/net/wireless/realtek/rtw89/fw.h @@ -3937,6 +3937,7 @@ enum rtw89_mcc_h2c_func { enum rtw89_rfk_offload_h2c_func { H2C_FUNC_RFK_IQK_OFFLOAD = 0x1, H2C_FUNC_RFK_DPK_OFFLOAD = 0x3, + H2C_FUNC_RFK_DACK_OFFLOAD = 0x5, H2C_FUNC_RFK_RXDCK_OFFLOAD = 0x6, H2C_FUNC_RFK_PRE_NOTIFY = 0x8, }; @@ -4001,6 +4002,12 @@ struct rtw89_h2c_rf_dpk { u8 dpk_dbg_en; } __packed; +struct rtw89_h2c_rf_dack { + __le32 len; + __le32 phy; + __le32 type; +} __packed; + struct rtw89_h2c_rf_rxdck { u8 len; u8 phy; @@ -4201,6 +4208,7 @@ int rtw89_fw_h2c_rf_pre_ntfy(struct rtw89_dev *rtwdev, enum rtw89_phy_idx phy_idx); int rtw89_fw_h2c_rf_iqk(struct rtw89_dev *rtwdev, enum rtw89_phy_idx phy_idx); int rtw89_fw_h2c_rf_dpk(struct rtw89_dev *rtwdev, enum rtw89_phy_idx phy_idx); +int rtw89_fw_h2c_rf_dack(struct rtw89_dev *rtwdev, enum rtw89_phy_idx phy_idx); int rtw89_fw_h2c_rf_rxdck(struct rtw89_dev *rtwdev, enum rtw89_phy_idx phy_idx); int rtw89_fw_h2c_raw_with_hdr(struct rtw89_dev *rtwdev, u8 h2c_class, u8 h2c_func, u8 *buf, u16 len, -- cgit v1.2.3 From af41e89ea323ca48d3ddf1a55b0f632d19ae0ae6 Mon Sep 17 00:00:00 2001 From: Ping-Ke Shih Date: Fri, 2 Feb 2024 11:06:38 +0800 Subject: wifi: rtw89: rfk: add H2C command to trigger TXGAPK TXGAPK stands for TX power gap calibration. Use this calibration to compensate TX power gap to output expected power. Signed-off-by: Ping-Ke Shih Signed-off-by: Kalle Valo Link: https://msgid.link/20240202030642.108385-8-pkshih@realtek.com --- drivers/net/wireless/realtek/rtw89/fw.c | 44 +++++++++++++++++++++++++++++++++ drivers/net/wireless/realtek/rtw89/fw.h | 13 ++++++++++ 2 files changed, 57 insertions(+) (limited to 'drivers/net') diff --git a/drivers/net/wireless/realtek/rtw89/fw.c b/drivers/net/wireless/realtek/rtw89/fw.c index 5b6693ffa290..3f5e72209001 100644 --- a/drivers/net/wireless/realtek/rtw89/fw.c +++ b/drivers/net/wireless/realtek/rtw89/fw.c @@ -4671,6 +4671,50 @@ fail: return ret; } +int rtw89_fw_h2c_rf_txgapk(struct rtw89_dev *rtwdev, enum rtw89_phy_idx phy_idx) +{ + const struct rtw89_chan *chan = rtw89_chan_get(rtwdev, + RTW89_SUB_ENTITY_0); + struct rtw89_hal *hal = &rtwdev->hal; + struct rtw89_h2c_rf_txgapk *h2c; + u32 len = sizeof(*h2c); + struct sk_buff *skb; + int ret; + + skb = rtw89_fw_h2c_alloc_skb_with_hdr(rtwdev, len); + if (!skb) { + rtw89_err(rtwdev, "failed to alloc skb for h2c RF TXGAPK\n"); + return -ENOMEM; + } + skb_put(skb, len); + h2c = (struct rtw89_h2c_rf_txgapk *)skb->data; + + h2c->len = len; + h2c->ktype = 2; + h2c->phy = phy_idx; + h2c->kpath = RF_AB; + h2c->band = chan->band_type; + h2c->bw = chan->band_width; + h2c->ch = chan->channel; + h2c->cv = hal->cv; + + rtw89_h2c_pkt_set_hdr(rtwdev, skb, FWCMD_TYPE_H2C, + H2C_CAT_OUTSRC, H2C_CL_OUTSRC_RF_FW_RFK, + H2C_FUNC_RFK_TXGAPK_OFFLOAD, 0, 0, len); + + ret = rtw89_h2c_tx(rtwdev, skb, false); + if (ret) { + rtw89_err(rtwdev, "failed to send h2c\n"); + goto fail; + } + + return 0; +fail: + dev_kfree_skb_any(skb); + + return ret; +} + int rtw89_fw_h2c_rf_dack(struct rtw89_dev *rtwdev, enum rtw89_phy_idx phy_idx) { struct rtw89_h2c_rf_dack *h2c; diff --git a/drivers/net/wireless/realtek/rtw89/fw.h b/drivers/net/wireless/realtek/rtw89/fw.h index 0fdc62fdd25a..666c3e7ec0d0 100644 --- a/drivers/net/wireless/realtek/rtw89/fw.h +++ b/drivers/net/wireless/realtek/rtw89/fw.h @@ -3937,6 +3937,7 @@ enum rtw89_mcc_h2c_func { enum rtw89_rfk_offload_h2c_func { H2C_FUNC_RFK_IQK_OFFLOAD = 0x1, H2C_FUNC_RFK_DPK_OFFLOAD = 0x3, + H2C_FUNC_RFK_TXGAPK_OFFLOAD = 0x4, H2C_FUNC_RFK_DACK_OFFLOAD = 0x5, H2C_FUNC_RFK_RXDCK_OFFLOAD = 0x6, H2C_FUNC_RFK_PRE_NOTIFY = 0x8, @@ -4002,6 +4003,17 @@ struct rtw89_h2c_rf_dpk { u8 dpk_dbg_en; } __packed; +struct rtw89_h2c_rf_txgapk { + u8 len; + u8 ktype; + u8 phy; + u8 kpath; + u8 band; + u8 bw; + u8 ch; + u8 cv; +} __packed; + struct rtw89_h2c_rf_dack { __le32 len; __le32 phy; @@ -4208,6 +4220,7 @@ int rtw89_fw_h2c_rf_pre_ntfy(struct rtw89_dev *rtwdev, enum rtw89_phy_idx phy_idx); int rtw89_fw_h2c_rf_iqk(struct rtw89_dev *rtwdev, enum rtw89_phy_idx phy_idx); int rtw89_fw_h2c_rf_dpk(struct rtw89_dev *rtwdev, enum rtw89_phy_idx phy_idx); +int rtw89_fw_h2c_rf_txgapk(struct rtw89_dev *rtwdev, enum rtw89_phy_idx phy_idx); int rtw89_fw_h2c_rf_dack(struct rtw89_dev *rtwdev, enum rtw89_phy_idx phy_idx); int rtw89_fw_h2c_rf_rxdck(struct rtw89_dev *rtwdev, enum rtw89_phy_idx phy_idx); int rtw89_fw_h2c_raw_with_hdr(struct rtw89_dev *rtwdev, -- cgit v1.2.3 From bd6f5f27cb2c2b0635cc9212fb82e6f112e7e681 Mon Sep 17 00:00:00 2001 From: Ping-Ke Shih Date: Fri, 2 Feb 2024 11:06:39 +0800 Subject: wifi: rtw89: rfk: add H2C command to trigger TSSI TSSI is short for transmitter signal strength indication, which is a close-loop hardware circuit to feedback actual transmitting power as a reference to adjust power for next transmission. When connecting and switching bands or channels, do TSSI calibration and reset hardware status to output expected power. Signed-off-by: Ping-Ke Shih Signed-off-by: Kalle Valo Link: https://msgid.link/20240202030642.108385-9-pkshih@realtek.com --- drivers/net/wireless/realtek/rtw89/core.h | 6 + drivers/net/wireless/realtek/rtw89/fw.c | 48 +++ drivers/net/wireless/realtek/rtw89/fw.h | 32 ++ drivers/net/wireless/realtek/rtw89/phy.c | 607 ++++++++++++++++++++++++++++++ drivers/net/wireless/realtek/rtw89/phy.h | 8 + 5 files changed, 701 insertions(+) (limited to 'drivers/net') diff --git a/drivers/net/wireless/realtek/rtw89/core.h b/drivers/net/wireless/realtek/rtw89/core.h index e049f7b5168b..ccc9f96fc18b 100644 --- a/drivers/net/wireless/realtek/rtw89/core.h +++ b/drivers/net/wireless/realtek/rtw89/core.h @@ -17,6 +17,7 @@ struct rtw89_pci_info; struct rtw89_mac_gen_def; struct rtw89_phy_gen_def; struct rtw89_efuse_block_cfg; +struct rtw89_h2c_rf_tssi; struct rtw89_fw_txpwr_track_cfg; struct rtw89_phy_rfk_log_fmt; @@ -4471,6 +4472,11 @@ struct rtw89_cfo_tracking_info { u8 lock_cnt; }; +enum rtw89_tssi_mode { + RTW89_TSSI_NORMAL = 0, + RTW89_TSSI_SCAN = 1, +}; + enum rtw89_tssi_alimk_band { TSSI_ALIMK_2G = 0, TSSI_ALIMK_5GL, diff --git a/drivers/net/wireless/realtek/rtw89/fw.c b/drivers/net/wireless/realtek/rtw89/fw.c index 3f5e72209001..c3f0a79f3de4 100644 --- a/drivers/net/wireless/realtek/rtw89/fw.c +++ b/drivers/net/wireless/realtek/rtw89/fw.c @@ -4593,6 +4593,54 @@ fail: return ret; } +int rtw89_fw_h2c_rf_tssi(struct rtw89_dev *rtwdev, enum rtw89_phy_idx phy_idx, + enum rtw89_tssi_mode tssi_mode) +{ + const struct rtw89_chan *chan = rtw89_chan_get(rtwdev, + RTW89_SUB_ENTITY_0); + struct rtw89_hal *hal = &rtwdev->hal; + struct rtw89_h2c_rf_tssi *h2c; + u32 len = sizeof(*h2c); + struct sk_buff *skb; + int ret; + + skb = rtw89_fw_h2c_alloc_skb_with_hdr(rtwdev, len); + if (!skb) { + rtw89_err(rtwdev, "failed to alloc skb for h2c RF TSSI\n"); + return -ENOMEM; + } + skb_put(skb, len); + h2c = (struct rtw89_h2c_rf_tssi *)skb->data; + + h2c->len = cpu_to_le16(len); + h2c->phy = phy_idx; + h2c->ch = chan->channel; + h2c->bw = chan->band_width; + h2c->band = chan->band_type; + h2c->hwtx_en = true; + h2c->cv = hal->cv; + h2c->tssi_mode = tssi_mode; + + rtw89_phy_rfk_tssi_fill_fwcmd_efuse_to_de(rtwdev, phy_idx, chan, h2c); + rtw89_phy_rfk_tssi_fill_fwcmd_tmeter_tbl(rtwdev, phy_idx, chan, h2c); + + rtw89_h2c_pkt_set_hdr(rtwdev, skb, FWCMD_TYPE_H2C, + H2C_CAT_OUTSRC, H2C_CL_OUTSRC_RF_FW_RFK, + H2C_FUNC_RFK_TSSI_OFFLOAD, 0, 0, len); + + ret = rtw89_h2c_tx(rtwdev, skb, false); + if (ret) { + rtw89_err(rtwdev, "failed to send h2c\n"); + goto fail; + } + + return 0; +fail: + dev_kfree_skb_any(skb); + + return ret; +} + int rtw89_fw_h2c_rf_iqk(struct rtw89_dev *rtwdev, enum rtw89_phy_idx phy_idx) { struct rtw89_h2c_rf_iqk *h2c; diff --git a/drivers/net/wireless/realtek/rtw89/fw.h b/drivers/net/wireless/realtek/rtw89/fw.h index 666c3e7ec0d0..02a7c7b2c8be 100644 --- a/drivers/net/wireless/realtek/rtw89/fw.h +++ b/drivers/net/wireless/realtek/rtw89/fw.h @@ -3935,6 +3935,7 @@ enum rtw89_mcc_h2c_func { #define H2C_CL_OUTSRC_RF_FW_RFK 0xb enum rtw89_rfk_offload_h2c_func { + H2C_FUNC_RFK_TSSI_OFFLOAD = 0x0, H2C_FUNC_RFK_IQK_OFFLOAD = 0x1, H2C_FUNC_RFK_DPK_OFFLOAD = 0x3, H2C_FUNC_RFK_TXGAPK_OFFLOAD = 0x4, @@ -3987,6 +3988,35 @@ struct rtw89_fw_h2c_rfk_pre_info { } __packed mlo; } __packed; +struct rtw89_h2c_rf_tssi { + __le16 len; + u8 phy; + u8 ch; + u8 bw; + u8 band; + u8 hwtx_en; + u8 cv; + s8 curr_tssi_cck_de[2]; + s8 curr_tssi_cck_de_20m[2]; + s8 curr_tssi_cck_de_40m[2]; + s8 curr_tssi_efuse_cck_de[2]; + s8 curr_tssi_ofdm_de[2]; + s8 curr_tssi_ofdm_de_20m[2]; + s8 curr_tssi_ofdm_de_40m[2]; + s8 curr_tssi_ofdm_de_80m[2]; + s8 curr_tssi_ofdm_de_160m[2]; + s8 curr_tssi_ofdm_de_320m[2]; + s8 curr_tssi_efuse_ofdm_de[2]; + s8 curr_tssi_ofdm_de_diff_20m[2]; + s8 curr_tssi_ofdm_de_diff_80m[2]; + s8 curr_tssi_ofdm_de_diff_160m[2]; + s8 curr_tssi_ofdm_de_diff_320m[2]; + s8 curr_tssi_trim_de[2]; + u8 pg_thermal[2]; + u8 ftable[2][128]; + u8 tssi_mode; +} __packed; + struct rtw89_h2c_rf_iqk { __le32 phy_idx; __le32 dbcc; @@ -4218,6 +4248,8 @@ int rtw89_fw_h2c_rf_reg(struct rtw89_dev *rtwdev, int rtw89_fw_h2c_rf_ntfy_mcc(struct rtw89_dev *rtwdev); int rtw89_fw_h2c_rf_pre_ntfy(struct rtw89_dev *rtwdev, enum rtw89_phy_idx phy_idx); +int rtw89_fw_h2c_rf_tssi(struct rtw89_dev *rtwdev, enum rtw89_phy_idx phy_idx, + enum rtw89_tssi_mode tssi_mode); int rtw89_fw_h2c_rf_iqk(struct rtw89_dev *rtwdev, enum rtw89_phy_idx phy_idx); int rtw89_fw_h2c_rf_dpk(struct rtw89_dev *rtwdev, enum rtw89_phy_idx phy_idx); int rtw89_fw_h2c_rf_txgapk(struct rtw89_dev *rtwdev, enum rtw89_phy_idx phy_idx); diff --git a/drivers/net/wireless/realtek/rtw89/phy.c b/drivers/net/wireless/realtek/rtw89/phy.c index 3de61c0d7b03..77b3b233697b 100644 --- a/drivers/net/wireless/realtek/rtw89/phy.c +++ b/drivers/net/wireless/realtek/rtw89/phy.c @@ -2959,6 +2959,613 @@ void rtw89_phy_c2h_handle(struct rtw89_dev *rtwdev, struct sk_buff *skb, handler(rtwdev, skb, len); } +static u32 phy_tssi_get_cck_group(u8 ch) +{ + switch (ch) { + case 1 ... 2: + return 0; + case 3 ... 5: + return 1; + case 6 ... 8: + return 2; + case 9 ... 11: + return 3; + case 12 ... 13: + return 4; + case 14: + return 5; + } + + return 0; +} + +#define PHY_TSSI_EXTRA_GROUP_BIT BIT(31) +#define PHY_TSSI_EXTRA_GROUP(idx) (PHY_TSSI_EXTRA_GROUP_BIT | (idx)) +#define PHY_IS_TSSI_EXTRA_GROUP(group) ((group) & PHY_TSSI_EXTRA_GROUP_BIT) +#define PHY_TSSI_EXTRA_GET_GROUP_IDX1(group) \ + ((group) & ~PHY_TSSI_EXTRA_GROUP_BIT) +#define PHY_TSSI_EXTRA_GET_GROUP_IDX2(group) \ + (PHY_TSSI_EXTRA_GET_GROUP_IDX1(group) + 1) + +static u32 phy_tssi_get_ofdm_group(u8 ch) +{ + switch (ch) { + case 1 ... 2: + return 0; + case 3 ... 5: + return 1; + case 6 ... 8: + return 2; + case 9 ... 11: + return 3; + case 12 ... 14: + return 4; + case 36 ... 40: + return 5; + case 41 ... 43: + return PHY_TSSI_EXTRA_GROUP(5); + case 44 ... 48: + return 6; + case 49 ... 51: + return PHY_TSSI_EXTRA_GROUP(6); + case 52 ... 56: + return 7; + case 57 ... 59: + return PHY_TSSI_EXTRA_GROUP(7); + case 60 ... 64: + return 8; + case 100 ... 104: + return 9; + case 105 ... 107: + return PHY_TSSI_EXTRA_GROUP(9); + case 108 ... 112: + return 10; + case 113 ... 115: + return PHY_TSSI_EXTRA_GROUP(10); + case 116 ... 120: + return 11; + case 121 ... 123: + return PHY_TSSI_EXTRA_GROUP(11); + case 124 ... 128: + return 12; + case 129 ... 131: + return PHY_TSSI_EXTRA_GROUP(12); + case 132 ... 136: + return 13; + case 137 ... 139: + return PHY_TSSI_EXTRA_GROUP(13); + case 140 ... 144: + return 14; + case 149 ... 153: + return 15; + case 154 ... 156: + return PHY_TSSI_EXTRA_GROUP(15); + case 157 ... 161: + return 16; + case 162 ... 164: + return PHY_TSSI_EXTRA_GROUP(16); + case 165 ... 169: + return 17; + case 170 ... 172: + return PHY_TSSI_EXTRA_GROUP(17); + case 173 ... 177: + return 18; + } + + return 0; +} + +static u32 phy_tssi_get_6g_ofdm_group(u8 ch) +{ + switch (ch) { + case 1 ... 5: + return 0; + case 6 ... 8: + return PHY_TSSI_EXTRA_GROUP(0); + case 9 ... 13: + return 1; + case 14 ... 16: + return PHY_TSSI_EXTRA_GROUP(1); + case 17 ... 21: + return 2; + case 22 ... 24: + return PHY_TSSI_EXTRA_GROUP(2); + case 25 ... 29: + return 3; + case 33 ... 37: + return 4; + case 38 ... 40: + return PHY_TSSI_EXTRA_GROUP(4); + case 41 ... 45: + return 5; + case 46 ... 48: + return PHY_TSSI_EXTRA_GROUP(5); + case 49 ... 53: + return 6; + case 54 ... 56: + return PHY_TSSI_EXTRA_GROUP(6); + case 57 ... 61: + return 7; + case 65 ... 69: + return 8; + case 70 ... 72: + return PHY_TSSI_EXTRA_GROUP(8); + case 73 ... 77: + return 9; + case 78 ... 80: + return PHY_TSSI_EXTRA_GROUP(9); + case 81 ... 85: + return 10; + case 86 ... 88: + return PHY_TSSI_EXTRA_GROUP(10); + case 89 ... 93: + return 11; + case 97 ... 101: + return 12; + case 102 ... 104: + return PHY_TSSI_EXTRA_GROUP(12); + case 105 ... 109: + return 13; + case 110 ... 112: + return PHY_TSSI_EXTRA_GROUP(13); + case 113 ... 117: + return 14; + case 118 ... 120: + return PHY_TSSI_EXTRA_GROUP(14); + case 121 ... 125: + return 15; + case 129 ... 133: + return 16; + case 134 ... 136: + return PHY_TSSI_EXTRA_GROUP(16); + case 137 ... 141: + return 17; + case 142 ... 144: + return PHY_TSSI_EXTRA_GROUP(17); + case 145 ... 149: + return 18; + case 150 ... 152: + return PHY_TSSI_EXTRA_GROUP(18); + case 153 ... 157: + return 19; + case 161 ... 165: + return 20; + case 166 ... 168: + return PHY_TSSI_EXTRA_GROUP(20); + case 169 ... 173: + return 21; + case 174 ... 176: + return PHY_TSSI_EXTRA_GROUP(21); + case 177 ... 181: + return 22; + case 182 ... 184: + return PHY_TSSI_EXTRA_GROUP(22); + case 185 ... 189: + return 23; + case 193 ... 197: + return 24; + case 198 ... 200: + return PHY_TSSI_EXTRA_GROUP(24); + case 201 ... 205: + return 25; + case 206 ... 208: + return PHY_TSSI_EXTRA_GROUP(25); + case 209 ... 213: + return 26; + case 214 ... 216: + return PHY_TSSI_EXTRA_GROUP(26); + case 217 ... 221: + return 27; + case 225 ... 229: + return 28; + case 230 ... 232: + return PHY_TSSI_EXTRA_GROUP(28); + case 233 ... 237: + return 29; + case 238 ... 240: + return PHY_TSSI_EXTRA_GROUP(29); + case 241 ... 245: + return 30; + case 246 ... 248: + return PHY_TSSI_EXTRA_GROUP(30); + case 249 ... 253: + return 31; + } + + return 0; +} + +static u32 phy_tssi_get_trim_group(u8 ch) +{ + switch (ch) { + case 1 ... 8: + return 0; + case 9 ... 14: + return 1; + case 36 ... 48: + return 2; + case 49 ... 51: + return PHY_TSSI_EXTRA_GROUP(2); + case 52 ... 64: + return 3; + case 100 ... 112: + return 4; + case 113 ... 115: + return PHY_TSSI_EXTRA_GROUP(4); + case 116 ... 128: + return 5; + case 132 ... 144: + return 6; + case 149 ... 177: + return 7; + } + + return 0; +} + +static u32 phy_tssi_get_6g_trim_group(u8 ch) +{ + switch (ch) { + case 1 ... 13: + return 0; + case 14 ... 16: + return PHY_TSSI_EXTRA_GROUP(0); + case 17 ... 29: + return 1; + case 33 ... 45: + return 2; + case 46 ... 48: + return PHY_TSSI_EXTRA_GROUP(2); + case 49 ... 61: + return 3; + case 65 ... 77: + return 4; + case 78 ... 80: + return PHY_TSSI_EXTRA_GROUP(4); + case 81 ... 93: + return 5; + case 97 ... 109: + return 6; + case 110 ... 112: + return PHY_TSSI_EXTRA_GROUP(6); + case 113 ... 125: + return 7; + case 129 ... 141: + return 8; + case 142 ... 144: + return PHY_TSSI_EXTRA_GROUP(8); + case 145 ... 157: + return 9; + case 161 ... 173: + return 10; + case 174 ... 176: + return PHY_TSSI_EXTRA_GROUP(10); + case 177 ... 189: + return 11; + case 193 ... 205: + return 12; + case 206 ... 208: + return PHY_TSSI_EXTRA_GROUP(12); + case 209 ... 221: + return 13; + case 225 ... 237: + return 14; + case 238 ... 240: + return PHY_TSSI_EXTRA_GROUP(14); + case 241 ... 253: + return 15; + } + + return 0; +} + +static s8 phy_tssi_get_ofdm_de(struct rtw89_dev *rtwdev, + enum rtw89_phy_idx phy, + const struct rtw89_chan *chan, + enum rtw89_rf_path path) +{ + struct rtw89_tssi_info *tssi_info = &rtwdev->tssi; + enum rtw89_band band = chan->band_type; + u8 ch = chan->channel; + u32 gidx_1st; + u32 gidx_2nd; + s8 de_1st; + s8 de_2nd; + u32 gidx; + s8 val; + + if (band == RTW89_BAND_6G) + goto calc_6g; + + gidx = phy_tssi_get_ofdm_group(ch); + + rtw89_debug(rtwdev, RTW89_DBG_TSSI, + "[TSSI][TRIM]: path=%d mcs group_idx=0x%x\n", + path, gidx); + + if (PHY_IS_TSSI_EXTRA_GROUP(gidx)) { + gidx_1st = PHY_TSSI_EXTRA_GET_GROUP_IDX1(gidx); + gidx_2nd = PHY_TSSI_EXTRA_GET_GROUP_IDX2(gidx); + de_1st = tssi_info->tssi_mcs[path][gidx_1st]; + de_2nd = tssi_info->tssi_mcs[path][gidx_2nd]; + val = (de_1st + de_2nd) / 2; + + rtw89_debug(rtwdev, RTW89_DBG_TSSI, + "[TSSI][TRIM]: path=%d mcs de=%d 1st=%d 2nd=%d\n", + path, val, de_1st, de_2nd); + } else { + val = tssi_info->tssi_mcs[path][gidx]; + + rtw89_debug(rtwdev, RTW89_DBG_TSSI, + "[TSSI][TRIM]: path=%d mcs de=%d\n", path, val); + } + + return val; + +calc_6g: + gidx = phy_tssi_get_6g_ofdm_group(ch); + + rtw89_debug(rtwdev, RTW89_DBG_TSSI, + "[TSSI][TRIM]: path=%d mcs group_idx=0x%x\n", + path, gidx); + + if (PHY_IS_TSSI_EXTRA_GROUP(gidx)) { + gidx_1st = PHY_TSSI_EXTRA_GET_GROUP_IDX1(gidx); + gidx_2nd = PHY_TSSI_EXTRA_GET_GROUP_IDX2(gidx); + de_1st = tssi_info->tssi_6g_mcs[path][gidx_1st]; + de_2nd = tssi_info->tssi_6g_mcs[path][gidx_2nd]; + val = (de_1st + de_2nd) / 2; + + rtw89_debug(rtwdev, RTW89_DBG_TSSI, + "[TSSI][TRIM]: path=%d mcs de=%d 1st=%d 2nd=%d\n", + path, val, de_1st, de_2nd); + } else { + val = tssi_info->tssi_6g_mcs[path][gidx]; + + rtw89_debug(rtwdev, RTW89_DBG_TSSI, + "[TSSI][TRIM]: path=%d mcs de=%d\n", path, val); + } + + return val; +} + +static s8 phy_tssi_get_ofdm_trim_de(struct rtw89_dev *rtwdev, + enum rtw89_phy_idx phy, + const struct rtw89_chan *chan, + enum rtw89_rf_path path) +{ + struct rtw89_tssi_info *tssi_info = &rtwdev->tssi; + enum rtw89_band band = chan->band_type; + u8 ch = chan->channel; + u32 tgidx_1st; + u32 tgidx_2nd; + s8 tde_1st; + s8 tde_2nd; + u32 tgidx; + s8 val; + + if (band == RTW89_BAND_6G) + goto calc_6g; + + tgidx = phy_tssi_get_trim_group(ch); + + rtw89_debug(rtwdev, RTW89_DBG_TSSI, + "[TSSI][TRIM]: path=%d mcs trim_group_idx=0x%x\n", + path, tgidx); + + if (PHY_IS_TSSI_EXTRA_GROUP(tgidx)) { + tgidx_1st = PHY_TSSI_EXTRA_GET_GROUP_IDX1(tgidx); + tgidx_2nd = PHY_TSSI_EXTRA_GET_GROUP_IDX2(tgidx); + tde_1st = tssi_info->tssi_trim[path][tgidx_1st]; + tde_2nd = tssi_info->tssi_trim[path][tgidx_2nd]; + val = (tde_1st + tde_2nd) / 2; + + rtw89_debug(rtwdev, RTW89_DBG_TSSI, + "[TSSI][TRIM]: path=%d mcs trim_de=%d 1st=%d 2nd=%d\n", + path, val, tde_1st, tde_2nd); + } else { + val = tssi_info->tssi_trim[path][tgidx]; + + rtw89_debug(rtwdev, RTW89_DBG_TSSI, + "[TSSI][TRIM]: path=%d mcs trim_de=%d\n", + path, val); + } + + return val; + +calc_6g: + tgidx = phy_tssi_get_6g_trim_group(ch); + + rtw89_debug(rtwdev, RTW89_DBG_TSSI, + "[TSSI][TRIM]: path=%d mcs trim_group_idx=0x%x\n", + path, tgidx); + + if (PHY_IS_TSSI_EXTRA_GROUP(tgidx)) { + tgidx_1st = PHY_TSSI_EXTRA_GET_GROUP_IDX1(tgidx); + tgidx_2nd = PHY_TSSI_EXTRA_GET_GROUP_IDX2(tgidx); + tde_1st = tssi_info->tssi_trim_6g[path][tgidx_1st]; + tde_2nd = tssi_info->tssi_trim_6g[path][tgidx_2nd]; + val = (tde_1st + tde_2nd) / 2; + + rtw89_debug(rtwdev, RTW89_DBG_TSSI, + "[TSSI][TRIM]: path=%d mcs trim_de=%d 1st=%d 2nd=%d\n", + path, val, tde_1st, tde_2nd); + } else { + val = tssi_info->tssi_trim_6g[path][tgidx]; + + rtw89_debug(rtwdev, RTW89_DBG_TSSI, + "[TSSI][TRIM]: path=%d mcs trim_de=%d\n", + path, val); + } + + return val; +} + +void rtw89_phy_rfk_tssi_fill_fwcmd_efuse_to_de(struct rtw89_dev *rtwdev, + enum rtw89_phy_idx phy, + const struct rtw89_chan *chan, + struct rtw89_h2c_rf_tssi *h2c) +{ + struct rtw89_tssi_info *tssi_info = &rtwdev->tssi; + u8 ch = chan->channel; + s8 trim_de; + s8 ofdm_de; + s8 cck_de; + u8 gidx; + s8 val; + int i; + + rtw89_debug(rtwdev, RTW89_DBG_TSSI, "[TSSI][TRIM]: phy=%d ch=%d\n", + phy, ch); + + for (i = RF_PATH_A; i <= RF_PATH_B; i++) { + trim_de = phy_tssi_get_ofdm_trim_de(rtwdev, phy, chan, i); + h2c->curr_tssi_trim_de[i] = trim_de; + + rtw89_debug(rtwdev, RTW89_DBG_TSSI, + "[TSSI][TRIM]: path=%d trim_de=0x%x\n", i, trim_de); + + gidx = phy_tssi_get_cck_group(ch); + cck_de = tssi_info->tssi_cck[i][gidx]; + val = u32_get_bits(cck_de + trim_de, 0xff); + + h2c->curr_tssi_cck_de[i] = 0x0; + h2c->curr_tssi_cck_de_20m[i] = val; + h2c->curr_tssi_cck_de_40m[i] = val; + h2c->curr_tssi_efuse_cck_de[i] = cck_de; + + rtw89_debug(rtwdev, RTW89_DBG_TSSI, + "[TSSI][TRIM]: path=%d cck_de=0x%x\n", i, cck_de); + + ofdm_de = phy_tssi_get_ofdm_de(rtwdev, phy, chan, i); + val = u32_get_bits(ofdm_de + trim_de, 0xff); + + h2c->curr_tssi_ofdm_de[i] = 0x0; + h2c->curr_tssi_ofdm_de_20m[i] = val; + h2c->curr_tssi_ofdm_de_40m[i] = val; + h2c->curr_tssi_ofdm_de_80m[i] = val; + h2c->curr_tssi_ofdm_de_160m[i] = val; + h2c->curr_tssi_ofdm_de_320m[i] = val; + h2c->curr_tssi_efuse_ofdm_de[i] = ofdm_de; + + rtw89_debug(rtwdev, RTW89_DBG_TSSI, + "[TSSI][TRIM]: path=%d ofdm_de=0x%x\n", i, ofdm_de); + } +} + +void rtw89_phy_rfk_tssi_fill_fwcmd_tmeter_tbl(struct rtw89_dev *rtwdev, + enum rtw89_phy_idx phy, + const struct rtw89_chan *chan, + struct rtw89_h2c_rf_tssi *h2c) +{ + struct rtw89_fw_txpwr_track_cfg *trk = rtwdev->fw.elm_info.txpwr_trk; + struct rtw89_tssi_info *tssi_info = &rtwdev->tssi; + const s8 *thm_up[RF_PATH_B + 1] = {}; + const s8 *thm_down[RF_PATH_B + 1] = {}; + u8 subband = chan->subband_type; + s8 thm_ofst[128] = {0}; + u8 thermal; + u8 path; + u8 i, j; + + switch (subband) { + default: + case RTW89_CH_2G: + thm_up[RF_PATH_A] = trk->delta[RTW89_FW_TXPWR_TRK_TYPE_2GA_P][0]; + thm_down[RF_PATH_A] = trk->delta[RTW89_FW_TXPWR_TRK_TYPE_2GA_N][0]; + thm_up[RF_PATH_B] = trk->delta[RTW89_FW_TXPWR_TRK_TYPE_2GB_P][0]; + thm_down[RF_PATH_B] = trk->delta[RTW89_FW_TXPWR_TRK_TYPE_2GB_N][0]; + break; + case RTW89_CH_5G_BAND_1: + thm_up[RF_PATH_A] = trk->delta[RTW89_FW_TXPWR_TRK_TYPE_5GA_P][0]; + thm_down[RF_PATH_A] = trk->delta[RTW89_FW_TXPWR_TRK_TYPE_5GA_N][0]; + thm_up[RF_PATH_B] = trk->delta[RTW89_FW_TXPWR_TRK_TYPE_5GB_P][0]; + thm_down[RF_PATH_B] = trk->delta[RTW89_FW_TXPWR_TRK_TYPE_5GB_N][0]; + break; + case RTW89_CH_5G_BAND_3: + thm_up[RF_PATH_A] = trk->delta[RTW89_FW_TXPWR_TRK_TYPE_5GA_P][1]; + thm_down[RF_PATH_A] = trk->delta[RTW89_FW_TXPWR_TRK_TYPE_5GA_N][1]; + thm_up[RF_PATH_B] = trk->delta[RTW89_FW_TXPWR_TRK_TYPE_5GB_P][1]; + thm_down[RF_PATH_B] = trk->delta[RTW89_FW_TXPWR_TRK_TYPE_5GB_N][1]; + break; + case RTW89_CH_5G_BAND_4: + thm_up[RF_PATH_A] = trk->delta[RTW89_FW_TXPWR_TRK_TYPE_5GA_P][2]; + thm_down[RF_PATH_A] = trk->delta[RTW89_FW_TXPWR_TRK_TYPE_5GA_N][2]; + thm_up[RF_PATH_B] = trk->delta[RTW89_FW_TXPWR_TRK_TYPE_5GB_P][2]; + thm_down[RF_PATH_B] = trk->delta[RTW89_FW_TXPWR_TRK_TYPE_5GB_N][2]; + break; + case RTW89_CH_6G_BAND_IDX0: + case RTW89_CH_6G_BAND_IDX1: + thm_up[RF_PATH_A] = trk->delta[RTW89_FW_TXPWR_TRK_TYPE_6GA_P][0]; + thm_down[RF_PATH_A] = trk->delta[RTW89_FW_TXPWR_TRK_TYPE_6GA_N][0]; + thm_up[RF_PATH_B] = trk->delta[RTW89_FW_TXPWR_TRK_TYPE_6GB_P][0]; + thm_down[RF_PATH_B] = trk->delta[RTW89_FW_TXPWR_TRK_TYPE_6GB_N][0]; + break; + case RTW89_CH_6G_BAND_IDX2: + case RTW89_CH_6G_BAND_IDX3: + thm_up[RF_PATH_A] = trk->delta[RTW89_FW_TXPWR_TRK_TYPE_6GA_P][1]; + thm_down[RF_PATH_A] = trk->delta[RTW89_FW_TXPWR_TRK_TYPE_6GA_N][1]; + thm_up[RF_PATH_B] = trk->delta[RTW89_FW_TXPWR_TRK_TYPE_6GB_P][1]; + thm_down[RF_PATH_B] = trk->delta[RTW89_FW_TXPWR_TRK_TYPE_6GB_N][1]; + break; + case RTW89_CH_6G_BAND_IDX4: + case RTW89_CH_6G_BAND_IDX5: + thm_up[RF_PATH_A] = trk->delta[RTW89_FW_TXPWR_TRK_TYPE_6GA_P][2]; + thm_down[RF_PATH_A] = trk->delta[RTW89_FW_TXPWR_TRK_TYPE_6GA_N][2]; + thm_up[RF_PATH_B] = trk->delta[RTW89_FW_TXPWR_TRK_TYPE_6GB_P][2]; + thm_down[RF_PATH_B] = trk->delta[RTW89_FW_TXPWR_TRK_TYPE_6GB_N][2]; + break; + case RTW89_CH_6G_BAND_IDX6: + case RTW89_CH_6G_BAND_IDX7: + thm_up[RF_PATH_A] = trk->delta[RTW89_FW_TXPWR_TRK_TYPE_6GA_P][3]; + thm_down[RF_PATH_A] = trk->delta[RTW89_FW_TXPWR_TRK_TYPE_6GA_N][3]; + thm_up[RF_PATH_B] = trk->delta[RTW89_FW_TXPWR_TRK_TYPE_6GB_P][3]; + thm_down[RF_PATH_B] = trk->delta[RTW89_FW_TXPWR_TRK_TYPE_6GB_N][3]; + break; + } + + rtw89_debug(rtwdev, RTW89_DBG_TSSI, + "[TSSI] tmeter tbl on subband: %u\n", subband); + + for (path = RF_PATH_A; path <= RF_PATH_B; path++) { + thermal = tssi_info->thermal[path]; + rtw89_debug(rtwdev, RTW89_DBG_TSSI, + "path: %u, pg thermal: 0x%x\n", path, thermal); + + if (thermal == 0xff) { + h2c->pg_thermal[path] = 0x38; + memset(h2c->ftable[path], 0, sizeof(h2c->ftable[path])); + continue; + } + + h2c->pg_thermal[path] = thermal; + + i = 0; + for (j = 0; j < 64; j++) + thm_ofst[j] = i < DELTA_SWINGIDX_SIZE ? + thm_up[path][i++] : + thm_up[path][DELTA_SWINGIDX_SIZE - 1]; + + i = 1; + for (j = 127; j >= 64; j--) + thm_ofst[j] = i < DELTA_SWINGIDX_SIZE ? + -thm_down[path][i++] : + -thm_down[path][DELTA_SWINGIDX_SIZE - 1]; + + for (i = 0; i < 128; i += 4) { + h2c->ftable[path][i + 0] = thm_ofst[i + 3]; + h2c->ftable[path][i + 1] = thm_ofst[i + 2]; + h2c->ftable[path][i + 2] = thm_ofst[i + 1]; + h2c->ftable[path][i + 3] = thm_ofst[i + 0]; + + rtw89_debug(rtwdev, RTW89_DBG_TSSI, + "thm ofst [%x]: %02x %02x %02x %02x\n", + i, thm_ofst[i], thm_ofst[i + 1], + thm_ofst[i + 2], thm_ofst[i + 3]); + } + } +} + static u8 rtw89_phy_cfo_get_xcap_reg(struct rtw89_dev *rtwdev, bool sc_xo) { const struct rtw89_xtal_info *xtal = rtwdev->chip->xtal_info; diff --git a/drivers/net/wireless/realtek/rtw89/phy.h b/drivers/net/wireless/realtek/rtw89/phy.h index df915cb0833f..459e919ddd24 100644 --- a/drivers/net/wireless/realtek/rtw89/phy.h +++ b/drivers/net/wireless/realtek/rtw89/phy.h @@ -888,6 +888,14 @@ void rtw89_phy_c2h_handle(struct rtw89_dev *rtwdev, struct sk_buff *skb, void rtw89_phy_rfk_report_prep(struct rtw89_dev *rtwdev); int rtw89_phy_rfk_report_wait(struct rtw89_dev *rtwdev, const char *rfk_name, unsigned int ms); +void rtw89_phy_rfk_tssi_fill_fwcmd_efuse_to_de(struct rtw89_dev *rtwdev, + enum rtw89_phy_idx phy, + const struct rtw89_chan *chan, + struct rtw89_h2c_rf_tssi *h2c); +void rtw89_phy_rfk_tssi_fill_fwcmd_tmeter_tbl(struct rtw89_dev *rtwdev, + enum rtw89_phy_idx phy, + const struct rtw89_chan *chan, + struct rtw89_h2c_rf_tssi *h2c); void rtw89_phy_cfo_track(struct rtw89_dev *rtwdev); void rtw89_phy_cfo_track_work(struct work_struct *work); void rtw89_phy_cfo_parse(struct rtw89_dev *rtwdev, s16 cfo_val, -- cgit v1.2.3 From ff146ec22d5fe136b71b31703b1bea540ffc4d5f Mon Sep 17 00:00:00 2001 From: Ping-Ke Shih Date: Fri, 2 Feb 2024 11:06:40 +0800 Subject: wifi: rtw89: 8922a: rfk: implement chip_ops to call RF calibrations Calling RF calibrations when interface up, connection, switching bands and going to scan. For 8922AE, RF calibrations are moved to firmware, so use H2C commands to trigger RF calibrations and wait for a C2H event to indicate completion. Then, do next RF calibration. Signed-off-by: Ping-Ke Shih Signed-off-by: Kalle Valo Link: https://msgid.link/20240202030642.108385-10-pkshih@realtek.com --- drivers/net/wireless/realtek/rtw89/coex.h | 1 + drivers/net/wireless/realtek/rtw89/phy.c | 115 ++++++++++++++++++++++++++ drivers/net/wireless/realtek/rtw89/phy.h | 25 +++++- drivers/net/wireless/realtek/rtw89/rtw8922a.c | 69 ++++++++++++++++ 4 files changed, 207 insertions(+), 3 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/realtek/rtw89/coex.h b/drivers/net/wireless/realtek/rtw89/coex.h index 46e25c6f88a6..08121fd899e6 100644 --- a/drivers/net/wireless/realtek/rtw89/coex.h +++ b/drivers/net/wireless/realtek/rtw89/coex.h @@ -23,6 +23,7 @@ enum btc_wl_rfk_type { BTC_WRFKT_DACK = 4, BTC_WRFKT_RXDCK = 5, BTC_WRFKT_TSSI = 6, + BTC_WRFKT_CHLK = 7, }; #define NM_EXEC false diff --git a/drivers/net/wireless/realtek/rtw89/phy.c b/drivers/net/wireless/realtek/rtw89/phy.c index 77b3b233697b..f02b365b0cec 100644 --- a/drivers/net/wireless/realtek/rtw89/phy.c +++ b/drivers/net/wireless/realtek/rtw89/phy.c @@ -2834,6 +2834,7 @@ void (* const rtw89_phy_c2h_rfk_log_handler[])(struct rtw89_dev *rtwdev, [RTW89_PHY_C2H_RFK_LOG_FUNC_TXGAPK] = rtw89_phy_c2h_rfk_log_txgapk, }; +static void rtw89_phy_rfk_report_prep(struct rtw89_dev *rtwdev) { struct rtw89_rfk_wait_info *wait = &rtwdev->rfk_wait; @@ -2843,6 +2844,7 @@ void rtw89_phy_rfk_report_prep(struct rtw89_dev *rtwdev) reinit_completion(&wait->completion); } +static int rtw89_phy_rfk_report_wait(struct rtw89_dev *rtwdev, const char *rfk_name, unsigned int ms) { @@ -2959,6 +2961,119 @@ void rtw89_phy_c2h_handle(struct rtw89_dev *rtwdev, struct sk_buff *skb, handler(rtwdev, skb, len); } +int rtw89_phy_rfk_pre_ntfy_and_wait(struct rtw89_dev *rtwdev, + enum rtw89_phy_idx phy_idx, + unsigned int ms) +{ + int ret; + + rtw89_phy_rfk_report_prep(rtwdev); + + ret = rtw89_fw_h2c_rf_pre_ntfy(rtwdev, phy_idx); + if (ret) + return ret; + + return rtw89_phy_rfk_report_wait(rtwdev, "PRE_NTFY", ms); +} +EXPORT_SYMBOL(rtw89_phy_rfk_pre_ntfy_and_wait); + +int rtw89_phy_rfk_tssi_and_wait(struct rtw89_dev *rtwdev, + enum rtw89_phy_idx phy_idx, + enum rtw89_tssi_mode tssi_mode, + unsigned int ms) +{ + int ret; + + rtw89_phy_rfk_report_prep(rtwdev); + + ret = rtw89_fw_h2c_rf_tssi(rtwdev, phy_idx, tssi_mode); + if (ret) + return ret; + + return rtw89_phy_rfk_report_wait(rtwdev, "TSSI", ms); +} +EXPORT_SYMBOL(rtw89_phy_rfk_tssi_and_wait); + +int rtw89_phy_rfk_iqk_and_wait(struct rtw89_dev *rtwdev, + enum rtw89_phy_idx phy_idx, + unsigned int ms) +{ + int ret; + + rtw89_phy_rfk_report_prep(rtwdev); + + ret = rtw89_fw_h2c_rf_iqk(rtwdev, phy_idx); + if (ret) + return ret; + + return rtw89_phy_rfk_report_wait(rtwdev, "IQK", ms); +} +EXPORT_SYMBOL(rtw89_phy_rfk_iqk_and_wait); + +int rtw89_phy_rfk_dpk_and_wait(struct rtw89_dev *rtwdev, + enum rtw89_phy_idx phy_idx, + unsigned int ms) +{ + int ret; + + rtw89_phy_rfk_report_prep(rtwdev); + + ret = rtw89_fw_h2c_rf_dpk(rtwdev, phy_idx); + if (ret) + return ret; + + return rtw89_phy_rfk_report_wait(rtwdev, "DPK", ms); +} +EXPORT_SYMBOL(rtw89_phy_rfk_dpk_and_wait); + +int rtw89_phy_rfk_txgapk_and_wait(struct rtw89_dev *rtwdev, + enum rtw89_phy_idx phy_idx, + unsigned int ms) +{ + int ret; + + rtw89_phy_rfk_report_prep(rtwdev); + + ret = rtw89_fw_h2c_rf_txgapk(rtwdev, phy_idx); + if (ret) + return ret; + + return rtw89_phy_rfk_report_wait(rtwdev, "TXGAPK", ms); +} +EXPORT_SYMBOL(rtw89_phy_rfk_txgapk_and_wait); + +int rtw89_phy_rfk_dack_and_wait(struct rtw89_dev *rtwdev, + enum rtw89_phy_idx phy_idx, + unsigned int ms) +{ + int ret; + + rtw89_phy_rfk_report_prep(rtwdev); + + ret = rtw89_fw_h2c_rf_dack(rtwdev, phy_idx); + if (ret) + return ret; + + return rtw89_phy_rfk_report_wait(rtwdev, "DACK", ms); +} +EXPORT_SYMBOL(rtw89_phy_rfk_dack_and_wait); + +int rtw89_phy_rfk_rxdck_and_wait(struct rtw89_dev *rtwdev, + enum rtw89_phy_idx phy_idx, + unsigned int ms) +{ + int ret; + + rtw89_phy_rfk_report_prep(rtwdev); + + ret = rtw89_fw_h2c_rf_rxdck(rtwdev, phy_idx); + if (ret) + return ret; + + return rtw89_phy_rfk_report_wait(rtwdev, "RX_DCK", ms); +} +EXPORT_SYMBOL(rtw89_phy_rfk_rxdck_and_wait); + static u32 phy_tssi_get_cck_group(u8 ch) { switch (ch) { diff --git a/drivers/net/wireless/realtek/rtw89/phy.h b/drivers/net/wireless/realtek/rtw89/phy.h index 459e919ddd24..d80ddc723e86 100644 --- a/drivers/net/wireless/realtek/rtw89/phy.h +++ b/drivers/net/wireless/realtek/rtw89/phy.h @@ -885,9 +885,28 @@ void rtw89_phy_rate_pattern_vif(struct rtw89_dev *rtwdev, bool rtw89_phy_c2h_chk_atomic(struct rtw89_dev *rtwdev, u8 class, u8 func); void rtw89_phy_c2h_handle(struct rtw89_dev *rtwdev, struct sk_buff *skb, u32 len, u8 class, u8 func); -void rtw89_phy_rfk_report_prep(struct rtw89_dev *rtwdev); -int rtw89_phy_rfk_report_wait(struct rtw89_dev *rtwdev, const char *rfk_name, - unsigned int ms); +int rtw89_phy_rfk_pre_ntfy_and_wait(struct rtw89_dev *rtwdev, + enum rtw89_phy_idx phy_idx, + unsigned int ms); +int rtw89_phy_rfk_tssi_and_wait(struct rtw89_dev *rtwdev, + enum rtw89_phy_idx phy_idx, + enum rtw89_tssi_mode tssi_mode, + unsigned int ms); +int rtw89_phy_rfk_iqk_and_wait(struct rtw89_dev *rtwdev, + enum rtw89_phy_idx phy_idx, + unsigned int ms); +int rtw89_phy_rfk_dpk_and_wait(struct rtw89_dev *rtwdev, + enum rtw89_phy_idx phy_idx, + unsigned int ms); +int rtw89_phy_rfk_txgapk_and_wait(struct rtw89_dev *rtwdev, + enum rtw89_phy_idx phy_idx, + unsigned int ms); +int rtw89_phy_rfk_dack_and_wait(struct rtw89_dev *rtwdev, + enum rtw89_phy_idx phy_idx, + unsigned int ms); +int rtw89_phy_rfk_rxdck_and_wait(struct rtw89_dev *rtwdev, + enum rtw89_phy_idx phy_idx, + unsigned int ms); void rtw89_phy_rfk_tssi_fill_fwcmd_efuse_to_de(struct rtw89_dev *rtwdev, enum rtw89_phy_idx phy, const struct rtw89_chan *chan, diff --git a/drivers/net/wireless/realtek/rtw89/rtw8922a.c b/drivers/net/wireless/realtek/rtw89/rtw8922a.c index aefad3f2e612..69ae8f81181e 100644 --- a/drivers/net/wireless/realtek/rtw89/rtw8922a.c +++ b/drivers/net/wireless/realtek/rtw89/rtw8922a.c @@ -2,6 +2,7 @@ /* Copyright(c) 2023 Realtek Corporation */ +#include "coex.h" #include "debug.h" #include "efuse.h" #include "fw.h" @@ -1369,6 +1370,69 @@ void rtw8922a_hal_reset(struct rtw89_dev *rtwdev, } } +static void rtw8922a_rfk_init(struct rtw89_dev *rtwdev) +{ + struct rtw89_rfk_mcc_info *rfk_mcc = &rtwdev->rfk_mcc; + + rtwdev->is_tssi_mode[RF_PATH_A] = false; + rtwdev->is_tssi_mode[RF_PATH_B] = false; + memset(rfk_mcc, 0, sizeof(*rfk_mcc)); +} + +static void _wait_rx_mode(struct rtw89_dev *rtwdev, u8 kpath) +{ + u32 rf_mode; + u8 path; + int ret; + + for (path = 0; path < RF_PATH_NUM_8922A; path++) { + if (!(kpath & BIT(path))) + continue; + + ret = read_poll_timeout_atomic(rtw89_read_rf, rf_mode, rf_mode != 2, + 2, 5000, false, rtwdev, path, 0x00, + RR_MOD_MASK); + rtw89_debug(rtwdev, RTW89_DBG_RFK, + "[RFK] Wait S%d to Rx mode!! (ret = %d)\n", + path, ret); + } +} + +static void rtw8922a_rfk_channel(struct rtw89_dev *rtwdev) +{ + enum rtw89_phy_idx phy_idx = RTW89_PHY_0; + u8 phy_map = rtw89_btc_phymap(rtwdev, phy_idx, RF_AB); + u32 tx_en; + + rtw89_btc_ntfy_wl_rfk(rtwdev, phy_map, BTC_WRFKT_CHLK, BTC_WRFK_START); + rtw89_chip_stop_sch_tx(rtwdev, phy_idx, &tx_en, RTW89_SCH_TX_SEL_ALL); + _wait_rx_mode(rtwdev, RF_AB); + + rtw89_phy_rfk_pre_ntfy_and_wait(rtwdev, phy_idx, 5); + rtw89_phy_rfk_txgapk_and_wait(rtwdev, phy_idx, 54); + rtw89_phy_rfk_iqk_and_wait(rtwdev, phy_idx, 84); + rtw89_phy_rfk_tssi_and_wait(rtwdev, phy_idx, RTW89_TSSI_NORMAL, 6); + rtw89_phy_rfk_dpk_and_wait(rtwdev, phy_idx, 34); + rtw89_phy_rfk_rxdck_and_wait(rtwdev, RTW89_PHY_0, 32); + + rtw89_chip_resume_sch_tx(rtwdev, phy_idx, tx_en); + rtw89_btc_ntfy_wl_rfk(rtwdev, phy_map, BTC_WRFKT_CHLK, BTC_WRFK_STOP); +} + +static void rtw8922a_rfk_band_changed(struct rtw89_dev *rtwdev, + enum rtw89_phy_idx phy_idx) +{ + rtw89_phy_rfk_tssi_and_wait(rtwdev, phy_idx, RTW89_TSSI_SCAN, 6); +} + +static void rtw8922a_rfk_scan(struct rtw89_dev *rtwdev, bool start) +{ +} + +static void rtw8922a_rfk_track(struct rtw89_dev *rtwdev) +{ +} + static void rtw8922a_set_txpwr_ref(struct rtw89_dev *rtwdev, enum rtw89_phy_idx phy_idx) { @@ -1622,6 +1686,11 @@ static const struct rtw89_chip_ops rtw8922a_chip_ops = { .read_phycap = rtw8922a_read_phycap, .fem_setup = NULL, .rfe_gpio = NULL, + .rfk_init = rtw8922a_rfk_init, + .rfk_channel = rtw8922a_rfk_channel, + .rfk_band_changed = rtw8922a_rfk_band_changed, + .rfk_scan = rtw8922a_rfk_scan, + .rfk_track = rtw8922a_rfk_track, .power_trim = rtw8922a_power_trim, .set_txpwr = rtw8922a_set_txpwr, .set_txpwr_ctrl = rtw8922a_set_txpwr_ctrl, -- cgit v1.2.3 From 7e2629dc843fb46f0b8b3aba44708b508f6f98cf Mon Sep 17 00:00:00 2001 From: Ping-Ke Shih Date: Fri, 2 Feb 2024 11:06:41 +0800 Subject: wifi: rtw89: 8922a: add chip_ops::rfk_init_late to do initial RF calibrations later The RF calibrations are moved into firmware, so we trigger calibrations by H2C commands and wait for C2H completion events. However, these events can be received only after HCI (i.e. PCI for now) starts, so we should do initial RF calibrations after that. Signed-off-by: Ping-Ke Shih Signed-off-by: Kalle Valo Link: https://msgid.link/20240202030642.108385-11-pkshih@realtek.com --- drivers/net/wireless/realtek/rtw89/core.c | 1 + drivers/net/wireless/realtek/rtw89/core.h | 9 +++++++++ drivers/net/wireless/realtek/rtw89/rtw8851b.c | 1 + drivers/net/wireless/realtek/rtw89/rtw8852a.c | 1 + drivers/net/wireless/realtek/rtw89/rtw8852b.c | 1 + drivers/net/wireless/realtek/rtw89/rtw8852c.c | 1 + drivers/net/wireless/realtek/rtw89/rtw8922a.c | 9 +++++++++ 7 files changed, 23 insertions(+) (limited to 'drivers/net') diff --git a/drivers/net/wireless/realtek/rtw89/core.c b/drivers/net/wireless/realtek/rtw89/core.c index c6c3e0c0bf84..61a216464b6d 100644 --- a/drivers/net/wireless/realtek/rtw89/core.c +++ b/drivers/net/wireless/realtek/rtw89/core.c @@ -4101,6 +4101,7 @@ int rtw89_core_start(struct rtw89_dev *rtwdev) set_bit(RTW89_FLAG_RUNNING, rtwdev->flags); + rtw89_chip_rfk_init_late(rtwdev); rtw89_btc_ntfy_radio_state(rtwdev, BTC_RFCTRL_WL_ON); rtw89_fw_h2c_fw_log(rtwdev, rtwdev->fw.log.enable); rtw89_fw_h2c_init_ba_cam(rtwdev); diff --git a/drivers/net/wireless/realtek/rtw89/core.h b/drivers/net/wireless/realtek/rtw89/core.h index ccc9f96fc18b..270403f6c3d5 100644 --- a/drivers/net/wireless/realtek/rtw89/core.h +++ b/drivers/net/wireless/realtek/rtw89/core.h @@ -3157,6 +3157,7 @@ struct rtw89_chip_ops { void (*fem_setup)(struct rtw89_dev *rtwdev); void (*rfe_gpio)(struct rtw89_dev *rtwdev); void (*rfk_init)(struct rtw89_dev *rtwdev); + void (*rfk_init_late)(struct rtw89_dev *rtwdev); void (*rfk_channel)(struct rtw89_dev *rtwdev); void (*rfk_band_changed)(struct rtw89_dev *rtwdev, enum rtw89_phy_idx phy_idx); @@ -5642,6 +5643,14 @@ static inline void rtw89_chip_rfk_init(struct rtw89_dev *rtwdev) chip->ops->rfk_init(rtwdev); } +static inline void rtw89_chip_rfk_init_late(struct rtw89_dev *rtwdev) +{ + const struct rtw89_chip_info *chip = rtwdev->chip; + + if (chip->ops->rfk_init_late) + chip->ops->rfk_init_late(rtwdev); +} + static inline void rtw89_chip_rfk_channel(struct rtw89_dev *rtwdev) { const struct rtw89_chip_info *chip = rtwdev->chip; diff --git a/drivers/net/wireless/realtek/rtw89/rtw8851b.c b/drivers/net/wireless/realtek/rtw89/rtw8851b.c index 09b23c56aa8e..09e38713bca7 100644 --- a/drivers/net/wireless/realtek/rtw89/rtw8851b.c +++ b/drivers/net/wireless/realtek/rtw89/rtw8851b.c @@ -2311,6 +2311,7 @@ static const struct rtw89_chip_ops rtw8851b_chip_ops = { .fem_setup = NULL, .rfe_gpio = rtw8851b_rfe_gpio, .rfk_init = rtw8851b_rfk_init, + .rfk_init_late = NULL, .rfk_channel = rtw8851b_rfk_channel, .rfk_band_changed = rtw8851b_rfk_band_changed, .rfk_scan = rtw8851b_rfk_scan, diff --git a/drivers/net/wireless/realtek/rtw89/rtw8852a.c b/drivers/net/wireless/realtek/rtw89/rtw8852a.c index c28f05bbdccf..01c249dddfb8 100644 --- a/drivers/net/wireless/realtek/rtw89/rtw8852a.c +++ b/drivers/net/wireless/realtek/rtw89/rtw8852a.c @@ -2055,6 +2055,7 @@ static const struct rtw89_chip_ops rtw8852a_chip_ops = { .fem_setup = rtw8852a_fem_setup, .rfe_gpio = NULL, .rfk_init = rtw8852a_rfk_init, + .rfk_init_late = NULL, .rfk_channel = rtw8852a_rfk_channel, .rfk_band_changed = rtw8852a_rfk_band_changed, .rfk_scan = rtw8852a_rfk_scan, diff --git a/drivers/net/wireless/realtek/rtw89/rtw8852b.c b/drivers/net/wireless/realtek/rtw89/rtw8852b.c index 18ed372ed5cd..fb6ad335a37a 100644 --- a/drivers/net/wireless/realtek/rtw89/rtw8852b.c +++ b/drivers/net/wireless/realtek/rtw89/rtw8852b.c @@ -2480,6 +2480,7 @@ static const struct rtw89_chip_ops rtw8852b_chip_ops = { .fem_setup = NULL, .rfe_gpio = NULL, .rfk_init = rtw8852b_rfk_init, + .rfk_init_late = NULL, .rfk_channel = rtw8852b_rfk_channel, .rfk_band_changed = rtw8852b_rfk_band_changed, .rfk_scan = rtw8852b_rfk_scan, diff --git a/drivers/net/wireless/realtek/rtw89/rtw8852c.c b/drivers/net/wireless/realtek/rtw89/rtw8852c.c index 431acfaba89b..00861c328ca0 100644 --- a/drivers/net/wireless/realtek/rtw89/rtw8852c.c +++ b/drivers/net/wireless/realtek/rtw89/rtw8852c.c @@ -2825,6 +2825,7 @@ static const struct rtw89_chip_ops rtw8852c_chip_ops = { .fem_setup = NULL, .rfe_gpio = NULL, .rfk_init = rtw8852c_rfk_init, + .rfk_init_late = NULL, .rfk_channel = rtw8852c_rfk_channel, .rfk_band_changed = rtw8852c_rfk_band_changed, .rfk_scan = rtw8852c_rfk_scan, diff --git a/drivers/net/wireless/realtek/rtw89/rtw8922a.c b/drivers/net/wireless/realtek/rtw89/rtw8922a.c index 69ae8f81181e..0cbe4780eb69 100644 --- a/drivers/net/wireless/realtek/rtw89/rtw8922a.c +++ b/drivers/net/wireless/realtek/rtw89/rtw8922a.c @@ -1379,6 +1379,14 @@ static void rtw8922a_rfk_init(struct rtw89_dev *rtwdev) memset(rfk_mcc, 0, sizeof(*rfk_mcc)); } +static void rtw8922a_rfk_init_late(struct rtw89_dev *rtwdev) +{ + rtw89_phy_rfk_pre_ntfy_and_wait(rtwdev, RTW89_PHY_0, 5); + + rtw89_phy_rfk_dack_and_wait(rtwdev, RTW89_PHY_0, 58); + rtw89_phy_rfk_rxdck_and_wait(rtwdev, RTW89_PHY_0, 32); +} + static void _wait_rx_mode(struct rtw89_dev *rtwdev, u8 kpath) { u32 rf_mode; @@ -1687,6 +1695,7 @@ static const struct rtw89_chip_ops rtw8922a_chip_ops = { .fem_setup = NULL, .rfe_gpio = NULL, .rfk_init = rtw8922a_rfk_init, + .rfk_init_late = rtw8922a_rfk_init_late, .rfk_channel = rtw8922a_rfk_channel, .rfk_band_changed = rtw8922a_rfk_band_changed, .rfk_scan = rtw8922a_rfk_scan, -- cgit v1.2.3 From 4dbd964f33aab6f99891b9610ad4b36cc215be0d Mon Sep 17 00:00:00 2001 From: Ping-Ke Shih Date: Fri, 2 Feb 2024 11:06:42 +0800 Subject: wifi: rtw89: 8922a: add chip_ops::rfk_hw_init Add a chip_ops for WiFi 7 chips to set additional RF configurations including MLO and PLL settings. Signed-off-by: Ping-Ke Shih Signed-off-by: Kalle Valo Link: https://msgid.link/20240202030642.108385-12-pkshih@realtek.com --- drivers/net/wireless/realtek/rtw89/core.h | 9 + drivers/net/wireless/realtek/rtw89/mac.h | 2 + drivers/net/wireless/realtek/rtw89/phy.c | 1 + drivers/net/wireless/realtek/rtw89/reg.h | 6 + drivers/net/wireless/realtek/rtw89/rtw8851b.c | 1 + drivers/net/wireless/realtek/rtw89/rtw8852a.c | 1 + drivers/net/wireless/realtek/rtw89/rtw8852b.c | 1 + drivers/net/wireless/realtek/rtw89/rtw8852c.c | 1 + drivers/net/wireless/realtek/rtw89/rtw8922a.c | 1 + drivers/net/wireless/realtek/rtw89/rtw8922a_rfk.c | 202 ++++++++++++++++++++++ drivers/net/wireless/realtek/rtw89/rtw8922a_rfk.h | 1 + 11 files changed, 226 insertions(+) (limited to 'drivers/net') diff --git a/drivers/net/wireless/realtek/rtw89/core.h b/drivers/net/wireless/realtek/rtw89/core.h index 270403f6c3d5..22255e98ab6b 100644 --- a/drivers/net/wireless/realtek/rtw89/core.h +++ b/drivers/net/wireless/realtek/rtw89/core.h @@ -3156,6 +3156,7 @@ struct rtw89_chip_ops { int (*read_phycap)(struct rtw89_dev *rtwdev, u8 *phycap_map); void (*fem_setup)(struct rtw89_dev *rtwdev); void (*rfe_gpio)(struct rtw89_dev *rtwdev); + void (*rfk_hw_init)(struct rtw89_dev *rtwdev); void (*rfk_init)(struct rtw89_dev *rtwdev); void (*rfk_init_late)(struct rtw89_dev *rtwdev); void (*rfk_channel)(struct rtw89_dev *rtwdev); @@ -5604,6 +5605,14 @@ static inline void rtw89_chip_rfe_gpio(struct rtw89_dev *rtwdev) chip->ops->rfe_gpio(rtwdev); } +static inline void rtw89_chip_rfk_hw_init(struct rtw89_dev *rtwdev) +{ + const struct rtw89_chip_info *chip = rtwdev->chip; + + if (chip->ops->rfk_hw_init) + chip->ops->rfk_hw_init(rtwdev); +} + static inline void rtw89_chip_bb_preinit(struct rtw89_dev *rtwdev, enum rtw89_phy_idx phy_idx) { diff --git a/drivers/net/wireless/realtek/rtw89/mac.h b/drivers/net/wireless/realtek/rtw89/mac.h index b3fe4cab6d3a..7aea57804e93 100644 --- a/drivers/net/wireless/realtek/rtw89/mac.h +++ b/drivers/net/wireless/realtek/rtw89/mac.h @@ -1328,6 +1328,7 @@ enum rtw89_mac_xtal_si_offset { #define XTAL_SI_BIG_PWR_CUT BIT(1) XTAL_SI_XTAL_DRV = 0x15, #define XTAL_SI_DRV_LATCH BIT(4) + XTAL_SI_XTAL_PLL = 0x16, XTAL_SI_XTAL_XMD_2 = 0x24, #define XTAL_SI_LDO_LPS GENMASK(6, 4) XTAL_SI_XTAL_XMD_4 = 0x26, @@ -1361,6 +1362,7 @@ enum rtw89_mac_xtal_si_offset { XTAL_SI_SRAM_CTRL = 0xA1, #define XTAL_SI_SRAM_DIS BIT(1) #define FULL_BIT_MASK GENMASK(7, 0) + XTAL_SI_APBT = 0xD1, XTAL_SI_PLL = 0xE0, XTAL_SI_PLL_1 = 0xE1, }; diff --git a/drivers/net/wireless/realtek/rtw89/phy.c b/drivers/net/wireless/realtek/rtw89/phy.c index f02b365b0cec..9a8f5b764617 100644 --- a/drivers/net/wireless/realtek/rtw89/phy.c +++ b/drivers/net/wireless/realtek/rtw89/phy.c @@ -5874,6 +5874,7 @@ void rtw89_phy_dm_init(struct rtw89_dev *rtwdev) rtw89_chip_rfe_gpio(rtwdev); rtw89_phy_antdiv_set_ant(rtwdev); + rtw89_chip_rfk_hw_init(rtwdev); rtw89_phy_init_rf_nctl(rtwdev); rtw89_chip_rfk_init(rtwdev); rtw89_chip_set_txpwr_ctrl(rtwdev); diff --git a/drivers/net/wireless/realtek/rtw89/reg.h b/drivers/net/wireless/realtek/rtw89/reg.h index 9f209f068679..6368b2b32c0c 100644 --- a/drivers/net/wireless/realtek/rtw89/reg.h +++ b/drivers/net/wireless/realtek/rtw89/reg.h @@ -7402,6 +7402,7 @@ #define RR_MOD_M_RXBB GENMASK(9, 5) #define RR_MOD_LO_SEL BIT(1) #define RR_MODOPT 0x01 +#define RR_TXG_SEL GENMASK(19, 17) #define RR_MODOPT_M_TXPWR GENMASK(5, 0) #define RR_WLSEL 0x02 #define RR_WLSEL_AG GENMASK(18, 16) @@ -7594,6 +7595,7 @@ #define RR_MIXER_GN GENMASK(4, 3) #define RR_POW 0xa0 #define RR_POW_SYN GENMASK(3, 2) +#define RR_POW_SYN_V1 GENMASK(3, 0) #define RR_LOGEN 0xa3 #define RR_LOGEN_RPT GENMASK(19, 16) #define RR_SX 0xaf @@ -8734,6 +8736,8 @@ #define B_COEF_SEL_IQC BIT(0) #define B_COEF_SEL_IQC_V1 GENMASK(1, 0) #define B_COEF_SEL_MDPD BIT(8) +#define B_COEF_SEL_MDPD_V1 GENMASK(9, 8) +#define B_COEF_SEL_EN BIT(31) #define R_CFIR_SYS 0x8120 #define R_IQK_RES 0x8124 #define B_IQK_RES_K BIT(28) @@ -8755,8 +8759,10 @@ #define B_RFGAIN_BND GENMASK(4, 0) #define R_CFIR_MAP 0x8150 #define R_CFIR_LUT 0x8154 +#define R_CFIR_LUT_C1 0x8254 #define B_CFIR_LUT_SEL BIT(8) #define B_CFIR_LUT_SET BIT(4) +#define B_CFIR_LUT_G5 BIT(5) #define B_CFIR_LUT_G3 BIT(3) #define B_CFIR_LUT_G2 BIT(2) #define B_CFIR_LUT_GP_V1 GENMASK(2, 0) diff --git a/drivers/net/wireless/realtek/rtw89/rtw8851b.c b/drivers/net/wireless/realtek/rtw89/rtw8851b.c index 09e38713bca7..83db0a686ee2 100644 --- a/drivers/net/wireless/realtek/rtw89/rtw8851b.c +++ b/drivers/net/wireless/realtek/rtw89/rtw8851b.c @@ -2310,6 +2310,7 @@ static const struct rtw89_chip_ops rtw8851b_chip_ops = { .read_phycap = rtw8851b_read_phycap, .fem_setup = NULL, .rfe_gpio = rtw8851b_rfe_gpio, + .rfk_hw_init = NULL, .rfk_init = rtw8851b_rfk_init, .rfk_init_late = NULL, .rfk_channel = rtw8851b_rfk_channel, diff --git a/drivers/net/wireless/realtek/rtw89/rtw8852a.c b/drivers/net/wireless/realtek/rtw89/rtw8852a.c index 01c249dddfb8..8e808ded5d52 100644 --- a/drivers/net/wireless/realtek/rtw89/rtw8852a.c +++ b/drivers/net/wireless/realtek/rtw89/rtw8852a.c @@ -2054,6 +2054,7 @@ static const struct rtw89_chip_ops rtw8852a_chip_ops = { .read_phycap = rtw8852a_read_phycap, .fem_setup = rtw8852a_fem_setup, .rfe_gpio = NULL, + .rfk_hw_init = NULL, .rfk_init = rtw8852a_rfk_init, .rfk_init_late = NULL, .rfk_channel = rtw8852a_rfk_channel, diff --git a/drivers/net/wireless/realtek/rtw89/rtw8852b.c b/drivers/net/wireless/realtek/rtw89/rtw8852b.c index fb6ad335a37a..19454766f3de 100644 --- a/drivers/net/wireless/realtek/rtw89/rtw8852b.c +++ b/drivers/net/wireless/realtek/rtw89/rtw8852b.c @@ -2479,6 +2479,7 @@ static const struct rtw89_chip_ops rtw8852b_chip_ops = { .read_phycap = rtw8852b_read_phycap, .fem_setup = NULL, .rfe_gpio = NULL, + .rfk_hw_init = NULL, .rfk_init = rtw8852b_rfk_init, .rfk_init_late = NULL, .rfk_channel = rtw8852b_rfk_channel, diff --git a/drivers/net/wireless/realtek/rtw89/rtw8852c.c b/drivers/net/wireless/realtek/rtw89/rtw8852c.c index 00861c328ca0..ca8547fbd70e 100644 --- a/drivers/net/wireless/realtek/rtw89/rtw8852c.c +++ b/drivers/net/wireless/realtek/rtw89/rtw8852c.c @@ -2824,6 +2824,7 @@ static const struct rtw89_chip_ops rtw8852c_chip_ops = { .read_phycap = rtw8852c_read_phycap, .fem_setup = NULL, .rfe_gpio = NULL, + .rfk_hw_init = NULL, .rfk_init = rtw8852c_rfk_init, .rfk_init_late = NULL, .rfk_channel = rtw8852c_rfk_channel, diff --git a/drivers/net/wireless/realtek/rtw89/rtw8922a.c b/drivers/net/wireless/realtek/rtw89/rtw8922a.c index 0cbe4780eb69..6dc051934b0f 100644 --- a/drivers/net/wireless/realtek/rtw89/rtw8922a.c +++ b/drivers/net/wireless/realtek/rtw89/rtw8922a.c @@ -1694,6 +1694,7 @@ static const struct rtw89_chip_ops rtw8922a_chip_ops = { .read_phycap = rtw8922a_read_phycap, .fem_setup = NULL, .rfe_gpio = NULL, + .rfk_hw_init = rtw8922a_rfk_hw_init, .rfk_init = rtw8922a_rfk_init, .rfk_init_late = rtw8922a_rfk_init_late, .rfk_channel = rtw8922a_rfk_channel, diff --git a/drivers/net/wireless/realtek/rtw89/rtw8922a_rfk.c b/drivers/net/wireless/realtek/rtw89/rtw8922a_rfk.c index e0e8048db739..d8ef986e7877 100644 --- a/drivers/net/wireless/realtek/rtw89/rtw8922a_rfk.c +++ b/drivers/net/wireless/realtek/rtw89/rtw8922a_rfk.c @@ -2,7 +2,9 @@ /* Copyright(c) 2023 Realtek Corporation */ +#include "chan.h" #include "debug.h" +#include "mac.h" #include "phy.h" #include "reg.h" #include "rtw8922a.h" @@ -31,3 +33,203 @@ void rtw8922a_tssi_cont_en_phyidx(struct rtw89_dev *rtwdev, bool en, u8 phy_idx) rtw8922a_tssi_cont_en(rtwdev, en, RF_PATH_B); } } + +enum _rf_syn_pow { + RF_SYN_ON_OFF, + RF_SYN_OFF_ON, + RF_SYN_ALLON, + RF_SYN_ALLOFF, +}; + +static void rtw8922a_set_syn01_cav(struct rtw89_dev *rtwdev, enum _rf_syn_pow syn) +{ + if (syn == RF_SYN_ALLON) { + rtw89_write_rf(rtwdev, RF_PATH_A, RR_POW, RR_POW_SYN, 0x3); + rtw89_write_rf(rtwdev, RF_PATH_A, RR_POW, RR_POW_SYN, 0x2); + rtw89_write_rf(rtwdev, RF_PATH_A, RR_POW, RR_POW_SYN, 0x3); + + rtw89_write_rf(rtwdev, RF_PATH_B, RR_POW, RR_POW_SYN, 0x3); + rtw89_write_rf(rtwdev, RF_PATH_B, RR_POW, RR_POW_SYN, 0x2); + rtw89_write_rf(rtwdev, RF_PATH_B, RR_POW, RR_POW_SYN, 0x3); + } else if (syn == RF_SYN_ON_OFF) { + rtw89_write_rf(rtwdev, RF_PATH_A, RR_POW, RR_POW_SYN, 0x3); + rtw89_write_rf(rtwdev, RF_PATH_A, RR_POW, RR_POW_SYN, 0x2); + rtw89_write_rf(rtwdev, RF_PATH_A, RR_POW, RR_POW_SYN, 0x3); + + rtw89_write_rf(rtwdev, RF_PATH_B, RR_POW, RR_POW_SYN, 0x0); + } else if (syn == RF_SYN_OFF_ON) { + rtw89_write_rf(rtwdev, RF_PATH_A, RR_POW, RR_POW_SYN, 0x0); + + rtw89_write_rf(rtwdev, RF_PATH_B, RR_POW, RR_POW_SYN, 0x3); + rtw89_write_rf(rtwdev, RF_PATH_B, RR_POW, RR_POW_SYN, 0x2); + rtw89_write_rf(rtwdev, RF_PATH_B, RR_POW, RR_POW_SYN, 0x3); + } else if (syn == RF_SYN_ALLOFF) { + rtw89_write_rf(rtwdev, RF_PATH_A, RR_POW, RR_POW_SYN, 0x0); + rtw89_write_rf(rtwdev, RF_PATH_B, RR_POW, RR_POW_SYN, 0x0); + } +} + +static void rtw8922a_set_syn01_cbv(struct rtw89_dev *rtwdev, enum _rf_syn_pow syn) +{ + if (syn == RF_SYN_ALLON) { + rtw89_write_rf(rtwdev, RF_PATH_A, RR_POW, RR_POW_SYN_V1, 0xf); + rtw89_write_rf(rtwdev, RF_PATH_B, RR_POW, RR_POW_SYN_V1, 0xf); + } else if (syn == RF_SYN_ON_OFF) { + rtw89_write_rf(rtwdev, RF_PATH_A, RR_POW, RR_POW_SYN_V1, 0xf); + rtw89_write_rf(rtwdev, RF_PATH_B, RR_POW, RR_POW_SYN_V1, 0x0); + } else if (syn == RF_SYN_OFF_ON) { + rtw89_write_rf(rtwdev, RF_PATH_A, RR_POW, RR_POW_SYN_V1, 0x0); + rtw89_write_rf(rtwdev, RF_PATH_B, RR_POW, RR_POW_SYN_V1, 0xf); + } else if (syn == RF_SYN_ALLOFF) { + rtw89_write_rf(rtwdev, RF_PATH_A, RR_POW, RR_POW_SYN_V1, 0x0); + rtw89_write_rf(rtwdev, RF_PATH_B, RR_POW, RR_POW_SYN_V1, 0x0); + } +} + +static void rtw8922a_set_syn01(struct rtw89_dev *rtwdev, enum _rf_syn_pow syn) +{ + struct rtw89_hal *hal = &rtwdev->hal; + + rtw89_debug(rtwdev, RTW89_DBG_RFK, "SYN config=%d\n", syn); + + if (hal->cv == CHIP_CAV) + rtw8922a_set_syn01_cav(rtwdev, syn); + else + rtw8922a_set_syn01_cbv(rtwdev, syn); +} + +static void rtw8922a_chlk_ktbl_sel(struct rtw89_dev *rtwdev, u8 kpath, u8 idx) +{ + u32 tmp; + + if (idx > 2) { + rtw89_warn(rtwdev, "[DBCC][ERROR]indx is out of limit!! index(%d)", idx); + return; + } + + if (kpath & RF_A) { + rtw89_phy_write32_mask(rtwdev, R_COEF_SEL, B_COEF_SEL_EN, 0x1); + rtw89_phy_write32_mask(rtwdev, R_COEF_SEL, B_COEF_SEL_IQC_V1, idx); + rtw89_phy_write32_mask(rtwdev, R_COEF_SEL, B_COEF_SEL_MDPD_V1, idx); + rtw89_write_rf(rtwdev, RF_PATH_A, RR_MODOPT, RR_TXG_SEL, 0x4 | idx); + + tmp = rtw89_phy_read32_mask(rtwdev, R_COEF_SEL, BIT(0)); + rtw89_phy_write32_mask(rtwdev, R_CFIR_LUT, B_CFIR_LUT_G3, tmp); + tmp = rtw89_phy_read32_mask(rtwdev, R_COEF_SEL, BIT(1)); + rtw89_phy_write32_mask(rtwdev, R_CFIR_LUT, B_CFIR_LUT_G5, tmp); + } + + if (kpath & RF_B) { + rtw89_phy_write32_mask(rtwdev, R_COEF_SEL_C1, B_COEF_SEL_EN, 0x1); + rtw89_phy_write32_mask(rtwdev, R_COEF_SEL_C1, B_COEF_SEL_IQC_V1, idx); + rtw89_phy_write32_mask(rtwdev, R_COEF_SEL_C1, B_COEF_SEL_MDPD_V1, idx); + rtw89_write_rf(rtwdev, RF_PATH_B, RR_MODOPT, RR_TXG_SEL, 0x4 | idx); + + tmp = rtw89_phy_read32_mask(rtwdev, R_COEF_SEL_C1, BIT(0)); + rtw89_phy_write32_mask(rtwdev, R_CFIR_LUT_C1, B_CFIR_LUT_G3, tmp); + tmp = rtw89_phy_read32_mask(rtwdev, R_COEF_SEL_C1, BIT(1)); + rtw89_phy_write32_mask(rtwdev, R_CFIR_LUT_C1, B_CFIR_LUT_G5, tmp); + } +} + +static void rtw8922a_chlk_reload(struct rtw89_dev *rtwdev) +{ + struct rtw89_rfk_mcc_info *rfk_mcc = &rtwdev->rfk_mcc; + enum rtw89_sub_entity_idx sub_entity_idx; + const struct rtw89_chan *chan; + enum rtw89_entity_mode mode; + u8 s0_tbl, s1_tbl; + u8 tbl_sel; + + mode = rtw89_get_entity_mode(rtwdev); + switch (mode) { + case RTW89_ENTITY_MODE_MCC_PREPARE: + sub_entity_idx = RTW89_SUB_ENTITY_1; + tbl_sel = 1; + break; + default: + sub_entity_idx = RTW89_SUB_ENTITY_0; + tbl_sel = 0; + break; + } + + chan = rtw89_chan_get(rtwdev, sub_entity_idx); + + rfk_mcc->ch[tbl_sel] = chan->channel; + rfk_mcc->band[tbl_sel] = chan->band_type; + rfk_mcc->bw[tbl_sel] = chan->band_width; + rfk_mcc->table_idx = tbl_sel; + + s0_tbl = tbl_sel; + s1_tbl = tbl_sel; + + rtw8922a_chlk_ktbl_sel(rtwdev, RF_A, s0_tbl); + rtw8922a_chlk_ktbl_sel(rtwdev, RF_B, s1_tbl); +} + +static void rtw8922a_rfk_mlo_ctrl(struct rtw89_dev *rtwdev) +{ + enum _rf_syn_pow syn_pow; + + if (!rtwdev->dbcc_en) + goto set_rfk_reload; + + switch (rtwdev->mlo_dbcc_mode) { + case MLO_0_PLUS_2_1RF: + syn_pow = RF_SYN_OFF_ON; + break; + case MLO_0_PLUS_2_2RF: + case MLO_1_PLUS_1_2RF: + case MLO_2_PLUS_0_1RF: + case MLO_2_PLUS_0_2RF: + case MLO_2_PLUS_2_2RF: + case MLO_DBCC_NOT_SUPPORT: + default: + syn_pow = RF_SYN_ON_OFF; + break; + case MLO_1_PLUS_1_1RF: + case DBCC_LEGACY: + syn_pow = RF_SYN_ALLON; + break; + } + + rtw8922a_set_syn01(rtwdev, syn_pow); + +set_rfk_reload: + rtw8922a_chlk_reload(rtwdev); +} + +static void rtw8922a_rfk_pll_init(struct rtw89_dev *rtwdev) +{ + int ret; + u8 tmp; + + ret = rtw89_mac_read_xtal_si(rtwdev, XTAL_SI_PLL_1, &tmp); + if (ret) + return; + ret = rtw89_mac_write_xtal_si(rtwdev, XTAL_SI_PLL_1, tmp | 0xf8, 0xFF); + if (ret) + return; + + ret = rtw89_mac_read_xtal_si(rtwdev, XTAL_SI_APBT, &tmp); + if (ret) + return; + ret = rtw89_mac_write_xtal_si(rtwdev, XTAL_SI_APBT, tmp & ~0x60, 0xFF); + if (ret) + return; + + ret = rtw89_mac_read_xtal_si(rtwdev, XTAL_SI_XTAL_PLL, &tmp); + if (ret) + return; + ret = rtw89_mac_write_xtal_si(rtwdev, XTAL_SI_XTAL_PLL, tmp | 0x38, 0xFF); + if (ret) + return; +} + +void rtw8922a_rfk_hw_init(struct rtw89_dev *rtwdev) +{ + if (rtwdev->dbcc_en) + rtw8922a_rfk_mlo_ctrl(rtwdev); + + rtw8922a_rfk_pll_init(rtwdev); +} diff --git a/drivers/net/wireless/realtek/rtw89/rtw8922a_rfk.h b/drivers/net/wireless/realtek/rtw89/rtw8922a_rfk.h index fbd22de269e2..de5fa6c74530 100644 --- a/drivers/net/wireless/realtek/rtw89/rtw8922a_rfk.h +++ b/drivers/net/wireless/realtek/rtw89/rtw8922a_rfk.h @@ -8,5 +8,6 @@ #include "core.h" void rtw8922a_tssi_cont_en_phyidx(struct rtw89_dev *rtwdev, bool en, u8 phy_idx); +void rtw8922a_rfk_hw_init(struct rtw89_dev *rtwdev); #endif -- cgit v1.2.3 From dedf78efd2885048ca36bc17fbd4e1c0af33f2ad Mon Sep 17 00:00:00 2001 From: Ping-Ke Shih Date: Sun, 4 Feb 2024 09:26:24 +0800 Subject: wifi: rtw89: fw: consider checksum length of security data The newer firmware file provides security data with checksum, so we need to consider the length. Otherwise it will fail to validate total firmware length resulting in failed to probe. Signed-off-by: Ping-Ke Shih Signed-off-by: Kalle Valo Link: https://msgid.link/20240204012627.9647-2-pkshih@realtek.com --- drivers/net/wireless/realtek/rtw89/fw.c | 3 +++ drivers/net/wireless/realtek/rtw89/fw.h | 3 +++ 2 files changed, 6 insertions(+) (limited to 'drivers/net') diff --git a/drivers/net/wireless/realtek/rtw89/fw.c b/drivers/net/wireless/realtek/rtw89/fw.c index c3f0a79f3de4..4a2081131c3e 100644 --- a/drivers/net/wireless/realtek/rtw89/fw.c +++ b/drivers/net/wireless/realtek/rtw89/fw.c @@ -177,6 +177,7 @@ static int rtw89_fw_hdr_parser_v1(struct rtw89_dev *rtwdev, const u8 *fw, u32 le u32 i; info->section_num = le32_get_bits(fw_hdr->w6, FW_HDR_V1_W6_SEC_NUM); + info->dsp_checksum = le32_get_bits(fw_hdr->w6, FW_HDR_V1_W6_DSP_CHKSUM); base_hdr_len = struct_size(fw_hdr, sections, info->section_num); info->dynamic_hdr_en = le32_get_bits(fw_hdr->w7, FW_HDR_V1_W7_DYN_HDR); @@ -205,6 +206,8 @@ static int rtw89_fw_hdr_parser_v1(struct rtw89_dev *rtwdev, const u8 *fw, u32 le section_info->mssc = le32_get_bits(section->w2, FWSECTION_HDR_V1_W2_MSSC); mssc_len += section_info->mssc * FWDL_SECURITY_SIGLEN; + if (info->dsp_checksum) + mssc_len += section_info->mssc * FWDL_SECURITY_CHKSUM_LEN; } else { section_info->mssc = 0; } diff --git a/drivers/net/wireless/realtek/rtw89/fw.h b/drivers/net/wireless/realtek/rtw89/fw.h index 02a7c7b2c8be..b12f93e39d1e 100644 --- a/drivers/net/wireless/realtek/rtw89/fw.h +++ b/drivers/net/wireless/realtek/rtw89/fw.h @@ -237,6 +237,7 @@ struct rtw89_fw_bin_info { u32 hdr_len; bool dynamic_hdr_en; u32 dynamic_hdr_len; + bool dsp_checksum; struct rtw89_fw_hdr_section_info section_info[FWDL_SECTION_MAX_NUM]; }; @@ -466,6 +467,7 @@ static inline void RTW89_SET_EDCA_PARAM(void *cmd, u32 val) #define FWDL_SECURITY_SECTION_TYPE 9 #define FWDL_SECURITY_SIGLEN 512 +#define FWDL_SECURITY_CHKSUM_LEN 8 struct rtw89_fw_dynhdr_sec { __le32 w0; @@ -568,6 +570,7 @@ struct rtw89_fw_hdr_v1 { #define FW_HDR_V1_W5_YEAR GENMASK(15, 0) #define FW_HDR_V1_W5_HDR_SIZE GENMASK(31, 16) #define FW_HDR_V1_W6_SEC_NUM GENMASK(15, 8) +#define FW_HDR_V1_W6_DSP_CHKSUM BIT(24) #define FW_HDR_V1_W7_DYN_HDR BIT(16) static inline void SET_FW_HDR_PART_SIZE(void *fwhdr, u32 val) -- cgit v1.2.3 From 5462b8505f538b00d287a6de9a0fb2be6059bfc4 Mon Sep 17 00:00:00 2001 From: Ping-Ke Shih Date: Sun, 4 Feb 2024 09:26:25 +0800 Subject: wifi: rtw89: fw: read firmware secure information from efuse To support firmware secure boot, read secure information from efuse to know if current hardware module can support secure boot with certain cryptography method. This information should be prepared before downloading firmware, so read efuse right after power on at probe stage. The secure information includes secure cryptography method and secure key index that are used to choose proper key material when downloading firmware. Signed-off-by: Ping-Ke Shih Signed-off-by: Kalle Valo Link: https://msgid.link/20240204012627.9647-3-pkshih@realtek.com --- drivers/net/wireless/realtek/rtw89/core.h | 15 +++ drivers/net/wireless/realtek/rtw89/efuse.h | 1 + drivers/net/wireless/realtek/rtw89/efuse_be.c | 142 ++++++++++++++++++++++++++ drivers/net/wireless/realtek/rtw89/pci.c | 2 + drivers/net/wireless/realtek/rtw89/rtw8922a.c | 3 + 5 files changed, 163 insertions(+) (limited to 'drivers/net') diff --git a/drivers/net/wireless/realtek/rtw89/core.h b/drivers/net/wireless/realtek/rtw89/core.h index 22255e98ab6b..713383b6d818 100644 --- a/drivers/net/wireless/realtek/rtw89/core.h +++ b/drivers/net/wireless/realtek/rtw89/core.h @@ -4033,6 +4033,19 @@ struct rtw89_fw_elm_info { struct rtw89_phy_rfk_log_fmt *rfk_log_fmt; }; +enum rtw89_fw_mss_dev_type { + RTW89_FW_MSS_DEV_TYPE_FWSEC_DEF = 0xF, + RTW89_FW_MSS_DEV_TYPE_FWSEC_INV = 0xFF, +}; + +struct rtw89_fw_secure { + bool secure_boot; + u32 sb_sel_mgn; + u8 mss_dev_type; + u8 mss_cust_idx; + u8 mss_key_num; +}; + struct rtw89_fw_info { struct rtw89_fw_req_info req; int fw_format; @@ -4047,6 +4060,7 @@ struct rtw89_fw_info { struct rtw89_fw_log log; u32 feature_map; struct rtw89_fw_elm_info elm_info; + struct rtw89_fw_secure sec; }; #define RTW89_CHK_FW_FEATURE(_feat, _fw) \ @@ -4199,6 +4213,7 @@ enum rtw89_flags { RTW89_FLAG_CMAC1_FUNC, RTW89_FLAG_FW_RDY, RTW89_FLAG_RUNNING, + RTW89_FLAG_PROBE_DONE, RTW89_FLAG_BFEE_MON, RTW89_FLAG_BFEE_EN, RTW89_FLAG_BFEE_TIMER_KEEP, diff --git a/drivers/net/wireless/realtek/rtw89/efuse.h b/drivers/net/wireless/realtek/rtw89/efuse.h index 5c6787179bad..72416f56a071 100644 --- a/drivers/net/wireless/realtek/rtw89/efuse.h +++ b/drivers/net/wireless/realtek/rtw89/efuse.h @@ -23,5 +23,6 @@ int rtw89_parse_efuse_map_be(struct rtw89_dev *rtwdev); int rtw89_parse_phycap_map_be(struct rtw89_dev *rtwdev); int rtw89_cnv_efuse_state_be(struct rtw89_dev *rtwdev, bool idle); int rtw89_read_efuse_ver(struct rtw89_dev *rtwdev, u8 *efv); +int rtw89_efuse_read_fw_secure_be(struct rtw89_dev *rtwdev); #endif diff --git a/drivers/net/wireless/realtek/rtw89/efuse_be.c b/drivers/net/wireless/realtek/rtw89/efuse_be.c index 8e8b7cd315f7..0be26d5fdf7c 100644 --- a/drivers/net/wireless/realtek/rtw89/efuse_be.c +++ b/drivers/net/wireless/realtek/rtw89/efuse_be.c @@ -7,6 +7,31 @@ #include "mac.h" #include "reg.h" +#define EFUSE_EXTERNALPN_ADDR_BE 0x1580 +#define EFUSE_B1_MSSDEVTYPE_MASK GENMASK(3, 0) +#define EFUSE_B1_MSSCUSTIDX0_MASK GENMASK(7, 4) +#define EFUSE_SERIALNUM_ADDR_BE 0x1581 +#define EFUSE_B2_MSSKEYNUM_MASK GENMASK(3, 0) +#define EFUSE_B2_MSSCUSTIDX1_MASK BIT(6) +#define EFUSE_SB_CRYP_SEL_ADDR 0x1582 +#define EFUSE_SB_CRYP_SEL_SIZE 2 +#define EFUSE_SB_CRYP_SEL_DEFAULT 0xFFFF +#define SB_SEL_MGN_MAX_SIZE 2 +#define EFUSE_SEC_BE_START 0x1580 +#define EFUSE_SEC_BE_SIZE 4 + +enum rtw89_efuse_mss_dev_type { + MSS_DEV_TYPE_FWSEC_DEF = 0xF, + MSS_DEV_TYPE_FWSEC_WINLIN_INBOX = 0xC, + MSS_DEV_TYPE_FWSEC_NONLIN_INBOX_NON_COB = 0xA, + MSS_DEV_TYPE_FWSEC_NONLIN_INBOX_COB = 0x9, + MSS_DEV_TYPE_FWSEC_NONWIN_INBOX = 0x6, +}; + +static const u32 sb_sel_mgn[SB_SEL_MGN_MAX_SIZE] = { + 0x8000100, 0xC000180 +}; + static void rtw89_enable_efuse_pwr_cut_ddv_be(struct rtw89_dev *rtwdev) { const struct rtw89_chip_info *chip = rtwdev->chip; @@ -418,3 +443,120 @@ out_free: return ret; } + +static u16 get_sb_cryp_sel_idx(u16 sb_cryp_sel) +{ + u8 low_bit, high_bit, cnt_zero = 0; + u8 idx, sel_form_v, sel_idx_v; + u16 sb_cryp_sel_v = 0x0; + + sel_form_v = u16_get_bits(sb_cryp_sel, MASKBYTE0); + sel_idx_v = u16_get_bits(sb_cryp_sel, MASKBYTE1); + + for (idx = 0; idx < 4; idx++) { + low_bit = !!(sel_form_v & BIT(idx)); + high_bit = !!(sel_form_v & BIT(7 - idx)); + if (low_bit != high_bit) + return U16_MAX; + if (low_bit) + continue; + + cnt_zero++; + if (cnt_zero == 1) + sb_cryp_sel_v = idx * 16; + else if (cnt_zero > 1) + return U16_MAX; + } + + low_bit = u8_get_bits(sel_idx_v, 0x0F); + high_bit = u8_get_bits(sel_idx_v, 0xF0); + + if ((low_bit ^ high_bit) != 0xF) + return U16_MAX; + + return sb_cryp_sel_v + low_bit; +} + +static u8 get_mss_dev_type_idx(struct rtw89_dev *rtwdev, u8 mss_dev_type) +{ + switch (mss_dev_type) { + case MSS_DEV_TYPE_FWSEC_WINLIN_INBOX: + mss_dev_type = 0x0; + break; + case MSS_DEV_TYPE_FWSEC_NONLIN_INBOX_NON_COB: + mss_dev_type = 0x1; + break; + case MSS_DEV_TYPE_FWSEC_NONLIN_INBOX_COB: + mss_dev_type = 0x2; + break; + case MSS_DEV_TYPE_FWSEC_NONWIN_INBOX: + mss_dev_type = 0x3; + break; + case MSS_DEV_TYPE_FWSEC_DEF: + mss_dev_type = RTW89_FW_MSS_DEV_TYPE_FWSEC_DEF; + break; + default: + rtw89_warn(rtwdev, "unknown mss_dev_type %d", mss_dev_type); + mss_dev_type = RTW89_FW_MSS_DEV_TYPE_FWSEC_INV; + break; + } + + return mss_dev_type; +} + +int rtw89_efuse_read_fw_secure_be(struct rtw89_dev *rtwdev) +{ + struct rtw89_fw_secure *sec = &rtwdev->fw.sec; + u32 sec_addr = EFUSE_SEC_BE_START; + u32 sec_size = EFUSE_SEC_BE_SIZE; + u16 sb_cryp_sel, sb_cryp_sel_idx; + u8 sec_map[EFUSE_SEC_BE_SIZE]; + u8 mss_dev_type; + u8 b1, b2; + int ret; + + ret = rtw89_dump_physical_efuse_map_be(rtwdev, sec_map, + sec_addr, sec_size, false); + if (ret) { + rtw89_warn(rtwdev, "failed to dump secsel map\n"); + return ret; + } + + sb_cryp_sel = sec_map[EFUSE_SB_CRYP_SEL_ADDR - sec_addr] | + sec_map[EFUSE_SB_CRYP_SEL_ADDR - sec_addr + 1] << 8; + if (sb_cryp_sel == EFUSE_SB_CRYP_SEL_DEFAULT) + goto out; + + sb_cryp_sel_idx = get_sb_cryp_sel_idx(sb_cryp_sel); + if (sb_cryp_sel_idx >= SB_SEL_MGN_MAX_SIZE) { + rtw89_warn(rtwdev, "invalid SB cryp sel idx %d\n", sb_cryp_sel_idx); + goto out; + } + + sec->sb_sel_mgn = sb_sel_mgn[sb_cryp_sel_idx]; + + b1 = sec_map[EFUSE_EXTERNALPN_ADDR_BE - sec_addr]; + b2 = sec_map[EFUSE_SERIALNUM_ADDR_BE - sec_addr]; + + mss_dev_type = u8_get_bits(b1, EFUSE_B1_MSSDEVTYPE_MASK); + sec->mss_cust_idx = 0x1F - (u8_get_bits(b1, EFUSE_B1_MSSCUSTIDX0_MASK) | + u8_get_bits(b2, EFUSE_B2_MSSCUSTIDX1_MASK) << 4); + sec->mss_key_num = 0xF - u8_get_bits(b2, EFUSE_B2_MSSKEYNUM_MASK); + + sec->mss_dev_type = get_mss_dev_type_idx(rtwdev, mss_dev_type); + if (sec->mss_dev_type == RTW89_FW_MSS_DEV_TYPE_FWSEC_INV) { + rtw89_warn(rtwdev, "invalid mss_dev_type %d\n", mss_dev_type); + goto out; + } + + sec->secure_boot = true; + +out: + rtw89_debug(rtwdev, RTW89_DBG_FW, + "MSS secure_boot=%d dev_type=%d cust_idx=%d key_num=%d\n", + sec->secure_boot, sec->mss_dev_type, sec->mss_cust_idx, + sec->mss_key_num); + + return 0; +} +EXPORT_SYMBOL(rtw89_efuse_read_fw_secure_be); diff --git a/drivers/net/wireless/realtek/rtw89/pci.c b/drivers/net/wireless/realtek/rtw89/pci.c index b51ec3cbc715..67d7294e488a 100644 --- a/drivers/net/wireless/realtek/rtw89/pci.c +++ b/drivers/net/wireless/realtek/rtw89/pci.c @@ -4180,6 +4180,8 @@ int rtw89_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id) goto err_free_irq; } + set_bit(RTW89_FLAG_PROBE_DONE, rtwdev->flags); + return 0; err_free_irq: diff --git a/drivers/net/wireless/realtek/rtw89/rtw8922a.c b/drivers/net/wireless/realtek/rtw89/rtw8922a.c index 6dc051934b0f..02ec4d27011f 100644 --- a/drivers/net/wireless/realtek/rtw89/rtw8922a.c +++ b/drivers/net/wireless/realtek/rtw89/rtw8922a.c @@ -377,6 +377,9 @@ static int rtw8922a_pwr_on_func(struct rtw89_dev *rtwdev) rtw89_write32_set(rtwdev, R_BE_FEN_RST_ENABLE, B_BE_FEN_BB_IP_RSTN | B_BE_FEN_BBPLAT_RSTB); + if (!test_bit(RTW89_FLAG_PROBE_DONE, rtwdev->flags)) + rtw89_efuse_read_fw_secure_be(rtwdev); + return 0; } -- cgit v1.2.3 From 12ff5e1cca33b32fae0b183203f5b58a610e137e Mon Sep 17 00:00:00 2001 From: Ping-Ke Shih Date: Sun, 4 Feb 2024 09:26:26 +0800 Subject: wifi: rtw89: fw: parse secure section from firmware file A firmware file can contains more than one section with secure type, so use secure information from efuse to choose the one with matched cryptography method. Then choose key data from MSS poll (multiple security section pool; see below picture) according to key_index from efuse. Note that the size of MSS pool isn't included in section size defined in firmware header, so we also need to parse header of MSS pool to get its size as shift to parse next section. If secure boot isn't supported by current hardware, the first secure section will be adopted, and no need additional process to key data. +---------------------------+ | firmware header | | | | +-----------------------+ | | | section type/size * N-|-|-------+ | | ... | | | | +-----------------------+ | | +---------------------------+ | : : | +---------------------------+ -\ | | secure section type (ID:9)| | | | | | <--+ | | | +---------------------------+ -/ |MSS Pool for above section | | | | | +---------------------------+ Signed-off-by: Ping-Ke Shih Signed-off-by: Kalle Valo Link: https://msgid.link/20240204012627.9647-4-pkshih@realtek.com --- drivers/net/wireless/realtek/rtw89/fw.c | 202 +++++++++++++++++++++++++++++--- drivers/net/wireless/realtek/rtw89/fw.h | 39 ++++++ 2 files changed, 227 insertions(+), 14 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/realtek/rtw89/fw.c b/drivers/net/wireless/realtek/rtw89/fw.c index 4a2081131c3e..00a6cb7fcd2a 100644 --- a/drivers/net/wireless/realtek/rtw89/fw.c +++ b/drivers/net/wireless/realtek/rtw89/fw.c @@ -13,6 +13,8 @@ #include "reg.h" #include "util.h" +static const u8 mss_signature[] = {0x4D, 0x53, 0x53, 0x4B, 0x50, 0x4F, 0x4F, 0x4C}; + union rtw89_fw_element_arg { size_t offset; enum rtw89_rf_path rf_path; @@ -163,6 +165,161 @@ static int rtw89_fw_hdr_parser_v0(struct rtw89_dev *rtwdev, const u8 *fw, u32 le return 0; } +static int __get_mssc_key_idx(struct rtw89_dev *rtwdev, + const struct rtw89_fw_mss_pool_hdr *mss_hdr, + u32 rmp_tbl_size, u32 *key_idx) +{ + struct rtw89_fw_secure *sec = &rtwdev->fw.sec; + u32 sel_byte_idx; + u32 mss_sel_idx; + u8 sel_bit_idx; + int i; + + if (sec->mss_dev_type == RTW89_FW_MSS_DEV_TYPE_FWSEC_DEF) { + if (!mss_hdr->defen) + return -ENOENT; + + mss_sel_idx = sec->mss_cust_idx * le16_to_cpu(mss_hdr->msskey_num_max) + + sec->mss_key_num; + } else { + if (mss_hdr->defen) + mss_sel_idx = FWDL_MSS_POOL_DEFKEYSETS_SIZE << 3; + else + mss_sel_idx = 0; + mss_sel_idx += sec->mss_dev_type * le16_to_cpu(mss_hdr->msskey_num_max) * + le16_to_cpu(mss_hdr->msscust_max) + + sec->mss_cust_idx * le16_to_cpu(mss_hdr->msskey_num_max) + + sec->mss_key_num; + } + + sel_byte_idx = mss_sel_idx >> 3; + sel_bit_idx = mss_sel_idx & 0x7; + + if (sel_byte_idx >= rmp_tbl_size) + return -EFAULT; + + if (!(mss_hdr->rmp_tbl[sel_byte_idx] & BIT(sel_bit_idx))) + return -ENOENT; + + *key_idx = hweight8(mss_hdr->rmp_tbl[sel_byte_idx] & (BIT(sel_bit_idx) - 1)); + + for (i = 0; i < sel_byte_idx; i++) + *key_idx += hweight8(mss_hdr->rmp_tbl[i]); + + return 0; +} + +static int __parse_formatted_mssc(struct rtw89_dev *rtwdev, + struct rtw89_fw_bin_info *info, + struct rtw89_fw_hdr_section_info *section_info, + const struct rtw89_fw_hdr_section_v1 *section, + const void *content, + u32 *mssc_len) +{ + const struct rtw89_fw_mss_pool_hdr *mss_hdr = content + section_info->len; + const union rtw89_fw_section_mssc_content *section_content = content; + struct rtw89_fw_secure *sec = &rtwdev->fw.sec; + u32 rmp_tbl_size; + u32 key_sign_len; + u32 real_key_idx; + u32 sb_sel_ver; + int ret; + + if (memcmp(mss_signature, mss_hdr->signature, sizeof(mss_signature)) != 0) { + rtw89_err(rtwdev, "[ERR] wrong MSS signature\n"); + return -ENOENT; + } + + if (mss_hdr->rmpfmt == MSS_POOL_RMP_TBL_BITMASK) { + rmp_tbl_size = (le16_to_cpu(mss_hdr->msskey_num_max) * + le16_to_cpu(mss_hdr->msscust_max) * + mss_hdr->mssdev_max) >> 3; + if (mss_hdr->defen) + rmp_tbl_size += FWDL_MSS_POOL_DEFKEYSETS_SIZE; + } else { + rtw89_err(rtwdev, "[ERR] MSS Key Pool Remap Table Format Unsupport:%X\n", + mss_hdr->rmpfmt); + return -EINVAL; + } + + if (rmp_tbl_size + sizeof(*mss_hdr) != le32_to_cpu(mss_hdr->key_raw_offset)) { + rtw89_err(rtwdev, "[ERR] MSS Key Pool Format Error:0x%X + 0x%X != 0x%X\n", + rmp_tbl_size, (int)sizeof(*mss_hdr), + le32_to_cpu(mss_hdr->key_raw_offset)); + return -EINVAL; + } + + key_sign_len = le16_to_cpu(section_content->key_sign_len.v) >> 2; + if (!key_sign_len) + key_sign_len = 512; + + if (info->dsp_checksum) + key_sign_len += FWDL_SECURITY_CHKSUM_LEN; + + *mssc_len = sizeof(*mss_hdr) + rmp_tbl_size + + le16_to_cpu(mss_hdr->keypair_num) * key_sign_len; + + if (!sec->secure_boot) + goto out; + + sb_sel_ver = le32_to_cpu(section_content->sb_sel_ver.v); + if (sb_sel_ver && sb_sel_ver != sec->sb_sel_mgn) + goto ignore; + + ret = __get_mssc_key_idx(rtwdev, mss_hdr, rmp_tbl_size, &real_key_idx); + if (ret) + goto ignore; + + section_info->key_addr = content + section_info->len + + le32_to_cpu(mss_hdr->key_raw_offset) + + key_sign_len * real_key_idx; + section_info->key_len = key_sign_len; + section_info->key_idx = real_key_idx; + +out: + if (info->secure_section_exist) { + section_info->ignore = true; + return 0; + } + + info->secure_section_exist = true; + + return 0; + +ignore: + section_info->ignore = true; + + return 0; +} + +static int __parse_security_section(struct rtw89_dev *rtwdev, + struct rtw89_fw_bin_info *info, + struct rtw89_fw_hdr_section_info *section_info, + const struct rtw89_fw_hdr_section_v1 *section, + const void *content, + u32 *mssc_len) +{ + int ret; + + section_info->mssc = + le32_get_bits(section->w2, FWSECTION_HDR_V1_W2_MSSC); + + if (section_info->mssc == FORMATTED_MSSC) { + ret = __parse_formatted_mssc(rtwdev, info, section_info, + section, content, mssc_len); + if (ret) + return -EINVAL; + } else { + *mssc_len = section_info->mssc * FWDL_SECURITY_SIGLEN; + if (info->dsp_checksum) + *mssc_len += section_info->mssc * FWDL_SECURITY_CHKSUM_LEN; + + info->secure_section_exist = true; + } + + return 0; +} + static int rtw89_fw_hdr_parser_v1(struct rtw89_dev *rtwdev, const u8 *fw, u32 len, struct rtw89_fw_bin_info *info) { @@ -173,7 +330,8 @@ static int rtw89_fw_hdr_parser_v1(struct rtw89_dev *rtwdev, const u8 *fw, u32 le const u8 *fw_end = fw + len; const u8 *bin; u32 base_hdr_len; - u32 mssc_len = 0; + u32 mssc_len; + int ret; u32 i; info->section_num = le32_get_bits(fw_hdr->w6, FW_HDR_V1_W6_SEC_NUM); @@ -200,18 +358,9 @@ static int rtw89_fw_hdr_parser_v1(struct rtw89_dev *rtwdev, const u8 *fw, u32 le section_info = info->section_info; for (i = 0; i < info->section_num; i++) { section = &fw_hdr->sections[i]; + section_info->type = le32_get_bits(section->w1, FWSECTION_HDR_V1_W1_SECTIONTYPE); - if (section_info->type == FWDL_SECURITY_SECTION_TYPE) { - section_info->mssc = - le32_get_bits(section->w2, FWSECTION_HDR_V1_W2_MSSC); - mssc_len += section_info->mssc * FWDL_SECURITY_SIGLEN; - if (info->dsp_checksum) - mssc_len += section_info->mssc * FWDL_SECURITY_CHKSUM_LEN; - } else { - section_info->mssc = 0; - } - section_info->len = le32_get_bits(section->w1, FWSECTION_HDR_V1_W1_SEC_SIZE); if (le32_get_bits(section->w1, FWSECTION_HDR_V1_W1_CHECKSUM)) @@ -220,15 +369,40 @@ static int rtw89_fw_hdr_parser_v1(struct rtw89_dev *rtwdev, const u8 *fw, u32 le section_info->dladdr = le32_get_bits(section->w0, FWSECTION_HDR_V1_W0_DL_ADDR); section_info->addr = bin; - bin += section_info->len; + + if (section_info->type == FWDL_SECURITY_SECTION_TYPE) { + ret = __parse_security_section(rtwdev, info, section_info, + section, bin, &mssc_len); + if (ret) + return ret; + } else { + section_info->mssc = 0; + mssc_len = 0; + } + + rtw89_debug(rtwdev, RTW89_DBG_FW, + "section[%d] type=%d len=0x%-6x mssc=%d mssc_len=%d addr=%tx\n", + i, section_info->type, section_info->len, + section_info->mssc, mssc_len, bin - fw); + rtw89_debug(rtwdev, RTW89_DBG_FW, + " ignore=%d key_addr=%p (0x%tx) key_len=%d key_idx=%d\n", + section_info->ignore, section_info->key_addr, + section_info->key_addr ? + section_info->key_addr - section_info->addr : 0, + section_info->key_len, section_info->key_idx); + + bin += section_info->len + mssc_len; section_info++; } - if (fw_end != bin + mssc_len) { + if (fw_end != bin) { rtw89_err(rtwdev, "[ERR]fw bin size\n"); return -EINVAL; } + if (!info->secure_section_exist) + rtw89_warn(rtwdev, "no firmware secure section\n"); + return 0; } @@ -1106,7 +1280,7 @@ static int rtw89_fw_download_suit(struct rtw89_dev *rtwdev, struct rtw89_fw_suit *fw_suit) { const struct rtw89_mac_gen_def *mac = rtwdev->chip->mac_def; - struct rtw89_fw_bin_info info; + struct rtw89_fw_bin_info info = {}; int ret; ret = rtw89_fw_hdr_parser(rtwdev, fw_suit, &info); diff --git a/drivers/net/wireless/realtek/rtw89/fw.h b/drivers/net/wireless/realtek/rtw89/fw.h index b12f93e39d1e..58dbaf7a11e7 100644 --- a/drivers/net/wireless/realtek/rtw89/fw.h +++ b/drivers/net/wireless/realtek/rtw89/fw.h @@ -230,6 +230,10 @@ struct rtw89_fw_hdr_section_info { u32 dladdr; u32 mssc; u8 type; + bool ignore; + const u8 *key_addr; + u32 key_len; + u32 key_idx; }; struct rtw89_fw_bin_info { @@ -238,6 +242,7 @@ struct rtw89_fw_bin_info { bool dynamic_hdr_en; u32 dynamic_hdr_len; bool dsp_checksum; + bool secure_section_exist; struct rtw89_fw_hdr_section_info section_info[FWDL_SECTION_MAX_NUM]; }; @@ -538,6 +543,7 @@ struct rtw89_fw_hdr_section_v1 { #define FWSECTION_HDR_V1_W1_CHECKSUM BIT(28) #define FWSECTION_HDR_V1_W1_REDL BIT(29) #define FWSECTION_HDR_V1_W2_MSSC GENMASK(7, 0) +#define FORMATTED_MSSC 0xFF #define FWSECTION_HDR_V1_W2_BBMCU_IDX GENMASK(27, 24) struct rtw89_fw_hdr_v1 { @@ -578,6 +584,39 @@ static inline void SET_FW_HDR_PART_SIZE(void *fwhdr, u32 val) le32p_replace_bits((__le32 *)fwhdr + 7, val, GENMASK(15, 0)); } +enum rtw89_fw_mss_pool_rmp_tbl_type { + MSS_POOL_RMP_TBL_BITMASK = 0x0, + MSS_POOL_RMP_TBL_RECORD = 0x1, +}; + +#define FWDL_MSS_POOL_DEFKEYSETS_SIZE 8 + +struct rtw89_fw_mss_pool_hdr { + u8 signature[8]; /* equal to mss_signature[] */ + __le32 rmp_tbl_offset; + __le32 key_raw_offset; + u8 defen; + u8 rsvd[3]; + u8 rmpfmt; /* enum rtw89_fw_mss_pool_rmp_tbl_type */ + u8 mssdev_max; + __le16 keypair_num; + __le16 msscust_max; + __le16 msskey_num_max; + __le32 rsvd3; + u8 rmp_tbl[]; +} __packed; + +union rtw89_fw_section_mssc_content { + struct { + u8 pad[58]; + __le32 v; + } __packed sb_sel_ver; + struct { + u8 pad[60]; + __le16 v; + } __packed key_sign_len; +} __packed; + static inline void SET_CTRL_INFO_MACID(void *table, u32 val) { le32p_replace_bits((__le32 *)(table) + 0, val, GENMASK(6, 0)); -- cgit v1.2.3 From 43f8a4dc40a70b3598dd0aae401dddaf63ca0d5b Mon Sep 17 00:00:00 2001 From: Ping-Ke Shih Date: Sun, 4 Feb 2024 09:26:27 +0800 Subject: wifi: rtw89: fw: download firmware with key data for secure boot Since firmware header contains multiple secure sections, we need to trim ignored sections, and then download firmware header with single one secure section. For secure boot, when downloading secure section, copy security key data from MSS poll by key_idx read from efuse. If non-secure boot, no need this extra copy. +---------------------------+ -\ | firmware header | | | | | | +-----------------------+ | | only preserve single one secure | | section type/size * N | | | section | | ... | | | | +-----------------------+ | | +---------------------------+ -/ : : +---------------------------+ -\ | secure section type (ID:9)| | | | | +----|-> [ security key data ] | | | +---------------------------+ -/ | |MSS Pool for above section | | | [ security key data 0 ] | +----|- [ security key data 1 ] | by key_idx | [ security key data 2 ] | | ... | +---------------------------+ Signed-off-by: Ping-Ke Shih Signed-off-by: Kalle Valo Link: https://msgid.link/20240204012627.9647-5-pkshih@realtek.com --- drivers/net/wireless/realtek/rtw89/fw.c | 95 ++++++++++++++++++++++++++++++--- drivers/net/wireless/realtek/rtw89/fw.h | 7 +-- 2 files changed, 91 insertions(+), 11 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/realtek/rtw89/fw.c b/drivers/net/wireless/realtek/rtw89/fw.c index 00a6cb7fcd2a..51072a2dcf10 100644 --- a/drivers/net/wireless/realtek/rtw89/fw.c +++ b/drivers/net/wireless/realtek/rtw89/fw.c @@ -1098,9 +1098,56 @@ static void rtw89_h2c_pkt_set_hdr_fwdl(struct rtw89_dev *rtwdev, len + H2C_HEADER_LEN)); } -static int __rtw89_fw_download_hdr(struct rtw89_dev *rtwdev, const u8 *fw, u32 len) +static u32 __rtw89_fw_download_tweak_hdr_v0(struct rtw89_dev *rtwdev, + struct rtw89_fw_bin_info *info, + struct rtw89_fw_hdr *fw_hdr) { + le32p_replace_bits(&fw_hdr->w7, FWDL_SECTION_PER_PKT_LEN, + FW_HDR_W7_PART_SIZE); + + return 0; +} + +static u32 __rtw89_fw_download_tweak_hdr_v1(struct rtw89_dev *rtwdev, + struct rtw89_fw_bin_info *info, + struct rtw89_fw_hdr_v1 *fw_hdr) +{ + struct rtw89_fw_hdr_section_info *section_info; + struct rtw89_fw_hdr_section_v1 *section; + u8 dst_sec_idx = 0; + u8 sec_idx; + + le32p_replace_bits(&fw_hdr->w7, FWDL_SECTION_PER_PKT_LEN, + FW_HDR_V1_W7_PART_SIZE); + + for (sec_idx = 0; sec_idx < info->section_num; sec_idx++) { + section_info = &info->section_info[sec_idx]; + section = &fw_hdr->sections[sec_idx]; + + if (section_info->ignore) + continue; + + if (dst_sec_idx != sec_idx) + fw_hdr->sections[dst_sec_idx] = *section; + + dst_sec_idx++; + } + + le32p_replace_bits(&fw_hdr->w6, dst_sec_idx, FW_HDR_V1_W6_SEC_NUM); + + return (info->section_num - dst_sec_idx) * sizeof(*section); +} + +static int __rtw89_fw_download_hdr(struct rtw89_dev *rtwdev, + const struct rtw89_fw_suit *fw_suit, + struct rtw89_fw_bin_info *info) +{ + u32 len = info->hdr_len - info->dynamic_hdr_len; + struct rtw89_fw_hdr_v1 *fw_hdr_v1; + const u8 *fw = fw_suit->data; + struct rtw89_fw_hdr *fw_hdr; struct sk_buff *skb; + u32 truncated; u32 ret = 0; skb = rtw89_fw_h2c_alloc_skb_with_hdr(rtwdev, len); @@ -1110,7 +1157,26 @@ static int __rtw89_fw_download_hdr(struct rtw89_dev *rtwdev, const u8 *fw, u32 l } skb_put_data(skb, fw, len); - SET_FW_HDR_PART_SIZE(skb->data, FWDL_SECTION_PER_PKT_LEN); + + switch (fw_suit->hdr_ver) { + case 0: + fw_hdr = (struct rtw89_fw_hdr *)skb->data; + truncated = __rtw89_fw_download_tweak_hdr_v0(rtwdev, info, fw_hdr); + break; + case 1: + fw_hdr_v1 = (struct rtw89_fw_hdr_v1 *)skb->data; + truncated = __rtw89_fw_download_tweak_hdr_v1(rtwdev, info, fw_hdr_v1); + break; + default: + ret = -EOPNOTSUPP; + goto fail; + } + + if (truncated) { + len -= truncated; + skb_trim(skb, len); + } + rtw89_h2c_pkt_set_hdr_fwdl(rtwdev, skb, FWCMD_TYPE_H2C, H2C_CAT_MAC, H2C_CL_MAC_FWDL, H2C_FUNC_MAC_FWHDR_DL, len); @@ -1129,12 +1195,14 @@ fail: return ret; } -static int rtw89_fw_download_hdr(struct rtw89_dev *rtwdev, const u8 *fw, u32 len) +static int rtw89_fw_download_hdr(struct rtw89_dev *rtwdev, + const struct rtw89_fw_suit *fw_suit, + struct rtw89_fw_bin_info *info) { const struct rtw89_mac_gen_def *mac = rtwdev->chip->mac_def; int ret; - ret = __rtw89_fw_download_hdr(rtwdev, fw, len); + ret = __rtw89_fw_download_hdr(rtwdev, fw_suit, info); if (ret) { rtw89_err(rtwdev, "[ERR]FW header download\n"); return ret; @@ -1158,9 +1226,21 @@ static int __rtw89_fw_download_main(struct rtw89_dev *rtwdev, struct sk_buff *skb; const u8 *section = info->addr; u32 residue_len = info->len; + bool copy_key = false; u32 pkt_len; int ret; + if (info->ignore) + return 0; + + if (info->key_addr && info->key_len) { + if (info->len > FWDL_SECTION_PER_PKT_LEN || info->len < info->key_len) + rtw89_warn(rtwdev, "ignore to copy key data because of len %d, %d, %d\n", + info->len, FWDL_SECTION_PER_PKT_LEN, info->key_len); + else + copy_key = true; + } + while (residue_len) { if (residue_len >= FWDL_SECTION_PER_PKT_LEN) pkt_len = FWDL_SECTION_PER_PKT_LEN; @@ -1174,6 +1254,10 @@ static int __rtw89_fw_download_main(struct rtw89_dev *rtwdev, } skb_put_data(skb, section, pkt_len); + if (copy_key) + memcpy(skb->data + pkt_len - info->key_len, + info->key_addr, info->key_len); + ret = rtw89_h2c_tx(rtwdev, skb, true); if (ret) { rtw89_err(rtwdev, "failed to send h2c\n"); @@ -1299,8 +1383,7 @@ static int rtw89_fw_download_suit(struct rtw89_dev *rtwdev, return ret; } - ret = rtw89_fw_download_hdr(rtwdev, fw_suit->data, info.hdr_len - - info.dynamic_hdr_len); + ret = rtw89_fw_download_hdr(rtwdev, fw_suit, &info); if (ret) return ret; diff --git a/drivers/net/wireless/realtek/rtw89/fw.h b/drivers/net/wireless/realtek/rtw89/fw.h index 58dbaf7a11e7..5609e5f7d7eb 100644 --- a/drivers/net/wireless/realtek/rtw89/fw.h +++ b/drivers/net/wireless/realtek/rtw89/fw.h @@ -526,6 +526,7 @@ struct rtw89_fw_hdr { #define FW_HDR_W4_MIN GENMASK(31, 24) #define FW_HDR_W5_YEAR GENMASK(31, 0) #define FW_HDR_W6_SEC_NUM GENMASK(15, 8) +#define FW_HDR_W7_PART_SIZE GENMASK(15, 0) #define FW_HDR_W7_DYN_HDR BIT(16) #define FW_HDR_W7_CMD_VERSERION GENMASK(31, 24) @@ -577,13 +578,9 @@ struct rtw89_fw_hdr_v1 { #define FW_HDR_V1_W5_HDR_SIZE GENMASK(31, 16) #define FW_HDR_V1_W6_SEC_NUM GENMASK(15, 8) #define FW_HDR_V1_W6_DSP_CHKSUM BIT(24) +#define FW_HDR_V1_W7_PART_SIZE GENMASK(15, 0) #define FW_HDR_V1_W7_DYN_HDR BIT(16) -static inline void SET_FW_HDR_PART_SIZE(void *fwhdr, u32 val) -{ - le32p_replace_bits((__le32 *)fwhdr + 7, val, GENMASK(15, 0)); -} - enum rtw89_fw_mss_pool_rmp_tbl_type { MSS_POOL_RMP_TBL_BITMASK = 0x0, MSS_POOL_RMP_TBL_RECORD = 0x1, -- cgit v1.2.3 From b8cfb7c819dd39965136a66fe3a7fde688d976fc Mon Sep 17 00:00:00 2001 From: Jérôme Pouiller Date: Fri, 2 Feb 2024 17:42:13 +0100 Subject: wifi: wfx: fix memory leak when starting AP MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Kmemleak reported this error: unreferenced object 0xd73d1180 (size 184): comm "wpa_supplicant", pid 1559, jiffies 13006305 (age 964.245s) hex dump (first 32 bytes): 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ 00 00 00 00 00 00 00 00 1e 00 01 00 00 00 00 00 ................ backtrace: [<5ca11420>] kmem_cache_alloc+0x20c/0x5ac [<127bdd74>] __alloc_skb+0x144/0x170 [] __netdev_alloc_skb+0x50/0x180 [<0f9fa1d5>] __ieee80211_beacon_get+0x290/0x4d4 [mac80211] [<7accd02d>] ieee80211_beacon_get_tim+0x54/0x18c [mac80211] [<41e25cc3>] wfx_start_ap+0xc8/0x234 [wfx] [<93a70356>] ieee80211_start_ap+0x404/0x6b4 [mac80211] [] nl80211_start_ap+0x76c/0x9e0 [cfg80211] [<47bd8b68>] genl_rcv_msg+0x198/0x378 [<453ef796>] netlink_rcv_skb+0xd0/0x130 [<6b7c977a>] genl_rcv+0x34/0x44 [<66b2d04d>] netlink_unicast+0x1b4/0x258 [] netlink_sendmsg+0x1e8/0x428 [] ____sys_sendmsg+0x1e0/0x274 [] ___sys_sendmsg+0x80/0xb4 [<69954f45>] __sys_sendmsg+0x64/0xa8 unreferenced object 0xce087000 (size 1024): comm "wpa_supplicant", pid 1559, jiffies 13006305 (age 964.246s) hex dump (first 32 bytes): 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ 10 00 07 40 00 00 00 00 00 00 00 00 00 00 00 00 ...@............ backtrace: [<9a993714>] __kmalloc_track_caller+0x230/0x600 [] kmalloc_reserve.constprop.0+0x30/0x74 [] __alloc_skb+0xa0/0x170 [] __netdev_alloc_skb+0x50/0x180 [<0f9fa1d5>] __ieee80211_beacon_get+0x290/0x4d4 [mac80211] [<7accd02d>] ieee80211_beacon_get_tim+0x54/0x18c [mac80211] [<41e25cc3>] wfx_start_ap+0xc8/0x234 [wfx] [<93a70356>] ieee80211_start_ap+0x404/0x6b4 [mac80211] [] nl80211_start_ap+0x76c/0x9e0 [cfg80211] [<47bd8b68>] genl_rcv_msg+0x198/0x378 [<453ef796>] netlink_rcv_skb+0xd0/0x130 [<6b7c977a>] genl_rcv+0x34/0x44 [<66b2d04d>] netlink_unicast+0x1b4/0x258 [] netlink_sendmsg+0x1e8/0x428 [] ____sys_sendmsg+0x1e0/0x274 [] ___sys_sendmsg+0x80/0xb4 However, since the kernel is build optimized, it seems the stack is not accurate. It appears the issue is related to wfx_set_mfp_ap(). The issue is obvious in this function: memory allocated by ieee80211_beacon_get() is never released. Fixing this leak makes kmemleak happy. Reported-by: Ulrich Mohr Co-developed-by: Ulrich Mohr Signed-off-by: Ulrich Mohr Fixes: 268bceec1684 ("staging: wfx: fix BA when device is AP and MFP is enabled") Signed-off-by: Jérôme Pouiller Signed-off-by: Kalle Valo Link: https://msgid.link/20240202164213.1606145-1-jerome.pouiller@silabs.com --- drivers/net/wireless/silabs/wfx/sta.c | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/silabs/wfx/sta.c b/drivers/net/wireless/silabs/wfx/sta.c index 537caf9d914a..bb4446b88c12 100644 --- a/drivers/net/wireless/silabs/wfx/sta.c +++ b/drivers/net/wireless/silabs/wfx/sta.c @@ -344,6 +344,7 @@ static int wfx_set_mfp_ap(struct wfx_vif *wvif) const int pairwise_cipher_suite_count_offset = 8 / sizeof(u16); const int pairwise_cipher_suite_size = 4 / sizeof(u16); const int akm_suite_size = 4 / sizeof(u16); + int ret = -EINVAL; const u16 *ptr; if (unlikely(!skb)) @@ -352,22 +353,26 @@ static int wfx_set_mfp_ap(struct wfx_vif *wvif) ptr = (u16 *)cfg80211_find_ie(WLAN_EID_RSN, skb->data + ieoffset, skb->len - ieoffset); if (unlikely(!ptr)) - return -EINVAL; + goto free_skb; ptr += pairwise_cipher_suite_count_offset; if (WARN_ON(ptr > (u16 *)skb_tail_pointer(skb))) - return -EINVAL; + goto free_skb; ptr += 1 + pairwise_cipher_suite_size * *ptr; if (WARN_ON(ptr > (u16 *)skb_tail_pointer(skb))) - return -EINVAL; + goto free_skb; ptr += 1 + akm_suite_size * *ptr; if (WARN_ON(ptr > (u16 *)skb_tail_pointer(skb))) - return -EINVAL; + goto free_skb; wfx_hif_set_mfp(wvif, *ptr & BIT(7), *ptr & BIT(6)); - return 0; + ret = 0; + +free_skb: + dev_kfree_skb(skb); + return ret; } int wfx_start_ap(struct ieee80211_hw *hw, struct ieee80211_vif *vif, -- cgit v1.2.3 From 94dd7ce1885e530a7b10bbe50d5d68ba1bb99e6e Mon Sep 17 00:00:00 2001 From: Martin Kaistra Date: Mon, 5 Feb 2024 10:30:40 +0100 Subject: wifi: rtl8xxxu: update rate mask per sta Until now, rtl8xxxu_watchdog_callback() only fetches RSSI and updates the rate mask in station mode. This means, in AP mode only the default rate mask is used. In order to have the rate mask reflect the actual connection quality, extend rtl8xxxu_watchdog_callback() to iterate over every sta. Like in the rtw88 driver, add a function to collect all currently present stas and then iterate over a list of copies to ensure no RCU lock problems for register access via USB. Remove the existing RCU lock in rtl8xxxu_refresh_rate_mask(). Since the currently used ieee80211_ave_rssi() is only for 'vif', add driver-level tracking of RSSI per sta. Signed-off-by: Martin Kaistra Reviewed-by: Ping-Ke Shih Signed-off-by: Kalle Valo Link: https://msgid.link/20240205093040.1941140-1-martin.kaistra@linutronix.de --- drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.h | 8 +- .../net/wireless/realtek/rtl8xxxu/rtl8xxxu_core.c | 188 +++++++++++++++++---- 2 files changed, 158 insertions(+), 38 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.h b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.h index 03307da67c2c..fd92d23c43d9 100644 --- a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.h +++ b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.h @@ -6,6 +6,7 @@ */ #include +#include #define RTL8XXXU_DEBUG_REG_WRITE 0x01 #define RTL8XXXU_DEBUG_REG_READ 0x02 @@ -1858,6 +1859,8 @@ struct rtl8xxxu_priv { int next_mbox; int nr_out_eps; + /* Ensure no added or deleted stas while iterating */ + struct mutex sta_mutex; struct mutex h2c_mutex; /* Protect the indirect register accesses of RTL8710BU. */ struct mutex syson_indirect_access_mutex; @@ -1892,7 +1895,6 @@ struct rtl8xxxu_priv { u8 pi_enabled:1; u8 no_pape:1; u8 int_buf[USB_INTR_CONTENT_LENGTH]; - u8 rssi_level; DECLARE_BITMAP(tx_aggr_started, IEEE80211_NUM_TIDS); DECLARE_BITMAP(tid_tx_operational, IEEE80211_NUM_TIDS); @@ -1913,11 +1915,15 @@ struct rtl8xxxu_priv { DECLARE_BITMAP(cam_map, RTL8XXXU_MAX_SEC_CAM_NUM); }; +DECLARE_EWMA(rssi, 10, 16); + struct rtl8xxxu_sta_info { struct ieee80211_sta *sta; struct ieee80211_vif *vif; u8 macid; + struct ewma_rssi avg_rssi; + u8 rssi_level; }; struct rtl8xxxu_vif { diff --git a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_core.c b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_core.c index 125f03354ceb..055f66b623ff 100644 --- a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_core.c +++ b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_core.c @@ -4991,10 +4991,11 @@ rtl8xxxu_bss_info_changed(struct ieee80211_hw *hw, struct ieee80211_vif *vif, struct rtl8xxxu_vif *rtlvif = (struct rtl8xxxu_vif *)vif->drv_priv; struct rtl8xxxu_priv *priv = hw->priv; struct device *dev = &priv->udev->dev; + struct rtl8xxxu_sta_info *sta_info; struct ieee80211_sta *sta; struct rtl8xxxu_ra_report *rarpt; + u8 val8, macid; u32 val32; - u8 val8; rarpt = &priv->ra_report; @@ -5017,6 +5018,7 @@ rtl8xxxu_bss_info_changed(struct ieee80211_hw *hw, struct ieee80211_vif *vif, rcu_read_unlock(); goto error; } + macid = rtl8xxxu_get_macid(priv, sta); if (sta->deflink.ht_cap.ht_supported) dev_info(dev, "%s: HT supported\n", __func__); @@ -5037,14 +5039,15 @@ rtl8xxxu_bss_info_changed(struct ieee80211_hw *hw, struct ieee80211_vif *vif, bw = RATE_INFO_BW_40; else bw = RATE_INFO_BW_20; + + sta_info = (struct rtl8xxxu_sta_info *)sta->drv_priv; + sta_info->rssi_level = RTL8XXXU_RATR_STA_INIT; rcu_read_unlock(); rtl8xxxu_update_ra_report(rarpt, highest_rate, sgi, bw); - priv->rssi_level = RTL8XXXU_RATR_STA_INIT; - priv->fops->update_rate_mask(priv, ramask, 0, sgi, - bw == RATE_INFO_BW_40, 0); + bw == RATE_INFO_BW_40, macid); rtl8xxxu_write8(priv, REG_BCN_MAX_ERR, 0xff); @@ -6317,6 +6320,76 @@ static void rtl8188e_c2hcmd_callback(struct work_struct *work) } } +#define rtl8xxxu_iterate_vifs_atomic(priv, iterator, data) \ + ieee80211_iterate_active_interfaces_atomic((priv)->hw, \ + IEEE80211_IFACE_ITER_NORMAL, iterator, data) + +struct rtl8xxxu_rx_update_rssi_data { + struct rtl8xxxu_priv *priv; + struct ieee80211_hdr *hdr; + struct ieee80211_rx_status *rx_status; + u8 *bssid; +}; + +static void rtl8xxxu_rx_update_rssi_iter(void *data, u8 *mac, + struct ieee80211_vif *vif) +{ + struct rtl8xxxu_rx_update_rssi_data *iter_data = data; + struct ieee80211_sta *sta; + struct ieee80211_hdr *hdr = iter_data->hdr; + struct rtl8xxxu_priv *priv = iter_data->priv; + struct rtl8xxxu_sta_info *sta_info; + struct ieee80211_rx_status *rx_status = iter_data->rx_status; + u8 *bssid = iter_data->bssid; + + if (!ether_addr_equal(vif->bss_conf.bssid, bssid)) + return; + + if (!(ether_addr_equal(vif->addr, hdr->addr1) || + ieee80211_is_beacon(hdr->frame_control))) + return; + + sta = ieee80211_find_sta_by_ifaddr(priv->hw, hdr->addr2, + vif->addr); + if (!sta) + return; + + sta_info = (struct rtl8xxxu_sta_info *)sta->drv_priv; + ewma_rssi_add(&sta_info->avg_rssi, -rx_status->signal); +} + +static inline u8 *get_hdr_bssid(struct ieee80211_hdr *hdr) +{ + __le16 fc = hdr->frame_control; + u8 *bssid; + + if (ieee80211_has_tods(fc)) + bssid = hdr->addr1; + else if (ieee80211_has_fromds(fc)) + bssid = hdr->addr2; + else + bssid = hdr->addr3; + + return bssid; +} + +static void rtl8xxxu_rx_update_rssi(struct rtl8xxxu_priv *priv, + struct ieee80211_rx_status *rx_status, + struct ieee80211_hdr *hdr) +{ + struct rtl8xxxu_rx_update_rssi_data data = {}; + + if (ieee80211_is_ctl(hdr->frame_control)) + return; + + data.priv = priv; + data.hdr = hdr; + data.rx_status = rx_status; + data.bssid = get_hdr_bssid(hdr); + + rtl8xxxu_iterate_vifs_atomic(priv, rtl8xxxu_rx_update_rssi_iter, &data); +} + int rtl8xxxu_parse_rxdesc16(struct rtl8xxxu_priv *priv, struct sk_buff *skb) { struct ieee80211_hw *hw = priv->hw; @@ -6376,18 +6449,26 @@ int rtl8xxxu_parse_rxdesc16(struct rtl8xxxu_priv *priv, struct sk_buff *skb) skb_queue_tail(&priv->c2hcmd_queue, skb); schedule_work(&priv->c2hcmd_work); } else { + struct ieee80211_hdr *hdr; + phy_stats = (struct rtl8723au_phy_stats *)skb->data; skb_pull(skb, drvinfo_sz + desc_shift); skb_trim(skb, pkt_len); - if (rx_desc->phy_stats) + hdr = (struct ieee80211_hdr *)skb->data; + if (rx_desc->phy_stats) { priv->fops->parse_phystats( priv, rx_status, phy_stats, rx_desc->rxmcs, - (struct ieee80211_hdr *)skb->data, + hdr, rx_desc->crc32 || rx_desc->icverr); + if (!rx_desc->crc32 && !rx_desc->icverr) + rtl8xxxu_rx_update_rssi(priv, + rx_status, + hdr); + } rx_status->mactime = rx_desc->tsfl; rx_status->flag |= RX_FLAG_MACTIME_START; @@ -6484,10 +6565,15 @@ int rtl8xxxu_parse_rxdesc24(struct rtl8xxxu_priv *priv, struct sk_buff *skb) } else { struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data; - if (rx_desc->phy_stats) + if (rx_desc->phy_stats) { priv->fops->parse_phystats(priv, rx_status, phy_stats, rx_desc->rxmcs, hdr, rx_desc->crc32 || rx_desc->icverr); + if (!rx_desc->crc32 && !rx_desc->icverr) + rtl8xxxu_rx_update_rssi(priv, + rx_status, + hdr); + } rx_status->mactime = rx_desc->tsfl; rx_status->flag |= RX_FLAG_MACTIME_START; @@ -7111,6 +7197,7 @@ static void rtl8xxxu_refresh_rate_mask(struct rtl8xxxu_priv *priv, int signal, struct ieee80211_sta *sta, bool force) { + struct rtl8xxxu_sta_info *sta_info = (struct rtl8xxxu_sta_info *)sta->drv_priv; struct ieee80211_hw *hw = priv->hw; u16 wireless_mode; u8 rssi_level, ratr_idx; @@ -7119,7 +7206,7 @@ static void rtl8xxxu_refresh_rate_mask(struct rtl8xxxu_priv *priv, u8 go_up_gap = 5; u8 macid = rtl8xxxu_get_macid(priv, sta); - rssi_level = priv->rssi_level; + rssi_level = sta_info->rssi_level; snr = rtl8xxxu_signal_to_snr(signal); snr_thresh_high = RTL8XXXU_SNR_THRESH_HIGH; snr_thresh_low = RTL8XXXU_SNR_THRESH_LOW; @@ -7144,18 +7231,16 @@ static void rtl8xxxu_refresh_rate_mask(struct rtl8xxxu_priv *priv, else rssi_level = RTL8XXXU_RATR_STA_LOW; - if (rssi_level != priv->rssi_level || force) { + if (rssi_level != sta_info->rssi_level || force) { int sgi = 0; u32 rate_bitmap = 0; - rcu_read_lock(); rate_bitmap = (sta->deflink.supp_rates[0] & 0xfff) | (sta->deflink.ht_cap.mcs.rx_mask[0] << 12) | (sta->deflink.ht_cap.mcs.rx_mask[1] << 20); if (sta->deflink.ht_cap.cap & (IEEE80211_HT_CAP_SGI_40 | IEEE80211_HT_CAP_SGI_20)) sgi = 1; - rcu_read_unlock(); wireless_mode = rtl8xxxu_wireless_mode(hw, sta); switch (wireless_mode) { @@ -7236,7 +7321,7 @@ static void rtl8xxxu_refresh_rate_mask(struct rtl8xxxu_priv *priv, break; } - priv->rssi_level = rssi_level; + sta_info->rssi_level = rssi_level; priv->fops->update_rate_mask(priv, rate_bitmap, ratr_idx, sgi, txbw_40mhz, macid); } } @@ -7329,40 +7414,60 @@ static void rtl8xxxu_track_cfo(struct rtl8xxxu_priv *priv) rtl8xxxu_set_atc_status(priv, abs(cfo_average) >= CFO_TH_ATC); } -static void rtl8xxxu_watchdog_callback(struct work_struct *work) +static void rtl8xxxu_ra_iter(void *data, struct ieee80211_sta *sta) { - struct ieee80211_vif *vif; - struct rtl8xxxu_priv *priv; - int i; + struct rtl8xxxu_sta_info *sta_info = (struct rtl8xxxu_sta_info *)sta->drv_priv; + struct rtl8xxxu_priv *priv = data; + int signal = -ewma_rssi_read(&sta_info->avg_rssi); - priv = container_of(work, struct rtl8xxxu_priv, ra_watchdog.work); - for (i = 0; i < ARRAY_SIZE(priv->vifs); i++) { - vif = priv->vifs[i]; + priv->fops->report_rssi(priv, rtl8xxxu_get_macid(priv, sta), + rtl8xxxu_signal_to_snr(signal)); + rtl8xxxu_refresh_rate_mask(priv, signal, sta, false); +} - if (!vif || vif->type != NL80211_IFTYPE_STATION) - continue; +struct rtl8xxxu_stas_entry { + struct list_head list; + struct ieee80211_sta *sta; +}; - int signal; - struct ieee80211_sta *sta; +struct rtl8xxxu_iter_stas_data { + struct rtl8xxxu_priv *priv; + struct list_head list; +}; - rcu_read_lock(); - sta = ieee80211_find_sta(vif, vif->bss_conf.bssid); - if (!sta) { - struct device *dev = &priv->udev->dev; +static void rtl8xxxu_collect_sta_iter(void *data, struct ieee80211_sta *sta) +{ + struct rtl8xxxu_iter_stas_data *iter_stas = data; + struct rtl8xxxu_stas_entry *stas_entry; - dev_dbg(dev, "%s: no sta found\n", __func__); - rcu_read_unlock(); - continue; - } - rcu_read_unlock(); + stas_entry = kmalloc(sizeof(*stas_entry), GFP_ATOMIC); + if (!stas_entry) + return; - signal = ieee80211_ave_rssi(vif); + stas_entry->sta = sta; + list_add_tail(&stas_entry->list, &iter_stas->list); +} - priv->fops->report_rssi(priv, rtl8xxxu_get_macid(priv, sta), - rtl8xxxu_signal_to_snr(signal)); +static void rtl8xxxu_watchdog_callback(struct work_struct *work) +{ - rtl8xxxu_refresh_rate_mask(priv, signal, sta, false); + struct rtl8xxxu_iter_stas_data iter_data; + struct rtl8xxxu_stas_entry *sta_entry, *tmp; + struct rtl8xxxu_priv *priv; + + priv = container_of(work, struct rtl8xxxu_priv, ra_watchdog.work); + iter_data.priv = priv; + INIT_LIST_HEAD(&iter_data.list); + + mutex_lock(&priv->sta_mutex); + ieee80211_iterate_stations_atomic(priv->hw, rtl8xxxu_collect_sta_iter, + &iter_data); + list_for_each_entry_safe(sta_entry, tmp, &iter_data.list, list) { + list_del_init(&sta_entry->list); + rtl8xxxu_ra_iter(priv, sta_entry->sta); + kfree(sta_entry); } + mutex_unlock(&priv->sta_mutex); if (priv->fops->set_crystal_cap) rtl8xxxu_track_cfo(priv); @@ -7504,10 +7609,15 @@ static int rtl8xxxu_sta_add(struct ieee80211_hw *hw, struct rtl8xxxu_vif *rtlvif = (struct rtl8xxxu_vif *)vif->drv_priv; struct rtl8xxxu_priv *priv = hw->priv; + mutex_lock(&priv->sta_mutex); + ewma_rssi_init(&sta_info->avg_rssi); if (vif->type == NL80211_IFTYPE_AP) { + sta_info->rssi_level = RTL8XXXU_RATR_STA_INIT; sta_info->macid = rtl8xxxu_acquire_macid(priv); - if (sta_info->macid >= RTL8XXXU_MAX_MAC_ID_NUM) + if (sta_info->macid >= RTL8XXXU_MAX_MAC_ID_NUM) { + mutex_unlock(&priv->sta_mutex); return -ENOSPC; + } rtl8xxxu_refresh_rate_mask(priv, 0, sta, true); priv->fops->report_connect(priv, sta_info->macid, H2C_MACID_ROLE_STA, true); @@ -7523,6 +7633,7 @@ static int rtl8xxxu_sta_add(struct ieee80211_hw *hw, break; } } + mutex_unlock(&priv->sta_mutex); return 0; } @@ -7534,8 +7645,10 @@ static int rtl8xxxu_sta_remove(struct ieee80211_hw *hw, struct rtl8xxxu_sta_info *sta_info = (struct rtl8xxxu_sta_info *)sta->drv_priv; struct rtl8xxxu_priv *priv = hw->priv; + mutex_lock(&priv->sta_mutex); if (vif->type == NL80211_IFTYPE_AP) rtl8xxxu_release_macid(priv, sta_info->macid); + mutex_unlock(&priv->sta_mutex); return 0; } @@ -7767,6 +7880,7 @@ static int rtl8xxxu_probe(struct usb_interface *interface, mutex_init(&priv->usb_buf_mutex); mutex_init(&priv->syson_indirect_access_mutex); mutex_init(&priv->h2c_mutex); + mutex_init(&priv->sta_mutex); INIT_LIST_HEAD(&priv->tx_urb_free_list); spin_lock_init(&priv->tx_urb_lock); INIT_LIST_HEAD(&priv->rx_urb_pending_list); -- cgit v1.2.3 From 0a44dfc070749514b804ccac0b1fd38718f7daa1 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Mon, 29 Jan 2024 19:34:38 +0100 Subject: wifi: mac80211: simplify non-chanctx drivers There are still surprisingly many non-chanctx drivers, but in mac80211 that code is a bit awkward. Simplify this by having those drivers assign 'emulated' ops, so that the mac80211 code can be more unified between non-chanctx/chanctx drivers. This cuts the number of places caring about it by about 15, which are scattered across - now they're fewer and no longer in the channel context handling. Link: https://msgid.link/20240129194108.6d0ead50f5cf.I60d093b2fc81ca1853925a4d0ac3a2337d5baa5b@changeid Signed-off-by: Johannes Berg --- drivers/net/wireless/admtek/adm8211.c | 4 + drivers/net/wireless/ath/ar5523/ar5523.c | 4 + drivers/net/wireless/ath/ath5k/mac80211-ops.c | 4 + drivers/net/wireless/ath/ath9k/htc_drv_main.c | 4 + drivers/net/wireless/ath/ath9k/main.c | 4 + drivers/net/wireless/ath/carl9170/main.c | 4 + drivers/net/wireless/ath/wcn36xx/main.c | 4 + drivers/net/wireless/atmel/at76c50x-usb.c | 4 + drivers/net/wireless/broadcom/b43/main.c | 4 + drivers/net/wireless/broadcom/b43legacy/main.c | 4 + .../broadcom/brcm80211/brcmsmac/mac80211_if.c | 4 + drivers/net/wireless/intel/iwlegacy/3945-mac.c | 4 + drivers/net/wireless/intel/iwlegacy/4965-mac.c | 4 + drivers/net/wireless/intel/iwlwifi/dvm/mac80211.c | 4 + drivers/net/wireless/intersil/p54/main.c | 4 + drivers/net/wireless/marvell/libertas_tf/main.c | 4 + drivers/net/wireless/marvell/mwl8k.c | 4 + drivers/net/wireless/mediatek/mt76/mt7603/main.c | 4 + drivers/net/wireless/mediatek/mt76/mt76x0/pci.c | 4 + drivers/net/wireless/mediatek/mt76/mt76x0/usb.c | 4 + .../net/wireless/mediatek/mt76/mt76x2/pci_main.c | 4 + .../net/wireless/mediatek/mt76/mt76x2/usb_main.c | 4 + drivers/net/wireless/mediatek/mt76/mt792x_core.c | 7 +- drivers/net/wireless/mediatek/mt76/mt7996/main.c | 4 + drivers/net/wireless/mediatek/mt7601u/main.c | 4 + drivers/net/wireless/purelifi/plfxlc/mac.c | 4 + drivers/net/wireless/ralink/rt2x00/rt2400pci.c | 4 + drivers/net/wireless/ralink/rt2x00/rt2500pci.c | 4 + drivers/net/wireless/ralink/rt2x00/rt2500usb.c | 4 + drivers/net/wireless/ralink/rt2x00/rt2800pci.c | 4 + drivers/net/wireless/ralink/rt2x00/rt2800soc.c | 4 + drivers/net/wireless/ralink/rt2x00/rt2800usb.c | 4 + drivers/net/wireless/ralink/rt2x00/rt61pci.c | 4 + drivers/net/wireless/ralink/rt2x00/rt73usb.c | 4 + drivers/net/wireless/realtek/rtl818x/rtl8180/dev.c | 4 + drivers/net/wireless/realtek/rtl818x/rtl8187/dev.c | 4 + .../net/wireless/realtek/rtl8xxxu/rtl8xxxu_core.c | 4 + drivers/net/wireless/realtek/rtlwifi/core.c | 4 + drivers/net/wireless/realtek/rtw88/mac80211.c | 4 + drivers/net/wireless/realtek/rtw89/core.c | 7 +- drivers/net/wireless/rsi/rsi_91x_mac80211.c | 4 + drivers/net/wireless/st/cw1200/main.c | 4 + drivers/net/wireless/ti/wl1251/main.c | 4 + drivers/net/wireless/virtual/mac80211_hwsim.c | 4 + drivers/net/wireless/zydas/zd1211rw/zd_mac.c | 4 + drivers/staging/vt6655/device_main.c | 4 + drivers/staging/vt6656/main_usb.c | 4 + include/net/mac80211.h | 13 ++ net/mac80211/cfg.c | 42 ++--- net/mac80211/chan.c | 111 ++--------- net/mac80211/ieee80211_i.h | 9 +- net/mac80211/iface.c | 6 +- net/mac80211/main.c | 205 +++++++++++++++++---- net/mac80211/mlme.c | 3 +- net/mac80211/offchannel.c | 21 ++- net/mac80211/scan.c | 18 +- net/mac80211/tx.c | 2 - net/mac80211/util.c | 27 ++- 58 files changed, 444 insertions(+), 207 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/admtek/adm8211.c b/drivers/net/wireless/admtek/adm8211.c index 2fceea9f6550..e3fd48dd3909 100644 --- a/drivers/net/wireless/admtek/adm8211.c +++ b/drivers/net/wireless/admtek/adm8211.c @@ -1759,6 +1759,10 @@ static int adm8211_alloc_rings(struct ieee80211_hw *dev) } static const struct ieee80211_ops adm8211_ops = { + .add_chanctx = ieee80211_emulate_add_chanctx, + .remove_chanctx = ieee80211_emulate_remove_chanctx, + .change_chanctx = ieee80211_emulate_change_chanctx, + .switch_vif_chanctx = ieee80211_emulate_switch_vif_chanctx, .tx = adm8211_tx, .wake_tx_queue = ieee80211_handle_wake_tx_queue, .start = adm8211_start, diff --git a/drivers/net/wireless/ath/ar5523/ar5523.c b/drivers/net/wireless/ath/ar5523/ar5523.c index a742cec44e3d..815f8f599f5d 100644 --- a/drivers/net/wireless/ath/ar5523/ar5523.c +++ b/drivers/net/wireless/ath/ar5523/ar5523.c @@ -1358,6 +1358,10 @@ static void ar5523_configure_filter(struct ieee80211_hw *hw, } static const struct ieee80211_ops ar5523_ops = { + .add_chanctx = ieee80211_emulate_add_chanctx, + .remove_chanctx = ieee80211_emulate_remove_chanctx, + .change_chanctx = ieee80211_emulate_change_chanctx, + .switch_vif_chanctx = ieee80211_emulate_switch_vif_chanctx, .start = ar5523_start, .stop = ar5523_stop, .tx = ar5523_tx, diff --git a/drivers/net/wireless/ath/ath5k/mac80211-ops.c b/drivers/net/wireless/ath/ath5k/mac80211-ops.c index c630343ca4f9..eea4bda77608 100644 --- a/drivers/net/wireless/ath/ath5k/mac80211-ops.c +++ b/drivers/net/wireless/ath/ath5k/mac80211-ops.c @@ -779,6 +779,10 @@ static int ath5k_set_ringparam(struct ieee80211_hw *hw, u32 tx, u32 rx) const struct ieee80211_ops ath5k_hw_ops = { + .add_chanctx = ieee80211_emulate_add_chanctx, + .remove_chanctx = ieee80211_emulate_remove_chanctx, + .change_chanctx = ieee80211_emulate_change_chanctx, + .switch_vif_chanctx = ieee80211_emulate_switch_vif_chanctx, .tx = ath5k_tx, .wake_tx_queue = ieee80211_handle_wake_tx_queue, .start = ath5k_start, diff --git a/drivers/net/wireless/ath/ath9k/htc_drv_main.c b/drivers/net/wireless/ath/ath9k/htc_drv_main.c index 9a9b5212051a..b389e19381c4 100644 --- a/drivers/net/wireless/ath/ath9k/htc_drv_main.c +++ b/drivers/net/wireless/ath/ath9k/htc_drv_main.c @@ -1868,6 +1868,10 @@ static void ath9k_htc_channel_switch_beacon(struct ieee80211_hw *hw, } struct ieee80211_ops ath9k_htc_ops = { + .add_chanctx = ieee80211_emulate_add_chanctx, + .remove_chanctx = ieee80211_emulate_remove_chanctx, + .change_chanctx = ieee80211_emulate_change_chanctx, + .switch_vif_chanctx = ieee80211_emulate_switch_vif_chanctx, .tx = ath9k_htc_tx, .wake_tx_queue = ieee80211_handle_wake_tx_queue, .start = ath9k_htc_start, diff --git a/drivers/net/wireless/ath/ath9k/main.c b/drivers/net/wireless/ath/ath9k/main.c index c48ff0ffbfef..a2943aaecb20 100644 --- a/drivers/net/wireless/ath/ath9k/main.c +++ b/drivers/net/wireless/ath/ath9k/main.c @@ -2786,6 +2786,10 @@ static int ath9k_get_txpower(struct ieee80211_hw *hw, struct ieee80211_vif *vif, } struct ieee80211_ops ath9k_ops = { + .add_chanctx = ieee80211_emulate_add_chanctx, + .remove_chanctx = ieee80211_emulate_remove_chanctx, + .change_chanctx = ieee80211_emulate_change_chanctx, + .switch_vif_chanctx = ieee80211_emulate_switch_vif_chanctx, .tx = ath9k_tx, .start = ath9k_start, .stop = ath9k_stop, diff --git a/drivers/net/wireless/ath/carl9170/main.c b/drivers/net/wireless/ath/carl9170/main.c index 524327d24964..7e7797bf44b7 100644 --- a/drivers/net/wireless/ath/carl9170/main.c +++ b/drivers/net/wireless/ath/carl9170/main.c @@ -1712,6 +1712,10 @@ static bool carl9170_tx_frames_pending(struct ieee80211_hw *hw) } static const struct ieee80211_ops carl9170_ops = { + .add_chanctx = ieee80211_emulate_add_chanctx, + .remove_chanctx = ieee80211_emulate_remove_chanctx, + .change_chanctx = ieee80211_emulate_change_chanctx, + .switch_vif_chanctx = ieee80211_emulate_switch_vif_chanctx, .start = carl9170_op_start, .stop = carl9170_op_stop, .tx = carl9170_op_tx, diff --git a/drivers/net/wireless/ath/wcn36xx/main.c b/drivers/net/wireless/ath/wcn36xx/main.c index 4e6b4df8562f..bfbd3c7a70b3 100644 --- a/drivers/net/wireless/ath/wcn36xx/main.c +++ b/drivers/net/wireless/ath/wcn36xx/main.c @@ -1347,6 +1347,10 @@ static void wcn36xx_sta_statistics(struct ieee80211_hw *hw, struct ieee80211_vif } static const struct ieee80211_ops wcn36xx_ops = { + .add_chanctx = ieee80211_emulate_add_chanctx, + .remove_chanctx = ieee80211_emulate_remove_chanctx, + .change_chanctx = ieee80211_emulate_change_chanctx, + .switch_vif_chanctx = ieee80211_emulate_switch_vif_chanctx, .start = wcn36xx_start, .stop = wcn36xx_stop, .add_interface = wcn36xx_add_interface, diff --git a/drivers/net/wireless/atmel/at76c50x-usb.c b/drivers/net/wireless/atmel/at76c50x-usb.c index 447b51cff8f9..0b55a272bfd6 100644 --- a/drivers/net/wireless/atmel/at76c50x-usb.c +++ b/drivers/net/wireless/atmel/at76c50x-usb.c @@ -2178,6 +2178,10 @@ static int at76_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd, } static const struct ieee80211_ops at76_ops = { + .add_chanctx = ieee80211_emulate_add_chanctx, + .remove_chanctx = ieee80211_emulate_remove_chanctx, + .change_chanctx = ieee80211_emulate_change_chanctx, + .switch_vif_chanctx = ieee80211_emulate_switch_vif_chanctx, .tx = at76_mac80211_tx, .wake_tx_queue = ieee80211_handle_wake_tx_queue, .add_interface = at76_add_interface, diff --git a/drivers/net/wireless/broadcom/b43/main.c b/drivers/net/wireless/broadcom/b43/main.c index effb6c23f825..badb2f494035 100644 --- a/drivers/net/wireless/broadcom/b43/main.c +++ b/drivers/net/wireless/broadcom/b43/main.c @@ -5172,6 +5172,10 @@ static int b43_op_get_survey(struct ieee80211_hw *hw, int idx, } static const struct ieee80211_ops b43_hw_ops = { + .add_chanctx = ieee80211_emulate_add_chanctx, + .remove_chanctx = ieee80211_emulate_remove_chanctx, + .change_chanctx = ieee80211_emulate_change_chanctx, + .switch_vif_chanctx = ieee80211_emulate_switch_vif_chanctx, .tx = b43_op_tx, .wake_tx_queue = ieee80211_handle_wake_tx_queue, .conf_tx = b43_op_conf_tx, diff --git a/drivers/net/wireless/broadcom/b43legacy/main.c b/drivers/net/wireless/broadcom/b43legacy/main.c index 760136638a95..18eb610f600a 100644 --- a/drivers/net/wireless/broadcom/b43legacy/main.c +++ b/drivers/net/wireless/broadcom/b43legacy/main.c @@ -3531,6 +3531,10 @@ static int b43legacy_op_get_survey(struct ieee80211_hw *hw, int idx, } static const struct ieee80211_ops b43legacy_hw_ops = { + .add_chanctx = ieee80211_emulate_add_chanctx, + .remove_chanctx = ieee80211_emulate_remove_chanctx, + .change_chanctx = ieee80211_emulate_change_chanctx, + .switch_vif_chanctx = ieee80211_emulate_switch_vif_chanctx, .tx = b43legacy_op_tx, .wake_tx_queue = ieee80211_handle_wake_tx_queue, .conf_tx = b43legacy_op_conf_tx, diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmsmac/mac80211_if.c b/drivers/net/wireless/broadcom/brcm80211/brcmsmac/mac80211_if.c index 543e93ec49d2..92860dc0a92e 100644 --- a/drivers/net/wireless/broadcom/brcm80211/brcmsmac/mac80211_if.c +++ b/drivers/net/wireless/broadcom/brcm80211/brcmsmac/mac80211_if.c @@ -959,6 +959,10 @@ static int brcms_ops_beacon_set_tim(struct ieee80211_hw *hw, } static const struct ieee80211_ops brcms_ops = { + .add_chanctx = ieee80211_emulate_add_chanctx, + .remove_chanctx = ieee80211_emulate_remove_chanctx, + .change_chanctx = ieee80211_emulate_change_chanctx, + .switch_vif_chanctx = ieee80211_emulate_switch_vif_chanctx, .tx = brcms_ops_tx, .wake_tx_queue = ieee80211_handle_wake_tx_queue, .start = brcms_ops_start, diff --git a/drivers/net/wireless/intel/iwlegacy/3945-mac.c b/drivers/net/wireless/intel/iwlegacy/3945-mac.c index 9eaf5ec133f9..075b705a8d7b 100644 --- a/drivers/net/wireless/intel/iwlegacy/3945-mac.c +++ b/drivers/net/wireless/intel/iwlegacy/3945-mac.c @@ -3432,6 +3432,10 @@ static const struct attribute_group il3945_attribute_group = { }; static struct ieee80211_ops il3945_mac_ops __ro_after_init = { + .add_chanctx = ieee80211_emulate_add_chanctx, + .remove_chanctx = ieee80211_emulate_remove_chanctx, + .change_chanctx = ieee80211_emulate_change_chanctx, + .switch_vif_chanctx = ieee80211_emulate_switch_vif_chanctx, .tx = il3945_mac_tx, .wake_tx_queue = ieee80211_handle_wake_tx_queue, .start = il3945_mac_start, diff --git a/drivers/net/wireless/intel/iwlegacy/4965-mac.c b/drivers/net/wireless/intel/iwlegacy/4965-mac.c index 70e420df1643..4beb7be6d51d 100644 --- a/drivers/net/wireless/intel/iwlegacy/4965-mac.c +++ b/drivers/net/wireless/intel/iwlegacy/4965-mac.c @@ -6301,6 +6301,10 @@ il4965_tx_queue_set_status(struct il_priv *il, struct il_tx_queue *txq, } static const struct ieee80211_ops il4965_mac_ops = { + .add_chanctx = ieee80211_emulate_add_chanctx, + .remove_chanctx = ieee80211_emulate_remove_chanctx, + .change_chanctx = ieee80211_emulate_change_chanctx, + .switch_vif_chanctx = ieee80211_emulate_switch_vif_chanctx, .tx = il4965_mac_tx, .wake_tx_queue = ieee80211_handle_wake_tx_queue, .start = il4965_mac_start, diff --git a/drivers/net/wireless/intel/iwlwifi/dvm/mac80211.c b/drivers/net/wireless/intel/iwlwifi/dvm/mac80211.c index 5f3d5b15f727..52b008ce53bd 100644 --- a/drivers/net/wireless/intel/iwlwifi/dvm/mac80211.c +++ b/drivers/net/wireless/intel/iwlwifi/dvm/mac80211.c @@ -1570,6 +1570,10 @@ static void iwlagn_mac_sta_notify(struct ieee80211_hw *hw, } const struct ieee80211_ops iwlagn_hw_ops = { + .add_chanctx = ieee80211_emulate_add_chanctx, + .remove_chanctx = ieee80211_emulate_remove_chanctx, + .change_chanctx = ieee80211_emulate_change_chanctx, + .switch_vif_chanctx = ieee80211_emulate_switch_vif_chanctx, .tx = iwlagn_mac_tx, .wake_tx_queue = ieee80211_handle_wake_tx_queue, .start = iwlagn_mac_start, diff --git a/drivers/net/wireless/intersil/p54/main.c b/drivers/net/wireless/intersil/p54/main.c index c6084683aedd..687841b2fa2a 100644 --- a/drivers/net/wireless/intersil/p54/main.c +++ b/drivers/net/wireless/intersil/p54/main.c @@ -704,6 +704,10 @@ static void p54_set_coverage_class(struct ieee80211_hw *dev, } static const struct ieee80211_ops p54_ops = { + .add_chanctx = ieee80211_emulate_add_chanctx, + .remove_chanctx = ieee80211_emulate_remove_chanctx, + .change_chanctx = ieee80211_emulate_change_chanctx, + .switch_vif_chanctx = ieee80211_emulate_switch_vif_chanctx, .tx = p54_tx_80211, .wake_tx_queue = ieee80211_handle_wake_tx_queue, .start = p54_start, diff --git a/drivers/net/wireless/marvell/libertas_tf/main.c b/drivers/net/wireless/marvell/libertas_tf/main.c index 199d33ed3bb9..9cca69fe04d7 100644 --- a/drivers/net/wireless/marvell/libertas_tf/main.c +++ b/drivers/net/wireless/marvell/libertas_tf/main.c @@ -473,6 +473,10 @@ static int lbtf_op_get_survey(struct ieee80211_hw *hw, int idx, } static const struct ieee80211_ops lbtf_ops = { + .add_chanctx = ieee80211_emulate_add_chanctx, + .remove_chanctx = ieee80211_emulate_remove_chanctx, + .change_chanctx = ieee80211_emulate_change_chanctx, + .switch_vif_chanctx = ieee80211_emulate_switch_vif_chanctx, .tx = lbtf_op_tx, .wake_tx_queue = ieee80211_handle_wake_tx_queue, .start = lbtf_op_start, diff --git a/drivers/net/wireless/marvell/mwl8k.c b/drivers/net/wireless/marvell/mwl8k.c index 13bcb123d122..ce8fea76dbb2 100644 --- a/drivers/net/wireless/marvell/mwl8k.c +++ b/drivers/net/wireless/marvell/mwl8k.c @@ -5610,6 +5610,10 @@ static void mwl8k_sw_scan_complete(struct ieee80211_hw *hw, } static const struct ieee80211_ops mwl8k_ops = { + .add_chanctx = ieee80211_emulate_add_chanctx, + .remove_chanctx = ieee80211_emulate_remove_chanctx, + .change_chanctx = ieee80211_emulate_change_chanctx, + .switch_vif_chanctx = ieee80211_emulate_switch_vif_chanctx, .tx = mwl8k_tx, .wake_tx_queue = ieee80211_handle_wake_tx_queue, .start = mwl8k_start, diff --git a/drivers/net/wireless/mediatek/mt76/mt7603/main.c b/drivers/net/wireless/mediatek/mt76/mt7603/main.c index e2146d30e553..9b49267b1eab 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7603/main.c +++ b/drivers/net/wireless/mediatek/mt76/mt7603/main.c @@ -701,6 +701,10 @@ static void mt7603_tx(struct ieee80211_hw *hw, } const struct ieee80211_ops mt7603_ops = { + .add_chanctx = ieee80211_emulate_add_chanctx, + .remove_chanctx = ieee80211_emulate_remove_chanctx, + .change_chanctx = ieee80211_emulate_change_chanctx, + .switch_vif_chanctx = ieee80211_emulate_switch_vif_chanctx, .tx = mt7603_tx, .start = mt7603_start, .stop = mt7603_stop, diff --git a/drivers/net/wireless/mediatek/mt76/mt76x0/pci.c b/drivers/net/wireless/mediatek/mt76/mt76x0/pci.c index 293e66fa83d5..79b7996ad1a8 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x0/pci.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x0/pci.c @@ -59,6 +59,10 @@ mt76x0e_flush(struct ieee80211_hw *hw, struct ieee80211_vif *vif, } static const struct ieee80211_ops mt76x0e_ops = { + .add_chanctx = ieee80211_emulate_add_chanctx, + .remove_chanctx = ieee80211_emulate_remove_chanctx, + .change_chanctx = ieee80211_emulate_change_chanctx, + .switch_vif_chanctx = ieee80211_emulate_switch_vif_chanctx, .tx = mt76x02_tx, .start = mt76x0e_start, .stop = mt76x0e_stop, diff --git a/drivers/net/wireless/mediatek/mt76/mt76x0/usb.c b/drivers/net/wireless/mediatek/mt76/mt76x0/usb.c index dd042949cf82..bba44f289b4e 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x0/usb.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x0/usb.c @@ -118,6 +118,10 @@ static int mt76x0u_start(struct ieee80211_hw *hw) } static const struct ieee80211_ops mt76x0u_ops = { + .add_chanctx = ieee80211_emulate_add_chanctx, + .remove_chanctx = ieee80211_emulate_remove_chanctx, + .change_chanctx = ieee80211_emulate_change_chanctx, + .switch_vif_chanctx = ieee80211_emulate_switch_vif_chanctx, .tx = mt76x02_tx, .start = mt76x0u_start, .stop = mt76x0u_stop, diff --git a/drivers/net/wireless/mediatek/mt76/mt76x2/pci_main.c b/drivers/net/wireless/mediatek/mt76/mt76x2/pci_main.c index b38bb7a2362b..bfc8c69f43fa 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x2/pci_main.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x2/pci_main.c @@ -132,6 +132,10 @@ static int mt76x2_set_antenna(struct ieee80211_hw *hw, u32 tx_ant, } const struct ieee80211_ops mt76x2_ops = { + .add_chanctx = ieee80211_emulate_add_chanctx, + .remove_chanctx = ieee80211_emulate_remove_chanctx, + .change_chanctx = ieee80211_emulate_change_chanctx, + .switch_vif_chanctx = ieee80211_emulate_switch_vif_chanctx, .tx = mt76x02_tx, .start = mt76x2_start, .stop = mt76x2_stop, diff --git a/drivers/net/wireless/mediatek/mt76/mt76x2/usb_main.c b/drivers/net/wireless/mediatek/mt76/mt76x2/usb_main.c index ac07ed1f63a3..9fe390fdd730 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x2/usb_main.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x2/usb_main.c @@ -103,6 +103,10 @@ mt76x2u_config(struct ieee80211_hw *hw, u32 changed) } const struct ieee80211_ops mt76x2u_ops = { + .add_chanctx = ieee80211_emulate_add_chanctx, + .remove_chanctx = ieee80211_emulate_remove_chanctx, + .change_chanctx = ieee80211_emulate_change_chanctx, + .switch_vif_chanctx = ieee80211_emulate_switch_vif_chanctx, .tx = mt76x02_tx, .start = mt76x2u_start, .stop = mt76x2u_stop, diff --git a/drivers/net/wireless/mediatek/mt76/mt792x_core.c b/drivers/net/wireless/mediatek/mt76/mt792x_core.c index c42101aa9e45..7872fbae7252 100644 --- a/drivers/net/wireless/mediatek/mt76/mt792x_core.c +++ b/drivers/net/wireless/mediatek/mt76/mt792x_core.c @@ -684,9 +684,10 @@ mt792x_get_mac80211_ops(struct device *dev, if (!(*fw_features & MT792x_FW_CAP_CNM)) { ops->remain_on_channel = NULL; ops->cancel_remain_on_channel = NULL; - ops->add_chanctx = NULL; - ops->remove_chanctx = NULL; - ops->change_chanctx = NULL; + ops->add_chanctx = ieee80211_emulate_add_chanctx; + ops->remove_chanctx = ieee80211_emulate_remove_chanctx; + ops->change_chanctx = ieee80211_emulate_change_chanctx; + ops->switch_vif_chanctx = ieee80211_emulate_switch_vif_chanctx; ops->assign_vif_chanctx = NULL; ops->unassign_vif_chanctx = NULL; ops->mgd_prepare_tx = NULL; diff --git a/drivers/net/wireless/mediatek/mt76/mt7996/main.c b/drivers/net/wireless/mediatek/mt76/mt7996/main.c index 51deea84b642..234e6495871b 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7996/main.c +++ b/drivers/net/wireless/mediatek/mt76/mt7996/main.c @@ -1450,6 +1450,10 @@ mt7996_net_fill_forward_path(struct ieee80211_hw *hw, #endif const struct ieee80211_ops mt7996_ops = { + .add_chanctx = ieee80211_emulate_add_chanctx, + .remove_chanctx = ieee80211_emulate_remove_chanctx, + .change_chanctx = ieee80211_emulate_change_chanctx, + .switch_vif_chanctx = ieee80211_emulate_switch_vif_chanctx, .tx = mt7996_tx, .start = mt7996_start, .stop = mt7996_stop, diff --git a/drivers/net/wireless/mediatek/mt7601u/main.c b/drivers/net/wireless/mediatek/mt7601u/main.c index c8d332456a6b..a7330576486b 100644 --- a/drivers/net/wireless/mediatek/mt7601u/main.c +++ b/drivers/net/wireless/mediatek/mt7601u/main.c @@ -405,6 +405,10 @@ out: } const struct ieee80211_ops mt7601u_ops = { + .add_chanctx = ieee80211_emulate_add_chanctx, + .remove_chanctx = ieee80211_emulate_remove_chanctx, + .change_chanctx = ieee80211_emulate_change_chanctx, + .switch_vif_chanctx = ieee80211_emulate_switch_vif_chanctx, .tx = mt7601u_tx, .wake_tx_queue = ieee80211_handle_wake_tx_queue, .start = mt7601u_start, diff --git a/drivers/net/wireless/purelifi/plfxlc/mac.c b/drivers/net/wireless/purelifi/plfxlc/mac.c index 6f5857d09af0..641f847d47ab 100644 --- a/drivers/net/wireless/purelifi/plfxlc/mac.c +++ b/drivers/net/wireless/purelifi/plfxlc/mac.c @@ -684,6 +684,10 @@ static int plfxlc_set_rts_threshold(struct ieee80211_hw *hw, u32 value) } static const struct ieee80211_ops plfxlc_ops = { + .add_chanctx = ieee80211_emulate_add_chanctx, + .remove_chanctx = ieee80211_emulate_remove_chanctx, + .change_chanctx = ieee80211_emulate_change_chanctx, + .switch_vif_chanctx = ieee80211_emulate_switch_vif_chanctx, .tx = plfxlc_op_tx, .wake_tx_queue = ieee80211_handle_wake_tx_queue, .start = plfxlc_op_start, diff --git a/drivers/net/wireless/ralink/rt2x00/rt2400pci.c b/drivers/net/wireless/ralink/rt2x00/rt2400pci.c index 13dd672b825e..42e21e9f303b 100644 --- a/drivers/net/wireless/ralink/rt2x00/rt2400pci.c +++ b/drivers/net/wireless/ralink/rt2x00/rt2400pci.c @@ -1705,6 +1705,10 @@ static int rt2400pci_tx_last_beacon(struct ieee80211_hw *hw) } static const struct ieee80211_ops rt2400pci_mac80211_ops = { + .add_chanctx = ieee80211_emulate_add_chanctx, + .remove_chanctx = ieee80211_emulate_remove_chanctx, + .change_chanctx = ieee80211_emulate_change_chanctx, + .switch_vif_chanctx = ieee80211_emulate_switch_vif_chanctx, .tx = rt2x00mac_tx, .wake_tx_queue = ieee80211_handle_wake_tx_queue, .start = rt2x00mac_start, diff --git a/drivers/net/wireless/ralink/rt2x00/rt2500pci.c b/drivers/net/wireless/ralink/rt2x00/rt2500pci.c index ecddda4c471e..36ddc5a69fa4 100644 --- a/drivers/net/wireless/ralink/rt2x00/rt2500pci.c +++ b/drivers/net/wireless/ralink/rt2x00/rt2500pci.c @@ -2003,6 +2003,10 @@ static int rt2500pci_tx_last_beacon(struct ieee80211_hw *hw) } static const struct ieee80211_ops rt2500pci_mac80211_ops = { + .add_chanctx = ieee80211_emulate_add_chanctx, + .remove_chanctx = ieee80211_emulate_remove_chanctx, + .change_chanctx = ieee80211_emulate_change_chanctx, + .switch_vif_chanctx = ieee80211_emulate_switch_vif_chanctx, .tx = rt2x00mac_tx, .wake_tx_queue = ieee80211_handle_wake_tx_queue, .start = rt2x00mac_start, diff --git a/drivers/net/wireless/ralink/rt2x00/rt2500usb.c b/drivers/net/wireless/ralink/rt2x00/rt2500usb.c index 13fdcff0ad66..09923765e2db 100644 --- a/drivers/net/wireless/ralink/rt2x00/rt2500usb.c +++ b/drivers/net/wireless/ralink/rt2x00/rt2500usb.c @@ -1794,6 +1794,10 @@ static int rt2500usb_probe_hw(struct rt2x00_dev *rt2x00dev) } static const struct ieee80211_ops rt2500usb_mac80211_ops = { + .add_chanctx = ieee80211_emulate_add_chanctx, + .remove_chanctx = ieee80211_emulate_remove_chanctx, + .change_chanctx = ieee80211_emulate_change_chanctx, + .switch_vif_chanctx = ieee80211_emulate_switch_vif_chanctx, .tx = rt2x00mac_tx, .wake_tx_queue = ieee80211_handle_wake_tx_queue, .start = rt2x00mac_start, diff --git a/drivers/net/wireless/ralink/rt2x00/rt2800pci.c b/drivers/net/wireless/ralink/rt2x00/rt2800pci.c index dcb56f708a5f..14c45aba836f 100644 --- a/drivers/net/wireless/ralink/rt2x00/rt2800pci.c +++ b/drivers/net/wireless/ralink/rt2x00/rt2800pci.c @@ -287,6 +287,10 @@ static int rt2800pci_read_eeprom(struct rt2x00_dev *rt2x00dev) } static const struct ieee80211_ops rt2800pci_mac80211_ops = { + .add_chanctx = ieee80211_emulate_add_chanctx, + .remove_chanctx = ieee80211_emulate_remove_chanctx, + .change_chanctx = ieee80211_emulate_change_chanctx, + .switch_vif_chanctx = ieee80211_emulate_switch_vif_chanctx, .tx = rt2x00mac_tx, .wake_tx_queue = ieee80211_handle_wake_tx_queue, .start = rt2x00mac_start, diff --git a/drivers/net/wireless/ralink/rt2x00/rt2800soc.c b/drivers/net/wireless/ralink/rt2x00/rt2800soc.c index 7118d4f9038d..701ba54bf3e5 100644 --- a/drivers/net/wireless/ralink/rt2x00/rt2800soc.c +++ b/drivers/net/wireless/ralink/rt2x00/rt2800soc.c @@ -132,6 +132,10 @@ static int rt2800soc_write_firmware(struct rt2x00_dev *rt2x00dev, } static const struct ieee80211_ops rt2800soc_mac80211_ops = { + .add_chanctx = ieee80211_emulate_add_chanctx, + .remove_chanctx = ieee80211_emulate_remove_chanctx, + .change_chanctx = ieee80211_emulate_change_chanctx, + .switch_vif_chanctx = ieee80211_emulate_switch_vif_chanctx, .tx = rt2x00mac_tx, .wake_tx_queue = ieee80211_handle_wake_tx_queue, .start = rt2x00mac_start, diff --git a/drivers/net/wireless/ralink/rt2x00/rt2800usb.c b/drivers/net/wireless/ralink/rt2x00/rt2800usb.c index b2a8e75a901b..160bef79acdb 100644 --- a/drivers/net/wireless/ralink/rt2x00/rt2800usb.c +++ b/drivers/net/wireless/ralink/rt2x00/rt2800usb.c @@ -629,6 +629,10 @@ static int rt2800usb_probe_hw(struct rt2x00_dev *rt2x00dev) } static const struct ieee80211_ops rt2800usb_mac80211_ops = { + .add_chanctx = ieee80211_emulate_add_chanctx, + .remove_chanctx = ieee80211_emulate_remove_chanctx, + .change_chanctx = ieee80211_emulate_change_chanctx, + .switch_vif_chanctx = ieee80211_emulate_switch_vif_chanctx, .tx = rt2x00mac_tx, .wake_tx_queue = ieee80211_handle_wake_tx_queue, .start = rt2x00mac_start, diff --git a/drivers/net/wireless/ralink/rt2x00/rt61pci.c b/drivers/net/wireless/ralink/rt2x00/rt61pci.c index 483723bf514b..d1cd5694e3c7 100644 --- a/drivers/net/wireless/ralink/rt2x00/rt61pci.c +++ b/drivers/net/wireless/ralink/rt2x00/rt61pci.c @@ -2872,6 +2872,10 @@ static u64 rt61pci_get_tsf(struct ieee80211_hw *hw, struct ieee80211_vif *vif) } static const struct ieee80211_ops rt61pci_mac80211_ops = { + .add_chanctx = ieee80211_emulate_add_chanctx, + .remove_chanctx = ieee80211_emulate_remove_chanctx, + .change_chanctx = ieee80211_emulate_change_chanctx, + .switch_vif_chanctx = ieee80211_emulate_switch_vif_chanctx, .tx = rt2x00mac_tx, .wake_tx_queue = ieee80211_handle_wake_tx_queue, .start = rt2x00mac_start, diff --git a/drivers/net/wireless/ralink/rt2x00/rt73usb.c b/drivers/net/wireless/ralink/rt2x00/rt73usb.c index dfa9d5213898..b79dda952a33 100644 --- a/drivers/net/wireless/ralink/rt2x00/rt73usb.c +++ b/drivers/net/wireless/ralink/rt2x00/rt73usb.c @@ -2291,6 +2291,10 @@ static u64 rt73usb_get_tsf(struct ieee80211_hw *hw, struct ieee80211_vif *vif) } static const struct ieee80211_ops rt73usb_mac80211_ops = { + .add_chanctx = ieee80211_emulate_add_chanctx, + .remove_chanctx = ieee80211_emulate_remove_chanctx, + .change_chanctx = ieee80211_emulate_change_chanctx, + .switch_vif_chanctx = ieee80211_emulate_switch_vif_chanctx, .tx = rt2x00mac_tx, .wake_tx_queue = ieee80211_handle_wake_tx_queue, .start = rt2x00mac_start, diff --git a/drivers/net/wireless/realtek/rtl818x/rtl8180/dev.c b/drivers/net/wireless/realtek/rtl818x/rtl8180/dev.c index f6c25a52b69a..77b6cb7e1f6b 100644 --- a/drivers/net/wireless/realtek/rtl818x/rtl8180/dev.c +++ b/drivers/net/wireless/realtek/rtl818x/rtl8180/dev.c @@ -1607,6 +1607,10 @@ static void rtl8180_configure_filter(struct ieee80211_hw *dev, } static const struct ieee80211_ops rtl8180_ops = { + .add_chanctx = ieee80211_emulate_add_chanctx, + .remove_chanctx = ieee80211_emulate_remove_chanctx, + .change_chanctx = ieee80211_emulate_change_chanctx, + .switch_vif_chanctx = ieee80211_emulate_switch_vif_chanctx, .tx = rtl8180_tx, .wake_tx_queue = ieee80211_handle_wake_tx_queue, .start = rtl8180_start, diff --git a/drivers/net/wireless/realtek/rtl818x/rtl8187/dev.c b/drivers/net/wireless/realtek/rtl818x/rtl8187/dev.c index 04945f905d6d..78d99afa373d 100644 --- a/drivers/net/wireless/realtek/rtl818x/rtl8187/dev.c +++ b/drivers/net/wireless/realtek/rtl818x/rtl8187/dev.c @@ -1377,6 +1377,10 @@ static int rtl8187_conf_tx(struct ieee80211_hw *dev, static const struct ieee80211_ops rtl8187_ops = { + .add_chanctx = ieee80211_emulate_add_chanctx, + .remove_chanctx = ieee80211_emulate_remove_chanctx, + .change_chanctx = ieee80211_emulate_change_chanctx, + .switch_vif_chanctx = ieee80211_emulate_switch_vif_chanctx, .tx = rtl8187_tx, .wake_tx_queue = ieee80211_handle_wake_tx_queue, .start = rtl8187_start, diff --git a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_core.c b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_core.c index 055f66b623ff..b0c1db726d7a 100644 --- a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_core.c +++ b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_core.c @@ -7654,6 +7654,10 @@ static int rtl8xxxu_sta_remove(struct ieee80211_hw *hw, } static const struct ieee80211_ops rtl8xxxu_ops = { + .add_chanctx = ieee80211_emulate_add_chanctx, + .remove_chanctx = ieee80211_emulate_remove_chanctx, + .change_chanctx = ieee80211_emulate_change_chanctx, + .switch_vif_chanctx = ieee80211_emulate_switch_vif_chanctx, .tx = rtl8xxxu_tx, .wake_tx_queue = ieee80211_handle_wake_tx_queue, .add_interface = rtl8xxxu_add_interface, diff --git a/drivers/net/wireless/realtek/rtlwifi/core.c b/drivers/net/wireless/realtek/rtlwifi/core.c index 69e97647e3d6..2e60a6991ca1 100644 --- a/drivers/net/wireless/realtek/rtlwifi/core.c +++ b/drivers/net/wireless/realtek/rtlwifi/core.c @@ -1903,6 +1903,10 @@ void rtl_init_sw_leds(struct ieee80211_hw *hw) EXPORT_SYMBOL(rtl_init_sw_leds); const struct ieee80211_ops rtl_ops = { + .add_chanctx = ieee80211_emulate_add_chanctx, + .remove_chanctx = ieee80211_emulate_remove_chanctx, + .change_chanctx = ieee80211_emulate_change_chanctx, + .switch_vif_chanctx = ieee80211_emulate_switch_vif_chanctx, .start = rtl_op_start, .stop = rtl_op_stop, .tx = rtl_op_tx, diff --git a/drivers/net/wireless/realtek/rtw88/mac80211.c b/drivers/net/wireless/realtek/rtw88/mac80211.c index d8d68f16014e..7af5bf7fe5b6 100644 --- a/drivers/net/wireless/realtek/rtw88/mac80211.c +++ b/drivers/net/wireless/realtek/rtw88/mac80211.c @@ -927,6 +927,10 @@ static void rtw_ops_sta_rc_update(struct ieee80211_hw *hw, } const struct ieee80211_ops rtw_ops = { + .add_chanctx = ieee80211_emulate_add_chanctx, + .remove_chanctx = ieee80211_emulate_remove_chanctx, + .change_chanctx = ieee80211_emulate_change_chanctx, + .switch_vif_chanctx = ieee80211_emulate_switch_vif_chanctx, .tx = rtw_ops_tx, .wake_tx_queue = rtw_ops_wake_tx_queue, .start = rtw_ops_start, diff --git a/drivers/net/wireless/realtek/rtw89/core.c b/drivers/net/wireless/realtek/rtw89/core.c index 61a216464b6d..650c507c8ed3 100644 --- a/drivers/net/wireless/realtek/rtw89/core.c +++ b/drivers/net/wireless/realtek/rtw89/core.c @@ -4579,9 +4579,10 @@ struct rtw89_dev *rtw89_alloc_ieee80211_hw(struct device *device, !RTW89_CHK_FW_FEATURE(BEACON_FILTER, &early_fw); if (no_chanctx) { - ops->add_chanctx = NULL; - ops->remove_chanctx = NULL; - ops->change_chanctx = NULL; + ops->add_chanctx = ieee80211_emulate_add_chanctx; + ops->remove_chanctx = ieee80211_emulate_remove_chanctx; + ops->change_chanctx = ieee80211_emulate_change_chanctx; + ops->switch_vif_chanctx = ieee80211_emulate_switch_vif_chanctx; ops->assign_vif_chanctx = NULL; ops->unassign_vif_chanctx = NULL; ops->remain_on_channel = NULL; diff --git a/drivers/net/wireless/rsi/rsi_91x_mac80211.c b/drivers/net/wireless/rsi/rsi_91x_mac80211.c index 05890536e353..e8aeb4d76c13 100644 --- a/drivers/net/wireless/rsi/rsi_91x_mac80211.c +++ b/drivers/net/wireless/rsi/rsi_91x_mac80211.c @@ -1957,6 +1957,10 @@ static int rsi_mac80211_resume(struct ieee80211_hw *hw) #endif static const struct ieee80211_ops mac80211_ops = { + .add_chanctx = ieee80211_emulate_add_chanctx, + .remove_chanctx = ieee80211_emulate_remove_chanctx, + .change_chanctx = ieee80211_emulate_change_chanctx, + .switch_vif_chanctx = ieee80211_emulate_switch_vif_chanctx, .tx = rsi_mac80211_tx, .wake_tx_queue = ieee80211_handle_wake_tx_queue, .start = rsi_mac80211_start, diff --git a/drivers/net/wireless/st/cw1200/main.c b/drivers/net/wireless/st/cw1200/main.c index 381013e0db63..a54a7b86864f 100644 --- a/drivers/net/wireless/st/cw1200/main.c +++ b/drivers/net/wireless/st/cw1200/main.c @@ -203,6 +203,10 @@ static const unsigned long cw1200_ttl[] = { }; static const struct ieee80211_ops cw1200_ops = { + .add_chanctx = ieee80211_emulate_add_chanctx, + .remove_chanctx = ieee80211_emulate_remove_chanctx, + .change_chanctx = ieee80211_emulate_change_chanctx, + .switch_vif_chanctx = ieee80211_emulate_switch_vif_chanctx, .start = cw1200_start, .stop = cw1200_stop, .add_interface = cw1200_add_interface, diff --git a/drivers/net/wireless/ti/wl1251/main.c b/drivers/net/wireless/ti/wl1251/main.c index cd9a41f59f32..0da2d29dd7bd 100644 --- a/drivers/net/wireless/ti/wl1251/main.c +++ b/drivers/net/wireless/ti/wl1251/main.c @@ -1351,6 +1351,10 @@ static struct ieee80211_supported_band wl1251_band_2ghz = { }; static const struct ieee80211_ops wl1251_ops = { + .add_chanctx = ieee80211_emulate_add_chanctx, + .remove_chanctx = ieee80211_emulate_remove_chanctx, + .change_chanctx = ieee80211_emulate_change_chanctx, + .switch_vif_chanctx = ieee80211_emulate_switch_vif_chanctx, .start = wl1251_op_start, .stop = wl1251_op_stop, .add_interface = wl1251_op_add_interface, diff --git a/drivers/net/wireless/virtual/mac80211_hwsim.c b/drivers/net/wireless/virtual/mac80211_hwsim.c index a06a462d38f0..907c0842fee7 100644 --- a/drivers/net/wireless/virtual/mac80211_hwsim.c +++ b/drivers/net/wireless/virtual/mac80211_hwsim.c @@ -3922,6 +3922,10 @@ static const struct ieee80211_ops mac80211_hwsim_ops = { HWSIM_NON_MLO_OPS .sw_scan_start = mac80211_hwsim_sw_scan, .sw_scan_complete = mac80211_hwsim_sw_scan_complete, + .add_chanctx = ieee80211_emulate_add_chanctx, + .remove_chanctx = ieee80211_emulate_remove_chanctx, + .change_chanctx = ieee80211_emulate_change_chanctx, + .switch_vif_chanctx = ieee80211_emulate_switch_vif_chanctx, }; #define HWSIM_CHANCTX_OPS \ diff --git a/drivers/net/wireless/zydas/zd1211rw/zd_mac.c b/drivers/net/wireless/zydas/zd1211rw/zd_mac.c index 5d534e15a844..900c063bd724 100644 --- a/drivers/net/wireless/zydas/zd1211rw/zd_mac.c +++ b/drivers/net/wireless/zydas/zd1211rw/zd_mac.c @@ -1343,6 +1343,10 @@ static u64 zd_op_get_tsf(struct ieee80211_hw *hw, struct ieee80211_vif *vif) } static const struct ieee80211_ops zd_ops = { + .add_chanctx = ieee80211_emulate_add_chanctx, + .remove_chanctx = ieee80211_emulate_remove_chanctx, + .change_chanctx = ieee80211_emulate_change_chanctx, + .switch_vif_chanctx = ieee80211_emulate_switch_vif_chanctx, .tx = zd_op_tx, .wake_tx_queue = ieee80211_handle_wake_tx_queue, .start = zd_op_start, diff --git a/drivers/staging/vt6655/device_main.c b/drivers/staging/vt6655/device_main.c index b0b262de6480..e23a5da2b67e 100644 --- a/drivers/staging/vt6655/device_main.c +++ b/drivers/staging/vt6655/device_main.c @@ -1684,6 +1684,10 @@ static void vnt_reset_tsf(struct ieee80211_hw *hw, struct ieee80211_vif *vif) } static const struct ieee80211_ops vnt_mac_ops = { + .add_chanctx = ieee80211_emulate_add_chanctx, + .remove_chanctx = ieee80211_emulate_remove_chanctx, + .change_chanctx = ieee80211_emulate_change_chanctx, + .switch_vif_chanctx = ieee80211_emulate_switch_vif_chanctx, .tx = vnt_tx_80211, .wake_tx_queue = ieee80211_handle_wake_tx_queue, .start = vnt_start, diff --git a/drivers/staging/vt6656/main_usb.c b/drivers/staging/vt6656/main_usb.c index 2abae90f3f52..6c70493d1b01 100644 --- a/drivers/staging/vt6656/main_usb.c +++ b/drivers/staging/vt6656/main_usb.c @@ -956,6 +956,10 @@ static void vnt_reset_tsf(struct ieee80211_hw *hw, struct ieee80211_vif *vif) } static const struct ieee80211_ops vnt_mac_ops = { + .add_chanctx = ieee80211_emulate_add_chanctx, + .remove_chanctx = ieee80211_emulate_remove_chanctx, + .change_chanctx = ieee80211_emulate_change_chanctx, + .switch_vif_chanctx = ieee80211_emulate_switch_vif_chanctx, .tx = vnt_tx_80211, .wake_tx_queue = ieee80211_handle_wake_tx_queue, .start = vnt_start, diff --git a/include/net/mac80211.h b/include/net/mac80211.h index 8d6ae22c09bf..62c4b4d10bb4 100644 --- a/include/net/mac80211.h +++ b/include/net/mac80211.h @@ -7532,4 +7532,17 @@ int ieee80211_set_active_links(struct ieee80211_vif *vif, u16 active_links); void ieee80211_set_active_links_async(struct ieee80211_vif *vif, u16 active_links); +/* for older drivers - let's not document these ... */ +int ieee80211_emulate_add_chanctx(struct ieee80211_hw *hw, + struct ieee80211_chanctx_conf *ctx); +void ieee80211_emulate_remove_chanctx(struct ieee80211_hw *hw, + struct ieee80211_chanctx_conf *ctx); +void ieee80211_emulate_change_chanctx(struct ieee80211_hw *hw, + struct ieee80211_chanctx_conf *ctx, + u32 changed); +int ieee80211_emulate_switch_vif_chanctx(struct ieee80211_hw *hw, + struct ieee80211_vif_chanctx_switch *vifs, + int n_vifs, + enum ieee80211_chanctx_switch_mode mode); + #endif /* MAC80211_H */ diff --git a/net/mac80211/cfg.c b/net/mac80211/cfg.c index 6e2acad7fd71..d3bf029709d5 100644 --- a/net/mac80211/cfg.c +++ b/net/mac80211/cfg.c @@ -886,33 +886,30 @@ static int ieee80211_set_monitor_channel(struct wiphy *wiphy, { struct ieee80211_local *local = wiphy_priv(wiphy); struct ieee80211_sub_if_data *sdata; - int ret = 0; + int ret; lockdep_assert_wiphy(local->hw.wiphy); if (cfg80211_chandef_identical(&local->monitor_chandef, chandef)) return 0; - if (local->use_chanctx) { - sdata = wiphy_dereference(local->hw.wiphy, - local->monitor_sdata); - if (sdata) { - ieee80211_link_release_channel(&sdata->deflink); - ret = ieee80211_link_use_channel(&sdata->deflink, - chandef, - IEEE80211_CHANCTX_EXCLUSIVE); - } - } else { - if (local->open_count == local->monitors) { - local->_oper_chandef = *chandef; - ieee80211_hw_config(local, 0); - } - } + sdata = wiphy_dereference(local->hw.wiphy, + local->monitor_sdata); + if (!sdata) + goto done; - if (ret == 0) - local->monitor_chandef = *chandef; + if (cfg80211_chandef_identical(&sdata->vif.bss_conf.chandef, chandef)) + return 0; - return ret; + ieee80211_link_release_channel(&sdata->deflink); + ret = ieee80211_link_use_channel(&sdata->deflink, + chandef, + IEEE80211_CHANCTX_EXCLUSIVE); + if (ret) + return ret; +done: + local->monitor_chandef = *chandef; + return 0; } static int @@ -3086,7 +3083,7 @@ static int ieee80211_get_tx_power(struct wiphy *wiphy, if (local->ops->get_txpower) return drv_get_txpower(local, sdata, dbm); - if (!local->use_chanctx) + if (local->emulate_chanctx) *dbm = local->hw.conf.power_level; else *dbm = sdata->vif.bss_conf.txpower; @@ -4214,10 +4211,7 @@ static int ieee80211_cfg_get_channel(struct wiphy *wiphy, } else if (local->open_count > 0 && local->open_count == local->monitors && sdata->vif.type == NL80211_IFTYPE_MONITOR) { - if (local->use_chanctx) - *chandef = local->monitor_chandef; - else - *chandef = local->_oper_chandef; + *chandef = local->monitor_chandef; ret = 0; } out: diff --git a/net/mac80211/chan.c b/net/mac80211/chan.c index 70ba5dc4b283..cf6297ffaef3 100644 --- a/net/mac80211/chan.c +++ b/net/mac80211/chan.c @@ -519,11 +519,6 @@ static void _ieee80211_change_chanctx(struct ieee80211_local *local, drv_change_chanctx(local, ctx, changed); - if (!local->use_chanctx) { - local->_oper_chandef = *chandef; - ieee80211_hw_config(local, 0); - } - /* check is BW wider */ ieee80211_chan_bw_change(local, old_ctx, false); } @@ -674,23 +669,15 @@ static int ieee80211_add_chanctx(struct ieee80211_local *local, ieee80211_add_wbrf(local, &ctx->conf.def); - if (!local->use_chanctx) - local->hw.conf.radar_enabled = ctx->conf.radar_enabled; - /* turn idle off *before* setting channel -- some drivers need that */ changed = ieee80211_idle_off(local); if (changed) ieee80211_hw_config(local, changed); - if (!local->use_chanctx) { - local->_oper_chandef = ctx->conf.def; - ieee80211_hw_config(local, IEEE80211_CONF_CHANGE_CHANNEL); - } else { - err = drv_add_chanctx(local, ctx); - if (err) { - ieee80211_recalc_idle(local); - return err; - } + err = drv_add_chanctx(local, ctx); + if (err) { + ieee80211_recalc_idle(local); + return err; } return 0; @@ -725,32 +712,7 @@ static void ieee80211_del_chanctx(struct ieee80211_local *local, { lockdep_assert_wiphy(local->hw.wiphy); - if (!local->use_chanctx) { - struct cfg80211_chan_def *chandef = &local->_oper_chandef; - /* S1G doesn't have 20MHz, so get the correct width for the - * current channel. - */ - if (chandef->chan->band == NL80211_BAND_S1GHZ) - chandef->width = - ieee80211_s1g_channel_width(chandef->chan); - else - chandef->width = NL80211_CHAN_WIDTH_20_NOHT; - chandef->center_freq1 = chandef->chan->center_freq; - chandef->freq1_offset = chandef->chan->freq_offset; - chandef->center_freq2 = 0; - - /* NOTE: Disabling radar is only valid here for - * single channel context. To be sure, check it ... - */ - WARN_ON(local->hw.conf.radar_enabled && - !list_empty(&local->chanctx_list)); - - local->hw.conf.radar_enabled = false; - - ieee80211_hw_config(local, IEEE80211_CONF_CHANGE_CHANNEL); - } else { - drv_remove_chanctx(local, ctx); - } + drv_remove_chanctx(local, ctx); ieee80211_recalc_idle(local); @@ -849,11 +811,6 @@ static void ieee80211_recalc_radar_chanctx(struct ieee80211_local *local, chanctx->conf.radar_enabled = radar_enabled; - if (!local->use_chanctx) { - local->hw.conf.radar_enabled = chanctx->conf.radar_enabled; - ieee80211_hw_config(local, IEEE80211_CONF_CHANGE_CHANNEL); - } - drv_change_chanctx(local, chanctx, IEEE80211_CHANCTX_CHANGE_RADAR); } @@ -995,16 +952,6 @@ void ieee80211_recalc_smps_chanctx(struct ieee80211_local *local, rcu_read_unlock(); - if (!local->use_chanctx) { - if (rx_chains_static > 1) - local->smps_mode = IEEE80211_SMPS_OFF; - else if (rx_chains_dynamic > 1) - local->smps_mode = IEEE80211_SMPS_DYNAMIC; - else - local->smps_mode = IEEE80211_SMPS_STATIC; - ieee80211_hw_config(local, 0); - } - if (rx_chains_static == chanctx->conf.rx_chains_static && rx_chains_dynamic == chanctx->conf.rx_chains_dynamic) return; @@ -1114,7 +1061,7 @@ int ieee80211_link_reserve_chanctx(struct ieee80211_link_data *link, lockdep_assert_wiphy(local->hw.wiphy); curr_ctx = ieee80211_link_get_chanctx(link); - if (curr_ctx && local->use_chanctx && !local->ops->switch_vif_chanctx) + if (curr_ctx && !local->ops->switch_vif_chanctx) return -EOPNOTSUPP; new_ctx = ieee80211_find_reservation_chanctx(local, chandef, mode); @@ -1412,24 +1359,6 @@ ieee80211_link_has_in_place_reservation(struct ieee80211_link_data *link) return true; } -static int ieee80211_chsw_switch_hwconf(struct ieee80211_local *local, - struct ieee80211_chanctx *new_ctx) -{ - const struct cfg80211_chan_def *chandef; - - lockdep_assert_wiphy(local->hw.wiphy); - - chandef = ieee80211_chanctx_reserved_chandef(local, new_ctx, NULL); - if (WARN_ON(!chandef)) - return -EINVAL; - - local->hw.conf.radar_enabled = new_ctx->conf.radar_enabled; - local->_oper_chandef = *chandef; - ieee80211_hw_config(local, 0); - - return 0; -} - static int ieee80211_chsw_switch_vifs(struct ieee80211_local *local, int n_vifs) { @@ -1518,7 +1447,6 @@ err: static int ieee80211_vif_use_reserved_switch(struct ieee80211_local *local) { struct ieee80211_chanctx *ctx, *ctx_tmp, *old_ctx; - struct ieee80211_chanctx *new_ctx = NULL; int err, n_assigned, n_reserved, n_ready; int n_ctx = 0, n_vifs_switch = 0, n_vifs_assign = 0, n_vifs_ctxless = 0; @@ -1551,9 +1479,6 @@ static int ieee80211_vif_use_reserved_switch(struct ieee80211_local *local) goto err; } - if (!local->use_chanctx) - new_ctx = ctx; - n_ctx++; n_assigned = 0; @@ -1607,9 +1532,7 @@ static int ieee80211_vif_use_reserved_switch(struct ieee80211_local *local) if (WARN_ON(n_ctx == 0) || WARN_ON(n_vifs_switch == 0 && n_vifs_assign == 0 && - n_vifs_ctxless == 0) || - WARN_ON(n_ctx > 1 && !local->use_chanctx) || - WARN_ON(!new_ctx && !local->use_chanctx)) { + n_vifs_ctxless == 0)) { err = -EINVAL; goto err; } @@ -1619,20 +1542,14 @@ static int ieee80211_vif_use_reserved_switch(struct ieee80211_local *local) * reservations and driver capabilities. */ - if (local->use_chanctx) { - if (n_vifs_switch > 0) { - err = ieee80211_chsw_switch_vifs(local, n_vifs_switch); - if (err) - goto err; - } + if (n_vifs_switch > 0) { + err = ieee80211_chsw_switch_vifs(local, n_vifs_switch); + if (err) + goto err; + } - if (n_vifs_assign > 0 || n_vifs_ctxless > 0) { - err = ieee80211_chsw_switch_ctxs(local); - if (err) - goto err; - } - } else { - err = ieee80211_chsw_switch_hwconf(local, new_ctx); + if (n_vifs_assign > 0 || n_vifs_ctxless > 0) { + err = ieee80211_chsw_switch_ctxs(local); if (err) goto err; } diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h index 29294cf88d39..cb4684a9451e 100644 --- a/net/mac80211/ieee80211_i.h +++ b/net/mac80211/ieee80211_i.h @@ -1348,7 +1348,8 @@ struct ieee80211_local { bool wiphy_ciphers_allocated; - bool use_chanctx; + struct cfg80211_chan_def dflt_chandef; + bool emulate_chanctx; /* protects the aggregated multicast list and filter calls */ spinlock_t filter_lock; @@ -1474,8 +1475,6 @@ struct ieee80211_local { enum mac80211_scan_state next_scan_state; struct wiphy_delayed_work scan_work; struct ieee80211_sub_if_data __rcu *scan_sdata; - /* For backward compatibility only -- do not use */ - struct cfg80211_chan_def _oper_chandef; /* Temporary remain-on-channel for off-channel operations */ struct ieee80211_channel *tmp_channel; @@ -1549,8 +1548,6 @@ struct ieee80211_local { int user_power_level; /* in dBm, for all interfaces */ - enum ieee80211_smps_mode smps_mode; - struct work_struct restart_work; #ifdef CONFIG_MAC80211_DEBUGFS @@ -1819,6 +1816,8 @@ u64 ieee80211_calculate_rx_timestamp(struct ieee80211_local *local, unsigned int mpdu_len, unsigned int mpdu_offset); int ieee80211_hw_config(struct ieee80211_local *local, u32 changed); +int ieee80211_hw_conf_chan(struct ieee80211_local *local); +void ieee80211_hw_conf_init(struct ieee80211_local *local); void ieee80211_tx_set_protected(struct ieee80211_tx_data *tx); void ieee80211_bss_info_change_notify(struct ieee80211_sub_if_data *sdata, u64 changed); diff --git a/net/mac80211/iface.c b/net/mac80211/iface.c index 1a6e9dd39a37..d81162bf7d48 100644 --- a/net/mac80211/iface.c +++ b/net/mac80211/iface.c @@ -1288,8 +1288,6 @@ int ieee80211_do_open(struct wireless_dev *wdev, bool coming_up) res = drv_start(local); if (res) goto err_del_bss; - /* we're brought up, everything changes */ - hw_reconf_flags = ~0; ieee80211_led_radio(local, true); ieee80211_mod_tpt_led_trig(local, IEEE80211_TPT_LEDTRIG_FL_RADIO, 0); @@ -1436,7 +1434,9 @@ int ieee80211_do_open(struct wireless_dev *wdev, bool coming_up) if (coming_up) local->open_count++; - if (hw_reconf_flags) + if (local->open_count == 1) + ieee80211_hw_conf_init(local); + else if (hw_reconf_flags) ieee80211_hw_config(local, hw_reconf_flags); ieee80211_recalc_ps(local); diff --git a/net/mac80211/main.c b/net/mac80211/main.c index e05bcc35bc1e..ce0cba8d7afc 100644 --- a/net/mac80211/main.c +++ b/net/mac80211/main.c @@ -93,16 +93,32 @@ static void ieee80211_reconfig_filter(struct wiphy *wiphy, ieee80211_configure_filter(local); } -static u32 ieee80211_hw_conf_chan(struct ieee80211_local *local) +static u32 ieee80211_calc_hw_conf_chan(struct ieee80211_local *local, + struct ieee80211_chanctx_conf *ctx) { struct ieee80211_sub_if_data *sdata; struct cfg80211_chan_def chandef = {}; + struct cfg80211_chan_def *oper = NULL; + enum ieee80211_smps_mode smps_mode = IEEE80211_SMPS_STATIC; u32 changed = 0; int power; u32 offchannel_flag; + if (!local->emulate_chanctx) + return 0; + offchannel_flag = local->hw.conf.flags & IEEE80211_CONF_OFFCHANNEL; + if (ctx && !WARN_ON(!ctx->def.chan)) { + oper = &ctx->def; + if (ctx->rx_chains_static > 1) + smps_mode = IEEE80211_SMPS_OFF; + else if (ctx->rx_chains_dynamic > 1) + smps_mode = IEEE80211_SMPS_DYNAMIC; + else + smps_mode = IEEE80211_SMPS_STATIC; + } + if (local->scan_chandef.chan) { chandef = local->scan_chandef; } else if (local->tmp_channel) { @@ -110,25 +126,30 @@ static u32 ieee80211_hw_conf_chan(struct ieee80211_local *local) chandef.width = NL80211_CHAN_WIDTH_20_NOHT; chandef.center_freq1 = chandef.chan->center_freq; chandef.freq1_offset = chandef.chan->freq_offset; - } else - chandef = local->_oper_chandef; + } else if (oper) { + chandef = *oper; + } else { + chandef = local->dflt_chandef; + } - WARN(!cfg80211_chandef_valid(&chandef), - "control:%d.%03d MHz width:%d center: %d.%03d/%d MHz", - chandef.chan->center_freq, chandef.chan->freq_offset, - chandef.width, chandef.center_freq1, chandef.freq1_offset, - chandef.center_freq2); + if (WARN(!cfg80211_chandef_valid(&chandef), + "control:%d.%03d MHz width:%d center: %d.%03d/%d MHz", + chandef.chan ? chandef.chan->center_freq : -1, + chandef.chan ? chandef.chan->freq_offset : 0, + chandef.width, chandef.center_freq1, chandef.freq1_offset, + chandef.center_freq2)) + return 0; - if (!cfg80211_chandef_identical(&chandef, &local->_oper_chandef)) + if (!oper || !cfg80211_chandef_identical(&chandef, oper)) local->hw.conf.flags |= IEEE80211_CONF_OFFCHANNEL; else local->hw.conf.flags &= ~IEEE80211_CONF_OFFCHANNEL; offchannel_flag ^= local->hw.conf.flags & IEEE80211_CONF_OFFCHANNEL; - if (offchannel_flag || - !cfg80211_chandef_identical(&local->hw.conf.chandef, - &local->_oper_chandef)) { + /* force it also for scanning, since drivers might config differently */ + if (offchannel_flag || local->scanning || + !cfg80211_chandef_identical(&local->hw.conf.chandef, &chandef)) { local->hw.conf.chandef = chandef; changed |= IEEE80211_CONF_CHANGE_CHANNEL; } @@ -140,8 +161,8 @@ static u32 ieee80211_hw_conf_chan(struct ieee80211_local *local) * that otherwise STATIC is used. */ local->hw.conf.smps_mode = IEEE80211_SMPS_STATIC; - } else if (local->hw.conf.smps_mode != local->smps_mode) { - local->hw.conf.smps_mode = local->smps_mode; + } else if (local->hw.conf.smps_mode != smps_mode) { + local->hw.conf.smps_mode = smps_mode; changed |= IEEE80211_CONF_CHANGE_SMPS; } @@ -173,12 +194,9 @@ int ieee80211_hw_config(struct ieee80211_local *local, u32 changed) might_sleep(); - if (!local->use_chanctx) - changed |= ieee80211_hw_conf_chan(local); - else - changed &= ~(IEEE80211_CONF_CHANGE_CHANNEL | - IEEE80211_CONF_CHANGE_POWER | - IEEE80211_CONF_CHANGE_SMPS); + WARN_ON(changed & (IEEE80211_CONF_CHANGE_CHANNEL | + IEEE80211_CONF_CHANGE_POWER | + IEEE80211_CONF_CHANGE_SMPS)); if (changed && local->open_count) { ret = drv_config(local, changed); @@ -202,6 +220,107 @@ int ieee80211_hw_config(struct ieee80211_local *local, u32 changed) return ret; } +/* for scanning, offchannel and chanctx emulation only */ +static int _ieee80211_hw_conf_chan(struct ieee80211_local *local, + struct ieee80211_chanctx_conf *ctx) +{ + u32 changed; + + if (!local->open_count) + return 0; + + changed = ieee80211_calc_hw_conf_chan(local, ctx); + if (!changed) + return 0; + + return drv_config(local, changed); +} + +int ieee80211_hw_conf_chan(struct ieee80211_local *local) +{ + struct ieee80211_chanctx *ctx; + + ctx = list_first_entry_or_null(&local->chanctx_list, + struct ieee80211_chanctx, + list); + + return _ieee80211_hw_conf_chan(local, ctx ? &ctx->conf : NULL); +} + +void ieee80211_hw_conf_init(struct ieee80211_local *local) +{ + u32 changed = ~(IEEE80211_CONF_CHANGE_CHANNEL | + IEEE80211_CONF_CHANGE_POWER | + IEEE80211_CONF_CHANGE_SMPS); + + if (WARN_ON(!local->open_count)) + return; + + if (local->emulate_chanctx) { + struct ieee80211_chanctx *ctx; + + ctx = list_first_entry_or_null(&local->chanctx_list, + struct ieee80211_chanctx, + list); + + changed |= ieee80211_calc_hw_conf_chan(local, + ctx ? &ctx->conf : NULL); + } + + WARN_ON(drv_config(local, changed)); +} + +int ieee80211_emulate_add_chanctx(struct ieee80211_hw *hw, + struct ieee80211_chanctx_conf *ctx) +{ + struct ieee80211_local *local = hw_to_local(hw); + + local->hw.conf.radar_enabled = ctx->radar_enabled; + + return _ieee80211_hw_conf_chan(local, ctx); +} +EXPORT_SYMBOL(ieee80211_emulate_add_chanctx); + +void ieee80211_emulate_remove_chanctx(struct ieee80211_hw *hw, + struct ieee80211_chanctx_conf *ctx) +{ + struct ieee80211_local *local = hw_to_local(hw); + + local->hw.conf.radar_enabled = false; + + _ieee80211_hw_conf_chan(local, NULL); +} +EXPORT_SYMBOL(ieee80211_emulate_remove_chanctx); + +void ieee80211_emulate_change_chanctx(struct ieee80211_hw *hw, + struct ieee80211_chanctx_conf *ctx, + u32 changed) +{ + struct ieee80211_local *local = hw_to_local(hw); + + local->hw.conf.radar_enabled = ctx->radar_enabled; + + _ieee80211_hw_conf_chan(local, ctx); +} +EXPORT_SYMBOL(ieee80211_emulate_change_chanctx); + +int ieee80211_emulate_switch_vif_chanctx(struct ieee80211_hw *hw, + struct ieee80211_vif_chanctx_switch *vifs, + int n_vifs, + enum ieee80211_chanctx_switch_mode mode) +{ + struct ieee80211_local *local = hw_to_local(hw); + + if (n_vifs <= 0) + return -EINVAL; + + local->hw.conf.radar_enabled = vifs[0].new_ctx->radar_enabled; + _ieee80211_hw_conf_chan(local, vifs[0].new_ctx); + + return 0; +} +EXPORT_SYMBOL(ieee80211_emulate_switch_vif_chanctx); + #define BSS_CHANGED_VIF_CFG_FLAGS (BSS_CHANGED_ASSOC |\ BSS_CHANGED_IDLE |\ BSS_CHANGED_PS |\ @@ -645,7 +764,7 @@ struct ieee80211_hw *ieee80211_alloc_hw_nm(size_t priv_data_len, struct ieee80211_local *local; int priv_size, i; struct wiphy *wiphy; - bool use_chanctx; + bool emulate_chanctx; if (WARN_ON(!ops->tx || !ops->start || !ops->stop || !ops->config || !ops->add_interface || !ops->remove_interface || @@ -660,12 +779,26 @@ struct ieee80211_hw *ieee80211_alloc_hw_nm(size_t priv_data_len, return NULL; /* check all or no channel context operations exist */ - i = !!ops->add_chanctx + !!ops->remove_chanctx + - !!ops->change_chanctx + !!ops->assign_vif_chanctx + - !!ops->unassign_vif_chanctx; - if (WARN_ON(i != 0 && i != 5)) - return NULL; - use_chanctx = i == 5; + if (ops->add_chanctx == ieee80211_emulate_add_chanctx && + ops->remove_chanctx == ieee80211_emulate_remove_chanctx && + ops->change_chanctx == ieee80211_emulate_change_chanctx) { + if (WARN_ON(ops->assign_vif_chanctx || + ops->unassign_vif_chanctx)) + return NULL; + emulate_chanctx = true; + } else { + if (WARN_ON(ops->add_chanctx == ieee80211_emulate_add_chanctx || + ops->remove_chanctx == ieee80211_emulate_remove_chanctx || + ops->change_chanctx == ieee80211_emulate_change_chanctx)) + return NULL; + if (WARN_ON(!ops->add_chanctx || + !ops->remove_chanctx || + !ops->change_chanctx || + !ops->assign_vif_chanctx || + !ops->unassign_vif_chanctx)) + return NULL; + emulate_chanctx = false; + } /* Ensure 32-byte alignment of our private data and hw private data. * We use the wiphy priv data for both our ieee80211_local and for @@ -699,7 +832,7 @@ struct ieee80211_hw *ieee80211_alloc_hw_nm(size_t priv_data_len, WIPHY_FLAG_REPORTS_OBSS | WIPHY_FLAG_OFFCHAN_TX; - if (!use_chanctx || ops->remain_on_channel) + if (emulate_chanctx || ops->remain_on_channel) wiphy->flags |= WIPHY_FLAG_HAS_REMAIN_ON_CHANNEL; wiphy->features |= NL80211_FEATURE_SK_TX_STATUS | @@ -756,7 +889,10 @@ struct ieee80211_hw *ieee80211_alloc_hw_nm(size_t priv_data_len, local->hw.priv = (char *)local + ALIGN(sizeof(*local), NETDEV_ALIGN); local->ops = ops; - local->use_chanctx = use_chanctx; + local->emulate_chanctx = emulate_chanctx; + + if (emulate_chanctx) + ieee80211_hw_set(&local->hw, CHANCTX_STA_CSA); /* * We need a bit of data queued to build aggregates properly, so @@ -833,7 +969,6 @@ struct ieee80211_hw *ieee80211_alloc_hw_nm(size_t priv_data_len, ieee80211_dfs_radar_detected_work); wiphy_work_init(&local->reconfig_filter, ieee80211_reconfig_filter); - local->smps_mode = IEEE80211_SMPS_OFF; wiphy_work_init(&local->dynamic_ps_enable_work, ieee80211_dynamic_ps_enable_work); @@ -984,7 +1119,7 @@ int ieee80211_register_hw(struct ieee80211_hw *hw) * as much, e.g. monitoring beacons would be hard if we * might not even know which link is active at which time. */ - if (WARN_ON(!local->use_chanctx)) + if (WARN_ON(local->emulate_chanctx)) return -EINVAL; if (WARN_ON(!local->ops->link_info_changed)) @@ -1028,7 +1163,7 @@ int ieee80211_register_hw(struct ieee80211_hw *hw) return -EINVAL; #endif - if (!local->use_chanctx) { + if (local->emulate_chanctx) { for (i = 0; i < local->hw.wiphy->n_iface_combinations; i++) { const struct ieee80211_iface_combination *comb; @@ -1094,11 +1229,11 @@ int ieee80211_register_hw(struct ieee80211_hw *hw) &sband->channels[i], NL80211_CHAN_NO_HT); /* init channel we're on */ - if (!local->use_chanctx && !local->_oper_chandef.chan) { + local->monitor_chandef = dflt_chandef; + if (local->emulate_chanctx) { + local->dflt_chandef = dflt_chandef; local->hw.conf.chandef = dflt_chandef; - local->_oper_chandef = dflt_chandef; } - local->monitor_chandef = dflt_chandef; } channels += sband->n_channels; diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c index 7c0339d4f059..9968bc0ddf6e 100644 --- a/net/mac80211/mlme.c +++ b/net/mac80211/mlme.c @@ -2287,8 +2287,7 @@ ieee80211_sta_process_chanswitch(struct ieee80211_link_data *link, chanctx = container_of(conf, struct ieee80211_chanctx, conf); - if (local->use_chanctx && - !ieee80211_hw_check(&local->hw, CHANCTX_STA_CSA)) { + if (!ieee80211_hw_check(&local->hw, CHANCTX_STA_CSA)) { sdata_info(sdata, "driver doesn't support chan-switch with channel contexts\n"); goto drop_connection; diff --git a/net/mac80211/offchannel.c b/net/mac80211/offchannel.c index 6c4080202573..221695d841fd 100644 --- a/net/mac80211/offchannel.c +++ b/net/mac80211/offchannel.c @@ -86,7 +86,7 @@ void ieee80211_offchannel_stop_vifs(struct ieee80211_local *local) lockdep_assert_wiphy(local->hw.wiphy); - if (WARN_ON(local->use_chanctx)) + if (WARN_ON(!local->emulate_chanctx)) return; /* @@ -136,7 +136,7 @@ void ieee80211_offchannel_return(struct ieee80211_local *local) lockdep_assert_wiphy(local->hw.wiphy); - if (WARN_ON(local->use_chanctx)) + if (WARN_ON(!local->emulate_chanctx)) return; list_for_each_entry(sdata, &local->interfaces, list) { @@ -351,10 +351,13 @@ static void _ieee80211_start_next_roc(struct ieee80211_local *local) * 20 MHz channel width) don't stop all the operations but still * treat it as though the ROC operation started properly, so * other ROC operations won't interfere with this one. + * + * Note: scan can't run, tmp_channel is what we use, so this + * must be the currently active channel. */ - roc->on_channel = roc->chan == local->_oper_chandef.chan && - local->_oper_chandef.width != NL80211_CHAN_WIDTH_5 && - local->_oper_chandef.width != NL80211_CHAN_WIDTH_10; + roc->on_channel = roc->chan == local->hw.conf.chandef.chan && + local->hw.conf.chandef.width != NL80211_CHAN_WIDTH_5 && + local->hw.conf.chandef.width != NL80211_CHAN_WIDTH_10; /* start this ROC */ ieee80211_recalc_idle(local); @@ -363,7 +366,7 @@ static void _ieee80211_start_next_roc(struct ieee80211_local *local) ieee80211_offchannel_stop_vifs(local); local->tmp_channel = roc->chan; - ieee80211_hw_config(local, 0); + ieee80211_hw_conf_chan(local); } wiphy_delayed_work_queue(local->hw.wiphy, &local->roc_work, @@ -426,7 +429,7 @@ static void __ieee80211_roc_work(struct ieee80211_local *local) return; if (!roc->started) { - WARN_ON(local->use_chanctx); + WARN_ON(!local->emulate_chanctx); _ieee80211_start_next_roc(local); } else { on_channel = roc->on_channel; @@ -439,7 +442,7 @@ static void __ieee80211_roc_work(struct ieee80211_local *local) ieee80211_flush_queues(local, NULL, false); local->tmp_channel = NULL; - ieee80211_hw_config(local, 0); + ieee80211_hw_conf_chan(local); ieee80211_offchannel_return(local); } @@ -539,7 +542,7 @@ static int ieee80211_start_roc_work(struct ieee80211_local *local, /* this may work, but is untested */ return -EOPNOTSUPP; - if (local->use_chanctx && !local->ops->remain_on_channel) + if (!local->emulate_chanctx && !local->ops->remain_on_channel) return -EOPNOTSUPP; roc = kzalloc(sizeof(*roc), GFP_KERNEL); diff --git a/net/mac80211/scan.c b/net/mac80211/scan.c index 81644d15fe2f..6dedbbba153a 100644 --- a/net/mac80211/scan.c +++ b/net/mac80211/scan.c @@ -476,7 +476,7 @@ static void __ieee80211_scan_completed(struct ieee80211_hw *hw, bool aborted) } /* Set power back to normal operating levels. */ - ieee80211_hw_config(local, 0); + ieee80211_hw_conf_chan(local); if (!hw_scan && was_scanning) { ieee80211_configure_filter(local); @@ -523,7 +523,7 @@ static int ieee80211_start_sw_scan(struct ieee80211_local *local, struct ieee80211_sub_if_data *sdata) { /* Software scan is not supported in multi-channel cases */ - if (local->use_chanctx) + if (!local->emulate_chanctx) return -EOPNOTSUPP; /* @@ -553,7 +553,7 @@ static int ieee80211_start_sw_scan(struct ieee80211_local *local, ieee80211_configure_filter(local); /* We need to set power level at maximum rate for scanning. */ - ieee80211_hw_config(local, 0); + ieee80211_hw_conf_chan(local); wiphy_delayed_work_queue(local->hw.wiphy, &local->scan_work, 0); @@ -790,7 +790,7 @@ static int __ieee80211_start_scan(struct ieee80211_sub_if_data *sdata, if (hw_scan) { __set_bit(SCAN_HW_SCANNING, &local->scanning); } else if ((req->n_channels == 1) && - (req->channels[0] == local->_oper_chandef.chan)) { + (req->channels[0] == local->hw.conf.chandef.chan)) { /* * If we are scanning only on the operating channel * then we do not need to stop normal activities @@ -808,7 +808,7 @@ static int __ieee80211_start_scan(struct ieee80211_sub_if_data *sdata, ieee80211_configure_filter(local); /* accept probe-responses */ /* We need to ensure power level is at max for scanning. */ - ieee80211_hw_config(local, 0); + ieee80211_hw_conf_chan(local); if ((req->channels[0]->flags & (IEEE80211_CHAN_NO_IR | IEEE80211_CHAN_RADAR)) || @@ -973,13 +973,13 @@ static void ieee80211_scan_state_set_channel(struct ieee80211_local *local, /* If scanning on oper channel, use whatever channel-type * is currently in use. */ - if (chan == local->_oper_chandef.chan) - local->scan_chandef = local->_oper_chandef; + if (chan == local->hw.conf.chandef.chan) + local->scan_chandef = local->hw.conf.chandef; else local->scan_chandef.width = NL80211_CHAN_WIDTH_20_NOHT; set_channel: - if (ieee80211_hw_config(local, IEEE80211_CONF_CHANGE_CHANNEL)) + if (ieee80211_hw_conf_chan(local)) skip = 1; /* advance state machine to next channel/band */ @@ -1023,7 +1023,7 @@ static void ieee80211_scan_state_suspend(struct ieee80211_local *local, { /* switch back to the operating channel */ local->scan_chandef.chan = NULL; - ieee80211_hw_config(local, IEEE80211_CONF_CHANGE_CHANNEL); + ieee80211_hw_conf_chan(local); /* disable PS */ ieee80211_offchannel_return(local); diff --git a/net/mac80211/tx.c b/net/mac80211/tx.c index 7b33942ea51f..f57f7963ca37 100644 --- a/net/mac80211/tx.c +++ b/net/mac80211/tx.c @@ -2390,8 +2390,6 @@ netdev_tx_t ieee80211_monitor_start_xmit(struct sk_buff *skb, if (chanctx_conf) chandef = &chanctx_conf->def; - else if (!local->use_chanctx) - chandef = &local->_oper_chandef; else goto fail_rcu; diff --git a/net/mac80211/util.c b/net/mac80211/util.c index 1a2522e699d4..51c1a99f57b8 100644 --- a/net/mac80211/util.c +++ b/net/mac80211/util.c @@ -2472,9 +2472,6 @@ static void ieee80211_assign_chanctx(struct ieee80211_local *local, lockdep_assert_wiphy(local->hw.wiphy); - if (!local->use_chanctx) - return; - conf = rcu_dereference_protected(link->conf->chanctx_conf, lockdep_is_held(&local->hw.wiphy->mtx)); if (conf) { @@ -2704,20 +2701,20 @@ int ieee80211_reconfig(struct ieee80211_local *local) } /* add channel contexts */ - if (local->use_chanctx) { - list_for_each_entry(ctx, &local->chanctx_list, list) - if (ctx->replace_state != - IEEE80211_CHANCTX_REPLACES_OTHER) - WARN_ON(drv_add_chanctx(local, ctx)); - - sdata = wiphy_dereference(local->hw.wiphy, - local->monitor_sdata); - if (sdata && ieee80211_sdata_running(sdata)) - ieee80211_assign_chanctx(local, sdata, &sdata->deflink); - } + list_for_each_entry(ctx, &local->chanctx_list, list) + if (ctx->replace_state != IEEE80211_CHANCTX_REPLACES_OTHER) + WARN_ON(drv_add_chanctx(local, ctx)); + + sdata = wiphy_dereference(local->hw.wiphy, local->monitor_sdata); + if (sdata && ieee80211_sdata_running(sdata)) + ieee80211_assign_chanctx(local, sdata, &sdata->deflink); /* reconfigure hardware */ - ieee80211_hw_config(local, ~0); + ieee80211_hw_config(local, IEEE80211_CONF_CHANGE_LISTEN_INTERVAL | + IEEE80211_CONF_CHANGE_MONITOR | + IEEE80211_CONF_CHANGE_PS | + IEEE80211_CONF_CHANGE_RETRY_LIMITS | + IEEE80211_CONF_CHANGE_IDLE); ieee80211_configure_filter(local); -- cgit v1.2.3 From 6092077ad09ce880c61735c314060f0bd79ae4aa Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Mon, 29 Jan 2024 19:34:40 +0100 Subject: wifi: mac80211: introduce 'channel request' For channel contexts, mac80211 currently uses the cfg80211 chandef struct (control channel, center freq(s), width) to define towards drivers and internally how these behave. In fact, there are _two_ such structs used, where the min_def can reduce bandwidth according to the stations connected. Unfortunately, with EHT this is longer be sufficient, at least not for all hardware. EHT requires that non-AP STAs that are connected to an AP with a lower bandwidth than it (the AP) advertises (e.g. 160 MHz STA connected to 320 MHz AP) still be able to receive downlink OFDMA and respond to trigger frames for uplink OFDMA that specify the position and bandwidth for the non-AP STA relative to the channel the AP is using. Therefore, they need to be aware of this, and at least for some hardware (e.g. Intel) this awareness is in the hardware. As a result, use of the "same" channel may need to be split over two channel contexts where they differ by the AP being used. As a first step, introduce a concept of a channel request ('chanreq') for each interface, to control the context it requests. This step does nothing but reorganise the code, so that later the AP's chandef can be added to the request in order to handle the EHT case described above. Link: https://msgid.link/20240129194108.2e88e48bd2e9.I4256183debe975c5ed71621611206fdbb69ba330@changeid Signed-off-by: Johannes Berg --- drivers/net/wireless/intel/iwlwifi/mvm/mac-ctxt.c | 8 +- drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c | 12 +- .../net/wireless/intel/iwlwifi/mvm/mld-mac80211.c | 10 +- drivers/net/wireless/intel/iwlwifi/mvm/ops.c | 8 +- drivers/net/wireless/intel/iwlwifi/mvm/rs-fw.c | 6 +- drivers/net/wireless/intel/iwlwifi/mvm/sta.c | 4 +- drivers/net/wireless/intel/iwlwifi/mvm/tx.c | 4 +- drivers/net/wireless/mediatek/mt76/mt7915/mcu.c | 4 +- drivers/net/wireless/realtek/rtw89/mac.c | 4 +- drivers/net/wireless/rsi/rsi_91x_mac80211.c | 4 +- drivers/net/wireless/silabs/wfx/sta.c | 4 +- drivers/net/wireless/ti/wlcore/main.c | 6 +- drivers/staging/vt6655/device_main.c | 2 +- drivers/staging/vt6656/main_usb.c | 2 +- include/net/mac80211.h | 12 +- net/mac80211/agg-tx.c | 2 +- net/mac80211/cfg.c | 66 +++--- net/mac80211/chan.c | 233 +++++++++++---------- net/mac80211/ht.c | 2 +- net/mac80211/ibss.c | 36 ++-- net/mac80211/ieee80211_i.h | 21 +- net/mac80211/iface.c | 6 +- net/mac80211/link.c | 3 +- net/mac80211/main.c | 2 +- net/mac80211/mesh.c | 81 +++---- net/mac80211/mesh_plink.c | 4 +- net/mac80211/mlme.c | 87 ++++---- net/mac80211/ocb.c | 3 +- net/mac80211/rate.c | 12 +- net/mac80211/spectmgmt.c | 22 +- net/mac80211/tdls.c | 8 +- net/mac80211/trace.h | 6 +- net/mac80211/util.c | 18 +- net/mac80211/vht.c | 6 +- 34 files changed, 379 insertions(+), 329 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/mac-ctxt.c b/drivers/net/wireless/intel/iwlwifi/mvm/mac-ctxt.c index bcf78ccba8c1..61269c7b1934 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/mac-ctxt.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/mac-ctxt.c @@ -455,7 +455,7 @@ void iwl_mvm_set_fw_protection_flags(struct iwl_mvm *mvm, break; case IEEE80211_HT_OP_MODE_PROTECTION_20MHZ: /* Protect when channel wider than 20MHz */ - if (link_conf->chandef.width > NL80211_CHAN_WIDTH_20) + if (link_conf->chanreq.oper.width > NL80211_CHAN_WIDTH_20) *protection_flags |= cpu_to_le32(ht_flag); break; default: @@ -494,7 +494,7 @@ void iwl_mvm_set_fw_qos_params(struct iwl_mvm *mvm, struct ieee80211_vif *vif, if (link_conf->qos) *qos_flags |= cpu_to_le32(MAC_QOS_FLG_UPDATE_EDCA); - if (link_conf->chandef.width != NL80211_CHAN_WIDTH_20_NOHT) + if (link_conf->chanreq.oper.width != NL80211_CHAN_WIDTH_20_NOHT) *qos_flags |= cpu_to_le32(MAC_QOS_FLG_TGN); } @@ -910,8 +910,8 @@ u8 iwl_mvm_mac_ctxt_get_lowest_rate(struct iwl_mvm *mvm, link_conf = rcu_dereference(vif->link_conf[link_id]); if (link_conf) { basic = link_conf->basic_rates; - if (link_conf->chandef.chan) - band = link_conf->chandef.chan->band; + if (link_conf->chanreq.oper.chan) + band = link_conf->chanreq.oper.chan->band; } rcu_read_unlock(); } diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c b/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c index 93baec9bb3fc..65293b45a98f 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c @@ -1641,7 +1641,7 @@ static int iwl_mvm_mac_add_interface(struct ieee80211_hw *hw, if (vif->type == NL80211_IFTYPE_MONITOR) { mvm->monitor_on = true; mvm->monitor_p80 = - iwl_mvm_chandef_get_primary_80(&vif->bss_conf.chandef); + iwl_mvm_chandef_get_primary_80(&vif->bss_conf.chanreq.oper); } if (!test_bit(IWL_MVM_STATUS_IN_HW_RESTART, &mvm->status)) @@ -3421,16 +3421,16 @@ iwl_mvm_check_he_obss_narrow_bw_ru(struct ieee80211_hw *hw, .tolerated = true, }; - if (WARN_ON_ONCE(!link_conf->chandef.chan || + if (WARN_ON_ONCE(!link_conf->chanreq.oper.chan || !mvmvif->link[link_id])) return; - if (!(link_conf->chandef.chan->flags & IEEE80211_CHAN_RADAR)) { + if (!(link_conf->chanreq.oper.chan->flags & IEEE80211_CHAN_RADAR)) { mvmvif->link[link_id]->he_ru_2mhz_block = false; return; } - cfg80211_bss_iter(hw->wiphy, &link_conf->chandef, + cfg80211_bss_iter(hw->wiphy, &link_conf->chanreq.oper, iwl_mvm_check_he_obss_narrow_bw_ru_iter, &iter_data); @@ -3490,10 +3490,10 @@ static void iwl_mvm_mei_host_associated(struct iwl_mvm *mvm, return; /* FIXME: MEI needs to be updated for MLO */ - if (!vif->bss_conf.chandef.chan) + if (!vif->bss_conf.chanreq.oper.chan) return; - conn_info.channel = vif->bss_conf.chandef.chan->hw_value; + conn_info.channel = vif->bss_conf.chanreq.oper.chan->hw_value; switch (mvm_sta->pairwise_cipher) { case WLAN_CIPHER_SUITE_TKIP: diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/mld-mac80211.c b/drivers/net/wireless/intel/iwlwifi/mvm/mld-mac80211.c index ff7d9a7d607e..b633a2a09c32 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/mld-mac80211.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/mld-mac80211.c @@ -656,8 +656,8 @@ void iwl_mvm_mld_select_links(struct iwl_mvm *mvm, struct ieee80211_vif *vif, continue; data[n_data].link_id = link_id; - data[n_data].band = link_conf->chandef.chan->band; - data[n_data].width = link_conf->chandef.width; + data[n_data].band = link_conf->chanreq.oper.chan->band; + data[n_data].width = link_conf->chanreq.oper.width; data[n_data].active = vif->active_links & BIT(link_id); n_data++; } @@ -1241,8 +1241,8 @@ int iwl_mvm_mld_get_primary_link(struct iwl_mvm *mvm, continue; data[n_data].link_id = link_id; - data[n_data].band = link_conf->chandef.chan->band; - data[n_data].width = link_conf->chandef.width; + data[n_data].band = link_conf->chanreq.oper.chan->band; + data[n_data].width = link_conf->chanreq.oper.width; data[n_data].active = true; n_data++; } @@ -1292,7 +1292,7 @@ static bool iwl_mvm_can_enter_esr(struct iwl_mvm *mvm, continue; /* BT Coex effects eSR mode only if one of the link is on LB */ - if (link_conf->chandef.chan->band != NL80211_BAND_2GHZ) + if (link_conf->chanreq.oper.chan->band != NL80211_BAND_2GHZ) continue; ret = iwl_mvm_bt_coex_calculate_esr_mode(mvm, vif, link_id, diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/ops.c b/drivers/net/wireless/intel/iwlwifi/mvm/ops.c index 747fc91ef8d0..ad4146d3345a 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/ops.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/ops.c @@ -161,9 +161,9 @@ static void iwl_mvm_rx_monitor_notif(struct iwl_mvm *mvm, if (!vif || vif->type != NL80211_IFTYPE_STATION) return; - if (!vif->bss_conf.chandef.chan || - vif->bss_conf.chandef.chan->band != NL80211_BAND_2GHZ || - vif->bss_conf.chandef.width < NL80211_CHAN_WIDTH_40) + if (!vif->bss_conf.chanreq.oper.chan || + vif->bss_conf.chanreq.oper.chan->band != NL80211_BAND_2GHZ || + vif->bss_conf.chanreq.oper.width < NL80211_CHAN_WIDTH_40) return; if (!vif->cfg.assoc) @@ -219,7 +219,7 @@ void iwl_mvm_update_link_smps(struct ieee80211_vif *vif, return; if (mvm->fw_static_smps_request && - link_conf->chandef.width == NL80211_CHAN_WIDTH_160 && + link_conf->chanreq.oper.width == NL80211_CHAN_WIDTH_160 && link_conf->he_support) mode = IEEE80211_SMPS_STATIC; diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/rs-fw.c b/drivers/net/wireless/intel/iwlwifi/mvm/rs-fw.c index 6cba8a353b53..71d92635d6d7 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/rs-fw.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/rs-fw.c @@ -525,10 +525,10 @@ u16 rs_fw_get_max_amsdu_len(struct ieee80211_sta *sta, const struct ieee80211_sta_ht_cap *ht_cap = &link_sta->ht_cap; const struct ieee80211_sta_eht_cap *eht_cap = &link_sta->eht_cap; - if (WARN_ON_ONCE(!link_conf->chandef.chan)) + if (WARN_ON_ONCE(!link_conf->chanreq.oper.chan)) return IEEE80211_MAX_MPDU_LEN_VHT_3895; - if (link_conf->chandef.chan->band == NL80211_BAND_6GHZ) { + if (link_conf->chanreq.oper.chan->band == NL80211_BAND_6GHZ) { switch (le16_get_bits(link_sta->he_6ghz_capa.capa, IEEE80211_HE_6GHZ_CAP_MAX_MPDU_LEN)) { case IEEE80211_VHT_CAP_MAX_MPDU_LENGTH_11454: @@ -538,7 +538,7 @@ u16 rs_fw_get_max_amsdu_len(struct ieee80211_sta *sta, default: return IEEE80211_MAX_MPDU_LEN_VHT_3895; } - } else if (link_conf->chandef.chan->band == NL80211_BAND_2GHZ && + } else if (link_conf->chanreq.oper.chan->band == NL80211_BAND_2GHZ && eht_cap->has_eht) { switch (u8_get_bits(eht_cap->eht_cap_elem.mac_cap_info[0], IEEE80211_EHT_MAC_CAP0_MAX_MPDU_LEN_MASK)) { diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/sta.c b/drivers/net/wireless/intel/iwlwifi/mvm/sta.c index 8ffbb8efda73..7e9f3a670212 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/sta.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/sta.c @@ -71,7 +71,7 @@ u32 iwl_mvm_get_sta_ampdu_dens(struct ieee80211_link_sta *link_sta, mpdu_dens = link_sta->ht_cap.ampdu_density; } - if (link_conf->chandef.chan->band == NL80211_BAND_6GHZ) { + if (link_conf->chanreq.oper.chan->band == NL80211_BAND_6GHZ) { /* overwrite HT values on 6 GHz */ mpdu_dens = le16_get_bits(link_sta->he_6ghz_capa.capa, IEEE80211_HE_6GHZ_CAP_MIN_MPDU_START); @@ -208,7 +208,7 @@ int iwl_mvm_sta_send_to_fw(struct iwl_mvm *mvm, struct ieee80211_sta *sta, } if (sta->deflink.ht_cap.ht_supported || - mvm_sta->vif->bss_conf.chandef.chan->band == NL80211_BAND_6GHZ) + mvm_sta->vif->bss_conf.chanreq.oper.chan->band == NL80211_BAND_6GHZ) add_sta_cmd.station_flags_msk |= cpu_to_le32(STA_FLG_MAX_AGG_SIZE_MSK | STA_FLG_AGG_MPDU_DENS_MSK); diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/tx.c b/drivers/net/wireless/intel/iwlwifi/mvm/tx.c index 79eb6394e5a7..58d1f283d628 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/tx.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/tx.c @@ -894,10 +894,10 @@ unsigned int iwl_mvm_max_amsdu_size(struct iwl_mvm *mvm, if (WARN_ON(!link_conf)) band = NL80211_BAND_2GHZ; else - band = link_conf->chandef.chan->band; + band = link_conf->chanreq.oper.chan->band; rcu_read_unlock(); } else { - band = mvmsta->vif->bss_conf.chandef.chan->band; + band = mvmsta->vif->bss_conf.chanreq.oper.chan->band; } lmac = iwl_mvm_get_lmac_id(mvm, band); diff --git a/drivers/net/wireless/mediatek/mt76/mt7915/mcu.c b/drivers/net/wireless/mediatek/mt76/mt7915/mcu.c index c67c4f6ca2aa..df1ad6d4e12d 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7915/mcu.c +++ b/drivers/net/wireless/mediatek/mt76/mt7915/mcu.c @@ -463,10 +463,10 @@ static bool mt7915_check_he_obss_narrow_bw_ru(struct ieee80211_hw *hw, .tolerated = true, }; - if (!(vif->bss_conf.chandef.chan->flags & IEEE80211_CHAN_RADAR)) + if (!(vif->bss_conf.chanreq.oper.chan->flags & IEEE80211_CHAN_RADAR)) return false; - cfg80211_bss_iter(hw->wiphy, &vif->bss_conf.chandef, + cfg80211_bss_iter(hw->wiphy, &vif->bss_conf.chanreq.oper, mt7915_check_he_obss_narrow_bw_ru_iter, &iter_data); diff --git a/drivers/net/wireless/realtek/rtw89/mac.c b/drivers/net/wireless/realtek/rtw89/mac.c index dbf2d6fe4ea7..ef4c492003d8 100644 --- a/drivers/net/wireless/realtek/rtw89/mac.c +++ b/drivers/net/wireless/realtek/rtw89/mac.c @@ -4615,10 +4615,10 @@ void rtw89_mac_set_he_obss_narrow_bw_ru(struct rtw89_dev *rtwdev, if (!vif->bss_conf.he_support || vif->type != NL80211_IFTYPE_STATION) return; - if (!(vif->bss_conf.chandef.chan->flags & IEEE80211_CHAN_RADAR)) + if (!(vif->bss_conf.chanreq.oper.chan->flags & IEEE80211_CHAN_RADAR)) return; - cfg80211_bss_iter(hw->wiphy, &vif->bss_conf.chandef, + cfg80211_bss_iter(hw->wiphy, &vif->bss_conf.chanreq.oper, rtw89_mac_check_he_obss_narrow_bw_ru_iter, &tolerated); diff --git a/drivers/net/wireless/rsi/rsi_91x_mac80211.c b/drivers/net/wireless/rsi/rsi_91x_mac80211.c index e8aeb4d76c13..211fa25b9a78 100644 --- a/drivers/net/wireless/rsi/rsi_91x_mac80211.c +++ b/drivers/net/wireless/rsi/rsi_91x_mac80211.c @@ -740,7 +740,7 @@ u16 rsi_get_connected_channel(struct ieee80211_vif *vif) return 0; bss = &vif->bss_conf; - channel = bss->chandef.chan; + channel = bss->chanreq.oper.chan; if (!channel) return 0; @@ -759,7 +759,7 @@ static void rsi_switch_channel(struct rsi_hw *adapter, if (!vif) return; - channel = vif->bss_conf.chandef.chan; + channel = vif->bss_conf.chanreq.oper.chan; if (!channel) return; diff --git a/drivers/net/wireless/silabs/wfx/sta.c b/drivers/net/wireless/silabs/wfx/sta.c index bb4446b88c12..a904602f02ce 100644 --- a/drivers/net/wireless/silabs/wfx/sta.c +++ b/drivers/net/wireless/silabs/wfx/sta.c @@ -144,13 +144,13 @@ static int wfx_get_ps_timeout(struct wfx_vif *wvif, bool *enable_ps) struct wfx_vif *wvif_ch0 = wdev_to_wvif(wvif->wdev, 0); struct ieee80211_vif *vif_ch0 = wvif_to_vif(wvif_ch0); - chan0 = vif_ch0->bss_conf.chandef.chan; + chan0 = vif_ch0->bss_conf.chanreq.oper.chan; } if (wdev_to_wvif(wvif->wdev, 1)) { struct wfx_vif *wvif_ch1 = wdev_to_wvif(wvif->wdev, 1); struct ieee80211_vif *vif_ch1 = wvif_to_vif(wvif_ch1); - chan1 = vif_ch1->bss_conf.chandef.chan; + chan1 = vif_ch1->bss_conf.chanreq.oper.chan; } if (chan0 && chan1 && vif->type != NL80211_IFTYPE_AP) { if (chan0->hw_value == chan1->hw_value) { diff --git a/drivers/net/wireless/ti/wlcore/main.c b/drivers/net/wireless/ti/wlcore/main.c index 5736acb4d206..ef12169f8044 100644 --- a/drivers/net/wireless/ti/wlcore/main.c +++ b/drivers/net/wireless/ti/wlcore/main.c @@ -2910,7 +2910,7 @@ static int wlcore_set_assoc(struct wl1271 *wl, struct wl12xx_vif *wlvif, int ret; wlvif->aid = vif->cfg.aid; - wlvif->channel_type = cfg80211_get_chandef_type(&bss_conf->chandef); + wlvif->channel_type = cfg80211_get_chandef_type(&bss_conf->chanreq.oper); wlvif->beacon_int = bss_conf->beacon_int; wlvif->wmm_enabled = bss_conf->qos; @@ -4242,7 +4242,7 @@ static void wl1271_bss_info_changed_ap(struct wl1271 *wl, /* Handle HT information change */ if ((changed & BSS_CHANGED_HT) && - (bss_conf->chandef.width != NL80211_CHAN_WIDTH_20_NOHT)) { + (bss_conf->chanreq.oper.width != NL80211_CHAN_WIDTH_20_NOHT)) { ret = wl1271_acx_set_ht_information(wl, wlvif, bss_conf->ht_operation_mode); if (ret < 0) { @@ -4515,7 +4515,7 @@ static void wl1271_bss_info_changed_sta(struct wl1271 *wl, /* Handle new association with HT. Do this after join. */ if (sta_exists) { bool enabled = - bss_conf->chandef.width != NL80211_CHAN_WIDTH_20_NOHT; + bss_conf->chanreq.oper.width != NL80211_CHAN_WIDTH_20_NOHT; ret = wlcore_hw_set_peer_cap(wl, &sta_ht_cap, diff --git a/drivers/staging/vt6655/device_main.c b/drivers/staging/vt6655/device_main.c index e23a5da2b67e..283804b49e91 100644 --- a/drivers/staging/vt6655/device_main.c +++ b/drivers/staging/vt6655/device_main.c @@ -1515,7 +1515,7 @@ static void vnt_bss_info_changed(struct ieee80211_hw *hw, if (changed & BSS_CHANGED_TXPOWER) RFbSetPower(priv, priv->wCurrentRate, - conf->chandef.chan->hw_value); + conf->chanreq.oper.chan->hw_value); if (changed & BSS_CHANGED_BEACON_ENABLED) { dev_dbg(&priv->pcid->dev, diff --git a/drivers/staging/vt6656/main_usb.c b/drivers/staging/vt6656/main_usb.c index 6c70493d1b01..7bbed462f062 100644 --- a/drivers/staging/vt6656/main_usb.c +++ b/drivers/staging/vt6656/main_usb.c @@ -794,7 +794,7 @@ static void vnt_bss_info_changed(struct ieee80211_hw *hw, vnt_set_bss_mode(priv); if (changed & (BSS_CHANGED_TXPOWER | BSS_CHANGED_BANDWIDTH)) - vnt_rf_setpower(priv, conf->chandef.chan); + vnt_rf_setpower(priv, conf->chanreq.oper.chan); if (changed & BSS_CHANGED_BEACON_ENABLED) { dev_dbg(&priv->usb->dev, diff --git a/include/net/mac80211.h b/include/net/mac80211.h index 62c4b4d10bb4..dd8a66e9afd9 100644 --- a/include/net/mac80211.h +++ b/include/net/mac80211.h @@ -223,6 +223,14 @@ enum ieee80211_chanctx_change { IEEE80211_CHANCTX_CHANGE_MIN_WIDTH = BIT(4), }; +/** + * struct ieee80211_chan_req - A channel "request" + * @oper: channel definition to use for operation + */ +struct ieee80211_chan_req { + struct cfg80211_chan_def oper; +}; + /** * struct ieee80211_chanctx_conf - channel context that vifs may be tuned to * @@ -583,7 +591,7 @@ struct ieee80211_fils_discovery { * @mcast_rate: per-band multicast rate index + 1 (0: disabled) * @bssid: The BSSID for this BSS * @enable_beacon: whether beaconing should be enabled or not - * @chandef: Channel definition for this BSS -- the hardware might be + * @chanreq: Channel request for this BSS -- the hardware might be * configured a higher bandwidth than this BSS uses, for example. * @mu_group: VHT MU-MIMO group membership data * @ht_operation_mode: HT operation mode like in &struct ieee80211_ht_operation. @@ -716,7 +724,7 @@ struct ieee80211_bss_conf { u32 cqm_rssi_hyst; s32 cqm_rssi_low; s32 cqm_rssi_high; - struct cfg80211_chan_def chandef; + struct ieee80211_chan_req chanreq; struct ieee80211_mu_group_data mu_group; bool qos; bool hidden_ssid; diff --git a/net/mac80211/agg-tx.c b/net/mac80211/agg-tx.c index b8a278355e18..21d55dc539f6 100644 --- a/net/mac80211/agg-tx.c +++ b/net/mac80211/agg-tx.c @@ -616,7 +616,7 @@ int ieee80211_start_tx_ba_session(struct ieee80211_sta *pubsta, u16 tid, return -EINVAL; if (!pubsta->deflink.ht_cap.ht_supported && - sta->sdata->vif.bss_conf.chandef.chan->band != NL80211_BAND_6GHZ) + sta->sdata->vif.bss_conf.chanreq.oper.chan->band != NL80211_BAND_6GHZ) return -EINVAL; if (WARN_ON_ONCE(!local->ops->ampdu_action)) diff --git a/net/mac80211/cfg.c b/net/mac80211/cfg.c index d3bf029709d5..5aa02b0872d9 100644 --- a/net/mac80211/cfg.c +++ b/net/mac80211/cfg.c @@ -886,11 +886,13 @@ static int ieee80211_set_monitor_channel(struct wiphy *wiphy, { struct ieee80211_local *local = wiphy_priv(wiphy); struct ieee80211_sub_if_data *sdata; + struct ieee80211_chan_req chanreq = { .oper = *chandef }; int ret; lockdep_assert_wiphy(local->hw.wiphy); - if (cfg80211_chandef_identical(&local->monitor_chandef, chandef)) + if (cfg80211_chandef_identical(&local->monitor_chanreq.oper, + &chanreq.oper)) return 0; sdata = wiphy_dereference(local->hw.wiphy, @@ -898,17 +900,17 @@ static int ieee80211_set_monitor_channel(struct wiphy *wiphy, if (!sdata) goto done; - if (cfg80211_chandef_identical(&sdata->vif.bss_conf.chandef, chandef)) + if (cfg80211_chandef_identical(&sdata->vif.bss_conf.chanreq.oper, + &chanreq.oper)) return 0; ieee80211_link_release_channel(&sdata->deflink); - ret = ieee80211_link_use_channel(&sdata->deflink, - chandef, + ret = ieee80211_link_use_channel(&sdata->deflink, &chanreq, IEEE80211_CHANCTX_EXCLUSIVE); if (ret) return ret; done: - local->monitor_chandef = *chandef; + local->monitor_chanreq = chanreq; return 0; } @@ -1257,6 +1259,7 @@ static int ieee80211_start_ap(struct wiphy *wiphy, struct net_device *dev, unsigned int link_id = params->beacon.link_id; struct ieee80211_link_data *link; struct ieee80211_bss_conf *link_conf; + struct ieee80211_chan_req chanreq = { .oper = params->chandef }; lockdep_assert_wiphy(local->hw.wiphy); @@ -1369,7 +1372,7 @@ static int ieee80211_start_ap(struct wiphy *wiphy, struct net_device *dev, return err; } - err = ieee80211_link_use_channel(link, ¶ms->chandef, + err = ieee80211_link_use_channel(link, &chanreq, IEEE80211_CHANCTX_SHARED); if (!err) ieee80211_link_copy_chanctx_to_vlans(link, false); @@ -1626,7 +1629,7 @@ static int ieee80211_stop_ap(struct wiphy *wiphy, struct net_device *dev, BSS_CHANGED_BEACON_ENABLED); if (sdata->wdev.cac_started) { - chandef = link_conf->chandef; + chandef = link_conf->chanreq.oper; wiphy_delayed_work_cancel(wiphy, &link->dfs_cac_timer_work); cfg80211_cac_event(sdata->dev, &chandef, NL80211_RADAR_CAC_ABORTED, @@ -1826,7 +1829,7 @@ static int sta_link_apply_parameters(struct ieee80211_local *local, if (params->supported_rates && params->supported_rates_len) { - ieee80211_parse_bitrates(link->conf->chandef.width, + ieee80211_parse_bitrates(link->conf->chanreq.oper.width, sband, params->supported_rates, params->supported_rates_len, &link_sta->pub->supp_rates[sband->band]); @@ -2602,6 +2605,7 @@ static int ieee80211_join_mesh(struct wiphy *wiphy, struct net_device *dev, const struct mesh_setup *setup) { struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); + struct ieee80211_chan_req chanreq = { .oper = setup->chandef }; struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh; int err; @@ -2618,7 +2622,7 @@ static int ieee80211_join_mesh(struct wiphy *wiphy, struct net_device *dev, sdata->deflink.smps_mode = IEEE80211_SMPS_OFF; sdata->deflink.needed_rx_chains = sdata->local->rx_chains; - err = ieee80211_link_use_channel(&sdata->deflink, &setup->chandef, + err = ieee80211_link_use_channel(&sdata->deflink, &chanreq, IEEE80211_CHANCTX_SHARED); if (err) return err; @@ -2661,7 +2665,7 @@ static int ieee80211_change_bss(struct wiphy *wiphy, return -EINVAL; if (params->basic_rates) { - if (!ieee80211_parse_bitrates(link->conf->chandef.width, + if (!ieee80211_parse_bitrates(link->conf->chanreq.oper.width, wiphy->bands[sband->band], params->basic_rates, params->basic_rates_len, @@ -3176,7 +3180,7 @@ int __ieee80211_request_smps_mgd(struct ieee80211_sub_if_data *sdata, * the new value until we associate. */ if (!sdata->u.mgd.associated || - link->conf->chandef.width == NL80211_CHAN_WIDTH_20_NOHT) + link->conf->chanreq.oper.width == NL80211_CHAN_WIDTH_20_NOHT) return 0; ap = sdata->vif.cfg.ap_addr; @@ -3331,9 +3335,11 @@ static int ieee80211_set_bitrate_mask(struct wiphy *wiphy, * so at a basic rate so that all clients can receive it. */ if (rcu_access_pointer(sdata->vif.bss_conf.chanctx_conf) && - sdata->vif.bss_conf.chandef.chan) { + sdata->vif.bss_conf.chanreq.oper.chan) { u32 basic_rates = sdata->vif.bss_conf.basic_rates; - enum nl80211_band band = sdata->vif.bss_conf.chandef.chan->band; + enum nl80211_band band; + + band = sdata->vif.bss_conf.chanreq.oper.chan->band; if (!(mask->control[band].legacy & basic_rates)) return -EINVAL; @@ -3385,6 +3391,7 @@ static int ieee80211_start_radar_detection(struct wiphy *wiphy, u32 cac_time_ms) { struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); + struct ieee80211_chan_req chanreq = { .oper = *chandef }; struct ieee80211_local *local = sdata->local; int err; @@ -3399,7 +3406,7 @@ static int ieee80211_start_radar_detection(struct wiphy *wiphy, sdata->deflink.smps_mode = IEEE80211_SMPS_OFF; sdata->deflink.needed_rx_chains = local->rx_chains; - err = ieee80211_link_use_channel(&sdata->deflink, chandef, + err = ieee80211_link_use_channel(&sdata->deflink, &chanreq, IEEE80211_CHANCTX_SHARED); if (err) goto out_unlock; @@ -3651,8 +3658,8 @@ static int __ieee80211_csa_finalize(struct ieee80211_link_data *link_data) return ieee80211_link_use_reserved_context(&sdata->deflink); } - if (!cfg80211_chandef_identical(&link_data->conf->chandef, - &link_data->csa_chandef)) + if (!cfg80211_chandef_identical(&link_data->conf->chanreq.oper, + &link_data->csa_chanreq.oper)) return -EINVAL; sdata->vif.bss_conf.csa_active = false; @@ -3679,7 +3686,7 @@ static int __ieee80211_csa_finalize(struct ieee80211_link_data *link_data) if (err) return err; - cfg80211_ch_switch_notify(sdata->dev, &link_data->csa_chandef, + cfg80211_ch_switch_notify(sdata->dev, &link_data->csa_chanreq.oper, link_data->link_id, link_data->conf->eht_puncturing); @@ -3814,7 +3821,7 @@ static int ieee80211_set_csa_beacon(struct ieee80211_sub_if_data *sdata, struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh; /* changes into another band are not supported */ - if (sdata->vif.bss_conf.chandef.chan->band != + if (sdata->vif.bss_conf.chanreq.oper.chan->band != params->chandef.chan->band) return -EINVAL; @@ -3862,6 +3869,7 @@ __ieee80211_channel_switch(struct wiphy *wiphy, struct net_device *dev, struct cfg80211_csa_settings *params) { struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); + struct ieee80211_chan_req chanreq = { .oper = params->chandef }; struct ieee80211_local *local = sdata->local; struct ieee80211_channel_switch ch_switch; struct ieee80211_chanctx_conf *conf; @@ -3877,8 +3885,8 @@ __ieee80211_channel_switch(struct wiphy *wiphy, struct net_device *dev, if (sdata->wdev.cac_started) return -EBUSY; - if (cfg80211_chandef_identical(¶ms->chandef, - &sdata->vif.bss_conf.chandef)) + if (cfg80211_chandef_identical(&chanreq.oper, + &sdata->vif.bss_conf.chanreq.oper)) return -EINVAL; /* don't allow another channel switch if one is already active. */ @@ -3903,14 +3911,14 @@ __ieee80211_channel_switch(struct wiphy *wiphy, struct net_device *dev, ch_switch.timestamp = 0; ch_switch.device_timestamp = 0; ch_switch.block_tx = params->block_tx; - ch_switch.chandef = params->chandef; + ch_switch.chandef = chanreq.oper; ch_switch.count = params->count; err = drv_pre_channel_switch(sdata, &ch_switch); if (err) goto out; - err = ieee80211_link_reserve_chanctx(&sdata->deflink, ¶ms->chandef, + err = ieee80211_link_reserve_chanctx(&sdata->deflink, &chanreq, chanctx->mode, params->radar_required); if (err) @@ -3936,7 +3944,7 @@ __ieee80211_channel_switch(struct wiphy *wiphy, struct net_device *dev, if (params->punct_bitmap && !sdata->vif.bss_conf.eht_support) goto out; - sdata->deflink.csa_chandef = params->chandef; + sdata->deflink.csa_chanreq = chanreq; sdata->deflink.csa_block_tx = params->block_tx; sdata->vif.bss_conf.csa_active = true; sdata->vif.bss_conf.csa_punct_bitmap = params->punct_bitmap; @@ -3946,14 +3954,15 @@ __ieee80211_channel_switch(struct wiphy *wiphy, struct net_device *dev, IEEE80211_QUEUE_STOP_REASON_CSA); cfg80211_ch_switch_started_notify(sdata->dev, - &sdata->deflink.csa_chandef, 0, + &sdata->deflink.csa_chanreq.oper, 0, params->count, params->block_tx, sdata->vif.bss_conf.csa_punct_bitmap); if (changed) { ieee80211_link_info_change_notify(sdata, &sdata->deflink, changed); - drv_channel_switch_beacon(sdata, ¶ms->chandef); + drv_channel_switch_beacon(sdata, + &sdata->deflink.csa_chanreq.oper); } else { /* if the beacon didn't change, we can finalize immediately */ ieee80211_csa_finalize(&sdata->deflink); @@ -4206,12 +4215,12 @@ static int ieee80211_cfg_get_channel(struct wiphy *wiphy, chanctx_conf = rcu_dereference(link->conf->chanctx_conf); if (chanctx_conf) { - *chandef = link->conf->chandef; + *chandef = link->conf->chanreq.oper; ret = 0; } else if (local->open_count > 0 && local->open_count == local->monitors && sdata->vif.type == NL80211_IFTYPE_MONITOR) { - *chandef = local->monitor_chandef; + *chandef = local->monitor_chanreq.oper; ret = 0; } out: @@ -4259,12 +4268,13 @@ static int ieee80211_set_ap_chanwidth(struct wiphy *wiphy, { struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); struct ieee80211_link_data *link; + struct ieee80211_chan_req chanreq = { .oper = *chandef }; int ret; u64 changed = 0; link = sdata_dereference(sdata->link[link_id], sdata); - ret = ieee80211_link_change_bandwidth(link, chandef, &changed); + ret = ieee80211_link_change_chanreq(link, &chanreq, &changed); if (ret == 0) ieee80211_link_info_change_notify(sdata, link, changed); diff --git a/net/mac80211/chan.c b/net/mac80211/chan.c index 6b82c79cf7a6..f1cef332e4db 100644 --- a/net/mac80211/chan.c +++ b/net/mac80211/chan.c @@ -81,87 +81,97 @@ ieee80211_link_get_chanctx(struct ieee80211_link_data *link) return container_of(conf, struct ieee80211_chanctx, conf); } -static const struct cfg80211_chan_def * -ieee80211_chanctx_reserved_chandef(struct ieee80211_local *local, +static const struct ieee80211_chan_req * +ieee80211_chanreq_compatible(const struct ieee80211_chan_req *a, + const struct ieee80211_chan_req *b) +{ + const struct cfg80211_chan_def *compat; + + compat = cfg80211_chandef_compatible(&a->oper, &b->oper); + + if (compat == &a->oper) + return a; + + if (compat == &b->oper) + return b; + + WARN_ON(compat); + return NULL; +} + +static const struct ieee80211_chan_req * +ieee80211_chanctx_compatible(struct ieee80211_chanctx *ctx, + const struct ieee80211_chan_req *req, + struct ieee80211_chan_req *tmp) +{ + *tmp = (struct ieee80211_chan_req){ + .oper = ctx->conf.def, + }; + + return ieee80211_chanreq_compatible(tmp, req); +} + +static const struct ieee80211_chan_req * +ieee80211_chanctx_reserved_chanreq(struct ieee80211_local *local, struct ieee80211_chanctx *ctx, - const struct cfg80211_chan_def *compat) + const struct ieee80211_chan_req *req) { struct ieee80211_link_data *link; lockdep_assert_wiphy(local->hw.wiphy); - if (WARN_ON(!compat)) + if (WARN_ON(!req)) return NULL; - list_for_each_entry(link, &ctx->reserved_links, - reserved_chanctx_list) { - compat = cfg80211_chandef_compatible(&link->reserved_chandef, - compat); - if (!compat) + list_for_each_entry(link, &ctx->reserved_links, reserved_chanctx_list) { + req = ieee80211_chanreq_compatible(&link->reserved, req); + if (!req) break; } - return compat; + return req; } -static const struct cfg80211_chan_def * +static const struct ieee80211_chan_req * ieee80211_chanctx_non_reserved_chandef(struct ieee80211_local *local, struct ieee80211_chanctx *ctx, - const struct cfg80211_chan_def *compat) + const struct ieee80211_chan_req *compat) { struct ieee80211_link_data *link; + const struct ieee80211_chan_req *comp_def = compat; lockdep_assert_wiphy(local->hw.wiphy); - list_for_each_entry(link, &ctx->assigned_links, - assigned_chanctx_list) { + list_for_each_entry(link, &ctx->assigned_links, assigned_chanctx_list) { struct ieee80211_bss_conf *link_conf = link->conf; if (link->reserved_chanctx) continue; - if (!compat) - compat = &link_conf->chandef; - - compat = cfg80211_chandef_compatible( - &link_conf->chandef, compat); - if (!compat) + comp_def = ieee80211_chanreq_compatible(&link_conf->chanreq, + comp_def); + if (!comp_def) break; } - return compat; -} - -static const struct cfg80211_chan_def * -ieee80211_chanctx_combined_chandef(struct ieee80211_local *local, - struct ieee80211_chanctx *ctx, - const struct cfg80211_chan_def *compat) -{ - lockdep_assert_wiphy(local->hw.wiphy); - - compat = ieee80211_chanctx_reserved_chandef(local, ctx, compat); - if (!compat) - return NULL; - - compat = ieee80211_chanctx_non_reserved_chandef(local, ctx, compat); - if (!compat) - return NULL; - - return compat; + return comp_def; } static bool -ieee80211_chanctx_can_reserve_chandef(struct ieee80211_local *local, - struct ieee80211_chanctx *ctx, - const struct cfg80211_chan_def *def) +ieee80211_chanctx_can_reserve(struct ieee80211_local *local, + struct ieee80211_chanctx *ctx, + const struct ieee80211_chan_req *req) { lockdep_assert_wiphy(local->hw.wiphy); - if (ieee80211_chanctx_combined_chandef(local, ctx, def)) - return true; + if (!ieee80211_chanctx_reserved_chanreq(local, ctx, req)) + return false; + + if (!ieee80211_chanctx_non_reserved_chandef(local, ctx, req)) + return false; if (!list_empty(&ctx->reserved_links) && - ieee80211_chanctx_reserved_chandef(local, ctx, def)) + ieee80211_chanctx_reserved_chanreq(local, ctx, req)) return true; return false; @@ -169,7 +179,7 @@ ieee80211_chanctx_can_reserve_chandef(struct ieee80211_local *local, static struct ieee80211_chanctx * ieee80211_find_reservation_chanctx(struct ieee80211_local *local, - const struct cfg80211_chan_def *chandef, + const struct ieee80211_chan_req *chanreq, enum ieee80211_chanctx_mode mode) { struct ieee80211_chanctx *ctx; @@ -186,8 +196,7 @@ ieee80211_find_reservation_chanctx(struct ieee80211_local *local, if (ctx->mode == IEEE80211_CHANCTX_EXCLUSIVE) continue; - if (!ieee80211_chanctx_can_reserve_chandef(local, ctx, - chandef)) + if (!ieee80211_chanctx_can_reserve(local, ctx, chanreq)) continue; return ctx; @@ -290,7 +299,7 @@ ieee80211_get_chanctx_vif_max_required_bw(struct ieee80211_sub_if_data *sdata, * point, so take the width from the chandef, but * account also for TDLS peers */ - width = max(link->conf->chandef.width, + width = max(link->conf->chanreq.oper.width, ieee80211_get_max_required_bw(sdata, link_id)); break; case NL80211_IFTYPE_P2P_DEVICE: @@ -299,7 +308,7 @@ ieee80211_get_chanctx_vif_max_required_bw(struct ieee80211_sub_if_data *sdata, case NL80211_IFTYPE_ADHOC: case NL80211_IFTYPE_MESH_POINT: case NL80211_IFTYPE_OCB: - width = link->conf->chandef.width; + width = link->conf->chanreq.oper.width; break; case NL80211_IFTYPE_WDS: case NL80211_IFTYPE_UNSPECIFIED: @@ -395,7 +404,7 @@ _ieee80211_recalc_chanctx_min_def(struct ieee80211_local *local, } /* calling this function is assuming that station vif is updated to - * lates changes by calling ieee80211_link_update_chandef + * lates changes by calling ieee80211_link_update_chanreq */ static void ieee80211_chan_bw_change(struct ieee80211_local *local, struct ieee80211_chanctx *ctx, @@ -475,9 +484,10 @@ void ieee80211_recalc_chanctx_min_def(struct ieee80211_local *local, static void _ieee80211_change_chanctx(struct ieee80211_local *local, struct ieee80211_chanctx *ctx, struct ieee80211_chanctx *old_ctx, - const struct cfg80211_chan_def *chandef, + const struct ieee80211_chan_req *chanreq, struct ieee80211_link_data *rsvd_for) { + const struct cfg80211_chan_def *chandef = &chanreq->oper; u32 changed; /* expected to handle only 20/40/80/160/320 channel widths */ @@ -526,16 +536,17 @@ static void _ieee80211_change_chanctx(struct ieee80211_local *local, static void ieee80211_change_chanctx(struct ieee80211_local *local, struct ieee80211_chanctx *ctx, struct ieee80211_chanctx *old_ctx, - const struct cfg80211_chan_def *chandef) + const struct ieee80211_chan_req *chanreq) { - _ieee80211_change_chanctx(local, ctx, old_ctx, chandef, NULL); + _ieee80211_change_chanctx(local, ctx, old_ctx, chanreq, NULL); } static struct ieee80211_chanctx * ieee80211_find_chanctx(struct ieee80211_local *local, - const struct cfg80211_chan_def *chandef, + const struct ieee80211_chan_req *chanreq, enum ieee80211_chanctx_mode mode) { + struct ieee80211_chan_req tmp; struct ieee80211_chanctx *ctx; lockdep_assert_wiphy(local->hw.wiphy); @@ -544,7 +555,7 @@ ieee80211_find_chanctx(struct ieee80211_local *local, return NULL; list_for_each_entry(ctx, &local->chanctx_list, list) { - const struct cfg80211_chan_def *compat; + const struct ieee80211_chan_req *compat; if (ctx->replace_state != IEEE80211_CHANCTX_REPLACE_NONE) continue; @@ -552,11 +563,11 @@ ieee80211_find_chanctx(struct ieee80211_local *local, if (ctx->mode == IEEE80211_CHANCTX_EXCLUSIVE) continue; - compat = cfg80211_chandef_compatible(&ctx->conf.def, chandef); + compat = ieee80211_chanctx_compatible(ctx, chanreq, &tmp); if (!compat) continue; - compat = ieee80211_chanctx_reserved_chandef(local, ctx, + compat = ieee80211_chanctx_reserved_chanreq(local, ctx, compat); if (!compat) continue; @@ -636,7 +647,7 @@ ieee80211_chanctx_radar_required(struct ieee80211_local *local, static struct ieee80211_chanctx * ieee80211_alloc_chanctx(struct ieee80211_local *local, - const struct cfg80211_chan_def *chandef, + const struct ieee80211_chan_req *chanreq, enum ieee80211_chanctx_mode mode) { struct ieee80211_chanctx *ctx; @@ -649,7 +660,7 @@ ieee80211_alloc_chanctx(struct ieee80211_local *local, INIT_LIST_HEAD(&ctx->assigned_links); INIT_LIST_HEAD(&ctx->reserved_links); - ctx->conf.def = *chandef; + ctx->conf.def = chanreq->oper; ctx->conf.rx_chains_static = 1; ctx->conf.rx_chains_dynamic = 1; ctx->mode = mode; @@ -685,7 +696,7 @@ static int ieee80211_add_chanctx(struct ieee80211_local *local, static struct ieee80211_chanctx * ieee80211_new_chanctx(struct ieee80211_local *local, - const struct cfg80211_chan_def *chandef, + const struct ieee80211_chan_req *chanreq, enum ieee80211_chanctx_mode mode) { struct ieee80211_chanctx *ctx; @@ -693,7 +704,7 @@ ieee80211_new_chanctx(struct ieee80211_local *local, lockdep_assert_wiphy(local->hw.wiphy); - ctx = ieee80211_alloc_chanctx(local, chandef, mode); + ctx = ieee80211_alloc_chanctx(local, chanreq, mode); if (!ctx) return ERR_PTR(-ENOMEM); @@ -737,6 +748,7 @@ void ieee80211_recalc_chanctx_chantype(struct ieee80211_local *local, struct ieee80211_chanctx_conf *conf = &ctx->conf; struct ieee80211_sub_if_data *sdata; const struct cfg80211_chan_def *compat = NULL; + struct ieee80211_chan_req chanreq = {}; struct sta_info *sta; lockdep_assert_wiphy(local->hw.wiphy); @@ -762,9 +774,9 @@ void ieee80211_recalc_chanctx_chantype(struct ieee80211_local *local, continue; if (!compat) - compat = &link_conf->chandef; + compat = &link_conf->chanreq.oper; - compat = cfg80211_chandef_compatible(&link_conf->chandef, + compat = cfg80211_chandef_compatible(&link_conf->chanreq.oper, compat); if (WARN_ON_ONCE(!compat)) break; @@ -794,7 +806,9 @@ void ieee80211_recalc_chanctx_chantype(struct ieee80211_local *local, if (!compat) return; - ieee80211_change_chanctx(local, ctx, ctx, compat); + chanreq.oper = *compat; + + ieee80211_change_chanctx(local, ctx, ctx, &chanreq); } static void ieee80211_recalc_radar_chanctx(struct ieee80211_local *local, @@ -1050,7 +1064,7 @@ int ieee80211_link_unreserve_chanctx(struct ieee80211_link_data *link) } int ieee80211_link_reserve_chanctx(struct ieee80211_link_data *link, - const struct cfg80211_chan_def *chandef, + const struct ieee80211_chan_req *chanreq, enum ieee80211_chanctx_mode mode, bool radar_required) { @@ -1064,10 +1078,10 @@ int ieee80211_link_reserve_chanctx(struct ieee80211_link_data *link, if (curr_ctx && !local->ops->switch_vif_chanctx) return -EOPNOTSUPP; - new_ctx = ieee80211_find_reservation_chanctx(local, chandef, mode); + new_ctx = ieee80211_find_reservation_chanctx(local, chanreq, mode); if (!new_ctx) { if (ieee80211_can_create_new_chanctx(local)) { - new_ctx = ieee80211_new_chanctx(local, chandef, mode); + new_ctx = ieee80211_new_chanctx(local, chanreq, mode); if (IS_ERR(new_ctx)) return PTR_ERR(new_ctx); } else { @@ -1121,7 +1135,7 @@ int ieee80211_link_reserve_chanctx(struct ieee80211_link_data *link, !list_empty(&curr_ctx->reserved_links)) return -EBUSY; - new_ctx = ieee80211_alloc_chanctx(local, chandef, mode); + new_ctx = ieee80211_alloc_chanctx(local, chanreq, mode); if (!new_ctx) return -ENOMEM; @@ -1139,7 +1153,7 @@ int ieee80211_link_reserve_chanctx(struct ieee80211_link_data *link, list_add(&link->reserved_chanctx_list, &new_ctx->reserved_links); link->reserved_chanctx = new_ctx; - link->reserved_chandef = *chandef; + link->reserved = *chanreq; link->reserved_radar_required = radar_required; link->reserved_ready = false; @@ -1178,14 +1192,14 @@ ieee80211_link_chanctx_reservation_complete(struct ieee80211_link_data *link) } static void -ieee80211_link_update_chandef(struct ieee80211_link_data *link, - const struct cfg80211_chan_def *chandef) +ieee80211_link_update_chanreq(struct ieee80211_link_data *link, + const struct ieee80211_chan_req *chanreq) { struct ieee80211_sub_if_data *sdata = link->sdata; unsigned int link_id = link->link_id; struct ieee80211_sub_if_data *vlan; - link->conf->chandef = *chandef; + link->conf->chanreq = *chanreq; if (sdata->vif.type != NL80211_IFTYPE_AP) return; @@ -1198,7 +1212,7 @@ ieee80211_link_update_chandef(struct ieee80211_link_data *link, if (WARN_ON(!vlan_conf)) continue; - vlan_conf->chandef = *chandef; + vlan_conf->chanreq = *chanreq; } rcu_read_unlock(); } @@ -1211,7 +1225,7 @@ ieee80211_link_use_reserved_reassign(struct ieee80211_link_data *link) struct ieee80211_local *local = sdata->local; struct ieee80211_vif_chanctx_switch vif_chsw[1] = {}; struct ieee80211_chanctx *old_ctx, *new_ctx; - const struct cfg80211_chan_def *chandef; + const struct ieee80211_chan_req *chanreq; u64 changed = 0; int err; @@ -1233,17 +1247,17 @@ ieee80211_link_use_reserved_reassign(struct ieee80211_link_data *link) IEEE80211_CHANCTX_REPLACES_OTHER)) return -EINVAL; - chandef = ieee80211_chanctx_non_reserved_chandef(local, new_ctx, - &link->reserved_chandef); - if (WARN_ON(!chandef)) + chanreq = ieee80211_chanctx_non_reserved_chandef(local, new_ctx, + &link->reserved); + if (WARN_ON(!chanreq)) return -EINVAL; - if (link_conf->chandef.width != link->reserved_chandef.width) + if (link_conf->chanreq.oper.width != link->reserved.oper.width) changed = BSS_CHANGED_BANDWIDTH; - ieee80211_link_update_chandef(link, &link->reserved_chandef); + ieee80211_link_update_chanreq(link, &link->reserved); - _ieee80211_change_chanctx(local, new_ctx, old_ctx, chandef, link); + _ieee80211_change_chanctx(local, new_ctx, old_ctx, chanreq, link); vif_chsw[0].vif = &sdata->vif; vif_chsw[0].old_ctx = &old_ctx->conf; @@ -1291,7 +1305,7 @@ ieee80211_link_use_reserved_assign(struct ieee80211_link_data *link) struct ieee80211_sub_if_data *sdata = link->sdata; struct ieee80211_local *local = sdata->local; struct ieee80211_chanctx *old_ctx, *new_ctx; - const struct cfg80211_chan_def *chandef; + const struct ieee80211_chan_req *chanreq; int err; old_ctx = ieee80211_link_get_chanctx(link); @@ -1310,12 +1324,12 @@ ieee80211_link_use_reserved_assign(struct ieee80211_link_data *link) IEEE80211_CHANCTX_REPLACES_OTHER)) return -EINVAL; - chandef = ieee80211_chanctx_non_reserved_chandef(local, new_ctx, - &link->reserved_chandef); - if (WARN_ON(!chandef)) + chanreq = ieee80211_chanctx_non_reserved_chandef(local, new_ctx, + &link->reserved); + if (WARN_ON(!chanreq)) return -EINVAL; - ieee80211_change_chanctx(local, new_ctx, new_ctx, chandef); + ieee80211_change_chanctx(local, new_ctx, new_ctx, chanreq); list_del(&link->reserved_chanctx_list); link->reserved_chanctx = NULL; @@ -1589,10 +1603,10 @@ static int ieee80211_vif_use_reserved_switch(struct ieee80211_local *local) link->radar_required = link->reserved_radar_required; - if (link_conf->chandef.width != link->reserved_chandef.width) + if (link_conf->chanreq.oper.width != link->reserved.oper.width) changed = BSS_CHANGED_BANDWIDTH; - ieee80211_link_update_chandef(link, &link->reserved_chandef); + ieee80211_link_update_chanreq(link, &link->reserved); if (changed) ieee80211_link_info_change_notify(sdata, link, @@ -1727,7 +1741,7 @@ static void __ieee80211_link_release_channel(struct ieee80211_link_data *link) } int ieee80211_link_use_channel(struct ieee80211_link_data *link, - const struct cfg80211_chan_def *chandef, + const struct ieee80211_chan_req *chanreq, enum ieee80211_chanctx_mode mode) { struct ieee80211_sub_if_data *sdata = link->sdata; @@ -1740,36 +1754,36 @@ int ieee80211_link_use_channel(struct ieee80211_link_data *link, if (sdata->vif.active_links && !(sdata->vif.active_links & BIT(link->link_id))) { - ieee80211_link_update_chandef(link, chandef); + ieee80211_link_update_chanreq(link, chanreq); return 0; } ret = cfg80211_chandef_dfs_required(local->hw.wiphy, - chandef, + &chanreq->oper, sdata->wdev.iftype); if (ret < 0) goto out; if (ret > 0) - radar_detect_width = BIT(chandef->width); + radar_detect_width = BIT(chanreq->oper.width); link->radar_required = ret; - ret = ieee80211_check_combinations(sdata, chandef, mode, + ret = ieee80211_check_combinations(sdata, &chanreq->oper, mode, radar_detect_width); if (ret < 0) goto out; __ieee80211_link_release_channel(link); - ctx = ieee80211_find_chanctx(local, chandef, mode); + ctx = ieee80211_find_chanctx(local, chanreq, mode); if (!ctx) - ctx = ieee80211_new_chanctx(local, chandef, mode); + ctx = ieee80211_new_chanctx(local, chanreq, mode); if (IS_ERR(ctx)) { ret = PTR_ERR(ctx); goto out; } - ieee80211_link_update_chandef(link, chandef); + ieee80211_link_update_chanreq(link, chanreq); ret = ieee80211_assign_link_chanctx(link, ctx); if (ret) { @@ -1849,28 +1863,33 @@ int ieee80211_link_use_reserved_context(struct ieee80211_link_data *link) return 0; } -int ieee80211_link_change_bandwidth(struct ieee80211_link_data *link, - const struct cfg80211_chan_def *chandef, - u64 *changed) +int ieee80211_link_change_chanreq(struct ieee80211_link_data *link, + const struct ieee80211_chan_req *chanreq, + u64 *changed) { struct ieee80211_sub_if_data *sdata = link->sdata; struct ieee80211_bss_conf *link_conf = link->conf; struct ieee80211_local *local = sdata->local; struct ieee80211_chanctx_conf *conf; struct ieee80211_chanctx *ctx; - const struct cfg80211_chan_def *compat; + const struct ieee80211_chan_req *compat; + struct ieee80211_chan_req tmp; lockdep_assert_wiphy(local->hw.wiphy); - if (!cfg80211_chandef_usable(sdata->local->hw.wiphy, chandef, + if (!cfg80211_chandef_usable(sdata->local->hw.wiphy, + &chanreq->oper, IEEE80211_CHAN_DISABLED)) return -EINVAL; - if (cfg80211_chandef_identical(chandef, &link_conf->chandef)) + /* for non-HT 20 MHz the rest doesn't matter */ + if (chanreq->oper.width == NL80211_CHAN_WIDTH_20_NOHT && + cfg80211_chandef_identical(&chanreq->oper, &link_conf->chanreq.oper)) return 0; - if (chandef->width == NL80211_CHAN_WIDTH_20_NOHT || - link_conf->chandef.width == NL80211_CHAN_WIDTH_20_NOHT) + /* but you cannot switch to/from it */ + if (chanreq->oper.width == NL80211_CHAN_WIDTH_20_NOHT || + link_conf->chanreq.oper.width == NL80211_CHAN_WIDTH_20_NOHT) return -EINVAL; conf = rcu_dereference_protected(link_conf->chanctx_conf, @@ -1880,13 +1899,13 @@ int ieee80211_link_change_bandwidth(struct ieee80211_link_data *link, ctx = container_of(conf, struct ieee80211_chanctx, conf); - compat = cfg80211_chandef_compatible(&conf->def, chandef); + compat = ieee80211_chanctx_compatible(ctx, chanreq, &tmp); if (!compat) return -EINVAL; switch (ctx->replace_state) { case IEEE80211_CHANCTX_REPLACE_NONE: - if (!ieee80211_chanctx_reserved_chandef(local, ctx, compat)) + if (!ieee80211_chanctx_reserved_chanreq(local, ctx, compat)) return -EBUSY; break; case IEEE80211_CHANCTX_WILL_BE_REPLACED: @@ -1901,7 +1920,7 @@ int ieee80211_link_change_bandwidth(struct ieee80211_link_data *link, break; } - ieee80211_link_update_chandef(link, chandef); + ieee80211_link_update_chanreq(link, chanreq); ieee80211_recalc_chanctx_chantype(local, ctx); diff --git a/net/mac80211/ht.c b/net/mac80211/ht.c index bccc99a00383..c3330aea4da3 100644 --- a/net/mac80211/ht.c +++ b/net/mac80211/ht.c @@ -257,7 +257,7 @@ bool ieee80211_ht_cap_ie_to_sta_ht_cap(struct ieee80211_sub_if_data *sdata, if (WARN_ON(!link_conf)) width = NL80211_CHAN_WIDTH_20_NOHT; else - width = link_conf->chandef.width; + width = link_conf->chanreq.oper.width; switch (width) { default: diff --git a/net/mac80211/ibss.c b/net/mac80211/ibss.c index c23f46218af7..27cc9ddd0432 100644 --- a/net/mac80211/ibss.c +++ b/net/mac80211/ibss.c @@ -223,7 +223,7 @@ static void __ieee80211_sta_join_ibss(struct ieee80211_sub_if_data *sdata, struct ieee80211_mgmt *mgmt; struct cfg80211_bss *bss; u64 bss_change; - struct cfg80211_chan_def chandef; + struct ieee80211_chan_req chanreq = {}; struct ieee80211_channel *chan; struct beacon_data *presp; struct cfg80211_inform_bss bss_meta = {}; @@ -257,22 +257,22 @@ static void __ieee80211_sta_join_ibss(struct ieee80211_sub_if_data *sdata, kfree_rcu(presp, rcu_head); /* make a copy of the chandef, it could be modified below. */ - chandef = *req_chandef; - chan = chandef.chan; - if (!cfg80211_reg_can_beacon(local->hw.wiphy, &chandef, + chanreq.oper = *req_chandef; + chan = chanreq.oper.chan; + if (!cfg80211_reg_can_beacon(local->hw.wiphy, &chanreq.oper, NL80211_IFTYPE_ADHOC)) { - if (chandef.width == NL80211_CHAN_WIDTH_5 || - chandef.width == NL80211_CHAN_WIDTH_10 || - chandef.width == NL80211_CHAN_WIDTH_20_NOHT || - chandef.width == NL80211_CHAN_WIDTH_20) { + if (chanreq.oper.width == NL80211_CHAN_WIDTH_5 || + chanreq.oper.width == NL80211_CHAN_WIDTH_10 || + chanreq.oper.width == NL80211_CHAN_WIDTH_20_NOHT || + chanreq.oper.width == NL80211_CHAN_WIDTH_20) { sdata_info(sdata, "Failed to join IBSS, beacons forbidden\n"); return; } - chandef.width = NL80211_CHAN_WIDTH_20; - chandef.center_freq1 = chan->center_freq; + chanreq.oper.width = NL80211_CHAN_WIDTH_20; + chanreq.oper.center_freq1 = chan->center_freq; /* check again for downgraded chandef */ - if (!cfg80211_reg_can_beacon(local->hw.wiphy, &chandef, + if (!cfg80211_reg_can_beacon(local->hw.wiphy, &chanreq.oper, NL80211_IFTYPE_ADHOC)) { sdata_info(sdata, "Failed to join IBSS, beacons forbidden\n"); @@ -281,7 +281,7 @@ static void __ieee80211_sta_join_ibss(struct ieee80211_sub_if_data *sdata, } err = cfg80211_chandef_dfs_required(sdata->local->hw.wiphy, - &chandef, NL80211_IFTYPE_ADHOC); + &chanreq.oper, NL80211_IFTYPE_ADHOC); if (err < 0) { sdata_info(sdata, "Failed to join IBSS, invalid chandef\n"); @@ -295,7 +295,7 @@ static void __ieee80211_sta_join_ibss(struct ieee80211_sub_if_data *sdata, radar_required = err; - if (ieee80211_link_use_channel(&sdata->deflink, &chandef, + if (ieee80211_link_use_channel(&sdata->deflink, &chanreq, ifibss->fixed_channel ? IEEE80211_CHANCTX_SHARED : IEEE80211_CHANCTX_EXCLUSIVE)) { @@ -307,7 +307,7 @@ static void __ieee80211_sta_join_ibss(struct ieee80211_sub_if_data *sdata, memcpy(ifibss->bssid, bssid, ETH_ALEN); presp = ieee80211_ibss_build_presp(sdata, beacon_int, basic_rates, - capability, tsf, &chandef, + capability, tsf, &chanreq.oper, &have_higher_than_11mbit, NULL); if (!presp) return; @@ -533,12 +533,12 @@ int ieee80211_ibss_finish_csa(struct ieee80211_sub_if_data *sdata, u64 *changed) IEEE80211_PRIVACY(ifibss->privacy)); /* XXX: should not really modify cfg80211 data */ if (cbss) { - cbss->channel = sdata->deflink.csa_chandef.chan; + cbss->channel = sdata->deflink.csa_chanreq.oper.chan; cfg80211_put_bss(sdata->local->hw.wiphy, cbss); } } - ifibss->chandef = sdata->deflink.csa_chandef; + ifibss->chandef = sdata->deflink.csa_chanreq.oper; /* generate the beacon */ return ieee80211_ibss_csa_beacon(sdata, NULL, changed); @@ -799,7 +799,7 @@ ieee80211_ibss_process_chanswitch(struct ieee80211_sub_if_data *sdata, goto disconnect; params.count = csa_ie.count; - params.chandef = csa_ie.chandef; + params.chandef = csa_ie.chanreq.oper; switch (ifibss->chandef.width) { case NL80211_CHAN_WIDTH_20_NOHT: @@ -858,7 +858,7 @@ ieee80211_ibss_process_chanswitch(struct ieee80211_sub_if_data *sdata, params.radar_required = err; if (cfg80211_chandef_identical(¶ms.chandef, - &sdata->vif.bss_conf.chandef)) { + &sdata->vif.bss_conf.chanreq.oper)) { ibss_dbg(sdata, "received csa with an identical chandef, ignoring\n"); return true; diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h index cb4684a9451e..70c48cad180a 100644 --- a/net/mac80211/ieee80211_i.h +++ b/net/mac80211/ieee80211_i.h @@ -884,6 +884,9 @@ struct ieee80211_chanctx { enum ieee80211_chanctx_mode mode; bool driver_present; + /* temporary data for search algorithm etc. */ + struct ieee80211_chan_req req; + struct ieee80211_chanctx_conf conf; }; @@ -1035,7 +1038,7 @@ struct ieee80211_link_data { bool operating_11g_mode; - struct cfg80211_chan_def csa_chandef; + struct ieee80211_chan_req csa_chanreq; struct wiphy_work color_change_finalize_work; struct delayed_work color_collision_detect_work; @@ -1043,7 +1046,7 @@ struct ieee80211_link_data { /* context reservation -- protected with wiphy mutex */ struct ieee80211_chanctx *reserved_chanctx; - struct cfg80211_chan_def reserved_chandef; + struct ieee80211_chan_req reserved; bool reserved_radar_required; bool reserved_ready; @@ -1574,7 +1577,7 @@ struct ieee80211_local { /* virtual monitor interface */ struct ieee80211_sub_if_data __rcu *monitor_sdata; - struct cfg80211_chan_def monitor_chandef; + struct ieee80211_chan_req monitor_chanreq; /* extended capabilities provided by mac80211 */ u8 ext_capa[8]; @@ -1639,7 +1642,7 @@ ieee80211_get_link_sband(struct ieee80211_link_data *link) /* this struct holds the value parsing from channel switch IE */ struct ieee80211_csa_ie { - struct cfg80211_chan_def chandef; + struct ieee80211_chan_req chanreq; u8 mode; u8 count; u8 ttl; @@ -2523,11 +2526,11 @@ void ieee80211_chandef_downgrade(struct cfg80211_chan_def *chandef, int __must_check ieee80211_link_use_channel(struct ieee80211_link_data *link, - const struct cfg80211_chan_def *chandef, + const struct ieee80211_chan_req *req, enum ieee80211_chanctx_mode mode); int __must_check ieee80211_link_reserve_chanctx(struct ieee80211_link_data *link, - const struct cfg80211_chan_def *chandef, + const struct ieee80211_chan_req *req, enum ieee80211_chanctx_mode mode, bool radar_required); int __must_check @@ -2535,9 +2538,9 @@ ieee80211_link_use_reserved_context(struct ieee80211_link_data *link); int ieee80211_link_unreserve_chanctx(struct ieee80211_link_data *link); int __must_check -ieee80211_link_change_bandwidth(struct ieee80211_link_data *link, - const struct cfg80211_chan_def *chandef, - u64 *changed); +ieee80211_link_change_chanreq(struct ieee80211_link_data *link, + const struct ieee80211_chan_req *req, + u64 *changed); void ieee80211_link_release_channel(struct ieee80211_link_data *link); void ieee80211_link_vlan_copy_chanctx(struct ieee80211_link_data *link); void ieee80211_link_copy_chanctx_to_vlans(struct ieee80211_link_data *link, diff --git a/net/mac80211/iface.c b/net/mac80211/iface.c index d81162bf7d48..227c8dc3fbe5 100644 --- a/net/mac80211/iface.c +++ b/net/mac80211/iface.c @@ -557,7 +557,7 @@ static void ieee80211_do_stop(struct ieee80211_sub_if_data *sdata, bool going_do &sdata->deflink.dfs_cac_timer_work); if (sdata->wdev.cac_started) { - chandef = sdata->vif.bss_conf.chandef; + chandef = sdata->vif.bss_conf.chanreq.oper; WARN_ON(local->suspended); ieee80211_link_release_channel(&sdata->deflink); cfg80211_cac_event(sdata->dev, &chandef, @@ -1164,7 +1164,7 @@ int ieee80211_add_virtual_monitor(struct ieee80211_local *local) rcu_assign_pointer(local->monitor_sdata, sdata); mutex_unlock(&local->iflist_mtx); - ret = ieee80211_link_use_channel(&sdata->deflink, &local->monitor_chandef, + ret = ieee80211_link_use_channel(&sdata->deflink, &local->monitor_chanreq, IEEE80211_CHANCTX_EXCLUSIVE); if (ret) { mutex_lock(&local->iflist_mtx); @@ -1252,7 +1252,7 @@ int ieee80211_do_open(struct wireless_dev *wdev, bool coming_up) sdata->vif.cab_queue = master->vif.cab_queue; memcpy(sdata->vif.hw_queue, master->vif.hw_queue, sizeof(sdata->vif.hw_queue)); - sdata->vif.bss_conf.chandef = master->vif.bss_conf.chandef; + sdata->vif.bss_conf.chanreq = master->vif.bss_conf.chanreq; sdata->crypto_tx_tailroom_needed_cnt += master->crypto_tx_tailroom_needed_cnt; diff --git a/net/mac80211/link.c b/net/mac80211/link.c index c0d05efcf6f8..2231eb38a211 100644 --- a/net/mac80211/link.c +++ b/net/mac80211/link.c @@ -402,7 +402,8 @@ static int _ieee80211_set_active_links(struct ieee80211_sub_if_data *sdata, link = sdata_dereference(sdata->link[link_id], sdata); - ret = ieee80211_link_use_channel(link, &link->conf->chandef, + ret = ieee80211_link_use_channel(link, + &link->conf->chanreq, IEEE80211_CHANCTX_SHARED); WARN_ON_ONCE(ret); diff --git a/net/mac80211/main.c b/net/mac80211/main.c index ce0cba8d7afc..879abe216a3e 100644 --- a/net/mac80211/main.c +++ b/net/mac80211/main.c @@ -1229,7 +1229,7 @@ int ieee80211_register_hw(struct ieee80211_hw *hw) &sband->channels[i], NL80211_CHAN_NO_HT); /* init channel we're on */ - local->monitor_chandef = dflt_chandef; + local->monitor_chanreq.oper = dflt_chandef; if (local->emulate_chanctx) { local->dflt_chandef = dflt_chandef; local->hw.conf.chandef = dflt_chandef; diff --git a/net/mac80211/mesh.c b/net/mac80211/mesh.c index 60dc453acb5a..e06d9ed2d31b 100644 --- a/net/mac80211/mesh.c +++ b/net/mac80211/mesh.c @@ -97,7 +97,7 @@ bool mesh_matches_local(struct ieee80211_sub_if_data *sdata, if (sdata->vif.bss_conf.basic_rates != basic_rates) return false; - cfg80211_chandef_create(&sta_chan_def, sdata->vif.bss_conf.chandef.chan, + cfg80211_chandef_create(&sta_chan_def, sdata->vif.bss_conf.chanreq.oper.chan, NL80211_CHAN_NO_HT); ieee80211_chandef_ht_oper(ie->ht_operation, &sta_chan_def); @@ -111,7 +111,7 @@ bool mesh_matches_local(struct ieee80211_sub_if_data *sdata, ie->eht_operation, &sta_chan_def); - if (!cfg80211_chandef_compatible(&sdata->vif.bss_conf.chandef, + if (!cfg80211_chandef_compatible(&sdata->vif.bss_conf.chanreq.oper, &sta_chan_def)) return false; @@ -436,9 +436,9 @@ int mesh_add_ht_cap_ie(struct ieee80211_sub_if_data *sdata, return 0; if (!sband->ht_cap.ht_supported || - sdata->vif.bss_conf.chandef.width == NL80211_CHAN_WIDTH_20_NOHT || - sdata->vif.bss_conf.chandef.width == NL80211_CHAN_WIDTH_5 || - sdata->vif.bss_conf.chandef.width == NL80211_CHAN_WIDTH_10) + sdata->vif.bss_conf.chanreq.oper.width == NL80211_CHAN_WIDTH_20_NOHT || + sdata->vif.bss_conf.chanreq.oper.width == NL80211_CHAN_WIDTH_5 || + sdata->vif.bss_conf.chanreq.oper.width == NL80211_CHAN_WIDTH_10) return 0; if (skb_tailroom(skb) < 2 + sizeof(struct ieee80211_ht_cap)) @@ -477,16 +477,16 @@ int mesh_add_ht_oper_ie(struct ieee80211_sub_if_data *sdata, return 0; if (!ht_cap->ht_supported || - sdata->vif.bss_conf.chandef.width == NL80211_CHAN_WIDTH_20_NOHT || - sdata->vif.bss_conf.chandef.width == NL80211_CHAN_WIDTH_5 || - sdata->vif.bss_conf.chandef.width == NL80211_CHAN_WIDTH_10) + sdata->vif.bss_conf.chanreq.oper.width == NL80211_CHAN_WIDTH_20_NOHT || + sdata->vif.bss_conf.chanreq.oper.width == NL80211_CHAN_WIDTH_5 || + sdata->vif.bss_conf.chanreq.oper.width == NL80211_CHAN_WIDTH_10) return 0; if (skb_tailroom(skb) < 2 + sizeof(struct ieee80211_ht_operation)) return -ENOMEM; pos = skb_put(skb, 2 + sizeof(struct ieee80211_ht_operation)); - ieee80211_ie_build_ht_oper(pos, ht_cap, &sdata->vif.bss_conf.chandef, + ieee80211_ie_build_ht_oper(pos, ht_cap, &sdata->vif.bss_conf.chanreq.oper, sdata->vif.bss_conf.ht_operation_mode, false); @@ -508,9 +508,9 @@ int mesh_add_vht_cap_ie(struct ieee80211_sub_if_data *sdata, return 0; if (!sband->vht_cap.vht_supported || - sdata->vif.bss_conf.chandef.width == NL80211_CHAN_WIDTH_20_NOHT || - sdata->vif.bss_conf.chandef.width == NL80211_CHAN_WIDTH_5 || - sdata->vif.bss_conf.chandef.width == NL80211_CHAN_WIDTH_10) + sdata->vif.bss_conf.chanreq.oper.width == NL80211_CHAN_WIDTH_20_NOHT || + sdata->vif.bss_conf.chanreq.oper.width == NL80211_CHAN_WIDTH_5 || + sdata->vif.bss_conf.chanreq.oper.width == NL80211_CHAN_WIDTH_10) return 0; if (skb_tailroom(skb) < 2 + sizeof(struct ieee80211_vht_cap)) @@ -549,9 +549,9 @@ int mesh_add_vht_oper_ie(struct ieee80211_sub_if_data *sdata, return 0; if (!vht_cap->vht_supported || - sdata->vif.bss_conf.chandef.width == NL80211_CHAN_WIDTH_20_NOHT || - sdata->vif.bss_conf.chandef.width == NL80211_CHAN_WIDTH_5 || - sdata->vif.bss_conf.chandef.width == NL80211_CHAN_WIDTH_10) + sdata->vif.bss_conf.chanreq.oper.width == NL80211_CHAN_WIDTH_20_NOHT || + sdata->vif.bss_conf.chanreq.oper.width == NL80211_CHAN_WIDTH_5 || + sdata->vif.bss_conf.chanreq.oper.width == NL80211_CHAN_WIDTH_10) return 0; if (skb_tailroom(skb) < 2 + sizeof(struct ieee80211_vht_operation)) @@ -559,7 +559,7 @@ int mesh_add_vht_oper_ie(struct ieee80211_sub_if_data *sdata, pos = skb_put(skb, 2 + sizeof(struct ieee80211_vht_operation)); ieee80211_ie_build_vht_oper(pos, vht_cap, - &sdata->vif.bss_conf.chandef); + &sdata->vif.bss_conf.chanreq.oper); return 0; } @@ -578,9 +578,9 @@ int mesh_add_he_cap_ie(struct ieee80211_sub_if_data *sdata, he_cap = ieee80211_get_he_iftype_cap(sband, NL80211_IFTYPE_MESH_POINT); if (!he_cap || - sdata->vif.bss_conf.chandef.width == NL80211_CHAN_WIDTH_20_NOHT || - sdata->vif.bss_conf.chandef.width == NL80211_CHAN_WIDTH_5 || - sdata->vif.bss_conf.chandef.width == NL80211_CHAN_WIDTH_10) + sdata->vif.bss_conf.chanreq.oper.width == NL80211_CHAN_WIDTH_20_NOHT || + sdata->vif.bss_conf.chanreq.oper.width == NL80211_CHAN_WIDTH_5 || + sdata->vif.bss_conf.chanreq.oper.width == NL80211_CHAN_WIDTH_10) return 0; if (skb_tailroom(skb) < ie_len) @@ -606,20 +606,20 @@ int mesh_add_he_oper_ie(struct ieee80211_sub_if_data *sdata, he_cap = ieee80211_get_he_iftype_cap(sband, NL80211_IFTYPE_MESH_POINT); if (!he_cap || - sdata->vif.bss_conf.chandef.width == NL80211_CHAN_WIDTH_20_NOHT || - sdata->vif.bss_conf.chandef.width == NL80211_CHAN_WIDTH_5 || - sdata->vif.bss_conf.chandef.width == NL80211_CHAN_WIDTH_10) + sdata->vif.bss_conf.chanreq.oper.width == NL80211_CHAN_WIDTH_20_NOHT || + sdata->vif.bss_conf.chanreq.oper.width == NL80211_CHAN_WIDTH_5 || + sdata->vif.bss_conf.chanreq.oper.width == NL80211_CHAN_WIDTH_10) return 0; len = 2 + 1 + sizeof(struct ieee80211_he_operation); - if (sdata->vif.bss_conf.chandef.chan->band == NL80211_BAND_6GHZ) + if (sdata->vif.bss_conf.chanreq.oper.chan->band == NL80211_BAND_6GHZ) len += sizeof(struct ieee80211_he_6ghz_oper); if (skb_tailroom(skb) < len) return -ENOMEM; pos = skb_put(skb, len); - ieee80211_ie_build_he_oper(pos, &sdata->vif.bss_conf.chandef); + ieee80211_ie_build_he_oper(pos, &sdata->vif.bss_conf.chanreq.oper); return 0; } @@ -659,9 +659,9 @@ int mesh_add_eht_cap_ie(struct ieee80211_sub_if_data *sdata, he_cap = ieee80211_get_he_iftype_cap(sband, NL80211_IFTYPE_MESH_POINT); eht_cap = ieee80211_get_eht_iftype_cap(sband, NL80211_IFTYPE_MESH_POINT); if (!he_cap || !eht_cap || - sdata->vif.bss_conf.chandef.width == NL80211_CHAN_WIDTH_20_NOHT || - sdata->vif.bss_conf.chandef.width == NL80211_CHAN_WIDTH_5 || - sdata->vif.bss_conf.chandef.width == NL80211_CHAN_WIDTH_10) + sdata->vif.bss_conf.chanreq.oper.width == NL80211_CHAN_WIDTH_20_NOHT || + sdata->vif.bss_conf.chanreq.oper.width == NL80211_CHAN_WIDTH_5 || + sdata->vif.bss_conf.chanreq.oper.width == NL80211_CHAN_WIDTH_10) return 0; if (skb_tailroom(skb) < ie_len) @@ -686,9 +686,9 @@ int mesh_add_eht_oper_ie(struct ieee80211_sub_if_data *sdata, struct sk_buff *sk eht_cap = ieee80211_get_eht_iftype_cap(sband, NL80211_IFTYPE_MESH_POINT); if (!eht_cap || - sdata->vif.bss_conf.chandef.width == NL80211_CHAN_WIDTH_20_NOHT || - sdata->vif.bss_conf.chandef.width == NL80211_CHAN_WIDTH_5 || - sdata->vif.bss_conf.chandef.width == NL80211_CHAN_WIDTH_10) + sdata->vif.bss_conf.chanreq.oper.width == NL80211_CHAN_WIDTH_20_NOHT || + sdata->vif.bss_conf.chanreq.oper.width == NL80211_CHAN_WIDTH_5 || + sdata->vif.bss_conf.chanreq.oper.width == NL80211_CHAN_WIDTH_10) return 0; len = 2 + 1 + offsetof(struct ieee80211_eht_operation, optional) + @@ -698,7 +698,7 @@ int mesh_add_eht_oper_ie(struct ieee80211_sub_if_data *sdata, struct sk_buff *sk return -ENOMEM; pos = skb_put(skb, len); - ieee80211_ie_build_eht_oper(pos, &sdata->vif.bss_conf.chandef, eht_cap); + ieee80211_ie_build_eht_oper(pos, &sdata->vif.bss_conf.chanreq.oper, eht_cap); return 0; } @@ -746,9 +746,9 @@ ieee80211_mesh_update_bss_params(struct ieee80211_sub_if_data *sdata, return; if (!ieee80211_get_he_iftype_cap(sband, NL80211_IFTYPE_MESH_POINT) || - sdata->vif.bss_conf.chandef.width == NL80211_CHAN_WIDTH_20_NOHT || - sdata->vif.bss_conf.chandef.width == NL80211_CHAN_WIDTH_5 || - sdata->vif.bss_conf.chandef.width == NL80211_CHAN_WIDTH_10) + sdata->vif.bss_conf.chanreq.oper.width == NL80211_CHAN_WIDTH_20_NOHT || + sdata->vif.bss_conf.chanreq.oper.width == NL80211_CHAN_WIDTH_5 || + sdata->vif.bss_conf.chanreq.oper.width == NL80211_CHAN_WIDTH_10) return; sdata->vif.bss_conf.he_support = true; @@ -1277,11 +1277,12 @@ static void ieee80211_mesh_csa_mark_radar(struct ieee80211_sub_if_data *sdata) * unavailable. */ err = cfg80211_chandef_dfs_required(sdata->local->hw.wiphy, - &sdata->vif.bss_conf.chandef, + &sdata->vif.bss_conf.chanreq.oper, NL80211_IFTYPE_MESH_POINT); if (err > 0) cfg80211_radar_event(sdata->local->hw.wiphy, - &sdata->vif.bss_conf.chandef, GFP_ATOMIC); + &sdata->vif.bss_conf.chanreq.oper, + GFP_ATOMIC); } static bool @@ -1302,7 +1303,7 @@ ieee80211_mesh_process_chnswitch(struct ieee80211_sub_if_data *sdata, if (!sband) return false; - switch (sdata->vif.bss_conf.chandef.width) { + switch (sdata->vif.bss_conf.chanreq.oper.width) { case NL80211_CHAN_WIDTH_20_NOHT: conn.mode = IEEE80211_CONN_MODE_LEGACY; conn.bw_limit = IEEE80211_CONN_BW_LIMIT_20; @@ -1339,7 +1340,7 @@ ieee80211_mesh_process_chnswitch(struct ieee80211_sub_if_data *sdata, if (csa_ie.reason_code == WLAN_REASON_MESH_CHAN_REGULATORY) ieee80211_mesh_csa_mark_radar(sdata); - params.chandef = csa_ie.chandef; + params.chandef = csa_ie.chanreq.oper; params.count = csa_ie.count; if (!cfg80211_chandef_usable(sdata->local->hw.wiphy, ¶ms.chandef, @@ -1375,7 +1376,7 @@ ieee80211_mesh_process_chnswitch(struct ieee80211_sub_if_data *sdata, params.radar_required = err; if (cfg80211_chandef_identical(¶ms.chandef, - &sdata->vif.bss_conf.chandef)) { + &sdata->vif.bss_conf.chanreq.oper)) { mcsa_dbg(sdata, "received csa with an identical chandef, ignoring\n"); return true; @@ -1555,7 +1556,7 @@ int ieee80211_mesh_finish_csa(struct ieee80211_sub_if_data *sdata, u64 *changed) *changed |= BSS_CHANGED_BEACON; mcsa_dbg(sdata, "complete switching to center freq %d MHz", - sdata->vif.bss_conf.chandef.chan->center_freq); + sdata->vif.bss_conf.chanreq.oper.chan->center_freq); return 0; } diff --git a/net/mac80211/mesh_plink.c b/net/mac80211/mesh_plink.c index 28bf794f67f8..e3aad60f68ab 100644 --- a/net/mac80211/mesh_plink.c +++ b/net/mac80211/mesh_plink.c @@ -163,7 +163,7 @@ static u64 mesh_set_ht_prot_mode(struct ieee80211_sub_if_data *sdata) u16 ht_opmode; bool non_ht_sta = false, ht20_sta = false; - switch (sdata->vif.bss_conf.chandef.width) { + switch (sdata->vif.bss_conf.chanreq.oper.width) { case NL80211_CHAN_WIDTH_20_NOHT: case NL80211_CHAN_WIDTH_5: case NL80211_CHAN_WIDTH_10: @@ -196,7 +196,7 @@ static u64 mesh_set_ht_prot_mode(struct ieee80211_sub_if_data *sdata) if (non_ht_sta) ht_opmode = IEEE80211_HT_OP_MODE_PROTECTION_NONHT_MIXED; else if (ht20_sta && - sdata->vif.bss_conf.chandef.width > NL80211_CHAN_WIDTH_20) + sdata->vif.bss_conf.chanreq.oper.width > NL80211_CHAN_WIDTH_20) ht_opmode = IEEE80211_HT_OP_MODE_PROTECTION_20MHZ; else ht_opmode = IEEE80211_HT_OP_MODE_PROTECTION_NONE; diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c index 9968bc0ddf6e..e9d720f25ddf 100644 --- a/net/mac80211/mlme.c +++ b/net/mac80211/mlme.c @@ -139,7 +139,7 @@ ieee80211_handle_puncturing_bitmap(struct ieee80211_link_data *link, const struct ieee80211_eht_operation *eht_oper, u16 bitmap, u64 *changed) { - struct cfg80211_chan_def *chandef = &link->conf->chandef; + struct cfg80211_chan_def *chandef = &link->conf->chanreq.oper; struct ieee80211_local *local = link->sdata->local; u16 extracted; u64 _changed = 0; @@ -862,8 +862,9 @@ static int ieee80211_config_bw(struct ieee80211_link_data *link, struct ieee802_11_elems *elems, u64 *changed) { - struct ieee80211_channel *channel = link->conf->chandef.chan; + struct ieee80211_channel *channel = link->conf->chanreq.oper.chan; struct ieee80211_sub_if_data *sdata = link->sdata; + struct ieee80211_chan_req chanreq = {}; struct cfg80211_chan_def ap_chandef; enum ieee80211_conn_mode ap_mode; u32 vht_cap_info = 0; @@ -913,7 +914,7 @@ static int ieee80211_config_bw(struct ieee80211_link_data *link, ieee80211_min_bw_limit_from_chandef(&ap_chandef)) ieee80211_chandef_downgrade(&ap_chandef, NULL); - if (cfg80211_chandef_identical(&ap_chandef, &link->conf->chandef)) + if (cfg80211_chandef_identical(&ap_chandef, &link->conf->chanreq.oper)) return 0; link_info(link, @@ -946,8 +947,9 @@ static int ieee80211_config_bw(struct ieee80211_link_data *link, * bandwidth changes where a this could happen, but those cases are * less common and wouldn't completely prevent using the AP. */ + chanreq.oper = ap_chandef; - ret = ieee80211_link_change_bandwidth(link, &ap_chandef, changed); + ret = ieee80211_link_change_chanreq(link, &chanreq, changed); if (ret) { sdata_info(sdata, "AP %pM changed bandwidth to incompatible one - disconnect\n", @@ -2069,8 +2071,8 @@ static void ieee80211_chswitch_work(struct wiphy *wiphy, return; } - if (!cfg80211_chandef_identical(&link->conf->chandef, - &link->csa_chandef)) { + if (!cfg80211_chandef_identical(&link->conf->chanreq.oper, + &link->csa_chanreq.oper)) { sdata_info(sdata, "failed to finalize channel switch, disconnecting\n"); wiphy_work_queue(sdata->local->hw.wiphy, @@ -2118,7 +2120,7 @@ static void ieee80211_chswitch_post_beacon(struct ieee80211_link_data *link) return; } - cfg80211_ch_switch_notify(sdata->dev, &link->reserved_chandef, + cfg80211_ch_switch_notify(sdata->dev, &link->reserved.oper, link->link_id, 0); } @@ -2211,7 +2213,7 @@ ieee80211_sta_process_chanswitch(struct ieee80211_link_data *link, ch_switch.timestamp = timestamp; ch_switch.device_timestamp = device_timestamp; ch_switch.block_tx = csa_ie.mode; - ch_switch.chandef = csa_ie.chandef; + ch_switch.chandef = csa_ie.chanreq.oper; ch_switch.count = csa_ie.count; ch_switch.delay = csa_ie.max_switch_time; } @@ -2231,34 +2233,36 @@ ieee80211_sta_process_chanswitch(struct ieee80211_link_data *link, return; } - if (link->conf->chandef.chan->band != - csa_ie.chandef.chan->band) { + if (link->conf->chanreq.oper.chan->band != + csa_ie.chanreq.oper.chan->band) { sdata_info(sdata, "AP %pM switches to different band (%d MHz, width:%d, CF1/2: %d/%d MHz), disconnecting\n", link->u.mgd.bssid, - csa_ie.chandef.chan->center_freq, - csa_ie.chandef.width, csa_ie.chandef.center_freq1, - csa_ie.chandef.center_freq2); + csa_ie.chanreq.oper.chan->center_freq, + csa_ie.chanreq.oper.width, + csa_ie.chanreq.oper.center_freq1, + csa_ie.chanreq.oper.center_freq2); goto drop_connection; } - if (!cfg80211_chandef_usable(local->hw.wiphy, &csa_ie.chandef, + if (!cfg80211_chandef_usable(local->hw.wiphy, &csa_ie.chanreq.oper, IEEE80211_CHAN_DISABLED)) { sdata_info(sdata, "AP %pM switches to unsupported channel " "(%d.%03d MHz, width:%d, CF1/2: %d.%03d/%d MHz), " "disconnecting\n", link->u.mgd.bssid, - csa_ie.chandef.chan->center_freq, - csa_ie.chandef.chan->freq_offset, - csa_ie.chandef.width, csa_ie.chandef.center_freq1, - csa_ie.chandef.freq1_offset, - csa_ie.chandef.center_freq2); + csa_ie.chanreq.oper.chan->center_freq, + csa_ie.chanreq.oper.chan->freq_offset, + csa_ie.chanreq.oper.width, + csa_ie.chanreq.oper.center_freq1, + csa_ie.chanreq.oper.freq1_offset, + csa_ie.chanreq.oper.center_freq2); goto drop_connection; } - if (cfg80211_chandef_identical(&csa_ie.chandef, - &link->conf->chandef) && + if (cfg80211_chandef_identical(&csa_ie.chanreq.oper, + &link->conf->chanreq.oper) && (!csa_ie.mode || !beacon)) { if (link->u.mgd.csa_ignored_same_chan) return; @@ -2299,7 +2303,7 @@ ieee80211_sta_process_chanswitch(struct ieee80211_link_data *link, goto drop_connection; } - res = ieee80211_link_reserve_chanctx(link, &csa_ie.chandef, + res = ieee80211_link_reserve_chanctx(link, &csa_ie.chanreq, chanctx->mode, false); if (res) { sdata_info(sdata, @@ -2309,7 +2313,7 @@ ieee80211_sta_process_chanswitch(struct ieee80211_link_data *link, } link->conf->csa_active = true; - link->csa_chandef = csa_ie.chandef; + link->csa_chanreq = csa_ie.chanreq; link->csa_block_tx = csa_ie.mode; link->u.mgd.csa_ignored_same_chan = false; link->u.mgd.beacon_crc_valid = false; @@ -2318,7 +2322,7 @@ ieee80211_sta_process_chanswitch(struct ieee80211_link_data *link, ieee80211_stop_vif_queues(local, sdata, IEEE80211_QUEUE_STOP_REASON_CSA); - cfg80211_ch_switch_started_notify(sdata->dev, &csa_ie.chandef, + cfg80211_ch_switch_started_notify(sdata->dev, &csa_ie.chanreq.oper, link->link_id, csa_ie.count, csa_ie.mode, 0); @@ -2741,7 +2745,7 @@ void ieee80211_dfs_cac_timer_work(struct wiphy *wiphy, struct wiphy_work *work) struct ieee80211_link_data *link = container_of(work, struct ieee80211_link_data, dfs_cac_timer_work.work); - struct cfg80211_chan_def chandef = link->conf->chandef; + struct cfg80211_chan_def chandef = link->conf->chanreq.oper; struct ieee80211_sub_if_data *sdata = link->sdata; lockdep_assert_wiphy(sdata->local->hw.wiphy); @@ -4508,11 +4512,11 @@ static bool ieee80211_assoc_config_link(struct ieee80211_link_data *link, goto out; } - if (WARN_ON(!link->conf->chandef.chan)) { + if (WARN_ON(!link->conf->chanreq.oper.chan)) { ret = false; goto out; } - sband = local->hw.wiphy->bands[link->conf->chandef.chan->band]; + sband = local->hw.wiphy->bands[link->conf->chanreq.oper.chan->band]; /* Set up internal HT/VHT capabilities */ if (elems->ht_cap_elem && link->u.mgd.conn.mode >= IEEE80211_CONN_MODE_HT) @@ -4580,7 +4584,7 @@ static bool ieee80211_assoc_config_link(struct ieee80211_link_data *link, } else if (is_6ghz) { link_info(link, "HE 6 GHz operation missing (on %d MHz), expect issues\n", - bss_conf->chandef.chan->center_freq); + bss_conf->chanreq.oper.chan->center_freq); } bss_conf->he_support = link_sta->pub->he_cap.has_he; @@ -5132,8 +5136,8 @@ static int ieee80211_prep_channel(struct ieee80211_sub_if_data *sdata, struct ieee80211_conn_settings *conn) { struct ieee80211_local *local = sdata->local; - struct cfg80211_chan_def chandef; bool is_6ghz = cbss->channel->band == NL80211_BAND_6GHZ; + struct ieee80211_chan_req chanreq = {}; struct ieee802_11_elems *elems; int ret; u32 i; @@ -5142,7 +5146,7 @@ static int ieee80211_prep_channel(struct ieee80211_sub_if_data *sdata, rcu_read_lock(); elems = ieee80211_determine_chan_mode(sdata, conn, cbss, link_id, - &chandef); + &chanreq.oper); if (IS_ERR(elems)) { rcu_read_unlock(); @@ -5196,17 +5200,18 @@ static int ieee80211_prep_channel(struct ieee80211_sub_if_data *sdata, * on incompatible channels, e.g. 80+80 and 160 sharing the * same control channel) try to use a smaller bandwidth. */ - ret = ieee80211_link_use_channel(link, &chandef, + ret = ieee80211_link_use_channel(link, &chanreq, IEEE80211_CHANCTX_SHARED); /* don't downgrade for 5 and 10 MHz channels, though. */ - if (chandef.width == NL80211_CHAN_WIDTH_5 || - chandef.width == NL80211_CHAN_WIDTH_10) + if (chanreq.oper.width == NL80211_CHAN_WIDTH_5 || + chanreq.oper.width == NL80211_CHAN_WIDTH_10) return ret; - while (ret && chandef.width != NL80211_CHAN_WIDTH_20_NOHT) { - ieee80211_chandef_downgrade(&chandef, conn); - ret = ieee80211_link_use_channel(link, &chandef, + while (ret && chanreq.oper.width != NL80211_CHAN_WIDTH_20_NOHT) { + ieee80211_chandef_downgrade(&chanreq.oper, conn); + + ret = ieee80211_link_use_channel(link, &chanreq, IEEE80211_CHANCTX_SHARED); } @@ -5862,7 +5867,7 @@ static bool ieee80211_config_puncturing(struct ieee80211_link_data *link, } extracted = ieee80211_extract_dis_subch_bmap(eht_oper, - &link->conf->chandef, + &link->conf->chanreq.oper, bitmap); /* accept if there are no changes */ @@ -5871,12 +5876,12 @@ static bool ieee80211_config_puncturing(struct ieee80211_link_data *link, return true; if (!cfg80211_valid_disable_subchannel_bitmap(&bitmap, - &link->conf->chandef)) { + &link->conf->chanreq.oper)) { link_info(link, "Got an invalid disable subchannel bitmap from AP %pM: bitmap = 0x%x, bw = 0x%x. disconnect\n", link->u.mgd.bssid, bitmap, - link->conf->chandef.width); + link->conf->chanreq.oper.width); return false; } @@ -6573,10 +6578,10 @@ static void ieee80211_rx_mgmt_beacon(struct ieee80211_link_data *link, goto free; } - if (WARN_ON(!link->conf->chandef.chan)) + if (WARN_ON(!link->conf->chanreq.oper.chan)) goto free; - sband = local->hw.wiphy->bands[link->conf->chandef.chan->band]; + sband = local->hw.wiphy->bands[link->conf->chanreq.oper.chan->band]; changed |= ieee80211_recalc_twt_req(sdata, sband, link, link_sta, elems); diff --git a/net/mac80211/ocb.c b/net/mac80211/ocb.c index 449af4e1cca4..2dd4a2196af4 100644 --- a/net/mac80211/ocb.c +++ b/net/mac80211/ocb.c @@ -168,6 +168,7 @@ void ieee80211_ocb_setup_sdata(struct ieee80211_sub_if_data *sdata) int ieee80211_ocb_join(struct ieee80211_sub_if_data *sdata, struct ocb_setup *setup) { + struct ieee80211_chan_req chanreq = { .oper = setup->chandef }; struct ieee80211_local *local = sdata->local; struct ieee80211_if_ocb *ifocb = &sdata->u.ocb; u64 changed = BSS_CHANGED_OCB | BSS_CHANGED_BSSID; @@ -182,7 +183,7 @@ int ieee80211_ocb_join(struct ieee80211_sub_if_data *sdata, sdata->deflink.smps_mode = IEEE80211_SMPS_OFF; sdata->deflink.needed_rx_chains = sdata->local->rx_chains; - err = ieee80211_link_use_channel(&sdata->deflink, &setup->chandef, + err = ieee80211_link_use_channel(&sdata->deflink, &chanreq, IEEE80211_CHANCTX_SHARED); if (err) return err; diff --git a/net/mac80211/rate.c b/net/mac80211/rate.c index d5ea5f5bcf3a..34e03b9522c8 100644 --- a/net/mac80211/rate.c +++ b/net/mac80211/rate.c @@ -4,7 +4,7 @@ * Copyright 2005-2006, Devicescape Software, Inc. * Copyright (c) 2006 Jiri Benc * Copyright 2017 Intel Deutschland GmbH - * Copyright (C) 2022 Intel Corporation + * Copyright (C) 2019, 2022-2024 Intel Corporation */ #include @@ -278,10 +278,10 @@ void ieee80211_check_rate_mask(struct ieee80211_link_data *link) u32 user_mask, basic_rates = link->conf->basic_rates; enum nl80211_band band; - if (WARN_ON(!link->conf->chandef.chan)) + if (WARN_ON(!link->conf->chanreq.oper.chan)) return; - band = link->conf->chandef.chan->band; + band = link->conf->chanreq.oper.chan->band; if (band == NL80211_BAND_S1GHZ) { /* TODO */ return; @@ -761,7 +761,7 @@ static bool rate_control_cap_mask(struct ieee80211_sub_if_data *sdata, u32 i, flags; *mask = sdata->rc_rateidx_mask[sband->band]; - flags = ieee80211_chandef_rate_flags(&sdata->vif.bss_conf.chandef); + flags = ieee80211_chandef_rate_flags(&sdata->vif.bss_conf.chanreq.oper); for (i = 0; i < sband->n_bitrates; i++) { if ((flags & sband->bitrates[i].flags) != flags) *mask &= ~BIT(i); @@ -817,7 +817,7 @@ rate_control_apply_mask_ratetbl(struct sta_info *sta, mcs_mask, vht_mask)) return; - chan_width = sta->sdata->vif.bss_conf.chandef.width; + chan_width = sta->sdata->vif.bss_conf.chanreq.oper.width; for (i = 0; i < IEEE80211_TX_RATE_TABLE_SIZE; i++) { if (rates->rate[i].idx < 0) break; @@ -854,7 +854,7 @@ static void rate_control_apply_mask(struct ieee80211_sub_if_data *sdata, * included in the configured mask and change the rate indexes * if needed. */ - chan_width = sdata->vif.bss_conf.chandef.width; + chan_width = sdata->vif.bss_conf.chanreq.oper.width; for (i = 0; i < max_rates; i++) { /* Skip invalid rates */ if (rates[i].idx < 0) diff --git a/net/mac80211/spectmgmt.c b/net/mac80211/spectmgmt.c index 51efc9bc8168..2b0bf2a1a877 100644 --- a/net/mac80211/spectmgmt.c +++ b/net/mac80211/spectmgmt.c @@ -108,26 +108,26 @@ int ieee80211_parse_ch_switch_ie(struct ieee80211_sub_if_data *sdata, default: /* secondary_channel_offset was present but is invalid */ case IEEE80211_HT_PARAM_CHA_SEC_NONE: - cfg80211_chandef_create(&csa_ie->chandef, new_chan, + cfg80211_chandef_create(&csa_ie->chanreq.oper, new_chan, NL80211_CHAN_HT20); break; case IEEE80211_HT_PARAM_CHA_SEC_ABOVE: - cfg80211_chandef_create(&csa_ie->chandef, new_chan, + cfg80211_chandef_create(&csa_ie->chanreq.oper, new_chan, NL80211_CHAN_HT40PLUS); break; case IEEE80211_HT_PARAM_CHA_SEC_BELOW: - cfg80211_chandef_create(&csa_ie->chandef, new_chan, + cfg80211_chandef_create(&csa_ie->chanreq.oper, new_chan, NL80211_CHAN_HT40MINUS); break; case -1: - cfg80211_chandef_create(&csa_ie->chandef, new_chan, + cfg80211_chandef_create(&csa_ie->chanreq.oper, new_chan, NL80211_CHAN_NO_HT); /* keep width for 5/10 MHz channels */ - switch (sdata->vif.bss_conf.chandef.width) { + switch (sdata->vif.bss_conf.chanreq.oper.width) { case NL80211_CHAN_WIDTH_5: case NL80211_CHAN_WIDTH_10: - csa_ie->chandef.width = - sdata->vif.bss_conf.chandef.width; + csa_ie->chanreq.oper.width = + sdata->vif.bss_conf.chanreq.oper.width; break; default: break; @@ -137,7 +137,7 @@ int ieee80211_parse_ch_switch_ie(struct ieee80211_sub_if_data *sdata, if (bwi) { /* start with the CSA one */ - new_vht_chandef = csa_ie->chandef; + new_vht_chandef = csa_ie->chanreq.oper; /* and update the width accordingly */ ieee80211_chandef_eht_oper(&bwi->info, &new_vht_chandef); } else if (wide_bw_chansw_ie) { @@ -159,7 +159,7 @@ int ieee80211_parse_ch_switch_ie(struct ieee80211_sub_if_data *sdata, /* default, for the case of IEEE80211_VHT_CHANWIDTH_USE_HT, * to the previously parsed chandef */ - new_vht_chandef = csa_ie->chandef; + new_vht_chandef = csa_ie->chanreq.oper; /* ignore if parsing fails */ if (!ieee80211_chandef_vht_oper(&sdata->local->hw, @@ -177,13 +177,13 @@ int ieee80211_parse_ch_switch_ie(struct ieee80211_sub_if_data *sdata, /* if VHT data is there validate & use it */ if (new_vht_chandef.chan) { if (!cfg80211_chandef_compatible(&new_vht_chandef, - &csa_ie->chandef)) { + &csa_ie->chanreq.oper)) { sdata_info(sdata, "BSS %pM: CSA has inconsistent channel data, disconnecting\n", bssid); return -EINVAL; } - csa_ie->chandef = new_vht_chandef; + csa_ie->chanreq.oper = new_vht_chandef; } if (elems->max_channel_switch_time) diff --git a/net/mac80211/tdls.c b/net/mac80211/tdls.c index 396fd54d8bf7..0f4aa42e070f 100644 --- a/net/mac80211/tdls.c +++ b/net/mac80211/tdls.c @@ -159,7 +159,7 @@ static void ieee80211_tdls_add_oper_classes(struct ieee80211_link_data *link, u8 *pos; u8 op_class; - if (!ieee80211_chandef_to_operating_class(&link->conf->chandef, + if (!ieee80211_chandef_to_operating_class(&link->conf->chanreq.oper, &op_class)) return; @@ -438,7 +438,7 @@ ieee80211_tdls_add_setup_start_ies(struct ieee80211_link_data *link, if (WARN_ON_ONCE(!sta)) return; - sta->tdls_chandef = link->conf->chandef; + sta->tdls_chandef = link->conf->chanreq.oper; } ieee80211_tdls_add_oper_classes(link, skb); @@ -638,7 +638,7 @@ ieee80211_tdls_add_setup_cfm_ies(struct ieee80211_link_data *link, if (WARN_ON_ONCE(!sta || !ap_sta)) return; - sta->tdls_chandef = link->conf->chandef; + sta->tdls_chandef = link->conf->chanreq.oper; /* add any custom IEs that go before the QoS IE */ if (extra_ies_len) { @@ -684,7 +684,7 @@ ieee80211_tdls_add_setup_cfm_ies(struct ieee80211_link_data *link, pos = skb_put(skb, 2 + sizeof(struct ieee80211_ht_operation)); ieee80211_ie_build_ht_oper(pos, &sta->sta.deflink.ht_cap, - &link->conf->chandef, prot, + &link->conf->chanreq.oper, prot, true); } diff --git a/net/mac80211/trace.h b/net/mac80211/trace.h index e2dde3e77c30..efff20d7fe0e 100644 --- a/net/mac80211/trace.h +++ b/net/mac80211/trace.h @@ -503,9 +503,9 @@ TRACE_EVENT(drv_link_info_changed, __entry->ht_operation_mode = link_conf->ht_operation_mode; __entry->cqm_rssi_thold = link_conf->cqm_rssi_thold; __entry->cqm_rssi_hyst = link_conf->cqm_rssi_hyst; - __entry->channel_width = link_conf->chandef.width; - __entry->channel_cfreq1 = link_conf->chandef.center_freq1; - __entry->channel_cfreq1_offset = link_conf->chandef.freq1_offset; + __entry->channel_width = link_conf->chanreq.oper.width; + __entry->channel_cfreq1 = link_conf->chanreq.oper.center_freq1; + __entry->channel_cfreq1_offset = link_conf->chanreq.oper.freq1_offset; __entry->qos = link_conf->qos; __entry->hidden_ssid = link_conf->hidden_ssid; __entry->txpower = link_conf->txpower; diff --git a/net/mac80211/util.c b/net/mac80211/util.c index 51c1a99f57b8..49eef33b5e70 100644 --- a/net/mac80211/util.c +++ b/net/mac80211/util.c @@ -2309,7 +2309,7 @@ struct sk_buff *ieee80211_build_probe_req(struct ieee80211_sub_if_data *sdata, * in order to maximize the chance that we get a response. Some * badly-behaved APs don't respond when this parameter is included. */ - chandef.width = sdata->vif.bss_conf.chandef.width; + chandef.width = sdata->vif.bss_conf.chanreq.oper.width; if (flags & IEEE80211_PROBE_FLAG_DIRECTED) chandef.chan = NULL; else @@ -2351,7 +2351,8 @@ u32 ieee80211_sta_get_rates(struct ieee80211_sub_if_data *sdata, if (WARN_ON(!sband)) return 1; - rate_flags = ieee80211_chandef_rate_flags(&sdata->vif.bss_conf.chandef); + rate_flags = + ieee80211_chandef_rate_flags(&sdata->vif.bss_conf.chanreq.oper); num_rates = sband->n_bitrates; supp_rates = 0; @@ -4026,7 +4027,8 @@ int ieee80211_add_srates_ie(struct ieee80211_sub_if_data *sdata, u32 basic_rates = sdata->vif.bss_conf.basic_rates; u32 rate_flags; - rate_flags = ieee80211_chandef_rate_flags(&sdata->vif.bss_conf.chandef); + rate_flags = + ieee80211_chandef_rate_flags(&sdata->vif.bss_conf.chanreq.oper); sband = local->hw.wiphy->bands[band]; rates = 0; for (i = 0; i < sband->n_bitrates; i++) { @@ -4068,8 +4070,8 @@ int ieee80211_add_ext_srates_ie(struct ieee80211_sub_if_data *sdata, u32 basic_rates = sdata->vif.bss_conf.basic_rates; u32 rate_flags; - rate_flags = ieee80211_chandef_rate_flags(&sdata->vif.bss_conf.chandef); - + rate_flags = + ieee80211_chandef_rate_flags(&sdata->vif.bss_conf.chanreq.oper); sband = local->hw.wiphy->bands[band]; exrates = 0; for (i = 0; i < sband->n_bitrates; i++) { @@ -4312,7 +4314,7 @@ void ieee80211_dfs_cac_cancel(struct ieee80211_local *local) &sdata->deflink.dfs_cac_timer_work); if (sdata->wdev.cac_started) { - chandef = sdata->vif.bss_conf.chandef; + chandef = sdata->vif.bss_conf.chanreq.oper; ieee80211_link_release_channel(&sdata->deflink); cfg80211_cac_event(sdata->dev, &chandef, @@ -4756,7 +4758,7 @@ static u8 ieee80211_chanctx_radar_detect(struct ieee80211_local *local, list_for_each_entry(link, &ctx->reserved_links, reserved_chanctx_list) if (link->reserved_radar_required) - radar_detect |= BIT(link->reserved_chandef.width); + radar_detect |= BIT(link->reserved.oper.width); /* * An in-place reservation context should not have any assigned vifs @@ -4770,7 +4772,7 @@ static u8 ieee80211_chanctx_radar_detect(struct ieee80211_local *local, continue; radar_detect |= - BIT(link->conf->chandef.width); + BIT(link->conf->chanreq.oper.width); } return radar_detect; diff --git a/net/mac80211/vht.c b/net/mac80211/vht.c index b3a5c3e96a72..2c475c439ba9 100644 --- a/net/mac80211/vht.c +++ b/net/mac80211/vht.c @@ -369,7 +369,7 @@ ieee80211_sta_cap_rx_bw(struct link_sta_info *link_sta) link_conf = rcu_dereference(sdata->vif.link_conf[link_id]); if (eht_cap->has_eht && - link_conf->chandef.chan->band == NL80211_BAND_6GHZ) { + link_conf->chanreq.oper.chan->band == NL80211_BAND_6GHZ) { info = eht_cap->eht_cap_elem.phy_cap_info[0]; if (info & IEEE80211_EHT_PHY_CAP0_320MHZ_IN_6GHZ) { @@ -380,7 +380,7 @@ ieee80211_sta_cap_rx_bw(struct link_sta_info *link_sta) info = he_cap->he_cap_elem.phy_cap_info[0]; - if (link_conf->chandef.chan->band == NL80211_BAND_2GHZ) { + if (link_conf->chanreq.oper.chan->band == NL80211_BAND_2GHZ) { if (info & IEEE80211_HE_PHY_CAP0_CHANNEL_WIDTH_SET_40MHZ_IN_2G) ret = IEEE80211_STA_RX_BW_40; else @@ -515,7 +515,7 @@ ieee80211_sta_cur_vht_bw(struct link_sta_info *link_sta) if (WARN_ON(!link_conf)) bss_width = NL80211_CHAN_WIDTH_20_NOHT; else - bss_width = link_conf->chandef.width; + bss_width = link_conf->chanreq.oper.width; rcu_read_unlock(); bw = ieee80211_sta_cap_rx_bw(link_sta); -- cgit v1.2.3 From b82730bf57b54803ab94abbfd8c4422a7081886d Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Mon, 29 Jan 2024 19:34:49 +0100 Subject: wifi: cfg80211/mac80211: move puncturing into chandef Aloka originally suggested that puncturing should be part of the chandef, so that it's treated correctly. At the time, I disagreed and it ended up not part of the chandef, but I've now realized that this was wrong. Even for clients, the RX, and perhaps more importantly, CCA configuration needs to take puncturing into account. Move puncturing into the chandef, and adjust all the code accordingly. Also add a few tests for puncturing in chandef compatibility checking. Link: https://lore.kernel.org/linux-wireless/20220214223051.3610-1-quic_alokad@quicinc.com/ Suggested-by: Aloka Dixit Link: https://msgid.link/20240129194108.307183a5d2e5.I4d7fe2f126b2366c1312010e2900dfb2abffa0f6@changeid Signed-off-by: Johannes Berg --- drivers/net/wireless/ath/ath12k/mac.c | 10 +- drivers/net/wireless/ath/ath6kl/cfg80211.c | 2 +- drivers/net/wireless/intel/iwlwifi/mvm/link.c | 16 +- .../net/wireless/intel/iwlwifi/mvm/mld-mac80211.c | 6 +- drivers/net/wireless/marvell/mwifiex/11h.c | 2 +- drivers/net/wireless/quantenna/qtnfmac/event.c | 2 +- drivers/net/wireless/realtek/rtw89/fw.c | 5 +- include/net/cfg80211.h | 44 ++--- include/net/mac80211.h | 11 +- net/mac80211/cfg.c | 21 +-- net/mac80211/chan.c | 10 +- net/mac80211/link.c | 2 +- net/mac80211/mlme.c | 180 +++------------------ net/mac80211/util.c | 26 ++- net/wireless/chan.c | 62 ++++--- net/wireless/nl80211.c | 67 +++----- net/wireless/tests/chan.c | 48 +++++- net/wireless/trace.h | 38 ++--- 18 files changed, 227 insertions(+), 325 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/ath/ath12k/mac.c b/drivers/net/wireless/ath/ath12k/mac.c index a27480a69b27..18fb42c045cc 100644 --- a/drivers/net/wireless/ath/ath12k/mac.c +++ b/drivers/net/wireless/ath/ath12k/mac.c @@ -2784,9 +2784,6 @@ static void ath12k_mac_bss_info_changed(struct ath12k *ar, } ath12k_mac_fils_discovery(arvif, info); - - if (changed & BSS_CHANGED_EHT_PUNCTURING) - arvif->punct_bitmap = info->eht_puncturing; } static void ath12k_mac_op_bss_info_changed(struct ieee80211_hw *hw, @@ -6373,6 +6370,8 @@ ath12k_mac_update_vif_chan(struct ath12k *ar, if (WARN_ON(!arvif->is_started)) continue; + arvif->punct_bitmap = vifs[i].new_ctx->def.punctured; + /* Firmware expect vdev_restart only if vdev is up. * If vdev is down then it expect vdev_stop->vdev_start. */ @@ -6473,7 +6472,8 @@ static void ath12k_mac_op_change_chanctx(struct ieee80211_hw *hw, goto unlock; if (changed & IEEE80211_CHANCTX_CHANGE_WIDTH || - changed & IEEE80211_CHANCTX_CHANGE_RADAR) + changed & IEEE80211_CHANCTX_CHANGE_RADAR || + changed & IEEE80211_CHANCTX_CHANGE_PUNCTURING) ath12k_mac_update_active_vif_chan(ar, ctx); /* TODO: Recalc radar detection */ @@ -6536,7 +6536,7 @@ ath12k_mac_op_assign_vif_chanctx(struct ieee80211_hw *hw, "mac chanctx assign ptr %pK vdev_id %i\n", ctx, arvif->vdev_id); - arvif->punct_bitmap = link_conf->eht_puncturing; + arvif->punct_bitmap = ctx->def.punctured; /* for some targets bss peer must be created before vdev_start */ if (ab->hw_params->vdev_start_delay && diff --git a/drivers/net/wireless/ath/ath6kl/cfg80211.c b/drivers/net/wireless/ath/ath6kl/cfg80211.c index e37db4af33de..61b2e3f15f0e 100644 --- a/drivers/net/wireless/ath/ath6kl/cfg80211.c +++ b/drivers/net/wireless/ath/ath6kl/cfg80211.c @@ -1119,7 +1119,7 @@ void ath6kl_cfg80211_ch_switch_notify(struct ath6kl_vif *vif, int freq, NL80211_CHAN_HT20 : NL80211_CHAN_NO_HT); wiphy_lock(vif->ar->wiphy); - cfg80211_ch_switch_notify(vif->ndev, &chandef, 0, 0); + cfg80211_ch_switch_notify(vif->ndev, &chandef, 0); wiphy_unlock(vif->ar->wiphy); } diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/link.c b/drivers/net/wireless/intel/iwlwifi/mvm/link.c index f3fcef9034ef..129eefcc45d6 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/link.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/link.c @@ -1,6 +1,6 @@ // SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause /* - * Copyright (C) 2022 - 2023 Intel Corporation + * Copyright (C) 2022 - 2024 Intel Corporation */ #include "mvm.h" #include "time-event.h" @@ -195,12 +195,20 @@ int iwl_mvm_link_changed(struct iwl_mvm *mvm, struct ieee80211_vif *vif, } if (changes & LINK_CONTEXT_MODIFY_EHT_PARAMS) { + struct ieee80211_chanctx_conf *ctx; + struct cfg80211_chan_def *def = NULL; + + rcu_read_lock(); + ctx = rcu_dereference(link_conf->chanctx_conf); + if (ctx) + def = iwl_mvm_chanctx_def(mvm, ctx); + if (iwlwifi_mod_params.disable_11be || - !link_conf->eht_support) + !link_conf->eht_support || !def) changes &= ~LINK_CONTEXT_MODIFY_EHT_PARAMS; else - cmd.puncture_mask = - cpu_to_le16(link_conf->eht_puncturing); + cmd.puncture_mask = cpu_to_le16(def->punctured); + rcu_read_unlock(); } cmd.bss_color = link_conf->he_bss_color.color; diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/mld-mac80211.c b/drivers/net/wireless/intel/iwlwifi/mvm/mld-mac80211.c index b633a2a09c32..7d89f50fbb10 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/mld-mac80211.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/mld-mac80211.c @@ -1,6 +1,6 @@ // SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause /* - * Copyright (C) 2022-2023 Intel Corporation + * Copyright (C) 2022-2024 Intel Corporation */ #include "mvm.h" @@ -752,8 +752,8 @@ iwl_mvm_mld_link_info_changed_station(struct iwl_mvm *mvm, link_changes |= LINK_CONTEXT_MODIFY_HE_PARAMS; } - /* Update EHT Puncturing info */ - if (changes & BSS_CHANGED_EHT_PUNCTURING && vif->cfg.assoc) + /* if associated, maybe puncturing changed - we'll check later */ + if (vif->cfg.assoc) link_changes |= LINK_CONTEXT_MODIFY_EHT_PARAMS; if (link_changes) { diff --git a/drivers/net/wireless/marvell/mwifiex/11h.c b/drivers/net/wireless/marvell/mwifiex/11h.c index da211372a481..b90f922f1cdc 100644 --- a/drivers/net/wireless/marvell/mwifiex/11h.c +++ b/drivers/net/wireless/marvell/mwifiex/11h.c @@ -288,6 +288,6 @@ void mwifiex_dfs_chan_sw_work_queue(struct work_struct *work) mwifiex_dbg(priv->adapter, MSG, "indicating channel switch completion to kernel\n"); wiphy_lock(priv->wdev.wiphy); - cfg80211_ch_switch_notify(priv->netdev, &priv->dfs_chandef, 0, 0); + cfg80211_ch_switch_notify(priv->netdev, &priv->dfs_chandef, 0); wiphy_unlock(priv->wdev.wiphy); } diff --git a/drivers/net/wireless/quantenna/qtnfmac/event.c b/drivers/net/wireless/quantenna/qtnfmac/event.c index 3b283e93a13e..76b07db284f8 100644 --- a/drivers/net/wireless/quantenna/qtnfmac/event.c +++ b/drivers/net/wireless/quantenna/qtnfmac/event.c @@ -478,7 +478,7 @@ qtnf_event_handle_freq_change(struct qtnf_wmac *mac, continue; wiphy_lock(priv_to_wiphy(vif->mac)); - cfg80211_ch_switch_notify(vif->netdev, &chandef, 0, 0); + cfg80211_ch_switch_notify(vif->netdev, &chandef, 0); wiphy_unlock(priv_to_wiphy(vif->mac)); } diff --git a/drivers/net/wireless/realtek/rtw89/fw.c b/drivers/net/wireless/realtek/rtw89/fw.c index 51072a2dcf10..540ea16f048e 100644 --- a/drivers/net/wireless/realtek/rtw89/fw.c +++ b/drivers/net/wireless/realtek/rtw89/fw.c @@ -2804,8 +2804,11 @@ int rtw89_fw_h2c_assoc_cmac_tbl_g7(struct rtw89_dev *rtwdev, } if (vif->bss_conf.eht_support) { - h2c->w4 |= le32_encode_bits(~vif->bss_conf.eht_puncturing, + u16 punct = vif->bss_conf.chanreq.oper.punctured; + + h2c->w4 |= le32_encode_bits(~punct, CCTLINFO_G7_W4_ACT_SUBCH_CBW); + rcu_read_unlock(); h2c->m4 |= cpu_to_le32(CCTLINFO_G7_W4_ACT_SUBCH_CBW); } diff --git a/include/net/cfg80211.h b/include/net/cfg80211.h index fc2ad80118e8..cb5e34d640cd 100644 --- a/include/net/cfg80211.h +++ b/include/net/cfg80211.h @@ -7,7 +7,7 @@ * Copyright 2006-2010 Johannes Berg * Copyright 2013-2014 Intel Mobile Communications GmbH * Copyright 2015-2017 Intel Deutschland GmbH - * Copyright (C) 2018-2021, 2023 Intel Corporation + * Copyright (C) 2018-2024 Intel Corporation */ #include @@ -808,6 +808,9 @@ struct key_params { * chan will define the primary channel and all other * parameters are ignored. * @freq1_offset: offset from @center_freq1, in KHz + * @punctured: mask of the punctured 20 MHz subchannels, with + * bits turned on being disabled (punctured); numbered + * from lower to higher frequency (like in the spec) */ struct cfg80211_chan_def { struct ieee80211_channel *chan; @@ -816,6 +819,7 @@ struct cfg80211_chan_def { u32 center_freq2; struct ieee80211_edmg edmg; u16 freq1_offset; + u16 punctured; }; /* @@ -956,7 +960,8 @@ cfg80211_chandef_identical(const struct cfg80211_chan_def *chandef1, chandef1->width == chandef2->width && chandef1->center_freq1 == chandef2->center_freq1 && chandef1->freq1_offset == chandef2->freq1_offset && - chandef1->center_freq2 == chandef2->center_freq2); + chandef1->center_freq2 == chandef2->center_freq2 && + chandef1->punctured == chandef2->punctured); } /** @@ -1051,12 +1056,15 @@ cfg80211_chandef_dfs_cac_time(struct wiphy *wiphy, * cfg80211_chandef_primary_freq - calculate primary 40/80/160 MHz freq * @chandef: chandef to calculate for * @primary_chan_width: primary channel width to calculate center for + * @punctured: punctured sub-channel bitmap, will be recalculated + * according to the new bandwidth, can be %NULL * * Returns: the primary 40/80/160 MHz channel center frequency, or -1 - * for errors + * for errors, updating the punctured bitmap */ -int cfg80211_chandef_primary_freq(const struct cfg80211_chan_def *chandef, - enum nl80211_chan_width primary_chan_width); +int cfg80211_chandef_primary(const struct cfg80211_chan_def *chandef, + enum nl80211_chan_width primary_chan_width, + u16 *punctured); /** * nl80211_send_chandef - sends the channel definition. @@ -1468,9 +1476,6 @@ struct cfg80211_unsol_bcast_probe_resp { * @fils_discovery: FILS discovery transmission parameters * @unsol_bcast_probe_resp: Unsolicited broadcast probe response parameters * @mbssid_config: AP settings for multiple bssid - * @punct_bitmap: Preamble puncturing bitmap. Each bit represents - * a 20 MHz channel, lowest bit corresponding to the lowest channel. - * Bit set to 1 indicates that the channel is punctured. */ struct cfg80211_ap_settings { struct cfg80211_chan_def chandef; @@ -1505,7 +1510,6 @@ struct cfg80211_ap_settings { struct cfg80211_fils_discovery fils_discovery; struct cfg80211_unsol_bcast_probe_resp unsol_bcast_probe_resp; struct cfg80211_mbssid_config mbssid_config; - u16 punct_bitmap; }; @@ -1539,9 +1543,6 @@ struct cfg80211_ap_update { * @radar_required: whether radar detection is required on the new channel * @block_tx: whether transmissions should be blocked while changing * @count: number of beacons until switch - * @punct_bitmap: Preamble puncturing bitmap. Each bit represents - * a 20 MHz channel, lowest bit corresponding to the lowest channel. - * Bit set to 1 indicates that the channel is punctured. */ struct cfg80211_csa_settings { struct cfg80211_chan_def chandef; @@ -1554,7 +1555,6 @@ struct cfg80211_csa_settings { bool radar_required; bool block_tx; u8 count; - u16 punct_bitmap; }; /** @@ -8738,14 +8738,13 @@ bool cfg80211_reg_can_beacon_relax(struct wiphy *wiphy, * @dev: the device which switched channels * @chandef: the new channel definition * @link_id: the link ID for MLO, must be 0 for non-MLO - * @punct_bitmap: the new puncturing bitmap * * Caller must hold wiphy mutex, therefore must only be called from sleepable * driver context! */ void cfg80211_ch_switch_notify(struct net_device *dev, struct cfg80211_chan_def *chandef, - unsigned int link_id, u16 punct_bitmap); + unsigned int link_id); /* * cfg80211_ch_switch_started_notify - notify channel switch start @@ -8754,7 +8753,6 @@ void cfg80211_ch_switch_notify(struct net_device *dev, * @link_id: the link ID for MLO, must be 0 for non-MLO * @count: the number of TBTTs until the channel switch happens * @quiet: whether or not immediate quiet was requested by the AP - * @punct_bitmap: the future puncturing bitmap * * Inform the userspace about the channel switch that has just * started, so that it can take appropriate actions (eg. starting @@ -8763,7 +8761,7 @@ void cfg80211_ch_switch_notify(struct net_device *dev, void cfg80211_ch_switch_started_notify(struct net_device *dev, struct cfg80211_chan_def *chandef, unsigned int link_id, u8 count, - bool quiet, u16 punct_bitmap); + bool quiet); /** * ieee80211_operating_class_to_band - convert operating class to band @@ -9381,18 +9379,6 @@ static inline int cfg80211_color_change_notify(struct net_device *dev) 0, 0); } -/** - * cfg80211_valid_disable_subchannel_bitmap - validate puncturing bitmap - * @bitmap: bitmap to be validated - * @chandef: channel definition - * - * Validate the puncturing bitmap. - * - * Return: %true if the bitmap is valid. %false otherwise. - */ -bool cfg80211_valid_disable_subchannel_bitmap(u16 *bitmap, - const struct cfg80211_chan_def *chandef); - /** * cfg80211_links_removed - Notify about removed STA MLD setup links. * @dev: network device. diff --git a/include/net/mac80211.h b/include/net/mac80211.h index ab6bc89d3394..54aa4a06c878 100644 --- a/include/net/mac80211.h +++ b/include/net/mac80211.h @@ -7,7 +7,7 @@ * Copyright 2007-2010 Johannes Berg * Copyright 2013-2014 Intel Mobile Communications GmbH * Copyright (C) 2015 - 2017 Intel Deutschland GmbH - * Copyright (C) 2018 - 2023 Intel Corporation + * Copyright (C) 2018 - 2024 Intel Corporation */ #ifndef MAC80211_H @@ -216,6 +216,8 @@ struct ieee80211_low_level_stats { * @IEEE80211_CHANCTX_CHANGE_MIN_WIDTH: The min required channel width changed * @IEEE80211_CHANCTX_CHANGE_AP: The AP channel definition changed, so (wider * bandwidth) OFDMA settings need to be changed + * @IEEE80211_CHANCTX_CHANGE_PUNCTURING: The punctured channel(s) bitmap + * was changed. */ enum ieee80211_chanctx_change { IEEE80211_CHANCTX_CHANGE_WIDTH = BIT(0), @@ -224,6 +226,7 @@ enum ieee80211_chanctx_change { IEEE80211_CHANCTX_CHANGE_CHANNEL = BIT(3), IEEE80211_CHANCTX_CHANGE_MIN_WIDTH = BIT(4), IEEE80211_CHANCTX_CHANGE_AP = BIT(5), + IEEE80211_CHANCTX_CHANGE_PUNCTURING = BIT(6), }; /** @@ -357,7 +360,6 @@ struct ieee80211_vif_chanctx_switch { * @BSS_CHANGED_FILS_DISCOVERY: FILS discovery status changed. * @BSS_CHANGED_UNSOL_BCAST_PROBE_RESP: Unsolicited broadcast probe response * status changed. - * @BSS_CHANGED_EHT_PUNCTURING: The channel puncturing bitmap changed. * @BSS_CHANGED_MLD_VALID_LINKS: MLD valid links status changed. * @BSS_CHANGED_MLD_TTLM: TID to link mapping was changed */ @@ -394,7 +396,6 @@ enum ieee80211_bss_change { BSS_CHANGED_HE_BSS_COLOR = 1<<29, BSS_CHANGED_FILS_DISCOVERY = 1<<30, BSS_CHANGED_UNSOL_BCAST_PROBE_RESP = 1<<31, - BSS_CHANGED_EHT_PUNCTURING = BIT_ULL(32), BSS_CHANGED_MLD_VALID_LINKS = BIT_ULL(33), BSS_CHANGED_MLD_TTLM = BIT_ULL(34), @@ -661,9 +662,7 @@ struct ieee80211_fils_discovery { * @tx_pwr_env_num: number of @tx_pwr_env. * @pwr_reduction: power constraint of BSS. * @eht_support: does this BSS support EHT - * @eht_puncturing: bitmap to indicate which channels are punctured in this BSS * @csa_active: marks whether a channel switch is going on. - * @csa_punct_bitmap: new puncturing bitmap for channel switch * @mu_mimo_owner: indicates interface owns MU-MIMO capability * @chanctx_conf: The channel context this interface is assigned to, or %NULL * when it is not assigned. This pointer is RCU-protected due to the TX @@ -766,10 +765,8 @@ struct ieee80211_bss_conf { u8 tx_pwr_env_num; u8 pwr_reduction; bool eht_support; - u16 eht_puncturing; bool csa_active; - u16 csa_punct_bitmap; bool mu_mimo_owner; struct ieee80211_chanctx_conf __rcu *chanctx_conf; diff --git a/net/mac80211/cfg.c b/net/mac80211/cfg.c index 5aa02b0872d9..2ddaf0037952 100644 --- a/net/mac80211/cfg.c +++ b/net/mac80211/cfg.c @@ -1343,8 +1343,6 @@ static int ieee80211_start_ap(struct wiphy *wiphy, struct net_device *dev, return -EOPNOTSUPP; link_conf->eht_support = true; - link_conf->eht_puncturing = params->punct_bitmap; - changed |= BSS_CHANGED_EHT_PUNCTURING; link_conf->eht_su_beamformer = params->eht_cap->fixed.phy_cap_info[0] & @@ -3668,12 +3666,6 @@ static int __ieee80211_csa_finalize(struct ieee80211_link_data *link_data) if (err) return err; - if (sdata->vif.bss_conf.eht_puncturing != sdata->vif.bss_conf.csa_punct_bitmap) { - sdata->vif.bss_conf.eht_puncturing = - sdata->vif.bss_conf.csa_punct_bitmap; - changed |= BSS_CHANGED_EHT_PUNCTURING; - } - ieee80211_link_info_change_notify(sdata, link_data, changed); if (link_data->csa_block_tx) { @@ -3687,8 +3679,7 @@ static int __ieee80211_csa_finalize(struct ieee80211_link_data *link_data) return err; cfg80211_ch_switch_notify(sdata->dev, &link_data->csa_chanreq.oper, - link_data->link_id, - link_data->conf->eht_puncturing); + link_data->link_id); return 0; } @@ -3889,6 +3880,9 @@ __ieee80211_channel_switch(struct wiphy *wiphy, struct net_device *dev, &sdata->vif.bss_conf.chanreq.oper)) return -EINVAL; + if (chanreq.oper.punctured && !sdata->vif.bss_conf.eht_support) + return -EINVAL; + /* don't allow another channel switch if one is already active. */ if (sdata->vif.bss_conf.csa_active) return -EBUSY; @@ -3941,13 +3935,9 @@ __ieee80211_channel_switch(struct wiphy *wiphy, struct net_device *dev, goto out; } - if (params->punct_bitmap && !sdata->vif.bss_conf.eht_support) - goto out; - sdata->deflink.csa_chanreq = chanreq; sdata->deflink.csa_block_tx = params->block_tx; sdata->vif.bss_conf.csa_active = true; - sdata->vif.bss_conf.csa_punct_bitmap = params->punct_bitmap; if (sdata->deflink.csa_block_tx) ieee80211_stop_vif_queues(local, sdata, @@ -3955,8 +3945,7 @@ __ieee80211_channel_switch(struct wiphy *wiphy, struct net_device *dev, cfg80211_ch_switch_started_notify(sdata->dev, &sdata->deflink.csa_chanreq.oper, 0, - params->count, params->block_tx, - sdata->vif.bss_conf.csa_punct_bitmap); + params->count, params->block_tx); if (changed) { ieee80211_link_info_change_notify(sdata, &sdata->deflink, diff --git a/net/mac80211/chan.c b/net/mac80211/chan.c index fe1489ba58c6..38acdc458c7c 100644 --- a/net/mac80211/chan.c +++ b/net/mac80211/chan.c @@ -1,7 +1,7 @@ // SPDX-License-Identifier: GPL-2.0-only /* * mac80211 - channel management - * Copyright 2020 - 2022 Intel Corporation + * Copyright 2020 - 2024 Intel Corporation */ #include @@ -517,8 +517,12 @@ static void _ieee80211_change_chanctx(struct ieee80211_local *local, ieee80211_remove_wbrf(local, &ctx->conf.def); - if (!cfg80211_chandef_identical(&ctx->conf.def, &chanreq->oper)) - changed |= IEEE80211_CHANCTX_CHANGE_WIDTH; + if (!cfg80211_chandef_identical(&ctx->conf.def, &chanreq->oper)) { + if (ctx->conf.def.width != chanreq->oper.width) + changed |= IEEE80211_CHANCTX_CHANGE_WIDTH; + if (ctx->conf.def.punctured != chanreq->oper.punctured) + changed |= IEEE80211_CHANCTX_CHANGE_PUNCTURING; + } if (!cfg80211_chandef_identical(&ctx->conf.ap, &chanreq->ap)) changed |= IEEE80211_CHANCTX_CHANGE_AP; ctx->conf.def = *chandef; diff --git a/net/mac80211/link.c b/net/mac80211/link.c index 2231eb38a211..4f19d6479bef 100644 --- a/net/mac80211/link.c +++ b/net/mac80211/link.c @@ -2,7 +2,7 @@ /* * MLO link handling * - * Copyright (C) 2022-2023 Intel Corporation + * Copyright (C) 2022-2024 Intel Corporation */ #include #include diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c index 74a15f18e7ee..4eaf5c10efdb 100644 --- a/net/mac80211/mlme.c +++ b/net/mac80211/mlme.c @@ -93,83 +93,6 @@ MODULE_PARM_DESC(probe_wait_ms, */ #define IEEE80211_SIGNAL_AVE_MIN_COUNT 4 -/* - * Extract from the given disabled subchannel bitmap (raw format - * from the EHT Operation Element) the bits for the subchannel - * we're using right now. - */ -static u16 -ieee80211_extract_dis_subch_bmap(const struct ieee80211_eht_operation *eht_oper, - struct cfg80211_chan_def *chandef, u16 bitmap) -{ - struct ieee80211_eht_operation_info *info = (void *)eht_oper->optional; - struct cfg80211_chan_def ap_chandef = *chandef; - u32 ap_center_freq, local_center_freq; - u32 ap_bw, local_bw; - int ap_start_freq, local_start_freq; - u16 shift, mask; - - if (!(eht_oper->params & IEEE80211_EHT_OPER_INFO_PRESENT) || - !(eht_oper->params & - IEEE80211_EHT_OPER_DISABLED_SUBCHANNEL_BITMAP_PRESENT)) - return 0; - - /* set 160/320 supported to get the full AP definition */ - ieee80211_chandef_eht_oper((const void *)eht_oper->optional, - &ap_chandef); - ap_center_freq = ap_chandef.center_freq1; - ap_bw = 20 * BIT(u8_get_bits(info->control, - IEEE80211_EHT_OPER_CHAN_WIDTH)); - ap_start_freq = ap_center_freq - ap_bw / 2; - local_center_freq = chandef->center_freq1; - local_bw = 20 * BIT(ieee80211_chan_width_to_rx_bw(chandef->width)); - local_start_freq = local_center_freq - local_bw / 2; - shift = (local_start_freq - ap_start_freq) / 20; - mask = BIT(local_bw / 20) - 1; - - return (bitmap >> shift) & mask; -} - -/* - * Handle the puncturing bitmap, possibly downgrading bandwidth to get a - * valid bitmap. - */ -static void -ieee80211_handle_puncturing_bitmap(struct ieee80211_link_data *link, - const struct ieee80211_eht_operation *eht_oper, - u16 bitmap, u64 *changed) -{ - struct cfg80211_chan_def *chandef = &link->conf->chanreq.oper; - struct ieee80211_local *local = link->sdata->local; - u16 extracted; - u64 _changed = 0; - - if (!changed) - changed = &_changed; - - while (chandef->width > NL80211_CHAN_WIDTH_40) { - extracted = - ieee80211_extract_dis_subch_bmap(eht_oper, chandef, - bitmap); - - if (cfg80211_valid_disable_subchannel_bitmap(&bitmap, - chandef) && - !(bitmap && ieee80211_hw_check(&local->hw, - DISALLOW_PUNCTURING))) - break; - ieee80211_chandef_downgrade(chandef, &link->u.mgd.conn); - *changed |= BSS_CHANGED_BANDWIDTH; - } - - if (chandef->width <= NL80211_CHAN_WIDTH_40) - extracted = 0; - - if (link->conf->eht_puncturing != extracted) { - link->conf->eht_puncturing = extracted; - *changed |= BSS_CHANGED_EHT_PUNCTURING; - } -} - /* * We can have multiple work items (and connection probing) * scheduling this timer, but we need to take care to only @@ -396,6 +319,9 @@ ieee80211_determine_ap_chan(struct ieee80211_sub_if_data *sdata, ieee80211_chandef_eht_oper((const void *)eht_oper->optional, &eht_chandef); + eht_chandef.punctured = + ieee80211_eht_oper_dis_subchan_bitmap(eht_oper); + if (!cfg80211_chandef_valid(&eht_chandef)) { sdata_info(sdata, "AP EHT information is invalid, disabling EHT\n"); @@ -661,13 +587,27 @@ ieee80211_verify_sta_eht_mcs_support(struct ieee80211_sub_if_data *sdata, return true; } +static bool ieee80211_chandef_usable(struct ieee80211_sub_if_data *sdata, + const struct cfg80211_chan_def *chandef, + u32 prohibited_flags) +{ + if (!cfg80211_chandef_usable(sdata->local->hw.wiphy, + chandef, prohibited_flags)) + return false; + + if (chandef->punctured && + ieee80211_hw_check(&sdata->local->hw, DISALLOW_PUNCTURING)) + return false; + + return true; +} + static struct ieee802_11_elems * ieee80211_determine_chan_mode(struct ieee80211_sub_if_data *sdata, struct ieee80211_conn_settings *conn, struct cfg80211_bss *cbss, int link_id, struct ieee80211_chan_req *chanreq) { - struct ieee80211_local *local = sdata->local; const struct cfg80211_bss_ies *ies = rcu_dereference(cbss->ies); struct ieee80211_bss *bss = (void *)cbss->priv; struct ieee80211_channel *channel = cbss->channel; @@ -761,8 +701,8 @@ again: else chanreq->ap.chan = NULL; - while (!cfg80211_chandef_usable(sdata->local->hw.wiphy, &chanreq->oper, - IEEE80211_CHAN_DISABLED)) { + while (!ieee80211_chandef_usable(sdata, &chanreq->oper, + IEEE80211_CHAN_DISABLED)) { if (WARN_ON(chanreq->oper.width == NL80211_CHAN_WIDTH_20_NOHT)) { ret = -EINVAL; goto free; @@ -812,30 +752,6 @@ again: sdata_info(sdata, "required MCSes not supported, disabling EHT\n"); } - if (conn->mode >= IEEE80211_CONN_MODE_EHT) { - u16 bitmap; - - if (WARN_ON_ONCE(!elems->eht_operation)) { - ret = -EINVAL; - goto free; - } - - bitmap = ieee80211_eht_oper_dis_subchan_bitmap(elems->eht_operation); - - if (!cfg80211_valid_disable_subchannel_bitmap(&bitmap, - &ap_chandef) || - (bitmap && - ieee80211_hw_check(&local->hw, DISALLOW_PUNCTURING))) { - conn->mode = IEEE80211_CONN_MODE_HE; - conn->bw_limit = min_t(enum ieee80211_conn_bw_limit, - conn->bw_limit, - IEEE80211_CONN_BW_LIMIT_160); - sdata_info(sdata, - "AP has invalid/unsupported puncturing, disabling EHT\n"); - } - /* FIXME: store puncturing bitmap */ - } - /* the mode can only decrease, so this must terminate */ if (ap_mode != conn->mode) goto again; @@ -2127,7 +2043,7 @@ static void ieee80211_chswitch_post_beacon(struct ieee80211_link_data *link) } cfg80211_ch_switch_notify(sdata->dev, &link->reserved.oper, - link->link_id, 0); + link->link_id); } void ieee80211_chswitch_done(struct ieee80211_vif *vif, bool success, @@ -2330,7 +2246,7 @@ ieee80211_sta_process_chanswitch(struct ieee80211_link_data *link, cfg80211_ch_switch_started_notify(sdata->dev, &csa_ie.chanreq.oper, link->link_id, csa_ie.count, - csa_ie.mode, 0); + csa_ie.mode); if (local->ops->channel_switch) { /* use driver's channel switch callback */ @@ -3394,8 +3310,6 @@ static void ieee80211_set_disassoc(struct ieee80211_sub_if_data *sdata, sdata->deflink.u.mgd.tracking_signal_avg = false; sdata->deflink.u.mgd.disable_wmm_tracking = false; - sdata->vif.bss_conf.eht_puncturing = 0; - ifmgd->flags = 0; for (link_id = 0; link_id < ARRAY_SIZE(sdata->link); link_id++) { @@ -4625,7 +4539,6 @@ static bool ieee80211_assoc_config_link(struct ieee80211_link_data *link, link_sta); bss_conf->eht_support = link_sta->pub->eht_cap.has_eht; - *changed |= BSS_CHANGED_EHT_PUNCTURING; } else { bss_conf->eht_support = false; } @@ -5865,40 +5778,6 @@ static bool ieee80211_rx_our_beacon(const u8 *tx_bssid, return ether_addr_equal(tx_bssid, bss->transmitted_bss->bssid); } -static bool ieee80211_config_puncturing(struct ieee80211_link_data *link, - const struct ieee80211_eht_operation *eht_oper, - u64 *changed) -{ - struct ieee80211_local *local = link->sdata->local; - u16 bitmap, extracted; - - bitmap = ieee80211_eht_oper_dis_subchan_bitmap(eht_oper); - extracted = ieee80211_extract_dis_subch_bmap(eht_oper, - &link->conf->chanreq.oper, - bitmap); - - /* accept if there are no changes */ - if (!(*changed & BSS_CHANGED_BANDWIDTH) && - extracted == link->conf->eht_puncturing) - return true; - - if (!cfg80211_valid_disable_subchannel_bitmap(&bitmap, - &link->conf->chanreq.oper)) { - link_info(link, - "Got an invalid disable subchannel bitmap from AP %pM: bitmap = 0x%x, bw = 0x%x. disconnect\n", - link->u.mgd.bssid, - bitmap, - link->conf->chanreq.oper.width); - return false; - } - - if (bitmap && ieee80211_hw_check(&local->hw, DISALLOW_PUNCTURING)) - return false; - - ieee80211_handle_puncturing_bitmap(link, eht_oper, bitmap, changed); - return true; -} - static void ieee80211_ml_reconf_work(struct wiphy *wiphy, struct wiphy_work *work) { @@ -6614,21 +6493,6 @@ static void ieee80211_rx_mgmt_beacon(struct ieee80211_link_data *link, elems->pwr_constr_elem, elems->cisco_dtpc_elem); - if (elems->eht_operation && - link->u.mgd.conn.mode >= IEEE80211_CONN_MODE_EHT) { - if (!ieee80211_config_puncturing(link, elems->eht_operation, - &changed)) { - ieee80211_set_disassoc(sdata, IEEE80211_STYPE_DEAUTH, - WLAN_REASON_DEAUTH_LEAVING, - true, deauth_buf); - ieee80211_report_disconnect(sdata, deauth_buf, - sizeof(deauth_buf), true, - WLAN_REASON_DEAUTH_LEAVING, - false); - goto free; - } - } - ieee80211_ml_reconfiguration(sdata, elems); ieee80211_process_adv_ttlm(sdata, elems, le64_to_cpu(mgmt->u.beacon.timestamp)); diff --git a/net/mac80211/util.c b/net/mac80211/util.c index 63a88169d53d..5108dbaa9360 100644 --- a/net/mac80211/util.c +++ b/net/mac80211/util.c @@ -6,7 +6,7 @@ * Copyright 2007 Johannes Berg * Copyright 2013-2014 Intel Mobile Communications GmbH * Copyright (C) 2015-2017 Intel Deutschland GmbH - * Copyright (C) 2018-2023 Intel Corporation + * Copyright (C) 2018-2024 Intel Corporation * * utilities for mac80211 */ @@ -2810,9 +2810,6 @@ int ieee80211_reconfig(struct ieee80211_local *local) sdata->vif.bss_conf.protected_keep_alive) changed |= BSS_CHANGED_KEEP_ALIVE; - if (sdata->vif.bss_conf.eht_puncturing) - changed |= BSS_CHANGED_EHT_PUNCTURING; - ieee80211_bss_info_change_notify(sdata, changed); } else if (!WARN_ON(!link)) { @@ -4365,14 +4362,17 @@ EXPORT_SYMBOL(ieee80211_radar_detected); void ieee80211_chandef_downgrade(struct cfg80211_chan_def *c, struct ieee80211_conn_settings *conn) { - /* no-HT indicates nothing to do */ - enum nl80211_chan_width new_primary_width = NL80211_CHAN_WIDTH_20_NOHT; + enum nl80211_chan_width new_primary_width; struct ieee80211_conn_settings _ignored = {}; /* allow passing NULL if caller doesn't care */ if (!conn) conn = &_ignored; +again: + /* no-HT indicates nothing to do */ + new_primary_width = NL80211_CHAN_WIDTH_20_NOHT; + switch (c->width) { default: case NL80211_CHAN_WIDTH_20_NOHT: @@ -4382,6 +4382,7 @@ void ieee80211_chandef_downgrade(struct cfg80211_chan_def *c, c->width = NL80211_CHAN_WIDTH_20_NOHT; conn->mode = IEEE80211_CONN_MODE_LEGACY; conn->bw_limit = IEEE80211_CONN_BW_LIMIT_20; + c->punctured = 0; break; case NL80211_CHAN_WIDTH_40: c->width = NL80211_CHAN_WIDTH_20; @@ -4389,6 +4390,7 @@ void ieee80211_chandef_downgrade(struct cfg80211_chan_def *c, if (conn->mode == IEEE80211_CONN_MODE_VHT) conn->mode = IEEE80211_CONN_MODE_HT; conn->bw_limit = IEEE80211_CONN_BW_LIMIT_20; + c->punctured = 0; break; case NL80211_CHAN_WIDTH_80: new_primary_width = NL80211_CHAN_WIDTH_40; @@ -4429,11 +4431,19 @@ void ieee80211_chandef_downgrade(struct cfg80211_chan_def *c, } if (new_primary_width != NL80211_CHAN_WIDTH_20_NOHT) { - c->center_freq1 = - cfg80211_chandef_primary_freq(c, new_primary_width); + c->center_freq1 = cfg80211_chandef_primary(c, new_primary_width, + &c->punctured); c->width = new_primary_width; } + /* + * With an 80 MHz channel, we might have the puncturing in the primary + * 40 Mhz channel, but that's not valid when downgraded to 40 MHz width. + * In that case, downgrade again. + */ + if (!cfg80211_chandef_valid(c) && c->punctured) + goto again; + WARN_ON_ONCE(!cfg80211_chandef_valid(c)); } diff --git a/net/wireless/chan.c b/net/wireless/chan.c index bfa2ea935fc2..e2ce89afa9ff 100644 --- a/net/wireless/chan.c +++ b/net/wireless/chan.c @@ -6,7 +6,7 @@ * * Copyright 2009 Johannes Berg * Copyright 2013-2014 Intel Mobile Communications GmbH - * Copyright 2018-2023 Intel Corporation + * Copyright 2018-2024 Intel Corporation */ #include @@ -27,11 +27,10 @@ void cfg80211_chandef_create(struct cfg80211_chan_def *chandef, if (WARN_ON(!chan)) return; - chandef->chan = chan; - chandef->freq1_offset = chan->freq_offset; - chandef->center_freq2 = 0; - chandef->edmg.bw_config = 0; - chandef->edmg.channels = 0; + *chandef = (struct cfg80211_chan_def) { + .chan = chan, + .freq1_offset = chan->freq_offset, + }; switch (chan_type) { case NL80211_CHAN_NO_HT: @@ -87,10 +86,9 @@ static const struct cfg80211_per_bw_puncturing_values per_bw_puncturing[] = { CFG80211_PER_BW_VALID_PUNCTURING_VALUES(320) }; -bool cfg80211_valid_disable_subchannel_bitmap(u16 *bitmap, - const struct cfg80211_chan_def *chandef) +static bool valid_puncturing_bitmap(const struct cfg80211_chan_def *chandef) { - u32 idx, i, start_freq; + u32 idx, i, start_freq, primary_center = chandef->chan->center_freq; switch (chandef->width) { case NL80211_CHAN_WIDTH_80: @@ -106,24 +104,23 @@ bool cfg80211_valid_disable_subchannel_bitmap(u16 *bitmap, start_freq = chandef->center_freq1 - 160; break; default: - *bitmap = 0; - break; + return chandef->punctured == 0; } - if (!*bitmap) + if (!chandef->punctured) return true; /* check if primary channel is punctured */ - if (*bitmap & (u16)BIT((chandef->chan->center_freq - start_freq) / 20)) + if (chandef->punctured & (u16)BIT((primary_center - start_freq) / 20)) return false; - for (i = 0; i < per_bw_puncturing[idx].len; i++) - if (per_bw_puncturing[idx].valid_values[i] == *bitmap) + for (i = 0; i < per_bw_puncturing[idx].len; i++) { + if (per_bw_puncturing[idx].valid_values[i] == chandef->punctured) return true; + } return false; } -EXPORT_SYMBOL(cfg80211_valid_disable_subchannel_bitmap); static bool cfg80211_edmg_chandef_valid(const struct cfg80211_chan_def *chandef) { @@ -386,17 +383,19 @@ bool cfg80211_chandef_valid(const struct cfg80211_chan_def *chandef) !cfg80211_edmg_chandef_valid(chandef)) return false; - return true; + return valid_puncturing_bitmap(chandef); } EXPORT_SYMBOL(cfg80211_chandef_valid); -int cfg80211_chandef_primary_freq(const struct cfg80211_chan_def *c, - enum nl80211_chan_width primary_chan_width) +int cfg80211_chandef_primary(const struct cfg80211_chan_def *c, + enum nl80211_chan_width primary_chan_width, + u16 *punctured) { int pri_width = nl80211_chan_width_to_mhz(primary_chan_width); int width = cfg80211_chandef_get_width(c); u32 control = c->chan->center_freq; u32 center = c->center_freq1; + u16 _punct = 0; if (WARN_ON_ONCE(pri_width < 0 || width < 0)) return -1; @@ -405,26 +404,41 @@ int cfg80211_chandef_primary_freq(const struct cfg80211_chan_def *c, if (WARN_ON_ONCE(pri_width > width)) return -1; + if (!punctured) + punctured = &_punct; + + *punctured = c->punctured; + while (width > pri_width) { - if (control > center) + unsigned int bits_to_drop = width / 20 / 2; + + if (control > center) { center += width / 4; - else + *punctured >>= bits_to_drop; + } else { center -= width / 4; + *punctured &= (1 << bits_to_drop) - 1; + } width /= 2; } return center; } -EXPORT_SYMBOL(cfg80211_chandef_primary_freq); +EXPORT_SYMBOL(cfg80211_chandef_primary); static const struct cfg80211_chan_def * check_chandef_primary_compat(const struct cfg80211_chan_def *c1, const struct cfg80211_chan_def *c2, enum nl80211_chan_width primary_chan_width) { + u16 punct_c1 = 0, punct_c2 = 0; + /* check primary is compatible -> error if not */ - if (cfg80211_chandef_primary_freq(c1, primary_chan_width) != - cfg80211_chandef_primary_freq(c2, primary_chan_width)) + if (cfg80211_chandef_primary(c1, primary_chan_width, &punct_c1) != + cfg80211_chandef_primary(c2, primary_chan_width, &punct_c2)) + return ERR_PTR(-EINVAL); + + if (punct_c1 != punct_c2) return ERR_PTR(-EINVAL); /* assumes c1 is smaller width, if that was just checked -> done */ diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c index 68c20409eca6..b533412ad1e0 100644 --- a/net/wireless/nl80211.c +++ b/net/wireless/nl80211.c @@ -3218,21 +3218,6 @@ static bool nl80211_can_set_dev_channel(struct wireless_dev *wdev) wdev->iftype == NL80211_IFTYPE_P2P_GO; } -static int nl80211_parse_punct_bitmap(struct cfg80211_registered_device *rdev, - struct genl_info *info, - const struct cfg80211_chan_def *chandef, - u16 *punct_bitmap) -{ - if (!wiphy_ext_feature_isset(&rdev->wiphy, NL80211_EXT_FEATURE_PUNCT)) - return -EINVAL; - - *punct_bitmap = nla_get_u32(info->attrs[NL80211_ATTR_PUNCT_BITMAP]); - if (!cfg80211_valid_disable_subchannel_bitmap(punct_bitmap, chandef)) - return -EINVAL; - - return 0; -} - int nl80211_parse_chandef(struct cfg80211_registered_device *rdev, struct genl_info *info, struct cfg80211_chan_def *chandef) @@ -3340,6 +3325,19 @@ int nl80211_parse_chandef(struct cfg80211_registered_device *rdev, chandef->edmg.channels = 0; } + if (info->attrs[NL80211_ATTR_PUNCT_BITMAP]) { + chandef->punctured = + nla_get_u32(info->attrs[NL80211_ATTR_PUNCT_BITMAP]); + + if (chandef->punctured && + !wiphy_ext_feature_isset(&rdev->wiphy, + NL80211_EXT_FEATURE_PUNCT)) { + NL_SET_ERR_MSG(extack, + "driver doesn't support puncturing"); + return -EINVAL; + } + } + if (!cfg80211_chandef_valid(chandef)) { NL_SET_ERR_MSG(extack, "invalid channel definition"); return -EINVAL; @@ -3816,6 +3814,10 @@ int nl80211_send_chandef(struct sk_buff *msg, const struct cfg80211_chan_def *ch if (chandef->center_freq2 && nla_put_u32(msg, NL80211_ATTR_CENTER_FREQ2, chandef->center_freq2)) return -ENOBUFS; + if (chandef->punctured && + nla_put_u32(msg, NL80211_ATTR_PUNCT_BITMAP, chandef->punctured)) + return -ENOBUFS; + return 0; } EXPORT_SYMBOL(nl80211_send_chandef); @@ -6061,14 +6063,6 @@ static int nl80211_start_ap(struct sk_buff *skb, struct genl_info *info) goto out; } - if (info->attrs[NL80211_ATTR_PUNCT_BITMAP]) { - err = nl80211_parse_punct_bitmap(rdev, info, - ¶ms->chandef, - ¶ms->punct_bitmap); - if (err) - goto out; - } - if (!cfg80211_reg_can_beacon_relax(&rdev->wiphy, ¶ms->chandef, wdev->iftype)) { err = -EINVAL; @@ -10228,14 +10222,6 @@ skip_beacons: if (info->attrs[NL80211_ATTR_CH_SWITCH_BLOCK_TX]) params.block_tx = true; - if (info->attrs[NL80211_ATTR_PUNCT_BITMAP]) { - err = nl80211_parse_punct_bitmap(rdev, info, - ¶ms.chandef, - ¶ms.punct_bitmap); - if (err) - goto free; - } - err = rdev_channel_switch(rdev, dev, ¶ms); free: @@ -19356,7 +19342,7 @@ static void nl80211_ch_switch_notify(struct cfg80211_registered_device *rdev, struct cfg80211_chan_def *chandef, gfp_t gfp, enum nl80211_commands notif, - u8 count, bool quiet, u16 punct_bitmap) + u8 count, bool quiet) { struct wireless_dev *wdev = netdev->ieee80211_ptr; struct sk_buff *msg; @@ -19390,9 +19376,6 @@ static void nl80211_ch_switch_notify(struct cfg80211_registered_device *rdev, goto nla_put_failure; } - if (nla_put_u32(msg, NL80211_ATTR_PUNCT_BITMAP, punct_bitmap)) - goto nla_put_failure; - genlmsg_end(msg, hdr); genlmsg_multicast_netns(&nl80211_fam, wiphy_net(&rdev->wiphy), msg, 0, @@ -19405,7 +19388,7 @@ static void nl80211_ch_switch_notify(struct cfg80211_registered_device *rdev, void cfg80211_ch_switch_notify(struct net_device *dev, struct cfg80211_chan_def *chandef, - unsigned int link_id, u16 punct_bitmap) + unsigned int link_id) { struct wireless_dev *wdev = dev->ieee80211_ptr; struct wiphy *wiphy = wdev->wiphy; @@ -19414,7 +19397,7 @@ void cfg80211_ch_switch_notify(struct net_device *dev, lockdep_assert_wiphy(wdev->wiphy); WARN_INVALID_LINK_ID(wdev, link_id); - trace_cfg80211_ch_switch_notify(dev, chandef, link_id, punct_bitmap); + trace_cfg80211_ch_switch_notify(dev, chandef, link_id); switch (wdev->iftype) { case NL80211_IFTYPE_STATION: @@ -19443,15 +19426,14 @@ void cfg80211_ch_switch_notify(struct net_device *dev, cfg80211_sched_dfs_chan_update(rdev); nl80211_ch_switch_notify(rdev, dev, link_id, chandef, GFP_KERNEL, - NL80211_CMD_CH_SWITCH_NOTIFY, 0, false, - punct_bitmap); + NL80211_CMD_CH_SWITCH_NOTIFY, 0, false); } EXPORT_SYMBOL(cfg80211_ch_switch_notify); void cfg80211_ch_switch_started_notify(struct net_device *dev, struct cfg80211_chan_def *chandef, unsigned int link_id, u8 count, - bool quiet, u16 punct_bitmap) + bool quiet) { struct wireless_dev *wdev = dev->ieee80211_ptr; struct wiphy *wiphy = wdev->wiphy; @@ -19460,13 +19442,12 @@ void cfg80211_ch_switch_started_notify(struct net_device *dev, lockdep_assert_wiphy(wdev->wiphy); WARN_INVALID_LINK_ID(wdev, link_id); - trace_cfg80211_ch_switch_started_notify(dev, chandef, link_id, - punct_bitmap); + trace_cfg80211_ch_switch_started_notify(dev, chandef, link_id); nl80211_ch_switch_notify(rdev, dev, link_id, chandef, GFP_KERNEL, NL80211_CMD_CH_SWITCH_STARTED_NOTIFY, - count, quiet, punct_bitmap); + count, quiet); } EXPORT_SYMBOL(cfg80211_ch_switch_started_notify); diff --git a/net/wireless/tests/chan.c b/net/wireless/tests/chan.c index b9e7a27e43cb..d02258ac2dab 100644 --- a/net/wireless/tests/chan.c +++ b/net/wireless/tests/chan.c @@ -2,7 +2,7 @@ /* * KUnit tests for channel helper functions * - * Copyright (C) 2023 Intel Corporation + * Copyright (C) 2023-2024 Intel Corporation */ #include #include @@ -140,6 +140,52 @@ static const struct chandef_compat_case { }, .compat = true, }, + { + .desc = "matching primary 160 MHz & punctured secondary 160 Mhz", + .c1 = { + .width = NL80211_CHAN_WIDTH_160, + .chan = &chan_6ghz_105, + .center_freq1 = 6475 + 70, + }, + .c2 = { + .width = NL80211_CHAN_WIDTH_320, + .chan = &chan_6ghz_105, + .center_freq1 = 6475 - 10, + .punctured = 0xf, + }, + .compat = true, + }, + { + .desc = "matching primary 160 MHz & punctured matching", + .c1 = { + .width = NL80211_CHAN_WIDTH_160, + .chan = &chan_6ghz_105, + .center_freq1 = 6475 + 70, + .punctured = 0xc0, + }, + .c2 = { + .width = NL80211_CHAN_WIDTH_320, + .chan = &chan_6ghz_105, + .center_freq1 = 6475 - 10, + .punctured = 0xc000, + }, + .compat = true, + }, + { + .desc = "matching primary 160 MHz & punctured not matching", + .c1 = { + .width = NL80211_CHAN_WIDTH_160, + .chan = &chan_6ghz_105, + .center_freq1 = 6475 + 70, + .punctured = 0x80, + }, + .c2 = { + .width = NL80211_CHAN_WIDTH_320, + .chan = &chan_6ghz_105, + .center_freq1 = 6475 - 10, + .punctured = 0xc000, + }, + }, }; KUNIT_ARRAY_PARAM_DESC(chandef_compat, chandef_compat_cases, desc) diff --git a/net/wireless/trace.h b/net/wireless/trace.h index 1f374c8a17a5..ae5e585b6863 100644 --- a/net/wireless/trace.h +++ b/net/wireless/trace.h @@ -1,4 +1,9 @@ /* SPDX-License-Identifier: GPL-2.0 */ +/* + * Portions of this file + * Copyright(c) 2016-2017 Intel Deutschland GmbH + * Copyright (C) 2018, 2020-2024 Intel Corporation + */ #undef TRACE_SYSTEM #define TRACE_SYSTEM cfg80211 @@ -135,7 +140,8 @@ __field(u32, width) \ __field(u32, center_freq1) \ __field(u32, freq1_offset) \ - __field(u32, center_freq2) + __field(u32, center_freq2) \ + __field(u16, punctured) #define CHAN_DEF_ASSIGN(chandef) \ do { \ if ((chandef) && (chandef)->chan) { \ @@ -148,6 +154,7 @@ __entry->center_freq1 = (chandef)->center_freq1;\ __entry->freq1_offset = (chandef)->freq1_offset;\ __entry->center_freq2 = (chandef)->center_freq2;\ + __entry->punctured = (chandef)->punctured; \ } else { \ __entry->band = 0; \ __entry->control_freq = 0; \ @@ -156,14 +163,15 @@ __entry->center_freq1 = 0; \ __entry->freq1_offset = 0; \ __entry->center_freq2 = 0; \ + __entry->punctured = 0; \ } \ } while (0) #define CHAN_DEF_PR_FMT \ - "band: %d, control freq: %u.%03u, width: %d, cf1: %u.%03u, cf2: %u" + "band: %d, control freq: %u.%03u, width: %d, cf1: %u.%03u, cf2: %u, punct: 0x%x" #define CHAN_DEF_PR_ARG __entry->band, __entry->control_freq, \ __entry->freq_offset, __entry->width, \ __entry->center_freq1, __entry->freq1_offset, \ - __entry->center_freq2 + __entry->center_freq2, __entry->punctured #define FILS_AAD_ASSIGN(fa) \ do { \ @@ -3267,47 +3275,39 @@ TRACE_EVENT(cfg80211_chandef_dfs_required, TRACE_EVENT(cfg80211_ch_switch_notify, TP_PROTO(struct net_device *netdev, struct cfg80211_chan_def *chandef, - unsigned int link_id, - u16 punct_bitmap), - TP_ARGS(netdev, chandef, link_id, punct_bitmap), + unsigned int link_id), + TP_ARGS(netdev, chandef, link_id), TP_STRUCT__entry( NETDEV_ENTRY CHAN_DEF_ENTRY __field(unsigned int, link_id) - __field(u16, punct_bitmap) ), TP_fast_assign( NETDEV_ASSIGN; CHAN_DEF_ASSIGN(chandef); __entry->link_id = link_id; - __entry->punct_bitmap = punct_bitmap; ), - TP_printk(NETDEV_PR_FMT ", " CHAN_DEF_PR_FMT ", link:%d, punct_bitmap:%u", - NETDEV_PR_ARG, CHAN_DEF_PR_ARG, __entry->link_id, - __entry->punct_bitmap) + TP_printk(NETDEV_PR_FMT ", " CHAN_DEF_PR_FMT ", link:%d", + NETDEV_PR_ARG, CHAN_DEF_PR_ARG, __entry->link_id) ); TRACE_EVENT(cfg80211_ch_switch_started_notify, TP_PROTO(struct net_device *netdev, struct cfg80211_chan_def *chandef, - unsigned int link_id, - u16 punct_bitmap), - TP_ARGS(netdev, chandef, link_id, punct_bitmap), + unsigned int link_id), + TP_ARGS(netdev, chandef, link_id), TP_STRUCT__entry( NETDEV_ENTRY CHAN_DEF_ENTRY __field(unsigned int, link_id) - __field(u16, punct_bitmap) ), TP_fast_assign( NETDEV_ASSIGN; CHAN_DEF_ASSIGN(chandef); __entry->link_id = link_id; - __entry->punct_bitmap = punct_bitmap; ), - TP_printk(NETDEV_PR_FMT ", " CHAN_DEF_PR_FMT ", link:%d, punct_bitmap:%u", - NETDEV_PR_ARG, CHAN_DEF_PR_ARG, __entry->link_id, - __entry->punct_bitmap) + TP_printk(NETDEV_PR_FMT ", " CHAN_DEF_PR_FMT ", link:%d", + NETDEV_PR_ARG, CHAN_DEF_PR_ARG, __entry->link_id) ); TRACE_EVENT(cfg80211_radar_event, -- cgit v1.2.3 From 84d3776ef71df5ef3631021536d6b04e2383ebc8 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Tue, 6 Feb 2024 13:45:56 +0100 Subject: wifi: mac80211_hwsim: add missing kernel-doc Some kernel-doc is missing here, add it. Link: https://msgid.link/20240206134555.eb95c1dfc1f0.Ibaf8b3249d9de59358bf6503fe4a186d9ac6544d@changeid Signed-off-by: Johannes Berg --- drivers/net/wireless/virtual/mac80211_hwsim.h | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/virtual/mac80211_hwsim.h b/drivers/net/wireless/virtual/mac80211_hwsim.h index 4676cdaf4cfd..21b1afd83dc1 100644 --- a/drivers/net/wireless/virtual/mac80211_hwsim.h +++ b/drivers/net/wireless/virtual/mac80211_hwsim.h @@ -3,7 +3,7 @@ * mac80211_hwsim - software simulator of 802.11 radio(s) for mac80211 * Copyright (c) 2008, Jouni Malinen * Copyright (c) 2011, Javier Lopez - * Copyright (C) 2020, 2022-2023 Intel Corporation + * Copyright (C) 2020, 2022-2024 Intel Corporation */ #ifndef __MAC80211_HWSIM_H @@ -84,6 +84,8 @@ enum hwsim_tx_control_flags { * @HWSIM_CMD_START_PMSR: request to start peer measurement with the * %HWSIM_ATTR_PMSR_REQUEST. Result will be sent back asynchronously * with %HWSIM_CMD_REPORT_PMSR. + * @HWSIM_CMD_ABORT_PMSR: Abort previously started peer measurement. + * @HWSIM_CMD_REPORT_PMSR: Report peer measurement data. * @__HWSIM_CMD_MAX: enum limit */ enum hwsim_commands { @@ -298,6 +300,7 @@ enum hwsim_vqs { * Information about a receiving or transmitting bitrate * that can be mapped to struct rate_info * + * @__HWSIM_RATE_INFO_ATTR_INVALID: reserved, netlink attribute 0 is invalid * @HWSIM_RATE_INFO_ATTR_FLAGS: bitflag of flags from &enum rate_info_flags * @HWSIM_RATE_INFO_ATTR_MCS: mcs index if struct describes an HT/VHT/HE rate * @HWSIM_RATE_INFO_ATTR_LEGACY: bitrate in 100kbit/s for 802.11abg -- cgit v1.2.3 From f29a8be886f5dd12b97624a87d6c46e2cf8d1821 Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Tue, 6 Feb 2024 16:08:52 +0300 Subject: wifi: iwlwifi: return negative -EINVAL instead of positive EINVAL The '-' character is missing in -EINVAL. Fixes: fc7214c3c986 ("wifi: iwlwifi: read DSM functions from UEFI") Signed-off-by: Dan Carpenter Link: https://msgid.link/f0391316-ab30-4664-96ac-03445ab2aeba@moroto.mountain Signed-off-by: Johannes Berg --- drivers/net/wireless/intel/iwlwifi/fw/uefi.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/intel/iwlwifi/fw/uefi.c b/drivers/net/wireless/intel/iwlwifi/fw/uefi.c index fe6d0141cd5b..3c4c99eed110 100644 --- a/drivers/net/wireless/intel/iwlwifi/fw/uefi.c +++ b/drivers/net/wireless/intel/iwlwifi/fw/uefi.c @@ -679,7 +679,7 @@ int iwl_uefi_get_dsm(struct iwl_fw_runtime *fwrt, enum iwl_dsm_funcs func, u32 *value) { struct uefi_cnv_var_general_cfg *data; - int ret = EINVAL; + int ret = -EINVAL; /* Not supported function index */ if (func >= DSM_FUNC_NUM_FUNCS || func == 5) -- cgit v1.2.3 From 480e7048aa0bbf0a79a976cdfa0195fd157da902 Mon Sep 17 00:00:00 2001 From: Aditya Kumar Singh Date: Tue, 30 Jan 2024 19:39:15 +0530 Subject: wifi: mac80211: update beacon counters per link basis Currently, function to update beacon counter uses deflink to fetch the beacon and then update the counter. However, with MLO, there is a need to update the counter for the beacon in a particular link. Add support to use link_id in order to fetch the beacon from a particular link data during beacon update counter. Signed-off-by: Aditya Kumar Singh Link: https://msgid.link/20240130140918.1172387-3-quic_adisi@quicinc.com Signed-off-by: Johannes Berg --- drivers/net/wireless/ath/ath10k/mac.c | 2 +- drivers/net/wireless/ath/ath11k/mac.c | 2 +- drivers/net/wireless/intel/iwlwifi/mvm/mac-ctxt.c | 2 +- include/net/mac80211.h | 4 +++- net/mac80211/tx.c | 14 +++++++++++--- 5 files changed, 17 insertions(+), 7 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/ath/ath10k/mac.c b/drivers/net/wireless/ath/ath10k/mac.c index fc503db2fd8e..b80220406104 100644 --- a/drivers/net/wireless/ath/ath10k/mac.c +++ b/drivers/net/wireless/ath/ath10k/mac.c @@ -2035,7 +2035,7 @@ static void ath10k_mac_vif_ap_csa_count_down(struct ath10k_vif *arvif) return; if (!ieee80211_beacon_cntdwn_is_complete(vif)) { - ieee80211_beacon_update_cntdwn(vif); + ieee80211_beacon_update_cntdwn(vif, 0); ret = ath10k_mac_setup_bcn_tmpl(arvif); if (ret) diff --git a/drivers/net/wireless/ath/ath11k/mac.c b/drivers/net/wireless/ath/ath11k/mac.c index bbf4d1f4d310..f7cab50bdfd1 100644 --- a/drivers/net/wireless/ath/ath11k/mac.c +++ b/drivers/net/wireless/ath/ath11k/mac.c @@ -1586,7 +1586,7 @@ void ath11k_mac_bcn_tx_event(struct ath11k_vif *arvif) arvif->bcca_zero_sent = false; if (vif->bss_conf.color_change_active) - ieee80211_beacon_update_cntdwn(vif); + ieee80211_beacon_update_cntdwn(vif, 0); ath11k_mac_setup_bcn_tmpl(arvif); } diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/mac-ctxt.c b/drivers/net/wireless/intel/iwlwifi/mvm/mac-ctxt.c index 61269c7b1934..3dea06b28472 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/mac-ctxt.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/mac-ctxt.c @@ -1467,7 +1467,7 @@ static void iwl_mvm_csa_count_down(struct iwl_mvm *mvm, mvmvif->csa_countdown = true; if (!ieee80211_beacon_cntdwn_is_complete(csa_vif)) { - int c = ieee80211_beacon_update_cntdwn(csa_vif); + int c = ieee80211_beacon_update_cntdwn(csa_vif, 0); iwl_mvm_mac_ctxt_beacon_changed(mvm, csa_vif, &csa_vif->bss_conf); diff --git a/include/net/mac80211.h b/include/net/mac80211.h index 54aa4a06c878..8acee7ce3aa9 100644 --- a/include/net/mac80211.h +++ b/include/net/mac80211.h @@ -5526,6 +5526,7 @@ static inline struct sk_buff *ieee80211_beacon_get(struct ieee80211_hw *hw, /** * ieee80211_beacon_update_cntdwn - request mac80211 to decrement the beacon countdown * @vif: &struct ieee80211_vif pointer from the add_interface callback. + * @link_id: valid link_id during MLO or 0 for non-MLO * * The beacon counter should be updated after each beacon transmission. * This function is called implicitly when @@ -5535,7 +5536,8 @@ static inline struct sk_buff *ieee80211_beacon_get(struct ieee80211_hw *hw, * * Return: new countdown value */ -u8 ieee80211_beacon_update_cntdwn(struct ieee80211_vif *vif); +u8 ieee80211_beacon_update_cntdwn(struct ieee80211_vif *vif, + unsigned int link_id); /** * ieee80211_beacon_set_cntdwn - request mac80211 to set beacon countdown diff --git a/net/mac80211/tx.c b/net/mac80211/tx.c index 098b32947c2b..876de3ba98ba 100644 --- a/net/mac80211/tx.c +++ b/net/mac80211/tx.c @@ -5027,16 +5027,24 @@ static u8 __ieee80211_beacon_update_cntdwn(struct beacon_data *beacon) return beacon->cntdwn_current_counter; } -u8 ieee80211_beacon_update_cntdwn(struct ieee80211_vif *vif) +u8 ieee80211_beacon_update_cntdwn(struct ieee80211_vif *vif, unsigned int link_id) { struct ieee80211_sub_if_data *sdata = vif_to_sdata(vif); + struct ieee80211_link_data *link; struct beacon_data *beacon = NULL; u8 count = 0; + if (WARN_ON(link_id >= IEEE80211_MLD_MAX_NUM_LINKS)) + return 0; + rcu_read_lock(); + link = rcu_dereference(sdata->link[link_id]); + if (!link) + goto unlock; + if (sdata->vif.type == NL80211_IFTYPE_AP) - beacon = rcu_dereference(sdata->deflink.u.ap.beacon); + beacon = rcu_dereference(link->u.ap.beacon); else if (sdata->vif.type == NL80211_IFTYPE_ADHOC) beacon = rcu_dereference(sdata->u.ibss.presp); else if (ieee80211_vif_is_mesh(&sdata->vif)) @@ -5277,7 +5285,7 @@ ieee80211_beacon_get_ap(struct ieee80211_hw *hw, if (beacon->cntdwn_counter_offsets[0]) { if (!is_template) - ieee80211_beacon_update_cntdwn(vif); + ieee80211_beacon_update_cntdwn(vif, link->link_id); ieee80211_set_beacon_cntdwn(sdata, beacon, link); } -- cgit v1.2.3 From 04ada8599c35ecb2cf16c94eb118d227630d06ee Mon Sep 17 00:00:00 2001 From: Aditya Kumar Singh Date: Tue, 30 Jan 2024 19:39:18 +0530 Subject: wifi: mac80211: add support to call csa_finish on a link Currently ieee80211_csa_finish() function finalizes CSA by scheduling a finalizing worker using the deflink. With MLO, there is a need to do it on a given link basis. Pass link ID of the link on which CSA needs to be finalized. Signed-off-by: Aditya Kumar Singh Link: https://msgid.link/20240130140918.1172387-6-quic_adisi@quicinc.com Signed-off-by: Johannes Berg --- drivers/net/wireless/ath/ath10k/mac.c | 2 +- drivers/net/wireless/ath/ath10k/wmi.c | 2 +- drivers/net/wireless/ath/ath11k/wmi.c | 2 +- drivers/net/wireless/ath/ath12k/wmi.c | 2 +- drivers/net/wireless/ath/ath9k/beacon.c | 2 +- drivers/net/wireless/ath/ath9k/htc_drv_beacon.c | 2 +- drivers/net/wireless/intel/iwlwifi/mvm/mac-ctxt.c | 4 ++-- drivers/net/wireless/intel/iwlwifi/mvm/time-event.c | 2 +- drivers/net/wireless/mediatek/mt76/mac80211.c | 2 +- drivers/net/wireless/mediatek/mt76/mt7615/mcu.c | 2 +- drivers/net/wireless/mediatek/mt76/mt7915/mcu.c | 2 +- drivers/net/wireless/mediatek/mt76/mt7996/mcu.c | 2 +- drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_core.c | 2 +- drivers/net/wireless/ti/wlcore/event.c | 2 +- drivers/net/wireless/virtual/mac80211_hwsim.c | 2 +- include/net/mac80211.h | 3 ++- net/mac80211/cfg.c | 15 +++++++++++++-- 17 files changed, 31 insertions(+), 19 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/ath/ath10k/mac.c b/drivers/net/wireless/ath/ath10k/mac.c index b80220406104..41053219ee95 100644 --- a/drivers/net/wireless/ath/ath10k/mac.c +++ b/drivers/net/wireless/ath/ath10k/mac.c @@ -2047,7 +2047,7 @@ static void ath10k_mac_vif_ap_csa_count_down(struct ath10k_vif *arvif) ath10k_warn(ar, "failed to update prb tmpl during csa: %d\n", ret); } else { - ieee80211_csa_finish(vif); + ieee80211_csa_finish(vif, 0); } } diff --git a/drivers/net/wireless/ath/ath10k/wmi.c b/drivers/net/wireless/ath/ath10k/wmi.c index 9e2f0a50aaea..ddf15717d504 100644 --- a/drivers/net/wireless/ath/ath10k/wmi.c +++ b/drivers/net/wireless/ath/ath10k/wmi.c @@ -3885,7 +3885,7 @@ void ath10k_wmi_event_host_swba(struct ath10k *ar, struct sk_buff *skb) */ if (arvif->vif->bss_conf.csa_active && ieee80211_beacon_cntdwn_is_complete(arvif->vif)) { - ieee80211_csa_finish(arvif->vif); + ieee80211_csa_finish(arvif->vif, 0); continue; } diff --git a/drivers/net/wireless/ath/ath11k/wmi.c b/drivers/net/wireless/ath/ath11k/wmi.c index 688ee20528a0..3c9f3b0bcfaa 100644 --- a/drivers/net/wireless/ath/ath11k/wmi.c +++ b/drivers/net/wireless/ath/ath11k/wmi.c @@ -8226,7 +8226,7 @@ ath11k_wmi_process_csa_switch_count_event(struct ath11k_base *ab, } if (arvif->is_up && arvif->vif->bss_conf.csa_active) - ieee80211_csa_finish(arvif->vif); + ieee80211_csa_finish(arvif->vif, 0); } rcu_read_unlock(); } diff --git a/drivers/net/wireless/ath/ath12k/wmi.c b/drivers/net/wireless/ath/ath12k/wmi.c index 2fa724e5851a..75c3a0d9b9ec 100644 --- a/drivers/net/wireless/ath/ath12k/wmi.c +++ b/drivers/net/wireless/ath/ath12k/wmi.c @@ -6448,7 +6448,7 @@ ath12k_wmi_process_csa_switch_count_event(struct ath12k_base *ab, } if (arvif->is_up && arvif->vif->bss_conf.csa_active) - ieee80211_csa_finish(arvif->vif); + ieee80211_csa_finish(arvif->vif, 0); } rcu_read_unlock(); } diff --git a/drivers/net/wireless/ath/ath9k/beacon.c b/drivers/net/wireless/ath/ath9k/beacon.c index ee72faac2f1d..4e48407138b2 100644 --- a/drivers/net/wireless/ath/ath9k/beacon.c +++ b/drivers/net/wireless/ath/ath9k/beacon.c @@ -368,7 +368,7 @@ bool ath9k_csa_is_finished(struct ath_softc *sc, struct ieee80211_vif *vif) if (!ieee80211_beacon_cntdwn_is_complete(vif)) return false; - ieee80211_csa_finish(vif); + ieee80211_csa_finish(vif, 0); return true; } diff --git a/drivers/net/wireless/ath/ath9k/htc_drv_beacon.c b/drivers/net/wireless/ath/ath9k/htc_drv_beacon.c index 533471e69400..8179d35dc310 100644 --- a/drivers/net/wireless/ath/ath9k/htc_drv_beacon.c +++ b/drivers/net/wireless/ath/ath9k/htc_drv_beacon.c @@ -517,7 +517,7 @@ bool ath9k_htc_csa_is_finished(struct ath9k_htc_priv *priv) if (!ieee80211_beacon_cntdwn_is_complete(vif)) return false; - ieee80211_csa_finish(vif); + ieee80211_csa_finish(vif, 0); priv->csa_vif = NULL; return true; diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/mac-ctxt.c b/drivers/net/wireless/intel/iwlwifi/mvm/mac-ctxt.c index 3dea06b28472..7cb6bc97b26c 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/mac-ctxt.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/mac-ctxt.c @@ -1486,7 +1486,7 @@ static void iwl_mvm_csa_count_down(struct iwl_mvm *mvm, } } else if (!iwl_mvm_te_scheduled(&mvmvif->time_event_data)) { /* we don't have CSA NoA scheduled yet, switch now */ - ieee80211_csa_finish(csa_vif); + ieee80211_csa_finish(csa_vif, 0); RCU_INIT_POINTER(mvm->csa_vif, NULL); } } @@ -1836,7 +1836,7 @@ void iwl_mvm_channel_switch_start_notif(struct iwl_mvm *mvm, msecs_to_jiffies(IWL_MVM_CS_UNBLOCK_TX_TIMEOUT * csa_vif->bss_conf.beacon_int)); - ieee80211_csa_finish(csa_vif); + ieee80211_csa_finish(csa_vif, 0); rcu_read_unlock(); diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/time-event.c b/drivers/net/wireless/intel/iwlwifi/mvm/time-event.c index 60ec5ca6927c..b7461bc32527 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/time-event.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/time-event.c @@ -168,7 +168,7 @@ static void iwl_mvm_csa_noa_start(struct iwl_mvm *mvm) goto out_unlock; } - ieee80211_csa_finish(csa_vif); + ieee80211_csa_finish(csa_vif, 0); rcu_read_unlock(); diff --git a/drivers/net/wireless/mediatek/mt76/mac80211.c b/drivers/net/wireless/mediatek/mt76/mac80211.c index 8a3a90d1bfac..8bf82755ca4c 100644 --- a/drivers/net/wireless/mediatek/mt76/mac80211.c +++ b/drivers/net/wireless/mediatek/mt76/mac80211.c @@ -1614,7 +1614,7 @@ static void __mt76_csa_finish(void *priv, u8 *mac, struct ieee80211_vif *vif) { if (vif->bss_conf.csa_active && ieee80211_beacon_cntdwn_is_complete(vif)) - ieee80211_csa_finish(vif); + ieee80211_csa_finish(vif, 0); } void mt76_csa_finish(struct mt76_dev *dev) diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/mcu.c b/drivers/net/wireless/mediatek/mt76/mt7615/mcu.c index ae34d019e588..c807bd8d928d 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7615/mcu.c +++ b/drivers/net/wireless/mediatek/mt76/mt7615/mcu.c @@ -353,7 +353,7 @@ static void mt7615_mcu_csa_finish(void *priv, u8 *mac, struct ieee80211_vif *vif) { if (vif->bss_conf.csa_active) - ieee80211_csa_finish(vif); + ieee80211_csa_finish(vif, 0); } static void diff --git a/drivers/net/wireless/mediatek/mt76/mt7915/mcu.c b/drivers/net/wireless/mediatek/mt76/mt7915/mcu.c index df1ad6d4e12d..d90f98c50039 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7915/mcu.c +++ b/drivers/net/wireless/mediatek/mt76/mt7915/mcu.c @@ -228,7 +228,7 @@ mt7915_mcu_csa_finish(void *priv, u8 *mac, struct ieee80211_vif *vif) if (!vif->bss_conf.csa_active || vif->type == NL80211_IFTYPE_STATION) return; - ieee80211_csa_finish(vif); + ieee80211_csa_finish(vif, 0); } static void diff --git a/drivers/net/wireless/mediatek/mt76/mt7996/mcu.c b/drivers/net/wireless/mediatek/mt76/mt7996/mcu.c index 699be57309c2..3ec813077dc2 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7996/mcu.c +++ b/drivers/net/wireless/mediatek/mt76/mt7996/mcu.c @@ -341,7 +341,7 @@ mt7996_mcu_csa_finish(void *priv, u8 *mac, struct ieee80211_vif *vif) if (!vif->bss_conf.csa_active || vif->type == NL80211_IFTYPE_STATION) return; - ieee80211_csa_finish(vif); + ieee80211_csa_finish(vif, 0); } static void diff --git a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_core.c b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_core.c index b0c1db726d7a..66bf92c164c3 100644 --- a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_core.c +++ b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_core.c @@ -5740,7 +5740,7 @@ static void rtl8xxxu_update_beacon_work_callback(struct work_struct *work) if (vif->bss_conf.csa_active) { if (ieee80211_beacon_cntdwn_is_complete(vif)) { - ieee80211_csa_finish(vif); + ieee80211_csa_finish(vif, 0); return; } schedule_delayed_work(&priv->update_beacon_work, diff --git a/drivers/net/wireless/ti/wlcore/event.c b/drivers/net/wireless/ti/wlcore/event.c index 1e082d039b82..2499dc908305 100644 --- a/drivers/net/wireless/ti/wlcore/event.c +++ b/drivers/net/wireless/ti/wlcore/event.c @@ -233,7 +233,7 @@ void wlcore_event_channel_switch(struct wl1271 *wl, cancel_delayed_work(&wlvif->channel_switch_work); } else { set_bit(WLVIF_FLAG_BEACON_DISABLED, &wlvif->flags); - ieee80211_csa_finish(vif); + ieee80211_csa_finish(vif, 0); } } } diff --git a/drivers/net/wireless/virtual/mac80211_hwsim.c b/drivers/net/wireless/virtual/mac80211_hwsim.c index 907c0842fee7..c337afd8bee2 100644 --- a/drivers/net/wireless/virtual/mac80211_hwsim.c +++ b/drivers/net/wireless/virtual/mac80211_hwsim.c @@ -2303,7 +2303,7 @@ static void mac80211_hwsim_beacon_tx(void *arg, u8 *mac, } if (link_conf->csa_active && ieee80211_beacon_cntdwn_is_complete(vif)) - ieee80211_csa_finish(vif); + ieee80211_csa_finish(vif, link_id); } static enum hrtimer_restart diff --git a/include/net/mac80211.h b/include/net/mac80211.h index 8acee7ce3aa9..45d905b17a65 100644 --- a/include/net/mac80211.h +++ b/include/net/mac80211.h @@ -5555,12 +5555,13 @@ void ieee80211_beacon_set_cntdwn(struct ieee80211_vif *vif, u8 counter); /** * ieee80211_csa_finish - notify mac80211 about channel switch * @vif: &struct ieee80211_vif pointer from the add_interface callback. + * @link_id: valid link_id during MLO or 0 for non-MLO * * After a channel switch announcement was scheduled and the counter in this * announcement hits 1, this function must be called by the driver to * notify mac80211 that the channel can be changed. */ -void ieee80211_csa_finish(struct ieee80211_vif *vif); +void ieee80211_csa_finish(struct ieee80211_vif *vif, unsigned int link_id); /** * ieee80211_beacon_cntdwn_is_complete - find out if countdown reached 1 diff --git a/net/mac80211/cfg.c b/net/mac80211/cfg.c index d30a64cf95cd..156a4215dcda 100644 --- a/net/mac80211/cfg.c +++ b/net/mac80211/cfg.c @@ -3547,13 +3547,24 @@ cfg80211_beacon_dup(struct cfg80211_beacon_data *beacon) return new_beacon; } -void ieee80211_csa_finish(struct ieee80211_vif *vif) +void ieee80211_csa_finish(struct ieee80211_vif *vif, unsigned int link_id) { struct ieee80211_sub_if_data *sdata = vif_to_sdata(vif); struct ieee80211_local *local = sdata->local; + struct ieee80211_link_data *link_data; + + if (WARN_ON(link_id >= IEEE80211_MLD_MAX_NUM_LINKS)) + return; rcu_read_lock(); + link_data = rcu_dereference(sdata->link[link_id]); + if (WARN_ON(!link_data)) { + rcu_read_unlock(); + return; + } + + /* TODO: MBSSID with MLO changes */ if (vif->mbssid_tx_vif == vif) { /* Trigger ieee80211_csa_finish() on the non-transmitting * interfaces when channel switch is received on @@ -3572,7 +3583,7 @@ void ieee80211_csa_finish(struct ieee80211_vif *vif) &iter->deflink.csa_finalize_work); } } - wiphy_work_queue(local->hw.wiphy, &sdata->deflink.csa_finalize_work); + wiphy_work_queue(local->hw.wiphy, &link_data->csa_finalize_work); rcu_read_unlock(); } -- cgit v1.2.3 From 80b0c88033ff8a9a0d6817ccdeebd512bef06cc0 Mon Sep 17 00:00:00 2001 From: Miri Korenblit Date: Mon, 5 Feb 2024 00:06:04 +0200 Subject: wifi: iwlwifi: add HONOR to PPAG approved list Add HONOR to the list of the OEMs that are allowed to use the PPAG feature Signed-off-by: Miri Korenblit Reviewed-by: Emmanuel Grumbach Link: https://msgid.link/20240204235836.3498abc62910.I156c34206c58ff26e73f705cbda6f1a49b88edda@changeid Signed-off-by: Johannes Berg --- drivers/net/wireless/intel/iwlwifi/fw/regulatory.c | 5 +++++ 1 file changed, 5 insertions(+) (limited to 'drivers/net') diff --git a/drivers/net/wireless/intel/iwlwifi/fw/regulatory.c b/drivers/net/wireless/intel/iwlwifi/fw/regulatory.c index 21b90278d1f2..597735a660a2 100644 --- a/drivers/net/wireless/intel/iwlwifi/fw/regulatory.c +++ b/drivers/net/wireless/intel/iwlwifi/fw/regulatory.c @@ -94,6 +94,11 @@ static const struct dmi_system_id dmi_ppag_approved_list[] = { DMI_MATCH(DMI_SYS_VENDOR, "Razer"), }, }, + { .ident = "Honor", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "HONOR"), + }, + }, {} }; -- cgit v1.2.3 From a20ac99b5f5ee768866b42d28138d90d89158042 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Mon, 5 Feb 2024 00:06:05 +0200 Subject: wifi: iwlwifi: pcie: don't allow hw-rfkill to stop device on gen2 On new devices the HW rfkill shutdown doesn't need to be handled "as fast as possible", so disallow the immediate shutdown mode here via documentation and a warning. Signed-off-by: Johannes Berg Signed-off-by: Miri Korenblit Link: https://msgid.link/20240204235836.794c5387e67e.I064365428815ec3135afa345fbbde78449b60203@changeid Signed-off-by: Johannes Berg --- drivers/net/wireless/intel/iwlwifi/iwl-op-mode.h | 4 +++- drivers/net/wireless/intel/iwlwifi/pcie/trans.c | 9 +++------ 2 files changed, 6 insertions(+), 7 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/intel/iwlwifi/iwl-op-mode.h b/drivers/net/wireless/intel/iwlwifi/iwl-op-mode.h index 3dc618a7c70f..1ca82f3e4ebf 100644 --- a/drivers/net/wireless/intel/iwlwifi/iwl-op-mode.h +++ b/drivers/net/wireless/intel/iwlwifi/iwl-op-mode.h @@ -68,9 +68,11 @@ struct iwl_cfg; * Must be atomic and called with BH disabled. * @queue_not_full: notifies that a HW queue is not full any more. * Must be atomic and called with BH disabled. - * @hw_rf_kill:notifies of a change in the HW rf kill switch. True means that + * @hw_rf_kill: notifies of a change in the HW rf kill switch. True means that * the radio is killed. Return %true if the device should be stopped by * the transport immediately after the call. May sleep. + * Note that this must not return %true for newer devices using gen2 PCIe + * transport. * @free_skb: allows the transport layer to free skbs that haven't been * reclaimed by the op_mode. This can happen when the driver is freed and * there are Tx packets pending in the transport layer. diff --git a/drivers/net/wireless/intel/iwlwifi/pcie/trans.c b/drivers/net/wireless/intel/iwlwifi/pcie/trans.c index b5756e168f49..6c76b2dd6878 100644 --- a/drivers/net/wireless/intel/iwlwifi/pcie/trans.c +++ b/drivers/net/wireless/intel/iwlwifi/pcie/trans.c @@ -1484,12 +1484,9 @@ void iwl_trans_pcie_rf_kill(struct iwl_trans *trans, bool state, bool from_irq) IWL_WARN(trans, "reporting RF_KILL (radio %s)\n", state ? "disabled" : "enabled"); - if (iwl_op_mode_hw_rf_kill(trans->op_mode, state)) { - if (trans->trans_cfg->gen2) - _iwl_trans_pcie_gen2_stop_device(trans); - else - _iwl_trans_pcie_stop_device(trans, from_irq); - } + if (iwl_op_mode_hw_rf_kill(trans->op_mode, state) && + !WARN_ON(trans->trans_cfg->gen2)) + _iwl_trans_pcie_stop_device(trans, from_irq); } void iwl_pcie_d3_complete_suspend(struct iwl_trans *trans, -- cgit v1.2.3 From 3d801a7591824aa29fdb0774e0881890d4a773f1 Mon Sep 17 00:00:00 2001 From: Anjaneyulu Date: Mon, 5 Feb 2024 00:06:06 +0200 Subject: wifi: iwlwifi: Add support for PPAG cmd v5 and PPAG revision 3 Add support for - PPAG revision 3 in BIOS to enable PPAG in UHB - PPAG command version 5, this command allows OEM to control enablement of PPAG for LPI for UHB mode in USA and ETSI countries. Signed-off-by: Anjaneyulu Signed-off-by: Miri Korenblit Link: https://msgid.link/20240204235836.d17425824b11.If2c1b29e3c579f4135383681af2d625cfe2cffcd@changeid Signed-off-by: Johannes Berg --- drivers/net/wireless/intel/iwlwifi/fw/acpi.c | 9 ++--- drivers/net/wireless/intel/iwlwifi/fw/api/power.h | 40 +++++++++++++++++++--- drivers/net/wireless/intel/iwlwifi/fw/regulatory.c | 20 +++++++---- drivers/net/wireless/intel/iwlwifi/fw/regulatory.h | 9 ++++- drivers/net/wireless/intel/iwlwifi/fw/runtime.h | 2 +- drivers/net/wireless/intel/iwlwifi/fw/uefi.c | 3 +- drivers/net/wireless/intel/iwlwifi/fw/uefi.h | 3 +- 7 files changed, 66 insertions(+), 20 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/intel/iwlwifi/fw/acpi.c b/drivers/net/wireless/intel/iwlwifi/fw/acpi.c index 9afb1b1d6aea..82ecea00f2b3 100644 --- a/drivers/net/wireless/intel/iwlwifi/fw/acpi.c +++ b/drivers/net/wireless/intel/iwlwifi/fw/acpi.c @@ -817,15 +817,15 @@ int iwl_acpi_get_ppag_table(struct iwl_fw_runtime *fwrt) if (IS_ERR(data)) return PTR_ERR(data); - /* try to read ppag table rev 2 or 1 (both have the same data size) */ + /* try to read ppag table rev 3, 2 or 1 (all have the same data size) */ wifi_pkg = iwl_acpi_get_wifi_pkg(fwrt->dev, data, ACPI_PPAG_WIFI_DATA_SIZE_V2, &tbl_rev); if (!IS_ERR(wifi_pkg)) { - if (tbl_rev == 1 || tbl_rev == 2) { + if (tbl_rev >= 1 && tbl_rev <= 3) { num_sub_bands = IWL_NUM_SUB_BANDS_V2; IWL_DEBUG_RADIO(fwrt, - "Reading PPAG table v2 (tbl_rev=%d)\n", + "Reading PPAG table (tbl_rev=%d)\n", tbl_rev); goto read_table; } else { @@ -857,7 +857,8 @@ read_table: goto out_free; } - fwrt->ppag_flags = flags->integer.value & IWL_PPAG_ETSI_CHINA_MASK; + fwrt->ppag_flags = iwl_bios_get_ppag_flags(flags->integer.value, + fwrt->ppag_ver); /* * read, verify gain values and save them into the PPAG table. diff --git a/drivers/net/wireless/intel/iwlwifi/fw/api/power.h b/drivers/net/wireless/intel/iwlwifi/fw/api/power.h index 040d83fa5424..0bf38243f88a 100644 --- a/drivers/net/wireless/intel/iwlwifi/fw/api/power.h +++ b/drivers/net/wireless/intel/iwlwifi/fw/api/power.h @@ -505,14 +505,41 @@ struct iwl_geo_tx_power_profiles_resp { __le32 profile_idx; } __packed; /* PER_CHAIN_LIMIT_OFFSET_RSP */ +/** + * enum iwl_ppag_flags - PPAG enable masks + * @IWL_PPAG_ETSI_MASK: enable PPAG in ETSI + * @IWL_PPAG_CHINA_MASK: enable PPAG in China + * @IWL_PPAG_ETSI_LPI_UHB_MASK: enable LPI in ETSI for UHB + * @IWL_PPAG_ETSI_VLP_UHB_MASK: enable VLP in ETSI for UHB + * @IWL_PPAG_ETSI_SP_UHB_MASK: enable SP in ETSI for UHB + * @IWL_PPAG_USA_LPI_UHB_MASK: enable LPI in USA for UHB + * @IWL_PPAG_USA_VLP_UHB_MASK: enable VLP in USA for UHB + * @IWL_PPAG_USA_SP_UHB_MASK: enable SP in USA for UHB + * @IWL_PPAG_CANADA_LPI_UHB_MASK: enable LPI in CANADA for UHB + * @IWL_PPAG_CANADA_VLP_UHB_MASK: enable VLP in CANADA for UHB + * @IWL_PPAG_CANADA_SP_UHB_MASK: enable SP in CANADA for UHB + */ +enum iwl_ppag_flags { + IWL_PPAG_ETSI_MASK = BIT(0), + IWL_PPAG_CHINA_MASK = BIT(1), + IWL_PPAG_ETSI_LPI_UHB_MASK = BIT(2), + IWL_PPAG_ETSI_VLP_UHB_MASK = BIT(3), + IWL_PPAG_ETSI_SP_UHB_MASK = BIT(4), + IWL_PPAG_USA_LPI_UHB_MASK = BIT(5), + IWL_PPAG_USA_VLP_UHB_MASK = BIT(6), + IWL_PPAG_USA_SP_UHB_MASK = BIT(7), + IWL_PPAG_CANADA_LPI_UHB_MASK = BIT(8), + IWL_PPAG_CANADA_VLP_UHB_MASK = BIT(9), + IWL_PPAG_CANADA_SP_UHB_MASK = BIT(10), +}; + /** * union iwl_ppag_table_cmd - union for all versions of PPAG command * @v1: version 1 * @v2: version 2 - * - * @flags: bit 0 - indicates enablement of PPAG for ETSI - * bit 1 - indicates enablement of PPAG for CHINA BIOS - * bit 1 can be used only in v3 (identical to v2) + * version 3, 4 and 5 are the same structure as v2, + * but has a different format of the flags bitmap + * @flags: values from &enum iwl_ppag_flags * @gain: table of antenna gain values per chain and sub-band * @reserved: reserved */ @@ -529,6 +556,11 @@ union iwl_ppag_table_cmd { } v2; } __packed; +#define IWL_PPAG_CMD_V4_MASK (IWL_PPAG_ETSI_MASK | IWL_PPAG_CHINA_MASK) +#define IWL_PPAG_CMD_V5_MASK (IWL_PPAG_CMD_V4_MASK | \ + IWL_PPAG_ETSI_LPI_UHB_MASK | \ + IWL_PPAG_USA_LPI_UHB_MASK) + #define MCC_TO_SAR_OFFSET_TABLE_ROW_SIZE 26 #define MCC_TO_SAR_OFFSET_TABLE_COL_SIZE 13 diff --git a/drivers/net/wireless/intel/iwlwifi/fw/regulatory.c b/drivers/net/wireless/intel/iwlwifi/fw/regulatory.c index 597735a660a2..36d506463e0e 100644 --- a/drivers/net/wireless/intel/iwlwifi/fw/regulatory.c +++ b/drivers/net/wireless/intel/iwlwifi/fw/regulatory.c @@ -320,7 +320,7 @@ int iwl_fill_ppag_table(struct iwl_fw_runtime *fwrt, WIDE_ID(PHY_OPS_GROUP, PER_PLATFORM_ANT_GAIN_CMD), 1); /* - * Starting from ver 4, driver needs to send the PPAG CMD regradless + * Starting from ver 4, driver needs to send the PPAG CMD regardless * if PPAG is enabled/disabled or valid/invalid. */ send_ppag_always = cmd_ver > 3; @@ -341,18 +341,18 @@ int iwl_fill_ppag_table(struct iwl_fw_runtime *fwrt, num_sub_bands = IWL_NUM_SUB_BANDS_V1; gain = cmd->v1.gain[0]; *cmd_size = sizeof(cmd->v1); - if (fwrt->ppag_ver == 1 || fwrt->ppag_ver == 2) { + if (fwrt->ppag_ver >= 1) { /* in this case FW supports revision 0 */ IWL_DEBUG_RADIO(fwrt, "PPAG table rev is %d, send truncated table\n", fwrt->ppag_ver); } - } else if (cmd_ver >= 2 && cmd_ver <= 4) { + } else if (cmd_ver >= 2 && cmd_ver <= 5) { num_sub_bands = IWL_NUM_SUB_BANDS_V2; gain = cmd->v2.gain[0]; *cmd_size = sizeof(cmd->v2); if (fwrt->ppag_ver == 0) { - /* in this case FW supports revisions 1 or 2 */ + /* in this case FW supports revisions 1,2 or 3 */ IWL_DEBUG_RADIO(fwrt, "PPAG table rev is 0, send padded table\n"); } @@ -364,11 +364,17 @@ int iwl_fill_ppag_table(struct iwl_fw_runtime *fwrt, /* ppag mode */ IWL_DEBUG_RADIO(fwrt, "PPAG MODE bits were read from bios: %d\n", - cmd->v1.flags); + le32_to_cpu(cmd->v1.flags)); + + if (cmd_ver == 5) + cmd->v1.flags &= cpu_to_le32(IWL_PPAG_CMD_V5_MASK); + else if (cmd_ver < 5) + cmd->v1.flags &= cpu_to_le32(IWL_PPAG_CMD_V4_MASK); + if ((cmd_ver == 1 && !fw_has_capa(&fwrt->fw->ucode_capa, IWL_UCODE_TLV_CAPA_PPAG_CHINA_BIOS_SUPPORT)) || - (cmd_ver == 2 && fwrt->ppag_ver == 2)) { + (cmd_ver == 2 && fwrt->ppag_ver >= 2)) { cmd->v1.flags &= cpu_to_le32(IWL_PPAG_ETSI_MASK); IWL_DEBUG_RADIO(fwrt, "masking ppag China bit\n"); } else { @@ -377,7 +383,7 @@ int iwl_fill_ppag_table(struct iwl_fw_runtime *fwrt, IWL_DEBUG_RADIO(fwrt, "PPAG MODE bits going to be sent: %d\n", - cmd->v1.flags); + le32_to_cpu(cmd->v1.flags)); for (i = 0; i < IWL_NUM_CHAIN_LIMITS; i++) { for (j = 0; j < num_sub_bands; j++) { diff --git a/drivers/net/wireless/intel/iwlwifi/fw/regulatory.h b/drivers/net/wireless/intel/iwlwifi/fw/regulatory.h index 52389f82cbb9..28e774766847 100644 --- a/drivers/net/wireless/intel/iwlwifi/fw/regulatory.h +++ b/drivers/net/wireless/intel/iwlwifi/fw/regulatory.h @@ -37,7 +37,7 @@ #define IWL_PPAG_MAX_HB 40 #define IWL_PPAG_ETSI_CHINA_MASK 3 -#define IWL_PPAG_ETSI_MASK BIT(0) +#define IWL_PPAG_REV3_MASK 0x7FF #define IWL_WTAS_BLACK_LIST_MAX 16 #define IWL_WTAS_ENABLED_MSK 0x1 @@ -189,4 +189,11 @@ __le32 iwl_get_lari_config_bitmap(struct iwl_fw_runtime *fwrt); int iwl_bios_get_dsm(struct iwl_fw_runtime *fwrt, enum iwl_dsm_funcs func, u32 *value); + +static inline u32 iwl_bios_get_ppag_flags(const u32 ppag_modes, + const u8 ppag_ver) +{ + return ppag_modes & (ppag_ver < 3 ? IWL_PPAG_ETSI_CHINA_MASK : + IWL_PPAG_REV3_MASK); +} #endif /* __fw_regulatory_h__ */ diff --git a/drivers/net/wireless/intel/iwlwifi/fw/runtime.h b/drivers/net/wireless/intel/iwlwifi/fw/runtime.h index 16d9ea6dd386..bd0c9b2224e1 100644 --- a/drivers/net/wireless/intel/iwlwifi/fw/runtime.h +++ b/drivers/net/wireless/intel/iwlwifi/fw/runtime.h @@ -174,7 +174,7 @@ struct iwl_fw_runtime { bool geo_enabled; struct iwl_ppag_chain ppag_chains[IWL_NUM_CHAIN_LIMITS]; u32 ppag_flags; - u32 ppag_ver; + u8 ppag_ver; #ifdef CONFIG_ACPI struct iwl_sar_offset_mapping_cmd sgom_table; bool sgom_enabled; diff --git a/drivers/net/wireless/intel/iwlwifi/fw/uefi.c b/drivers/net/wireless/intel/iwlwifi/fw/uefi.c index 3c4c99eed110..5148e8049867 100644 --- a/drivers/net/wireless/intel/iwlwifi/fw/uefi.c +++ b/drivers/net/wireless/intel/iwlwifi/fw/uefi.c @@ -541,7 +541,8 @@ int iwl_uefi_get_ppag_table(struct iwl_fw_runtime *fwrt) } fwrt->ppag_ver = data->revision; - fwrt->ppag_flags = data->ppag_modes & IWL_PPAG_ETSI_CHINA_MASK; + fwrt->ppag_flags = iwl_bios_get_ppag_flags(data->ppag_modes, + fwrt->ppag_ver); BUILD_BUG_ON(sizeof(fwrt->ppag_chains) != sizeof(data->ppag_chains)); memcpy(&fwrt->ppag_chains, &data->ppag_chains, diff --git a/drivers/net/wireless/intel/iwlwifi/fw/uefi.h b/drivers/net/wireless/intel/iwlwifi/fw/uefi.h index 1f7c3f4c2901..39053290bd59 100644 --- a/drivers/net/wireless/intel/iwlwifi/fw/uefi.h +++ b/drivers/net/wireless/intel/iwlwifi/fw/uefi.h @@ -116,8 +116,7 @@ struct uefi_cnv_var_wgds { /* * struct uefi_cnv_var_ppag - PPAG table as defined in UEFI * @revision: the revision of the table - * @ppag_modes: bit 0 - PPAG is enabled/disabled in ETSI, - * bit 1 - PPAG is enabled/disabled in China + * @ppag_modes: values from &enum iwl_ppag_flags * @ppag_chains: the PPAG values per chain and band */ struct uefi_cnv_var_ppag { -- cgit v1.2.3 From e047e0e3cc8b647eecf6ce644d5dacba44700d94 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Mon, 5 Feb 2024 00:06:07 +0200 Subject: wifi: iwlwifi: mvm: const-ify chandef pointers In much of the PHY context handling code the chandef coming from mac80211 is read-only, mark them const to make that clearer. Signed-off-by: Johannes Berg Signed-off-by: Miri Korenblit Link: https://msgid.link/20240204235836.e7fbd3e26d85.I72d72e61dc5f5fc76c53e32cb60b66237eaedec3@changeid Signed-off-by: Johannes Berg --- drivers/net/wireless/intel/iwlwifi/mvm/mvm.h | 10 +++++----- drivers/net/wireless/intel/iwlwifi/mvm/phy-ctxt.c | 14 +++++++------- 2 files changed, 12 insertions(+), 12 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h b/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h index eb30c299a71e..37195cb5f70b 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h +++ b/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h @@ -1810,18 +1810,18 @@ void iwl_mvm_rx_shared_mem_cfg_notif(struct iwl_mvm *mvm, /* MVM PHY */ struct iwl_mvm_phy_ctxt *iwl_mvm_get_free_phy_ctxt(struct iwl_mvm *mvm); int iwl_mvm_phy_ctxt_add(struct iwl_mvm *mvm, struct iwl_mvm_phy_ctxt *ctxt, - struct cfg80211_chan_def *chandef, + const struct cfg80211_chan_def *chandef, u8 chains_static, u8 chains_dynamic); int iwl_mvm_phy_ctxt_changed(struct iwl_mvm *mvm, struct iwl_mvm_phy_ctxt *ctxt, - struct cfg80211_chan_def *chandef, + const struct cfg80211_chan_def *chandef, u8 chains_static, u8 chains_dynamic); void iwl_mvm_phy_ctxt_ref(struct iwl_mvm *mvm, struct iwl_mvm_phy_ctxt *ctxt); void iwl_mvm_phy_ctxt_unref(struct iwl_mvm *mvm, struct iwl_mvm_phy_ctxt *ctxt); int iwl_mvm_phy_ctx_count(struct iwl_mvm *mvm); -u8 iwl_mvm_get_channel_width(struct cfg80211_chan_def *chandef); -u8 iwl_mvm_get_ctrl_pos(struct cfg80211_chan_def *chandef); +u8 iwl_mvm_get_channel_width(const struct cfg80211_chan_def *chandef); +u8 iwl_mvm_get_ctrl_pos(const struct cfg80211_chan_def *chandef); int iwl_mvm_phy_send_rlc(struct iwl_mvm *mvm, struct iwl_mvm_phy_ctxt *ctxt, u8 chains_static, u8 chains_dynamic); @@ -2530,7 +2530,7 @@ static inline void iwl_mvm_set_chan_info(struct iwl_mvm *mvm, static inline void iwl_mvm_set_chan_info_chandef(struct iwl_mvm *mvm, struct iwl_fw_channel_info *ci, - struct cfg80211_chan_def *chandef) + const struct cfg80211_chan_def *chandef) { enum nl80211_band band = chandef->chan->band; diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/phy-ctxt.c b/drivers/net/wireless/intel/iwlwifi/mvm/phy-ctxt.c index 8bf778503b74..bac655834f32 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/phy-ctxt.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/phy-ctxt.c @@ -9,7 +9,7 @@ #include "mvm.h" /* Maps the driver specific channel width definition to the fw values */ -u8 iwl_mvm_get_channel_width(struct cfg80211_chan_def *chandef) +u8 iwl_mvm_get_channel_width(const struct cfg80211_chan_def *chandef) { switch (chandef->width) { case NL80211_CHAN_WIDTH_20_NOHT: @@ -33,7 +33,7 @@ u8 iwl_mvm_get_channel_width(struct cfg80211_chan_def *chandef) * Maps the driver specific control channel position (relative to the center * freq) definitions to the the fw values */ -u8 iwl_mvm_get_ctrl_pos(struct cfg80211_chan_def *chandef) +u8 iwl_mvm_get_ctrl_pos(const struct cfg80211_chan_def *chandef) { int offs = chandef->chan->center_freq - chandef->center_freq1; int abs_offs = abs(offs); @@ -116,7 +116,7 @@ static void iwl_mvm_phy_ctxt_set_rxchain(struct iwl_mvm *mvm, static void iwl_mvm_phy_ctxt_cmd_data_v1(struct iwl_mvm *mvm, struct iwl_mvm_phy_ctxt *ctxt, struct iwl_phy_context_cmd_v1 *cmd, - struct cfg80211_chan_def *chandef, + const struct cfg80211_chan_def *chandef, u8 chains_static, u8 chains_dynamic) { struct iwl_phy_context_cmd_tail *tail = @@ -137,7 +137,7 @@ static void iwl_mvm_phy_ctxt_cmd_data_v1(struct iwl_mvm *mvm, static void iwl_mvm_phy_ctxt_cmd_data(struct iwl_mvm *mvm, struct iwl_mvm_phy_ctxt *ctxt, struct iwl_phy_context_cmd *cmd, - struct cfg80211_chan_def *chandef, + const struct cfg80211_chan_def *chandef, u8 chains_static, u8 chains_dynamic) { cmd->lmac_id = cpu_to_le32(iwl_mvm_get_lmac_id(mvm, @@ -197,7 +197,7 @@ int iwl_mvm_phy_send_rlc(struct iwl_mvm *mvm, struct iwl_mvm_phy_ctxt *ctxt, */ static int iwl_mvm_phy_ctxt_apply(struct iwl_mvm *mvm, struct iwl_mvm_phy_ctxt *ctxt, - struct cfg80211_chan_def *chandef, + const struct cfg80211_chan_def *chandef, u8 chains_static, u8 chains_dynamic, u32 action) { @@ -254,7 +254,7 @@ static int iwl_mvm_phy_ctxt_apply(struct iwl_mvm *mvm, * Send a command to add a PHY context based on the current HW configuration. */ int iwl_mvm_phy_ctxt_add(struct iwl_mvm *mvm, struct iwl_mvm_phy_ctxt *ctxt, - struct cfg80211_chan_def *chandef, + const struct cfg80211_chan_def *chandef, u8 chains_static, u8 chains_dynamic) { int ret; @@ -300,7 +300,7 @@ void iwl_mvm_phy_ctxt_ref(struct iwl_mvm *mvm, struct iwl_mvm_phy_ctxt *ctxt) * changed. */ int iwl_mvm_phy_ctxt_changed(struct iwl_mvm *mvm, struct iwl_mvm_phy_ctxt *ctxt, - struct cfg80211_chan_def *chandef, + const struct cfg80211_chan_def *chandef, u8 chains_static, u8 chains_dynamic) { enum iwl_ctxt_action action = FW_CTXT_ACTION_MODIFY; -- cgit v1.2.3 From f94c24386d04ec242207bdbdc59ccb1b0b3cfc3c Mon Sep 17 00:00:00 2001 From: Miri Korenblit Date: Mon, 5 Feb 2024 00:06:08 +0200 Subject: wifi: iwlwifi: adjust rx_phyinfo debugfs to MLO This debugfs entry is used to configure the rx_phyinfo. Currently we are sending the phy cmd only for the deflink. Change it to send the cmd for all active links of the vif Signed-off-by: Miri Korenblit Reviewed-by: Gregory Greenman Link: https://msgid.link/20240204235836.a68ee2b6cb58.Iddc47c608ec990b12be0ae5b1ee89bcf6beb0f6a@changeid Signed-off-by: Johannes Berg --- .../net/wireless/intel/iwlwifi/mvm/debugfs-vif.c | 44 ++++++++++++++-------- 1 file changed, 28 insertions(+), 16 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/debugfs-vif.c b/drivers/net/wireless/intel/iwlwifi/mvm/debugfs-vif.c index e8b881596baf..2b96cf9eac72 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/debugfs-vif.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/debugfs-vif.c @@ -578,34 +578,46 @@ static ssize_t iwl_dbgfs_rx_phyinfo_write(struct ieee80211_vif *vif, char *buf, { struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); struct iwl_mvm *mvm = mvmvif->mvm; - struct ieee80211_chanctx_conf *chanctx_conf; - struct iwl_mvm_phy_ctxt *phy_ctxt; + struct ieee80211_bss_conf *link_conf; u16 value; - int ret; + int link_id, ret = -EINVAL; ret = kstrtou16(buf, 0, &value); if (ret) return ret; mutex_lock(&mvm->mutex); - rcu_read_lock(); - chanctx_conf = rcu_dereference(vif->bss_conf.chanctx_conf); - /* make sure the channel context is assigned */ - if (!chanctx_conf) { + mvm->dbgfs_rx_phyinfo = value; + + for_each_vif_active_link(vif, link_conf, link_id) { + struct ieee80211_chanctx_conf *chanctx_conf; + struct cfg80211_chan_def min_def; + struct iwl_mvm_phy_ctxt *phy_ctxt; + u8 chains_static, chains_dynamic; + + rcu_read_lock(); + chanctx_conf = rcu_dereference(link_conf->chanctx_conf); + if (!chanctx_conf) { + rcu_read_unlock(); + continue; + } + /* A command can't be sent with RCU lock held, so copy + * everything here and use it after unlocking + */ + min_def = chanctx_conf->min_def; + chains_static = chanctx_conf->rx_chains_static; + chains_dynamic = chanctx_conf->rx_chains_dynamic; rcu_read_unlock(); - mutex_unlock(&mvm->mutex); - return -EINVAL; - } - phy_ctxt = &mvm->phy_ctxts[*(u16 *)chanctx_conf->drv_priv]; - rcu_read_unlock(); + phy_ctxt = mvmvif->link[link_id]->phy_ctxt; + if (!phy_ctxt) + continue; - mvm->dbgfs_rx_phyinfo = value; + ret = iwl_mvm_phy_ctxt_changed(mvm, phy_ctxt, &min_def, + chains_static, chains_dynamic); + } - ret = iwl_mvm_phy_ctxt_changed(mvm, phy_ctxt, &chanctx_conf->min_def, - chanctx_conf->rx_chains_static, - chanctx_conf->rx_chains_dynamic); mutex_unlock(&mvm->mutex); return ret ?: count; -- cgit v1.2.3 From 814cdd7c37525133e54c667ca3cae6461ded93dd Mon Sep 17 00:00:00 2001 From: Miri Korenblit Date: Mon, 5 Feb 2024 00:06:09 +0200 Subject: wifi: iwlwifi: read mac step from aux register in BZ, the mac step is not updated to the HW REV CSR. For BZ-I, read it from the CNVI aux register For BZ-U always take B step. Signed-off-by: Miri Korenblit Link: https://msgid.link/20240204235836.dcc18b533f13.I0a6267fa0a142744bcf7500b45f667b596b492c5@changeid Signed-off-by: Johannes Berg --- drivers/net/wireless/intel/iwlwifi/iwl-prph.h | 6 +++++- drivers/net/wireless/intel/iwlwifi/pcie/ctxt-info-gen3.c | 2 +- drivers/net/wireless/intel/iwlwifi/pcie/ctxt-info.c | 4 ++-- drivers/net/wireless/intel/iwlwifi/pcie/drv.c | 14 ++++++++++++++ 4 files changed, 22 insertions(+), 4 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/intel/iwlwifi/iwl-prph.h b/drivers/net/wireless/intel/iwlwifi/iwl-prph.h index c1c7d44f421b..a7d44df06eab 100644 --- a/drivers/net/wireless/intel/iwlwifi/iwl-prph.h +++ b/drivers/net/wireless/intel/iwlwifi/iwl-prph.h @@ -368,7 +368,11 @@ enum { WFPM_AUX_CTL_AUX_IF_MAC_OWNER_MSK = 0x80000000, }; -#define CNVI_AUX_MISC_CHIP 0xA200B0 +#define CNVI_AUX_MISC_CHIP 0xA200B0 +#define CNVI_AUX_MISC_CHIP_MAC_STEP(_val) (((_val) & 0xf000000) >> 24) +#define CNVI_AUX_MISC_CHIP_PROD_TYPE(_val) ((_val) & 0xfff) +#define CNVI_AUX_MISC_CHIP_PROD_TYPE_BZ_U 0x930 + #define CNVR_AUX_MISC_CHIP 0xA2B800 #define CNVR_SCU_SD_REGS_SD_REG_DIG_DCDC_VTRIM 0xA29890 #define CNVR_SCU_SD_REGS_SD_REG_ACTIVE_VDIG_MIRROR 0xA29938 diff --git a/drivers/net/wireless/intel/iwlwifi/pcie/ctxt-info-gen3.c b/drivers/net/wireless/intel/iwlwifi/pcie/ctxt-info-gen3.c index fa4a14546860..c8fc8b4fd85c 100644 --- a/drivers/net/wireless/intel/iwlwifi/pcie/ctxt-info-gen3.c +++ b/drivers/net/wireless/intel/iwlwifi/pcie/ctxt-info-gen3.c @@ -119,7 +119,7 @@ int iwl_pcie_ctxt_info_gen3_init(struct iwl_trans *trans, prph_sc_ctrl->version.version = 0; prph_sc_ctrl->version.mac_id = - cpu_to_le16((u16)iwl_read32(trans, CSR_HW_REV)); + cpu_to_le16((u16)trans->hw_rev); prph_sc_ctrl->version.size = cpu_to_le16(sizeof(*prph_scratch) / 4); control_flags |= IWL_PRPH_SCRATCH_MTR_MODE; diff --git a/drivers/net/wireless/intel/iwlwifi/pcie/ctxt-info.c b/drivers/net/wireless/intel/iwlwifi/pcie/ctxt-info.c index 5f55efe64bf5..0fa92704cd14 100644 --- a/drivers/net/wireless/intel/iwlwifi/pcie/ctxt-info.c +++ b/drivers/net/wireless/intel/iwlwifi/pcie/ctxt-info.c @@ -1,7 +1,7 @@ // SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause /* * Copyright (C) 2017 Intel Deutschland GmbH - * Copyright (C) 2018-2022 Intel Corporation + * Copyright (C) 2018-2023 Intel Corporation */ #include "iwl-trans.h" #include "iwl-fh.h" @@ -180,7 +180,7 @@ int iwl_pcie_ctxt_info_init(struct iwl_trans *trans, ctxt_info->version.version = 0; ctxt_info->version.mac_id = - cpu_to_le16((u16)iwl_read32(trans, CSR_HW_REV)); + cpu_to_le16((u16)trans->hw_rev); /* size is in DWs */ ctxt_info->version.size = cpu_to_le16(sizeof(*ctxt_info) / 4); diff --git a/drivers/net/wireless/intel/iwlwifi/pcie/drv.c b/drivers/net/wireless/intel/iwlwifi/pcie/drv.c index bbc8dc390bdc..1ed67b76b516 100644 --- a/drivers/net/wireless/intel/iwlwifi/pcie/drv.c +++ b/drivers/net/wireless/intel/iwlwifi/pcie/drv.c @@ -1155,6 +1155,20 @@ static void get_crf_id(struct iwl_trans *iwl_trans) iwl_trans->hw_cnv_id = iwl_read_prph_no_grab(iwl_trans, CNVI_AUX_MISC_CHIP); + /* In BZ, the MAC step must be read from the CNVI aux register */ + if (CSR_HW_REV_TYPE(iwl_trans->hw_rev) == IWL_CFG_MAC_TYPE_BZ) { + u8 step = CNVI_AUX_MISC_CHIP_MAC_STEP(iwl_trans->hw_cnv_id); + + /* For BZ-U, take B step also when A step is indicated */ + if ((CNVI_AUX_MISC_CHIP_PROD_TYPE(iwl_trans->hw_cnv_id) == + CNVI_AUX_MISC_CHIP_PROD_TYPE_BZ_U) && + step == SILICON_A_STEP) + step = SILICON_B_STEP; + + iwl_trans->hw_rev_step = step; + iwl_trans->hw_rev |= step; + } + /* Read cdb info (also contains the jacket info if needed in the future */ iwl_trans->hw_wfpm_id = iwl_read_umac_prph_no_grab(iwl_trans, WFPM_OTP_CFG1_ADDR); -- cgit v1.2.3 From 83f57c936b6e210d517fb5fa526895234bc974e8 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Mon, 5 Feb 2024 00:06:10 +0200 Subject: wifi: iwlwifi: mvm: remove EHT code from mac80211.c The code here is the pre-MLD API, but of course older FW that doesn't support MLD APIs cannot support EHT. Remove some code that shouldn't be there. Signed-off-by: Johannes Berg Signed-off-by: Miri Korenblit Link: https://msgid.link/20240204235836.bde5a9d87759.I4c69dd94416f92b0f1f53dd57dafecbec643600d@changeid Signed-off-by: Johannes Berg --- drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c | 15 ++++----------- 1 file changed, 4 insertions(+), 11 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c b/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c index 65293b45a98f..7b57ae9f8ad3 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c @@ -2611,9 +2611,7 @@ static void iwl_mvm_bss_info_changed_station(struct iwl_mvm *mvm, */ if (changes & BSS_CHANGED_ASSOC && vif->cfg.assoc) { if ((vif->bss_conf.he_support && - !iwlwifi_mod_params.disable_11ax) || - (vif->bss_conf.eht_support && - !iwlwifi_mod_params.disable_11be)) + !iwlwifi_mod_params.disable_11ax)) iwl_mvm_cfg_he_sta(mvm, vif, mvmvif->deflink.ap_sta_id); iwl_mvm_mac_ctxt_recalc_tsf_id(mvm, vif); @@ -2622,10 +2620,7 @@ static void iwl_mvm_bss_info_changed_station(struct iwl_mvm *mvm, /* Update MU EDCA params */ if (changes & BSS_CHANGED_QOS && mvmvif->associated && vif->cfg.assoc && - ((vif->bss_conf.he_support && - !iwlwifi_mod_params.disable_11ax) || - (vif->bss_conf.eht_support && - !iwlwifi_mod_params.disable_11be))) + (vif->bss_conf.he_support && !iwlwifi_mod_params.disable_11ax)) iwl_mvm_cfg_he_sta(mvm, vif, mvmvif->deflink.ap_sta_id); /* @@ -3737,10 +3732,8 @@ iwl_mvm_sta_state_auth_to_assoc(struct ieee80211_hw *hw, * the default bss_conf */ if (!mvm->mld_api_is_used && - ((vif->bss_conf.he_support && - !iwlwifi_mod_params.disable_11ax) || - (vif->bss_conf.eht_support && - !iwlwifi_mod_params.disable_11be))) + (vif->bss_conf.he_support && + !iwlwifi_mod_params.disable_11ax)) iwl_mvm_cfg_he_sta(mvm, vif, mvm_sta->deflink.sta_id); } else if (vif->type == NL80211_IFTYPE_STATION) { iwl_mvm_vif_set_he_support(hw, vif, sta, true); -- cgit v1.2.3 From 318b3fac347cc307b39412cd8133488a83cd73a9 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Mon, 5 Feb 2024 00:06:11 +0200 Subject: wifi: iwlwifi: use system_unbound_wq for debug dump This can take some time, so it's better to use the unbound workqueue. Signed-off-by: Johannes Berg Signed-off-by: Miri Korenblit Link: https://msgid.link/20240204235836.75c8d2286f81.I478e9faf422f22ae66c0a113003fea83565c5692@changeid Signed-off-by: Johannes Berg --- drivers/net/wireless/intel/iwlwifi/fw/dbg.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/intel/iwlwifi/fw/dbg.c b/drivers/net/wireless/intel/iwlwifi/fw/dbg.c index e7ff043f9f0a..db6d7013df66 100644 --- a/drivers/net/wireless/intel/iwlwifi/fw/dbg.c +++ b/drivers/net/wireless/intel/iwlwifi/fw/dbg.c @@ -2878,7 +2878,8 @@ int iwl_fw_dbg_collect_desc(struct iwl_fw_runtime *fwrt, IWL_WARN(fwrt, "Collecting data: trigger %d fired.\n", le32_to_cpu(desc->trig_desc.type)); - schedule_delayed_work(&wk_data->wk, usecs_to_jiffies(delay)); + queue_delayed_work(system_unbound_wq, &wk_data->wk, + usecs_to_jiffies(delay)); return 0; } @@ -3180,7 +3181,9 @@ int iwl_fw_dbg_ini_collect(struct iwl_fw_runtime *fwrt, if (sync) iwl_fw_dbg_collect_sync(fwrt, idx); else - schedule_delayed_work(&fwrt->dump.wks[idx].wk, usecs_to_jiffies(delay)); + queue_delayed_work(system_unbound_wq, + &fwrt->dump.wks[idx].wk, + usecs_to_jiffies(delay)); return 0; } -- cgit v1.2.3 From 449619744df11873f4b4e534502e1f10653b57ce Mon Sep 17 00:00:00 2001 From: Emmanuel Grumbach Date: Mon, 5 Feb 2024 00:06:12 +0200 Subject: wifi: iwlwifi: mvm: don't support reduced tx power on ack for new devices This is no longer supported by the firmware. Signed-off-by: Emmanuel Grumbach Signed-off-by: Miri Korenblit Link: https://msgid.link/20240204235836.768d56206093.I737872ff19f0dbeefca42a239d673f05b9ac06f0@changeid Signed-off-by: Johannes Berg --- drivers/net/wireless/intel/iwlwifi/mvm/coex.c | 3 +++ 1 file changed, 3 insertions(+) (limited to 'drivers/net') diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/coex.c b/drivers/net/wireless/intel/iwlwifi/mvm/coex.c index 2c34c55ca5f4..535edb51d1c0 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/coex.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/coex.c @@ -181,6 +181,9 @@ static int iwl_mvm_bt_coex_reduced_txp(struct iwl_mvm *mvm, u8 sta_id, struct iwl_mvm_sta *mvmsta; u32 value; + if (mvm->trans->trans_cfg->device_family >= IWL_DEVICE_FAMILY_AX210) + return 0; + mvmsta = iwl_mvm_sta_from_staid_protected(mvm, sta_id); if (!mvmsta) return 0; -- cgit v1.2.3 From f51d6431824f0afb9f73d68971d154c47c26b86a Mon Sep 17 00:00:00 2001 From: Miri Korenblit Date: Mon, 5 Feb 2024 00:06:13 +0200 Subject: wifi: iwlwifi: support EHT for WH sku_cap_11be_enable should be set to true also for WH. Fixes: e1374ed25324 ("wifi: iwlwifi: Add support for new CNVi (SC)") Signed-off-by: Miri Korenblit Reviewed-by: Emmanuel Grumbach Link: https://msgid.link/20240204235836.a6d4097cbaca.I8b00fa7b6226b4116cd91f70fb0b15e79b4dee5a@changeid Signed-off-by: Johannes Berg --- drivers/net/wireless/intel/iwlwifi/iwl-nvm-parse.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/intel/iwlwifi/iwl-nvm-parse.c b/drivers/net/wireless/intel/iwlwifi/iwl-nvm-parse.c index c30187d77b3c..d2f133255ee6 100644 --- a/drivers/net/wireless/intel/iwlwifi/iwl-nvm-parse.c +++ b/drivers/net/wireless/intel/iwlwifi/iwl-nvm-parse.c @@ -2125,7 +2125,7 @@ struct iwl_nvm_data *iwl_get_nvm(struct iwl_trans *trans, !!(mac_flags & NVM_MAC_SKU_FLAGS_BAND_5_2_ENABLED); nvm->sku_cap_mimo_disabled = !!(mac_flags & NVM_MAC_SKU_FLAGS_MIMO_DISABLED); - if (CSR_HW_RFID_TYPE(trans->hw_rf_id) == IWL_CFG_RF_TYPE_FM) + if (CSR_HW_RFID_TYPE(trans->hw_rf_id) >= IWL_CFG_RF_TYPE_FM) nvm->sku_cap_11be_enable = true; /* Initialize PHY sku data */ -- cgit v1.2.3 From f863afbd301ef2a29364316dd14a73699d0bc673 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Mon, 5 Feb 2024 00:06:17 +0200 Subject: wifi: iwlwifi: mvm: remove one queue sync on BA session stop As documented in the comment, this queue sync was here to ensure that an async IWL_MVM_RXQ_NSSN_SYNC queue sync won't race with setting up a new BA session with the same BAID. However, we no longer do IWL_MVM_RXQ_NSSN_SYNC queue sync, so we can remove this as well. Signed-off-by: Johannes Berg Reviewed-by: Grumbach, Emmanuel Signed-off-by: Miri Korenblit Link: https://msgid.link/20240204235836.0a09ab337b54.I0dfe239dc30577a2ff23f910b10e9957364ccc78@changeid Signed-off-by: Johannes Berg --- drivers/net/wireless/intel/iwlwifi/mvm/sta.c | 12 +----------- 1 file changed, 1 insertion(+), 11 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/sta.c b/drivers/net/wireless/intel/iwlwifi/mvm/sta.c index 7e9f3a670212..f3efbec38253 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/sta.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/sta.c @@ -1,6 +1,6 @@ // SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause /* - * Copyright (C) 2012-2015, 2018-2023 Intel Corporation + * Copyright (C) 2012-2015, 2018-2024 Intel Corporation * Copyright (C) 2013-2015 Intel Mobile Communications GmbH * Copyright (C) 2016-2017 Intel Deutschland GmbH */ @@ -2989,16 +2989,6 @@ int iwl_mvm_sta_rx_agg(struct iwl_mvm *mvm, struct ieee80211_sta *sta, RCU_INIT_POINTER(mvm->baid_map[baid], NULL); kfree_rcu(baid_data, rcu_head); IWL_DEBUG_HT(mvm, "BAID %d is free\n", baid); - - /* - * After we've deleted it, do another queue sync - * so if an IWL_MVM_RXQ_NSSN_SYNC was concurrently - * running it won't find a new session in the old - * BAID. It can find the NULL pointer for the BAID, - * but we must not have it find a different session. - */ - iwl_mvm_sync_rx_queues_internal(mvm, IWL_MVM_RXQ_EMPTY, - true, NULL, 0); } return 0; -- cgit v1.2.3 From 8b720901d97d45d477121a406cb120cee6291b55 Mon Sep 17 00:00:00 2001 From: Avraham Stern Date: Tue, 6 Feb 2024 13:57:03 +0200 Subject: wifi: iwlwifi: mvm: advertise support for protected ranging negotiation Advertise support for protected ranging negotiation if the firmware supports it. Signed-off-by: Avraham Stern Reviewed-by: Luciano Coelho Signed-off-by: Miri Korenblit Link: https://msgid.link/20240206135637.9bb7e13ad18c.I578af1c9836e91069ce318b265bd221f42955992@changeid Signed-off-by: Johannes Berg --- drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c | 7 +++++++ 1 file changed, 7 insertions(+) (limited to 'drivers/net') diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c b/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c index 7b57ae9f8ad3..fa7d86917741 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c @@ -705,6 +705,13 @@ int iwl_mvm_mac_setup_register(struct iwl_mvm *mvm) } } + if (iwl_fw_lookup_cmd_ver(mvm->fw, WIDE_ID(LOCATION_GROUP, + TOF_RANGE_REQ_CMD), + IWL_FW_CMD_VER_UNKNOWN) >= 11) { + wiphy_ext_feature_set(hw->wiphy, + NL80211_EXT_FEATURE_PROT_RANGE_NEGO_AND_MEASURE); + } + mvm->rts_threshold = IEEE80211_MAX_RTS_THRESHOLD; #ifdef CONFIG_PM_SLEEP -- cgit v1.2.3 From 4d951e265c116c38862dcb1f59af5803762d4048 Mon Sep 17 00:00:00 2001 From: Ilan Peer Date: Mon, 5 Feb 2024 00:06:15 +0200 Subject: wifi: iwlwifi: mvm: Declare support for secure LTF measurement Declare support for secure LTF measurement if the FW supports it. Signed-off-by: Ilan Peer Signed-off-by: Miri Korenblit Link: https://msgid.link/20240204235836.f20d2437c06f.I479df8ab543db2d05c413119ad3eb3936cc86294@changeid Signed-off-by: Johannes Berg --- drivers/net/wireless/intel/iwlwifi/fw/file.h | 3 ++- drivers/net/wireless/intel/iwlwifi/mvm/ftm-responder.c | 6 ++++++ drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c | 5 +++++ 3 files changed, 13 insertions(+), 1 deletion(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/intel/iwlwifi/fw/file.h b/drivers/net/wireless/intel/iwlwifi/fw/file.h index b216da7d95fc..b7ef0882dbad 100644 --- a/drivers/net/wireless/intel/iwlwifi/fw/file.h +++ b/drivers/net/wireless/intel/iwlwifi/fw/file.h @@ -385,6 +385,7 @@ typedef unsigned int __bitwise iwl_ucode_tlv_capa_t; * complete to FW. * @IWL_UCODE_TLV_CAPA_SPP_AMSDU_SUPPORT: Support SPP (signaling and payload * protected) A-MSDU. + * @IWL_UCODE_TLV_CAPA_SECURE_LTF_SUPPORT: Support secure LTF measurement. * * @NUM_IWL_UCODE_TLV_CAPA: number of bits used */ @@ -483,7 +484,7 @@ enum iwl_ucode_tlv_capa { IWL_UCODE_TLV_CAPA_STA_EXP_MFP_SUPPORT = (__force iwl_ucode_tlv_capa_t)114, IWL_UCODE_TLV_CAPA_SNIFF_VALIDATE_SUPPORT = (__force iwl_ucode_tlv_capa_t)116, IWL_UCODE_TLV_CAPA_CHINA_22_REG_SUPPORT = (__force iwl_ucode_tlv_capa_t)117, - + IWL_UCODE_TLV_CAPA_SECURE_LTF_SUPPORT = (__force iwl_ucode_tlv_capa_t)121, NUM_IWL_UCODE_TLV_CAPA /* * This construction make both sparse (which cannot increment the previous diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/ftm-responder.c b/drivers/net/wireless/intel/iwlwifi/mvm/ftm-responder.c index f72ca38d7c0e..dca36b0662c7 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/ftm-responder.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/ftm-responder.c @@ -349,6 +349,12 @@ int iwl_mvm_ftm_respoder_add_pasn_sta(struct iwl_mvm *mvm, } if (hltk && hltk_len) { + if (!fw_has_capa(&mvm->fw->ucode_capa, + IWL_UCODE_TLV_CAPA_SECURE_LTF_SUPPORT)) { + IWL_ERR(mvm, "No support for secure LTF measurement\n"); + return -EINVAL; + } + hltk_data.cipher = iwl_mvm_cipher_to_location_cipher(cipher); if (hltk_data.cipher == IWL_LOCATION_CIPHER_INVALID) { IWL_ERR(mvm, "invalid cipher: %u\n", cipher); diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c b/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c index fa7d86917741..40e97e812f5f 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c @@ -710,6 +710,11 @@ int iwl_mvm_mac_setup_register(struct iwl_mvm *mvm) IWL_FW_CMD_VER_UNKNOWN) >= 11) { wiphy_ext_feature_set(hw->wiphy, NL80211_EXT_FEATURE_PROT_RANGE_NEGO_AND_MEASURE); + + if (fw_has_capa(&mvm->fw->ucode_capa, + IWL_UCODE_TLV_CAPA_SECURE_LTF_SUPPORT)) + wiphy_ext_feature_set(hw->wiphy, + NL80211_EXT_FEATURE_SECURE_LTF); } mvm->rts_threshold = IEEE80211_MAX_RTS_THRESHOLD; -- cgit v1.2.3 From f4eedfd88b62819bedad7d92571febef9093bc72 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Mon, 5 Feb 2024 21:21:01 +0200 Subject: wifi: iwlwifi: mvm: expand queue sync warning messages It's a bit tricky to understand what's going on here, add more data to the warning messages to make that clearer. Signed-off-by: Johannes Berg Reviewed-by: Emmanuel Grumbach Signed-off-by: Miri Korenblit Link: https://msgid.link/20240205211151.1df82a509636.I2f71811569a5c48eb166c4caa779af2d6160ad33@changeid Signed-off-by: Johannes Berg --- drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c | 7 ++++--- drivers/net/wireless/intel/iwlwifi/mvm/rxmq.c | 10 +++++----- 2 files changed, 9 insertions(+), 8 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c b/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c index 40e97e812f5f..3622f67588fe 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c @@ -1,6 +1,6 @@ // SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause /* - * Copyright (C) 2012-2014, 2018-2023 Intel Corporation + * Copyright (C) 2012-2014, 2018-2024 Intel Corporation * Copyright (C) 2013-2015 Intel Mobile Communications GmbH * Copyright (C) 2016-2017 Intel Deutschland GmbH */ @@ -6097,8 +6097,9 @@ void iwl_mvm_sync_rx_queues_internal(struct iwl_mvm *mvm, iwl_mvm_is_radio_killed(mvm), HZ); WARN_ONCE(!ret && !iwl_mvm_is_radio_killed(mvm), - "queue sync: failed to sync, state is 0x%lx\n", - mvm->queue_sync_state); + "queue sync: failed to sync, state is 0x%lx, cookie %d\n", + mvm->queue_sync_state, + mvm->queue_sync_cookie); } out: diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/rxmq.c b/drivers/net/wireless/intel/iwlwifi/mvm/rxmq.c index 67062fe40152..7979b7952a79 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/rxmq.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/rxmq.c @@ -1,6 +1,6 @@ // SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause /* - * Copyright (C) 2012-2014, 2018-2023 Intel Corporation + * Copyright (C) 2012-2014, 2018-2024 Intel Corporation * Copyright (C) 2013-2015 Intel Mobile Communications GmbH * Copyright (C) 2015-2017 Intel Deutschland GmbH */ @@ -688,11 +688,11 @@ void iwl_mvm_rx_queue_notif(struct iwl_mvm *mvm, struct napi_struct *napi, return; len -= sizeof(*notif) + sizeof(*internal_notif); - if (internal_notif->sync && - mvm->queue_sync_cookie != internal_notif->cookie) { - WARN_ONCE(1, "Received expired RX queue sync message\n"); + if (WARN_ONCE(internal_notif->sync && + mvm->queue_sync_cookie != internal_notif->cookie, + "Received expired RX queue sync message (cookie %d but wanted %d, queue %d)\n", + internal_notif->cookie, mvm->queue_sync_cookie, queue)) return; - } switch (internal_notif->type) { case IWL_MVM_RXQ_EMPTY: -- cgit v1.2.3 From 87f690f5a9030a694dbf9d794ee940998118a195 Mon Sep 17 00:00:00 2001 From: Shaul Triebitz Date: Mon, 5 Feb 2024 21:21:02 +0200 Subject: wifi: iwlwifi: mvm: define RX queue sync timeout as a macro define the timeout on RX queues notification as a macro so it will be clearer. Signed-off-by: Shaul Triebitz Reviewed-by: Luciano Coelho Signed-off-by: Miri Korenblit Link: https://msgid.link/20240205211151.a6985ea87751.Iafb7ae13aa58d66512e4b3fa6c75149c75cbc305@changeid Signed-off-by: Johannes Berg --- drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c b/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c index 3622f67588fe..f18c77d88f3a 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c @@ -6046,6 +6046,7 @@ void iwl_mvm_mac_event_callback(struct ieee80211_hw *hw, } } +#define SYNC_RX_QUEUE_TIMEOUT (HZ) void iwl_mvm_sync_rx_queues_internal(struct iwl_mvm *mvm, enum iwl_mvm_rxq_notif_type type, bool sync, @@ -6095,7 +6096,7 @@ void iwl_mvm_sync_rx_queues_internal(struct iwl_mvm *mvm, ret = wait_event_timeout(mvm->rx_sync_waitq, READ_ONCE(mvm->queue_sync_state) == 0 || iwl_mvm_is_radio_killed(mvm), - HZ); + SYNC_RX_QUEUE_TIMEOUT); WARN_ONCE(!ret && !iwl_mvm_is_radio_killed(mvm), "queue sync: failed to sync, state is 0x%lx, cookie %d\n", mvm->queue_sync_state, -- cgit v1.2.3 From 0dd2b42c2c096e39da4c35927db4ed1f6c587bea Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Mon, 5 Feb 2024 21:21:03 +0200 Subject: wifi: iwlwifi: mvm: don't abort queue sync in CT-kill CT kill should stop doing a lot of TX etc. to cool down the NIC, but we don't stop all commands from going to the NIC, and as such we shouldn't abort queue sync, since it can get confused if we do, warning that we do it twice at the same time etc. Only stop it when we'd also not send it in the first place. Signed-off-by: Johannes Berg Signed-off-by: Miri Korenblit Link: https://msgid.link/20240205211151.4e0745e2cd97.I311dc623ce68de6a2da3c21c8d84a387844f714a@changeid Signed-off-by: Johannes Berg --- drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c | 4 ++-- drivers/net/wireless/intel/iwlwifi/mvm/ops.c | 16 +++++++--------- 2 files changed, 9 insertions(+), 11 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c b/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c index f18c77d88f3a..ab1219f4a5dc 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c @@ -6095,9 +6095,9 @@ void iwl_mvm_sync_rx_queues_internal(struct iwl_mvm *mvm, lockdep_assert_held(&mvm->mutex); ret = wait_event_timeout(mvm->rx_sync_waitq, READ_ONCE(mvm->queue_sync_state) == 0 || - iwl_mvm_is_radio_killed(mvm), + iwl_mvm_is_radio_hw_killed(mvm), SYNC_RX_QUEUE_TIMEOUT); - WARN_ONCE(!ret && !iwl_mvm_is_radio_killed(mvm), + WARN_ONCE(!ret && !iwl_mvm_is_radio_hw_killed(mvm), "queue sync: failed to sync, state is 0x%lx, cookie %d\n", mvm->queue_sync_state, mvm->queue_sync_cookie); diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/ops.c b/drivers/net/wireless/intel/iwlwifi/mvm/ops.c index ad4146d3345a..77dce70eccc4 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/ops.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/ops.c @@ -1,6 +1,6 @@ // SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause /* - * Copyright (C) 2012-2014, 2018-2023 Intel Corporation + * Copyright (C) 2012-2014, 2018-2024 Intel Corporation * Copyright (C) 2013-2015 Intel Mobile Communications GmbH * Copyright (C) 2016-2017 Intel Deutschland GmbH */ @@ -1828,12 +1828,8 @@ static void iwl_mvm_wake_sw_queue(struct iwl_op_mode *op_mode, int hw_queue) static void iwl_mvm_set_rfkill_state(struct iwl_mvm *mvm) { - bool state = iwl_mvm_is_radio_killed(mvm); - - if (state) - wake_up(&mvm->rx_sync_waitq); - - wiphy_rfkill_set_hw_state(mvm->hw->wiphy, state); + wiphy_rfkill_set_hw_state(mvm->hw->wiphy, + iwl_mvm_is_radio_killed(mvm)); } void iwl_mvm_set_hw_ctkill_state(struct iwl_mvm *mvm, bool state) @@ -1858,10 +1854,12 @@ static bool iwl_mvm_set_hw_rfkill_state(struct iwl_op_mode *op_mode, bool state) bool rfkill_safe_init_done = READ_ONCE(mvm->rfkill_safe_init_done); bool unified = iwl_mvm_has_unified_ucode(mvm); - if (state) + if (state) { set_bit(IWL_MVM_STATUS_HW_RFKILL, &mvm->status); - else + wake_up(&mvm->rx_sync_waitq); + } else { clear_bit(IWL_MVM_STATUS_HW_RFKILL, &mvm->status); + } iwl_mvm_set_rfkill_state(mvm); -- cgit v1.2.3 From 74f4cd71070538bd9a8b6686fc53e7b77d510afa Mon Sep 17 00:00:00 2001 From: Miri Korenblit Date: Mon, 5 Feb 2024 21:21:04 +0200 Subject: wifi: iwlwifi: take SGOM and UATS code out of ACPI ifdef The BIOS tables SGOM and UATS are read from UEFI, but require additional tables (WGDS and DSM func 3, respectively) which used to be read from ACPI only, so the code handling those tables had to be under ifdef ACPI. But now the driver reads those tables (WGDS and DSM) from both ACPI and UEFI, so SGOM and UATS code shouldn't be under ifdef ACPI anymore. Signed-off-by: Miri Korenblit Link: https://msgid.link/20240205211151.dcaa3325773f.I649079c842369dcae3a362842322deca422a61d5@changeid Signed-off-by: Johannes Berg --- drivers/net/wireless/intel/iwlwifi/fw/runtime.h | 4 +--- drivers/net/wireless/intel/iwlwifi/fw/uefi.c | 4 +--- drivers/net/wireless/intel/iwlwifi/mvm/fw.c | 14 +------------- 3 files changed, 3 insertions(+), 19 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/intel/iwlwifi/fw/runtime.h b/drivers/net/wireless/intel/iwlwifi/fw/runtime.h index bd0c9b2224e1..b2bc4fd37abf 100644 --- a/drivers/net/wireless/intel/iwlwifi/fw/runtime.h +++ b/drivers/net/wireless/intel/iwlwifi/fw/runtime.h @@ -1,7 +1,7 @@ /* SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause */ /* * Copyright (C) 2017 Intel Deutschland GmbH - * Copyright (C) 2018-2023 Intel Corporation + * Copyright (C) 2018-2024 Intel Corporation */ #ifndef __iwl_fw_runtime_h__ #define __iwl_fw_runtime_h__ @@ -175,11 +175,9 @@ struct iwl_fw_runtime { struct iwl_ppag_chain ppag_chains[IWL_NUM_CHAIN_LIMITS]; u32 ppag_flags; u8 ppag_ver; -#ifdef CONFIG_ACPI struct iwl_sar_offset_mapping_cmd sgom_table; bool sgom_enabled; struct iwl_uats_table_cmd uats_table; -#endif u8 uefi_tables_lock_status; bool uats_enabled; }; diff --git a/drivers/net/wireless/intel/iwlwifi/fw/uefi.c b/drivers/net/wireless/intel/iwlwifi/fw/uefi.c index 5148e8049867..e81fc0129b9d 100644 --- a/drivers/net/wireless/intel/iwlwifi/fw/uefi.c +++ b/drivers/net/wireless/intel/iwlwifi/fw/uefi.c @@ -1,6 +1,6 @@ // SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause /* - * Copyright(c) 2021-2023 Intel Corporation + * Copyright(c) 2021-2024 Intel Corporation */ #include "iwl-drv.h" @@ -324,7 +324,6 @@ void iwl_uefi_get_step_table(struct iwl_trans *trans) } IWL_EXPORT_SYMBOL(iwl_uefi_get_step_table); -#ifdef CONFIG_ACPI static int iwl_uefi_sgom_parse(struct uefi_cnv_wlan_sgom_data *sgom_data, struct iwl_fw_runtime *fwrt) { @@ -412,7 +411,6 @@ int iwl_uefi_get_uats_table(struct iwl_trans *trans, return 0; } IWL_EXPORT_SYMBOL(iwl_uefi_get_uats_table); -#endif /* CONFIG_ACPI */ static void iwl_uefi_set_sar_profile(struct iwl_fw_runtime *fwrt, struct uefi_sar_profile *uefi_sar_prof, diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/fw.c b/drivers/net/wireless/intel/iwlwifi/mvm/fw.c index b596a1a83750..5381afdd4021 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/fw.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/fw.c @@ -1,6 +1,6 @@ // SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause /* - * Copyright (C) 2012-2014, 2018-2023 Intel Corporation + * Copyright (C) 2012-2014, 2018-2024 Intel Corporation * Copyright (C) 2013-2015 Intel Mobile Communications GmbH * Copyright (C) 2016-2017 Intel Deutschland GmbH */ @@ -488,7 +488,6 @@ static void iwl_mvm_phy_filter_init(struct iwl_mvm *mvm, #endif /* CONFIG_ACPI */ } -#if defined(CONFIG_ACPI) && defined(CONFIG_EFI) static void iwl_mvm_uats_init(struct iwl_mvm *mvm) { u8 cmd_ver; @@ -568,17 +567,6 @@ static int iwl_mvm_sgom_init(struct iwl_mvm *mvm) return ret; } -#else - -static int iwl_mvm_sgom_init(struct iwl_mvm *mvm) -{ - return 0; -} - -static void iwl_mvm_uats_init(struct iwl_mvm *mvm) -{ -} -#endif static int iwl_send_phy_cfg_cmd(struct iwl_mvm *mvm) { -- cgit v1.2.3 From 556c7cd721b5262579ba1710c3b4e7ffdb5573ac Mon Sep 17 00:00:00 2001 From: Miri Korenblit Date: Mon, 5 Feb 2024 21:21:05 +0200 Subject: wifi: iwlwifi: properly check if link is active Before sending SESSION PROTECTION cmd the driver verifies that the link for which the cmd is going to be sent is active. The existing code is checking it only for MLD vifs, but also the deflink (in non-MLD vifs) needs to be active in order the have a session protection for it. Fix this by checking if the link is active also for non-MLD vifs Fixes: 135065837310 ("wifi: iwlwifi: support link_id in SESSION_PROTECTION cmd") Signed-off-by: Miri Korenblit Reviewed-by: Johannes Berg Link: https://msgid.link/20240205211151.c61820f14ca6.Ibbe0f848f3e71f64313d21642650b6e4bfbe4b39@changeid Signed-off-by: Johannes Berg --- drivers/net/wireless/intel/iwlwifi/mvm/time-event.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/time-event.c b/drivers/net/wireless/intel/iwlwifi/mvm/time-event.c index b7461bc32527..2956127fd11b 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/time-event.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/time-event.c @@ -706,8 +706,7 @@ static int iwl_mvm_get_session_prot_id(struct iwl_mvm *mvm, "Invalid link ID for session protection: %u\n", link_id)) return -EINVAL; - if (WARN(ieee80211_vif_is_mld(vif) && - !(vif->active_links & BIT(link_id)), + if (WARN(!mvmvif->link[link_id]->active, "Session Protection on an inactive link: %u\n", link_id)) return -EINVAL; -- cgit v1.2.3 From b7acc059a728b591f1a27da0bfd460b0513fda7d Mon Sep 17 00:00:00 2001 From: Daniel Amosi Date: Mon, 5 Feb 2024 21:21:07 +0200 Subject: wifi: iwlwifi: mvm: Keep connection in case of missed beacons during RX The client needs to disconnect from AP in case of more than 19 missed beacons only if no data is coming from that AP, otherwise it needs to stay connected. Signed-off-by: Daniel Amosi Signed-off-by: Miri Korenblit Link: https://msgid.link/20240205211151.080195242c18.Ib166fc4e46666165a88e673a4a196cb8f18fdec4@changeid Signed-off-by: Johannes Berg --- drivers/net/wireless/intel/iwlwifi/mvm/mac-ctxt.c | 14 +++++++++++--- drivers/net/wireless/intel/iwlwifi/mvm/mvm.h | 3 ++- 2 files changed, 13 insertions(+), 4 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/mac-ctxt.c b/drivers/net/wireless/intel/iwlwifi/mvm/mac-ctxt.c index 7cb6bc97b26c..cc592e288188 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/mac-ctxt.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/mac-ctxt.c @@ -1,6 +1,6 @@ // SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause /* - * Copyright (C) 2012-2014, 2018-2023 Intel Corporation + * Copyright (C) 2012-2014, 2018-2024 Intel Corporation * Copyright (C) 2013-2014 Intel Mobile Communications GmbH * Copyright (C) 2015-2017 Intel Deutschland GmbH */ @@ -1626,8 +1626,16 @@ void iwl_mvm_rx_missed_beacons_notif(struct iwl_mvm *mvm, * TODO: the threshold should be adjusted based on latency conditions, * and/or in case of a CS flow on one of the other AP vifs. */ - if (rx_missed_bcon > IWL_MVM_MISSED_BEACONS_THRESHOLD_LONG) { - iwl_mvm_connection_loss(mvm, vif, "missed beacons"); + if (rx_missed_bcon >= IWL_MVM_MISSED_BEACONS_THRESHOLD_LONG) { + if (rx_missed_bcon_since_rx >= IWL_MVM_MISSED_BEACONS_SINCE_RX_THOLD) { + iwl_mvm_connection_loss(mvm, vif, "missed beacons"); + } else { + IWL_WARN(mvm, + "missed beacons exceeds threshold, but receiving data. Stay connected, Expect bugs.\n"); + IWL_WARN(mvm, + "missed_beacons:%d, missed_beacons_since_rx:%d\n", + rx_missed_bcon, rx_missed_bcon_since_rx); + } } else if (rx_missed_bcon_since_rx > IWL_MVM_MISSED_BEACONS_THRESHOLD) { if (!iwl_mvm_has_new_tx_api(mvm)) ieee80211_beacon_loss(vif); diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h b/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h index 37195cb5f70b..937d0bd9c531 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h +++ b/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h @@ -40,8 +40,9 @@ #define IWL_MVM_MAX_ADDRESSES 5 /* RSSI offset for WkP */ #define IWL_RSSI_OFFSET 50 +#define IWL_MVM_MISSED_BEACONS_SINCE_RX_THOLD 4 #define IWL_MVM_MISSED_BEACONS_THRESHOLD 8 -#define IWL_MVM_MISSED_BEACONS_THRESHOLD_LONG 16 +#define IWL_MVM_MISSED_BEACONS_THRESHOLD_LONG 19 /* A TimeUnit is 1024 microsecond */ #define MSEC_TO_TU(_msec) (_msec*1000/1024) -- cgit v1.2.3 From f05ef3497f260d0ab75aed45205bfe90beb3bd90 Mon Sep 17 00:00:00 2001 From: Shaul Triebitz Date: Mon, 5 Feb 2024 21:21:09 +0200 Subject: wifi: iwlwifi: mvm: fix the key PN index When waking from D3 (and a GTK rekey happened during D3), the key itself is saved in iwl_wowlan_status_data::gtk array, but the PN is saved in iwl_wowlan_status_data::gtk_seq array. The indices (of the same key) might differ in both arrays. Fix using the gtk array index in the gtk_seq array. Rather, iterate and search for the correct key in the gtk_seq array. Signed-off-by: Shaul Triebitz Signed-off-by: Miri Korenblit Link: https://msgid.link/20240205211151.bdd0511c007d.I3325288c64c010a4d008ac4429de1c2b14ef764c@changeid Signed-off-by: Johannes Berg --- drivers/net/wireless/intel/iwlwifi/mvm/d3.c | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/d3.c b/drivers/net/wireless/intel/iwlwifi/mvm/d3.c index 6396fbde03c4..994387eac6f7 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/d3.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/d3.c @@ -1,6 +1,6 @@ // SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause /* - * Copyright (C) 2012-2014, 2018-2023 Intel Corporation + * Copyright (C) 2012-2014, 2018-2024 Intel Corporation * Copyright (C) 2013-2015 Intel Mobile Communications GmbH * Copyright (C) 2016-2017 Intel Deutschland GmbH */ @@ -1958,7 +1958,7 @@ static bool iwl_mvm_gtk_rekey(struct iwl_wowlan_status_data *status, struct ieee80211_vif *vif, struct iwl_mvm *mvm, u32 gtk_cipher) { - int i; + int i, j; struct ieee80211_key_conf *key; struct { struct ieee80211_key_conf conf; @@ -2002,7 +2002,15 @@ static bool iwl_mvm_gtk_rekey(struct iwl_wowlan_status_data *status, key = ieee80211_gtk_rekey_add(vif, &conf.conf); if (IS_ERR(key)) return false; - iwl_mvm_set_key_rx_seq_idx(key, status, i); + + for (j = 0; j < ARRAY_SIZE(status->gtk_seq); j++) { + if (!status->gtk_seq[j].valid || + status->gtk_seq[j].key_id != key->keyidx) + continue; + iwl_mvm_set_key_rx_seq_idx(key, status, j); + break; + } + WARN_ON(j == ARRAY_SIZE(status->gtk_seq)); } return true; -- cgit v1.2.3 From 066425b6c8d25d9b8d6cf49e6d0910d8cb2d06fe Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Mon, 5 Feb 2024 21:21:10 +0200 Subject: wifi: iwlwifi: mvm: combine condition/warning WARN() returns the value of the condition, so it's nicer to combine the warning and the if. Signed-off-by: Johannes Berg Signed-off-by: Miri Korenblit Link: https://msgid.link/20240205211151.44f63334760e.If0a2cf347a8676a3830c5c3183a257fe11f31419@changeid Signed-off-by: Johannes Berg --- drivers/net/wireless/intel/iwlwifi/mvm/rxmq.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/rxmq.c b/drivers/net/wireless/intel/iwlwifi/mvm/rxmq.c index 7979b7952a79..7c0da3b8ad77 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/rxmq.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/rxmq.c @@ -649,10 +649,8 @@ static void iwl_mvm_release_frames_from_notif(struct iwl_mvm *mvm, rcu_read_lock(); ba_data = rcu_dereference(mvm->baid_map[baid]); - if (!ba_data) { - WARN(true, "BAID %d not found in map\n", baid); + if (WARN(!ba_data, "BAID %d not found in map\n", baid)) goto out; - } /* pick any STA ID to find the pointer */ sta_id = ffs(ba_data->sta_mask) - 1; -- cgit v1.2.3 From 1b3741ea4089ff7e87ea722004c0dc54adcbdf25 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Mon, 5 Feb 2024 21:21:11 +0200 Subject: wifi: iwlwifi: mvm: limit pseudo-D3 to 60 seconds With unlimited pseudo-D3, we can get stuck here in the read if the firmware never wakes up. All of our testing infrastructure however will anyway give up after at most a minute, so there's no value in that. Limit this to about a minute to avoid getting stuck with the RTNL held forever, which basically makes the machine unusable and then we can't even understand what caused the failure. Signed-off-by: Johannes Berg Signed-off-by: Miri Korenblit Link: https://msgid.link/20240205211151.ca55b3a7fa8d.Id746846f187442ebc689416d2688f2bd9278c0e9@changeid Signed-off-by: Johannes Berg --- drivers/net/wireless/intel/iwlwifi/mvm/d3.c | 7 +++++++ 1 file changed, 7 insertions(+) (limited to 'drivers/net') diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/d3.c b/drivers/net/wireless/intel/iwlwifi/mvm/d3.c index 994387eac6f7..af449cb9f967 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/d3.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/d3.c @@ -3389,6 +3389,7 @@ static ssize_t iwl_mvm_d3_test_read(struct file *file, char __user *user_buf, size_t count, loff_t *ppos) { struct iwl_mvm *mvm = file->private_data; + unsigned long end = jiffies + 60 * HZ; u32 pme_asserted; while (true) { @@ -3402,6 +3403,12 @@ static ssize_t iwl_mvm_d3_test_read(struct file *file, char __user *user_buf, if (msleep_interruptible(100)) break; + + if (time_is_before_jiffies(end)) { + IWL_ERR(mvm, + "ending pseudo-D3 with timeout after ~60 seconds\n"); + return -ETIMEDOUT; + } } return 0; -- cgit v1.2.3 From c4302c0f2dd31cd071ae8d49370b49bd78a22a9b Mon Sep 17 00:00:00 2001 From: Shaul Triebitz Date: Mon, 5 Feb 2024 21:21:12 +0200 Subject: wifi: iwlwifi: mvm: always update keys in D3 exit If during D3 there was both a GTK rekey and a disconnection, when waking up, we must first update the new keys and then disconnect. The reason is that when disconnecting we first need to remove the keys. Trying to remove invalid keys results in firmware assert. Signed-off-by: Shaul Triebitz Signed-off-by: Miri Korenblit Link: https://msgid.link/20240205211151.68cf3974b5d7.Iac9b71a1906ab973aba9baadc9e923b63c0b4945@changeid Signed-off-by: Johannes Berg --- drivers/net/wireless/intel/iwlwifi/mvm/d3.c | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/d3.c b/drivers/net/wireless/intel/iwlwifi/mvm/d3.c index af449cb9f967..89030647e639 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/d3.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/d3.c @@ -2100,7 +2100,6 @@ static bool iwl_mvm_setup_connection_keep(struct iwl_mvm *mvm, .status = status, }; int i; - u32 disconnection_reasons = IWL_WOWLAN_WAKEUP_BY_DISCONNECTION_ON_MISSED_BEACON | IWL_WOWLAN_WAKEUP_BY_DISCONNECTION_ON_DEAUTH; @@ -2108,9 +2107,6 @@ static bool iwl_mvm_setup_connection_keep(struct iwl_mvm *mvm, if (!status || !vif->bss_conf.bssid) return false; - if (status->wakeup_reasons & disconnection_reasons) - return false; - if (iwl_mvm_lookup_wowlan_status_ver(mvm) > 6 || iwl_fw_lookup_notif_ver(mvm->fw, PROT_OFFLOAD_GROUP, WOWLAN_INFO_NOTIFICATION, @@ -2171,6 +2167,9 @@ out: mvmvif->seqno = status->non_qos_seq_ctr + 0x10; } + if (status->wakeup_reasons & disconnection_reasons) + return false; + return true; } -- cgit v1.2.3 From 0c1c91604f3e3fc41f4d77dcfc3753860a9a32c9 Mon Sep 17 00:00:00 2001 From: Shaul Triebitz Date: Mon, 5 Feb 2024 21:21:13 +0200 Subject: wifi: iwlwifi: mvm: avoid garbage iPN After waking from D3, we set the iPN given by the firmware. For some reason, CIPHER_SUITE_AES_CMAC was missed. That caused copying garbage to the iPN - causing false replays. (since 'seq' is on the stack, and the iPN from the firmware was not copied into it, it contains garbage which later is copied to the iPN key). Signed-off-by: Shaul Triebitz Signed-off-by: Miri Korenblit Link: https://msgid.link/20240205211151.2be5b35be30f.I99db8700d01092d22a6d76f1fc1bd5916c9df784@changeid Signed-off-by: Johannes Berg --- drivers/net/wireless/intel/iwlwifi/mvm/d3.c | 3 +++ 1 file changed, 3 insertions(+) (limited to 'drivers/net') diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/d3.c b/drivers/net/wireless/intel/iwlwifi/mvm/d3.c index 89030647e639..5bc08c1d207a 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/d3.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/d3.c @@ -1866,9 +1866,12 @@ iwl_mvm_d3_set_igtk_bigtk_ipn(const struct iwl_multicast_key_data *key, memcpy(seq->aes_gmac.pn, key->ipn, sizeof(seq->aes_gmac.pn)); break; case WLAN_CIPHER_SUITE_BIP_CMAC_256: + case WLAN_CIPHER_SUITE_AES_CMAC: BUILD_BUG_ON(sizeof(seq->aes_cmac.pn) != sizeof(key->ipn)); memcpy(seq->aes_cmac.pn, key->ipn, sizeof(seq->aes_cmac.pn)); break; + default: + WARN_ON(1); } } -- cgit v1.2.3 From 2e0e766bd8a7f14f10c3e70b8203c4c1e6d9ec76 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Mon, 5 Feb 2024 21:21:14 +0200 Subject: wifi: iwlwifi: mvm: fix erroneous queue index mask When retrieving the queue index ("SCD SSN") from the TX response, it's currently masked with 0xFFF. However, now that we have queues longer than 4k, that became wrong, so make the mask depend on the hardware family. This fixes an issue where if we get a single frame reclaim while in the top half of an 8k long queue, we'd reclaim-wrap the queue twice (once on this and then again on the next non-single reclaim) which at least triggers the WARN_ON_ONCE() in iwl_txq_reclaim(), but could have other negative side effects (such as unmapping a frame that wasn't transmitted yet, and then taking an IOMMU fault) as well. Fixes: 7b3e42ea2ead ("iwlwifi: support multiple tfd queue max sizes for different devices") Signed-off-by: Johannes Berg Signed-off-by: Miri Korenblit Link: https://msgid.link/20240205211151.4148a6ef54e0.I733a70f679c25f9f99097a8dcb3a1f8165da6997@changeid Signed-off-by: Johannes Berg --- drivers/net/wireless/intel/iwlwifi/mvm/tx.c | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/tx.c b/drivers/net/wireless/intel/iwlwifi/mvm/tx.c index 58d1f283d628..f401cd6ef3ac 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/tx.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/tx.c @@ -1,6 +1,6 @@ // SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause /* - * Copyright (C) 2012-2014, 2018-2023 Intel Corporation + * Copyright (C) 2012-2014, 2018-2024 Intel Corporation * Copyright (C) 2013-2015 Intel Mobile Communications GmbH * Copyright (C) 2016-2017 Intel Deutschland GmbH */ @@ -1612,12 +1612,18 @@ static void iwl_mvm_tx_status_check_trigger(struct iwl_mvm *mvm, * of the batch. This is why the SSN of the SCD is written at the end of the * whole struct at a variable offset. This function knows how to cope with the * variable offset and returns the SSN of the SCD. + * + * For 22000-series and lower, this is just 12 bits. For later, 16 bits. */ static inline u32 iwl_mvm_get_scd_ssn(struct iwl_mvm *mvm, struct iwl_mvm_tx_resp *tx_resp) { - return le32_to_cpup((__le32 *)iwl_mvm_get_agg_status(mvm, tx_resp) + - tx_resp->frame_count) & 0xfff; + u32 val = le32_to_cpup((__le32 *)iwl_mvm_get_agg_status(mvm, tx_resp) + + tx_resp->frame_count); + + if (mvm->trans->trans_cfg->device_family >= IWL_DEVICE_FAMILY_AX210) + return val & 0xFFFF; + return val & 0xFFF; } static void iwl_mvm_rx_tx_cmd_single(struct iwl_mvm *mvm, -- cgit v1.2.3 From c82a950f63a32c3148db1c6e4a3bd7140a11a95d Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Mon, 5 Feb 2024 21:21:15 +0200 Subject: wifi: iwlwifi: mvm: don't do duplicate detection for nullfunc packets For non-QoS nullfunc packets we currently do the duplicate detection, which seems a bit wrong. Fix the code to check for _any_ instead of just _qos_ nullfunc. Also remove setting the RX_FLAG_DUP_VALIDATED flag, we haven't done anything here; in particular, we haven't checked for multicast in an MLO scenario. Signed-off-by: Johannes Berg Signed-off-by: Miri Korenblit Link: https://msgid.link/20240205211151.4fea3bd2d4a6.Ib80764f4581d875cff08469016894f7c817c3828@changeid Signed-off-by: Johannes Berg --- drivers/net/wireless/intel/iwlwifi/mvm/rxmq.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/rxmq.c b/drivers/net/wireless/intel/iwlwifi/mvm/rxmq.c index 7c0da3b8ad77..b7639e429889 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/rxmq.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/rxmq.c @@ -519,11 +519,9 @@ static bool iwl_mvm_is_dup(struct ieee80211_sta *sta, int queue, * (IEEE 802.11-2012: 9.3.2.10 "Duplicate detection and recovery") */ if (ieee80211_is_ctl(hdr->frame_control) || - ieee80211_is_qos_nullfunc(hdr->frame_control) || - is_multicast_ether_addr(hdr->addr1)) { - rx_status->flag |= RX_FLAG_DUP_VALIDATED; + ieee80211_is_any_nullfunc(hdr->frame_control) || + is_multicast_ether_addr(hdr->addr1)) return false; - } if (ieee80211_is_data_qos(hdr->frame_control)) { /* frame has qos control */ -- cgit v1.2.3 From 38a3241f2f7d6e863c71cd6f5fabf2a000d89c9f Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Tue, 6 Feb 2024 18:02:05 +0200 Subject: wifi: iwlwifi: fw: allow vmalloc for PNVM image This image can be pretty big (I've seen order-7 allocations!), and we later have to copy it to DMA memory (in newer FW even there it won't need to be contiguous), so we can easily deal with it being in vmalloc. Use kvmemdup()/kvfree() for it. Signed-off-by: Johannes Berg Signed-off-by: Miri Korenblit Link: https://msgid.link/20240206175739.9b4c06b5d533.Idf699b36ec95ee36f530355cd2cb1da297a098f1@changeid Signed-off-by: Johannes Berg --- drivers/net/wireless/intel/iwlwifi/fw/pnvm.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/intel/iwlwifi/fw/pnvm.c b/drivers/net/wireless/intel/iwlwifi/fw/pnvm.c index 053174f00e49..1195e708caa9 100644 --- a/drivers/net/wireless/intel/iwlwifi/fw/pnvm.c +++ b/drivers/net/wireless/intel/iwlwifi/fw/pnvm.c @@ -1,6 +1,6 @@ // SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause /* - * Copyright(c) 2020-2023 Intel Corporation + * Copyright(c) 2020-2024 Intel Corporation */ #include "iwl-drv.h" @@ -252,7 +252,7 @@ static int iwl_pnvm_get_from_fs(struct iwl_trans *trans, u8 **data, size_t *len) } new_len = pnvm->size; - *data = kmemdup(pnvm->data, pnvm->size, GFP_KERNEL); + *data = kvmemdup(pnvm->data, pnvm->size, GFP_KERNEL); release_firmware(pnvm); if (!*data) @@ -275,8 +275,8 @@ static u8 *iwl_get_pnvm_image(struct iwl_trans *trans_p, size_t *len) if (*len >= sizeof(*package)) { /* we need only the data */ *len -= sizeof(*package); - image = kmemdup(package->data, - *len, GFP_KERNEL); + image = kvmemdup(package->data, + *len, GFP_KERNEL); } /* * free package regardless of whether kmemdup @@ -333,7 +333,7 @@ static void iwl_pnvm_load_pnvm_to_trans(struct iwl_trans *trans, set: iwl_trans_set_pnvm(trans, capa); free: - kfree(data); + kvfree(data); kfree(pnvm_data); } -- cgit v1.2.3 From e35f316bce9e5733c9826120c1838f4c447b2c4c Mon Sep 17 00:00:00 2001 From: Emmanuel Grumbach Date: Tue, 6 Feb 2024 18:02:06 +0200 Subject: wifi: iwlwifi: mvm: don't set the MFP flag for the GTK The firmware doesn't need the MFP flag for the GTK, it can even make the firmware crash. in case the AP is configured with: group cipher TKIP and MFPC. We would send the GTK with cipher = TKIP and MFP which is of course not possible. Fixes: 5c75a208c244 ("wifi: iwlwifi: mvm: support new key API") Signed-off-by: Emmanuel Grumbach Signed-off-by: Miri Korenblit Link: https://msgid.link/20240206175739.2f2c602ab3c6.If13b2e2fa532381d985c07df130bee1478046c89@changeid Signed-off-by: Johannes Berg --- drivers/net/wireless/intel/iwlwifi/mvm/mld-key.c | 18 +++++++++++------- 1 file changed, 11 insertions(+), 7 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/mld-key.c b/drivers/net/wireless/intel/iwlwifi/mvm/mld-key.c index bbd37a95d4c8..8a38fc4b0b0f 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/mld-key.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/mld-key.c @@ -1,6 +1,6 @@ // SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause /* - * Copyright (C) 2022 - 2023 Intel Corporation + * Copyright (C) 2022 - 2024 Intel Corporation */ #include #include @@ -62,11 +62,13 @@ u32 iwl_mvm_get_sec_flags(struct iwl_mvm *mvm, struct ieee80211_key_conf *keyconf) { struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); + bool pairwise = keyconf->flags & IEEE80211_KEY_FLAG_PAIRWISE; + bool igtk = keyconf->keyidx == 4 || keyconf->keyidx == 5; u32 flags = 0; lockdep_assert_held(&mvm->mutex); - if (!(keyconf->flags & IEEE80211_KEY_FLAG_PAIRWISE)) + if (!pairwise) flags |= IWL_SEC_KEY_FLAG_MCAST_KEY; switch (keyconf->cipher) { @@ -96,12 +98,14 @@ u32 iwl_mvm_get_sec_flags(struct iwl_mvm *mvm, if (!sta && vif->type == NL80211_IFTYPE_STATION) sta = mvmvif->ap_sta; - /* Set the MFP flag also for an AP interface where the key is an IGTK - * key as in such a case the station would always be NULL + /* + * If we are installing an iGTK (in AP or STA mode), we need to tell + * the firmware this key will en/decrypt MGMT frames. + * Same goes if we are installing a pairwise key for an MFP station. + * In case we're installing a groupwise key (which is not an iGTK), + * then, we will not use this key for MGMT frames. */ - if ((!IS_ERR_OR_NULL(sta) && sta->mfp) || - (vif->type == NL80211_IFTYPE_AP && - (keyconf->keyidx == 4 || keyconf->keyidx == 5))) + if ((!IS_ERR_OR_NULL(sta) && sta->mfp && pairwise) || igtk) flags |= IWL_SEC_KEY_FLAG_MFP; if (keyconf->flags & IEEE80211_KEY_FLAG_SPP_AMSDU) -- cgit v1.2.3 From ff04f78ce38d79bdbf6b1fd276a6a2d035e21951 Mon Sep 17 00:00:00 2001 From: Emmanuel Grumbach Date: Tue, 6 Feb 2024 18:02:07 +0200 Subject: wifi: iwlwifi: mvm: don't send the smart fifo command if not needed Newer firmware versions no longer needs this command. Don't send it if the firmware advertises it does not need it. Signed-off-by: Emmanuel Grumbach Signed-off-by: Miri Korenblit Link: https://msgid.link/20240206175739.527595995aa0.I0381bef1dc815945f2ec194fecc657e5c75bb2ec@changeid Signed-off-by: Johannes Berg --- drivers/net/wireless/intel/iwlwifi/fw/file.h | 5 ++++- drivers/net/wireless/intel/iwlwifi/mvm/sf.c | 5 ++++- 2 files changed, 8 insertions(+), 2 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/intel/iwlwifi/fw/file.h b/drivers/net/wireless/intel/iwlwifi/fw/file.h index b7ef0882dbad..08d9aeaedd99 100644 --- a/drivers/net/wireless/intel/iwlwifi/fw/file.h +++ b/drivers/net/wireless/intel/iwlwifi/fw/file.h @@ -1,6 +1,6 @@ /* SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause */ /* - * Copyright (C) 2008-2014, 2018-2023 Intel Corporation + * Copyright (C) 2008-2014, 2018-2024 Intel Corporation * Copyright (C) 2013-2015 Intel Mobile Communications GmbH * Copyright (C) 2016-2017 Intel Deutschland GmbH */ @@ -247,6 +247,8 @@ typedef unsigned int __bitwise iwl_ucode_tlv_api_t; * logic. * @IWL_UCODE_TLV_API_INT_DBG_BUF_CLEAR: Firmware supports clearing the debug * internal buffer + * @IWL_UCODE_TLV_API_SMART_FIFO_OFFLOAD: Firmware doesn't need the host to + * configure the smart fifo * * @NUM_IWL_UCODE_TLV_API: number of bits used */ @@ -287,6 +289,7 @@ enum iwl_ucode_tlv_api { /* API Set 2 */ IWL_UCODE_TLV_API_NO_HOST_DISABLE_TX = (__force iwl_ucode_tlv_api_t)66, IWL_UCODE_TLV_API_INT_DBG_BUF_CLEAR = (__force iwl_ucode_tlv_api_t)67, + IWL_UCODE_TLV_API_SMART_FIFO_OFFLOAD = (__force iwl_ucode_tlv_api_t)68, NUM_IWL_UCODE_TLV_API /* diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/sf.c b/drivers/net/wireless/intel/iwlwifi/mvm/sf.c index 30d4233595e8..16285ae7cae9 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/sf.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/sf.c @@ -1,6 +1,6 @@ // SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause /* - * Copyright (C) 2013-2014, 2018-2019, 2022-2023 Intel Corporation + * Copyright (C) 2013-2014, 2018-2019, 2022-2024 Intel Corporation * Copyright (C) 2013-2014 Intel Mobile Communications GmbH */ #include "mvm.h" @@ -232,6 +232,9 @@ int iwl_mvm_sf_update(struct iwl_mvm *mvm, struct ieee80211_vif *changed_vif, }; struct ieee80211_sta *sta = NULL; + if (fw_has_api(&mvm->fw->ucode_capa, + IWL_UCODE_TLV_API_SMART_FIFO_OFFLOAD)) + return 0; /* * Ignore the call if we are in HW Restart flow, or if the handled * vif is a p2p device. -- cgit v1.2.3 From 5f4e0994996fa08d57711b5b247a0cb3085ec66a Mon Sep 17 00:00:00 2001 From: Mukesh Sisodiya Date: Tue, 6 Feb 2024 18:02:08 +0200 Subject: wifi: iwlwifi: pcie: Add new PCI device id and CNVI Add the support for a new PCIE device-id 0x272E and a new CNVI type. Signed-off-by: Mukesh Sisodiya Signed-off-by: Miri Korenblit Link: https://msgid.link/20240206175739.506db9b4a664.Ia2e3a77b880c449ac0e8d20b8cea25e6f07f1b81@changeid Signed-off-by: Johannes Berg --- drivers/net/wireless/intel/iwlwifi/cfg/sc.c | 38 ++++++++++++++++++++++--- drivers/net/wireless/intel/iwlwifi/iwl-config.h | 8 +++++- drivers/net/wireless/intel/iwlwifi/pcie/drv.c | 15 +++++++++- 3 files changed, 55 insertions(+), 6 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/intel/iwlwifi/cfg/sc.c b/drivers/net/wireless/intel/iwlwifi/cfg/sc.c index e0679093ed8e..be98a174a311 100644 --- a/drivers/net/wireless/intel/iwlwifi/cfg/sc.c +++ b/drivers/net/wireless/intel/iwlwifi/cfg/sc.c @@ -1,7 +1,7 @@ // SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause /* * Copyright (C) 2015-2017 Intel Deutschland GmbH - * Copyright (C) 2018-2023 Intel Corporation + * Copyright (C) 2018-2024 Intel Corporation */ #include #include @@ -33,6 +33,10 @@ #define IWL_SC_A_GF_A_FW_PRE "iwlwifi-sc-a0-gf-a0" #define IWL_SC_A_GF4_A_FW_PRE "iwlwifi-sc-a0-gf4-a0" #define IWL_SC_A_WH_A_FW_PRE "iwlwifi-sc-a0-wh-a0" +#define IWL_SC2_A_FM_C_FW_PRE "iwlwifi-sc2-a0-fm-c0" +#define IWL_SC2_A_WH_A_FW_PRE "iwlwifi-sc2-a0-wh-a0" +#define IWL_SC2F_A_FM_C_FW_PRE "iwlwifi-sc2f-a0-fm-c0" +#define IWL_SC2F_A_WH_A_FW_PRE "iwlwifi-sc2f-a0-wh-a0" #define IWL_SC_A_FM_B_FW_MODULE_FIRMWARE(api) \ IWL_SC_A_FM_B_FW_PRE "-" __stringify(api) ".ucode" @@ -48,6 +52,14 @@ IWL_SC_A_GF4_A_FW_PRE "-" __stringify(api) ".ucode" #define IWL_SC_A_WH_A_FW_MODULE_FIRMWARE(api) \ IWL_SC_A_WH_A_FW_PRE "-" __stringify(api) ".ucode" +#define IWL_SC2_A_FM_C_FW_MODULE_FIRMWARE(api) \ + IWL_SC2_A_FM_C_FW_PRE "-" __stringify(api) ".ucode" +#define IWL_SC2_A_WH_A_FW_MODULE_FIRMWARE(api) \ + IWL_SC2_A_WH_A_FW_PRE "-" __stringify(api) ".ucode" +#define IWL_SC2F_A_FM_C_FW_MODULE_FIRMWARE(api) \ + IWL_SC2F_A_FM_C_FW_PRE "-" __stringify(api) ".ucode" +#define IWL_SC2F_A_WH_A_FW_MODULE_FIRMWARE(api) \ + IWL_SC2F_A_WH_A_FW_PRE "-" __stringify(api) ".ucode" static const struct iwl_base_params iwl_sc_base_params = { .eeprom_size = OTP_LOW_IMAGE_SIZE_32K, @@ -124,6 +136,9 @@ static const struct iwl_base_params iwl_sc_base_params = { #define IWL_DEVICE_SC \ IWL_DEVICE_BZ_COMMON, \ + .uhb_supported = true, \ + .features = IWL_TX_CSUM_NETIF_FLAGS | NETIF_F_RXCSUM, \ + .num_rbds = IWL_NUM_RBDS_SC_EHT, \ .ht_params = &iwl_22000_ht_params /* @@ -149,10 +164,21 @@ const char iwl_sc_name[] = "Intel(R) TBD Sc device"; const struct iwl_cfg iwl_cfg_sc = { .fw_name_mac = "sc", - .uhb_supported = true, IWL_DEVICE_SC, - .features = IWL_TX_CSUM_NETIF_FLAGS | NETIF_F_RXCSUM, - .num_rbds = IWL_NUM_RBDS_SC_EHT, +}; + +const char iwl_sc2_name[] = "Intel(R) TBD Sc2 device"; + +const struct iwl_cfg iwl_cfg_sc2 = { + .fw_name_mac = "sc2", + IWL_DEVICE_SC, +}; + +const char iwl_sc2f_name[] = "Intel(R) TBD Sc2f device"; + +const struct iwl_cfg iwl_cfg_sc2f = { + .fw_name_mac = "sc2f", + IWL_DEVICE_SC, }; MODULE_FIRMWARE(IWL_SC_A_FM_B_FW_MODULE_FIRMWARE(IWL_SC_UCODE_API_MAX)); @@ -162,3 +188,7 @@ MODULE_FIRMWARE(IWL_SC_A_HR_B_FW_MODULE_FIRMWARE(IWL_SC_UCODE_API_MAX)); MODULE_FIRMWARE(IWL_SC_A_GF_A_FW_MODULE_FIRMWARE(IWL_SC_UCODE_API_MAX)); MODULE_FIRMWARE(IWL_SC_A_GF4_A_FW_MODULE_FIRMWARE(IWL_SC_UCODE_API_MAX)); MODULE_FIRMWARE(IWL_SC_A_WH_A_FW_MODULE_FIRMWARE(IWL_SC_UCODE_API_MAX)); +MODULE_FIRMWARE(IWL_SC2_A_FM_C_FW_MODULE_FIRMWARE(IWL_SC_UCODE_API_MAX)); +MODULE_FIRMWARE(IWL_SC2_A_WH_A_FW_MODULE_FIRMWARE(IWL_SC_UCODE_API_MAX)); +MODULE_FIRMWARE(IWL_SC2F_A_FM_C_FW_MODULE_FIRMWARE(IWL_SC_UCODE_API_MAX)); +MODULE_FIRMWARE(IWL_SC2F_A_WH_A_FW_MODULE_FIRMWARE(IWL_SC_UCODE_API_MAX)); diff --git a/drivers/net/wireless/intel/iwlwifi/iwl-config.h b/drivers/net/wireless/intel/iwlwifi/iwl-config.h index 97e73443316a..6aa4f7f9c708 100644 --- a/drivers/net/wireless/intel/iwlwifi/iwl-config.h +++ b/drivers/net/wireless/intel/iwlwifi/iwl-config.h @@ -2,7 +2,7 @@ /* * Copyright (C) 2005-2014, 2018-2021 Intel Corporation * Copyright (C) 2016-2017 Intel Deutschland GmbH - * Copyright (C) 2018-2023 Intel Corporation + * Copyright (C) 2018-2024 Intel Corporation */ #ifndef __IWL_CONFIG_H__ #define __IWL_CONFIG_H__ @@ -419,6 +419,8 @@ struct iwl_cfg { #define IWL_CFG_MAC_TYPE_BZ 0x46 #define IWL_CFG_MAC_TYPE_GL 0x47 #define IWL_CFG_MAC_TYPE_SC 0x48 +#define IWL_CFG_MAC_TYPE_SC2 0x49 +#define IWL_CFG_MAC_TYPE_SC2F 0x4A #define IWL_CFG_RF_TYPE_TH 0x105 #define IWL_CFG_RF_TYPE_TH1 0x108 @@ -541,6 +543,8 @@ extern const char iwl_ax411_name[]; extern const char iwl_bz_name[]; extern const char iwl_mtp_name[]; extern const char iwl_sc_name[]; +extern const char iwl_sc2_name[]; +extern const char iwl_sc2f_name[]; #if IS_ENABLED(CONFIG_IWLDVM) extern const struct iwl_cfg iwl5300_agn_cfg; extern const struct iwl_cfg iwl5100_agn_cfg; @@ -646,6 +650,8 @@ extern const struct iwl_cfg iwl_cfg_bz; extern const struct iwl_cfg iwl_cfg_gl; extern const struct iwl_cfg iwl_cfg_sc; +extern const struct iwl_cfg iwl_cfg_sc2; +extern const struct iwl_cfg iwl_cfg_sc2f; #endif /* CONFIG_IWLMVM */ #endif /* __IWL_CONFIG_H__ */ diff --git a/drivers/net/wireless/intel/iwlwifi/pcie/drv.c b/drivers/net/wireless/intel/iwlwifi/pcie/drv.c index 1ed67b76b516..4a657036b9d6 100644 --- a/drivers/net/wireless/intel/iwlwifi/pcie/drv.c +++ b/drivers/net/wireless/intel/iwlwifi/pcie/drv.c @@ -1,6 +1,6 @@ // SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause /* - * Copyright (C) 2005-2014, 2018-2023 Intel Corporation + * Copyright (C) 2005-2014, 2018-2024 Intel Corporation * Copyright (C) 2013-2015 Intel Mobile Communications GmbH * Copyright (C) 2016-2017 Intel Deutschland GmbH */ @@ -509,6 +509,9 @@ static const struct pci_device_id iwl_hw_card_ids[] = { /* Sc devices */ {IWL_PCI_DEVICE(0xE440, PCI_ANY_ID, iwl_sc_trans_cfg)}, + {IWL_PCI_DEVICE(0xE340, PCI_ANY_ID, iwl_sc_trans_cfg)}, + {IWL_PCI_DEVICE(0xD340, PCI_ANY_ID, iwl_sc_trans_cfg)}, + {IWL_PCI_DEVICE(0x6E70, PCI_ANY_ID, iwl_sc_trans_cfg)}, #endif /* CONFIG_IWLMVM */ {0} @@ -1121,6 +1124,16 @@ VISIBLE_IF_IWLWIFI_KUNIT const struct iwl_dev_info iwl_dev_info_table[] = { IWL_CFG_ANY, IWL_CFG_ANY, IWL_CFG_ANY, IWL_CFG_ANY, IWL_CFG_ANY, IWL_CFG_ANY, iwl_cfg_sc, iwl_sc_name), + _IWL_DEV_INFO(IWL_CFG_ANY, IWL_CFG_ANY, + IWL_CFG_MAC_TYPE_SC2, IWL_CFG_ANY, + IWL_CFG_ANY, IWL_CFG_ANY, IWL_CFG_ANY, + IWL_CFG_ANY, IWL_CFG_ANY, IWL_CFG_ANY, + iwl_cfg_sc2, iwl_sc2_name), + _IWL_DEV_INFO(IWL_CFG_ANY, IWL_CFG_ANY, + IWL_CFG_MAC_TYPE_SC2F, IWL_CFG_ANY, + IWL_CFG_ANY, IWL_CFG_ANY, IWL_CFG_ANY, + IWL_CFG_ANY, IWL_CFG_ANY, IWL_CFG_ANY, + iwl_cfg_sc2f, iwl_sc2f_name), #endif /* CONFIG_IWLMVM */ }; EXPORT_SYMBOL_IF_IWLWIFI_KUNIT(iwl_dev_info_table); -- cgit v1.2.3 From d5bd4041cd70faf26fc9a54bd6f172537bbe77f3 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Tue, 6 Feb 2024 18:02:09 +0200 Subject: wifi: iwlwifi: mvm: don't set replay counters to 0xff The firmware (later) actually uses the values even for keys that are invalid as far as the host is concerned, later in rekeying, and then only sets the low 48 bits since the PNs are only 48 bits over the air. It does, however, compare the full 64 bits later, obviously causing problems. Remove the memset and use kzalloc instead to avoid any old heap data leaking to the firmware. We already init all the other fields in the struct anyway. This leaves the data set to zero for any unused fields, so the firmware can look at them safely even if they're not used right now. Fixes: 79e561f0f05a ("iwlwifi: mvm: d3: implement RSC command version 5") Signed-off-by: Johannes Berg Signed-off-by: Miri Korenblit Link: https://msgid.link/20240206175739.462101146fef.I10f3855b99417af4247cff04af78dcbc6cb75c9c@changeid Signed-off-by: Johannes Berg --- drivers/net/wireless/intel/iwlwifi/mvm/d3.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/d3.c b/drivers/net/wireless/intel/iwlwifi/mvm/d3.c index 5bc08c1d207a..e1c77276557d 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/d3.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/d3.c @@ -461,12 +461,10 @@ static int iwl_mvm_wowlan_config_rsc_tsc(struct iwl_mvm *mvm, struct wowlan_key_rsc_v5_data data = {}; int i; - data.rsc = kmalloc(sizeof(*data.rsc), GFP_KERNEL); + data.rsc = kzalloc(sizeof(*data.rsc), GFP_KERNEL); if (!data.rsc) return -ENOMEM; - memset(data.rsc, 0xff, sizeof(*data.rsc)); - for (i = 0; i < ARRAY_SIZE(data.rsc->mcast_key_id_map); i++) data.rsc->mcast_key_id_map[i] = IWL_MCAST_KEY_MAP_INVALID; -- cgit v1.2.3 From 87f5b5f2c036cdf1ed2269b1d11f005b9bd0b2dc Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Tue, 6 Feb 2024 18:02:10 +0200 Subject: wifi: iwlwifi: mvm: remove flags for enable/disable beacon filter The flags argument to enable/disable beacon filtering functions is unused and always zero, so just remove it. Signed-off-by: Johannes Berg Signed-off-by: Miri Korenblit Link: https://msgid.link/20240206175739.2c739c1034a5.I8619949ad4ebd31593d10ece371ebdc6c48db98f@changeid Signed-off-by: Johannes Berg --- .../net/wireless/intel/iwlwifi/mvm/debugfs-vif.c | 6 ++--- drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c | 18 +++++++------- .../net/wireless/intel/iwlwifi/mvm/mld-mac80211.c | 2 +- drivers/net/wireless/intel/iwlwifi/mvm/mvm.h | 6 ++--- drivers/net/wireless/intel/iwlwifi/mvm/power.c | 29 +++++++++------------- 5 files changed, 27 insertions(+), 34 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/debugfs-vif.c b/drivers/net/wireless/intel/iwlwifi/mvm/debugfs-vif.c index 2b96cf9eac72..aa3c9c2cbd7f 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/debugfs-vif.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/debugfs-vif.c @@ -1,6 +1,6 @@ // SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause /* - * Copyright (C) 2012-2014, 2018-2023 Intel Corporation + * Copyright (C) 2012-2014, 2018-2024 Intel Corporation * Copyright (C) 2013-2015 Intel Mobile Communications GmbH * Copyright (C) 2016-2017 Intel Deutschland GmbH */ @@ -381,9 +381,9 @@ static ssize_t iwl_dbgfs_bf_params_write(struct ieee80211_vif *vif, char *buf, mutex_lock(&mvm->mutex); iwl_dbgfs_update_bf(vif, param, value); if (param == MVM_DEBUGFS_BF_ENABLE_BEACON_FILTER && !value) - ret = iwl_mvm_disable_beacon_filter(mvm, vif, 0); + ret = iwl_mvm_disable_beacon_filter(mvm, vif); else - ret = iwl_mvm_enable_beacon_filter(mvm, vif, 0); + ret = iwl_mvm_enable_beacon_filter(mvm, vif); mutex_unlock(&mvm->mutex); return ret ?: count; diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c b/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c index ab1219f4a5dc..576b90da94ff 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c @@ -1448,7 +1448,7 @@ int iwl_mvm_post_channel_switch(struct ieee80211_hw *hw, if (!fw_has_capa(&mvm->fw->ucode_capa, IWL_UCODE_TLV_CAPA_CHANNEL_SWITCH_CMD)) { - ret = iwl_mvm_enable_beacon_filter(mvm, vif, 0); + ret = iwl_mvm_enable_beacon_filter(mvm, vif); if (ret) goto out_unlock; @@ -1632,7 +1632,7 @@ static int iwl_mvm_mac_add_interface(struct ieee80211_hw *hw, goto out_remove_mac; /* beacon filtering */ - ret = iwl_mvm_disable_beacon_filter(mvm, vif, 0); + ret = iwl_mvm_disable_beacon_filter(mvm, vif); if (ret) goto out_remove_mac; @@ -2575,7 +2575,7 @@ iwl_mvm_bss_info_changed_station_common(struct iwl_mvm *mvm, iwl_mvm_stop_session_protection(mvm, vif); iwl_mvm_sf_update(mvm, vif, false); - WARN_ON(iwl_mvm_enable_beacon_filter(mvm, vif, 0)); + WARN_ON(iwl_mvm_enable_beacon_filter(mvm, vif)); } if (changes & (BSS_CHANGED_PS | BSS_CHANGED_P2P_PS | BSS_CHANGED_QOS | @@ -2596,7 +2596,7 @@ iwl_mvm_bss_info_changed_station_common(struct iwl_mvm *mvm, /* FIXME: need to update per link when FW API will * support it */ - ret = iwl_mvm_enable_beacon_filter(mvm, vif, 0); + ret = iwl_mvm_enable_beacon_filter(mvm, vif); if (ret) IWL_ERR(mvm, "failed to update CQM thresholds\n"); @@ -3797,7 +3797,7 @@ iwl_mvm_sta_state_assoc_to_authorized(struct iwl_mvm *mvm, NL80211_TDLS_ENABLE_LINK); } else { /* enable beacon filtering */ - WARN_ON(iwl_mvm_enable_beacon_filter(mvm, vif, 0)); + WARN_ON(iwl_mvm_enable_beacon_filter(mvm, vif)); mvmvif->authorized = 1; @@ -3855,7 +3855,7 @@ iwl_mvm_sta_state_authorized_to_assoc(struct iwl_mvm *mvm, mvmvif->authorized = 0; /* disable beacon filtering */ - iwl_mvm_disable_beacon_filter(mvm, vif, 0); + iwl_mvm_disable_beacon_filter(mvm, vif); } return 0; @@ -5299,8 +5299,8 @@ static int __iwl_mvm_mac_testmode_cmd(struct iwl_mvm *mvm, return -EINVAL; if (nla_get_u32(tb[IWL_MVM_TM_ATTR_BEACON_FILTER_STATE])) - return iwl_mvm_enable_beacon_filter(mvm, vif, 0); - return iwl_mvm_disable_beacon_filter(mvm, vif, 0); + return iwl_mvm_enable_beacon_filter(mvm, vif); + return iwl_mvm_disable_beacon_filter(mvm, vif); } return -EOPNOTSUPP; @@ -5384,7 +5384,7 @@ static int iwl_mvm_old_pre_chan_sw_sta(struct iwl_mvm *mvm, iwl_mvm_csa_client_absent(mvm, vif); if (mvmvif->bf_data.bf_enabled) { - int ret = iwl_mvm_disable_beacon_filter(mvm, vif, 0); + int ret = iwl_mvm_disable_beacon_filter(mvm, vif); if (ret) return ret; diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/mld-mac80211.c b/drivers/net/wireless/intel/iwlwifi/mvm/mld-mac80211.c index 7d89f50fbb10..021592f69f38 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/mld-mac80211.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/mld-mac80211.c @@ -47,7 +47,7 @@ static int iwl_mvm_mld_mac_add_interface(struct ieee80211_hw *hw, goto out_unlock; /* beacon filtering */ - ret = iwl_mvm_disable_beacon_filter(mvm, vif, 0); + ret = iwl_mvm_disable_beacon_filter(mvm, vif); if (ret) goto out_remove_mac; diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h b/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h index 937d0bd9c531..6000c79ce4a5 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h +++ b/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h @@ -2145,11 +2145,9 @@ iwl_mvm_beacon_filter_debugfs_parameters(struct ieee80211_vif *vif, {} #endif int iwl_mvm_enable_beacon_filter(struct iwl_mvm *mvm, - struct ieee80211_vif *vif, - u32 flags); + struct ieee80211_vif *vif); int iwl_mvm_disable_beacon_filter(struct iwl_mvm *mvm, - struct ieee80211_vif *vif, - u32 flags); + struct ieee80211_vif *vif); /* SMPS */ void iwl_mvm_update_smps(struct iwl_mvm *mvm, struct ieee80211_vif *vif, enum iwl_mvm_smps_type_request req_type, diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/power.c b/drivers/net/wireless/intel/iwlwifi/mvm/power.c index 1b9b06e0443f..41e68aa6bec8 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/power.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/power.c @@ -1,6 +1,6 @@ // SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause /* - * Copyright (C) 2012-2014, 2018-2019, 2021-2023 Intel Corporation + * Copyright (C) 2012-2014, 2018-2019, 2021-2024 Intel Corporation * Copyright (C) 2013-2014 Intel Mobile Communications GmbH * Copyright (C) 2015-2017 Intel Deutschland GmbH */ @@ -20,8 +20,7 @@ static int iwl_mvm_beacon_filter_send_cmd(struct iwl_mvm *mvm, - struct iwl_beacon_filter_cmd *cmd, - u32 flags) + struct iwl_beacon_filter_cmd *cmd) { u16 len; @@ -62,7 +61,7 @@ int iwl_mvm_beacon_filter_send_cmd(struct iwl_mvm *mvm, len = offsetof(struct iwl_beacon_filter_cmd, bf_threshold_absolute_low); - return iwl_mvm_send_cmd_pdu(mvm, REPLY_BEACON_FILTERING_CMD, flags, + return iwl_mvm_send_cmd_pdu(mvm, REPLY_BEACON_FILTERING_CMD, 0, len, cmd); } @@ -813,8 +812,7 @@ iwl_mvm_beacon_filter_debugfs_parameters(struct ieee80211_vif *vif, static int _iwl_mvm_enable_beacon_filter(struct iwl_mvm *mvm, struct ieee80211_vif *vif, - struct iwl_beacon_filter_cmd *cmd, - u32 cmd_flags) + struct iwl_beacon_filter_cmd *cmd) { struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); int ret; @@ -825,7 +823,7 @@ static int _iwl_mvm_enable_beacon_filter(struct iwl_mvm *mvm, iwl_mvm_beacon_filter_set_cqm_params(mvm, vif, cmd); iwl_mvm_beacon_filter_debugfs_parameters(vif, cmd); - ret = iwl_mvm_beacon_filter_send_cmd(mvm, cmd, cmd_flags); + ret = iwl_mvm_beacon_filter_send_cmd(mvm, cmd); if (!ret) mvmvif->bf_data.bf_enabled = true; @@ -834,20 +832,18 @@ static int _iwl_mvm_enable_beacon_filter(struct iwl_mvm *mvm, } int iwl_mvm_enable_beacon_filter(struct iwl_mvm *mvm, - struct ieee80211_vif *vif, - u32 flags) + struct ieee80211_vif *vif) { struct iwl_beacon_filter_cmd cmd = { IWL_BF_CMD_CONFIG_DEFAULTS, .bf_enable_beacon_filter = cpu_to_le32(1), }; - return _iwl_mvm_enable_beacon_filter(mvm, vif, &cmd, flags); + return _iwl_mvm_enable_beacon_filter(mvm, vif, &cmd); } static int _iwl_mvm_disable_beacon_filter(struct iwl_mvm *mvm, - struct ieee80211_vif *vif, - u32 flags) + struct ieee80211_vif *vif) { struct iwl_beacon_filter_cmd cmd = {}; struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); @@ -856,7 +852,7 @@ static int _iwl_mvm_disable_beacon_filter(struct iwl_mvm *mvm, if (vif->type != NL80211_IFTYPE_STATION || vif->p2p) return 0; - ret = iwl_mvm_beacon_filter_send_cmd(mvm, &cmd, flags); + ret = iwl_mvm_beacon_filter_send_cmd(mvm, &cmd); if (!ret) mvmvif->bf_data.bf_enabled = false; @@ -865,10 +861,9 @@ static int _iwl_mvm_disable_beacon_filter(struct iwl_mvm *mvm, } int iwl_mvm_disable_beacon_filter(struct iwl_mvm *mvm, - struct ieee80211_vif *vif, - u32 flags) + struct ieee80211_vif *vif) { - return _iwl_mvm_disable_beacon_filter(mvm, vif, flags); + return _iwl_mvm_disable_beacon_filter(mvm, vif); } static int iwl_mvm_power_set_ps(struct iwl_mvm *mvm) @@ -919,7 +914,7 @@ static int iwl_mvm_power_set_ba(struct iwl_mvm *mvm, !vif->cfg.ps || iwl_mvm_vif_low_latency(mvmvif)); - return _iwl_mvm_enable_beacon_filter(mvm, vif, &cmd, 0); + return _iwl_mvm_enable_beacon_filter(mvm, vif, &cmd); } int iwl_mvm_power_update_ps(struct iwl_mvm *mvm) -- cgit v1.2.3 From ae6d30a715210de16682369269cb6c25134ddbe2 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Tue, 6 Feb 2024 18:02:11 +0200 Subject: wifi: iwlwifi: mvm: show skb_mac_gso_segment() failure reason If this warning triggers we don't really know why, print out the return value so we can see it. Signed-off-by: Johannes Berg Signed-off-by: Miri Korenblit Link: https://msgid.link/20240206175739.b1b907741e85.Ib8ee9c90bd8f1af69969981ff0c63e9cc3123e1f@changeid Signed-off-by: Johannes Berg --- drivers/net/wireless/intel/iwlwifi/mvm/tx.c | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/tx.c b/drivers/net/wireless/intel/iwlwifi/mvm/tx.c index f401cd6ef3ac..cc73d7d7de7d 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/tx.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/tx.c @@ -939,9 +939,15 @@ iwl_mvm_tx_tso_segment(struct sk_buff *skb, unsigned int num_subframes, next = skb_gso_segment(skb, netdev_flags); skb_shinfo(skb)->gso_size = mss; skb_shinfo(skb)->gso_type = ipv4 ? SKB_GSO_TCPV4 : SKB_GSO_TCPV6; - if (WARN_ON_ONCE(IS_ERR(next))) - return -EINVAL; - else if (next) + + if (IS_ERR(next) && PTR_ERR(next) == -ENOMEM) + return -ENOMEM; + + if (WARN_ONCE(IS_ERR(next), + "skb_gso_segment error: %d\n", (int)PTR_ERR(next))) + return PTR_ERR(next); + + if (next) consume_skb(skb); skb_list_walk_safe(next, tmp, next) { -- cgit v1.2.3 From dbc396244a5e1ce51e90abd3acc98de707445d6d Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Tue, 6 Feb 2024 18:02:13 +0200 Subject: wifi: iwlwifi: mvm: move BA notif messages before action This is always a bit confusing, the code first does all the reclaim (with its own debug messages), and _then_ prints it got a BA notification from firmware. Turn that around. Signed-off-by: Johannes Berg Signed-off-by: Miri Korenblit Link: https://msgid.link/20240206175739.825245e0803f.Ic607c57f43eb7c7ff122ffee8f3994fd040d578f@changeid Signed-off-by: Johannes Berg --- drivers/net/wireless/intel/iwlwifi/mvm/tx.c | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/tx.c b/drivers/net/wireless/intel/iwlwifi/mvm/tx.c index cc73d7d7de7d..4981bb1f0251 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/tx.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/tx.c @@ -2162,6 +2162,12 @@ void iwl_mvm_rx_ba_notif(struct iwl_mvm *mvm, struct iwl_rx_cmd_buffer *rxb) tfd_cnt, pkt_len)) return; + IWL_DEBUG_TX_REPLY(mvm, + "BA_NOTIFICATION Received from sta_id = %d, flags %x, sent:%d, acked:%d\n", + sta_id, le32_to_cpu(ba_res->flags), + le16_to_cpu(ba_res->txed), + le16_to_cpu(ba_res->done)); + rcu_read_lock(); mvmsta = iwl_mvm_sta_from_staid_rcu(mvm, sta_id); @@ -2197,12 +2203,6 @@ void iwl_mvm_rx_ba_notif(struct iwl_mvm *mvm, struct iwl_rx_cmd_buffer *rxb) iwl_mvm_tx_airtime(mvm, mvmsta, le32_to_cpu(ba_res->wireless_time)); rcu_read_unlock(); - - IWL_DEBUG_TX_REPLY(mvm, - "BA_NOTIFICATION Received from sta_id = %d, flags %x, sent:%d, acked:%d\n", - sta_id, le32_to_cpu(ba_res->flags), - le16_to_cpu(ba_res->txed), - le16_to_cpu(ba_res->done)); return; } @@ -2234,9 +2234,6 @@ void iwl_mvm_rx_ba_notif(struct iwl_mvm *mvm, struct iwl_rx_cmd_buffer *rxb) rcu_read_unlock(); - iwl_mvm_tx_reclaim(mvm, sta_id, tid, txq, index, &ba_info, - tid_data->rate_n_flags, false); - IWL_DEBUG_TX_REPLY(mvm, "BA_NOTIFICATION Received from %pM, sta_id = %d\n", ba_notif->sta_addr, ba_notif->sta_id); @@ -2249,6 +2246,9 @@ void iwl_mvm_rx_ba_notif(struct iwl_mvm *mvm, struct iwl_rx_cmd_buffer *rxb) IWL_DEBUG_TX_REPLY(mvm, "reduced txp from ba notif %d\n", ba_notif->reduced_txp); + + iwl_mvm_tx_reclaim(mvm, sta_id, tid, txq, index, &ba_info, + tid_data->rate_n_flags, false); } /* -- cgit v1.2.3 From 4dbc306e0736685c5298073bed19cbf9f4b4cb92 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Tue, 6 Feb 2024 18:02:14 +0200 Subject: wifi: iwlwifi: queue: improve warning for no skb in reclaim We've seen this warning trigger, and while the reason is probably obvious, I haven't been able to see it yet. Add more information to the warning message to help identify the cause. Also print out both index and SSN for all the messages. Signed-off-by: Johannes Berg Signed-off-by: Miri Korenblit Link: https://msgid.link/20240206175739.581427dc81fc.I9a109d02b4349807dce521c693ecd3516ec58cc0@changeid Signed-off-by: Johannes Berg --- drivers/net/wireless/intel/iwlwifi/queue/tx.c | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/intel/iwlwifi/queue/tx.c b/drivers/net/wireless/intel/iwlwifi/queue/tx.c index ba0419bc1765..d3bde2d010b7 100644 --- a/drivers/net/wireless/intel/iwlwifi/queue/tx.c +++ b/drivers/net/wireless/intel/iwlwifi/queue/tx.c @@ -1,6 +1,6 @@ // SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause /* - * Copyright (C) 2020-2023 Intel Corporation + * Copyright (C) 2020-2024 Intel Corporation */ #include #include @@ -1602,8 +1602,8 @@ void iwl_txq_reclaim(struct iwl_trans *trans, int txq_id, int ssn, if (read_ptr == tfd_num) goto out; - IWL_DEBUG_TX_REPLY(trans, "[Q %d] %d -> %d (%d)\n", - txq_id, txq->read_ptr, tfd_num, ssn); + IWL_DEBUG_TX_REPLY(trans, "[Q %d] %d (%d) -> %d (%d)\n", + txq_id, read_ptr, txq->read_ptr, tfd_num, ssn); /*Since we free until index _not_ inclusive, the one before index is * the last we will free. This one must be used */ @@ -1631,7 +1631,8 @@ void iwl_txq_reclaim(struct iwl_trans *trans, int txq_id, int ssn, read_ptr = iwl_txq_get_cmd_index(txq, txq->read_ptr)) { struct sk_buff *skb = txq->entries[read_ptr].skb; - if (WARN_ON_ONCE(!skb)) + if (WARN_ONCE(!skb, "no SKB at %d (%d) on queue %d\n", + read_ptr, txq->read_ptr, txq_id)) continue; iwl_txq_free_tso_page(trans, skb); -- cgit v1.2.3 From bad9d21110037fa346426566d34dcffffc166fc6 Mon Sep 17 00:00:00 2001 From: Arnd Bergmann Date: Mon, 12 Feb 2024 12:23:36 +0100 Subject: wifi: iwlwifi: fix #ifdef CONFIG_ACPI check The #ifdef check around the function definition for two functions was changed without also changing the one on the declaration: drivers/net/wireless/intel/iwlwifi/fw/uefi.c:359:6: error: redefinition of 'iwl_uefi_get_sgom_table' 359 | void iwl_uefi_get_sgom_table(struct iwl_trans *trans, | ^~~~~~~~~~~~~~~~~~~~~~~ In file included from drivers/net/wireless/intel/iwlwifi/fw/uefi.c:11: drivers/net/wireless/intel/iwlwifi/fw/uefi.h:294:6: note: previous definition of 'iwl_uefi_get_sgom_table' with type 'void(struct iwl_trans *, struct iwl_fw_runtime *)' 294 | void iwl_uefi_get_sgom_table(struct iwl_trans *trans, struct iwl_fw_runtime *fwrt) | ^~~~~~~~~~~~~~~~~~~~~~~ drivers/net/wireless/intel/iwlwifi/fw/uefi.c:392:5: error: redefinition of 'iwl_uefi_get_uats_table' 392 | int iwl_uefi_get_uats_table(struct iwl_trans *trans, | ^~~~~~~~~~~~~~~~~~~~~~~ drivers/net/wireless/intel/iwlwifi/fw/uefi.h:299:5: note: previous definition of 'iwl_uefi_get_uats_table' with type 'int(struct iwl_trans *, struct iwl_fw_runtime *)' 299 | int iwl_uefi_get_uats_table(struct iwl_trans *trans, | ^~~~~~~~~~~~~~~~~~~~~~~ Adapt it by merging the declarations into the existing #ifdef block. Fixes: 74f4cd710705 ("wifi: iwlwifi: take SGOM and UATS code out of ACPI ifdef") Signed-off-by: Arnd Bergmann Link: https://msgid.link/20240212112343.1148931-1-arnd@kernel.org Signed-off-by: Johannes Berg --- drivers/net/wireless/intel/iwlwifi/fw/uefi.h | 11 ++++------- 1 file changed, 4 insertions(+), 7 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/intel/iwlwifi/fw/uefi.h b/drivers/net/wireless/intel/iwlwifi/fw/uefi.h index 39053290bd59..303cc299d1bc 100644 --- a/drivers/net/wireless/intel/iwlwifi/fw/uefi.h +++ b/drivers/net/wireless/intel/iwlwifi/fw/uefi.h @@ -204,6 +204,9 @@ int iwl_uefi_get_mcc(struct iwl_fw_runtime *fwrt, char *mcc); int iwl_uefi_get_eckv(struct iwl_fw_runtime *fwrt, u32 *extl_clk); int iwl_uefi_get_dsm(struct iwl_fw_runtime *fwrt, enum iwl_dsm_funcs func, u32 *value); +void iwl_uefi_get_sgom_table(struct iwl_trans *trans, struct iwl_fw_runtime *fwrt); +int iwl_uefi_get_uats_table(struct iwl_trans *trans, + struct iwl_fw_runtime *fwrt); #else /* CONFIG_EFI */ static inline void *iwl_uefi_get_pnvm(struct iwl_trans *trans, size_t *len) { @@ -283,13 +286,7 @@ static inline int iwl_uefi_get_dsm(struct iwl_fw_runtime *fwrt, { return -ENOENT; } -#endif /* CONFIG_EFI */ -#if defined(CONFIG_EFI) && defined(CONFIG_ACPI) -void iwl_uefi_get_sgom_table(struct iwl_trans *trans, struct iwl_fw_runtime *fwrt); -int iwl_uefi_get_uats_table(struct iwl_trans *trans, - struct iwl_fw_runtime *fwrt); -#else static inline void iwl_uefi_get_sgom_table(struct iwl_trans *trans, struct iwl_fw_runtime *fwrt) { @@ -301,5 +298,5 @@ int iwl_uefi_get_uats_table(struct iwl_trans *trans, { return 0; } -#endif +#endif /* CONFIG_EFI */ #endif /* __iwl_fw_uefi__ */ -- cgit v1.2.3 From 425c33264e151578a269c9c0ab9e0fb1d616f518 Mon Sep 17 00:00:00 2001 From: Dmitry Antipov Date: Wed, 10 Jan 2024 14:53:11 +0300 Subject: wifi: mwifiex: use kstrtoX_from_user() in debugfs handlers Use convenient 'kstrtou32_from_user()' in 'mwifiex_verext_write()' and 'kstrtobool_from_user()' in 'mwifiex_timeshare_coex_write()', respectively. Compile tested only. Signed-off-by: Dmitry Antipov Signed-off-by: Kalle Valo Link: https://msgid.link/20240110115314.421298-1-dmantipov@yandex.ru --- drivers/net/wireless/marvell/mwifiex/debugfs.c | 19 ++++--------------- 1 file changed, 4 insertions(+), 15 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/marvell/mwifiex/debugfs.c b/drivers/net/wireless/marvell/mwifiex/debugfs.c index d14a0f4c1b6d..9deaf59dcb62 100644 --- a/drivers/net/wireless/marvell/mwifiex/debugfs.c +++ b/drivers/net/wireless/marvell/mwifiex/debugfs.c @@ -566,14 +566,8 @@ mwifiex_verext_write(struct file *file, const char __user *ubuf, int ret; u32 versionstrsel; struct mwifiex_private *priv = (void *)file->private_data; - char buf[16]; - memset(buf, 0, sizeof(buf)); - - if (copy_from_user(&buf, ubuf, min_t(size_t, sizeof(buf) - 1, count))) - return -EFAULT; - - ret = kstrtou32(buf, 10, &versionstrsel); + ret = kstrtou32_from_user(ubuf, count, 10, &versionstrsel); if (ret) return ret; @@ -874,19 +868,14 @@ mwifiex_timeshare_coex_write(struct file *file, const char __user *ubuf, { bool timeshare_coex; struct mwifiex_private *priv = file->private_data; - char kbuf[16]; int ret; if (priv->adapter->fw_api_ver != MWIFIEX_FW_V15) return -EOPNOTSUPP; - memset(kbuf, 0, sizeof(kbuf)); - - if (copy_from_user(&kbuf, ubuf, min_t(size_t, sizeof(kbuf) - 1, count))) - return -EFAULT; - - if (kstrtobool(kbuf, ×hare_coex)) - return -EINVAL; + ret = kstrtobool_from_user(ubuf, count, ×hare_coex); + if (ret) + return ret; ret = mwifiex_send_cmd(priv, HostCmd_CMD_ROBUST_COEX, HostCmd_ACT_GEN_SET, 0, ×hare_coex, true); -- cgit v1.2.3 From a8e5fefa91236fd0d51464bf8156d738f0dfab9d Mon Sep 17 00:00:00 2001 From: Ajay Singh Date: Mon, 15 Jan 2024 15:56:30 +0100 Subject: wifi: wilc1000: set preamble size to auto as default in wilc_init_fw_config() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit WILC driver currently applies some default configuration whenever the firmware is initialized, and sets the default preamble size to short. However, despite this passed option, firmware is also able to successfully connect to access points only using long preamble, so this setting does not really enforce short preambles and is misleading regarding applied configuration. Update default configuration and make it match the firmware behavior by passing the existing WILC_FW_PREAMBLE_AUTO value (2 instead of 0). The updated setting does not really alter firmware behavior since it is still capable to connect to both short preamble and long preamble access points, but at list the setting now expresses for real the corresponding firmware behavior. More info: it has been implemented to address the transmission (Tx) blackout issue observed in the 802.11b mode. The modification has no impact on the other modes, which will continue to work as they did in the previous implementation. This change will allow the 802.11b transmission (2, 5.5, 11Mbps) to use long preamble. Signed-off-by: Ajay Singh Signed-off-by: Alexis Lothoré Signed-off-by: Kalle Valo Link: https://msgid.link/20240115-wilc_1000_fixes-v1-1-54d29463a738@bootlin.com --- drivers/net/wireless/microchip/wilc1000/netdev.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/microchip/wilc1000/netdev.c b/drivers/net/wireless/microchip/wilc1000/netdev.c index ef22bf6bf86a..a8b5c8dec69c 100644 --- a/drivers/net/wireless/microchip/wilc1000/netdev.c +++ b/drivers/net/wireless/microchip/wilc1000/netdev.c @@ -284,7 +284,7 @@ static int wilc_init_fw_config(struct net_device *dev, struct wilc_vif *vif) if (!wilc_wlan_cfg_set(vif, 0, WID_11G_OPERATING_MODE, &b, 1, 0, 0)) goto fail; - b = WILC_FW_PREAMBLE_SHORT; + b = WILC_FW_PREAMBLE_AUTO; if (!wilc_wlan_cfg_set(vif, 0, WID_PREAMBLE, &b, 1, 0, 0)) goto fail; -- cgit v1.2.3 From 188045a85614433c8aa176f7899fcfb7c7183408 Mon Sep 17 00:00:00 2001 From: Zong-Zhe Yang Date: Tue, 6 Feb 2024 11:06:19 +0800 Subject: wifi: rtw89: drop TIMING_BEACON_ONLY and sync beacon TSF by self Some of our calculation during concurrent mode depend on last beacon TSF. Originally, we just set IEEE80211_HW_TIMING_BEACON_ONLY and get what we want from mac80211. But, IEEE80211_HW_TIMING_BEACON_ONLY will be restricted once we declare MLO. Since we are about to consider the MLO stuffs, so sync beacon TSF by ourselves now and unset IEEE80211_HW_TIMING_BEACON_ONLY. Signed-off-by: Zong-Zhe Yang Signed-off-by: Ping-Ke Shih Signed-off-by: Kalle Valo Link: https://msgid.link/20240206030624.23382-2-pkshih@realtek.com --- drivers/net/wireless/realtek/rtw89/chan.c | 9 +-------- drivers/net/wireless/realtek/rtw89/core.c | 18 ++++++++++++++---- drivers/net/wireless/realtek/rtw89/core.h | 1 + drivers/net/wireless/realtek/rtw89/mac80211.c | 1 + 4 files changed, 17 insertions(+), 12 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/realtek/rtw89/chan.c b/drivers/net/wireless/realtek/rtw89/chan.c index 21449cb9b069..2a95f9db83f9 100644 --- a/drivers/net/wireless/realtek/rtw89/chan.c +++ b/drivers/net/wireless/realtek/rtw89/chan.c @@ -320,19 +320,12 @@ int rtw89_iterate_mcc_roles(struct rtw89_dev *rtwdev, return 0; } -/* For now, IEEE80211_HW_TIMING_BEACON_ONLY can make things simple to ensure - * correctness of MCC calculation logic below. We have noticed that once driver - * declares WIPHY_FLAG_SUPPORTS_MLO, the use of IEEE80211_HW_TIMING_BEACON_ONLY - * will be restricted. We will make an alternative in driver when it is ready - * for MLO. - */ static u32 rtw89_mcc_get_tbtt_ofst(struct rtw89_dev *rtwdev, struct rtw89_mcc_role *role, u64 tsf) { struct rtw89_vif *rtwvif = role->rtwvif; - struct ieee80211_vif *vif = rtwvif_to_vif(rtwvif); u32 bcn_intvl_us = ieee80211_tu_to_usec(role->beacon_interval); - u64 sync_tsf = vif->bss_conf.sync_tsf; + u64 sync_tsf = READ_ONCE(rtwvif->sync_bcn_tsf); u32 remainder; if (tsf < sync_tsf) { diff --git a/drivers/net/wireless/realtek/rtw89/core.c b/drivers/net/wireless/realtek/rtw89/core.c index 650c507c8ed3..95ace26a8f66 100644 --- a/drivers/net/wireless/realtek/rtw89/core.c +++ b/drivers/net/wireless/realtek/rtw89/core.c @@ -1868,6 +1868,17 @@ static void rtw89_core_cancel_6ghz_probe_tx(struct rtw89_dev *rtwdev, ieee80211_queue_work(rtwdev->hw, &rtwdev->cancel_6ghz_probe_work); } +static void rtw89_vif_sync_bcn_tsf(struct rtw89_vif *rtwvif, + struct ieee80211_hdr *hdr, size_t len) +{ + struct ieee80211_mgmt *mgmt = (typeof(mgmt))hdr; + + if (len < offsetof(typeof(*mgmt), u.beacon.variable)) + return; + + WRITE_ONCE(rtwvif->sync_bcn_tsf, le64_to_cpu(mgmt->u.beacon.timestamp)); +} + static void rtw89_vif_rx_stats_iter(void *data, u8 *mac, struct ieee80211_vif *vif) { @@ -1898,8 +1909,10 @@ static void rtw89_vif_rx_stats_iter(void *data, u8 *mac, return; if (ieee80211_is_beacon(hdr->frame_control)) { - if (vif->type == NL80211_IFTYPE_STATION) + if (vif->type == NL80211_IFTYPE_STATION) { + rtw89_vif_sync_bcn_tsf(rtwvif, hdr, skb->len); rtw89_fw_h2c_rssi_offload(rtwdev, phy_ppdu); + } pkt_stat->beacon_nr++; } @@ -4447,9 +4460,6 @@ static int rtw89_core_register_hw(struct rtw89_dev *rtwdev) ieee80211_hw_set(hw, SUPPORTS_MULTI_BSSID); ieee80211_hw_set(hw, WANT_MONITOR_VIF); - /* ref: description of rtw89_mcc_get_tbtt_ofst() in chan.c */ - ieee80211_hw_set(hw, TIMING_BEACON_ONLY); - if (chip->support_bandwidths & BIT(NL80211_CHAN_WIDTH_160)) ieee80211_hw_set(hw, SUPPORTS_VHT_EXT_NSS_BW); diff --git a/drivers/net/wireless/realtek/rtw89/core.h b/drivers/net/wireless/realtek/rtw89/core.h index 713383b6d818..75269c1d94cc 100644 --- a/drivers/net/wireless/realtek/rtw89/core.h +++ b/drivers/net/wireless/realtek/rtw89/core.h @@ -3044,6 +3044,7 @@ struct rtw89_vif { u8 bcn_hit_cond; u8 hit_rule; u8 last_noa_nr; + u64 sync_bcn_tsf; bool offchan; bool trigger; bool lsig_txop; diff --git a/drivers/net/wireless/realtek/rtw89/mac80211.c b/drivers/net/wireless/realtek/rtw89/mac80211.c index b61c5be8cae3..31d1ffb16e83 100644 --- a/drivers/net/wireless/realtek/rtw89/mac80211.c +++ b/drivers/net/wireless/realtek/rtw89/mac80211.c @@ -449,6 +449,7 @@ static void rtw89_ops_bss_info_changed(struct ieee80211_hw *hw, ether_addr_copy(rtwvif->bssid, conf->bssid); rtw89_cam_bssid_changed(rtwdev, rtwvif); rtw89_fw_h2c_cam(rtwdev, rtwvif, NULL, NULL); + WRITE_ONCE(rtwvif->sync_bcn_tsf, 0); } if (changed & BSS_CHANGED_BEACON) -- cgit v1.2.3 From 4f0beeefcce8ad1035d063a012db6cf510aa1ed1 Mon Sep 17 00:00:00 2001 From: Zong-Zhe Yang Date: Tue, 6 Feb 2024 11:06:20 +0800 Subject: wifi: rtw89: chan: add sub-entity swap function to cover replacing Originally, we replaced sub-entity of index 0 with another one in some cases. However, we will need a swap here in following implementations. So, we introduce it ahead and change code from replacing to swapping. Signed-off-by: Zong-Zhe Yang Signed-off-by: Ping-Ke Shih Signed-off-by: Kalle Valo Link: https://msgid.link/20240206030624.23382-3-pkshih@realtek.com --- drivers/net/wireless/realtek/rtw89/chan.c | 47 +++++++++++++++++++++++-------- 1 file changed, 36 insertions(+), 11 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/realtek/rtw89/chan.c b/drivers/net/wireless/realtek/rtw89/chan.c index 2a95f9db83f9..11d46878f51e 100644 --- a/drivers/net/wireless/realtek/rtw89/chan.c +++ b/drivers/net/wireless/realtek/rtw89/chan.c @@ -1893,6 +1893,41 @@ void rtw89_chanctx_proceed(struct rtw89_dev *rtwdev) rtw89_queue_chanctx_work(rtwdev); } +static void rtw89_swap_sub_entity(struct rtw89_dev *rtwdev, + enum rtw89_sub_entity_idx idx1, + enum rtw89_sub_entity_idx idx2) +{ + struct rtw89_hal *hal = &rtwdev->hal; + struct rtw89_sub_entity tmp; + struct rtw89_vif *rtwvif; + u8 cur; + + if (idx1 == idx2) + return; + + hal->sub[idx1].cfg->idx = idx2; + hal->sub[idx2].cfg->idx = idx1; + + tmp = hal->sub[idx1]; + hal->sub[idx1] = hal->sub[idx2]; + hal->sub[idx2] = tmp; + + rtw89_for_each_rtwvif(rtwdev, rtwvif) { + if (!rtwvif->chanctx_assigned) + continue; + if (rtwvif->sub_entity_idx == idx1) + rtwvif->sub_entity_idx = idx2; + else if (rtwvif->sub_entity_idx == idx2) + rtwvif->sub_entity_idx = idx1; + } + + cur = atomic_read(&hal->roc_entity_idx); + if (cur == idx1) + atomic_set(&hal->roc_entity_idx, idx2); + else if (cur == idx2) + atomic_set(&hal->roc_entity_idx, idx1); +} + int rtw89_chanctx_ops_add(struct rtw89_dev *rtwdev, struct ieee80211_chanctx_conf *ctx) { @@ -1918,7 +1953,6 @@ void rtw89_chanctx_ops_remove(struct rtw89_dev *rtwdev, struct rtw89_hal *hal = &rtwdev->hal; struct rtw89_chanctx_cfg *cfg = (struct rtw89_chanctx_cfg *)ctx->drv_priv; enum rtw89_entity_mode mode; - struct rtw89_vif *rtwvif; u8 drop, roll; drop = cfg->idx; @@ -1934,16 +1968,7 @@ void rtw89_chanctx_ops_remove(struct rtw89_dev *rtwdev, /* RTW89_SUB_ENTITY_0 is going to release, and another exists. * Make another roll down to RTW89_SUB_ENTITY_0 to replace. */ - hal->sub[roll].cfg->idx = RTW89_SUB_ENTITY_0; - hal->sub[RTW89_SUB_ENTITY_0] = hal->sub[roll]; - - rtw89_for_each_rtwvif(rtwdev, rtwvif) { - if (rtwvif->sub_entity_idx == roll) - rtwvif->sub_entity_idx = RTW89_SUB_ENTITY_0; - } - - atomic_cmpxchg(&hal->roc_entity_idx, roll, RTW89_SUB_ENTITY_0); - + rtw89_swap_sub_entity(rtwdev, RTW89_SUB_ENTITY_0, roll); drop = roll; out: -- cgit v1.2.3 From ab12a3bfbf775182dc86ef8f70eab487c5deb761 Mon Sep 17 00:00:00 2001 From: Zong-Zhe Yang Date: Tue, 6 Feb 2024 11:06:21 +0800 Subject: wifi: rtw89: chan: tweak bitmap recalc ahead before MLO Originally, we just declared two sub-entity, and according to rolling down mechanism, we ensured that index 0 contained sub-entity as long as there are sub-entity. So, we could use for-loop after deciding the last index. But, we are preparing to expand num of sub-entity for MLO. Then, there won't be just two sub-entity. And, there might be holes between two bits in the bitmap. So, we cannot simply do for-loop as before. Instead, we need to follow the set bits. Signed-off-by: Zong-Zhe Yang Signed-off-by: Ping-Ke Shih Signed-off-by: Kalle Valo Link: https://msgid.link/20240206030624.23382-4-pkshih@realtek.com --- drivers/net/wireless/realtek/rtw89/chan.c | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/realtek/rtw89/chan.c b/drivers/net/wireless/realtek/rtw89/chan.c index 11d46878f51e..6a666a92b59b 100644 --- a/drivers/net/wireless/realtek/rtw89/chan.c +++ b/drivers/net/wireless/realtek/rtw89/chan.c @@ -214,31 +214,32 @@ void rtw89_entity_init(struct rtw89_dev *rtwdev) enum rtw89_entity_mode rtw89_entity_recalc(struct rtw89_dev *rtwdev) { + DECLARE_BITMAP(recalc_map, NUM_OF_RTW89_SUB_ENTITY) = {}; struct rtw89_hal *hal = &rtwdev->hal; const struct cfg80211_chan_def *chandef; enum rtw89_entity_mode mode; struct rtw89_chan chan; u8 weight; - u8 last; u8 idx; lockdep_assert_held(&rtwdev->mutex); + bitmap_copy(recalc_map, hal->entity_map, NUM_OF_RTW89_SUB_ENTITY); + weight = bitmap_weight(hal->entity_map, NUM_OF_RTW89_SUB_ENTITY); switch (weight) { default: rtw89_warn(rtwdev, "unknown ent chan weight: %d\n", weight); - bitmap_zero(hal->entity_map, NUM_OF_RTW89_SUB_ENTITY); + bitmap_zero(recalc_map, NUM_OF_RTW89_SUB_ENTITY); fallthrough; case 0: rtw89_config_default_chandef(rtwdev); + set_bit(RTW89_SUB_ENTITY_0, recalc_map); fallthrough; case 1: - last = RTW89_SUB_ENTITY_0; mode = RTW89_ENTITY_MODE_SCC; break; case 2: - last = RTW89_SUB_ENTITY_1; mode = rtw89_get_entity_mode(rtwdev); if (mode == RTW89_ENTITY_MODE_MCC) break; @@ -247,7 +248,7 @@ enum rtw89_entity_mode rtw89_entity_recalc(struct rtw89_dev *rtwdev) break; } - for (idx = 0; idx <= last; idx++) { + for_each_set_bit(idx, recalc_map, NUM_OF_RTW89_SUB_ENTITY) { chandef = rtw89_chandef_get(rtwdev, idx); rtw89_get_channel_params(chandef, &chan); if (chan.channel == 0) { -- cgit v1.2.3 From d79fa0a6d8c229435e48d239dc1f0a0f39235fc8 Mon Sep 17 00:00:00 2001 From: Zong-Zhe Yang Date: Tue, 6 Feb 2024 11:06:22 +0800 Subject: wifi: rtw89: chan: tweak weight recalc ahead before MLO Originally, we consider weight only based on how many chanctxs that mac80211 sets. However, we need to consider both active chanctxs and active interfaces to distinguish MCC (multiple channel concurrent) from impending MLO. Although the logic of handling is extended, for now, behavior might not be different under current condition. Signed-off-by: Zong-Zhe Yang Signed-off-by: Ping-Ke Shih Signed-off-by: Kalle Valo Link: https://msgid.link/20240206030624.23382-5-pkshih@realtek.com --- drivers/net/wireless/realtek/rtw89/chan.c | 51 ++++++++++++++++++++++++++++--- drivers/net/wireless/realtek/rtw89/chan.h | 5 +++ drivers/net/wireless/realtek/rtw89/core.h | 6 +++- 3 files changed, 56 insertions(+), 6 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/realtek/rtw89/chan.c b/drivers/net/wireless/realtek/rtw89/chan.c index 6a666a92b59b..57fabc05dab9 100644 --- a/drivers/net/wireless/realtek/rtw89/chan.c +++ b/drivers/net/wireless/realtek/rtw89/chan.c @@ -212,24 +212,51 @@ void rtw89_entity_init(struct rtw89_dev *rtwdev) rtw89_config_default_chandef(rtwdev); } +static void rtw89_entity_calculate_weight(struct rtw89_dev *rtwdev, + struct rtw89_entity_weight *w) +{ + struct rtw89_hal *hal = &rtwdev->hal; + const struct rtw89_chanctx_cfg *cfg; + struct rtw89_vif *rtwvif; + int idx; + + for_each_set_bit(idx, hal->entity_map, NUM_OF_RTW89_SUB_ENTITY) { + cfg = hal->sub[idx].cfg; + if (!cfg) { + /* doesn't run with chanctx ops; one channel at most */ + w->active_chanctxs = 1; + break; + } + + if (cfg->ref_count > 0) + w->active_chanctxs++; + } + + rtw89_for_each_rtwvif(rtwdev, rtwvif) { + if (rtwvif->chanctx_assigned) + w->active_roles++; + } +} + enum rtw89_entity_mode rtw89_entity_recalc(struct rtw89_dev *rtwdev) { DECLARE_BITMAP(recalc_map, NUM_OF_RTW89_SUB_ENTITY) = {}; struct rtw89_hal *hal = &rtwdev->hal; const struct cfg80211_chan_def *chandef; + struct rtw89_entity_weight w = {}; enum rtw89_entity_mode mode; struct rtw89_chan chan; - u8 weight; u8 idx; lockdep_assert_held(&rtwdev->mutex); bitmap_copy(recalc_map, hal->entity_map, NUM_OF_RTW89_SUB_ENTITY); - weight = bitmap_weight(hal->entity_map, NUM_OF_RTW89_SUB_ENTITY); - switch (weight) { + rtw89_entity_calculate_weight(rtwdev, &w); + switch (w.active_chanctxs) { default: - rtw89_warn(rtwdev, "unknown ent chan weight: %d\n", weight); + rtw89_warn(rtwdev, "unknown ent chanctxs weight: %d\n", + w.active_chanctxs); bitmap_zero(recalc_map, NUM_OF_RTW89_SUB_ENTITY); fallthrough; case 0: @@ -239,7 +266,14 @@ enum rtw89_entity_mode rtw89_entity_recalc(struct rtw89_dev *rtwdev) case 1: mode = RTW89_ENTITY_MODE_SCC; break; - case 2: + case 2 ... NUM_OF_RTW89_SUB_ENTITY: + if (w.active_roles != NUM_OF_RTW89_MCC_ROLES) { + rtw89_debug(rtwdev, RTW89_DBG_CHAN, + "unhandled ent: %d chanctxs %d roles\n", + w.active_chanctxs, w.active_roles); + return RTW89_ENTITY_MODE_UNHANDLED; + } + mode = rtw89_get_entity_mode(rtwdev); if (mode == RTW89_ENTITY_MODE_MCC) break; @@ -582,6 +616,9 @@ static int rtw89_mcc_fill_all_roles(struct rtw89_dev *rtwdev) int ret; rtw89_for_each_rtwvif(rtwdev, rtwvif) { + if (!rtwvif->chanctx_assigned) + continue; + if (sel.bind_vif[rtwvif->sub_entity_idx]) { rtw89_warn(rtwdev, "MCC skip extra vif on chanctx[%d]\n", @@ -2007,6 +2044,7 @@ int rtw89_chanctx_ops_assign_vif(struct rtw89_dev *rtwdev, rtwvif->sub_entity_idx = cfg->idx; rtwvif->chanctx_assigned = true; + cfg->ref_count++; return 0; } @@ -2014,6 +2052,9 @@ void rtw89_chanctx_ops_unassign_vif(struct rtw89_dev *rtwdev, struct rtw89_vif *rtwvif, struct ieee80211_chanctx_conf *ctx) { + struct rtw89_chanctx_cfg *cfg = (struct rtw89_chanctx_cfg *)ctx->drv_priv; + rtwvif->sub_entity_idx = RTW89_SUB_ENTITY_0; rtwvif->chanctx_assigned = false; + cfg->ref_count--; } diff --git a/drivers/net/wireless/realtek/rtw89/chan.h b/drivers/net/wireless/realtek/rtw89/chan.h index 9b98d8f4ee9d..ffa412f281f3 100644 --- a/drivers/net/wireless/realtek/rtw89/chan.h +++ b/drivers/net/wireless/realtek/rtw89/chan.h @@ -38,6 +38,11 @@ enum rtw89_chanctx_pause_reasons { RTW89_CHANCTX_PAUSE_REASON_ROC, }; +struct rtw89_entity_weight { + unsigned int active_chanctxs; + unsigned int active_roles; +}; + static inline bool rtw89_get_entity_state(struct rtw89_dev *rtwdev) { struct rtw89_hal *hal = &rtwdev->hal; diff --git a/drivers/net/wireless/realtek/rtw89/core.h b/drivers/net/wireless/realtek/rtw89/core.h index 75269c1d94cc..d98dcf12bef7 100644 --- a/drivers/net/wireless/realtek/rtw89/core.h +++ b/drivers/net/wireless/realtek/rtw89/core.h @@ -4136,6 +4136,7 @@ struct rtw89_tas_info { struct rtw89_chanctx_cfg { enum rtw89_sub_entity_idx idx; + int ref_count; }; enum rtw89_chanctx_changes { @@ -4155,13 +4156,16 @@ enum rtw89_entity_mode { RTW89_ENTITY_MODE_MCC, NUM_OF_RTW89_ENTITY_MODE, - RTW89_ENTITY_MODE_INVALID = NUM_OF_RTW89_ENTITY_MODE, + RTW89_ENTITY_MODE_INVALID = -EINVAL, + RTW89_ENTITY_MODE_UNHANDLED = -ESRCH, }; struct rtw89_sub_entity { struct cfg80211_chan_def chandef; struct rtw89_chan chan; struct rtw89_chan_rcd rcd; + + /* only assigned when running with chanctx_ops */ struct rtw89_chanctx_cfg *cfg; }; -- cgit v1.2.3 From 1ae9fbaf22ee82bb3ed47ac12ea92dbb7c51769f Mon Sep 17 00:00:00 2001 From: Zong-Zhe Yang Date: Tue, 6 Feb 2024 11:06:23 +0800 Subject: wifi: rtw89: chan: move handling from add/remove to assign/unassign for MLO After MLO, we will need to consider not only active chanctx but also active interfaces (roles) to decide entity things. So in advance, we move handling from chanctx_ops::add/remove to chanctx_ops::assign_vif/unassign_vif. Then, we can recalculate and aware active interfaces' changes. For now, behavior should not be really different, since active chanctx and active interface are one-to-one mapping before MLO. Signed-off-by: Zong-Zhe Yang Signed-off-by: Ping-Ke Shih Signed-off-by: Kalle Valo Link: https://msgid.link/20240206030624.23382-6-pkshih@realtek.com --- drivers/net/wireless/realtek/rtw89/chan.c | 75 ++++++++++++++++++------------- drivers/net/wireless/realtek/rtw89/core.c | 5 ++- drivers/net/wireless/realtek/rtw89/core.h | 2 +- 3 files changed, 47 insertions(+), 35 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/realtek/rtw89/chan.c b/drivers/net/wireless/realtek/rtw89/chan.c index 57fabc05dab9..71fe0d3ab3b0 100644 --- a/drivers/net/wireless/realtek/rtw89/chan.c +++ b/drivers/net/wireless/realtek/rtw89/chan.c @@ -1979,7 +1979,6 @@ int rtw89_chanctx_ops_add(struct rtw89_dev *rtwdev, return -ENOENT; rtw89_config_entity_chandef(rtwdev, idx, &ctx->def); - rtw89_set_channel(rtwdev); cfg->idx = idx; hal->sub[idx].cfg = cfg; return 0; @@ -1990,37 +1989,8 @@ void rtw89_chanctx_ops_remove(struct rtw89_dev *rtwdev, { struct rtw89_hal *hal = &rtwdev->hal; struct rtw89_chanctx_cfg *cfg = (struct rtw89_chanctx_cfg *)ctx->drv_priv; - enum rtw89_entity_mode mode; - u8 drop, roll; - - drop = cfg->idx; - if (drop != RTW89_SUB_ENTITY_0) - goto out; - - roll = find_next_bit(hal->entity_map, NUM_OF_RTW89_SUB_ENTITY, drop + 1); - - /* Follow rtw89_config_default_chandef() when rtw89_entity_recalc(). */ - if (roll == NUM_OF_RTW89_SUB_ENTITY) - goto out; - - /* RTW89_SUB_ENTITY_0 is going to release, and another exists. - * Make another roll down to RTW89_SUB_ENTITY_0 to replace. - */ - rtw89_swap_sub_entity(rtwdev, RTW89_SUB_ENTITY_0, roll); - drop = roll; -out: - mode = rtw89_get_entity_mode(rtwdev); - switch (mode) { - case RTW89_ENTITY_MODE_MCC: - rtw89_mcc_stop(rtwdev); - break; - default: - break; - } - - clear_bit(drop, hal->entity_map); - rtw89_set_channel(rtwdev); + clear_bit(cfg->idx, hal->entity_map); } void rtw89_chanctx_ops_change(struct rtw89_dev *rtwdev, @@ -2045,7 +2015,8 @@ int rtw89_chanctx_ops_assign_vif(struct rtw89_dev *rtwdev, rtwvif->sub_entity_idx = cfg->idx; rtwvif->chanctx_assigned = true; cfg->ref_count++; - return 0; + + return rtw89_set_channel(rtwdev); } void rtw89_chanctx_ops_unassign_vif(struct rtw89_dev *rtwdev, @@ -2053,8 +2024,48 @@ void rtw89_chanctx_ops_unassign_vif(struct rtw89_dev *rtwdev, struct ieee80211_chanctx_conf *ctx) { struct rtw89_chanctx_cfg *cfg = (struct rtw89_chanctx_cfg *)ctx->drv_priv; + struct rtw89_hal *hal = &rtwdev->hal; + struct rtw89_entity_weight w = {}; + enum rtw89_sub_entity_idx roll; + enum rtw89_entity_mode cur; rtwvif->sub_entity_idx = RTW89_SUB_ENTITY_0; rtwvif->chanctx_assigned = false; cfg->ref_count--; + + if (cfg->ref_count != 0) + goto out; + + if (cfg->idx != RTW89_SUB_ENTITY_0) + goto out; + + roll = find_next_bit(hal->entity_map, NUM_OF_RTW89_SUB_ENTITY, + cfg->idx + 1); + /* Follow rtw89_config_default_chandef() when rtw89_entity_recalc(). */ + if (roll == NUM_OF_RTW89_SUB_ENTITY) + goto out; + + /* RTW89_SUB_ENTITY_0 is going to release, and another exists. + * Make another roll down to RTW89_SUB_ENTITY_0 to replace. + */ + rtw89_swap_sub_entity(rtwdev, cfg->idx, roll); + +out: + rtw89_entity_calculate_weight(rtwdev, &w); + + cur = rtw89_get_entity_mode(rtwdev); + switch (cur) { + case RTW89_ENTITY_MODE_MCC: + /* If still multi-roles, re-plan MCC for chanctx changes. + * Otherwise, just stop MCC. + */ + rtw89_mcc_stop(rtwdev); + if (w.active_roles == NUM_OF_RTW89_MCC_ROLES) + rtw89_mcc_start(rtwdev); + break; + default: + break; + } + + rtw89_set_channel(rtwdev); } diff --git a/drivers/net/wireless/realtek/rtw89/core.c b/drivers/net/wireless/realtek/rtw89/core.c index 95ace26a8f66..6441d99cd6c0 100644 --- a/drivers/net/wireless/realtek/rtw89/core.c +++ b/drivers/net/wireless/realtek/rtw89/core.c @@ -372,7 +372,7 @@ void rtw89_core_set_chip_txpwr(struct rtw89_dev *rtwdev) chip->ops->set_txpwr(rtwdev, chan, phy_idx); } -void rtw89_set_channel(struct rtw89_dev *rtwdev) +int rtw89_set_channel(struct rtw89_dev *rtwdev) { struct rtw89_hal *hal = &rtwdev->hal; const struct rtw89_chip_info *chip = rtwdev->chip; @@ -399,7 +399,7 @@ void rtw89_set_channel(struct rtw89_dev *rtwdev) break; default: WARN(1, "Invalid ent mode: %d\n", mode); - return; + return -EINVAL; } roc_idx = atomic_read(&hal->roc_entity_idx); @@ -426,6 +426,7 @@ void rtw89_set_channel(struct rtw89_dev *rtwdev) } rtw89_set_entity_state(rtwdev, true); + return 0; } void rtw89_get_channel(struct rtw89_dev *rtwdev, struct rtw89_vif *rtwvif, diff --git a/drivers/net/wireless/realtek/rtw89/core.h b/drivers/net/wireless/realtek/rtw89/core.h index d98dcf12bef7..462c4b03c76b 100644 --- a/drivers/net/wireless/realtek/rtw89/core.h +++ b/drivers/net/wireless/realtek/rtw89/core.h @@ -6045,7 +6045,7 @@ void rtw89_core_set_chip_txpwr(struct rtw89_dev *rtwdev); void rtw89_get_default_chandef(struct cfg80211_chan_def *chandef); void rtw89_get_channel_params(const struct cfg80211_chan_def *chandef, struct rtw89_chan *chan); -void rtw89_set_channel(struct rtw89_dev *rtwdev); +int rtw89_set_channel(struct rtw89_dev *rtwdev); void rtw89_get_channel(struct rtw89_dev *rtwdev, struct rtw89_vif *rtwvif, struct rtw89_chan *chan); u8 rtw89_core_acquire_bit_map(unsigned long *addr, unsigned long size); -- cgit v1.2.3 From 162bf67f74c71d56889c1c938d7901cfb76e2cbd Mon Sep 17 00:00:00 2001 From: Zong-Zhe Yang Date: Tue, 6 Feb 2024 11:06:24 +0800 Subject: wifi: rtw89: chan: MCC take reconfig into account During mac80211 reconfig, chanctx ops of multiple channels might not be called in order as normal cases. However, we expect the first active chanctx always to be put at our sub entity index 0. So, if it does not, we do a swap there. Besides, reconfig won't allocate a new chanctx object. So, we should reset the reference count when ops add chanctx. Signed-off-by: Zong-Zhe Yang Signed-off-by: Ping-Ke Shih Signed-off-by: Kalle Valo Link: https://msgid.link/20240206030624.23382-7-pkshih@realtek.com --- drivers/net/wireless/realtek/rtw89/chan.c | 13 +++++++++++++ 1 file changed, 13 insertions(+) (limited to 'drivers/net') diff --git a/drivers/net/wireless/realtek/rtw89/chan.c b/drivers/net/wireless/realtek/rtw89/chan.c index 71fe0d3ab3b0..7b9baf4db70f 100644 --- a/drivers/net/wireless/realtek/rtw89/chan.c +++ b/drivers/net/wireless/realtek/rtw89/chan.c @@ -1980,6 +1980,7 @@ int rtw89_chanctx_ops_add(struct rtw89_dev *rtwdev, rtw89_config_entity_chandef(rtwdev, idx, &ctx->def); cfg->idx = idx; + cfg->ref_count = 0; hal->sub[idx].cfg = cfg; return 0; } @@ -2011,11 +2012,23 @@ int rtw89_chanctx_ops_assign_vif(struct rtw89_dev *rtwdev, struct ieee80211_chanctx_conf *ctx) { struct rtw89_chanctx_cfg *cfg = (struct rtw89_chanctx_cfg *)ctx->drv_priv; + struct rtw89_entity_weight w = {}; rtwvif->sub_entity_idx = cfg->idx; rtwvif->chanctx_assigned = true; cfg->ref_count++; + if (cfg->idx == RTW89_SUB_ENTITY_0) + goto out; + + rtw89_entity_calculate_weight(rtwdev, &w); + if (w.active_chanctxs != 1) + goto out; + + /* put the first active chanctx at RTW89_SUB_ENTITY_0 */ + rtw89_swap_sub_entity(rtwdev, cfg->idx, RTW89_SUB_ENTITY_0); + +out: return rtw89_set_channel(rtwdev); } -- cgit v1.2.3 From c08a986344a5eb80ae3651f33d0f386cd9e97252 Mon Sep 17 00:00:00 2001 From: David Mosberger-Tang Date: Wed, 7 Feb 2024 05:07:42 +0000 Subject: wifi: wilc1000: correct CRC7 calculation Document ATWILC1000/ATWILC3000 Baremetal Wi-Fi/BLE Link Controller Software Design Guide https://tinyurl.com/yer2xhyc says that bit 0 of the CRC7 code must always be a 1. I confirmed that today with a logic analyzer: setting bit 0 causes wilc1000 to accept a command with CRC7 enabled, whereas clearing bit 0 causes wilc1000 to reject the command with a CRC error. Signed-off-by: David Mosberger-Tang Signed-off-by: Kalle Valo Link: https://msgid.link/20240207050736.2717641-1-davidm@egauge.net --- drivers/net/wireless/microchip/wilc1000/spi.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/microchip/wilc1000/spi.c b/drivers/net/wireless/microchip/wilc1000/spi.c index eaf4dda9c540..c92ee4b73a74 100644 --- a/drivers/net/wireless/microchip/wilc1000/spi.c +++ b/drivers/net/wireless/microchip/wilc1000/spi.c @@ -473,7 +473,7 @@ static int spi_data_write(struct wilc *wilc, u8 *b, u32 sz) ********************************************/ static u8 wilc_get_crc7(u8 *buffer, u32 len) { - return crc7_be(0xfe, buffer, len); + return crc7_be(0xfe, buffer, len) | 0x01; } static int wilc_spi_single_read(struct wilc *wilc, u8 cmd, u32 adr, void *b, -- cgit v1.2.3 From 14ddc470ba22057f7734245a6a521d764f8a7fbe Mon Sep 17 00:00:00 2001 From: Kees Cook Date: Wed, 7 Feb 2024 02:30:33 -0800 Subject: wifi: mwifiex: Refactor 1-element array into flexible array in struct mwifiex_ie_types_chan_list_param_set struct mwifiex_ie_types_chan_list_param_set::chan_scan_param is treated as a flexible array, so convert it into one so that it doesn't trip the array bounds sanitizer[1]. Only a few places were using sizeof() on the whole struct, so adjust those to follow the calculation pattern to avoid including the trailing single element. Examining binary output differences doesn't appear to show any literal size values changing, though it is obfuscated a bit by the compiler adjusting register usage and stack spill slots, etc. Link: https://github.com/KSPP/linux/issues/51 [1] Cc: Brian Norris Cc: Kalle Valo Cc: Dmitry Antipov Cc: Johannes Berg Cc: zuoqilin Cc: Ruan Jinjie Cc: Thomas Gleixner Cc: Christophe JAILLET Cc: Gustavo A. R. Silva Cc: linux-wireless@vger.kernel.org Signed-off-by: Kees Cook Reviewed-by: Gustavo A. R. Silva Signed-off-by: Kalle Valo Link: https://msgid.link/20240207103024.make.423-kees@kernel.org --- drivers/net/wireless/marvell/mwifiex/11n.c | 12 +++++------- drivers/net/wireless/marvell/mwifiex/fw.h | 2 +- drivers/net/wireless/marvell/mwifiex/scan.c | 14 ++++++-------- 3 files changed, 12 insertions(+), 16 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/marvell/mwifiex/11n.c b/drivers/net/wireless/marvell/mwifiex/11n.c index 90e401100898..c0c635e74bc5 100644 --- a/drivers/net/wireless/marvell/mwifiex/11n.c +++ b/drivers/net/wireless/marvell/mwifiex/11n.c @@ -392,12 +392,10 @@ mwifiex_cmd_append_11n_tlv(struct mwifiex_private *priv, chan_list = (struct mwifiex_ie_types_chan_list_param_set *) *buffer; - memset(chan_list, 0, - sizeof(struct mwifiex_ie_types_chan_list_param_set)); + memset(chan_list, 0, struct_size(chan_list, chan_scan_param, 1)); chan_list->header.type = cpu_to_le16(TLV_TYPE_CHANLIST); - chan_list->header.len = cpu_to_le16( - sizeof(struct mwifiex_ie_types_chan_list_param_set) - - sizeof(struct mwifiex_ie_types_header)); + chan_list->header.len = + cpu_to_le16(sizeof(struct mwifiex_chan_scan_param_set)); chan_list->chan_scan_param[0].chan_number = bss_desc->bcn_ht_oper->primary_chan; chan_list->chan_scan_param[0].radio_type = @@ -411,8 +409,8 @@ mwifiex_cmd_append_11n_tlv(struct mwifiex_private *priv, (bss_desc->bcn_ht_oper->ht_param & IEEE80211_HT_PARAM_CHA_SEC_OFFSET)); - *buffer += sizeof(struct mwifiex_ie_types_chan_list_param_set); - ret_len += sizeof(struct mwifiex_ie_types_chan_list_param_set); + *buffer += struct_size(chan_list, chan_scan_param, 1); + ret_len += struct_size(chan_list, chan_scan_param, 1); } if (bss_desc->bcn_bss_co_2040) { diff --git a/drivers/net/wireless/marvell/mwifiex/fw.h b/drivers/net/wireless/marvell/mwifiex/fw.h index 62f3c9a52a1d..3adc447b715f 100644 --- a/drivers/net/wireless/marvell/mwifiex/fw.h +++ b/drivers/net/wireless/marvell/mwifiex/fw.h @@ -770,7 +770,7 @@ struct mwifiex_chan_scan_param_set { struct mwifiex_ie_types_chan_list_param_set { struct mwifiex_ie_types_header header; - struct mwifiex_chan_scan_param_set chan_scan_param[1]; + struct mwifiex_chan_scan_param_set chan_scan_param[]; } __packed; struct mwifiex_ie_types_rxba_sync { diff --git a/drivers/net/wireless/marvell/mwifiex/scan.c b/drivers/net/wireless/marvell/mwifiex/scan.c index a2ddac363b10..0326b121747c 100644 --- a/drivers/net/wireless/marvell/mwifiex/scan.c +++ b/drivers/net/wireless/marvell/mwifiex/scan.c @@ -664,15 +664,14 @@ mwifiex_scan_channel_list(struct mwifiex_private *priv, /* Copy the current channel TLV to the command being prepared */ - memcpy(chan_tlv_out->chan_scan_param + tlv_idx, + memcpy(&chan_tlv_out->chan_scan_param[tlv_idx], tmp_chan_list, - sizeof(chan_tlv_out->chan_scan_param)); + sizeof(*chan_tlv_out->chan_scan_param)); /* Increment the TLV header length by the size appended */ le16_unaligned_add_cpu(&chan_tlv_out->header.len, - sizeof( - chan_tlv_out->chan_scan_param)); + sizeof(*chan_tlv_out->chan_scan_param)); /* * The tlv buffer length is set to the number of bytes @@ -2369,12 +2368,11 @@ int mwifiex_cmd_802_11_bg_scan_config(struct mwifiex_private *priv, chan_idx < MWIFIEX_BG_SCAN_CHAN_MAX && bgscan_cfg_in->chan_list[chan_idx].chan_number; chan_idx++) { - temp_chan = chan_list_tlv->chan_scan_param + chan_idx; + temp_chan = &chan_list_tlv->chan_scan_param[chan_idx]; /* Increment the TLV header length by size appended */ le16_unaligned_add_cpu(&chan_list_tlv->header.len, - sizeof( - chan_list_tlv->chan_scan_param)); + sizeof(*chan_list_tlv->chan_scan_param)); temp_chan->chan_number = bgscan_cfg_in->chan_list[chan_idx].chan_number; @@ -2413,7 +2411,7 @@ int mwifiex_cmd_802_11_bg_scan_config(struct mwifiex_private *priv, chan_scan_param); le16_unaligned_add_cpu(&chan_list_tlv->header.len, chan_num * - sizeof(chan_list_tlv->chan_scan_param[0])); + sizeof(*chan_list_tlv->chan_scan_param)); } tlv_pos += (sizeof(chan_list_tlv->header) -- cgit v1.2.3 From f20073f50dfd1e1232e44834c74db718ffd2149b Mon Sep 17 00:00:00 2001 From: Alexey Berezhok Date: Thu, 8 Feb 2024 11:51:21 +0300 Subject: wifi: brcmfmac: do not cast hidden SSID attribute value to boolean In 'brcmf_cfg80211_start_ap()', not assume that NL80211_HIDDEN_SSID_NOT_IN_USE is zero but prefer an explicit check instead. Compile tested only. Found by Linux Verification Center (linuxtesting.org) with SVACE. Signed-off-by: Alexey Berezhok Signed-off-by: Kalle Valo Link: https://msgid.link/20240208085121.2430-1-a@bayrepo.ru --- drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c index d0cb39278cb9..adf8a14feb49 100644 --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c @@ -5274,7 +5274,7 @@ brcmf_cfg80211_start_ap(struct wiphy *wiphy, struct net_device *ndev, settings->hidden_ssid); if (err) { bphy_err(drvr, "%s closednet error (%d)\n", - settings->hidden_ssid ? + (settings->hidden_ssid != NL80211_HIDDEN_SSID_NOT_IN_USE) ? "enabled" : "disabled", err); goto exit; -- cgit v1.2.3 From db84b758541f0925a5c8263ea0af1656fe38412f Mon Sep 17 00:00:00 2001 From: Ping-Ke Shih Date: Fri, 9 Feb 2024 14:52:19 +0800 Subject: wifi: rtw89: correct PHY register offset for PHY-1 PHY-1 can be seen as a copy of PHY-0, and the difference is their base register address, so add a function to get offset to access PHY-1. Signed-off-by: Ping-Ke Shih Signed-off-by: Kalle Valo Link: https://msgid.link/20240209065229.34515-2-pkshih@realtek.com --- drivers/net/wireless/realtek/rtw89/phy.c | 13 +++++++++---- drivers/net/wireless/realtek/rtw89/phy.h | 1 + drivers/net/wireless/realtek/rtw89/phy_be.c | 19 +++++++++++++++++++ 3 files changed, 29 insertions(+), 4 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/realtek/rtw89/phy.c b/drivers/net/wireless/realtek/rtw89/phy.c index 9a8f5b764617..7c2f0ba996b1 100644 --- a/drivers/net/wireless/realtek/rtw89/phy.c +++ b/drivers/net/wireless/realtek/rtw89/phy.c @@ -13,6 +13,13 @@ #include "txrx.h" #include "util.h" +static u32 rtw89_phy0_phy1_offset(struct rtw89_dev *rtwdev, u32 addr) +{ + const struct rtw89_phy_gen_def *phy = rtwdev->chip->phy_def; + + return phy->phy0_phy1_offset(rtwdev, addr); +} + static u16 get_max_amsdu_len(struct rtw89_dev *rtwdev, const struct rtw89_ra_report *report) { @@ -1633,14 +1640,11 @@ static void rtw89_phy_init_rf_nctl(struct rtw89_dev *rtwdev) rtw89_rfk_parser(rtwdev, chip->nctl_post_table); } -static u32 rtw89_phy0_phy1_offset(struct rtw89_dev *rtwdev, u32 addr) +static u32 rtw89_phy0_phy1_offset_ax(struct rtw89_dev *rtwdev, u32 addr) { u32 phy_page = addr >> 8; u32 ofst = 0; - if (rtwdev->chip->chip_gen == RTW89_CHIP_BE) - return addr < 0x10000 ? 0x20000 : 0; - switch (phy_page) { case 0x6: case 0x7: @@ -6392,6 +6396,7 @@ const struct rtw89_phy_gen_def rtw89_phy_gen_ax = { .ccx = &rtw89_ccx_regs_ax, .physts = &rtw89_physts_regs_ax, .cfo = &rtw89_cfo_regs_ax, + .phy0_phy1_offset = rtw89_phy0_phy1_offset_ax, .config_bb_gain = rtw89_phy_config_bb_gain_ax, .preinit_rf_nctl = rtw89_phy_preinit_rf_nctl_ax, .bb_wrap_init = NULL, diff --git a/drivers/net/wireless/realtek/rtw89/phy.h b/drivers/net/wireless/realtek/rtw89/phy.h index d80ddc723e86..76234daab896 100644 --- a/drivers/net/wireless/realtek/rtw89/phy.h +++ b/drivers/net/wireless/realtek/rtw89/phy.h @@ -510,6 +510,7 @@ struct rtw89_phy_gen_def { const struct rtw89_ccx_regs *ccx; const struct rtw89_physts_regs *physts; const struct rtw89_cfo_regs *cfo; + u32 (*phy0_phy1_offset)(struct rtw89_dev *rtwdev, u32 addr); void (*config_bb_gain)(struct rtw89_dev *rtwdev, const struct rtw89_reg2_def *reg, enum rtw89_rf_path rf_path, diff --git a/drivers/net/wireless/realtek/rtw89/phy_be.c b/drivers/net/wireless/realtek/rtw89/phy_be.c index 6849438a5f3c..be0148f2b96f 100644 --- a/drivers/net/wireless/realtek/rtw89/phy_be.c +++ b/drivers/net/wireless/realtek/rtw89/phy_be.c @@ -78,6 +78,24 @@ static const struct rtw89_cfo_regs rtw89_cfo_regs_be = { .valid_0_mask = B_DCFO_OPT_EN_V1, }; +static u32 rtw89_phy0_phy1_offset_be(struct rtw89_dev *rtwdev, u32 addr) +{ + u32 phy_page = addr >> 8; + u32 ofst = 0; + + if ((phy_page >= 0x4 && phy_page <= 0xF) || + (phy_page >= 0x20 && phy_page <= 0x2B) || + (phy_page >= 0x40 && phy_page <= 0x4f) || + (phy_page >= 0x60 && phy_page <= 0x6f) || + (phy_page >= 0xE4 && phy_page <= 0xE5) || + (phy_page >= 0xE8 && phy_page <= 0xED)) + ofst = 0x1000; + else + ofst = 0x0; + + return ofst; +} + union rtw89_phy_bb_gain_arg_be { u32 addr; struct { @@ -952,6 +970,7 @@ const struct rtw89_phy_gen_def rtw89_phy_gen_be = { .ccx = &rtw89_ccx_regs_be, .physts = &rtw89_physts_regs_be, .cfo = &rtw89_cfo_regs_be, + .phy0_phy1_offset = rtw89_phy0_phy1_offset_be, .config_bb_gain = rtw89_phy_config_bb_gain_be, .preinit_rf_nctl = rtw89_phy_preinit_rf_nctl_be, .bb_wrap_init = rtw89_phy_bb_wrap_init_be, -- cgit v1.2.3 From e10cd2ddd89e8b3e61b49247067e79f7debec2f1 Mon Sep 17 00:00:00 2001 From: Ping-Ke Shih Date: Fri, 9 Feb 2024 14:52:20 +0800 Subject: wifi: rtw89: load BB parameters to PHY-1 We are going to support MLO/DBCC, so need to load parameter table to PHY-1 as well. Signed-off-by: Ping-Ke Shih Signed-off-by: Kalle Valo Link: https://msgid.link/20240209065229.34515-3-pkshih@realtek.com --- drivers/net/wireless/realtek/rtw89/phy.c | 29 ++++++++++++++++++++--------- 1 file changed, 20 insertions(+), 9 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/realtek/rtw89/phy.c b/drivers/net/wireless/realtek/rtw89/phy.c index 7c2f0ba996b1..81f73821e3fc 100644 --- a/drivers/net/wireless/realtek/rtw89/phy.c +++ b/drivers/net/wireless/realtek/rtw89/phy.c @@ -1025,22 +1025,30 @@ static void rtw89_phy_config_bb_reg(struct rtw89_dev *rtwdev, enum rtw89_rf_path rf_path, void *extra_data) { - if (reg->addr == 0xfe) + u32 addr; + + if (reg->addr == 0xfe) { mdelay(50); - else if (reg->addr == 0xfd) + } else if (reg->addr == 0xfd) { mdelay(5); - else if (reg->addr == 0xfc) + } else if (reg->addr == 0xfc) { mdelay(1); - else if (reg->addr == 0xfb) + } else if (reg->addr == 0xfb) { udelay(50); - else if (reg->addr == 0xfa) + } else if (reg->addr == 0xfa) { udelay(5); - else if (reg->addr == 0xf9) + } else if (reg->addr == 0xf9) { udelay(1); - else if (reg->data == BYPASS_CR_DATA) + } else if (reg->data == BYPASS_CR_DATA) { rtw89_debug(rtwdev, RTW89_DBG_PHY_TRACK, "Bypass CR 0x%x\n", reg->addr); - else - rtw89_phy_write32(rtwdev, reg->addr, reg->data); + } else { + addr = reg->addr; + + if ((uintptr_t)extra_data == RTW89_PHY_1) + addr += rtw89_phy0_phy1_offset(rtwdev, reg->addr); + + rtw89_phy_write32(rtwdev, addr, reg->data); + } } union rtw89_phy_bb_gain_arg { @@ -1554,6 +1562,9 @@ void rtw89_phy_init_bb_reg(struct rtw89_dev *rtwdev) bb_table = elm_info->bb_tbl ? elm_info->bb_tbl : chip->bb_table; rtw89_phy_init_reg(rtwdev, bb_table, rtw89_phy_config_bb_reg, NULL); + if (rtwdev->dbcc_en) + rtw89_phy_init_reg(rtwdev, bb_table, rtw89_phy_config_bb_reg, + (void *)RTW89_PHY_1); rtw89_chip_init_txpwr_unit(rtwdev, RTW89_PHY_0); bb_gain_table = elm_info->bb_gain ? elm_info->bb_gain : chip->bb_gain_table; -- cgit v1.2.3 From b6e65d18bc2e124d8ac017ad26ace0f5852fe51d Mon Sep 17 00:00:00 2001 From: Ping-Ke Shih Date: Fri, 9 Feb 2024 14:52:21 +0800 Subject: wifi: rtw89: mac: return held quota of DLE when changing MAC-1 DLE (data link engine) could hold quota when we are going to enable/disable MAC-1 block, so trigger hardware to return all held quota. Signed-off-by: Ping-Ke Shih Signed-off-by: Kalle Valo Link: https://msgid.link/20240209065229.34515-4-pkshih@realtek.com --- drivers/net/wireless/realtek/rtw89/mac.c | 19 +++++--- drivers/net/wireless/realtek/rtw89/mac.h | 4 +- drivers/net/wireless/realtek/rtw89/mac_be.c | 70 ++++++++++++++++++++++++++++- drivers/net/wireless/realtek/rtw89/reg.h | 10 +++++ 4 files changed, 95 insertions(+), 8 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/realtek/rtw89/mac.c b/drivers/net/wireless/realtek/rtw89/mac.c index ef4c492003d8..716e2192b774 100644 --- a/drivers/net/wireless/realtek/rtw89/mac.c +++ b/drivers/net/wireless/realtek/rtw89/mac.c @@ -3192,13 +3192,11 @@ static int set_cpuio_ax(struct rtw89_dev *rtwdev, return 0; } -int rtw89_mac_dle_quota_change(struct rtw89_dev *rtwdev, enum rtw89_qta_mode mode) +int rtw89_mac_dle_quota_change(struct rtw89_dev *rtwdev, enum rtw89_qta_mode mode, + bool band1_en) { const struct rtw89_mac_gen_def *mac = rtwdev->chip->mac_def; const struct rtw89_dle_mem *cfg; - struct rtw89_cpuio_ctrl ctrl_para = {0}; - u16 pkt_id; - int ret; cfg = get_dle_mem_cfg(rtwdev, mode); if (!cfg) { @@ -3213,6 +3211,16 @@ int rtw89_mac_dle_quota_change(struct rtw89_dev *rtwdev, enum rtw89_qta_mode mod dle_quota_cfg(rtwdev, cfg, INVALID_QT_WCPU); + return mac->dle_quota_change(rtwdev, band1_en); +} + +static int dle_quota_change_ax(struct rtw89_dev *rtwdev, bool band1_en) +{ + const struct rtw89_mac_gen_def *mac = rtwdev->chip->mac_def; + struct rtw89_cpuio_ctrl ctrl_para = {0}; + u16 pkt_id; + int ret; + ret = mac->dle_buf_req(rtwdev, 0x20, true, &pkt_id); if (ret) { rtw89_err(rtwdev, "[ERR]WDE DLE buf req\n"); @@ -3301,7 +3309,7 @@ static int band1_enable_ax(struct rtw89_dev *rtwdev) return ret; } - ret = rtw89_mac_dle_quota_change(rtwdev, rtwdev->mac.qta_mode); + ret = rtw89_mac_dle_quota_change(rtwdev, rtwdev->mac.qta_mode, true); if (ret) { rtw89_err(rtwdev, "[ERR]DLE quota change %d\n", ret); return ret; @@ -6218,6 +6226,7 @@ const struct rtw89_mac_gen_def rtw89_mac_gen_ax = { .wde_quota_cfg = wde_quota_cfg_ax, .ple_quota_cfg = ple_quota_cfg_ax, .set_cpuio = set_cpuio_ax, + .dle_quota_change = dle_quota_change_ax, .disable_cpu = rtw89_mac_disable_cpu_ax, .fwdl_enable_wcpu = rtw89_mac_enable_cpu_ax, diff --git a/drivers/net/wireless/realtek/rtw89/mac.h b/drivers/net/wireless/realtek/rtw89/mac.h index 7aea57804e93..b0a3b2a9eb5b 100644 --- a/drivers/net/wireless/realtek/rtw89/mac.h +++ b/drivers/net/wireless/realtek/rtw89/mac.h @@ -932,6 +932,7 @@ struct rtw89_mac_gen_def { const struct rtw89_ple_quota *max_cfg); int (*set_cpuio)(struct rtw89_dev *rtwdev, struct rtw89_cpuio_ctrl *ctrl_para, bool wd); + int (*dle_quota_change)(struct rtw89_dev *rtwdev, bool band1_en); void (*disable_cpu)(struct rtw89_dev *rtwdev); int (*fwdl_enable_wcpu)(struct rtw89_dev *rtwdev, u8 boot_reason, @@ -1388,7 +1389,8 @@ int rtw89_mac_resize_ple_rx_quota(struct rtw89_dev *rtwdev, bool wow); int rtw89_mac_ptk_drop_by_band_and_wait(struct rtw89_dev *rtwdev, enum rtw89_mac_idx band); void rtw89_mac_hw_mgnt_sec(struct rtw89_dev *rtwdev, bool wow); -int rtw89_mac_dle_quota_change(struct rtw89_dev *rtwdev, enum rtw89_qta_mode mode); +int rtw89_mac_dle_quota_change(struct rtw89_dev *rtwdev, enum rtw89_qta_mode mode, + bool band1_en); int rtw89_mac_get_dle_rsvd_qt_cfg(struct rtw89_dev *rtwdev, enum rtw89_mac_dle_rsvd_qt_type type, struct rtw89_mac_dle_rsvd_qt_cfg *cfg); diff --git a/drivers/net/wireless/realtek/rtw89/mac_be.c b/drivers/net/wireless/realtek/rtw89/mac_be.c index 13e6fa7a3ae8..e2e0a7549b53 100644 --- a/drivers/net/wireless/realtek/rtw89/mac_be.c +++ b/drivers/net/wireless/realtek/rtw89/mac_be.c @@ -1449,6 +1449,71 @@ static int set_cpuio_be(struct rtw89_dev *rtwdev, return 0; } +static int dle_upd_qta_aval_page_be(struct rtw89_dev *rtwdev, + enum rtw89_mac_dle_ctrl_type type, + enum rtw89_mac_dle_ple_quota_id quota_id) +{ + u32 val; + + if (type == DLE_CTRL_TYPE_WDE) { + rtw89_write32_mask(rtwdev, R_BE_WDE_BUFMGN_CTL, + B_BE_WDE_AVAL_UPD_QTAID_MASK, quota_id); + rtw89_write32_set(rtwdev, R_BE_WDE_BUFMGN_CTL, B_BE_WDE_AVAL_UPD_REQ); + + return read_poll_timeout(rtw89_read32, val, + !(val & B_BE_WDE_AVAL_UPD_REQ), + 1, 2000, false, rtwdev, R_BE_WDE_BUFMGN_CTL); + } else if (type == DLE_CTRL_TYPE_PLE) { + rtw89_write32_mask(rtwdev, R_BE_PLE_BUFMGN_CTL, + B_BE_PLE_AVAL_UPD_QTAID_MASK, quota_id); + rtw89_write32_set(rtwdev, R_BE_PLE_BUFMGN_CTL, B_BE_PLE_AVAL_UPD_REQ); + + return read_poll_timeout(rtw89_read32, val, + !(val & B_BE_PLE_AVAL_UPD_REQ), + 1, 2000, false, rtwdev, R_BE_PLE_BUFMGN_CTL); + } + + rtw89_warn(rtwdev, "%s wrong type %d\n", __func__, type); + return -EINVAL; +} + +static int dle_quota_change_be(struct rtw89_dev *rtwdev, bool band1_en) +{ + int ret; + + if (band1_en) { + ret = dle_upd_qta_aval_page_be(rtwdev, DLE_CTRL_TYPE_PLE, + PLE_QTAID_B0_TXPL); + if (ret) { + rtw89_err(rtwdev, "update PLE B0 TX avail page fail %d\n", ret); + return ret; + } + + ret = dle_upd_qta_aval_page_be(rtwdev, DLE_CTRL_TYPE_PLE, + PLE_QTAID_CMAC0_RX); + if (ret) { + rtw89_err(rtwdev, "update PLE CMAC0 RX avail page fail %d\n", ret); + return ret; + } + } else { + ret = dle_upd_qta_aval_page_be(rtwdev, DLE_CTRL_TYPE_PLE, + PLE_QTAID_B1_TXPL); + if (ret) { + rtw89_err(rtwdev, "update PLE B1 TX avail page fail %d\n", ret); + return ret; + } + + ret = dle_upd_qta_aval_page_be(rtwdev, DLE_CTRL_TYPE_PLE, + PLE_QTAID_CMAC1_RX); + if (ret) { + rtw89_err(rtwdev, "update PLE CMAC1 RX avail page fail %d\n", ret); + return ret; + } + } + + return 0; +} + static int preload_init_be(struct rtw89_dev *rtwdev, u8 mac_idx, enum rtw89_qta_mode mode) { @@ -1538,7 +1603,7 @@ static int band1_enable_be(struct rtw89_dev *rtwdev) return ret; } - ret = rtw89_mac_dle_quota_change(rtwdev, rtwdev->mac.qta_mode); + ret = rtw89_mac_dle_quota_change(rtwdev, rtwdev->mac.qta_mode, true); if (ret) { rtw89_err(rtwdev, "[ERR]DLE quota change %d\n", ret); return ret; @@ -1593,7 +1658,7 @@ static int band1_disable_be(struct rtw89_dev *rtwdev) return ret; } - ret = rtw89_mac_dle_quota_change(rtwdev, rtwdev->mac.qta_mode); + ret = rtw89_mac_dle_quota_change(rtwdev, rtwdev->mac.qta_mode, false); if (ret) { rtw89_err(rtwdev, "[ERR]DLE quota change %d\n", ret); return ret; @@ -2347,6 +2412,7 @@ const struct rtw89_mac_gen_def rtw89_mac_gen_be = { .wde_quota_cfg = wde_quota_cfg_be, .ple_quota_cfg = ple_quota_cfg_be, .set_cpuio = set_cpuio_be, + .dle_quota_change = dle_quota_change_be, .disable_cpu = rtw89_mac_disable_cpu_be, .fwdl_enable_wcpu = rtw89_mac_fwdl_enable_wcpu_be, diff --git a/drivers/net/wireless/realtek/rtw89/reg.h b/drivers/net/wireless/realtek/rtw89/reg.h index 6368b2b32c0c..20b538526541 100644 --- a/drivers/net/wireless/realtek/rtw89/reg.h +++ b/drivers/net/wireless/realtek/rtw89/reg.h @@ -5020,6 +5020,11 @@ #define B_BE_WDE_START_BOUND_MASK GENMASK(14, 8) #define B_BE_WDE_PAGE_SEL_MASK GENMASK(1, 0) +#define R_BE_WDE_BUFMGN_CTL 0x8C10 +#define B_BE_WDE_AVAL_UPD_REQ BIT(29) +#define B_BE_WDE_AVAL_UPD_QTAID_MASK GENMASK(27, 24) +#define B_BE_WDE_BUFMGN_FRZTMR_MODE BIT(0) + #define R_BE_WDE_ERR_IMR 0x8C38 #define B_BE_WDE_DATCHN_CAMREQ_ERR_INT_EN BIT(29) #define B_BE_WDE_DATCHN_ADRERR_ERR_INT_EN BIT(28) @@ -5136,6 +5141,11 @@ #define B_BE_PLE_START_BOUND_MASK GENMASK(14, 8) #define B_BE_PLE_PAGE_SEL_MASK GENMASK(1, 0) +#define R_BE_PLE_BUFMGN_CTL 0x9010 +#define B_BE_PLE_AVAL_UPD_REQ BIT(29) +#define B_BE_PLE_AVAL_UPD_QTAID_MASK GENMASK(27, 24) +#define B_BE_PLE_BUFMGN_FRZTMR_MODE BIT(0) + #define R_BE_PLE_ERR_IMR 0x9038 #define B_BE_PLE_DATCHN_CAMREQ_ERR_INT_EN BIT(29) #define B_BE_PLE_DATCHN_ADRERR_ERR_INT_EN BIT(28) -- cgit v1.2.3 From b204d2475266ad4b917419bd8c3d5cc1f75111b8 Mon Sep 17 00:00:00 2001 From: Ping-Ke Shih Date: Fri, 9 Feb 2024 14:52:22 +0800 Subject: wifi: rtw89: mac: correct MUEDCA setting for MAC-1 Consider mac_idx as an argument to set this register to disable QoS NULL update MUEDCA timer. Signed-off-by: Ping-Ke Shih Signed-off-by: Kalle Valo Link: https://msgid.link/20240209065229.34515-5-pkshih@realtek.com --- drivers/net/wireless/realtek/rtw89/mac_be.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/realtek/rtw89/mac_be.c b/drivers/net/wireless/realtek/rtw89/mac_be.c index e2e0a7549b53..fdbfb76f97ee 100644 --- a/drivers/net/wireless/realtek/rtw89/mac_be.c +++ b/drivers/net/wireless/realtek/rtw89/mac_be.c @@ -995,7 +995,8 @@ static int tmac_init_be(struct rtw89_dev *rtwdev, u8 mac_idx) { u32 reg; - rtw89_write32_clr(rtwdev, R_BE_TB_PPDU_CTRL, B_BE_QOSNULL_UPD_MUEDCA_EN); + reg = rtw89_mac_reg_by_idx(rtwdev, R_BE_TB_PPDU_CTRL, mac_idx); + rtw89_write32_clr(rtwdev, reg, B_BE_QOSNULL_UPD_MUEDCA_EN); reg = rtw89_mac_reg_by_idx(rtwdev, R_BE_WMTX_TCR_BE_4, mac_idx); rtw89_write32_mask(rtwdev, reg, B_BE_EHT_HE_PPDU_4XLTF_ZLD_USTIMER_MASK, 0x12); -- cgit v1.2.3 From fecf6b57fbc7560ee5f6e9771ac1f2653e4cc49d Mon Sep 17 00:00:00 2001 From: Ping-Ke Shih Date: Fri, 9 Feb 2024 14:52:23 +0800 Subject: wifi: rtw89: mac: reset PHY-1 hardware when going to enable/disable When going to use PHY-1, reset the hardware to make it work properly. Signed-off-by: Ping-Ke Shih Signed-off-by: Kalle Valo Link: https://msgid.link/20240209065229.34515-6-pkshih@realtek.com --- drivers/net/wireless/realtek/rtw89/mac_be.c | 7 +++++++ 1 file changed, 7 insertions(+) (limited to 'drivers/net') diff --git a/drivers/net/wireless/realtek/rtw89/mac_be.c b/drivers/net/wireless/realtek/rtw89/mac_be.c index fdbfb76f97ee..f3c82751993c 100644 --- a/drivers/net/wireless/realtek/rtw89/mac_be.c +++ b/drivers/net/wireless/realtek/rtw89/mac_be.c @@ -1546,6 +1546,13 @@ static int preload_init_be(struct rtw89_dev *rtwdev, u8 mac_idx, static int dbcc_bb_ctrl_be(struct rtw89_dev *rtwdev, bool bb1_en) { + u32 set = B_BE_FEN_BB1PLAT_RSTB | B_BE_FEN_BB1_IP_RSTN; + + if (bb1_en) + rtw89_write32_set(rtwdev, R_BE_FEN_RST_ENABLE, set); + else + rtw89_write32_clr(rtwdev, R_BE_FEN_RST_ENABLE, set); + return 0; } -- cgit v1.2.3 From 505b57d08f72dc67c97bf743bb33ca5c95755def Mon Sep 17 00:00:00 2001 From: Ping-Ke Shih Date: Fri, 9 Feb 2024 14:52:24 +0800 Subject: wifi: rtw89: use PLCP information to match BSS_COLOR and AID Hardware can use spatial reuse to reduce interference in OBSS environment, and originally use MAC header to match BSS color and AID. Change to use PLCP to match them earlier to prevent margin timing. Signed-off-by: Ping-Ke Shih Signed-off-by: Kalle Valo Link: https://msgid.link/20240209065229.34515-7-pkshih@realtek.com --- drivers/net/wireless/realtek/rtw89/mac.c | 3 +++ drivers/net/wireless/realtek/rtw89/mac_be.c | 3 +++ drivers/net/wireless/realtek/rtw89/reg.h | 14 ++++++++++++++ 3 files changed, 20 insertions(+) (limited to 'drivers/net') diff --git a/drivers/net/wireless/realtek/rtw89/mac.c b/drivers/net/wireless/realtek/rtw89/mac.c index 716e2192b774..71e9b9d7b430 100644 --- a/drivers/net/wireless/realtek/rtw89/mac.c +++ b/drivers/net/wireless/realtek/rtw89/mac.c @@ -2537,6 +2537,9 @@ static int spatial_reuse_init_ax(struct rtw89_dev *rtwdev, u8 mac_idx) reg = rtw89_mac_reg_by_idx(rtwdev, R_AX_RX_SR_CTRL, mac_idx); rtw89_write8_clr(rtwdev, reg, B_AX_SR_EN); + reg = rtw89_mac_reg_by_idx(rtwdev, R_AX_BSSID_SRC_CTRL, mac_idx); + rtw89_write8_set(rtwdev, reg, B_AX_PLCP_SRC_EN); + return 0; } diff --git a/drivers/net/wireless/realtek/rtw89/mac_be.c b/drivers/net/wireless/realtek/rtw89/mac_be.c index f3c82751993c..f4b51183e3f4 100644 --- a/drivers/net/wireless/realtek/rtw89/mac_be.c +++ b/drivers/net/wireless/realtek/rtw89/mac_be.c @@ -988,6 +988,9 @@ static int spatial_reuse_init_be(struct rtw89_dev *rtwdev, u8 mac_idx) reg = rtw89_mac_reg_by_idx(rtwdev, R_BE_RX_SR_CTRL, mac_idx); rtw89_write8_clr(rtwdev, reg, B_BE_SR_EN | B_BE_SR_CTRL_PLCP_EN); + reg = rtw89_mac_reg_by_idx(rtwdev, R_BE_BSSID_SRC_CTRL, mac_idx); + rtw89_write8_set(rtwdev, reg, B_BE_PLCP_SRC_EN); + return 0; } diff --git a/drivers/net/wireless/realtek/rtw89/reg.h b/drivers/net/wireless/realtek/rtw89/reg.h index 20b538526541..31bdc7616749 100644 --- a/drivers/net/wireless/realtek/rtw89/reg.h +++ b/drivers/net/wireless/realtek/rtw89/reg.h @@ -3246,6 +3246,13 @@ #define R_AX_RX_SR_CTRL_C1 0xEE4A #define B_AX_SR_EN BIT(0) +#define R_AX_BSSID_SRC_CTRL 0xCE4B +#define R_AX_BSSID_SRC_CTRL_C1 0xEE4B +#define B_AX_BSSID_MATCH BIT(3) +#define B_AX_PARTIAL_AID_MATCH BIT(2) +#define B_AX_BSSCOLOR_MATCH BIT(1) +#define B_AX_PLCP_SRC_EN BIT(0) + #define R_AX_CSIRPT_OPTION 0xCE64 #define R_AX_CSIRPT_OPTION_C1 0xEE64 #define B_AX_CSIPRT_HESU_AID_EN BIT(25) @@ -7208,6 +7215,13 @@ #define B_BE_SR_CTRL_PLCP_EN BIT(1) #define B_BE_SR_EN BIT(0) +#define R_BE_BSSID_SRC_CTRL 0x1144B +#define R_BE_BSSID_SRC_CTRL_C1 0x1544B +#define B_BE_BSSID_MATCH BIT(3) +#define B_BE_PARTIAL_AID_MATCH BIT(2) +#define B_BE_BSSCOLOR_MATCH BIT(1) +#define B_BE_PLCP_SRC_EN BIT(0) + #define R_BE_CSIRPT_OPTION 0x11464 #define R_BE_CSIRPT_OPTION_C1 0x15464 #define B_BE_CSIPRT_EHTSU_AID_EN BIT(26) -- cgit v1.2.3 From 49ea98235ada68ee1e2cad660bbb2e8e2cd87670 Mon Sep 17 00:00:00 2001 From: Zong-Zhe Yang Date: Fri, 9 Feb 2024 14:52:25 +0800 Subject: wifi: rtw89: differentiate narrow_bw_ru_dis setting according to chip gen When there are OBSS that cannot interpret 26-tone RU transmissions, we should disable 26-tone RU HE TB PPDU transmissions. So, add registers accordingly. Signed-off-by: Zong-Zhe Yang Signed-off-by: Ping-Ke Shih Signed-off-by: Kalle Valo Link: https://msgid.link/20240209065229.34515-8-pkshih@realtek.com --- drivers/net/wireless/realtek/rtw89/mac.c | 12 +++++++++--- drivers/net/wireless/realtek/rtw89/mac.h | 1 + drivers/net/wireless/realtek/rtw89/mac_be.c | 4 ++++ 3 files changed, 14 insertions(+), 3 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/realtek/rtw89/mac.c b/drivers/net/wireless/realtek/rtw89/mac.c index 71e9b9d7b430..8a1d3e6e81a9 100644 --- a/drivers/net/wireless/realtek/rtw89/mac.c +++ b/drivers/net/wireless/realtek/rtw89/mac.c @@ -4619,6 +4619,7 @@ void rtw89_mac_set_he_obss_narrow_bw_ru(struct rtw89_dev *rtwdev, struct ieee80211_vif *vif) { struct rtw89_vif *rtwvif = (struct rtw89_vif *)vif->drv_priv; + const struct rtw89_mac_gen_def *mac = rtwdev->chip->mac_def; struct ieee80211_hw *hw = rtwdev->hw; bool tolerated = true; u32 reg; @@ -4633,11 +4634,12 @@ void rtw89_mac_set_he_obss_narrow_bw_ru(struct rtw89_dev *rtwdev, rtw89_mac_check_he_obss_narrow_bw_ru_iter, &tolerated); - reg = rtw89_mac_reg_by_idx(rtwdev, R_AX_RXTRIG_TEST_USER_2, rtwvif->mac_idx); + reg = rtw89_mac_reg_by_idx(rtwdev, mac->narrow_bw_ru_dis.addr, + rtwvif->mac_idx); if (tolerated) - rtw89_write32_clr(rtwdev, reg, B_AX_RXTRIG_RU26_DIS); + rtw89_write32_clr(rtwdev, reg, mac->narrow_bw_ru_dis.mask); else - rtw89_write32_set(rtwdev, reg, B_AX_RXTRIG_RU26_DIS); + rtw89_write32_set(rtwdev, reg, mac->narrow_bw_ru_dis.mask); } void rtw89_mac_stop_ap(struct rtw89_dev *rtwdev, struct rtw89_vif *rtwvif) @@ -6206,6 +6208,10 @@ const struct rtw89_mac_gen_def rtw89_mac_gen_ax = { .mask = B_AX_BFMEE_HT_NDPA_EN | B_AX_BFMEE_VHT_NDPA_EN | B_AX_BFMEE_HE_NDPA_EN, }, + .narrow_bw_ru_dis = { + .addr = R_AX_RXTRIG_TEST_USER_2, + .mask = B_AX_RXTRIG_RU26_DIS, + }, .check_mac_en = rtw89_mac_check_mac_en_ax, .sys_init = sys_init_ax, diff --git a/drivers/net/wireless/realtek/rtw89/mac.h b/drivers/net/wireless/realtek/rtw89/mac.h index b0a3b2a9eb5b..c5ebac1d5990 100644 --- a/drivers/net/wireless/realtek/rtw89/mac.h +++ b/drivers/net/wireless/realtek/rtw89/mac.h @@ -898,6 +898,7 @@ struct rtw89_mac_gen_def { struct rtw89_reg_def muedca_ctrl; struct rtw89_reg_def bfee_ctrl; + struct rtw89_reg_def narrow_bw_ru_dis; int (*check_mac_en)(struct rtw89_dev *rtwdev, u8 band, enum rtw89_mac_hwmod_sel sel); diff --git a/drivers/net/wireless/realtek/rtw89/mac_be.c b/drivers/net/wireless/realtek/rtw89/mac_be.c index f4b51183e3f4..6388c56a3c90 100644 --- a/drivers/net/wireless/realtek/rtw89/mac_be.c +++ b/drivers/net/wireless/realtek/rtw89/mac_be.c @@ -2400,6 +2400,10 @@ const struct rtw89_mac_gen_def rtw89_mac_gen_be = { .mask = B_BE_BFMEE_HT_NDPA_EN | B_BE_BFMEE_VHT_NDPA_EN | B_BE_BFMEE_HE_NDPA_EN | B_BE_BFMEE_EHT_NDPA_EN, }, + .narrow_bw_ru_dis = { + .addr = R_BE_RXTRIG_TEST_USER_2, + .mask = B_BE_RXTRIG_RU26_DIS, + }, .check_mac_en = rtw89_mac_check_mac_en_be, .sys_init = sys_init_be, -- cgit v1.2.3 From ef95df598622a399b62b69b764682c21543b1d63 Mon Sep 17 00:00:00 2001 From: Ping-Ke Shih Date: Fri, 9 Feb 2024 14:52:26 +0800 Subject: wifi: rtw89: 8922a: correct register definition and merge IO for ctrl_nbtg_bt_tx() ctrl_nbtg_bt_tx is used to control AGC settings under non-shared path condition, which is affected by BT TX. To speed up IO, merge continual bit mask into one IO. Also, correct a register definition. Signed-off-by: Ping-Ke Shih Signed-off-by: Kalle Valo Link: https://msgid.link/20240209065229.34515-9-pkshih@realtek.com --- drivers/net/wireless/realtek/rtw89/reg.h | 6 +++++- drivers/net/wireless/realtek/rtw89/rtw8922a.c | 30 +++++++-------------------- 2 files changed, 13 insertions(+), 23 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/realtek/rtw89/reg.h b/drivers/net/wireless/realtek/rtw89/reg.h index 31bdc7616749..26aa2d9bd526 100644 --- a/drivers/net/wireless/realtek/rtw89/reg.h +++ b/drivers/net/wireless/realtek/rtw89/reg.h @@ -8077,14 +8077,16 @@ #define R_S1_ADDCK 0x3E00 #define B_S1_ADDCK_I GENMASK(9, 0) #define B_S1_ADDCK_Q GENMASK(19, 10) -#define R_OP1DB_A 0x406B +#define R_OP1DB_A 0x40B0 #define B_OP1DB_A GENMASK(31, 24) #define R_OP1DB1_A 0x40BC +#define B_TIA10_A GENMASK(15, 0) #define B_TIA1_A GENMASK(15, 8) #define B_TIA0_A GENMASK(7, 0) #define R_BKOFF_A 0x40E0 #define B_BKOFF_IBADC_A GENMASK(23, 18) #define R_BACKOFF_A 0x40E4 +#define B_LNA_IBADC_A GENMASK(29, 18) #define B_BACKOFF_LNA_A GENMASK(29, 24) #define B_BACKOFF_IBADC_A GENMASK(23, 18) #define R_RXBY_WBADC_A 0x40F4 @@ -8140,11 +8142,13 @@ #define R_LNA_OP 0x44B0 #define B_LNA6 GENMASK(31, 24) #define R_LNA_TIA 0x44BC +#define B_TIA10_B GENMASK(15, 0) #define B_TIA1_B GENMASK(15, 8) #define B_TIA0_B GENMASK(7, 0) #define R_BKOFF_B 0x44E0 #define B_BKOFF_IBADC_B GENMASK(23, 18) #define R_BACKOFF_B 0x44E4 +#define B_LNA_IBADC_B GENMASK(29, 18) #define B_BACKOFF_LNA_B GENMASK(29, 24) #define B_BACKOFF_IBADC_B GENMASK(23, 18) #define R_RXBY_WBADC_B 0x44F4 diff --git a/drivers/net/wireless/realtek/rtw89/rtw8922a.c b/drivers/net/wireless/realtek/rtw89/rtw8922a.c index 02ec4d27011f..f7b81daa0b03 100644 --- a/drivers/net/wireless/realtek/rtw89/rtw8922a.c +++ b/drivers/net/wireless/realtek/rtw89/rtw8922a.c @@ -1526,11 +1526,8 @@ static void rtw8922a_ctrl_nbtg_bt_tx(struct rtw89_dev *rtwdev, bool en, 0x0, phy_idx); rtw89_phy_write32_idx(rtwdev, R_BT_SHARE_A, B_BT_TRK_OFF_A, 0x0, phy_idx); rtw89_phy_write32_idx(rtwdev, R_OP1DB_A, B_OP1DB_A, 0x80, phy_idx); - rtw89_phy_write32_idx(rtwdev, R_OP1DB1_A, B_TIA0_A, 0x80, phy_idx); - rtw89_phy_write32_idx(rtwdev, R_OP1DB1_A, B_TIA1_A, 0x80, phy_idx); - rtw89_phy_write32_idx(rtwdev, R_BACKOFF_A, B_BACKOFF_IBADC_A, - 0x34, phy_idx); - rtw89_phy_write32_idx(rtwdev, R_BACKOFF_A, B_BACKOFF_LNA_A, 0x0, phy_idx); + rtw89_phy_write32_idx(rtwdev, R_OP1DB1_A, B_TIA10_A, 0x8080, phy_idx); + rtw89_phy_write32_idx(rtwdev, R_BACKOFF_A, B_LNA_IBADC_A, 0x34, phy_idx); rtw89_phy_write32_idx(rtwdev, R_BKOFF_A, B_BKOFF_IBADC_A, 0x34, phy_idx); rtw89_phy_write32_idx(rtwdev, R_FORCE_FIR_B, B_FORCE_FIR_B, 0x3, phy_idx); rtw89_phy_write32_idx(rtwdev, R_RXBY_WBADC_B, B_RXBY_WBADC_B, @@ -1539,11 +1536,8 @@ static void rtw8922a_ctrl_nbtg_bt_tx(struct rtw89_dev *rtwdev, bool en, 0x0, phy_idx); rtw89_phy_write32_idx(rtwdev, R_BT_SHARE_B, B_BT_TRK_OFF_B, 0x0, phy_idx); rtw89_phy_write32_idx(rtwdev, R_LNA_OP, B_LNA6, 0x80, phy_idx); - rtw89_phy_write32_idx(rtwdev, R_LNA_TIA, B_TIA0_B, 0x80, phy_idx); - rtw89_phy_write32_idx(rtwdev, R_LNA_TIA, B_TIA1_B, 0x80, phy_idx); - rtw89_phy_write32_idx(rtwdev, R_BACKOFF_B, B_BACKOFF_IBADC_B, - 0x34, phy_idx); - rtw89_phy_write32_idx(rtwdev, R_BACKOFF_B, B_BACKOFF_LNA_B, 0x0, phy_idx); + rtw89_phy_write32_idx(rtwdev, R_LNA_TIA, B_TIA10_B, 0x8080, phy_idx); + rtw89_phy_write32_idx(rtwdev, R_BACKOFF_B, B_LNA_IBADC_B, 0x34, phy_idx); rtw89_phy_write32_idx(rtwdev, R_BKOFF_B, B_BKOFF_IBADC_B, 0x34, phy_idx); } else { rtw89_phy_write32_idx(rtwdev, R_FORCE_FIR_A, B_FORCE_FIR_A, 0x0, phy_idx); @@ -1553,12 +1547,8 @@ static void rtw8922a_ctrl_nbtg_bt_tx(struct rtw89_dev *rtwdev, bool en, 0x1, phy_idx); rtw89_phy_write32_idx(rtwdev, R_BT_SHARE_A, B_BT_TRK_OFF_A, 0x1, phy_idx); rtw89_phy_write32_idx(rtwdev, R_OP1DB_A, B_OP1DB_A, 0x1a, phy_idx); - rtw89_phy_write32_idx(rtwdev, R_OP1DB1_A, B_TIA0_A, 0x2a, phy_idx); - rtw89_phy_write32_idx(rtwdev, R_OP1DB1_A, B_TIA1_A, 0x2a, phy_idx); - rtw89_phy_write32_idx(rtwdev, R_BACKOFF_A, B_BACKOFF_IBADC_A, - 0x26, phy_idx); - rtw89_phy_write32_idx(rtwdev, R_BACKOFF_A, B_BACKOFF_LNA_A, - 0x1e, phy_idx); + rtw89_phy_write32_idx(rtwdev, R_OP1DB1_A, B_TIA10_A, 0x2a2a, phy_idx); + rtw89_phy_write32_idx(rtwdev, R_BACKOFF_A, B_LNA_IBADC_A, 0x7a6, phy_idx); rtw89_phy_write32_idx(rtwdev, R_BKOFF_A, B_BKOFF_IBADC_A, 0x26, phy_idx); rtw89_phy_write32_idx(rtwdev, R_FORCE_FIR_B, B_FORCE_FIR_B, 0x0, phy_idx); rtw89_phy_write32_idx(rtwdev, R_RXBY_WBADC_B, B_RXBY_WBADC_B, @@ -1567,12 +1557,8 @@ static void rtw8922a_ctrl_nbtg_bt_tx(struct rtw89_dev *rtwdev, bool en, 0x1, phy_idx); rtw89_phy_write32_idx(rtwdev, R_BT_SHARE_B, B_BT_TRK_OFF_B, 0x1, phy_idx); rtw89_phy_write32_idx(rtwdev, R_LNA_OP, B_LNA6, 0x20, phy_idx); - rtw89_phy_write32_idx(rtwdev, R_LNA_TIA, B_TIA0_B, 0x30, phy_idx); - rtw89_phy_write32_idx(rtwdev, R_LNA_TIA, B_TIA1_B, 0x2a, phy_idx); - rtw89_phy_write32_idx(rtwdev, R_BACKOFF_B, B_BACKOFF_IBADC_B, - 0x26, phy_idx); - rtw89_phy_write32_idx(rtwdev, R_BACKOFF_B, B_BACKOFF_LNA_B, - 0x1e, phy_idx); + rtw89_phy_write32_idx(rtwdev, R_LNA_TIA, B_TIA10_B, 0x2a30, phy_idx); + rtw89_phy_write32_idx(rtwdev, R_BACKOFF_B, B_LNA_IBADC_B, 0x7a6, phy_idx); rtw89_phy_write32_idx(rtwdev, R_BKOFF_B, B_BKOFF_IBADC_B, 0x26, phy_idx); } } -- cgit v1.2.3 From 598481c6eb20b29088caa0c69085904b2ca08674 Mon Sep 17 00:00:00 2001 From: Chih-Kang Chang Date: Fri, 9 Feb 2024 14:52:27 +0800 Subject: wifi: rtw89: 8922a: implement AP mode related reg for BE generation Modify reg for BE generation when AP stop, otherwise have warning messages "Polling beacon packet empty fail". Signed-off-by: Chih-Kang Chang Signed-off-by: Ping-Ke Shih Signed-off-by: Kalle Valo Link: https://msgid.link/20240209065229.34515-10-pkshih@realtek.com --- drivers/net/wireless/realtek/rtw89/core.h | 3 +++ drivers/net/wireless/realtek/rtw89/mac.c | 13 +++++++++---- drivers/net/wireless/realtek/rtw89/mac_be.c | 3 +++ drivers/net/wireless/realtek/rtw89/reg.h | 6 ++++++ 4 files changed, 21 insertions(+), 4 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/realtek/rtw89/core.h b/drivers/net/wireless/realtek/rtw89/core.h index 462c4b03c76b..0e451245a65a 100644 --- a/drivers/net/wireless/realtek/rtw89/core.h +++ b/drivers/net/wireless/realtek/rtw89/core.h @@ -958,6 +958,9 @@ struct rtw89_port_reg { u32 mbssid; u32 mbssid_drop; u32 tsf_sync; + u32 ptcl_dbg; + u32 ptcl_dbg_info; + u32 bcn_drop_all; u32 hiq_win[RTW89_PORT_NUM]; }; diff --git a/drivers/net/wireless/realtek/rtw89/mac.c b/drivers/net/wireless/realtek/rtw89/mac.c index 8a1d3e6e81a9..9e9a05cc49de 100644 --- a/drivers/net/wireless/realtek/rtw89/mac.c +++ b/drivers/net/wireless/realtek/rtw89/mac.c @@ -4037,6 +4037,9 @@ static const struct rtw89_port_reg rtw89_port_base_ax = { .mbssid = R_AX_MBSSID_CTRL, .mbssid_drop = R_AX_MBSSID_DROP_0, .tsf_sync = R_AX_PORT0_TSF_SYNC, + .ptcl_dbg = R_AX_PTCL_DBG, + .ptcl_dbg_info = R_AX_PTCL_DBG_INFO, + .bcn_drop_all = R_AX_BCN_DROP_ALL0, .hiq_win = {R_AX_P0MB_HGQ_WINDOW_CFG_0, R_AX_PORT_HGQ_WINDOW_CFG, R_AX_PORT_HGQ_WINDOW_CFG + 1, R_AX_PORT_HGQ_WINDOW_CFG + 2, R_AX_PORT_HGQ_WINDOW_CFG + 3}, @@ -4045,13 +4048,15 @@ static const struct rtw89_port_reg rtw89_port_base_ax = { static void rtw89_mac_check_packet_ctrl(struct rtw89_dev *rtwdev, struct rtw89_vif *rtwvif, u8 type) { + const struct rtw89_mac_gen_def *mac = rtwdev->chip->mac_def; + const struct rtw89_port_reg *p = mac->port_base; u8 mask = B_AX_PTCL_DBG_INFO_MASK_BY_PORT(rtwvif->port); u32 reg_info, reg_ctrl; u32 val; int ret; - reg_info = rtw89_mac_reg_by_idx(rtwdev, R_AX_PTCL_DBG_INFO, rtwvif->mac_idx); - reg_ctrl = rtw89_mac_reg_by_idx(rtwdev, R_AX_PTCL_DBG, rtwvif->mac_idx); + reg_info = rtw89_mac_reg_by_idx(rtwdev, p->ptcl_dbg_info, rtwvif->mac_idx); + reg_ctrl = rtw89_mac_reg_by_idx(rtwdev, p->ptcl_dbg, rtwvif->mac_idx); rtw89_write32_mask(rtwdev, reg_ctrl, B_AX_PTCL_DBG_SEL_MASK, type); rtw89_write32_set(rtwdev, reg_ctrl, B_AX_PTCL_DBG_EN); @@ -4068,7 +4073,7 @@ static void rtw89_mac_bcn_drop(struct rtw89_dev *rtwdev, struct rtw89_vif *rtwvi const struct rtw89_mac_gen_def *mac = rtwdev->chip->mac_def; const struct rtw89_port_reg *p = mac->port_base; - rtw89_write32_set(rtwdev, R_AX_BCN_DROP_ALL0, BIT(rtwvif->port)); + rtw89_write32_set(rtwdev, p->bcn_drop_all, BIT(rtwvif->port)); rtw89_write32_port_mask(rtwdev, rtwvif, p->tbtt_prohib, B_AX_TBTT_SETUP_MASK, 1); rtw89_write32_port_mask(rtwdev, rtwvif, p->bcn_area, B_AX_BCN_MSK_AREA_MASK, 0); rtw89_write32_port_mask(rtwdev, rtwvif, p->tbtt_prohib, B_AX_TBTT_HOLD_MASK, 0); @@ -4081,7 +4086,7 @@ static void rtw89_mac_bcn_drop(struct rtw89_dev *rtwdev, struct rtw89_vif *rtwvi if (rtwvif->port == RTW89_PORT_0) rtw89_mac_check_packet_ctrl(rtwdev, rtwvif, AX_PTCL_DBG_BCNQ_NUM1); - rtw89_write32_clr(rtwdev, R_AX_BCN_DROP_ALL0, BIT(rtwvif->port)); + rtw89_write32_clr(rtwdev, p->bcn_drop_all, BIT(rtwvif->port)); rtw89_write32_port_clr(rtwdev, rtwvif, p->port_cfg, B_AX_TBTT_PROHIB_EN); fsleep(2000); } diff --git a/drivers/net/wireless/realtek/rtw89/mac_be.c b/drivers/net/wireless/realtek/rtw89/mac_be.c index 6388c56a3c90..6447353d35d3 100644 --- a/drivers/net/wireless/realtek/rtw89/mac_be.c +++ b/drivers/net/wireless/realtek/rtw89/mac_be.c @@ -52,6 +52,9 @@ static const struct rtw89_port_reg rtw89_port_base_be = { .mbssid = R_BE_MBSSID_CTRL, .mbssid_drop = R_BE_MBSSID_DROP_0, .tsf_sync = R_BE_PORT_0_TSF_SYNC, + .ptcl_dbg = R_BE_PTCL_DBG, + .ptcl_dbg_info = R_BE_PTCL_DBG_INFO, + .bcn_drop_all = R_BE_BCN_DROP_ALL0, .hiq_win = {R_BE_P0MB_HGQ_WINDOW_CFG_0, R_BE_PORT_HGQ_WINDOW_CFG, R_BE_PORT_HGQ_WINDOW_CFG + 1, R_BE_PORT_HGQ_WINDOW_CFG + 2, R_BE_PORT_HGQ_WINDOW_CFG + 3}, diff --git a/drivers/net/wireless/realtek/rtw89/reg.h b/drivers/net/wireless/realtek/rtw89/reg.h index 26aa2d9bd526..23a09efabab7 100644 --- a/drivers/net/wireless/realtek/rtw89/reg.h +++ b/drivers/net/wireless/realtek/rtw89/reg.h @@ -6347,6 +6347,8 @@ #define R_BE_TSFTR_HIGH_P0_C1 0x1443C #define B_BE_TSFTR_HIGH_P0_MASK GENMASK(31, 0) +#define R_BE_BCN_DROP_ALL0 0x10560 + #define R_BE_MBSSID_CTRL 0x10568 #define R_BE_MBSSID_CTRL_C1 0x14568 #define B_BE_MBSSID_MODE_SEL BIT(20) @@ -6533,6 +6535,10 @@ #define B_BE_PTCL_DROP BIT(5) #define B_BE_PTCL_TX_QUEUE_IDX_MASK GENMASK(4, 0) +#define R_BE_PTCL_DBG_INFO 0x108F0 + +#define R_BE_PTCL_DBG 0x108F4 + #define R_BE_RX_ERROR_FLAG 0x10C00 #define R_BE_RX_ERROR_FLAG_C1 0x14C00 #define B_BE_RX_CSI_NOT_RELEASE_ERROR BIT(31) -- cgit v1.2.3 From 5f9c264f8e0904729edb861eafbec081299237eb Mon Sep 17 00:00:00 2001 From: Po-Hao Huang Date: Fri, 9 Feb 2024 14:52:28 +0800 Subject: wifi: rtw89: reference quota mode when setting Tx power Reference the current quota mode to avoid misleading warnings. This patch is required after supporting DBCC quota mode. Signed-off-by: Po-Hao Huang Signed-off-by: Ping-Ke Shih Signed-off-by: Kalle Valo Link: https://msgid.link/20240209065229.34515-11-pkshih@realtek.com --- drivers/net/wireless/realtek/rtw89/mac.c | 3 +-- drivers/net/wireless/realtek/rtw89/mac_be.c | 3 +-- 2 files changed, 2 insertions(+), 4 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/realtek/rtw89/mac.c b/drivers/net/wireless/realtek/rtw89/mac.c index 9e9a05cc49de..296576a634e7 100644 --- a/drivers/net/wireless/realtek/rtw89/mac.c +++ b/drivers/net/wireless/realtek/rtw89/mac.c @@ -5221,8 +5221,7 @@ bool rtw89_mac_get_txpwr_cr_ax(struct rtw89_dev *rtwdev, enum rtw89_phy_idx phy_idx, u32 reg_base, u32 *cr) { - const struct rtw89_dle_mem *dle_mem = rtwdev->chip->dle_mem; - enum rtw89_qta_mode mode = dle_mem->mode; + enum rtw89_qta_mode mode = rtwdev->mac.qta_mode; u32 addr = rtw89_mac_reg_by_idx(rtwdev, reg_base, phy_idx); if (addr < R_AX_PWR_RATE_CTRL || addr > CMAC1_END_ADDR_AX) { diff --git a/drivers/net/wireless/realtek/rtw89/mac_be.c b/drivers/net/wireless/realtek/rtw89/mac_be.c index 6447353d35d3..320e88229971 100644 --- a/drivers/net/wireless/realtek/rtw89/mac_be.c +++ b/drivers/net/wireless/realtek/rtw89/mac_be.c @@ -1896,8 +1896,7 @@ static bool rtw89_mac_get_txpwr_cr_be(struct rtw89_dev *rtwdev, enum rtw89_phy_idx phy_idx, u32 reg_base, u32 *cr) { - const struct rtw89_dle_mem *dle_mem = rtwdev->chip->dle_mem; - enum rtw89_qta_mode mode = dle_mem->mode; + enum rtw89_qta_mode mode = rtwdev->mac.qta_mode; int ret; ret = rtw89_mac_check_mac_en(rtwdev, (enum rtw89_mac_idx)phy_idx, -- cgit v1.2.3 From 4ae8ac201ddb1665ad3ef96d583f73ad51415ab7 Mon Sep 17 00:00:00 2001 From: Ping-Ke Shih Date: Fri, 9 Feb 2024 14:52:29 +0800 Subject: wifi: rtw89: change qutoa to DBCC by default for WiFi 7 chips Since WiFi 7 is expected to support MLO, so we should enable MAC-0/1 and PHY-0/1. By default, set dbcc_en=true, change quota to DBCC mode, and set MLO mode to 2 + 0 that means we only use 2x2 connection on MAC/PHY-0 for now. Signed-off-by: Ping-Ke Shih Signed-off-by: Kalle Valo Link: https://msgid.link/20240209065229.34515-12-pkshih@realtek.com --- drivers/net/wireless/realtek/rtw89/core.c | 8 +++++++- drivers/net/wireless/realtek/rtw89/core.h | 1 + drivers/net/wireless/realtek/rtw89/mac.c | 8 ++++---- drivers/net/wireless/realtek/rtw89/rtw8922a.c | 7 +++++++ 4 files changed, 19 insertions(+), 5 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/realtek/rtw89/core.c b/drivers/net/wireless/realtek/rtw89/core.c index 6441d99cd6c0..f697e3d898e6 100644 --- a/drivers/net/wireless/realtek/rtw89/core.c +++ b/drivers/net/wireless/realtek/rtw89/core.c @@ -4075,7 +4075,6 @@ int rtw89_core_start(struct rtw89_dev *rtwdev) { int ret; - rtwdev->mac.qta_mode = RTW89_QTA_SCC; ret = rtw89_mac_init(rtwdev); if (ret) { rtw89_err(rtwdev, "mac init fail, ret:%d\n", ret); @@ -4213,6 +4212,13 @@ int rtw89_core_init(struct rtw89_dev *rtwdev) rtwdev->hal.rx_fltr = DEFAULT_AX_RX_FLTR; rtwdev->dbcc_en = false; rtwdev->mlo_dbcc_mode = MLO_DBCC_NOT_SUPPORT; + rtwdev->mac.qta_mode = RTW89_QTA_SCC; + + if (rtwdev->chip->chip_gen == RTW89_CHIP_BE) { + rtwdev->dbcc_en = true; + rtwdev->mac.qta_mode = RTW89_QTA_DBCC; + rtwdev->mlo_dbcc_mode = MLO_2_PLUS_0_1RF; + } INIT_WORK(&btc->eapol_notify_work, rtw89_btc_ntfy_eapol_packet_work); INIT_WORK(&btc->arp_notify_work, rtw89_btc_ntfy_arp_packet_work); diff --git a/drivers/net/wireless/realtek/rtw89/core.h b/drivers/net/wireless/realtek/rtw89/core.h index 0e451245a65a..e3913efedc28 100644 --- a/drivers/net/wireless/realtek/rtw89/core.h +++ b/drivers/net/wireless/realtek/rtw89/core.h @@ -3306,6 +3306,7 @@ struct rtw89_scan_option { enum rtw89_qta_mode { RTW89_QTA_SCC, + RTW89_QTA_DBCC, RTW89_QTA_DLFW, RTW89_QTA_WOW, diff --git a/drivers/net/wireless/realtek/rtw89/mac.c b/drivers/net/wireless/realtek/rtw89/mac.c index 296576a634e7..3ea50d49e12f 100644 --- a/drivers/net/wireless/realtek/rtw89/mac.c +++ b/drivers/net/wireless/realtek/rtw89/mac.c @@ -1625,7 +1625,7 @@ const struct rtw89_mac_size_set rtw89_mac_size = { .wde_size19 = {RTW89_WDE_PG_64, 3328, 0,}, /* PCIE */ .ple_size0 = {RTW89_PLE_PG_128, 1520, 16,}, - .ple_size0_v1 = {RTW89_PLE_PG_128, 2672, 256, 212992,}, + .ple_size0_v1 = {RTW89_PLE_PG_128, 2688, 240, 212992,}, .ple_size3_v1 = {RTW89_PLE_PG_128, 2928, 0, 212992,}, /* DLFW */ .ple_size4 = {RTW89_PLE_PG_128, 64, 1472,}, @@ -1650,8 +1650,8 @@ const struct rtw89_mac_size_set rtw89_mac_size = { .wde_qt17 = {0, 0, 0, 0,}, /* 8852C PCIE SCC */ .wde_qt18 = {3228, 60, 0, 40,}, - .ple_qt0 = {320, 0, 32, 16, 13, 13, 292, 0, 32, 18, 1, 4, 0,}, - .ple_qt1 = {320, 0, 32, 16, 1944, 1944, 2223, 0, 1963, 1949, 1, 1935, 0,}, + .ple_qt0 = {320, 320, 32, 16, 13, 13, 292, 292, 64, 18, 1, 4, 0,}, + .ple_qt1 = {320, 320, 32, 16, 1316, 1316, 1595, 1595, 1367, 1321, 1, 1307, 0,}, /* PCIE SCC */ .ple_qt4 = {264, 0, 16, 20, 26, 13, 356, 0, 32, 40, 8,}, /* PCIE SCC */ @@ -1677,7 +1677,7 @@ const struct rtw89_mac_size_set rtw89_mac_size = { .ple_qt_52b_wow = {147, 0, 16, 20, 157, 13, 133, 0, 172, 14, 24, 0,}, /* 8851B PCIE WOW */ .ple_qt_51b_wow = {147, 0, 16, 20, 157, 13, 133, 0, 172, 14, 24, 0,}, - .ple_rsvd_qt0 = {2, 112, 56, 6, 6, 6, 6, 0, 0, 62,}, + .ple_rsvd_qt0 = {2, 107, 107, 6, 6, 6, 6, 0, 0, 0,}, .ple_rsvd_qt1 = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0,}, .rsvd0_size0 = {212992, 0,}, .rsvd1_size0 = {587776, 2048,}, diff --git a/drivers/net/wireless/realtek/rtw89/rtw8922a.c b/drivers/net/wireless/realtek/rtw89/rtw8922a.c index f7b81daa0b03..a4b7d2e79638 100644 --- a/drivers/net/wireless/realtek/rtw89/rtw8922a.c +++ b/drivers/net/wireless/realtek/rtw89/rtw8922a.c @@ -47,6 +47,8 @@ static const struct rtw89_hfc_pub_cfg rtw8922a_hfc_pubcfg_pcie = { static const struct rtw89_hfc_param_ini rtw8922a_hfc_param_ini_pcie[] = { [RTW89_QTA_SCC] = {rtw8922a_hfc_chcfg_pcie, &rtw8922a_hfc_pubcfg_pcie, &rtw89_mac_size.hfc_prec_cfg_c0, RTW89_HCIFC_POH}, + [RTW89_QTA_DBCC] = {rtw8922a_hfc_chcfg_pcie, &rtw8922a_hfc_pubcfg_pcie, + &rtw89_mac_size.hfc_prec_cfg_c0, RTW89_HCIFC_POH}, [RTW89_QTA_DLFW] = {NULL, NULL, &rtw89_mac_size.hfc_prec_cfg_c2, RTW89_HCIFC_POH}, [RTW89_QTA_INVALID] = {NULL}, @@ -58,6 +60,11 @@ static const struct rtw89_dle_mem rtw8922a_dle_mem_pcie[] = { &rtw89_mac_size.wde_qt0_v1, &rtw89_mac_size.ple_qt0, &rtw89_mac_size.ple_qt1, &rtw89_mac_size.ple_rsvd_qt0, &rtw89_mac_size.rsvd0_size0, &rtw89_mac_size.rsvd1_size0}, + [RTW89_QTA_DBCC] = {RTW89_QTA_DBCC, &rtw89_mac_size.wde_size0_v1, + &rtw89_mac_size.ple_size0_v1, &rtw89_mac_size.wde_qt0_v1, + &rtw89_mac_size.wde_qt0_v1, &rtw89_mac_size.ple_qt0, + &rtw89_mac_size.ple_qt1, &rtw89_mac_size.ple_rsvd_qt0, + &rtw89_mac_size.rsvd0_size0, &rtw89_mac_size.rsvd1_size0}, [RTW89_QTA_DLFW] = {RTW89_QTA_DLFW, &rtw89_mac_size.wde_size4_v1, &rtw89_mac_size.ple_size3_v1, &rtw89_mac_size.wde_qt4, &rtw89_mac_size.wde_qt4, &rtw89_mac_size.ple_qt9, -- cgit v1.2.3 From 6f656131f6988709e3bf828c3ad992032b717c2e Mon Sep 17 00:00:00 2001 From: Lorenzo Bianconi Date: Thu, 8 Feb 2024 12:01:43 +0100 Subject: wifi: mac80211: remove gfp parameter from ieee80211_obss_color_collision_notify Get rid of gfp parameter from ieee80211_obss_color_collision_notify since it is no longer used. Signed-off-by: Lorenzo Bianconi Reviewed-by: Jeff Johnson Acked-by: Jeff Johnson Link: https://msgid.link/f91e1c78896408ac556586ba8c99e4e389aeba02.1707389901.git.lorenzo@kernel.org Signed-off-by: Johannes Berg --- drivers/net/wireless/ath/ath11k/wmi.c | 3 +-- include/net/mac80211.h | 3 +-- net/mac80211/cfg.c | 2 +- net/mac80211/rx.c | 3 +-- 4 files changed, 4 insertions(+), 7 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/ath/ath11k/wmi.c b/drivers/net/wireless/ath/ath11k/wmi.c index 3c9f3b0bcfaa..1943e636faef 100644 --- a/drivers/net/wireless/ath/ath11k/wmi.c +++ b/drivers/net/wireless/ath/ath11k/wmi.c @@ -4020,8 +4020,7 @@ ath11k_wmi_obss_color_collision_event(struct ath11k_base *ab, struct sk_buff *sk switch (ev->evt_type) { case WMI_BSS_COLOR_COLLISION_DETECTION: - ieee80211_obss_color_collision_notify(arvif->vif, ev->obss_color_bitmap, - GFP_KERNEL); + ieee80211_obss_color_collision_notify(arvif->vif, ev->obss_color_bitmap); ath11k_dbg(ab, ATH11K_DBG_WMI, "OBSS color collision detected vdev:%d, event:%d, bitmap:%08llx\n", ev->vdev_id, ev->evt_type, ev->obss_color_bitmap); diff --git a/include/net/mac80211.h b/include/net/mac80211.h index 45d905b17a65..fc223761e3af 100644 --- a/include/net/mac80211.h +++ b/include/net/mac80211.h @@ -7490,11 +7490,10 @@ ieee80211_get_unsol_bcast_probe_resp_tmpl(struct ieee80211_hw *hw, * @vif: &struct ieee80211_vif pointer from the add_interface callback. * @color_bitmap: a 64 bit bitmap representing the colors that the local BSS is * aware of. - * @gfp: allocation flags */ void ieee80211_obss_color_collision_notify(struct ieee80211_vif *vif, - u64 color_bitmap, gfp_t gfp); + u64 color_bitmap); /** * ieee80211_is_tx_data - check if frame is a data frame diff --git a/net/mac80211/cfg.c b/net/mac80211/cfg.c index 156a4215dcda..6f7c96c358f4 100644 --- a/net/mac80211/cfg.c +++ b/net/mac80211/cfg.c @@ -4765,7 +4765,7 @@ EXPORT_SYMBOL_GPL(ieee80211_color_change_finish); void ieee80211_obss_color_collision_notify(struct ieee80211_vif *vif, - u64 color_bitmap, gfp_t gfp) + u64 color_bitmap) { struct ieee80211_sub_if_data *sdata = vif_to_sdata(vif); struct ieee80211_link_data *link = &sdata->deflink; diff --git a/net/mac80211/rx.c b/net/mac80211/rx.c index 9902ea69af0a..c1f850138405 100644 --- a/net/mac80211/rx.c +++ b/net/mac80211/rx.c @@ -3386,8 +3386,7 @@ ieee80211_rx_check_bss_color_collision(struct ieee80211_rx_data *rx) IEEE80211_HE_OPERATION_BSS_COLOR_MASK); if (color == bss_conf->he_bss_color.color) ieee80211_obss_color_collision_notify(&rx->sdata->vif, - BIT_ULL(color), - GFP_ATOMIC); + BIT_ULL(color)); } } -- cgit v1.2.3 From 675516f55db27b351334c9027407e40b1e72818b Mon Sep 17 00:00:00 2001 From: Andrei Otcheretianski Date: Tue, 6 Feb 2024 16:54:04 +0200 Subject: wifi: mac80211_hwsim: Add 160MHz bw range to regdom_custom_04 This allows testing 160MHz channels with DFS concurrent. While at it, remove the TODO for adding a module param to enable NL80211_EXT_FEATURE_DFS_CONCURRENT. This is not really needed as mac80211_hwsim still needs to be loaded with custom regdom. Signed-off-by: Andrei Otcheretianski Signed-off-by: Miri Korenblit Link: https://msgid.link/20240206164849.1b9955e511f0.I5e5315e3a047db3677bfb5ead003a3a4f7d29b13@changeid Signed-off-by: Johannes Berg --- drivers/net/wireless/virtual/mac80211_hwsim.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/virtual/mac80211_hwsim.c b/drivers/net/wireless/virtual/mac80211_hwsim.c index c337afd8bee2..0554946ed30e 100644 --- a/drivers/net/wireless/virtual/mac80211_hwsim.c +++ b/drivers/net/wireless/virtual/mac80211_hwsim.c @@ -196,8 +196,11 @@ static const struct ieee80211_regdomain hwsim_world_regdom_custom_04 = { .reg_rules = { REG_RULE(2412 - 10, 2462 + 10, 40, 0, 20, 0), REG_RULE(2484 - 10, 2484 + 10, 40, 0, 20, 0), - REG_RULE(5150 - 10, 5240 + 10, 80, 0, 30, 0), + REG_RULE(5150 - 10, 5240 + 10, 80, 0, 30, NL80211_RRF_AUTO_BW), REG_RULE(5260 - 10, 5320 + 10, 80, 0, 30, + NL80211_RRF_DFS_CONCURRENT | NL80211_RRF_DFS | + NL80211_RRF_AUTO_BW), + REG_RULE(5500 - 10, 5720 + 10, 160, 0, 30, NL80211_RRF_DFS_CONCURRENT | NL80211_RRF_DFS), REG_RULE(5745 - 10, 5825 + 10, 80, 0, 30, 0), REG_RULE(5855 - 10, 5925 + 10, 80, 0, 33, 0), @@ -5390,7 +5393,6 @@ static int mac80211_hwsim_new_radio(struct genl_info *info, schedule_timeout_interruptible(1); } - /* TODO: Add param */ wiphy_ext_feature_set(hw->wiphy, NL80211_EXT_FEATURE_DFS_CONCURRENT); -- cgit v1.2.3 From 24e5252c590dd8fd9ed702e0fbe426eda78641cd Mon Sep 17 00:00:00 2001 From: Shaul Triebitz Date: Tue, 6 Feb 2024 18:02:12 +0200 Subject: wifi: iwlwifi: iwlmvm: handle unprotected deauth/disassoc in d3 In MFP, do not disconnect if an unprotected deauth or disassoc was received during D3. For that, need to configure wowlan with MFP (IS_11W_ASSOC). Now, in case of an unprotected deauth/disassoc, the wakeup reason returned by the firmware will be: IWL_WAKEUP_BY_11W_UNPROTECTED_DEAUTH_OR_DISASSOC (and not IWL_WOWLAN_WAKEUP_BY_DISCONNECTION_ON_DEAUTH which will cause a disconnection). Also, report this reason to cfg80211. In another patch, the driver will send an SA query. Signed-off-by: Shaul Triebitz Signed-off-by: Miri Korenblit Link: https://msgid.link/20240206175739.fde438a22e3f.I3c8497520aaa95a22febff727b0ad08146965d47@changeid Signed-off-by: Johannes Berg --- drivers/net/wireless/intel/iwlwifi/mvm/d3.c | 6 ++++++ 1 file changed, 6 insertions(+) (limited to 'drivers/net') diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/d3.c b/drivers/net/wireless/intel/iwlwifi/mvm/d3.c index e1c77276557d..26c01d740d0d 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/d3.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/d3.c @@ -925,6 +925,9 @@ iwl_mvm_get_wowlan_config(struct iwl_mvm *mvm, wowlan_config_cmd->flags = ENABLE_L3_FILTERING | ENABLE_NBNS_FILTERING | ENABLE_DHCP_FILTERING; + if (ap_sta->mfp) + wowlan_config_cmd->flags |= IS_11W_ASSOC; + if (iwl_fw_lookup_cmd_ver(mvm->fw, WOWLAN_CONFIGURATION, 0) < 6) { /* Query the last used seqno and set it */ int ret = iwl_mvm_get_last_nonqos_seq(mvm, vif); @@ -1511,6 +1514,9 @@ static void iwl_mvm_report_wakeup_reasons(struct iwl_mvm *mvm, if (reasons & IWL_WOWLAN_WAKEUP_BY_REM_WAKE_WAKEUP_PACKET) wakeup.tcp_match = true; + if (reasons & IWL_WAKEUP_BY_11W_UNPROTECTED_DEAUTH_OR_DISASSOC) + wakeup.unprot_deauth_disassoc = true; + if (status->wake_packet) { int pktsize = status->wake_packet_bufsize; int pktlen = status->wake_packet_length; -- cgit v1.2.3 From 0d2fc8821a7d667180ce27732697105db843a1b9 Mon Sep 17 00:00:00 2001 From: Mukesh Sisodiya Date: Thu, 8 Feb 2024 18:58:35 +0200 Subject: wifi: iwlwifi: nvm: parse the VLP/AFC bit from regulatory 6 GHz STA supports different power types as LPI, SP, VLP. and this information is provided by regulatory info. Add support in driver to parse the power type capability in regulatory info from FW and set it to the channel flags. Signed-off-by: Mukesh Sisodiya Reviewed-by: Gregory Greenman Signed-off-by: Miri Korenblit Link: https://msgid.link/20240208185302.9c6a4acabdb3.I501de5c0d86b9702bf61158a2e91c954a1da9a2a@changeid Signed-off-by: Johannes Berg --- drivers/net/wireless/intel/iwlwifi/iwl-nvm-parse.c | 33 ++++++++++++++++++---- drivers/net/wireless/intel/iwlwifi/iwl-nvm-parse.h | 2 +- drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c | 3 +- 3 files changed, 31 insertions(+), 7 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/intel/iwlwifi/iwl-nvm-parse.c b/drivers/net/wireless/intel/iwlwifi/iwl-nvm-parse.c index d2f133255ee6..baa39a18087a 100644 --- a/drivers/net/wireless/intel/iwlwifi/iwl-nvm-parse.c +++ b/drivers/net/wireless/intel/iwlwifi/iwl-nvm-parse.c @@ -156,6 +156,8 @@ static struct ieee80211_rate iwl_cfg80211_rates[] = { * @NVM_CHANNEL_80MHZ: 80 MHz channel okay * @NVM_CHANNEL_160MHZ: 160 MHz channel okay * @NVM_CHANNEL_DC_HIGH: DC HIGH required/allowed (?) + * @NVM_CHANNEL_VLP: client support connection to UHB VLP AP + * @NVM_CHANNEL_AFC: client support connection to UHB AFC AP */ enum iwl_nvm_channel_flags { NVM_CHANNEL_VALID = BIT(0), @@ -170,6 +172,8 @@ enum iwl_nvm_channel_flags { NVM_CHANNEL_80MHZ = BIT(10), NVM_CHANNEL_160MHZ = BIT(11), NVM_CHANNEL_DC_HIGH = BIT(12), + NVM_CHANNEL_VLP = BIT(13), + NVM_CHANNEL_AFC = BIT(14), }; /** @@ -309,7 +313,7 @@ static inline void iwl_nvm_print_channel_flags(struct device *dev, u32 level, /* Note: already can print up to 101 characters, 110 is the limit! */ IWL_DEBUG_DEV(dev, level, - "Ch. %d: 0x%x:%s%s%s%s%s%s%s%s%s%s%s%s\n", + "Ch. %d: 0x%x:%s%s%s%s%s%s%s%s%s%s%s%s%s%s\n", chan, flags, CHECK_AND_PRINT_I(VALID), CHECK_AND_PRINT_I(IBSS), @@ -322,7 +326,9 @@ static inline void iwl_nvm_print_channel_flags(struct device *dev, u32 level, CHECK_AND_PRINT_I(40MHZ), CHECK_AND_PRINT_I(80MHZ), CHECK_AND_PRINT_I(160MHZ), - CHECK_AND_PRINT_I(DC_HIGH)); + CHECK_AND_PRINT_I(DC_HIGH), + CHECK_AND_PRINT_I(VLP), + CHECK_AND_PRINT_I(AFC)); #undef CHECK_AND_PRINT_I } @@ -366,6 +372,12 @@ static u32 iwl_get_channel_flags(u8 ch_num, int ch_idx, enum nl80211_band band, (flags & IEEE80211_CHAN_NO_IR)) flags |= IEEE80211_CHAN_IR_CONCURRENT; + /* Set the AP type for the UHB case. */ + if (!(nvm_flags & NVM_CHANNEL_VLP)) + flags |= IEEE80211_CHAN_NO_6GHZ_VLP_CLIENT; + if (!(nvm_flags & NVM_CHANNEL_AFC)) + flags |= IEEE80211_CHAN_NO_6GHZ_AFC_CLIENT; + return flags; } @@ -1600,7 +1612,8 @@ IWL_EXPORT_SYMBOL(iwl_parse_nvm_data); static u32 iwl_nvm_get_regdom_bw_flags(const u16 *nvm_chan, int ch_idx, u16 nvm_flags, struct iwl_reg_capa reg_capa, - const struct iwl_cfg *cfg) + const struct iwl_cfg *cfg, + bool uats_enabled) { u32 flags = NL80211_RRF_NO_HT40; @@ -1645,6 +1658,16 @@ static u32 iwl_nvm_get_regdom_bw_flags(const u16 *nvm_chan, flags &= ~NL80211_RRF_NO_IR; } } + + /* Set the AP type for the UHB case. */ + if (uats_enabled) { + if (!(nvm_flags & NVM_CHANNEL_VLP)) + flags |= NL80211_RRF_NO_6GHZ_VLP_CLIENT; + + if (!(nvm_flags & NVM_CHANNEL_AFC)) + flags |= NL80211_RRF_NO_6GHZ_AFC_CLIENT; + } + /* * reg_capa is per regulatory domain so apply it for every channel */ @@ -1699,7 +1722,7 @@ static struct iwl_reg_capa iwl_get_reg_capa(u32 flags, u8 resp_ver) struct ieee80211_regdomain * iwl_parse_nvm_mcc_info(struct device *dev, const struct iwl_cfg *cfg, int num_of_ch, __le32 *channels, u16 fw_mcc, - u16 geo_info, u32 cap, u8 resp_ver) + u16 geo_info, u32 cap, u8 resp_ver, bool uats_enabled) { int ch_idx; u16 ch_flags; @@ -1765,7 +1788,7 @@ iwl_parse_nvm_mcc_info(struct device *dev, const struct iwl_cfg *cfg, reg_rule_flags = iwl_nvm_get_regdom_bw_flags(nvm_chan, ch_idx, ch_flags, reg_capa, - cfg); + cfg, uats_enabled); /* we can't continue the same rule */ if (ch_idx == 0 || prev_reg_rule_flags != reg_rule_flags || diff --git a/drivers/net/wireless/intel/iwlwifi/iwl-nvm-parse.h b/drivers/net/wireless/intel/iwlwifi/iwl-nvm-parse.h index 651ed25b683b..fd9c3bed9407 100644 --- a/drivers/net/wireless/intel/iwlwifi/iwl-nvm-parse.h +++ b/drivers/net/wireless/intel/iwlwifi/iwl-nvm-parse.h @@ -50,7 +50,7 @@ iwl_parse_nvm_data(struct iwl_trans *trans, const struct iwl_cfg *cfg, struct ieee80211_regdomain * iwl_parse_nvm_mcc_info(struct device *dev, const struct iwl_cfg *cfg, int num_of_ch, __le32 *channels, u16 fw_mcc, - u16 geo_info, u32 cap, u8 resp_ver); + u16 geo_info, u32 cap, u8 resp_ver, bool uats_enabled); /** * struct iwl_nvm_section - describes an NVM section in memory. diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c b/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c index 576b90da94ff..8503c5b6c756 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c @@ -138,7 +138,8 @@ struct ieee80211_regdomain *iwl_mvm_get_regdomain(struct wiphy *wiphy, resp->channels, __le16_to_cpu(resp->mcc), __le16_to_cpu(resp->geo_info), - le32_to_cpu(resp->cap), resp_ver); + le32_to_cpu(resp->cap), resp_ver, + mvm->fwrt.uats_enabled); /* Store the return source id */ src_id = resp->source_id; if (IS_ERR_OR_NULL(regd)) { -- cgit v1.2.3 From 07da4a1b2a59d1392fc61ed12692602b89c33e8a Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Thu, 8 Feb 2024 18:58:36 +0200 Subject: wifi: iwlwifi: mvm: work around A-MSDU size problem The firmware will now start with 1500 byte A-MSDU size rather than 3500 as before, and that seems to cause some really hard to debug problems. Keep A-MSDU disabled if the size is less than 2000 to disable this for now. Signed-off-by: Johannes Berg Signed-off-by: Miri Korenblit Link: https://msgid.link/20240208185302.3dcd0a1767d0.I450d35f3085b3b04a96dd1e1e7d8c27bda9ce8f5@changeid Signed-off-by: Johannes Berg --- drivers/net/wireless/intel/iwlwifi/mvm/rs-fw.c | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/rs-fw.c b/drivers/net/wireless/intel/iwlwifi/mvm/rs-fw.c index 71d92635d6d7..00860feefa7a 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/rs-fw.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/rs-fw.c @@ -1,7 +1,7 @@ // SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause /* * Copyright (C) 2017 Intel Deutschland GmbH - * Copyright (C) 2018-2023 Intel Corporation + * Copyright (C) 2018-2024 Intel Corporation */ #include "rs.h" #include "fw-api.h" @@ -479,9 +479,15 @@ void iwl_mvm_tlc_update_notif(struct iwl_mvm *mvm, } if (flags & IWL_TLC_NOTIF_FLAG_AMSDU && !mvm_link_sta->orig_amsdu_len) { + u32 enabled = le32_to_cpu(notif->amsdu_enabled); u16 size = le32_to_cpu(notif->amsdu_size); int i; + if (size < 2000) { + size = 0; + enabled = 0; + } + if (link_sta->agg.max_amsdu_len < size) { /* * In debug link_sta->agg.max_amsdu_len < size @@ -492,7 +498,7 @@ void iwl_mvm_tlc_update_notif(struct iwl_mvm *mvm, goto out; } - mvmsta->amsdu_enabled = le32_to_cpu(notif->amsdu_enabled); + mvmsta->amsdu_enabled = enabled; mvmsta->max_amsdu_len = size; link_sta->agg.max_rc_amsdu_len = mvmsta->max_amsdu_len; -- cgit v1.2.3 From 59214747f26a6c1b3616ef75f9eec7543ddba8e4 Mon Sep 17 00:00:00 2001 From: Ilan Peer Date: Thu, 8 Feb 2024 18:58:37 +0200 Subject: wifi: iwlwifi: mvm: Extend support for P2P service discovery New additions to the P2P specification use action frames to extend the P2P device discovery and service discovery. Thus, configure the P2P Device link to accept all management frames. Signed-off-by: Ilan Peer Signed-off-by: Miri Korenblit Link: https://msgid.link/20240208185302.7ae41234de7b.Ie0b08d4b965409ef6df5505396927567fb899d52@changeid Signed-off-by: Johannes Berg --- drivers/net/wireless/intel/iwlwifi/mvm/mld-mac.c | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/mld-mac.c b/drivers/net/wireless/intel/iwlwifi/mvm/mld-mac.c index f313a8d771e4..4dc692c2c449 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/mld-mac.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/mld-mac.c @@ -1,6 +1,6 @@ // SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause /* - * Copyright (C) 2022 - 2023 Intel Corporation + * Copyright (C) 2022 - 2024 Intel Corporation */ #include "mvm.h" @@ -205,8 +205,11 @@ static int iwl_mvm_mld_mac_ctxt_cmd_p2p_device(struct iwl_mvm *mvm, cmd.p2p_dev.is_disc_extended = iwl_mac_ctxt_p2p_dev_has_extended_disc(mvm, vif); - /* Override the filter flags to accept only probe requests */ - cmd.filter_flags = cpu_to_le32(MAC_CFG_FILTER_ACCEPT_PROBE_REQ); + /* Override the filter flags to accept all management frames. This is + * needed to support both P2P device discovery using probe requests and + * P2P service discovery using action frames + */ + cmd.filter_flags = cpu_to_le32(MAC_CFG_FILTER_ACCEPT_CONTROL_AND_MGMT); return iwl_mvm_mld_mac_ctxt_send_cmd(mvm, &cmd); } -- cgit v1.2.3 From 4cdb86487e3eaddb4b3a7df30ae709e810aac84b Mon Sep 17 00:00:00 2001 From: Ilan Peer Date: Thu, 8 Feb 2024 18:58:38 +0200 Subject: wifi: iwlwifi: mvm: Fix the listener MAC filter flags One of the flags was from the wrong API. Fixes: 9be162a7b670 ("wifi: iwlwifi: mvm: add support for the new MAC CTXT command") Signed-off-by: Ilan Peer Signed-off-by: Miri Korenblit Link: https://msgid.link/20240208185302.a338c30ec4e9.Ic2813cdeba4443c692d462fc4859392f069d7e33@changeid Signed-off-by: Johannes Berg --- drivers/net/wireless/intel/iwlwifi/mvm/mld-mac.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/mld-mac.c b/drivers/net/wireless/intel/iwlwifi/mvm/mld-mac.c index 4dc692c2c449..bb7851042177 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/mld-mac.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/mld-mac.c @@ -167,7 +167,7 @@ static int iwl_mvm_mld_mac_ctxt_cmd_listener(struct iwl_mvm *mvm, iwl_mvm_mld_mac_ctxt_cmd_common(mvm, vif, &cmd, action); cmd.filter_flags = cpu_to_le32(MAC_CFG_FILTER_PROMISC | - MAC_FILTER_IN_CONTROL_AND_MGMT | + MAC_CFG_FILTER_ACCEPT_CONTROL_AND_MGMT | MAC_CFG_FILTER_ACCEPT_BEACON | MAC_CFG_FILTER_ACCEPT_PROBE_REQ | MAC_CFG_FILTER_ACCEPT_GRP); -- cgit v1.2.3 From 41c5f4707d9d54255f5bfa90d184eac68f06a2f6 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Thu, 8 Feb 2024 18:58:39 +0200 Subject: wifi: iwlwifi: api: fix constant version to match FW The versioning here comes from the firmware, so it should be the same as in the firmware, fix that. Signed-off-by: Johannes Berg Signed-off-by: Miri Korenblit Link: https://msgid.link/20240208185302.fbcb99d896b3.Ibf018d22ca673565cb9028adabd04d4804231ac0@changeid Signed-off-by: Johannes Berg --- drivers/net/wireless/intel/iwlwifi/fw/api/mac.h | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/intel/iwlwifi/fw/api/mac.h b/drivers/net/wireless/intel/iwlwifi/fw/api/mac.h index 55882190251c..545826973a80 100644 --- a/drivers/net/wireless/intel/iwlwifi/fw/api/mac.h +++ b/drivers/net/wireless/intel/iwlwifi/fw/api/mac.h @@ -1,6 +1,6 @@ /* SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause */ /* - * Copyright (C) 2012-2014, 2018-2022 Intel Corporation + * Copyright (C) 2012-2014, 2018-2022, 2024 Intel Corporation * Copyright (C) 2017 Intel Deutschland GmbH */ #ifndef __iwl_fw_api_mac_h__ @@ -431,8 +431,8 @@ enum iwl_he_pkt_ext_constellations { }; #define MAX_HE_SUPP_NSS 2 -#define MAX_CHANNEL_BW_INDX_API_D_VER_2 4 -#define MAX_CHANNEL_BW_INDX_API_D_VER_3 5 +#define MAX_CHANNEL_BW_INDX_API_D_VER_1 4 +#define MAX_CHANNEL_BW_INDX_API_D_VER_2 5 /** * struct iwl_he_pkt_ext_v1 - QAM thresholds @@ -455,7 +455,7 @@ enum iwl_he_pkt_ext_constellations { * (0-low_th, 1-high_th) */ struct iwl_he_pkt_ext_v1 { - u8 pkt_ext_qam_th[MAX_HE_SUPP_NSS][MAX_CHANNEL_BW_INDX_API_D_VER_2][2]; + u8 pkt_ext_qam_th[MAX_HE_SUPP_NSS][MAX_CHANNEL_BW_INDX_API_D_VER_1][2]; } __packed; /* PKT_EXT_DOT11AX_API_S_VER_1 */ /** @@ -480,7 +480,7 @@ struct iwl_he_pkt_ext_v1 { * (0-low_th, 1-high_th) */ struct iwl_he_pkt_ext_v2 { - u8 pkt_ext_qam_th[MAX_HE_SUPP_NSS][MAX_CHANNEL_BW_INDX_API_D_VER_3][2]; + u8 pkt_ext_qam_th[MAX_HE_SUPP_NSS][MAX_CHANNEL_BW_INDX_API_D_VER_2][2]; } __packed; /* PKT_EXT_DOT11AX_API_S_VER_2 */ /** -- cgit v1.2.3 From 8efadbc3882b8f9084869c5da9660d49cd62c060 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Thu, 8 Feb 2024 18:58:40 +0200 Subject: wifi: iwlwifi: don't use TRUE/FALSE with bool With C99 bool we really also should use true/false, not the upper-case variants, wherever they may actually be coming from. Fix that. Signed-off-by: Johannes Berg Signed-off-by: Miri Korenblit Link: https://msgid.link/20240208185302.5732dd306ee9.Ifc07c026ac3779429e3dc949e96c9437e89f7bf9@changeid Signed-off-by: Johannes Berg --- drivers/net/wireless/intel/iwlwifi/iwl-dbg-tlv.c | 10 +++++----- drivers/net/wireless/intel/iwlwifi/mvm/d3.c | 2 +- drivers/net/wireless/intel/iwlwifi/mvm/fw.c | 2 +- drivers/net/wireless/intel/iwlwifi/mvm/ops.c | 2 +- 4 files changed, 8 insertions(+), 8 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/intel/iwlwifi/iwl-dbg-tlv.c b/drivers/net/wireless/intel/iwlwifi/iwl-dbg-tlv.c index 6cfcf1c14eaf..561d0c261123 100644 --- a/drivers/net/wireless/intel/iwlwifi/iwl-dbg-tlv.c +++ b/drivers/net/wireless/intel/iwlwifi/iwl-dbg-tlv.c @@ -1245,7 +1245,7 @@ iwl_dbg_tlv_tp_trigger(struct iwl_fw_runtime *fwrt, bool sync, } } - fwrt->trans->dbg.restart_required = FALSE; + fwrt->trans->dbg.restart_required = false; IWL_DEBUG_FW(fwrt, "WRT: tp %d, reset_fw %d\n", tp, dump_data.trig->reset_fw); IWL_DEBUG_FW(fwrt, @@ -1255,22 +1255,22 @@ iwl_dbg_tlv_tp_trigger(struct iwl_fw_runtime *fwrt, bool sync, if (fwrt->trans->trans_cfg->device_family == IWL_DEVICE_FAMILY_9000) { - fwrt->trans->dbg.restart_required = TRUE; + fwrt->trans->dbg.restart_required = true; } else if (tp == IWL_FW_INI_TIME_POINT_FW_ASSERT && fwrt->trans->dbg.last_tp_resetfw == IWL_FW_INI_RESET_FW_MODE_STOP_FW_ONLY) { - fwrt->trans->dbg.restart_required = FALSE; + fwrt->trans->dbg.restart_required = false; fwrt->trans->dbg.last_tp_resetfw = 0xFF; IWL_DEBUG_FW(fwrt, "WRT: FW_ASSERT due to reset_fw_mode-no restart\n"); } else if (le32_to_cpu(dump_data.trig->reset_fw) == IWL_FW_INI_RESET_FW_MODE_STOP_AND_RELOAD_FW) { IWL_DEBUG_FW(fwrt, "WRT: stop and reload firmware\n"); - fwrt->trans->dbg.restart_required = TRUE; + fwrt->trans->dbg.restart_required = true; } else if (le32_to_cpu(dump_data.trig->reset_fw) == IWL_FW_INI_RESET_FW_MODE_STOP_FW_ONLY) { IWL_DEBUG_FW(fwrt, "WRT: stop only and no reload firmware\n"); - fwrt->trans->dbg.restart_required = FALSE; + fwrt->trans->dbg.restart_required = false; fwrt->trans->dbg.last_tp_resetfw = le32_to_cpu(dump_data.trig->reset_fw); } else if (le32_to_cpu(dump_data.trig->reset_fw) == diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/d3.c b/drivers/net/wireless/intel/iwlwifi/mvm/d3.c index 26c01d740d0d..b6a9896bce25 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/d3.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/d3.c @@ -2997,7 +2997,7 @@ static void iwl_mvm_nd_match_info_handler(struct iwl_mvm *mvm, if (results->matched_profiles) { memcpy(results->matches, notif->matches, matches_len); - d3_data->nd_results_valid = TRUE; + d3_data->nd_results_valid = true; } /* no scan should be active at this point */ diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/fw.c b/drivers/net/wireless/intel/iwlwifi/mvm/fw.c index 5381afdd4021..e1c2b7fc92ab 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/fw.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/fw.c @@ -1323,7 +1323,7 @@ static void iwl_mvm_lari_cfg(struct iwl_mvm *mvm) if (le32_to_cpu(cmd.oem_uhb_allow_bitmap) & IWL_UATS_VLP_AP_SUPPORTED || le32_to_cpu(cmd.oem_uhb_allow_bitmap) & IWL_UATS_AFC_AP_SUPPORTED) - mvm->fwrt.uats_enabled = TRUE; + mvm->fwrt.uats_enabled = true; } void iwl_mvm_get_bios_tables(struct iwl_mvm *mvm) diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/ops.c b/drivers/net/wireless/intel/iwlwifi/mvm/ops.c index 77dce70eccc4..a93981cb9714 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/ops.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/ops.c @@ -1993,7 +1993,7 @@ void iwl_mvm_nic_restart(struct iwl_mvm *mvm, bool fw_error) ieee80211_restart_hw(mvm->hw); } else if (mvm->fwrt.trans->dbg.restart_required) { IWL_DEBUG_INFO(mvm, "FW restart requested after debug collection\n"); - mvm->fwrt.trans->dbg.restart_required = FALSE; + mvm->fwrt.trans->dbg.restart_required = false; ieee80211_restart_hw(mvm->hw); } else if (mvm->trans->trans_cfg->device_family <= IWL_DEVICE_FAMILY_8000) { ieee80211_restart_hw(mvm->hw); -- cgit v1.2.3 From 8cb3a308ceb19f8f74114c618b9e1778be498780 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Thu, 8 Feb 2024 18:58:41 +0200 Subject: wifi: iwlwifi: mvm: fix thermal kernel-doc This was misnamed, fix it. Also add a space to make it look cleaner. Signed-off-by: Johannes Berg Signed-off-by: Miri Korenblit Link: https://msgid.link/20240208185302.5eb9f05fbfe2.Id0a4df70f21e7e6d079a7a2084b748ab499b828c@changeid Signed-off-by: Johannes Berg --- drivers/net/wireless/intel/iwlwifi/mvm/mvm.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h b/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h index 6000c79ce4a5..83263d510a45 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h +++ b/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h @@ -540,8 +540,8 @@ struct iwl_mvm_tt_mgmt { #ifdef CONFIG_THERMAL /** - *struct iwl_mvm_thermal_device - thermal zone related data - * @temp_trips: temperature thresholds for report + * struct iwl_mvm_thermal_device - thermal zone related data + * @trips: temperature thresholds for report * @fw_trips_index: keep indexes to original array - temp_trips * @tzone: thermal zone device data */ -- cgit v1.2.3 From ac71795bfdc988b2dc305fcf91bc6d712c3603be Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Thu, 8 Feb 2024 18:58:42 +0200 Subject: wifi: iwlwifi: error-dump: fix kernel-doc issues Add missing and rename mismatched kernel-doc descriptions. Also just remove the unused IWL_FW_ERROR_DUMP_MAX constant. Signed-off-by: Johannes Berg Reviewed-by: Miriam Rachel Korenblit Signed-off-by: Miri Korenblit Link: https://msgid.link/20240208185302.b4706117c97b.I5151b055dcf23ccab3ea7cd7d654aeb621cd5119@changeid Signed-off-by: Johannes Berg --- drivers/net/wireless/intel/iwlwifi/fw/error-dump.h | 23 ++++++++++++---------- 1 file changed, 13 insertions(+), 10 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/intel/iwlwifi/fw/error-dump.h b/drivers/net/wireless/intel/iwlwifi/fw/error-dump.h index 06d6f7f66430..5c76e3b94968 100644 --- a/drivers/net/wireless/intel/iwlwifi/fw/error-dump.h +++ b/drivers/net/wireless/intel/iwlwifi/fw/error-dump.h @@ -1,6 +1,6 @@ /* SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause */ /* - * Copyright (C) 2014, 2018-2022 Intel Corporation + * Copyright (C) 2014, 2018-2024 Intel Corporation * Copyright (C) 2014-2015 Intel Mobile Communications GmbH * Copyright (C) 2016-2017 Intel Deutschland GmbH */ @@ -16,7 +16,7 @@ /** * enum iwl_fw_error_dump_type - types of data in the dump file * @IWL_FW_ERROR_DUMP_CSR: Control Status Registers - from offset 0 - * @IWL_FW_ERROR_DUMP_RXF: + * @IWL_FW_ERROR_DUMP_RXF: RX FIFO contents * @IWL_FW_ERROR_DUMP_TXCMD: last TX command data, structured as * &struct iwl_fw_error_dump_txcmd packets * @IWL_FW_ERROR_DUMP_DEV_FW_INFO: struct %iwl_fw_error_dump_info @@ -24,21 +24,24 @@ * @IWL_FW_ERROR_DUMP_FW_MONITOR: firmware monitor * @IWL_FW_ERROR_DUMP_PRPH: range of periphery registers - there can be several * sections like this in a single file. + * @IWL_FW_ERROR_DUMP_TXF: TX FIFO contents * @IWL_FW_ERROR_DUMP_FH_REGS: range of FH registers * @IWL_FW_ERROR_DUMP_MEM: chunk of memory * @IWL_FW_ERROR_DUMP_ERROR_INFO: description of what triggered this dump. * Structured as &struct iwl_fw_error_dump_trigger_desc. * @IWL_FW_ERROR_DUMP_RB: the content of an RB structured as * &struct iwl_fw_error_dump_rb - * @IWL_FW_ERROR_PAGING: UMAC's image memory segments which were + * @IWL_FW_ERROR_DUMP_PAGING: UMAC's image memory segments which were * paged to the DRAM. * @IWL_FW_ERROR_DUMP_RADIO_REG: Dump the radio registers. + * @IWL_FW_ERROR_DUMP_INTERNAL_TXF: internal TX FIFO data * @IWL_FW_ERROR_DUMP_EXTERNAL: used only by external code utilities, and * for that reason is not in use in any other place in the Linux Wi-Fi * stack. * @IWL_FW_ERROR_DUMP_MEM_CFG: the addresses and sizes of fifos in the smem, * which we get from the fw after ALIVE. The content is structured as * &struct iwl_fw_error_dump_smem_cfg. + * @IWL_FW_ERROR_DUMP_D3_DEBUG_DATA: D3 debug data */ enum iwl_fw_error_dump_type { /* 0 is deprecated */ @@ -59,8 +62,6 @@ enum iwl_fw_error_dump_type { IWL_FW_ERROR_DUMP_EXTERNAL = 15, /* Do not move */ IWL_FW_ERROR_DUMP_MEM_CFG = 16, IWL_FW_ERROR_DUMP_D3_DEBUG_DATA = 17, - - IWL_FW_ERROR_DUMP_MAX, }; /** @@ -442,7 +443,7 @@ struct iwl_fw_ini_err_table_dump { * struct iwl_fw_error_dump_rb - content of an Receive Buffer * @index: the index of the Receive Buffer in the Rx queue * @rxq: the RB's Rx queue - * @reserved: + * @reserved: reserved * @data: the content of the Receive Buffer */ struct iwl_fw_error_dump_rb { @@ -488,7 +489,7 @@ struct iwl_fw_ini_special_device_memory { * struct iwl_fw_error_dump_paging - content of the UMAC's image page * block on DRAM * @index: the index of the page block - * @reserved: + * @reserved: reserved * @data: the content of the page block */ struct iwl_fw_error_dump_paging { @@ -511,6 +512,7 @@ iwl_fw_error_next_data(struct iwl_fw_error_dump_data *data) /** * enum iwl_fw_dbg_trigger - triggers available * + * @FW_DBG_TRIGGER_INVALID: invalid trigger value * @FW_DBG_TRIGGER_USER: trigger log collection by user * This should not be defined as a trigger to the driver, but a value the * driver should set to indicate that the trigger was initiated by the @@ -530,14 +532,15 @@ iwl_fw_error_next_data(struct iwl_fw_error_dump_data *data) * @FW_DBG_TRIGGER_TIME_EVENT: trigger log collection upon time events related * events. * @FW_DBG_TRIGGER_BA: trigger log collection upon BlockAck related events. - * @FW_DBG_TX_LATENCY: trigger log collection when the tx latency goes above a - * threshold. - * @FW_DBG_TDLS: trigger log collection upon TDLS related events. + * @FW_DBG_TRIGGER_TX_LATENCY: trigger log collection when the tx latency + * goes above a threshold. + * @FW_DBG_TRIGGER_TDLS: trigger log collection upon TDLS related events. * @FW_DBG_TRIGGER_TX_STATUS: trigger log collection upon tx status when * the firmware sends a tx reply. * @FW_DBG_TRIGGER_ALIVE_TIMEOUT: trigger log collection if alive flow timeouts * @FW_DBG_TRIGGER_DRIVER: trigger log collection upon a flow failure * in the driver. + * @FW_DBG_TRIGGER_MAX: beyond triggers, number for sizing arrays etc. */ enum iwl_fw_dbg_trigger { FW_DBG_TRIGGER_INVALID = 0, -- cgit v1.2.3 From ecf7e563031d2685e9d3e6a870d6a7fc60d537f6 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Thu, 8 Feb 2024 18:58:43 +0200 Subject: wifi: iwlwifi: api: dbg-tlv: fix up kernel-doc Some things are misnamed or missing, fix that. Signed-off-by: Johannes Berg Signed-off-by: Miri Korenblit Link: https://msgid.link/20240208185302.895a2daa0e17.I4d4bdc4ebaf4bfef113a7e6c83848f5a4fb52977@changeid Signed-off-by: Johannes Berg --- drivers/net/wireless/intel/iwlwifi/fw/api/dbg-tlv.h | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/intel/iwlwifi/fw/api/dbg-tlv.h b/drivers/net/wireless/intel/iwlwifi/fw/api/dbg-tlv.h index 394747deb269..47c914de2992 100644 --- a/drivers/net/wireless/intel/iwlwifi/fw/api/dbg-tlv.h +++ b/drivers/net/wireless/intel/iwlwifi/fw/api/dbg-tlv.h @@ -1,6 +1,6 @@ /* SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause */ /* - * Copyright (C) 2018-2023 Intel Corporation + * Copyright (C) 2018-2024 Intel Corporation */ #ifndef __iwl_fw_dbg_tlv_h__ #define __iwl_fw_dbg_tlv_h__ @@ -319,7 +319,7 @@ struct iwl_fw_ini_conf_set_tlv { * @IWL_FW_INI_CONFIG_SET_TYPE_CSR: for CSR configuration * @IWL_FW_INI_CONFIG_SET_TYPE_DBGC_DRAM_ADDR: for DBGC_DRAM_ADDR configuration * @IWL_FW_INI_CONFIG_SET_TYPE_PERIPH_SCRATCH_HWM: for PERIPH SCRATCH HWM configuration - * @IWL_FW_INI_ALLOCATION_NUM: max number of configuration supported + * @IWL_FW_INI_CONFIG_SET_TYPE_MAX_NUM: max number of configuration supported */ enum iwl_fw_ini_config_set_type { @@ -360,6 +360,7 @@ enum iwl_fw_ini_allocation_id { * @IWL_FW_INI_LOCATION_SRAM_PATH: SRAM location * @IWL_FW_INI_LOCATION_DRAM_PATH: DRAM location * @IWL_FW_INI_LOCATION_NPK_PATH: NPK location + * @IWL_FW_INI_LOCATION_NUM: number of valid locations */ enum iwl_fw_ini_buffer_location { IWL_FW_INI_LOCATION_INVALID, @@ -439,6 +440,7 @@ enum iwl_fw_ini_region_device_memory_subtype { * Hard coded time points in which the driver can send hcmd or perform dump * collection * + * @IWL_FW_INI_TIME_POINT_INVALID: invalid timepoint * @IWL_FW_INI_TIME_POINT_EARLY: pre loading the FW * @IWL_FW_INI_TIME_POINT_AFTER_ALIVE: first cmd from host after alive notif * @IWL_FW_INI_TIME_POINT_POST_INIT: last cmd in series of init sequence @@ -553,7 +555,7 @@ enum iwl_fw_ini_dump_policy { * enum iwl_fw_ini_dump_type - Determines dump type based on size defined by FW. * * @IWL_FW_INI_DUMP_BRIEF : only dump the most important regions - * @IWL_FW_INI_DEBUG_MEDIUM: dump more regions than "brief", but not all regions + * @IWL_FW_INI_DUMP_MEDIUM: dump more regions than "brief", but not all regions * @IWL_FW_INI_DUMP_VERBOSE : dump all regions */ enum iwl_fw_ini_dump_type { -- cgit v1.2.3 From f16368a157008ac0755aa9457bc71a44e5e8a5f3 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Thu, 8 Feb 2024 18:58:44 +0200 Subject: wifi: iwlwifi: fw: file: clean up kernel-doc Add missing kernel-doc and otherwise fix things. Signed-off-by: Johannes Berg Signed-off-by: Miri Korenblit Link: https://msgid.link/20240208185302.c41fddd32c18.I1978ed9aa0484b37504f2bd4614ae0f620821f81@changeid Signed-off-by: Johannes Berg --- drivers/net/wireless/intel/iwlwifi/fw/file.h | 16 +++++++++++++--- 1 file changed, 13 insertions(+), 3 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/intel/iwlwifi/fw/file.h b/drivers/net/wireless/intel/iwlwifi/fw/file.h index 08d9aeaedd99..f69d29e531c8 100644 --- a/drivers/net/wireless/intel/iwlwifi/fw/file.h +++ b/drivers/net/wireless/intel/iwlwifi/fw/file.h @@ -216,6 +216,7 @@ typedef unsigned int __bitwise iwl_ucode_tlv_api_t; * ADD_MODIFY_STA_KEY_API_S_VER_2. * @IWL_UCODE_TLV_API_STA_TYPE: This ucode supports station type assignement. * @IWL_UCODE_TLV_API_NAN2_VER2: This ucode supports NAN API version 2 + * @IWL_UCODE_TLV_API_ADAPTIVE_DWELL: support for adaptive dwell in scanning * @IWL_UCODE_TLV_API_NEW_RX_STATS: should new RX STATISTICS API be used * @IWL_UCODE_TLV_API_QUOTA_LOW_LATENCY: Quota command includes a field * indicating low latency direction. @@ -239,10 +240,15 @@ typedef unsigned int __bitwise iwl_ucode_tlv_api_t; * SCAN_OFFLOAD_PROFILES_QUERY_RSP_S. * @IWL_UCODE_TLV_API_MBSSID_HE: This ucode supports v2 of * STA_CONTEXT_DOT11AX_API_S + * @IWL_UCODE_TLV_API_FTM_RTT_ACCURACY: version 7 of the range response API + * is supported by FW, this indicates the RTT confidence value * @IWL_UCODE_TLV_API_SAR_TABLE_VER: This ucode supports different sar * version tables. * @IWL_UCODE_TLV_API_REDUCED_SCAN_CONFIG: This ucode supports v3 of - * SCAN_CONFIG_DB_CMD_API_S. + * SCAN_CONFIG_DB_CMD_API_S. + * @IWL_UCODE_TLV_API_ADWELL_HB_DEF_N_AP: support for setting adaptive dwell + * number of APs in the 5 GHz band + * @IWL_UCODE_TLV_API_BAND_IN_RX_DATA: FW reports band number in RX notification * @IWL_UCODE_TLV_API_NO_HOST_DISABLE_TX: Firmware offloaded the station disable tx * logic. * @IWL_UCODE_TLV_API_INT_DBG_BUF_CLEAR: Firmware supports clearing the debug @@ -573,6 +579,7 @@ enum iwl_fw_dbg_reg_operator { * struct iwl_fw_dbg_reg_op - an operation on a register * * @op: &enum iwl_fw_dbg_reg_operator + * @reserved: reserved * @addr: offset of the register * @val: value */ @@ -619,6 +626,7 @@ struct iwl_fw_dbg_mem_seg_tlv { * @version: version of the TLV - currently 0 * @monitor_mode: &enum iwl_fw_dbg_monitor_mode * @size_power: buffer size will be 2^(size_power + 11) + * @reserved: reserved * @base_reg: addr of the base addr register (PRPH) * @end_reg: addr of the end addr register (PRPH) * @write_ptr_reg: the addr of the reg of the write pointer @@ -729,6 +737,8 @@ enum iwl_fw_dbg_trigger_vif_type { * @trig_dis_ms: the time, in milliseconds, after an occurrence of this * trigger in which another occurrence should be ignored. * @flags: &enum iwl_fw_dbg_trigger_flags + * @reserved: reserved (for alignment) + * @data: trigger data */ struct iwl_fw_dbg_trigger_tlv { __le32 id; @@ -769,7 +779,7 @@ struct iwl_fw_dbg_trigger_missed_bcon { /** * struct iwl_fw_dbg_trigger_cmd - configures trigger for messages from FW. - * cmds: the list of commands to trigger the collection on + * @cmds: the list of commands to trigger the collection on */ struct iwl_fw_dbg_trigger_cmd { struct cmd { @@ -779,7 +789,7 @@ struct iwl_fw_dbg_trigger_cmd { } __packed; /** - * iwl_fw_dbg_trigger_stats - configures trigger for statistics + * struct iwl_fw_dbg_trigger_stats - configures trigger for statistics * @stop_offset: the offset of the value to be monitored * @stop_threshold: the threshold above which to collect * @start_offset: the offset of the value to be monitored -- cgit v1.2.3 From d8af46dec1ff0141f66253336f5a52cbb237d18a Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Thu, 8 Feb 2024 18:58:45 +0200 Subject: wifi: iwlwifi: iwl-trans.h: clean up kernel-doc Add missing kernel-doc, fix annotations, etc. Signed-off-by: Johannes Berg Signed-off-by: Miri Korenblit Link: https://msgid.link/20240208185302.a66b5cad363b.I3ee4522ac34c3e5984fce5c1cb677fb3db7a965b@changeid Signed-off-by: Johannes Berg --- drivers/net/wireless/intel/iwlwifi/iwl-trans.h | 64 ++++++++++++++++++++------ 1 file changed, 51 insertions(+), 13 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/intel/iwlwifi/iwl-trans.h b/drivers/net/wireless/intel/iwlwifi/iwl-trans.h index 3047ffc24415..b93cef7b2330 100644 --- a/drivers/net/wireless/intel/iwlwifi/iwl-trans.h +++ b/drivers/net/wireless/intel/iwlwifi/iwl-trans.h @@ -519,6 +519,7 @@ struct iwl_pnvm_image { * Must be atomic * @reclaim: free packet until ssn. Returns a list of freed packets. * Must be atomic + * @set_q_ptrs: set queue pointers internally, after D3 when HW state changed * @txq_enable: setup a queue. To setup an AC queue, use the * iwl_trans_ac_txq_enable wrapper. fw_alive must have been called before * this one. The op_mode must not configure the HCMD queue. The scheduler @@ -528,6 +529,8 @@ struct iwl_pnvm_image { * hardware scheduler bug. May sleep. * @txq_disable: de-configure a Tx queue to send AMPDUs * Must be atomic + * @txq_alloc: Allocate a new TX queue, may sleep. + * @txq_free: Free a previously allocated TX queue. * @txq_set_shared_mode: change Tx queue shared/unshared marking * @wait_tx_queues_empty: wait until tx queues are empty. May sleep. * @wait_txq_empty: wait until specific tx queue is empty. May sleep. @@ -547,23 +550,27 @@ struct iwl_pnvm_image { * the op_mode. May be called several times before start_fw, can't be * called after that. * @set_pmi: set the power pmi state + * @sw_reset: trigger software reset of the NIC * @grab_nic_access: wake the NIC to be able to access non-HBUS regs. * Sleeping is not allowed between grab_nic_access and * release_nic_access. * @release_nic_access: let the NIC go to sleep. The "flags" parameter * must be the same one that was sent before to the grab_nic_access. - * @set_bits_mask - set SRAM register according to value and mask. + * @set_bits_mask: set SRAM register according to value and mask. * @dump_data: return a vmalloc'ed buffer with debug data, maybe containing last * TX'ed commands and similar. The buffer will be vfree'd by the caller. * Note that the transport must fill in the proper file headers. * @debugfs_cleanup: used in the driver unload flow to make a proper cleanup * of the trans debugfs + * @sync_nmi: trigger a firmware NMI and wait for it to complete * @load_pnvm: save the pnvm data in DRAM * @set_pnvm: set the pnvm data in the prph scratch buffer, inside the * context info. * @load_reduce_power: copy reduce power table to the corresponding DRAM memory * @set_reduce_power: set reduce power table addresses in the sratch buffer * @interrupts: disable/enable interrupts to transport + * @imr_dma_data: set up IMR DMA + * @rxq_dma_data: retrieve RX queue DMA data, see @struct iwl_trans_rxq_dma_data */ struct iwl_trans_ops { @@ -775,7 +782,7 @@ struct iwl_self_init_dram { * @imr_size: imr dram size received from fw * @sram_addr: sram address from debug tlv * @sram_size: sram size from debug tlv - * @imr2sram_remainbyte`: size remained after each dma transfer + * @imr2sram_remainbyte: size remained after each dma transfer * @imr_curr_addr: current dst address used during dma transfer * @imr_base_addr: imr address received from fw */ @@ -822,12 +829,16 @@ struct iwl_pc_data { * @fw_mon: DRAM buffer for firmware monitor * @hw_error: equals true if hw error interrupt was received from the FW * @ini_dest: debug monitor destination uses &enum iwl_fw_ini_buffer_location + * @unsupported_region_msk: unsupported regions out of active_regions * @active_regions: active regions * @debug_info_tlv_list: list of debug info TLVs * @time_point: array of debug time points * @periodic_trig_list: periodic triggers list * @domains_bitmap: bitmap of active domains other than &IWL_FW_INI_DOMAIN_ALWAYS_ON * @ucode_preset: preset based on ucode + * @restart_required: indicates debug restart is required + * @last_tp_resetfw: last handling of reset during debug timepoint + * @imr_data: IMR debug data allocation * @dump_file_name_ext: dump file name extension * @dump_file_name_ext_valid: dump file name extension if valid or not * @num_pc: number of program counter for cpu @@ -930,6 +941,7 @@ struct iwl_pcie_first_tb_buf { * @wd_timeout: queue watchdog timeout (jiffies) - per queue * @frozen: tx stuck queue timer is frozen * @frozen_expiry_remainder: remember how long until the timer fires + * @block: queue is blocked * @bc_tbl: byte count table of the queue (relevant only for gen2 transport) * @write_ptr: 1-st empty entry (index) host_w * @read_ptr: last used entry (index) host_r @@ -938,6 +950,8 @@ struct iwl_pcie_first_tb_buf { * @id: queue id * @low_mark: low watermark, resume queue if free space more than this * @high_mark: high watermark, stop queue if free space less than this + * @overflow_q: overflow queue for handling frames that didn't fit on HW queue + * @overflow_tx: need to transmit from overflow * * A Tx queue consists of circular buffer of BDs (a.k.a. TFDs, transmit frame * descriptors) and required locking structures. @@ -990,10 +1004,19 @@ struct iwl_txq { * @bc_table_dword: true if the BC table expects DWORD (as opposed to bytes) * @page_offs: offset from skb->cb to mac header page pointer * @dev_cmd_offs: offset from skb->cb to iwl_device_tx_cmd pointer - * @queue_used - bit mask of used queues - * @queue_stopped - bit mask of stopped queues + * @queue_used: bit mask of used queues + * @queue_stopped: bit mask of stopped queues + * @txq: array of TXQ data structures representing the TXQs * @scd_bc_tbls: gen1 pointer to the byte count table of the scheduler * @queue_alloc_cmd_ver: queue allocation command version + * @bc_pool: bytecount DMA allocations pool + * @bc_tbl_size: bytecount table size + * @tso_hdr_page: page allocated (per CPU) for A-MSDU headers when doing TSO + * (and similar usage) + * @tfd: TFD data + * @tfd.max_tbs: max number of buffers per TFD + * @tfd.size: TFD size + * @tfd.addr_size: TFD/TB address size */ struct iwl_trans_txqs { unsigned long queue_used[BITS_TO_LONGS(IWL_MAX_TVQM_QUEUES)]; @@ -1026,27 +1049,35 @@ struct iwl_trans_txqs { /** * struct iwl_trans - transport common data * - * @csme_own - true if we couldn't get ownership on the device - * @ops - pointer to iwl_trans_ops - * @op_mode - pointer to the op_mode + * @csme_own: true if we couldn't get ownership on the device + * @ops: pointer to iwl_trans_ops + * @op_mode: pointer to the op_mode * @trans_cfg: the trans-specific configuration part - * @cfg - pointer to the configuration - * @drv - pointer to iwl_drv + * @cfg: pointer to the configuration + * @drv: pointer to iwl_drv + * @state: current device state * @status: a bit-mask of transport status flags - * @dev - pointer to struct device * that represents the device + * @dev: pointer to struct device * that represents the device * @max_skb_frags: maximum number of fragments an SKB can have when transmitted. * 0 indicates that frag SKBs (NETIF_F_SG) aren't supported. - * @hw_rf_id a u32 with the device RF ID - * @hw_crf_id a u32 with the device CRF ID - * @hw_wfpm_id a u32 with the device wfpm ID + * @hw_rf_id: a u32 with the device RF ID + * @hw_cnv_id: a u32 with the device CNV ID + * @hw_crf_id: a u32 with the device CRF ID + * @hw_wfpm_id: a u32 with the device wfpm ID * @hw_id: a u32 with the ID of the device / sub-device. * Set during transport allocation. * @hw_id_str: a string with info about HW ID. Set during transport allocation. + * @sku_id: the SKU identifier (for PNVM matching) + * @pnvm_loaded: indicates PNVM was loaded + * @hw_rev: the revision data of the HW * @hw_rev_step: The mac step of the HW * @pm_support: set to true in start_hw if link pm is supported * @ltr_enabled: set to true if the LTR is enabled * @fail_to_parse_pnvm_image: set to true if pnvm parsing failed + * @reduce_power_loaded: indicates reduced power section was loaded * @failed_to_load_reduce_power_image: set to true if pnvm loading failed + * @command_groups: pointer to command group name list array + * @command_groups_size: array size of @command_groups * @wide_cmd_header: true when ucode supports wide command header format * @wait_command_queue: wait queue for sync commands * @num_rx_queues: number of RX queues allocated by the transport; @@ -1055,13 +1086,19 @@ struct iwl_trans_txqs { * @iml: a pointer to the image loader itself * @dev_cmd_pool: pool for Tx cmd allocation - for internal use only. * The user should use iwl_trans_{alloc,free}_tx_cmd. + * @dev_cmd_pool_name: name for the TX command allocation pool + * @dbgfs_dir: iwlwifi debugfs base dir for this device + * @sync_cmd_lockdep_map: lockdep map for checking sync commands * @rx_mpdu_cmd: MPDU RX command ID, must be assigned by opmode before * starting the firmware, used for tracing * @rx_mpdu_cmd_hdr_size: used for tracing, amount of data before the * start of the 802.11 header in the @rx_mpdu_cmd + * @dbg: additional debug data, see &struct iwl_trans_debug + * @init_dram: FW initialization DMA data * @system_pm_mode: the system-wide power management mode in use. * This mode is set dynamically, depending on the WoWLAN values * configured from the userspace at runtime. + * @name: the device name * @txqs: transport tx queues data. * @mbx_addr_0_step: step address data 0 * @mbx_addr_1_step: step address data 1 @@ -1071,6 +1108,7 @@ struct iwl_trans_txqs { * @reduced_cap_sku: reduced capability supported SKU * @no_160: device not supporting 160 MHz * @step_urm: STEP is in URM, no support for MCS>9 in 320 MHz + * @trans_specific: data for the specific transport this is allocated for/with */ struct iwl_trans { bool csme_own; -- cgit v1.2.3 From d34637a986d6105875f3a02cdd16bd26d5811c38 Mon Sep 17 00:00:00 2001 From: Miri Korenblit Date: Thu, 8 Feb 2024 18:58:46 +0200 Subject: wifi: iwlwifi: bump FW API to 89 for AX/BZ/SC devices Start supporting API version 89 for new devices. Signed-off-by: Miri Korenblit Link: https://msgid.link/20240208185302.b5d0c18c3dad.I55d5bd15638970d27b30b38e9ef47cddf6ba715e@changeid Signed-off-by: Johannes Berg --- drivers/net/wireless/intel/iwlwifi/cfg/ax210.c | 4 ++-- drivers/net/wireless/intel/iwlwifi/cfg/bz.c | 4 ++-- drivers/net/wireless/intel/iwlwifi/cfg/sc.c | 2 +- 3 files changed, 5 insertions(+), 5 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/intel/iwlwifi/cfg/ax210.c b/drivers/net/wireless/intel/iwlwifi/cfg/ax210.c index 456c7fff60a0..2e530fc928a4 100644 --- a/drivers/net/wireless/intel/iwlwifi/cfg/ax210.c +++ b/drivers/net/wireless/intel/iwlwifi/cfg/ax210.c @@ -1,7 +1,7 @@ // SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause /* * Copyright (C) 2015-2017 Intel Deutschland GmbH - * Copyright (C) 2018-2023 Intel Corporation + * Copyright (C) 2018-2024 Intel Corporation */ #include #include @@ -10,7 +10,7 @@ #include "fw/api/txq.h" /* Highest firmware API version supported */ -#define IWL_AX210_UCODE_API_MAX 88 +#define IWL_AX210_UCODE_API_MAX 89 /* Lowest firmware API version supported */ #define IWL_AX210_UCODE_API_MIN 59 diff --git a/drivers/net/wireless/intel/iwlwifi/cfg/bz.c b/drivers/net/wireless/intel/iwlwifi/cfg/bz.c index c858f355701e..14c5cc265fe3 100644 --- a/drivers/net/wireless/intel/iwlwifi/cfg/bz.c +++ b/drivers/net/wireless/intel/iwlwifi/cfg/bz.c @@ -1,7 +1,7 @@ // SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause /* * Copyright (C) 2015-2017 Intel Deutschland GmbH - * Copyright (C) 2018-2023 Intel Corporation + * Copyright (C) 2018-2024 Intel Corporation */ #include #include @@ -10,7 +10,7 @@ #include "fw/api/txq.h" /* Highest firmware API version supported */ -#define IWL_BZ_UCODE_API_MAX 88 +#define IWL_BZ_UCODE_API_MAX 89 /* Lowest firmware API version supported */ #define IWL_BZ_UCODE_API_MIN 80 diff --git a/drivers/net/wireless/intel/iwlwifi/cfg/sc.c b/drivers/net/wireless/intel/iwlwifi/cfg/sc.c index be98a174a311..dbbcb2d0968c 100644 --- a/drivers/net/wireless/intel/iwlwifi/cfg/sc.c +++ b/drivers/net/wireless/intel/iwlwifi/cfg/sc.c @@ -10,7 +10,7 @@ #include "fw/api/txq.h" /* Highest firmware API version supported */ -#define IWL_SC_UCODE_API_MAX 88 +#define IWL_SC_UCODE_API_MAX 89 /* Lowest firmware API version supported */ #define IWL_SC_UCODE_API_MIN 82 -- cgit v1.2.3 From 182094411e29fa76b6651f31fd7b941780a45c56 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Thu, 8 Feb 2024 18:58:47 +0200 Subject: wifi: iwlwifi: mvm: check own capabilities for EMLSR There may be different hardware or configurations supported, so check for our own EMLSR capability before allowing it to be used, in addition to checking the AP's. Signed-off-by: Johannes Berg Signed-off-by: Miri Korenblit Link: https://msgid.link/20240208185302.036443611696.If33caabd7cf372834287863b40b2d6d1ef1ca3f7@changeid Signed-off-by: Johannes Berg --- drivers/net/wireless/intel/iwlwifi/mvm/mld-mac80211.c | 7 +++++++ 1 file changed, 7 insertions(+) (limited to 'drivers/net') diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/mld-mac80211.c b/drivers/net/wireless/intel/iwlwifi/mvm/mld-mac80211.c index 021592f69f38..084314bf6f36 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/mld-mac80211.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/mld-mac80211.c @@ -1275,6 +1275,7 @@ static bool iwl_mvm_can_enter_esr(struct iwl_mvm *mvm, struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); int primary_link = iwl_mvm_mld_get_primary_link(mvm, vif, desired_links); + const struct wiphy_iftype_ext_capab *ext_capa; bool ret = true; int link_id; @@ -1284,6 +1285,12 @@ static bool iwl_mvm_can_enter_esr(struct iwl_mvm *mvm, if (!(vif->cfg.eml_cap & IEEE80211_EML_CAP_EMLSR_SUPP)) return false; + ext_capa = cfg80211_get_iftype_ext_capa(mvm->hw->wiphy, + ieee80211_vif_type_p2p(vif)); + if (!ext_capa || + !(ext_capa->eml_capabilities & IEEE80211_EML_CAP_EMLSR_SUPP)) + return false; + for_each_set_bit(link_id, &desired_links, IEEE80211_MLD_MAX_NUM_LINKS) { struct ieee80211_bss_conf *link_conf = link_conf_dereference_protected(vif, link_id); -- cgit v1.2.3 From 35c1bbd93c4e6969b3ac238b48a8bdff3e223ed8 Mon Sep 17 00:00:00 2001 From: Miri Korenblit Date: Mon, 5 Feb 2024 21:21:06 +0200 Subject: wifi: iwlwifi: mvm: remove IWL_MVM_STATUS_NEED_FLUSH_P2P This is set when a P2P ROC ends, and uses as an indication inside iwl_mvm_roc_done_wk that the resources used for this ROC (sta/link) needs to be flushed/deactivated (respectively). But we also have IWL_MVM_STATUS_ROC_RUNNING, which is set whenever P2P ROC starts, and is not even used in iwl_mvm_roc_done_wk. Use IWL_MVM_STATUS_ROC_RUNNING as an indicator, and remove the redundant bit. While at it, add a call to synchronize_net also for the AUX ROC case, which is missing in the existing code. Signed-off-by: Miri Korenblit Link: https://msgid.link/20240205211151.0494f75de311.Ic4aacacf7581a5c9046c4f1df87cbb67470853e7@changeid Signed-off-by: Johannes Berg --- drivers/net/wireless/intel/iwlwifi/mvm/mvm.h | 4 +- .../net/wireless/intel/iwlwifi/mvm/time-event.c | 89 +++++++++------------- 2 files changed, 38 insertions(+), 55 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h b/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h index 83263d510a45..ce78c21883e9 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h +++ b/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h @@ -1,6 +1,6 @@ /* SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause */ /* - * Copyright (C) 2012-2014, 2018-2023 Intel Corporation + * Copyright (C) 2012-2014, 2018-2024 Intel Corporation * Copyright (C) 2013-2015 Intel Mobile Communications GmbH * Copyright (C) 2016-2017 Intel Deutschland GmbH */ @@ -1221,7 +1221,6 @@ struct iwl_mvm { * @IWL_MVM_STATUS_IN_HW_RESTART: HW restart is active * @IWL_MVM_STATUS_ROC_AUX_RUNNING: AUX remain-on-channel is running * @IWL_MVM_STATUS_FIRMWARE_RUNNING: firmware is running - * @IWL_MVM_STATUS_NEED_FLUSH_P2P: need to flush P2P bcast STA * @IWL_MVM_STATUS_IN_D3: in D3 (or at least about to go into it) * @IWL_MVM_STATUS_SUPPRESS_ERROR_LOG_ONCE: suppress one error log * if this is set, when intentionally triggered @@ -1236,7 +1235,6 @@ enum iwl_mvm_status { IWL_MVM_STATUS_IN_HW_RESTART, IWL_MVM_STATUS_ROC_AUX_RUNNING, IWL_MVM_STATUS_FIRMWARE_RUNNING, - IWL_MVM_STATUS_NEED_FLUSH_P2P, IWL_MVM_STATUS_IN_D3, IWL_MVM_STATUS_SUPPRESS_ERROR_LOG_ONCE, IWL_MVM_STATUS_STARTING, diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/time-event.c b/drivers/net/wireless/intel/iwlwifi/mvm/time-event.c index 43732da7ba39..a03eceec70e9 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/time-event.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/time-event.c @@ -45,32 +45,24 @@ void iwl_mvm_te_clear_data(struct iwl_mvm *mvm, te_data->link_id = -1; } -void iwl_mvm_roc_done_wk(struct work_struct *wk) +static void iwl_mvm_cleanup_roc(struct iwl_mvm *mvm) { - struct iwl_mvm *mvm = container_of(wk, struct iwl_mvm, roc_done_wk); - /* * Clear the ROC_RUNNING status bit. * This will cause the TX path to drop offchannel transmissions. * That would also be done by mac80211, but it is racy, in particular - * in the case that the time event actually completed in the firmware - * (which is handled in iwl_mvm_te_handle_notif). - */ - clear_bit(IWL_MVM_STATUS_ROC_RUNNING, &mvm->status); - - synchronize_net(); - - /* - * Flush the offchannel queue -- this is called when the time + * in the case that the time event actually completed in the firmware. + * + * Also flush the offchannel queue -- this is called when the time * event finishes or is canceled, so that frames queued for it * won't get stuck on the queue and be transmitted in the next * time event. */ - - mutex_lock(&mvm->mutex); - if (test_and_clear_bit(IWL_MVM_STATUS_NEED_FLUSH_P2P, &mvm->status)) { + if (test_and_clear_bit(IWL_MVM_STATUS_ROC_RUNNING, &mvm->status)) { struct iwl_mvm_vif *mvmvif; + synchronize_net(); + /* * NB: access to this pointer would be racy, but the flush bit * can only be set when we had a P2P-Device VIF, and we have a @@ -105,21 +97,16 @@ void iwl_mvm_roc_done_wk(struct work_struct *wk) } } - /* - * Clear the ROC_AUX_RUNNING status bit. - * This will cause the TX path to drop offchannel transmissions. - * That would also be done by mac80211, but it is racy, in particular - * in the case that the time event actually completed in the firmware - * (which is handled in iwl_mvm_te_handle_notif). - */ + /* Do the same for AUX ROC */ if (test_and_clear_bit(IWL_MVM_STATUS_ROC_AUX_RUNNING, &mvm->status)) { - /* do the same in case of hot spot 2.0 */ + synchronize_net(); + iwl_mvm_flush_sta(mvm, mvm->aux_sta.sta_id, mvm->aux_sta.tfd_queue_msk); if (mvm->mld_api_is_used) { iwl_mvm_mld_rm_aux_sta(mvm); - goto out_unlock; + return; } /* In newer version of this command an aux station is added only @@ -128,8 +115,14 @@ void iwl_mvm_roc_done_wk(struct work_struct *wk) if (iwl_mvm_has_new_station_api(mvm->fw)) iwl_mvm_rm_aux_sta(mvm); } +} -out_unlock: +void iwl_mvm_roc_done_wk(struct work_struct *wk) +{ + struct iwl_mvm *mvm = container_of(wk, struct iwl_mvm, roc_done_wk); + + mutex_lock(&mvm->mutex); + iwl_mvm_cleanup_roc(mvm); mutex_unlock(&mvm->mutex); } @@ -294,18 +287,6 @@ static void iwl_mvm_te_check_trigger(struct iwl_mvm *mvm, } } -static void iwl_mvm_p2p_roc_finished(struct iwl_mvm *mvm) -{ - /* - * If the IWL_MVM_STATUS_NEED_FLUSH_P2P is already set, then the - * roc_done_wk is already scheduled or running, so don't schedule it - * again to avoid a race where the roc_done_wk clears this bit after - * it is set here, affecting the next run of the roc_done_wk. - */ - if (!test_and_set_bit(IWL_MVM_STATUS_NEED_FLUSH_P2P, &mvm->status)) - iwl_mvm_roc_finished(mvm); -} - /* * Handles a FW notification for an event that is known to the driver. * @@ -357,7 +338,7 @@ static void iwl_mvm_te_handle_notif(struct iwl_mvm *mvm, switch (te_data->vif->type) { case NL80211_IFTYPE_P2P_DEVICE: ieee80211_remain_on_channel_expired(mvm->hw); - iwl_mvm_p2p_roc_finished(mvm); + iwl_mvm_roc_finished(mvm); break; case NL80211_IFTYPE_STATION: /* @@ -782,7 +763,7 @@ static bool __iwl_mvm_remove_time_event(struct iwl_mvm *mvm, iwl_mvm_cancel_session_protection(mvm, vif, id, link_id); if (iftype == NL80211_IFTYPE_P2P_DEVICE) { - iwl_mvm_p2p_roc_finished(mvm); + iwl_mvm_roc_finished(mvm); } } return false; @@ -972,7 +953,7 @@ void iwl_mvm_rx_session_protect_notif(struct iwl_mvm *mvm, /* End TE, notify mac80211 */ mvmvif->time_event_data.id = SESSION_PROTECT_CONF_MAX_ID; mvmvif->time_event_data.link_id = -1; - iwl_mvm_p2p_roc_finished(mvm); + iwl_mvm_roc_finished(mvm); ieee80211_remain_on_channel_expired(mvm->hw); } else if (le32_to_cpu(notif->start)) { if (WARN_ON(mvmvif->time_event_data.id != @@ -1244,17 +1225,13 @@ void iwl_mvm_stop_roc(struct iwl_mvm *mvm, struct ieee80211_vif *vif) IWL_UCODE_TLV_CAPA_SESSION_PROT_CMD)) { mvmvif = iwl_mvm_vif_from_mac80211(vif); - if (vif->type == NL80211_IFTYPE_P2P_DEVICE) { + if (vif->type == NL80211_IFTYPE_P2P_DEVICE) iwl_mvm_cancel_session_protection(mvm, vif, mvmvif->time_event_data.id, mvmvif->time_event_data.link_id); - iwl_mvm_p2p_roc_finished(mvm); - } else { + else iwl_mvm_roc_station_remove(mvm, mvmvif); - iwl_mvm_roc_finished(mvm); - } - - return; + goto cleanup_roc; } te_data = iwl_mvm_get_roc_te(mvm); @@ -1265,13 +1242,21 @@ void iwl_mvm_stop_roc(struct iwl_mvm *mvm, struct ieee80211_vif *vif) mvmvif = iwl_mvm_vif_from_mac80211(te_data->vif); - if (te_data->vif->type == NL80211_IFTYPE_P2P_DEVICE) { + if (te_data->vif->type == NL80211_IFTYPE_P2P_DEVICE) iwl_mvm_remove_time_event(mvm, mvmvif, te_data); - iwl_mvm_p2p_roc_finished(mvm); - } else { + else iwl_mvm_remove_aux_roc_te(mvm, mvmvif, te_data); - iwl_mvm_roc_finished(mvm); - } + +cleanup_roc: + /* + * In case we get here before the ROC event started, + * (so the status bit isn't set) set it here so iwl_mvm_cleanup_roc will + * cleanup things properly + */ + set_bit(vif->type == NL80211_IFTYPE_P2P_DEVICE ? + IWL_MVM_STATUS_ROC_RUNNING : IWL_MVM_STATUS_ROC_AUX_RUNNING, + &mvm->status); + iwl_mvm_cleanup_roc(mvm); } void iwl_mvm_remove_csa_period(struct iwl_mvm *mvm, -- cgit v1.2.3 From 77770189921e38597a42744c7032b8222538cdf3 Mon Sep 17 00:00:00 2001 From: Miri Korenblit Date: Mon, 5 Feb 2024 21:21:08 +0200 Subject: wifi: iwlwifi: cancel session protection only if there is one mac80211 might (due to an unavoidable race) cancel a ROC that has already expired. In that case the driver should not send the session protection cmd to cancel the ROC. When session protection is supported, the te_data::id field is reused to save the configuration id. Check it before sending the cmd. Signed-off-by: Miri Korenblit Link: https://msgid.link/20240205211151.30176bf869d9.Id811c20d3746b870cbe0c946bbfe1c0ab0a290cb@changeid Signed-off-by: Johannes Berg --- drivers/net/wireless/intel/iwlwifi/mvm/time-event.c | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/time-event.c b/drivers/net/wireless/intel/iwlwifi/mvm/time-event.c index a03eceec70e9..89b1c7a87660 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/time-event.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/time-event.c @@ -1224,13 +1224,21 @@ void iwl_mvm_stop_roc(struct iwl_mvm *mvm, struct ieee80211_vif *vif) if (fw_has_capa(&mvm->fw->ucode_capa, IWL_UCODE_TLV_CAPA_SESSION_PROT_CMD)) { mvmvif = iwl_mvm_vif_from_mac80211(vif); + te_data = &mvmvif->time_event_data; + + if (vif->type == NL80211_IFTYPE_P2P_DEVICE) { + if (te_data->id >= SESSION_PROTECT_CONF_MAX_ID) { + IWL_DEBUG_TE(mvm, + "No remain on channel event\n"); + return; + } - if (vif->type == NL80211_IFTYPE_P2P_DEVICE) iwl_mvm_cancel_session_protection(mvm, vif, - mvmvif->time_event_data.id, - mvmvif->time_event_data.link_id); - else + te_data->id, + te_data->link_id); + } else { iwl_mvm_roc_station_remove(mvm, mvmvif); + } goto cleanup_roc; } -- cgit v1.2.3 From cb5942b77c05d54310a0420cac12935e9b6aa21c Mon Sep 17 00:00:00 2001 From: Alexis Lothoré Date: Mon, 12 Feb 2024 13:57:37 +0100 Subject: wifi: wilc1000: prevent use-after-free on vif when cleaning up all interfaces MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit wilc_netdev_cleanup currently triggers a KASAN warning, which can be observed on interface registration error path, or simply by removing the module/unbinding device from driver: echo spi0.1 > /sys/bus/spi/drivers/wilc1000_spi/unbind ================================================================== BUG: KASAN: slab-use-after-free in wilc_netdev_cleanup+0x508/0x5cc Read of size 4 at addr c54d1ce8 by task sh/86 CPU: 0 PID: 86 Comm: sh Not tainted 6.8.0-rc1+ #117 Hardware name: Atmel SAMA5 unwind_backtrace from show_stack+0x18/0x1c show_stack from dump_stack_lvl+0x34/0x58 dump_stack_lvl from print_report+0x154/0x500 print_report from kasan_report+0xac/0xd8 kasan_report from wilc_netdev_cleanup+0x508/0x5cc wilc_netdev_cleanup from wilc_bus_remove+0xc8/0xec wilc_bus_remove from spi_remove+0x8c/0xac spi_remove from device_release_driver_internal+0x434/0x5f8 device_release_driver_internal from unbind_store+0xbc/0x108 unbind_store from kernfs_fop_write_iter+0x398/0x584 kernfs_fop_write_iter from vfs_write+0x728/0xf88 vfs_write from ksys_write+0x110/0x1e4 ksys_write from ret_fast_syscall+0x0/0x1c [...] Allocated by task 1: kasan_save_track+0x30/0x5c __kasan_kmalloc+0x8c/0x94 __kmalloc_node+0x1cc/0x3e4 kvmalloc_node+0x48/0x180 alloc_netdev_mqs+0x68/0x11dc alloc_etherdev_mqs+0x28/0x34 wilc_netdev_ifc_init+0x34/0x8ec wilc_cfg80211_init+0x690/0x910 wilc_bus_probe+0xe0/0x4a0 spi_probe+0x158/0x1b0 really_probe+0x270/0xdf4 __driver_probe_device+0x1dc/0x580 driver_probe_device+0x60/0x140 __driver_attach+0x228/0x5d4 bus_for_each_dev+0x13c/0x1a8 bus_add_driver+0x2a0/0x608 driver_register+0x24c/0x578 do_one_initcall+0x180/0x310 kernel_init_freeable+0x424/0x484 kernel_init+0x20/0x148 ret_from_fork+0x14/0x28 Freed by task 86: kasan_save_track+0x30/0x5c kasan_save_free_info+0x38/0x58 __kasan_slab_free+0xe4/0x140 kfree+0xb0/0x238 device_release+0xc0/0x2a8 kobject_put+0x1d4/0x46c netdev_run_todo+0x8fc/0x11d0 wilc_netdev_cleanup+0x1e4/0x5cc wilc_bus_remove+0xc8/0xec spi_remove+0x8c/0xac device_release_driver_internal+0x434/0x5f8 unbind_store+0xbc/0x108 kernfs_fop_write_iter+0x398/0x584 vfs_write+0x728/0xf88 ksys_write+0x110/0x1e4 ret_fast_syscall+0x0/0x1c [...] David Mosberger-Tan initial investigation [1] showed that this use-after-free is due to netdevice unregistration during vif list traversal. When unregistering a net device, since the needs_free_netdev has been set to true during registration, the netdevice object is also freed, and as a consequence, the corresponding vif object too, since it is attached to it as private netdevice data. The next occurrence of the loop then tries to access freed vif pointer to the list to move forward in the list. Fix this use-after-free thanks to two mechanisms: - navigate in the list with list_for_each_entry_safe, which allows to safely modify the list as we go through each element. For each element, remove it from the list with list_del_rcu - make sure to wait for RCU grace period end after each vif removal to make sure it is safe to free the corresponding vif too (through unregister_netdev) Since we are in a RCU "modifier" path (not a "reader" path), and because such path is expected not to be concurrent to any other modifier (we are using the vif_mutex lock), we do not need to use RCU list API, that's why we can benefit from list_for_each_entry_safe. [1] https://lore.kernel.org/linux-wireless/ab077dbe58b1ea5de0a3b2ca21f275a07af967d2.camel@egauge.net/ Fixes: 8399918f3056 ("staging: wilc1000: use RCU list to maintain vif interfaces list") Signed-off-by: Alexis Lothoré Signed-off-by: Kalle Valo Link: https://msgid.link/20240212-wilc_rework_deinit-v1-1-9203ae56c27f@bootlin.com --- drivers/net/wireless/microchip/wilc1000/netdev.c | 28 ++++++------------------ 1 file changed, 7 insertions(+), 21 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/microchip/wilc1000/netdev.c b/drivers/net/wireless/microchip/wilc1000/netdev.c index a8b5c8dec69c..22f461f477f1 100644 --- a/drivers/net/wireless/microchip/wilc1000/netdev.c +++ b/drivers/net/wireless/microchip/wilc1000/netdev.c @@ -890,8 +890,7 @@ static const struct net_device_ops wilc_netdev_ops = { void wilc_netdev_cleanup(struct wilc *wilc) { - struct wilc_vif *vif; - int srcu_idx, ifc_cnt = 0; + struct wilc_vif *vif, *vif_tmp; if (!wilc) return; @@ -901,32 +900,19 @@ void wilc_netdev_cleanup(struct wilc *wilc) wilc->firmware = NULL; } - srcu_idx = srcu_read_lock(&wilc->srcu); - list_for_each_entry_rcu(vif, &wilc->vif_list, list) { + list_for_each_entry_safe(vif, vif_tmp, &wilc->vif_list, list) { + mutex_lock(&wilc->vif_mutex); + list_del_rcu(&vif->list); + wilc->vif_num--; + mutex_unlock(&wilc->vif_mutex); + synchronize_srcu(&wilc->srcu); if (vif->ndev) unregister_netdev(vif->ndev); } - srcu_read_unlock(&wilc->srcu, srcu_idx); wilc_wfi_deinit_mon_interface(wilc, false); destroy_workqueue(wilc->hif_workqueue); - while (ifc_cnt < WILC_NUM_CONCURRENT_IFC) { - mutex_lock(&wilc->vif_mutex); - if (wilc->vif_num <= 0) { - mutex_unlock(&wilc->vif_mutex); - break; - } - vif = wilc_get_wl_to_vif(wilc); - if (!IS_ERR(vif)) - list_del_rcu(&vif->list); - - wilc->vif_num--; - mutex_unlock(&wilc->vif_mutex); - synchronize_srcu(&wilc->srcu); - ifc_cnt++; - } - wilc_wlan_cfg_deinit(wilc); wlan_deinit_locks(wilc); wiphy_unregister(wilc->wiphy); -- cgit v1.2.3 From dd2f633eafa4ce5b9cb2ee09bf5d709535a02e79 Mon Sep 17 00:00:00 2001 From: David Mosberger-Tang Date: Mon, 12 Feb 2024 20:22:30 +0000 Subject: wifi: wilc1000: validate chip id during bus probe MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Previously, the driver created a net device (typically wlan0) as soon as the module was loaded. This commit changes the driver to follow normal Linux convention of creating the net device only when bus probing detects a supported chip. Signed-off-by: David Mosberger-Tang Tested-By: Alexis Lothoré Signed-off-by: Kalle Valo Link: https://msgid.link/20240212202057.3468714-1-davidm@egauge.net --- drivers/net/wireless/microchip/wilc1000/spi.c | 69 ++++++++++++++++++++------ drivers/net/wireless/microchip/wilc1000/wlan.c | 5 -- drivers/net/wireless/microchip/wilc1000/wlan.h | 5 ++ 3 files changed, 59 insertions(+), 20 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/microchip/wilc1000/spi.c b/drivers/net/wireless/microchip/wilc1000/spi.c index c92ee4b73a74..3c4451535c8a 100644 --- a/drivers/net/wireless/microchip/wilc1000/spi.c +++ b/drivers/net/wireless/microchip/wilc1000/spi.c @@ -42,7 +42,7 @@ MODULE_PARM_DESC(enable_crc16, #define WILC_SPI_RSP_HDR_EXTRA_DATA 8 struct wilc_spi { - bool isinit; /* true if SPI protocol has been configured */ + bool isinit; /* true if wilc_spi_init was successful */ bool probing_crc; /* true if we're probing chip's CRC config */ bool crc7_enabled; /* true if crc7 is currently enabled */ bool crc16_enabled; /* true if crc16 is currently enabled */ @@ -55,6 +55,8 @@ struct wilc_spi { static const struct wilc_hif_func wilc_hif_spi; static int wilc_spi_reset(struct wilc *wilc); +static int wilc_spi_configure_bus_protocol(struct wilc *wilc); +static int wilc_validate_chipid(struct wilc *wilc); /******************************************** * @@ -232,8 +234,27 @@ static int wilc_bus_probe(struct spi_device *spi) } clk_prepare_enable(wilc->rtc_clk); + dev_info(&spi->dev, "Selected CRC config: crc7=%s, crc16=%s\n", + enable_crc7 ? "on" : "off", enable_crc16 ? "on" : "off"); + + /* we need power to configure the bus protocol and to read the chip id: */ + + wilc_wlan_power(wilc, true); + + ret = wilc_spi_configure_bus_protocol(wilc); + if (ret) + goto power_down; + + ret = wilc_validate_chipid(wilc); + if (ret) + goto power_down; + + wilc_wlan_power(wilc, false); return 0; +power_down: + clk_disable_unprepare(wilc->rtc_clk); + wilc_wlan_power(wilc, false); netdev_cleanup: wilc_netdev_cleanup(wilc); free: @@ -1102,26 +1123,34 @@ static int wilc_spi_deinit(struct wilc *wilc) static int wilc_spi_init(struct wilc *wilc, bool resume) { - struct spi_device *spi = to_spi_device(wilc->dev); struct wilc_spi *spi_priv = wilc->bus_data; - u32 reg; - u32 chipid; - int ret, i; + int ret; if (spi_priv->isinit) { /* Confirm we can read chipid register without error: */ - ret = wilc_spi_read_reg(wilc, WILC_CHIPID, &chipid); - if (ret == 0) + if (wilc_validate_chipid(wilc) == 0) return 0; - - dev_err(&spi->dev, "Fail cmd read chip id...\n"); } wilc_wlan_power(wilc, true); - /* - * configure protocol - */ + ret = wilc_spi_configure_bus_protocol(wilc); + if (ret) { + wilc_wlan_power(wilc, false); + return ret; + } + + spi_priv->isinit = true; + + return 0; +} + +static int wilc_spi_configure_bus_protocol(struct wilc *wilc) +{ + struct spi_device *spi = to_spi_device(wilc->dev); + struct wilc_spi *spi_priv = wilc->bus_data; + u32 reg; + int ret, i; /* * Infer the CRC settings that are currently in effect. This @@ -1173,6 +1202,15 @@ static int wilc_spi_init(struct wilc *wilc, bool resume) spi_priv->probing_crc = false; + return 0; +} + +static int wilc_validate_chipid(struct wilc *wilc) +{ + struct spi_device *spi = to_spi_device(wilc->dev); + u32 chipid; + int ret; + /* * make sure can read chip id without protocol error */ @@ -1181,9 +1219,10 @@ static int wilc_spi_init(struct wilc *wilc, bool resume) dev_err(&spi->dev, "Fail cmd read chip id...\n"); return ret; } - - spi_priv->isinit = true; - + if (!is_wilc1000(chipid)) { + dev_err(&spi->dev, "Unknown chip id 0x%x\n", chipid); + return -ENODEV; + } return 0; } diff --git a/drivers/net/wireless/microchip/wilc1000/wlan.c b/drivers/net/wireless/microchip/wilc1000/wlan.c index 6b2f2269ddf8..68be233c36ce 100644 --- a/drivers/net/wireless/microchip/wilc1000/wlan.c +++ b/drivers/net/wireless/microchip/wilc1000/wlan.c @@ -12,11 +12,6 @@ #define WAKE_UP_TRIAL_RETRY 10000 -static inline bool is_wilc1000(u32 id) -{ - return (id & (~WILC_CHIP_REV_FIELD)) == WILC_1000_BASE_ID; -} - static inline void acquire_bus(struct wilc *wilc, enum bus_acquire acquire) { mutex_lock(&wilc->hif_cs); diff --git a/drivers/net/wireless/microchip/wilc1000/wlan.h b/drivers/net/wireless/microchip/wilc1000/wlan.h index f02775f7e41f..54643d8fef04 100644 --- a/drivers/net/wireless/microchip/wilc1000/wlan.h +++ b/drivers/net/wireless/microchip/wilc1000/wlan.h @@ -409,6 +409,11 @@ struct wilc_cfg_rsp { struct wilc_vif; +static inline bool is_wilc1000(u32 id) +{ + return (id & (~WILC_CHIP_REV_FIELD)) == WILC_1000_BASE_ID; +} + int wilc_wlan_firmware_download(struct wilc *wilc, const u8 *buffer, u32 buffer_size); int wilc_wlan_start(struct wilc *wilc); -- cgit v1.2.3 From 6ca3b88c320b5933b4371f940f70aba382e12ecf Mon Sep 17 00:00:00 2001 From: Zong-Zhe Yang Date: Tue, 13 Feb 2024 15:35:10 +0800 Subject: wifi: rtw89: fw: add definition of H2C command and C2H event for MRC series For Wi-Fi 7 chips, FW supports MRC (multi-role concurrent) functions including H2C commands and C2H events. We can consider FW MRC functions as a superset of FW MCC (multi-channel concurrent) functions. And, MRC functions can take MLO things into account. Basically before MLO, SW can also manipulate FW MRC to work original SW MCC flow. So, we add them first and implement the handling in the following. And then, SW MCC will call different series of FW functions according to chip later. Signed-off-by: Zong-Zhe Yang Signed-off-by: Ping-Ke Shih Signed-off-by: Kalle Valo Link: https://msgid.link/20240213073514.23796-2-pkshih@realtek.com --- drivers/net/wireless/realtek/rtw89/fw.h | 172 +++++++++++++++++++++++++++++++ drivers/net/wireless/realtek/rtw89/mac.h | 24 +++-- 2 files changed, 190 insertions(+), 6 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/realtek/rtw89/fw.h b/drivers/net/wireless/realtek/rtw89/fw.h index 5609e5f7d7eb..409f62cea0d7 100644 --- a/drivers/net/wireless/realtek/rtw89/fw.h +++ b/drivers/net/wireless/realtek/rtw89/fw.h @@ -3385,6 +3385,143 @@ inline void RTW89_SET_FWCMD_MCC_SET_DURATION_DURATION_Y(void *cmd, u32 val) le32p_replace_bits((__le32 *)cmd + 4, val, GENMASK(31, 0)); } +enum rtw89_h2c_mrc_sch_types { + RTW89_H2C_MRC_SCH_BAND0_ONLY = 0, + RTW89_H2C_MRC_SCH_BAND1_ONLY = 1, + RTW89_H2C_MRC_SCH_DUAL_BAND = 2, +}; + +enum rtw89_h2c_mrc_role_types { + RTW89_H2C_MRC_ROLE_WIFI = 0, + RTW89_H2C_MRC_ROLE_BT = 1, + RTW89_H2C_MRC_ROLE_EMPTY = 2, +}; + +struct rtw89_h2c_mrc_add_role { + __le32 w0; + __le32 w1; + __le32 w2; + __le32 macid_main_bitmap; + __le32 macid_paired_bitmap; +} __packed; + +#define RTW89_H2C_MRC_ADD_ROLE_W0_MACID GENMASK(15, 0) +#define RTW89_H2C_MRC_ADD_ROLE_W0_ROLE_TYPE GENMASK(23, 16) +#define RTW89_H2C_MRC_ADD_ROLE_W0_IS_MASTER BIT(24) +#define RTW89_H2C_MRC_ADD_ROLE_W0_IS_ALT_ROLE BIT(25) +#define RTW89_H2C_MRC_ADD_ROLE_W0_TX_NULL_EN BIT(26) +#define RTW89_H2C_MRC_ADD_ROLE_W0_ROLE_ALT_EN BIT(27) +#define RTW89_H2C_MRC_ADD_ROLE_W1_CENTRAL_CH_SEG GENMASK(7, 0) +#define RTW89_H2C_MRC_ADD_ROLE_W1_PRI_CH GENMASK(15, 8) +#define RTW89_H2C_MRC_ADD_ROLE_W1_BW GENMASK(19, 16) +#define RTW89_H2C_MRC_ADD_ROLE_W1_CH_BAND_TYPE GENMASK(21, 20) +#define RTW89_H2C_MRC_ADD_ROLE_W1_RFK_BY_PASS BIT(22) +#define RTW89_H2C_MRC_ADD_ROLE_W1_CAN_BTC BIT(23) +#define RTW89_H2C_MRC_ADD_ROLE_W1_NULL_EARLY GENMASK(31, 24) +#define RTW89_H2C_MRC_ADD_ROLE_W2_ALT_PERIOD GENMASK(7, 0) +#define RTW89_H2C_MRC_ADD_ROLE_W2_ALT_ROLE_TYPE GENMASK(15, 8) +#define RTW89_H2C_MRC_ADD_ROLE_W2_ALT_ROLE_MACID GENMASK(23, 16) + +struct rtw89_h2c_mrc_add_slot { + __le32 w0; + __le32 w1; + struct rtw89_h2c_mrc_add_role roles[]; +} __packed; + +#define RTW89_H2C_MRC_ADD_SLOT_W0_DURATION GENMASK(15, 0) +#define RTW89_H2C_MRC_ADD_SLOT_W0_COURTESY_EN BIT(17) +#define RTW89_H2C_MRC_ADD_SLOT_W0_ROLE_NUM GENMASK(31, 24) +#define RTW89_H2C_MRC_ADD_SLOT_W1_COURTESY_PERIOD GENMASK(7, 0) +#define RTW89_H2C_MRC_ADD_SLOT_W1_COURTESY_TARGET GENMASK(15, 8) + +struct rtw89_h2c_mrc_add { + __le32 w0; + /* Logically append flexible struct rtw89_h2c_mrc_add_slot, but there + * are other flexible array inside it. We cannot access them correctly + * through this struct. So, in case misusing, we don't really declare + * it here. + */ +} __packed; + +#define RTW89_H2C_MRC_ADD_W0_SCH_IDX GENMASK(3, 0) +#define RTW89_H2C_MRC_ADD_W0_SCH_TYPE GENMASK(7, 4) +#define RTW89_H2C_MRC_ADD_W0_SLOT_NUM GENMASK(15, 8) +#define RTW89_H2C_MRC_ADD_W0_BTC_IN_SCH BIT(16) + +enum rtw89_h2c_mrc_start_actions { + RTW89_H2C_MRC_START_ACTION_START_NEW = 0, + RTW89_H2C_MRC_START_ACTION_REPLACE_OLD = 1, +}; + +struct rtw89_h2c_mrc_start { + __le32 w0; + __le32 start_tsf_low; + __le32 start_tsf_high; +} __packed; + +#define RTW89_H2C_MRC_START_W0_SCH_IDX GENMASK(3, 0) +#define RTW89_H2C_MRC_START_W0_OLD_SCH_IDX GENMASK(7, 4) +#define RTW89_H2C_MRC_START_W0_ACTION GENMASK(15, 8) + +struct rtw89_h2c_mrc_del { + __le32 w0; +} __packed; + +#define RTW89_H2C_MRC_DEL_W0_SCH_IDX GENMASK(3, 0) +#define RTW89_H2C_MRC_DEL_W0_DEL_ALL BIT(4) +#define RTW89_H2C_MRC_DEL_W0_STOP_ONLY BIT(5) +#define RTW89_H2C_MRC_DEL_W0_SPECIFIC_ROLE_EN BIT(6) +#define RTW89_H2C_MRC_DEL_W0_STOP_SLOT_IDX GENMASK(15, 8) +#define RTW89_H2C_MRC_DEL_W0_SPECIFIC_ROLE_MACID GENMASK(31, 16) + +struct rtw89_h2c_mrc_req_tsf { + u8 req_tsf_num; + u8 infos[] __counted_by(req_tsf_num); +} __packed; + +#define RTW89_H2C_MRC_REQ_TSF_INFO_BAND GENMASK(3, 0) +#define RTW89_H2C_MRC_REQ_TSF_INFO_PORT GENMASK(7, 4) + +enum rtw89_h2c_mrc_upd_bitmap_actions { + RTW89_H2C_MRC_UPD_BITMAP_ACTION_DEL = 0, + RTW89_H2C_MRC_UPD_BITMAP_ACTION_ADD = 1, +}; + +struct rtw89_h2c_mrc_upd_bitmap { + __le32 w0; + __le32 w1; +} __packed; + +#define RTW89_H2C_MRC_UPD_BITMAP_W0_SCH_IDX GENMASK(3, 0) +#define RTW89_H2C_MRC_UPD_BITMAP_W0_ACTION BIT(4) +#define RTW89_H2C_MRC_UPD_BITMAP_W0_MACID GENMASK(31, 16) +#define RTW89_H2C_MRC_UPD_BITMAP_W1_CLIENT_MACID GENMASK(15, 0) + +struct rtw89_h2c_mrc_sync { + __le32 w0; + __le32 w1; +} __packed; + +#define RTW89_H2C_MRC_SYNC_W0_SYNC_EN BIT(0) +#define RTW89_H2C_MRC_SYNC_W0_SRC_PORT GENMASK(11, 8) +#define RTW89_H2C_MRC_SYNC_W0_SRC_BAND GENMASK(15, 12) +#define RTW89_H2C_MRC_SYNC_W0_DEST_PORT GENMASK(19, 16) +#define RTW89_H2C_MRC_SYNC_W0_DEST_BAND GENMASK(23, 20) +#define RTW89_H2C_MRC_SYNC_W1_OFFSET GENMASK(15, 0) + +struct rtw89_h2c_mrc_upd_duration { + __le32 w0; + __le32 start_tsf_low; + __le32 start_tsf_high; + __le32 slots[]; +} __packed; + +#define RTW89_H2C_MRC_UPD_DURATION_W0_SCH_IDX GENMASK(3, 0) +#define RTW89_H2C_MRC_UPD_DURATION_W0_SLOT_NUM GENMASK(15, 8) +#define RTW89_H2C_MRC_UPD_DURATION_W0_BTC_IN_SCH BIT(16) +#define RTW89_H2C_MRC_UPD_DURATION_SLOT_SLOT_IDX GENMASK(7, 0) +#define RTW89_H2C_MRC_UPD_DURATION_SLOT_DURATION GENMASK(31, 16) + #define RTW89_C2H_HEADER_LEN 8 struct rtw89_c2h_hdr { @@ -3573,6 +3710,29 @@ static_assert(sizeof(struct rtw89_mac_mcc_tsf_rpt) <= RTW89_COMPLETION_BUF_SIZE) #define RTW89_GET_MAC_C2H_MCC_STATUS_RPT_TSF_HIGH(c2h) \ le32_get_bits(*((const __le32 *)(c2h) + 4), GENMASK(31, 0)) +struct rtw89_c2h_mrc_tsf_rpt_info { + __le32 tsf_low; + __le32 tsf_high; +} __packed; + +struct rtw89_c2h_mrc_tsf_rpt { + struct rtw89_c2h_hdr hdr; + __le32 w2; + struct rtw89_c2h_mrc_tsf_rpt_info infos[]; +} __packed; + +#define RTW89_C2H_MRC_TSF_RPT_W2_REQ_TSF_NUM GENMASK(7, 0) + +struct rtw89_c2h_mrc_status_rpt { + struct rtw89_c2h_hdr hdr; + __le32 w2; + __le32 tsf_low; + __le32 tsf_high; +} __packed; + +#define RTW89_C2H_MRC_STATUS_RPT_W2_STATUS GENMASK(5, 0) +#define RTW89_C2H_MRC_STATUS_RPT_W2_SCH_IDX GENMASK(7, 6) + struct rtw89_c2h_pkt_ofld_rsp { __le32 w0; __le32 w1; @@ -3959,6 +4119,18 @@ enum rtw89_mcc_h2c_func { #define RTW89_MCC_WAIT_COND(group, func) \ ((group) * NUM_OF_RTW89_MCC_H2C_FUNC + (func)) +/* CLASS 24 - MRC */ +#define H2C_CL_MRC 0x18 +enum rtw89_mrc_h2c_func { + H2C_FUNC_MRC_REQ_TSF = 0x0, + H2C_FUNC_ADD_MRC = 0x1, + H2C_FUNC_START_MRC = 0x2, + H2C_FUNC_DEL_MRC = 0x3, + H2C_FUNC_MRC_SYNC = 0x4, + H2C_FUNC_MRC_UPD_DURATION = 0x5, + H2C_FUNC_MRC_UPD_BITMAP = 0x6, +}; + #define H2C_CAT_OUTSRC 0x2 #define H2C_CL_OUTSRC_RA 0x1 diff --git a/drivers/net/wireless/realtek/rtw89/mac.h b/drivers/net/wireless/realtek/rtw89/mac.h index c5ebac1d5990..12318d850475 100644 --- a/drivers/net/wireless/realtek/rtw89/mac.h +++ b/drivers/net/wireless/realtek/rtw89/mac.h @@ -406,13 +406,19 @@ enum rtw89_mac_c2h_mcc_func { NUM_OF_RTW89_MAC_C2H_FUNC_MCC, }; +enum rtw89_mac_c2h_mrc_func { + RTW89_MAC_C2H_FUNC_MRC_TSF_RPT = 0, + RTW89_MAC_C2H_FUNC_MRC_STATUS_RPT = 1, +}; + enum rtw89_mac_c2h_class { - RTW89_MAC_C2H_CLASS_INFO, - RTW89_MAC_C2H_CLASS_OFLD, - RTW89_MAC_C2H_CLASS_TWT, - RTW89_MAC_C2H_CLASS_WOW, - RTW89_MAC_C2H_CLASS_MCC, - RTW89_MAC_C2H_CLASS_FWDBG, + RTW89_MAC_C2H_CLASS_INFO = 0x0, + RTW89_MAC_C2H_CLASS_OFLD = 0x1, + RTW89_MAC_C2H_CLASS_TWT = 0x2, + RTW89_MAC_C2H_CLASS_WOW = 0x3, + RTW89_MAC_C2H_CLASS_MCC = 0x4, + RTW89_MAC_C2H_CLASS_FWDBG = 0x5, + RTW89_MAC_C2H_CLASS_MRC = 0xe, RTW89_MAC_C2H_CLASS_MAX, }; @@ -441,6 +447,12 @@ enum rtw89_mac_mcc_status { RTW89_MAC_MCC_TXNULL1_FAIL = 27, }; +enum rtw89_mac_mrc_status { + RTW89_MAC_MRC_START_SCH_OK = 0, + RTW89_MAC_MRC_STOP_SCH_OK = 1, + RTW89_MAC_MRC_DEL_SCH_OK = 2, +}; + struct rtw89_mac_ax_coex { #define RTW89_MAC_AX_COEX_RTK_MODE 0 #define RTW89_MAC_AX_COEX_CSR_MODE 1 -- cgit v1.2.3 From b8e59e55345878747b6de944e785728fb215b26c Mon Sep 17 00:00:00 2001 From: Zong-Zhe Yang Date: Tue, 13 Feb 2024 15:35:11 +0800 Subject: wifi: rtw89: mac: implement MRC C2H event handling Add handling of MRC (multiple role concurrent) C2H events including TSF report and status report. Parse report data and then complete the corresponding H2C commands, which will be implemented in the following. Signed-off-by: Zong-Zhe Yang Signed-off-by: Ping-Ke Shih Signed-off-by: Kalle Valo Link: https://msgid.link/20240213073514.23796-3-pkshih@realtek.com --- drivers/net/wireless/realtek/rtw89/core.h | 2 +- drivers/net/wireless/realtek/rtw89/fw.h | 18 ++++++ drivers/net/wireless/realtek/rtw89/mac.c | 91 +++++++++++++++++++++++++++++++ drivers/net/wireless/realtek/rtw89/mac.h | 2 + 4 files changed, 112 insertions(+), 1 deletion(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/realtek/rtw89/core.h b/drivers/net/wireless/realtek/rtw89/core.h index e3913efedc28..6269ae2539b2 100644 --- a/drivers/net/wireless/realtek/rtw89/core.h +++ b/drivers/net/wireless/realtek/rtw89/core.h @@ -3918,7 +3918,7 @@ enum rtw89_host_rpr_mode { RTW89_RPR_MODE_STF }; -#define RTW89_COMPLETION_BUF_SIZE 24 +#define RTW89_COMPLETION_BUF_SIZE 40 #define RTW89_WAIT_COND_IDLE UINT_MAX struct rtw89_completion_data { diff --git a/drivers/net/wireless/realtek/rtw89/fw.h b/drivers/net/wireless/realtek/rtw89/fw.h index 409f62cea0d7..d44df3897dd2 100644 --- a/drivers/net/wireless/realtek/rtw89/fw.h +++ b/drivers/net/wireless/realtek/rtw89/fw.h @@ -3474,6 +3474,8 @@ struct rtw89_h2c_mrc_del { #define RTW89_H2C_MRC_DEL_W0_STOP_SLOT_IDX GENMASK(15, 8) #define RTW89_H2C_MRC_DEL_W0_SPECIFIC_ROLE_MACID GENMASK(31, 16) +#define RTW89_MAC_MRC_MAX_REQ_TSF_NUM 2 + struct rtw89_h2c_mrc_req_tsf { u8 req_tsf_num; u8 infos[] __counted_by(req_tsf_num); @@ -3710,6 +3712,13 @@ static_assert(sizeof(struct rtw89_mac_mcc_tsf_rpt) <= RTW89_COMPLETION_BUF_SIZE) #define RTW89_GET_MAC_C2H_MCC_STATUS_RPT_TSF_HIGH(c2h) \ le32_get_bits(*((const __le32 *)(c2h) + 4), GENMASK(31, 0)) +struct rtw89_mac_mrc_tsf_rpt { + unsigned int num; + u64 tsfs[RTW89_MAC_MRC_MAX_REQ_TSF_NUM]; +}; + +static_assert(sizeof(struct rtw89_mac_mrc_tsf_rpt) <= RTW89_COMPLETION_BUF_SIZE); + struct rtw89_c2h_mrc_tsf_rpt_info { __le32 tsf_low; __le32 tsf_high; @@ -4129,8 +4138,17 @@ enum rtw89_mrc_h2c_func { H2C_FUNC_MRC_SYNC = 0x4, H2C_FUNC_MRC_UPD_DURATION = 0x5, H2C_FUNC_MRC_UPD_BITMAP = 0x6, + + NUM_OF_RTW89_MRC_H2C_FUNC, }; +/* can consider MRC's sch_idx as MCC's group */ +#define RTW89_MRC_WAIT_COND(sch_idx, func) \ + ((sch_idx) * NUM_OF_RTW89_MRC_H2C_FUNC + (func)) + +#define RTW89_MRC_WAIT_COND_REQ_TSF \ + RTW89_MRC_WAIT_COND(0 /* don't care */, H2C_FUNC_MRC_REQ_TSF) + #define H2C_CAT_OUTSRC 0x2 #define H2C_CL_OUTSRC_RA 0x1 diff --git a/drivers/net/wireless/realtek/rtw89/mac.c b/drivers/net/wireless/realtek/rtw89/mac.c index 3ea50d49e12f..908245ac46bd 100644 --- a/drivers/net/wireless/realtek/rtw89/mac.c +++ b/drivers/net/wireless/realtek/rtw89/mac.c @@ -5099,6 +5099,84 @@ rtw89_mac_c2h_mcc_status_rpt(struct rtw89_dev *rtwdev, struct sk_buff *c2h, u32 rtw89_complete_cond(&rtwdev->mcc.wait, cond, &data); } +static void +rtw89_mac_c2h_mrc_tsf_rpt(struct rtw89_dev *rtwdev, struct sk_buff *c2h, u32 len) +{ + struct rtw89_wait_info *wait = &rtwdev->mcc.wait; + const struct rtw89_c2h_mrc_tsf_rpt *c2h_rpt; + struct rtw89_completion_data data = {}; + struct rtw89_mac_mrc_tsf_rpt *rpt; + unsigned int i; + + c2h_rpt = (const struct rtw89_c2h_mrc_tsf_rpt *)c2h->data; + rpt = (struct rtw89_mac_mrc_tsf_rpt *)data.buf; + rpt->num = min_t(u8, RTW89_MAC_MRC_MAX_REQ_TSF_NUM, + le32_get_bits(c2h_rpt->w2, + RTW89_C2H_MRC_TSF_RPT_W2_REQ_TSF_NUM)); + + for (i = 0; i < rpt->num; i++) { + u32 tsf_high = le32_to_cpu(c2h_rpt->infos[i].tsf_high); + u32 tsf_low = le32_to_cpu(c2h_rpt->infos[i].tsf_low); + + rpt->tsfs[i] = (u64)tsf_high << 32 | tsf_low; + + rtw89_debug(rtwdev, RTW89_DBG_CHAN, + "MRC C2H TSF RPT: index %u> %llu\n", + i, rpt->tsfs[i]); + } + + rtw89_complete_cond(wait, RTW89_MRC_WAIT_COND_REQ_TSF, &data); +} + +static void +rtw89_mac_c2h_mrc_status_rpt(struct rtw89_dev *rtwdev, struct sk_buff *c2h, u32 len) +{ + struct rtw89_wait_info *wait = &rtwdev->mcc.wait; + const struct rtw89_c2h_mrc_status_rpt *c2h_rpt; + struct rtw89_completion_data data = {}; + enum rtw89_mac_mrc_status status; + unsigned int cond; + bool next = false; + u32 tsf_high; + u32 tsf_low; + u8 sch_idx; + u8 func; + + c2h_rpt = (const struct rtw89_c2h_mrc_status_rpt *)c2h->data; + sch_idx = le32_get_bits(c2h_rpt->w2, RTW89_C2H_MRC_STATUS_RPT_W2_SCH_IDX); + status = le32_get_bits(c2h_rpt->w2, RTW89_C2H_MRC_STATUS_RPT_W2_STATUS); + tsf_high = le32_to_cpu(c2h_rpt->tsf_high); + tsf_low = le32_to_cpu(c2h_rpt->tsf_low); + + switch (status) { + case RTW89_MAC_MRC_START_SCH_OK: + func = H2C_FUNC_START_MRC; + break; + case RTW89_MAC_MRC_STOP_SCH_OK: + /* H2C_FUNC_DEL_MRC without STOP_ONLY, so wait for DEL_SCH_OK */ + func = H2C_FUNC_DEL_MRC; + next = true; + break; + case RTW89_MAC_MRC_DEL_SCH_OK: + func = H2C_FUNC_DEL_MRC; + break; + default: + rtw89_debug(rtwdev, RTW89_DBG_CHAN, + "invalid MRC C2H STS RPT: status %d\n", status); + return; + } + + rtw89_debug(rtwdev, RTW89_DBG_CHAN, + "MRC C2H STS RPT: sch_idx %d, status %d, tsf %llu\n", + sch_idx, status, (u64)tsf_high << 32 | tsf_low); + + if (next) + return; + + cond = RTW89_MRC_WAIT_COND(sch_idx, func); + rtw89_complete_cond(wait, cond, &data); +} + static void (* const rtw89_mac_c2h_ofld_handler[])(struct rtw89_dev *rtwdev, struct sk_buff *c2h, u32 len) = { @@ -5130,6 +5208,13 @@ void (* const rtw89_mac_c2h_mcc_handler[])(struct rtw89_dev *rtwdev, [RTW89_MAC_C2H_FUNC_MCC_STATUS_RPT] = rtw89_mac_c2h_mcc_status_rpt, }; +static +void (* const rtw89_mac_c2h_mrc_handler[])(struct rtw89_dev *rtwdev, + struct sk_buff *c2h, u32 len) = { + [RTW89_MAC_C2H_FUNC_MRC_TSF_RPT] = rtw89_mac_c2h_mrc_tsf_rpt, + [RTW89_MAC_C2H_FUNC_MRC_STATUS_RPT] = rtw89_mac_c2h_mrc_status_rpt, +}; + static void rtw89_mac_c2h_scanofld_rsp_atomic(struct rtw89_dev *rtwdev, struct sk_buff *skb) { @@ -5180,6 +5265,8 @@ bool rtw89_mac_c2h_chk_atomic(struct rtw89_dev *rtwdev, struct sk_buff *c2h, } case RTW89_MAC_C2H_CLASS_MCC: return true; + case RTW89_MAC_C2H_CLASS_MRC: + return true; } } @@ -5202,6 +5289,10 @@ void rtw89_mac_c2h_handle(struct rtw89_dev *rtwdev, struct sk_buff *skb, if (func < NUM_OF_RTW89_MAC_C2H_FUNC_MCC) handler = rtw89_mac_c2h_mcc_handler[func]; break; + case RTW89_MAC_C2H_CLASS_MRC: + if (func < NUM_OF_RTW89_MAC_C2H_FUNC_MRC) + handler = rtw89_mac_c2h_mrc_handler[func]; + break; case RTW89_MAC_C2H_CLASS_FWDBG: return; default: diff --git a/drivers/net/wireless/realtek/rtw89/mac.h b/drivers/net/wireless/realtek/rtw89/mac.h index 12318d850475..db95509fad2f 100644 --- a/drivers/net/wireless/realtek/rtw89/mac.h +++ b/drivers/net/wireless/realtek/rtw89/mac.h @@ -409,6 +409,8 @@ enum rtw89_mac_c2h_mcc_func { enum rtw89_mac_c2h_mrc_func { RTW89_MAC_C2H_FUNC_MRC_TSF_RPT = 0, RTW89_MAC_C2H_FUNC_MRC_STATUS_RPT = 1, + + NUM_OF_RTW89_MAC_C2H_FUNC_MRC, }; enum rtw89_mac_c2h_class { -- cgit v1.2.3 From 9de7829aa6fa78402f4efef60d919b1f8b54bbdb Mon Sep 17 00:00:00 2001 From: Zong-Zhe Yang Date: Tue, 13 Feb 2024 15:35:12 +0800 Subject: wifi: rtw89: fw: implement MRC H2C command functions Implement MRC (multiple role concurrent) H2C commands. Mainly deal with H2C format, LE type built from CPU value, default setting on some fields, and then sending the command to FW. Besides, MRC start, MRC delete, and MRC request TSF need to wait for a report from C2H events. Signed-off-by: Zong-Zhe Yang Signed-off-by: Ping-Ke Shih Signed-off-by: Kalle Valo Link: https://msgid.link/20240213073514.23796-4-pkshih@realtek.com --- drivers/net/wireless/realtek/rtw89/fw.c | 366 ++++++++++++++++++++++++++++++++ drivers/net/wireless/realtek/rtw89/fw.h | 94 ++++++++ 2 files changed, 460 insertions(+) (limited to 'drivers/net') diff --git a/drivers/net/wireless/realtek/rtw89/fw.c b/drivers/net/wireless/realtek/rtw89/fw.c index 540ea16f048e..2ab45d0878f7 100644 --- a/drivers/net/wireless/realtek/rtw89/fw.c +++ b/drivers/net/wireless/realtek/rtw89/fw.c @@ -6669,6 +6669,372 @@ int rtw89_fw_h2c_mcc_set_duration(struct rtw89_dev *rtwdev, return rtw89_h2c_tx_and_wait(rtwdev, skb, wait, cond); } +static +u32 rtw89_fw_h2c_mrc_add_slot(struct rtw89_dev *rtwdev, + const struct rtw89_fw_mrc_add_slot_arg *slot_arg, + struct rtw89_h2c_mrc_add_slot *slot_h2c) +{ + bool fill_h2c = !!slot_h2c; + unsigned int i; + + if (!fill_h2c) + goto calc_len; + + slot_h2c->w0 = le32_encode_bits(slot_arg->duration, + RTW89_H2C_MRC_ADD_SLOT_W0_DURATION) | + le32_encode_bits(slot_arg->courtesy_en, + RTW89_H2C_MRC_ADD_SLOT_W0_COURTESY_EN) | + le32_encode_bits(slot_arg->role_num, + RTW89_H2C_MRC_ADD_SLOT_W0_ROLE_NUM); + slot_h2c->w1 = le32_encode_bits(slot_arg->courtesy_period, + RTW89_H2C_MRC_ADD_SLOT_W1_COURTESY_PERIOD) | + le32_encode_bits(slot_arg->courtesy_target, + RTW89_H2C_MRC_ADD_SLOT_W1_COURTESY_TARGET); + + for (i = 0; i < slot_arg->role_num; i++) { + slot_h2c->roles[i].w0 = + le32_encode_bits(slot_arg->roles[i].macid, + RTW89_H2C_MRC_ADD_ROLE_W0_MACID) | + le32_encode_bits(slot_arg->roles[i].role_type, + RTW89_H2C_MRC_ADD_ROLE_W0_ROLE_TYPE) | + le32_encode_bits(slot_arg->roles[i].is_master, + RTW89_H2C_MRC_ADD_ROLE_W0_IS_MASTER) | + le32_encode_bits(slot_arg->roles[i].en_tx_null, + RTW89_H2C_MRC_ADD_ROLE_W0_TX_NULL_EN) | + le32_encode_bits(false, + RTW89_H2C_MRC_ADD_ROLE_W0_IS_ALT_ROLE) | + le32_encode_bits(false, + RTW89_H2C_MRC_ADD_ROLE_W0_ROLE_ALT_EN); + slot_h2c->roles[i].w1 = + le32_encode_bits(slot_arg->roles[i].central_ch, + RTW89_H2C_MRC_ADD_ROLE_W1_CENTRAL_CH_SEG) | + le32_encode_bits(slot_arg->roles[i].primary_ch, + RTW89_H2C_MRC_ADD_ROLE_W1_PRI_CH) | + le32_encode_bits(slot_arg->roles[i].bw, + RTW89_H2C_MRC_ADD_ROLE_W1_BW) | + le32_encode_bits(slot_arg->roles[i].band, + RTW89_H2C_MRC_ADD_ROLE_W1_CH_BAND_TYPE) | + le32_encode_bits(slot_arg->roles[i].null_early, + RTW89_H2C_MRC_ADD_ROLE_W1_NULL_EARLY) | + le32_encode_bits(false, + RTW89_H2C_MRC_ADD_ROLE_W1_RFK_BY_PASS) | + le32_encode_bits(true, + RTW89_H2C_MRC_ADD_ROLE_W1_CAN_BTC); + slot_h2c->roles[i].macid_main_bitmap = + cpu_to_le32(slot_arg->roles[i].macid_main_bitmap); + slot_h2c->roles[i].macid_paired_bitmap = + cpu_to_le32(slot_arg->roles[i].macid_paired_bitmap); + } + +calc_len: + return struct_size(slot_h2c, roles, slot_arg->role_num); +} + +int rtw89_fw_h2c_mrc_add(struct rtw89_dev *rtwdev, + const struct rtw89_fw_mrc_add_arg *arg) +{ + struct rtw89_h2c_mrc_add *h2c_head; + struct sk_buff *skb; + unsigned int i; + void *tmp; + u32 len; + int ret; + + len = sizeof(*h2c_head); + for (i = 0; i < arg->slot_num; i++) + len += rtw89_fw_h2c_mrc_add_slot(rtwdev, &arg->slots[i], NULL); + + skb = rtw89_fw_h2c_alloc_skb_with_hdr(rtwdev, len); + if (!skb) { + rtw89_err(rtwdev, "failed to alloc skb for mrc add\n"); + return -ENOMEM; + } + + skb_put(skb, len); + tmp = skb->data; + + h2c_head = tmp; + h2c_head->w0 = le32_encode_bits(arg->sch_idx, + RTW89_H2C_MRC_ADD_W0_SCH_IDX) | + le32_encode_bits(arg->sch_type, + RTW89_H2C_MRC_ADD_W0_SCH_TYPE) | + le32_encode_bits(arg->slot_num, + RTW89_H2C_MRC_ADD_W0_SLOT_NUM) | + le32_encode_bits(arg->btc_in_sch, + RTW89_H2C_MRC_ADD_W0_BTC_IN_SCH); + + tmp += sizeof(*h2c_head); + for (i = 0; i < arg->slot_num; i++) + tmp += rtw89_fw_h2c_mrc_add_slot(rtwdev, &arg->slots[i], tmp); + + rtw89_h2c_pkt_set_hdr(rtwdev, skb, FWCMD_TYPE_H2C, + H2C_CAT_MAC, + H2C_CL_MRC, + H2C_FUNC_ADD_MRC, 0, 0, + len); + + ret = rtw89_h2c_tx(rtwdev, skb, false); + if (ret) { + rtw89_err(rtwdev, "failed to send h2c\n"); + dev_kfree_skb_any(skb); + return -EBUSY; + } + + return 0; +} + +int rtw89_fw_h2c_mrc_start(struct rtw89_dev *rtwdev, + const struct rtw89_fw_mrc_start_arg *arg) +{ + struct rtw89_wait_info *wait = &rtwdev->mcc.wait; + struct rtw89_h2c_mrc_start *h2c; + u32 len = sizeof(*h2c); + struct sk_buff *skb; + unsigned int cond; + + skb = rtw89_fw_h2c_alloc_skb_with_hdr(rtwdev, len); + if (!skb) { + rtw89_err(rtwdev, "failed to alloc skb for mrc start\n"); + return -ENOMEM; + } + + skb_put(skb, len); + h2c = (struct rtw89_h2c_mrc_start *)skb->data; + + h2c->w0 = le32_encode_bits(arg->sch_idx, + RTW89_H2C_MRC_START_W0_SCH_IDX) | + le32_encode_bits(arg->old_sch_idx, + RTW89_H2C_MRC_START_W0_OLD_SCH_IDX) | + le32_encode_bits(arg->action, + RTW89_H2C_MRC_START_W0_ACTION); + + h2c->start_tsf_high = cpu_to_le32(arg->start_tsf >> 32); + h2c->start_tsf_low = cpu_to_le32(arg->start_tsf); + + rtw89_h2c_pkt_set_hdr(rtwdev, skb, FWCMD_TYPE_H2C, + H2C_CAT_MAC, + H2C_CL_MRC, + H2C_FUNC_START_MRC, 0, 0, + len); + + cond = RTW89_MRC_WAIT_COND(arg->sch_idx, H2C_FUNC_START_MRC); + return rtw89_h2c_tx_and_wait(rtwdev, skb, wait, cond); +} + +int rtw89_fw_h2c_mrc_del(struct rtw89_dev *rtwdev, u8 sch_idx) +{ + struct rtw89_wait_info *wait = &rtwdev->mcc.wait; + struct rtw89_h2c_mrc_del *h2c; + u32 len = sizeof(*h2c); + struct sk_buff *skb; + unsigned int cond; + + skb = rtw89_fw_h2c_alloc_skb_with_hdr(rtwdev, len); + if (!skb) { + rtw89_err(rtwdev, "failed to alloc skb for mrc del\n"); + return -ENOMEM; + } + + skb_put(skb, len); + h2c = (struct rtw89_h2c_mrc_del *)skb->data; + + h2c->w0 = le32_encode_bits(sch_idx, RTW89_H2C_MRC_DEL_W0_SCH_IDX); + + rtw89_h2c_pkt_set_hdr(rtwdev, skb, FWCMD_TYPE_H2C, + H2C_CAT_MAC, + H2C_CL_MRC, + H2C_FUNC_DEL_MRC, 0, 0, + len); + + cond = RTW89_MRC_WAIT_COND(sch_idx, H2C_FUNC_DEL_MRC); + return rtw89_h2c_tx_and_wait(rtwdev, skb, wait, cond); +} + +int rtw89_fw_h2c_mrc_req_tsf(struct rtw89_dev *rtwdev, + const struct rtw89_fw_mrc_req_tsf_arg *arg, + struct rtw89_mac_mrc_tsf_rpt *rpt) +{ + struct rtw89_wait_info *wait = &rtwdev->mcc.wait; + struct rtw89_h2c_mrc_req_tsf *h2c; + struct rtw89_mac_mrc_tsf_rpt *tmp; + struct sk_buff *skb; + unsigned int i; + u32 len; + int ret; + + len = struct_size(h2c, infos, arg->num); + skb = rtw89_fw_h2c_alloc_skb_with_hdr(rtwdev, len); + if (!skb) { + rtw89_err(rtwdev, "failed to alloc skb for mrc req tsf\n"); + return -ENOMEM; + } + + skb_put(skb, len); + h2c = (struct rtw89_h2c_mrc_req_tsf *)skb->data; + + h2c->req_tsf_num = arg->num; + for (i = 0; i < arg->num; i++) + h2c->infos[i] = + u8_encode_bits(arg->infos[i].band, + RTW89_H2C_MRC_REQ_TSF_INFO_BAND) | + u8_encode_bits(arg->infos[i].port, + RTW89_H2C_MRC_REQ_TSF_INFO_PORT); + + rtw89_h2c_pkt_set_hdr(rtwdev, skb, FWCMD_TYPE_H2C, + H2C_CAT_MAC, + H2C_CL_MRC, + H2C_FUNC_MRC_REQ_TSF, 0, 0, + len); + + ret = rtw89_h2c_tx_and_wait(rtwdev, skb, wait, RTW89_MRC_WAIT_COND_REQ_TSF); + if (ret) + return ret; + + tmp = (struct rtw89_mac_mrc_tsf_rpt *)wait->data.buf; + *rpt = *tmp; + + return 0; +} + +int rtw89_fw_h2c_mrc_upd_bitmap(struct rtw89_dev *rtwdev, + const struct rtw89_fw_mrc_upd_bitmap_arg *arg) +{ + struct rtw89_h2c_mrc_upd_bitmap *h2c; + u32 len = sizeof(*h2c); + struct sk_buff *skb; + int ret; + + skb = rtw89_fw_h2c_alloc_skb_with_hdr(rtwdev, len); + if (!skb) { + rtw89_err(rtwdev, "failed to alloc skb for mrc upd bitmap\n"); + return -ENOMEM; + } + + skb_put(skb, len); + h2c = (struct rtw89_h2c_mrc_upd_bitmap *)skb->data; + + h2c->w0 = le32_encode_bits(arg->sch_idx, + RTW89_H2C_MRC_UPD_BITMAP_W0_SCH_IDX) | + le32_encode_bits(arg->action, + RTW89_H2C_MRC_UPD_BITMAP_W0_ACTION) | + le32_encode_bits(arg->macid, + RTW89_H2C_MRC_UPD_BITMAP_W0_MACID); + h2c->w1 = le32_encode_bits(arg->client_macid, + RTW89_H2C_MRC_UPD_BITMAP_W1_CLIENT_MACID); + + rtw89_h2c_pkt_set_hdr(rtwdev, skb, FWCMD_TYPE_H2C, + H2C_CAT_MAC, + H2C_CL_MRC, + H2C_FUNC_MRC_UPD_BITMAP, 0, 0, + len); + + ret = rtw89_h2c_tx(rtwdev, skb, false); + if (ret) { + rtw89_err(rtwdev, "failed to send h2c\n"); + dev_kfree_skb_any(skb); + return -EBUSY; + } + + return 0; +} + +int rtw89_fw_h2c_mrc_sync(struct rtw89_dev *rtwdev, + const struct rtw89_fw_mrc_sync_arg *arg) +{ + struct rtw89_h2c_mrc_sync *h2c; + u32 len = sizeof(*h2c); + struct sk_buff *skb; + int ret; + + skb = rtw89_fw_h2c_alloc_skb_with_hdr(rtwdev, len); + if (!skb) { + rtw89_err(rtwdev, "failed to alloc skb for mrc sync\n"); + return -ENOMEM; + } + + skb_put(skb, len); + h2c = (struct rtw89_h2c_mrc_sync *)skb->data; + + h2c->w0 = le32_encode_bits(true, RTW89_H2C_MRC_SYNC_W0_SYNC_EN) | + le32_encode_bits(arg->src.port, + RTW89_H2C_MRC_SYNC_W0_SRC_PORT) | + le32_encode_bits(arg->src.band, + RTW89_H2C_MRC_SYNC_W0_SRC_BAND) | + le32_encode_bits(arg->dest.port, + RTW89_H2C_MRC_SYNC_W0_DEST_PORT) | + le32_encode_bits(arg->dest.band, + RTW89_H2C_MRC_SYNC_W0_DEST_BAND); + h2c->w1 = le32_encode_bits(arg->offset, RTW89_H2C_MRC_SYNC_W1_OFFSET); + + rtw89_h2c_pkt_set_hdr(rtwdev, skb, FWCMD_TYPE_H2C, + H2C_CAT_MAC, + H2C_CL_MRC, + H2C_FUNC_MRC_SYNC, 0, 0, + len); + + ret = rtw89_h2c_tx(rtwdev, skb, false); + if (ret) { + rtw89_err(rtwdev, "failed to send h2c\n"); + dev_kfree_skb_any(skb); + return -EBUSY; + } + + return 0; +} + +int rtw89_fw_h2c_mrc_upd_duration(struct rtw89_dev *rtwdev, + const struct rtw89_fw_mrc_upd_duration_arg *arg) +{ + struct rtw89_h2c_mrc_upd_duration *h2c; + struct sk_buff *skb; + unsigned int i; + u32 len; + int ret; + + len = struct_size(h2c, slots, arg->slot_num); + skb = rtw89_fw_h2c_alloc_skb_with_hdr(rtwdev, len); + if (!skb) { + rtw89_err(rtwdev, "failed to alloc skb for mrc upd duration\n"); + return -ENOMEM; + } + + skb_put(skb, len); + h2c = (struct rtw89_h2c_mrc_upd_duration *)skb->data; + + h2c->w0 = le32_encode_bits(arg->sch_idx, + RTW89_H2C_MRC_UPD_DURATION_W0_SCH_IDX) | + le32_encode_bits(arg->slot_num, + RTW89_H2C_MRC_UPD_DURATION_W0_SLOT_NUM) | + le32_encode_bits(false, + RTW89_H2C_MRC_UPD_DURATION_W0_BTC_IN_SCH); + + h2c->start_tsf_high = cpu_to_le32(arg->start_tsf >> 32); + h2c->start_tsf_low = cpu_to_le32(arg->start_tsf); + + for (i = 0; i < arg->slot_num; i++) { + h2c->slots[i] = + le32_encode_bits(arg->slots[i].slot_idx, + RTW89_H2C_MRC_UPD_DURATION_SLOT_SLOT_IDX) | + le32_encode_bits(arg->slots[i].duration, + RTW89_H2C_MRC_UPD_DURATION_SLOT_DURATION); + } + + rtw89_h2c_pkt_set_hdr(rtwdev, skb, FWCMD_TYPE_H2C, + H2C_CAT_MAC, + H2C_CL_MRC, + H2C_FUNC_MRC_UPD_DURATION, 0, 0, + len); + + ret = rtw89_h2c_tx(rtwdev, skb, false); + if (ret) { + rtw89_err(rtwdev, "failed to send h2c\n"); + dev_kfree_skb_any(skb); + return -EBUSY; + } + + return 0; +} + static bool __fw_txpwr_entry_zero_ext(const void *ext_ptr, u8 ext_len) { static const u8 zeros[U8_MAX] = {}; diff --git a/drivers/net/wireless/realtek/rtw89/fw.h b/drivers/net/wireless/realtek/rtw89/fw.h index d44df3897dd2..9c5464dcc081 100644 --- a/drivers/net/wireless/realtek/rtw89/fw.h +++ b/drivers/net/wireless/realtek/rtw89/fw.h @@ -3397,6 +3397,45 @@ enum rtw89_h2c_mrc_role_types { RTW89_H2C_MRC_ROLE_EMPTY = 2, }; +#define RTW89_MAC_MRC_MAX_ADD_SLOT_NUM 3 +#define RTW89_MAC_MRC_MAX_ADD_ROLE_NUM_PER_SLOT 1 /* before MLO */ + +struct rtw89_fw_mrc_add_slot_arg { + u16 duration; /* unit: TU */ + bool courtesy_en; + u8 courtesy_period; + u8 courtesy_target; /* slot idx */ + + unsigned int role_num; + struct { + enum rtw89_h2c_mrc_role_types role_type; + bool is_master; + bool en_tx_null; + enum rtw89_band band; + enum rtw89_bandwidth bw; + u8 macid; + u8 central_ch; + u8 primary_ch; + u8 null_early; /* unit: TU */ + + /* if MLD, for macid: [0, chip::support_mld_num) + * otherwise, for macid: [0, 32) + */ + u32 macid_main_bitmap; + /* for MLD, bit X maps to macid: X + chip::support_mld_num */ + u32 macid_paired_bitmap; + } roles[RTW89_MAC_MRC_MAX_ADD_ROLE_NUM_PER_SLOT]; +}; + +struct rtw89_fw_mrc_add_arg { + u8 sch_idx; + enum rtw89_h2c_mrc_sch_types sch_type; + bool btc_in_sch; + + unsigned int slot_num; + struct rtw89_fw_mrc_add_slot_arg slots[RTW89_MAC_MRC_MAX_ADD_SLOT_NUM]; +}; + struct rtw89_h2c_mrc_add_role { __le32 w0; __le32 w1; @@ -3453,6 +3492,13 @@ enum rtw89_h2c_mrc_start_actions { RTW89_H2C_MRC_START_ACTION_REPLACE_OLD = 1, }; +struct rtw89_fw_mrc_start_arg { + u8 sch_idx; + u8 old_sch_idx; + u64 start_tsf; + enum rtw89_h2c_mrc_start_actions action; +}; + struct rtw89_h2c_mrc_start { __le32 w0; __le32 start_tsf_low; @@ -3476,6 +3522,14 @@ struct rtw89_h2c_mrc_del { #define RTW89_MAC_MRC_MAX_REQ_TSF_NUM 2 +struct rtw89_fw_mrc_req_tsf_arg { + unsigned int num; + struct { + u8 band; + u8 port; + } infos[RTW89_MAC_MRC_MAX_REQ_TSF_NUM]; +}; + struct rtw89_h2c_mrc_req_tsf { u8 req_tsf_num; u8 infos[] __counted_by(req_tsf_num); @@ -3489,6 +3543,13 @@ enum rtw89_h2c_mrc_upd_bitmap_actions { RTW89_H2C_MRC_UPD_BITMAP_ACTION_ADD = 1, }; +struct rtw89_fw_mrc_upd_bitmap_arg { + u8 sch_idx; + u8 macid; + u8 client_macid; + enum rtw89_h2c_mrc_upd_bitmap_actions action; +}; + struct rtw89_h2c_mrc_upd_bitmap { __le32 w0; __le32 w1; @@ -3499,6 +3560,14 @@ struct rtw89_h2c_mrc_upd_bitmap { #define RTW89_H2C_MRC_UPD_BITMAP_W0_MACID GENMASK(31, 16) #define RTW89_H2C_MRC_UPD_BITMAP_W1_CLIENT_MACID GENMASK(15, 0) +struct rtw89_fw_mrc_sync_arg { + u8 offset; /* unit: TU */ + struct { + u8 band; + u8 port; + } src, dest; +}; + struct rtw89_h2c_mrc_sync { __le32 w0; __le32 w1; @@ -3511,6 +3580,17 @@ struct rtw89_h2c_mrc_sync { #define RTW89_H2C_MRC_SYNC_W0_DEST_BAND GENMASK(23, 20) #define RTW89_H2C_MRC_SYNC_W1_OFFSET GENMASK(15, 0) +struct rtw89_fw_mrc_upd_duration_arg { + u8 sch_idx; + u64 start_tsf; + + unsigned int slot_num; + struct { + u8 slot_idx; + u16 duration; /* unit: TU */ + } slots[RTW89_MAC_MRC_MAX_ADD_SLOT_NUM]; +}; + struct rtw89_h2c_mrc_upd_duration { __le32 w0; __le32 start_tsf_low; @@ -4565,6 +4645,20 @@ int rtw89_fw_h2c_mcc_sync(struct rtw89_dev *rtwdev, u8 group, u8 source, u8 target, u8 offset); int rtw89_fw_h2c_mcc_set_duration(struct rtw89_dev *rtwdev, const struct rtw89_fw_mcc_duration *p); +int rtw89_fw_h2c_mrc_add(struct rtw89_dev *rtwdev, + const struct rtw89_fw_mrc_add_arg *arg); +int rtw89_fw_h2c_mrc_start(struct rtw89_dev *rtwdev, + const struct rtw89_fw_mrc_start_arg *arg); +int rtw89_fw_h2c_mrc_del(struct rtw89_dev *rtwdev, u8 sch_idx); +int rtw89_fw_h2c_mrc_req_tsf(struct rtw89_dev *rtwdev, + const struct rtw89_fw_mrc_req_tsf_arg *arg, + struct rtw89_mac_mrc_tsf_rpt *rpt); +int rtw89_fw_h2c_mrc_upd_bitmap(struct rtw89_dev *rtwdev, + const struct rtw89_fw_mrc_upd_bitmap_arg *arg); +int rtw89_fw_h2c_mrc_sync(struct rtw89_dev *rtwdev, + const struct rtw89_fw_mrc_sync_arg *arg); +int rtw89_fw_h2c_mrc_upd_duration(struct rtw89_dev *rtwdev, + const struct rtw89_fw_mrc_upd_duration_arg *arg); static inline void rtw89_fw_h2c_init_ba_cam(struct rtw89_dev *rtwdev) { -- cgit v1.2.3 From f931cce310e0beb2d4b9f2b60b3e3ce69ff87dfb Mon Sep 17 00:00:00 2001 From: Zong-Zhe Yang Date: Tue, 13 Feb 2024 15:35:13 +0800 Subject: wifi: rtw89: chan: support MCC on Wi-Fi 7 chips On Wi-Fi 7 chips, concurrent stuffs are supported by FW MRC series (multi-role concurrent) functions. And, driver has implemented the corresponding SW handling in patches in front of this one. Now, we extend SW MCC (multi-channel concurrent) flow to work on Wi-Fi 7 chips. In SW point of view, things look as below. | SW | | FW func | | | | H2C/C2H | -------------------------------------------- | | ax | | | /----| FW MCC func | | MCC | -- chip --+ | | | \----| FW MRC func | | | be | Signed-off-by: Zong-Zhe Yang Signed-off-by: Ping-Ke Shih Signed-off-by: Kalle Valo Link: https://msgid.link/20240213073514.23796-5-pkshih@realtek.com --- drivers/net/wireless/realtek/rtw89/chan.c | 440 ++++++++++++++++++++++++++++-- drivers/net/wireless/realtek/rtw89/core.h | 7 + 2 files changed, 420 insertions(+), 27 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/realtek/rtw89/chan.c b/drivers/net/wireless/realtek/rtw89/chan.c index 7b9baf4db70f..051a3cad6101 100644 --- a/drivers/net/wireless/realtek/rtw89/chan.c +++ b/drivers/net/wireless/realtek/rtw89/chan.c @@ -322,6 +322,13 @@ static void rtw89_chanctx_notify(struct rtw89_dev *rtwdev, } } +static bool rtw89_concurrent_via_mrc(struct rtw89_dev *rtwdev) +{ + enum rtw89_chip_gen chip_gen = rtwdev->chip->chip_gen; + + return chip_gen == RTW89_CHIP_BE; +} + /* This function centrally manages how MCC roles are sorted and iterated. * And, it guarantees that ordered_idx is less than NUM_OF_RTW89_MCC_ROLES. * So, if data needs to pass an array for ordered_idx, the array can declare @@ -374,16 +381,13 @@ static u32 rtw89_mcc_get_tbtt_ofst(struct rtw89_dev *rtwdev, return remainder; } -static u16 rtw89_mcc_get_bcn_ofst(struct rtw89_dev *rtwdev) +static int __mcc_fw_req_tsf(struct rtw89_dev *rtwdev, u64 *tsf_ref, u64 *tsf_aux) { struct rtw89_mcc_info *mcc = &rtwdev->mcc; struct rtw89_mcc_role *ref = &mcc->role_ref; struct rtw89_mcc_role *aux = &mcc->role_aux; struct rtw89_mac_mcc_tsf_rpt rpt = {}; struct rtw89_fw_mcc_tsf_req req = {}; - u32 bcn_intvl_ref_us = ieee80211_tu_to_usec(ref->beacon_interval); - u32 tbtt_ofst_ref, tbtt_ofst_aux; - u64 tsf_ref, tsf_aux; int ret; req.group = mcc->group; @@ -393,11 +397,63 @@ static u16 rtw89_mcc_get_bcn_ofst(struct rtw89_dev *rtwdev) if (ret) { rtw89_debug(rtwdev, RTW89_DBG_CHAN, "MCC h2c failed to request tsf: %d\n", ret); - return RTW89_MCC_DFLT_BCN_OFST_TIME; + return ret; + } + + *tsf_ref = (u64)rpt.tsf_x_high << 32 | rpt.tsf_x_low; + *tsf_aux = (u64)rpt.tsf_y_high << 32 | rpt.tsf_y_low; + + return 0; +} + +static int __mrc_fw_req_tsf(struct rtw89_dev *rtwdev, u64 *tsf_ref, u64 *tsf_aux) +{ + struct rtw89_mcc_info *mcc = &rtwdev->mcc; + struct rtw89_mcc_role *ref = &mcc->role_ref; + struct rtw89_mcc_role *aux = &mcc->role_aux; + struct rtw89_fw_mrc_req_tsf_arg arg = {}; + struct rtw89_mac_mrc_tsf_rpt rpt = {}; + int ret; + + BUILD_BUG_ON(RTW89_MAC_MRC_MAX_REQ_TSF_NUM < NUM_OF_RTW89_MCC_ROLES); + + arg.num = 2; + arg.infos[0].band = ref->rtwvif->mac_idx; + arg.infos[0].port = ref->rtwvif->port; + arg.infos[1].band = aux->rtwvif->mac_idx; + arg.infos[1].port = aux->rtwvif->port; + + ret = rtw89_fw_h2c_mrc_req_tsf(rtwdev, &arg, &rpt); + if (ret) { + rtw89_debug(rtwdev, RTW89_DBG_CHAN, + "MRC h2c failed to request tsf: %d\n", ret); + return ret; } - tsf_ref = (u64)rpt.tsf_x_high << 32 | rpt.tsf_x_low; - tsf_aux = (u64)rpt.tsf_y_high << 32 | rpt.tsf_y_low; + *tsf_ref = rpt.tsfs[0]; + *tsf_aux = rpt.tsfs[1]; + + return 0; +} + +static u16 rtw89_mcc_get_bcn_ofst(struct rtw89_dev *rtwdev) +{ + struct rtw89_mcc_info *mcc = &rtwdev->mcc; + struct rtw89_mcc_role *ref = &mcc->role_ref; + struct rtw89_mcc_role *aux = &mcc->role_aux; + u32 bcn_intvl_ref_us = ieee80211_tu_to_usec(ref->beacon_interval); + u32 tbtt_ofst_ref, tbtt_ofst_aux; + u64 tsf_ref, tsf_aux; + int ret; + + if (rtw89_concurrent_via_mrc(rtwdev)) + ret = __mrc_fw_req_tsf(rtwdev, &tsf_ref, &tsf_aux); + else + ret = __mcc_fw_req_tsf(rtwdev, &tsf_ref, &tsf_aux); + + if (ret) + return RTW89_MCC_DFLT_BCN_OFST_TIME; + tbtt_ofst_ref = rtw89_mcc_get_tbtt_ofst(rtwdev, ref, tsf_ref); tbtt_ofst_aux = rtw89_mcc_get_tbtt_ofst(rtwdev, aux, tsf_aux); @@ -420,6 +476,28 @@ void rtw89_mcc_role_fw_macid_bitmap_set_bit(struct rtw89_mcc_role *mcc_role, mcc_role->macid_bitmap[idx] |= BIT(pos); } +static +u32 rtw89_mcc_role_fw_macid_bitmap_to_u32(struct rtw89_mcc_role *mcc_role) +{ + unsigned int macid; + unsigned int i, j; + u32 bitmap = 0; + + for (i = 0; i < ARRAY_SIZE(mcc_role->macid_bitmap); i++) { + for (j = 0; j < 8; j++) { + macid = i * 8 + j; + if (macid >= 32) + goto out; + + if (mcc_role->macid_bitmap[i] & BIT(j)) + bitmap |= BIT(macid); + } + } + +out: + return bitmap; +} + static void rtw89_mcc_role_macid_sta_iter(void *data, struct ieee80211_sta *sta) { struct rtw89_sta *rtwsta = (struct rtw89_sta *)sta->drv_priv; @@ -1181,7 +1259,11 @@ static void rtw89_mcc_sync_tbtt(struct rtw89_dev *rtwdev, tsf_ofst_tgt = bcn_intvl_src_us - remainder; config->sync.macid_tgt = tgt->rtwvif->mac_id; + config->sync.band_tgt = tgt->rtwvif->mac_idx; + config->sync.port_tgt = tgt->rtwvif->port; config->sync.macid_src = src->rtwvif->mac_id; + config->sync.band_src = src->rtwvif->mac_idx; + config->sync.port_src = src->rtwvif->port; config->sync.offset = tsf_ofst_tgt / 1024; config->sync.enable = true; @@ -1328,6 +1410,37 @@ static int __mcc_fw_add_role(struct rtw89_dev *rtwdev, struct rtw89_mcc_role *ro return 0; } +static +void __mrc_fw_add_role(struct rtw89_dev *rtwdev, struct rtw89_mcc_role *role, + struct rtw89_fw_mrc_add_arg *arg, u8 slot_idx) +{ + struct rtw89_mcc_info *mcc = &rtwdev->mcc; + struct rtw89_mcc_role *ref = &mcc->role_ref; + struct rtw89_mcc_policy *policy = &role->policy; + struct rtw89_fw_mrc_add_slot_arg *slot_arg; + const struct rtw89_chan *chan; + + slot_arg = &arg->slots[slot_idx]; + role->slot_idx = slot_idx; + + slot_arg->duration = role->duration; + slot_arg->role_num = 1; + + chan = rtw89_chan_get(rtwdev, role->rtwvif->sub_entity_idx); + + slot_arg->roles[0].role_type = RTW89_H2C_MRC_ROLE_WIFI; + slot_arg->roles[0].is_master = role == ref; + slot_arg->roles[0].band = chan->band_type; + slot_arg->roles[0].bw = chan->band_width; + slot_arg->roles[0].central_ch = chan->channel; + slot_arg->roles[0].primary_ch = chan->primary_channel; + slot_arg->roles[0].en_tx_null = !policy->dis_tx_null; + slot_arg->roles[0].null_early = policy->tx_null_early; + slot_arg->roles[0].macid = role->rtwvif->mac_id; + slot_arg->roles[0].macid_main_bitmap = + rtw89_mcc_role_fw_macid_bitmap_to_u32(role); +} + static int __mcc_fw_add_bt_role(struct rtw89_dev *rtwdev) { struct rtw89_mcc_info *mcc = &rtwdev->mcc; @@ -1349,6 +1462,20 @@ static int __mcc_fw_add_bt_role(struct rtw89_dev *rtwdev) return 0; } +static +void __mrc_fw_add_bt_role(struct rtw89_dev *rtwdev, + struct rtw89_fw_mrc_add_arg *arg, u8 slot_idx) +{ + struct rtw89_mcc_info *mcc = &rtwdev->mcc; + struct rtw89_mcc_bt_role *bt_role = &mcc->bt_role; + struct rtw89_fw_mrc_add_slot_arg *slot_arg = &arg->slots[slot_idx]; + + slot_arg->duration = bt_role->duration; + slot_arg->role_num = 1; + + slot_arg->roles[0].role_type = RTW89_H2C_MRC_ROLE_BT; +} + static int __mcc_fw_start(struct rtw89_dev *rtwdev, bool replace) { struct rtw89_mcc_info *mcc = &rtwdev->mcc; @@ -1434,6 +1561,130 @@ static int __mcc_fw_start(struct rtw89_dev *rtwdev, bool replace) return 0; } +static void __mrc_fw_add_courtesy(struct rtw89_dev *rtwdev, + struct rtw89_fw_mrc_add_arg *arg) +{ + struct rtw89_mcc_info *mcc = &rtwdev->mcc; + struct rtw89_mcc_role *ref = &mcc->role_ref; + struct rtw89_mcc_role *aux = &mcc->role_aux; + struct rtw89_mcc_config *config = &mcc->config; + struct rtw89_mcc_pattern *pattern = &config->pattern; + struct rtw89_mcc_courtesy *courtesy = &pattern->courtesy; + struct rtw89_fw_mrc_add_slot_arg *slot_arg_src; + u8 slot_idx_tgt; + + if (!courtesy->enable) + return; + + if (courtesy->macid_src == ref->rtwvif->mac_id) { + slot_arg_src = &arg->slots[ref->slot_idx]; + slot_idx_tgt = aux->slot_idx; + } else { + slot_arg_src = &arg->slots[aux->slot_idx]; + slot_idx_tgt = ref->slot_idx; + } + + slot_arg_src->courtesy_target = slot_idx_tgt; + slot_arg_src->courtesy_period = courtesy->slot_num; + slot_arg_src->courtesy_en = true; +} + +static int __mrc_fw_start(struct rtw89_dev *rtwdev, bool replace) +{ + struct rtw89_mcc_info *mcc = &rtwdev->mcc; + struct rtw89_mcc_role *ref = &mcc->role_ref; + struct rtw89_mcc_role *aux = &mcc->role_aux; + struct rtw89_mcc_config *config = &mcc->config; + struct rtw89_mcc_pattern *pattern = &config->pattern; + struct rtw89_mcc_sync *sync = &config->sync; + struct rtw89_fw_mrc_start_arg start_arg = {}; + struct rtw89_fw_mrc_add_arg add_arg = {}; + int ret; + + BUILD_BUG_ON(RTW89_MAC_MRC_MAX_ADD_SLOT_NUM < + NUM_OF_RTW89_MCC_ROLES + 1 /* bt role */); + + if (replace) { + start_arg.old_sch_idx = mcc->group; + start_arg.action = RTW89_H2C_MRC_START_ACTION_REPLACE_OLD; + mcc->group = RTW89_MCC_NEXT_GROUP(mcc->group); + } + + add_arg.sch_idx = mcc->group; + add_arg.sch_type = RTW89_H2C_MRC_SCH_BAND0_ONLY; + + switch (pattern->plan) { + case RTW89_MCC_PLAN_TAIL_BT: + __mrc_fw_add_role(rtwdev, ref, &add_arg, 0); + __mrc_fw_add_role(rtwdev, aux, &add_arg, 1); + __mrc_fw_add_bt_role(rtwdev, &add_arg, 2); + + add_arg.slot_num = 3; + add_arg.btc_in_sch = true; + break; + case RTW89_MCC_PLAN_MID_BT: + __mrc_fw_add_role(rtwdev, ref, &add_arg, 0); + __mrc_fw_add_bt_role(rtwdev, &add_arg, 1); + __mrc_fw_add_role(rtwdev, aux, &add_arg, 2); + + add_arg.slot_num = 3; + add_arg.btc_in_sch = true; + break; + case RTW89_MCC_PLAN_NO_BT: + __mrc_fw_add_role(rtwdev, ref, &add_arg, 0); + __mrc_fw_add_role(rtwdev, aux, &add_arg, 1); + + add_arg.slot_num = 2; + add_arg.btc_in_sch = false; + break; + default: + rtw89_warn(rtwdev, "MCC unknown plan: %d\n", pattern->plan); + return -EFAULT; + } + + __mrc_fw_add_courtesy(rtwdev, &add_arg); + + ret = rtw89_fw_h2c_mrc_add(rtwdev, &add_arg); + if (ret) { + rtw89_debug(rtwdev, RTW89_DBG_CHAN, + "MRC h2c failed to trigger add: %d\n", ret); + return ret; + } + + if (sync->enable) { + struct rtw89_fw_mrc_sync_arg sync_arg = { + .offset = sync->offset, + .src = { + .band = sync->band_src, + .port = sync->port_src, + }, + .dest = { + .band = sync->band_tgt, + .port = sync->port_tgt, + }, + }; + + ret = rtw89_fw_h2c_mrc_sync(rtwdev, &sync_arg); + if (ret) { + rtw89_debug(rtwdev, RTW89_DBG_CHAN, + "MRC h2c failed to trigger sync: %d\n", ret); + return ret; + } + } + + start_arg.sch_idx = mcc->group; + start_arg.start_tsf = config->start_tsf; + + ret = rtw89_fw_h2c_mrc_start(rtwdev, &start_arg); + if (ret) { + rtw89_debug(rtwdev, RTW89_DBG_CHAN, + "MRC h2c failed to trigger start: %d\n", ret); + return ret; + } + + return 0; +} + static int __mcc_fw_set_duration_no_bt(struct rtw89_dev *rtwdev, bool sync_changed) { struct rtw89_mcc_info *mcc = &rtwdev->mcc; @@ -1475,6 +1726,60 @@ static int __mcc_fw_set_duration_no_bt(struct rtw89_dev *rtwdev, bool sync_chang return 0; } +static int __mrc_fw_set_duration_no_bt(struct rtw89_dev *rtwdev, bool sync_changed) +{ + struct rtw89_mcc_info *mcc = &rtwdev->mcc; + struct rtw89_mcc_config *config = &mcc->config; + struct rtw89_mcc_sync *sync = &config->sync; + struct rtw89_mcc_role *ref = &mcc->role_ref; + struct rtw89_mcc_role *aux = &mcc->role_aux; + struct rtw89_fw_mrc_upd_duration_arg dur_arg = { + .sch_idx = mcc->group, + .start_tsf = config->start_tsf, + .slot_num = 2, + .slots[0] = { + .slot_idx = ref->slot_idx, + .duration = ref->duration, + }, + .slots[1] = { + .slot_idx = aux->slot_idx, + .duration = aux->duration, + }, + }; + struct rtw89_fw_mrc_sync_arg sync_arg = { + .offset = sync->offset, + .src = { + .band = sync->band_src, + .port = sync->port_src, + }, + .dest = { + .band = sync->band_tgt, + .port = sync->port_tgt, + }, + + }; + int ret; + + ret = rtw89_fw_h2c_mrc_upd_duration(rtwdev, &dur_arg); + if (ret) { + rtw89_debug(rtwdev, RTW89_DBG_CHAN, + "MRC h2c failed to update duration: %d\n", ret); + return ret; + } + + if (!sync->enable || !sync_changed) + return 0; + + ret = rtw89_fw_h2c_mrc_sync(rtwdev, &sync_arg); + if (ret) { + rtw89_debug(rtwdev, RTW89_DBG_CHAN, + "MRC h2c failed to trigger sync: %d\n", ret); + return ret; + } + + return 0; +} + static void rtw89_mcc_handle_beacon_noa(struct rtw89_dev *rtwdev, bool enable) { struct rtw89_mcc_info *mcc = &rtwdev->mcc; @@ -1593,7 +1898,11 @@ static int rtw89_mcc_start(struct rtw89_dev *rtwdev) if (ret) return ret; - ret = __mcc_fw_start(rtwdev, false); + if (rtw89_concurrent_via_mrc(rtwdev)) + ret = __mrc_fw_start(rtwdev, false); + else + ret = __mcc_fw_start(rtwdev, false); + if (ret) return ret; @@ -1611,16 +1920,23 @@ static void rtw89_mcc_stop(struct rtw89_dev *rtwdev) rtw89_debug(rtwdev, RTW89_DBG_CHAN, "MCC stop\n"); - ret = rtw89_fw_h2c_stop_mcc(rtwdev, mcc->group, - ref->rtwvif->mac_id, true); - if (ret) - rtw89_debug(rtwdev, RTW89_DBG_CHAN, - "MCC h2c failed to trigger stop: %d\n", ret); + if (rtw89_concurrent_via_mrc(rtwdev)) { + ret = rtw89_fw_h2c_mrc_del(rtwdev, mcc->group); + if (ret) + rtw89_debug(rtwdev, RTW89_DBG_CHAN, + "MRC h2c failed to trigger del: %d\n", ret); + } else { + ret = rtw89_fw_h2c_stop_mcc(rtwdev, mcc->group, + ref->rtwvif->mac_id, true); + if (ret) + rtw89_debug(rtwdev, RTW89_DBG_CHAN, + "MCC h2c failed to trigger stop: %d\n", ret); - ret = rtw89_fw_h2c_del_mcc_group(rtwdev, mcc->group, true); - if (ret) - rtw89_debug(rtwdev, RTW89_DBG_CHAN, - "MCC h2c failed to delete group: %d\n", ret); + ret = rtw89_fw_h2c_del_mcc_group(rtwdev, mcc->group, true); + if (ret) + rtw89_debug(rtwdev, RTW89_DBG_CHAN, + "MCC h2c failed to delete group: %d\n", ret); + } rtw89_chanctx_notify(rtwdev, RTW89_CHANCTX_STATE_MCC_STOP); @@ -1646,7 +1962,11 @@ static int rtw89_mcc_update(struct rtw89_dev *rtwdev) if (old_cfg.pattern.plan != RTW89_MCC_PLAN_NO_BT || config->pattern.plan != RTW89_MCC_PLAN_NO_BT) { - ret = __mcc_fw_start(rtwdev, true); + if (rtw89_concurrent_via_mrc(rtwdev)) + ret = __mrc_fw_start(rtwdev, true); + else + ret = __mcc_fw_start(rtwdev, true); + if (ret) return ret; } else { @@ -1655,7 +1975,11 @@ static int rtw89_mcc_update(struct rtw89_dev *rtwdev) else sync_changed = true; - ret = __mcc_fw_set_duration_no_bt(rtwdev, sync_changed); + if (rtw89_concurrent_via_mrc(rtwdev)) + ret = __mrc_fw_set_duration_no_bt(rtwdev, sync_changed); + else + ret = __mcc_fw_set_duration_no_bt(rtwdev, sync_changed); + if (ret) return ret; } @@ -1697,12 +2021,75 @@ static void rtw89_mcc_track(struct rtw89_dev *rtwdev) rtw89_queue_chanctx_change(rtwdev, RTW89_CHANCTX_BCN_OFFSET_CHANGE); } +static int __mcc_fw_upd_macid_bitmap(struct rtw89_dev *rtwdev, + struct rtw89_mcc_role *upd) +{ + struct rtw89_mcc_info *mcc = &rtwdev->mcc; + int ret; + + ret = rtw89_fw_h2c_mcc_macid_bitmap(rtwdev, mcc->group, + upd->rtwvif->mac_id, + upd->macid_bitmap); + if (ret) { + rtw89_debug(rtwdev, RTW89_DBG_CHAN, + "MCC h2c failed to update macid bitmap: %d\n", ret); + return ret; + } + + return 0; +} + +static int __mrc_fw_upd_macid_bitmap(struct rtw89_dev *rtwdev, + struct rtw89_mcc_role *cur, + struct rtw89_mcc_role *upd) +{ + struct rtw89_mcc_info *mcc = &rtwdev->mcc; + struct rtw89_fw_mrc_upd_bitmap_arg arg = {}; + u32 old = rtw89_mcc_role_fw_macid_bitmap_to_u32(cur); + u32 new = rtw89_mcc_role_fw_macid_bitmap_to_u32(upd); + u32 add = new & ~old; + u32 del = old & ~new; + int ret; + int i; + + arg.sch_idx = mcc->group; + arg.macid = upd->rtwvif->mac_id; + + for (i = 0; i < 32; i++) { + if (add & BIT(i)) { + arg.client_macid = i; + arg.action = RTW89_H2C_MRC_UPD_BITMAP_ACTION_ADD; + + ret = rtw89_fw_h2c_mrc_upd_bitmap(rtwdev, &arg); + if (ret) + goto err; + } + } + + for (i = 0; i < 32; i++) { + if (del & BIT(i)) { + arg.client_macid = i; + arg.action = RTW89_H2C_MRC_UPD_BITMAP_ACTION_DEL; + + ret = rtw89_fw_h2c_mrc_upd_bitmap(rtwdev, &arg); + if (ret) + goto err; + } + } + + return 0; + +err: + rtw89_debug(rtwdev, RTW89_DBG_CHAN, + "MRC h2c failed to update bitmap: %d\n", ret); + return ret; +} + static int rtw89_mcc_upd_map_iterator(struct rtw89_dev *rtwdev, struct rtw89_mcc_role *mcc_role, unsigned int ordered_idx, void *data) { - struct rtw89_mcc_info *mcc = &rtwdev->mcc; struct rtw89_mcc_role upd = { .rtwvif = mcc_role->rtwvif, }; @@ -1716,14 +2103,13 @@ static int rtw89_mcc_upd_map_iterator(struct rtw89_dev *rtwdev, sizeof(mcc_role->macid_bitmap)) == 0) return 0; - ret = rtw89_fw_h2c_mcc_macid_bitmap(rtwdev, mcc->group, - upd.rtwvif->mac_id, - upd.macid_bitmap); - if (ret) { - rtw89_debug(rtwdev, RTW89_DBG_CHAN, - "MCC h2c failed to update macid bitmap: %d\n", ret); + if (rtw89_concurrent_via_mrc(rtwdev)) + ret = __mrc_fw_upd_macid_bitmap(rtwdev, mcc_role, &upd); + else + ret = __mcc_fw_upd_macid_bitmap(rtwdev, &upd); + + if (ret) return ret; - } memcpy(mcc_role->macid_bitmap, upd.macid_bitmap, sizeof(mcc_role->macid_bitmap)); diff --git a/drivers/net/wireless/realtek/rtw89/core.h b/drivers/net/wireless/realtek/rtw89/core.h index 6269ae2539b2..d62d23015c48 100644 --- a/drivers/net/wireless/realtek/rtw89/core.h +++ b/drivers/net/wireless/realtek/rtw89/core.h @@ -4868,6 +4868,9 @@ struct rtw89_mcc_role { struct rtw89_mcc_policy policy; struct rtw89_mcc_limit limit; + /* only valid when running with FW MRC mechanism */ + u8 slot_idx; + /* byte-array in LE order for FW */ u8 macid_bitmap[BITS_TO_BYTES(RTW89_MAX_MAC_ID_NUM)]; @@ -4911,7 +4914,11 @@ struct rtw89_mcc_sync { bool enable; u16 offset; /* TU */ u8 macid_src; + u8 band_src; + u8 port_src; u8 macid_tgt; + u8 band_tgt; + u8 port_tgt; }; struct rtw89_mcc_config { -- cgit v1.2.3 From 441a6014d0243a432a96e23266896d2761116735 Mon Sep 17 00:00:00 2001 From: Zong-Zhe Yang Date: Tue, 13 Feb 2024 15:35:14 +0800 Subject: wifi: rtw89: 8922a: declare to support two chanctx We are going to allow MCC (multi-channel concurrency) on RTL8922A. So, increase 8922a::support_chanctx_num up to 2 first. Signed-off-by: Zong-Zhe Yang Signed-off-by: Ping-Ke Shih Signed-off-by: Kalle Valo Link: https://msgid.link/20240213073514.23796-6-pkshih@realtek.com --- drivers/net/wireless/realtek/rtw89/rtw8922a.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/realtek/rtw89/rtw8922a.c b/drivers/net/wireless/realtek/rtw89/rtw8922a.c index a4b7d2e79638..2f1e7767d58a 100644 --- a/drivers/net/wireless/realtek/rtw89/rtw8922a.c +++ b/drivers/net/wireless/realtek/rtw89/rtw8922a.c @@ -1759,7 +1759,7 @@ const struct rtw89_chip_info rtw8922a_chip_info = { .dig_table = NULL, .dig_regs = &rtw8922a_dig_regs, .tssi_dbw_table = NULL, - .support_chanctx_num = 1, + .support_chanctx_num = 2, .support_bands = BIT(NL80211_BAND_2GHZ) | BIT(NL80211_BAND_5GHZ) | BIT(NL80211_BAND_6GHZ), -- cgit v1.2.3 From 63d94f7496233600186303f1eee000ab2ffc920a Mon Sep 17 00:00:00 2001 From: Ping-Ke Shih Date: Tue, 13 Feb 2024 20:25:56 +0800 Subject: wifi: rtw89: fw: remove unnecessary rcu_read_unlock() for punctured The rcu_read_unlock() is accidentally added, and sparse warn: drivers/net/wireless/realtek/rtw89/fw.c:2807:17: warning: context imbalance in 'rtw89_fw_h2c_assoc_cmac_tbl_g7' - unexpected unlock Fixes: b82730bf57b5 ("wifi: cfg80211/mac80211: move puncturing into chandef") Cc: Johannes Berg Signed-off-by: Ping-Ke Shih Signed-off-by: Kalle Valo Link: https://msgid.link/20240213122556.9593-1-pkshih@realtek.com --- drivers/net/wireless/realtek/rtw89/fw.c | 1 - 1 file changed, 1 deletion(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/realtek/rtw89/fw.c b/drivers/net/wireless/realtek/rtw89/fw.c index 2ab45d0878f7..63897351ca15 100644 --- a/drivers/net/wireless/realtek/rtw89/fw.c +++ b/drivers/net/wireless/realtek/rtw89/fw.c @@ -2808,7 +2808,6 @@ int rtw89_fw_h2c_assoc_cmac_tbl_g7(struct rtw89_dev *rtwdev, h2c->w4 |= le32_encode_bits(~punct, CCTLINFO_G7_W4_ACT_SUBCH_CBW); - rcu_read_unlock(); h2c->m4 |= cpu_to_le32(CCTLINFO_G7_W4_ACT_SUBCH_CBW); } -- cgit v1.2.3 From bcfcbf23a98ca19ba5931914801b5939e0d17bda Mon Sep 17 00:00:00 2001 From: Bitterblue Smith Date: Tue, 13 Feb 2024 16:33:02 +0200 Subject: wifi: rtlwifi: rtl8192cu: Fix 2T2R chip type detection rtl8192cu handles 1T1R devices (RTL8188CUS), 1T2R devices (RTL8191CU), and 2T2R devices (RTL8192CU). The 2T2R devices were incorrectly detected as 1T2R because of a mistake in the IS_92C_1T2R macro. The visible effect of this is that the firmware was allowed to use TX rates only up to MCS7. Fix the IS_92C_1T2R macro. Now my 2T2R device has much better upload speed. Before: 46 Mbps. After: 82 Mbps. Also fix a debug message which was printing "RF_1T1R" even for 1T2R chips. Signed-off-by: Bitterblue Smith Acked-by: Ping-Ke Shih Signed-off-by: Kalle Valo Link: https://msgid.link/ed960059-5c77-422d-ac4e-fe9fc9d0d296@gmail.com --- drivers/net/wireless/realtek/rtlwifi/rtl8192cu/def.h | 2 +- drivers/net/wireless/realtek/rtlwifi/rtl8192cu/mac.c | 3 ++- 2 files changed, 3 insertions(+), 2 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/realtek/rtlwifi/rtl8192cu/def.h b/drivers/net/wireless/realtek/rtlwifi/rtl8192cu/def.h index 91e4427ab022..4757f93b84e4 100644 --- a/drivers/net/wireless/realtek/rtlwifi/rtl8192cu/def.h +++ b/drivers/net/wireless/realtek/rtlwifi/rtl8192cu/def.h @@ -11,7 +11,7 @@ #define CHIP_VENDOR_UMC_B_CUT BIT(6) #define IS_92C_1T2R(version) \ - (((version) & CHIP_92C) && ((version) & CHIP_92C_1T2R)) + (((version) & CHIP_92C_1T2R) == CHIP_92C_1T2R) #define IS_VENDOR_UMC(version) \ (((version) & CHIP_VENDOR_UMC) ? true : false) diff --git a/drivers/net/wireless/realtek/rtlwifi/rtl8192cu/mac.c b/drivers/net/wireless/realtek/rtlwifi/rtl8192cu/mac.c index 4ff0d4118193..a76f2dc8a977 100644 --- a/drivers/net/wireless/realtek/rtlwifi/rtl8192cu/mac.c +++ b/drivers/net/wireless/realtek/rtlwifi/rtl8192cu/mac.c @@ -101,7 +101,8 @@ void rtl92c_read_chip_version(struct ieee80211_hw *hw) rtlphy->rf_type = RF_1T1R; rtl_dbg(rtlpriv, COMP_INIT, DBG_LOUD, "Chip RF Type: %s\n", - rtlphy->rf_type == RF_2T2R ? "RF_2T2R" : "RF_1T1R"); + rtlphy->rf_type == RF_2T2R ? "RF_2T2R" : + rtlphy->rf_type == RF_1T2R ? "RF_1T2R" : "RF_1T1R"); if (get_rf_type(rtlphy) == RF_1T1R) rtlpriv->dm.rfpath_rxenable[0] = true; else -- cgit v1.2.3 From 42ffccd0a36e099dea3d3272c5d62a0454ded1f0 Mon Sep 17 00:00:00 2001 From: Bitterblue Smith Date: Tue, 13 Feb 2024 16:33:11 +0200 Subject: wifi: rtlwifi: rtl_usb: Store the endpoint addresses And use the stored addresses in rtl8192cu instead of hardcoding them. This is what the vendor drivers do. Perhaps this is not strictly necessary for RTL8192CU devices. However, the dual mac version of RTL8192DU has two USB interfaces, each with its own set of endpoints. Hardcoding their addresses in the upcoming rtl8192du driver would require making some assumptions which I'm not qualified to make. Signed-off-by: Bitterblue Smith Acked-by: Ping-Ke Shih Signed-off-by: Kalle Valo Link: https://msgid.link/7b6a602a-6101-4bab-958d-bcff4d565b40@gmail.com --- .../net/wireless/realtek/rtlwifi/rtl8192cu/sw.c | 1 - .../net/wireless/realtek/rtlwifi/rtl8192cu/trx.c | 77 ++++++++++++---------- .../net/wireless/realtek/rtlwifi/rtl8192cu/trx.h | 1 - drivers/net/wireless/realtek/rtlwifi/usb.c | 31 +++++++-- drivers/net/wireless/realtek/rtlwifi/usb.h | 2 + drivers/net/wireless/realtek/rtlwifi/wifi.h | 1 - 6 files changed, 68 insertions(+), 45 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/realtek/rtlwifi/rtl8192cu/sw.c b/drivers/net/wireless/realtek/rtlwifi/rtl8192cu/sw.c index 9f4cf09090d6..48be7e346efc 100644 --- a/drivers/net/wireless/realtek/rtlwifi/rtl8192cu/sw.c +++ b/drivers/net/wireless/realtek/rtlwifi/rtl8192cu/sw.c @@ -145,7 +145,6 @@ MODULE_PARM_DESC(debug_mask, "Set debug mask (default 0)"); static struct rtl_hal_usbint_cfg rtl92cu_interface_cfg = { /* rx */ - .in_ep_num = RTL92C_USB_BULK_IN_NUM, .rx_urb_num = RTL92C_NUM_RX_URBS, .rx_max_size = RTL92C_SIZE_MAX_RX_BUFFER, .usb_rx_hdl = rtl8192cu_rx_hdl, diff --git a/drivers/net/wireless/realtek/rtlwifi/rtl8192cu/trx.c b/drivers/net/wireless/realtek/rtlwifi/rtl8192cu/trx.c index e5c81c1c63c0..4856ed40005b 100644 --- a/drivers/net/wireless/realtek/rtlwifi/rtl8192cu/trx.c +++ b/drivers/net/wireless/realtek/rtlwifi/rtl8192cu/trx.c @@ -79,68 +79,75 @@ static int configvernoutep(struct ieee80211_hw *hw) static void twooutepmapping(struct ieee80211_hw *hw, bool is_chip8, bool bwificfg, struct rtl_ep_map *ep_map) { + struct rtl_usb_priv *usb_priv = rtl_usbpriv(hw); + struct rtl_usb *rtlusb = rtl_usbdev(usb_priv); struct rtl_priv *rtlpriv = rtl_priv(hw); if (bwificfg) { /* for WMM */ rtl_dbg(rtlpriv, COMP_INIT, DBG_DMESG, "USB Chip-B & WMM Setting.....\n"); - ep_map->ep_mapping[RTL_TXQ_BE] = 2; - ep_map->ep_mapping[RTL_TXQ_BK] = 3; - ep_map->ep_mapping[RTL_TXQ_VI] = 3; - ep_map->ep_mapping[RTL_TXQ_VO] = 2; - ep_map->ep_mapping[RTL_TXQ_MGT] = 2; - ep_map->ep_mapping[RTL_TXQ_BCN] = 2; - ep_map->ep_mapping[RTL_TXQ_HI] = 2; + ep_map->ep_mapping[RTL_TXQ_BE] = rtlusb->out_eps[0]; + ep_map->ep_mapping[RTL_TXQ_BK] = rtlusb->out_eps[1]; + ep_map->ep_mapping[RTL_TXQ_VI] = rtlusb->out_eps[1]; + ep_map->ep_mapping[RTL_TXQ_VO] = rtlusb->out_eps[0]; + ep_map->ep_mapping[RTL_TXQ_MGT] = rtlusb->out_eps[0]; + ep_map->ep_mapping[RTL_TXQ_BCN] = rtlusb->out_eps[0]; + ep_map->ep_mapping[RTL_TXQ_HI] = rtlusb->out_eps[0]; } else { /* typical setting */ rtl_dbg(rtlpriv, COMP_INIT, DBG_DMESG, "USB typical Setting.....\n"); - ep_map->ep_mapping[RTL_TXQ_BE] = 3; - ep_map->ep_mapping[RTL_TXQ_BK] = 3; - ep_map->ep_mapping[RTL_TXQ_VI] = 2; - ep_map->ep_mapping[RTL_TXQ_VO] = 2; - ep_map->ep_mapping[RTL_TXQ_MGT] = 2; - ep_map->ep_mapping[RTL_TXQ_BCN] = 2; - ep_map->ep_mapping[RTL_TXQ_HI] = 2; + ep_map->ep_mapping[RTL_TXQ_BE] = rtlusb->out_eps[1]; + ep_map->ep_mapping[RTL_TXQ_BK] = rtlusb->out_eps[1]; + ep_map->ep_mapping[RTL_TXQ_VI] = rtlusb->out_eps[0]; + ep_map->ep_mapping[RTL_TXQ_VO] = rtlusb->out_eps[0]; + ep_map->ep_mapping[RTL_TXQ_MGT] = rtlusb->out_eps[0]; + ep_map->ep_mapping[RTL_TXQ_BCN] = rtlusb->out_eps[0]; + ep_map->ep_mapping[RTL_TXQ_HI] = rtlusb->out_eps[0]; } } static void threeoutepmapping(struct ieee80211_hw *hw, bool bwificfg, struct rtl_ep_map *ep_map) { + struct rtl_usb_priv *usb_priv = rtl_usbpriv(hw); + struct rtl_usb *rtlusb = rtl_usbdev(usb_priv); struct rtl_priv *rtlpriv = rtl_priv(hw); if (bwificfg) { /* for WMM */ rtl_dbg(rtlpriv, COMP_INIT, DBG_DMESG, "USB 3EP Setting for WMM.....\n"); - ep_map->ep_mapping[RTL_TXQ_BE] = 5; - ep_map->ep_mapping[RTL_TXQ_BK] = 3; - ep_map->ep_mapping[RTL_TXQ_VI] = 3; - ep_map->ep_mapping[RTL_TXQ_VO] = 2; - ep_map->ep_mapping[RTL_TXQ_MGT] = 2; - ep_map->ep_mapping[RTL_TXQ_BCN] = 2; - ep_map->ep_mapping[RTL_TXQ_HI] = 2; + ep_map->ep_mapping[RTL_TXQ_BE] = rtlusb->out_eps[2]; + ep_map->ep_mapping[RTL_TXQ_BK] = rtlusb->out_eps[1]; + ep_map->ep_mapping[RTL_TXQ_VI] = rtlusb->out_eps[1]; + ep_map->ep_mapping[RTL_TXQ_VO] = rtlusb->out_eps[0]; + ep_map->ep_mapping[RTL_TXQ_MGT] = rtlusb->out_eps[0]; + ep_map->ep_mapping[RTL_TXQ_BCN] = rtlusb->out_eps[0]; + ep_map->ep_mapping[RTL_TXQ_HI] = rtlusb->out_eps[0]; } else { /* typical setting */ rtl_dbg(rtlpriv, COMP_INIT, DBG_DMESG, "USB 3EP Setting for typical.....\n"); - ep_map->ep_mapping[RTL_TXQ_BE] = 5; - ep_map->ep_mapping[RTL_TXQ_BK] = 5; - ep_map->ep_mapping[RTL_TXQ_VI] = 3; - ep_map->ep_mapping[RTL_TXQ_VO] = 2; - ep_map->ep_mapping[RTL_TXQ_MGT] = 2; - ep_map->ep_mapping[RTL_TXQ_BCN] = 2; - ep_map->ep_mapping[RTL_TXQ_HI] = 2; + ep_map->ep_mapping[RTL_TXQ_BE] = rtlusb->out_eps[2]; + ep_map->ep_mapping[RTL_TXQ_BK] = rtlusb->out_eps[2]; + ep_map->ep_mapping[RTL_TXQ_VI] = rtlusb->out_eps[1]; + ep_map->ep_mapping[RTL_TXQ_VO] = rtlusb->out_eps[0]; + ep_map->ep_mapping[RTL_TXQ_MGT] = rtlusb->out_eps[0]; + ep_map->ep_mapping[RTL_TXQ_BCN] = rtlusb->out_eps[0]; + ep_map->ep_mapping[RTL_TXQ_HI] = rtlusb->out_eps[0]; } } static void oneoutepmapping(struct ieee80211_hw *hw, struct rtl_ep_map *ep_map) { - ep_map->ep_mapping[RTL_TXQ_BE] = 2; - ep_map->ep_mapping[RTL_TXQ_BK] = 2; - ep_map->ep_mapping[RTL_TXQ_VI] = 2; - ep_map->ep_mapping[RTL_TXQ_VO] = 2; - ep_map->ep_mapping[RTL_TXQ_MGT] = 2; - ep_map->ep_mapping[RTL_TXQ_BCN] = 2; - ep_map->ep_mapping[RTL_TXQ_HI] = 2; + struct rtl_usb_priv *usb_priv = rtl_usbpriv(hw); + struct rtl_usb *rtlusb = rtl_usbdev(usb_priv); + + ep_map->ep_mapping[RTL_TXQ_BE] = rtlusb->out_eps[0]; + ep_map->ep_mapping[RTL_TXQ_BK] = rtlusb->out_eps[0]; + ep_map->ep_mapping[RTL_TXQ_VI] = rtlusb->out_eps[0]; + ep_map->ep_mapping[RTL_TXQ_VO] = rtlusb->out_eps[0]; + ep_map->ep_mapping[RTL_TXQ_MGT] = rtlusb->out_eps[0]; + ep_map->ep_mapping[RTL_TXQ_BCN] = rtlusb->out_eps[0]; + ep_map->ep_mapping[RTL_TXQ_HI] = rtlusb->out_eps[0]; } static int _out_ep_mapping(struct ieee80211_hw *hw) diff --git a/drivers/net/wireless/realtek/rtlwifi/rtl8192cu/trx.h b/drivers/net/wireless/realtek/rtlwifi/rtl8192cu/trx.h index 5f81cab205cc..8678fa0043f4 100644 --- a/drivers/net/wireless/realtek/rtlwifi/rtl8192cu/trx.h +++ b/drivers/net/wireless/realtek/rtlwifi/rtl8192cu/trx.h @@ -4,7 +4,6 @@ #ifndef __RTL92CU_TRX_H__ #define __RTL92CU_TRX_H__ -#define RTL92C_USB_BULK_IN_NUM 1 #define RTL92C_NUM_RX_URBS 8 #define RTL92C_NUM_TX_URBS 32 diff --git a/drivers/net/wireless/realtek/rtlwifi/usb.c b/drivers/net/wireless/realtek/rtlwifi/usb.c index 1fc480fe18ad..6e8c87a2fae4 100644 --- a/drivers/net/wireless/realtek/rtlwifi/usb.c +++ b/drivers/net/wireless/realtek/rtlwifi/usb.c @@ -216,7 +216,6 @@ static int _rtl_usb_init_rx(struct ieee80211_hw *hw) rtlusb->rx_max_size = rtlpriv->cfg->usb_interface_cfg->rx_max_size; rtlusb->rx_urb_num = rtlpriv->cfg->usb_interface_cfg->rx_urb_num; - rtlusb->in_ep = rtlpriv->cfg->usb_interface_cfg->in_ep_num; rtlusb->usb_rx_hdl = rtlpriv->cfg->usb_interface_cfg->usb_rx_hdl; rtlusb->usb_rx_segregate_hdl = rtlpriv->cfg->usb_interface_cfg->usb_rx_segregate_hdl; @@ -248,20 +247,38 @@ static int _rtl_usb_init(struct ieee80211_hw *hw) pep_desc = &usb_intf->cur_altsetting->endpoint[epidx].desc; - if (usb_endpoint_dir_in(pep_desc)) + if (usb_endpoint_dir_in(pep_desc)) { + if (usb_endpoint_xfer_bulk(pep_desc)) { + /* The vendor drivers assume there is only one + * bulk in ep and that it's the first in ep. + */ + if (rtlusb->in_ep_nums == 0) + rtlusb->in_ep = usb_endpoint_num(pep_desc); + else + pr_warn("%s: bulk in endpoint is not the first in endpoint\n", + __func__); + } + rtlusb->in_ep_nums++; - else if (usb_endpoint_dir_out(pep_desc)) + } else if (usb_endpoint_dir_out(pep_desc)) { + if (rtlusb->out_ep_nums < RTL_USB_MAX_BULKOUT_NUM) { + if (usb_endpoint_xfer_bulk(pep_desc)) + rtlusb->out_eps[rtlusb->out_ep_nums] = + usb_endpoint_num(pep_desc); + } else { + pr_warn("%s: found more bulk out endpoints than the expected %d\n", + __func__, RTL_USB_MAX_BULKOUT_NUM); + } + rtlusb->out_ep_nums++; + } rtl_dbg(rtlpriv, COMP_INIT, DBG_DMESG, "USB EP(0x%02x), MaxPacketSize=%d, Interval=%d\n", pep_desc->bEndpointAddress, pep_desc->wMaxPacketSize, pep_desc->bInterval); } - if (rtlusb->in_ep_nums < rtlpriv->cfg->usb_interface_cfg->in_ep_num) { - pr_err("Too few input end points found\n"); - return -EINVAL; - } + if (rtlusb->out_ep_nums == 0) { pr_err("No output end points found\n"); return -EINVAL; diff --git a/drivers/net/wireless/realtek/rtlwifi/usb.h b/drivers/net/wireless/realtek/rtlwifi/usb.h index 3bf85b23eec1..12529afc0510 100644 --- a/drivers/net/wireless/realtek/rtlwifi/usb.h +++ b/drivers/net/wireless/realtek/rtlwifi/usb.h @@ -19,6 +19,7 @@ #define RTL_USB_MAX_TXQ_NUM 4 /* max tx queue */ #define RTL_USB_MAX_EP_NUM 6 /* max ep number */ +#define RTL_USB_MAX_BULKOUT_NUM 4 #define RTL_USB_MAX_TX_URBS_NUM 8 enum rtl_txq { @@ -94,6 +95,7 @@ struct rtl_usb { /* Tx */ u8 out_ep_nums ; + u8 out_eps[RTL_USB_MAX_BULKOUT_NUM]; u8 out_queue_sel; struct rtl_ep_map ep_map; diff --git a/drivers/net/wireless/realtek/rtlwifi/wifi.h b/drivers/net/wireless/realtek/rtlwifi/wifi.h index 3821f6e31447..01df00a43cdb 100644 --- a/drivers/net/wireless/realtek/rtlwifi/wifi.h +++ b/drivers/net/wireless/realtek/rtlwifi/wifi.h @@ -2356,7 +2356,6 @@ struct rtl_mod_params { struct rtl_hal_usbint_cfg { /* data - rx */ - u32 in_ep_num; u32 rx_urb_num; u32 rx_max_size; -- cgit v1.2.3 From e1ea6db35fc3ba5ff063f097385e9f7a88c25356 Mon Sep 17 00:00:00 2001 From: Arnd Bergmann Date: Tue, 13 Feb 2024 11:05:37 +0100 Subject: wifi: brcmsmac: avoid function pointer casts An old cleanup went a little too far and causes a warning with clang-16 and higher as it breaks control flow integrity (KCFI) rules: drivers/net/wireless/broadcom/brcm80211/brcmsmac/phy_shim.c:64:34: error: cast from 'void (*)(struct brcms_phy *)' to 'void (*)(void *)' converts to incompatible function type [-Werror,-Wcast-function-type-strict] 64 | brcms_init_timer(physhim->wl, (void (*)(void *))fn, | ^~~~~~~~~~~~~~~~~~~~ Change this one instance back to passing a void pointer so it can be used with the timer callback interface. Fixes: d89a4c80601d ("staging: brcm80211: removed void * from softmac phy") Signed-off-by: Arnd Bergmann Acked-by: Arend van Spriel Signed-off-by: Kalle Valo Link: https://msgid.link/20240213100548.457854-1-arnd@kernel.org --- drivers/net/wireless/broadcom/brcm80211/brcmsmac/phy/phy_cmn.c | 3 ++- drivers/net/wireless/broadcom/brcm80211/brcmsmac/phy_shim.c | 5 ++--- drivers/net/wireless/broadcom/brcm80211/brcmsmac/phy_shim.h | 2 +- 3 files changed, 5 insertions(+), 5 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmsmac/phy/phy_cmn.c b/drivers/net/wireless/broadcom/brcm80211/brcmsmac/phy/phy_cmn.c index 07f83ff5a54a..a27d6f0b8819 100644 --- a/drivers/net/wireless/broadcom/brcm80211/brcmsmac/phy/phy_cmn.c +++ b/drivers/net/wireless/broadcom/brcm80211/brcmsmac/phy/phy_cmn.c @@ -383,8 +383,9 @@ struct shared_phy *wlc_phy_shared_attach(struct shared_phy_params *shp) return sh; } -static void wlc_phy_timercb_phycal(struct brcms_phy *pi) +static void wlc_phy_timercb_phycal(void *ptr) { + struct brcms_phy *pi = ptr; uint delay = 5; if (PHY_PERICAL_MPHASE_PENDING(pi)) { diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmsmac/phy_shim.c b/drivers/net/wireless/broadcom/brcm80211/brcmsmac/phy_shim.c index a0de5db0cd64..b72381791536 100644 --- a/drivers/net/wireless/broadcom/brcm80211/brcmsmac/phy_shim.c +++ b/drivers/net/wireless/broadcom/brcm80211/brcmsmac/phy_shim.c @@ -57,12 +57,11 @@ void wlc_phy_shim_detach(struct phy_shim_info *physhim) } struct wlapi_timer *wlapi_init_timer(struct phy_shim_info *physhim, - void (*fn)(struct brcms_phy *pi), + void (*fn)(void *pi), void *arg, const char *name) { return (struct wlapi_timer *) - brcms_init_timer(physhim->wl, (void (*)(void *))fn, - arg, name); + brcms_init_timer(physhim->wl, fn, arg, name); } void wlapi_free_timer(struct wlapi_timer *t) diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmsmac/phy_shim.h b/drivers/net/wireless/broadcom/brcm80211/brcmsmac/phy_shim.h index dd8774717ade..27d0934e600e 100644 --- a/drivers/net/wireless/broadcom/brcm80211/brcmsmac/phy_shim.h +++ b/drivers/net/wireless/broadcom/brcm80211/brcmsmac/phy_shim.h @@ -131,7 +131,7 @@ void wlc_phy_shim_detach(struct phy_shim_info *physhim); /* PHY to WL utility functions */ struct wlapi_timer *wlapi_init_timer(struct phy_shim_info *physhim, - void (*fn)(struct brcms_phy *pi), + void (*fn)(void *pi), void *arg, const char *name); void wlapi_free_timer(struct wlapi_timer *t); void wlapi_add_timer(struct wlapi_timer *t, uint ms, int periodic); -- cgit v1.2.3 From ca1e1163889395cae54c4f051c301a8a6d6de311 Mon Sep 17 00:00:00 2001 From: Ping-Ke Shih Date: Thu, 15 Feb 2024 13:57:38 +0800 Subject: wifi: rtw89: 8922a: add set_channel MAC part To set channel, add a function to get TXSB (TX subband) that is hardware index to indicate primary channel. Then, configure band, channel, bandwidth and TXSB via registers. Signed-off-by: Ping-Ke Shih Signed-off-by: Kalle Valo Link: https://msgid.link/20240215055741.14148-2-pkshih@realtek.com --- drivers/net/wireless/realtek/rtw89/phy.c | 47 ++++++++++++++ drivers/net/wireless/realtek/rtw89/phy.h | 2 + drivers/net/wireless/realtek/rtw89/reg.h | 33 +++++++++- drivers/net/wireless/realtek/rtw89/rtw8922a.c | 92 +++++++++++++++++++++++++++ 4 files changed, 173 insertions(+), 1 deletion(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/realtek/rtw89/phy.c b/drivers/net/wireless/realtek/rtw89/phy.c index 81f73821e3fc..dfbf59895e4e 100644 --- a/drivers/net/wireless/realtek/rtw89/phy.c +++ b/drivers/net/wireless/realtek/rtw89/phy.c @@ -725,6 +725,53 @@ u8 rtw89_phy_get_txsc(struct rtw89_dev *rtwdev, } EXPORT_SYMBOL(rtw89_phy_get_txsc); +u8 rtw89_phy_get_txsb(struct rtw89_dev *rtwdev, const struct rtw89_chan *chan, + enum rtw89_bandwidth dbw) +{ + enum rtw89_bandwidth cbw = chan->band_width; + u8 pri_ch = chan->primary_channel; + u8 central_ch = chan->channel; + u8 txsb_idx = 0; + + if (cbw == dbw || cbw == RTW89_CHANNEL_WIDTH_20) + return txsb_idx; + + switch (cbw) { + case RTW89_CHANNEL_WIDTH_40: + txsb_idx = pri_ch > central_ch ? 1 : 0; + break; + case RTW89_CHANNEL_WIDTH_80: + if (dbw == RTW89_CHANNEL_WIDTH_20) + txsb_idx = (pri_ch - central_ch + 6) / 4; + else + txsb_idx = pri_ch > central_ch ? 1 : 0; + break; + case RTW89_CHANNEL_WIDTH_160: + if (dbw == RTW89_CHANNEL_WIDTH_20) + txsb_idx = (pri_ch - central_ch + 14) / 4; + else if (dbw == RTW89_CHANNEL_WIDTH_40) + txsb_idx = (pri_ch - central_ch + 12) / 8; + else + txsb_idx = pri_ch > central_ch ? 1 : 0; + break; + case RTW89_CHANNEL_WIDTH_320: + if (dbw == RTW89_CHANNEL_WIDTH_20) + txsb_idx = (pri_ch - central_ch + 30) / 4; + else if (dbw == RTW89_CHANNEL_WIDTH_40) + txsb_idx = (pri_ch - central_ch + 28) / 8; + else if (dbw == RTW89_CHANNEL_WIDTH_80) + txsb_idx = (pri_ch - central_ch + 24) / 16; + else + txsb_idx = pri_ch > central_ch ? 1 : 0; + break; + default: + break; + } + + return txsb_idx; +} +EXPORT_SYMBOL(rtw89_phy_get_txsb); + static bool rtw89_phy_check_swsi_busy(struct rtw89_dev *rtwdev) { return !!rtw89_phy_read32_mask(rtwdev, R_SWSI_V1, B_SWSI_W_BUSY_V1) || diff --git a/drivers/net/wireless/realtek/rtw89/phy.h b/drivers/net/wireless/realtek/rtw89/phy.h index 76234daab896..de19f1c7f931 100644 --- a/drivers/net/wireless/realtek/rtw89/phy.h +++ b/drivers/net/wireless/realtek/rtw89/phy.h @@ -778,6 +778,8 @@ void rtw89_phy_write_reg3_tbl(struct rtw89_dev *rtwdev, u8 rtw89_phy_get_txsc(struct rtw89_dev *rtwdev, const struct rtw89_chan *chan, enum rtw89_bandwidth dbw); +u8 rtw89_phy_get_txsb(struct rtw89_dev *rtwdev, const struct rtw89_chan *chan, + enum rtw89_bandwidth dbw); u32 rtw89_phy_read_rf(struct rtw89_dev *rtwdev, enum rtw89_rf_path rf_path, u32 addr, u32 mask); u32 rtw89_phy_read_rf_v1(struct rtw89_dev *rtwdev, enum rtw89_rf_path rf_path, diff --git a/drivers/net/wireless/realtek/rtw89/reg.h b/drivers/net/wireless/realtek/rtw89/reg.h index 23a09efabab7..ae637203ee8a 100644 --- a/drivers/net/wireless/realtek/rtw89/reg.h +++ b/drivers/net/wireless/realtek/rtw89/reg.h @@ -5986,6 +5986,16 @@ B_BE_RMAC_CKEN | B_BE_TXTIME_CKEN | B_BE_RESP_PKTCTL_CKEN | \ B_BE_SIGB_CKEN) +#define R_BE_WMAC_RFMOD 0x10010 +#define R_BE_WMAC_RFMOD_C1 0x14010 +#define B_BE_CMAC_ASSERTION BIT(31) +#define B_BE_WMAC_RFMOD_MASK GENMASK(2, 0) +#define BE_WMAC_RFMOD_20M 0 +#define BE_WMAC_RFMOD_40M 1 +#define BE_WMAC_RFMOD_80M 2 +#define BE_WMAC_RFMOD_160M 3 +#define BE_WMAC_RFMOD_320M 4 + #define R_BE_TX_SUB_BAND_VALUE 0x10088 #define R_BE_TX_SUB_BAND_VALUE_C1 0x14088 #define B_BE_PRI20_BITMAP_MASK GENMASK(31, 16) @@ -6122,6 +6132,13 @@ #define B_BE_MACTX_LATENCY_MASK GENMASK(10, 8) #define B_BE_PREBKF_TIME_MASK GENMASK(4, 0) +#define R_BE_PREBKF_CFG_1 0x1033C +#define R_BE_PREBKF_CFG_1_C1 0x1433C +#define B_BE_SIFS_TIMEOUT_TB_AGGR_MASK GENMASK(31, 24) +#define B_BE_SIFS_PREBKF_MASK GENMASK(23, 16) +#define B_BE_SIFS_TIMEOUT_T2_MASK GENMASK(14, 8) +#define B_BE_SIFS_MACTXEN_T1_MASK GENMASK(6, 0) + #define R_BE_CCA_CFG_0 0x10340 #define R_BE_CCA_CFG_0_C1 0x14340 #define B_BE_R_SIFS_AGGR_TIME_V1_MASK GENMASK(31, 24) @@ -6163,9 +6180,12 @@ #define R_BE_MUEDCA_EN 0x10370 #define R_BE_MUEDCA_EN_C1 0x14370 +#define B_BE_SIFS_TIMEOUT_TB_T2_MASK GENMASK(30, 24) +#define B_BE_SIFS_MACTXEN_TB_T1_MASK GENMASK(22, 16) #define B_BE_MUEDCA_WMM_SEL BIT(8) -#define B_BE_SET_MUEDCATIMER_TF_1 BIT(5) +#define B_BE_SET_MUEDCATIMER_TF_MASK GENMASK(5, 4) #define B_BE_SET_MUEDCATIMER_TF_0 BIT(4) +#define B_BE_MUEDCA_EN_MASK GENMASK(1, 0) #define B_BE_MUEDCA_EN_0 BIT(0) #define R_BE_CTN_DRV_TXEN 0x10398 @@ -6419,6 +6439,17 @@ #define B_BE_SPEC_SIFS_OFDM_PTCL_MASK GENMASK(15, 8) #define B_BE_SPEC_SIFS_CCK_PTCL_MASK GENMASK(7, 0) +#define R_BE_TXRATE_CHK 0x10828 +#define R_BE_TXRATE_CHK_C1 0x14828 +#define B_BE_LATENCY_PADDING_PKT_TH_MASK GENMASK(31, 24) +#define B_BE_PLCP_FETCH_BUFF_MASK GENMASK(23, 16) +#define B_BE_OFDM_CCK_ERR_PROC BIT(6) +#define B_BE_PKT_LAST_TX BIT(5) +#define B_BE_BAND_MODE BIT(4) +#define B_BE_MAX_TXNSS_MASK GENMASK(3, 2) +#define B_BE_RTS_LIMIT_IN_OFDM6 BIT(1) +#define B_BE_CHECK_CCK_EN BIT(0) + #define R_BE_MBSSID_DROP_0 0x1083C #define R_BE_MBSSID_DROP_0_C1 0x1483C #define B_BE_GI_LTF_FB_SEL BIT(30) diff --git a/drivers/net/wireless/realtek/rtw89/rtw8922a.c b/drivers/net/wireless/realtek/rtw89/rtw8922a.c index 2f1e7767d58a..ac6fed211070 100644 --- a/drivers/net/wireless/realtek/rtw89/rtw8922a.c +++ b/drivers/net/wireless/realtek/rtw89/rtw8922a.c @@ -771,6 +771,97 @@ static void rtw8922a_power_trim(struct rtw89_dev *rtwdev) rtw8922a_pad_bias_trim(rtwdev); } +static void rtw8922a_set_channel_mac(struct rtw89_dev *rtwdev, + const struct rtw89_chan *chan, + u8 mac_idx) +{ + u32 sub_carr = rtw89_mac_reg_by_idx(rtwdev, R_BE_TX_SUB_BAND_VALUE, mac_idx); + u32 chk_rate = rtw89_mac_reg_by_idx(rtwdev, R_BE_TXRATE_CHK, mac_idx); + u32 rf_mod = rtw89_mac_reg_by_idx(rtwdev, R_BE_WMAC_RFMOD, mac_idx); + u8 txsb20 = 0, txsb40 = 0, txsb80 = 0; + u8 rf_mod_val, chk_rate_mask; + u32 txsb; + u32 reg; + + switch (chan->band_width) { + case RTW89_CHANNEL_WIDTH_160: + txsb80 = rtw89_phy_get_txsb(rtwdev, chan, RTW89_CHANNEL_WIDTH_80); + fallthrough; + case RTW89_CHANNEL_WIDTH_80: + txsb40 = rtw89_phy_get_txsb(rtwdev, chan, RTW89_CHANNEL_WIDTH_40); + fallthrough; + case RTW89_CHANNEL_WIDTH_40: + txsb20 = rtw89_phy_get_txsb(rtwdev, chan, RTW89_CHANNEL_WIDTH_20); + break; + default: + break; + } + + switch (chan->band_width) { + case RTW89_CHANNEL_WIDTH_160: + rf_mod_val = BE_WMAC_RFMOD_160M; + txsb = u32_encode_bits(txsb20, B_BE_TXSB_20M_MASK) | + u32_encode_bits(txsb40, B_BE_TXSB_40M_MASK) | + u32_encode_bits(txsb80, B_BE_TXSB_80M_MASK); + break; + case RTW89_CHANNEL_WIDTH_80: + rf_mod_val = BE_WMAC_RFMOD_80M; + txsb = u32_encode_bits(txsb20, B_BE_TXSB_20M_MASK) | + u32_encode_bits(txsb40, B_BE_TXSB_40M_MASK); + break; + case RTW89_CHANNEL_WIDTH_40: + rf_mod_val = BE_WMAC_RFMOD_40M; + txsb = u32_encode_bits(txsb20, B_BE_TXSB_20M_MASK); + break; + case RTW89_CHANNEL_WIDTH_20: + default: + rf_mod_val = BE_WMAC_RFMOD_20M; + txsb = 0; + break; + } + + if (txsb20 <= BE_PRI20_BITMAP_MAX) + txsb |= u32_encode_bits(BIT(txsb20), B_BE_PRI20_BITMAP_MASK); + + rtw89_write8_mask(rtwdev, rf_mod, B_BE_WMAC_RFMOD_MASK, rf_mod_val); + rtw89_write32(rtwdev, sub_carr, txsb); + + switch (chan->band_type) { + case RTW89_BAND_2G: + chk_rate_mask = B_BE_BAND_MODE; + break; + case RTW89_BAND_5G: + case RTW89_BAND_6G: + chk_rate_mask = B_BE_CHECK_CCK_EN | B_BE_RTS_LIMIT_IN_OFDM6; + break; + default: + rtw89_warn(rtwdev, "Invalid band_type:%d\n", chan->band_type); + return; + } + + rtw89_write8_clr(rtwdev, chk_rate, B_BE_BAND_MODE | B_BE_CHECK_CCK_EN | + B_BE_RTS_LIMIT_IN_OFDM6); + rtw89_write8_set(rtwdev, chk_rate, chk_rate_mask); + + switch (chan->band_width) { + case RTW89_CHANNEL_WIDTH_320: + case RTW89_CHANNEL_WIDTH_160: + case RTW89_CHANNEL_WIDTH_80: + case RTW89_CHANNEL_WIDTH_40: + reg = rtw89_mac_reg_by_idx(rtwdev, R_BE_PREBKF_CFG_1, mac_idx); + rtw89_write32_mask(rtwdev, reg, B_BE_SIFS_MACTXEN_T1_MASK, 0x41); + reg = rtw89_mac_reg_by_idx(rtwdev, R_BE_MUEDCA_EN, mac_idx); + rtw89_write32_mask(rtwdev, reg, B_BE_SIFS_MACTXEN_TB_T1_MASK, 0x41); + break; + default: + reg = rtw89_mac_reg_by_idx(rtwdev, R_BE_PREBKF_CFG_1, mac_idx); + rtw89_write32_mask(rtwdev, reg, B_BE_SIFS_MACTXEN_T1_MASK, 0x3f); + reg = rtw89_mac_reg_by_idx(rtwdev, R_BE_MUEDCA_EN, mac_idx); + rtw89_write32_mask(rtwdev, reg, B_BE_SIFS_MACTXEN_TB_T1_MASK, 0x3e); + break; + } +} + struct rtw8922a_bb_gain { u32 gain_g[BB_PATH_NUM_8922A]; u32 gain_a[BB_PATH_NUM_8922A]; @@ -1298,6 +1389,7 @@ static void rtw8922a_set_channel(struct rtw89_dev *rtwdev, enum rtw89_mac_idx mac_idx, enum rtw89_phy_idx phy_idx) { + rtw8922a_set_channel_mac(rtwdev, chan, mac_idx); rtw8922a_set_channel_bb(rtwdev, chan, phy_idx); } -- cgit v1.2.3 From f59cb1a030989ca0e5638fd4de91afddfbdbf89f Mon Sep 17 00:00:00 2001 From: Ping-Ke Shih Date: Thu, 15 Feb 2024 13:57:39 +0800 Subject: wifi: rtw89: 8922a: add set_channel BB part In additional to configure band, channel and bandwidth registers, it also configure CCK support on 2GHZ band, spur elimination, and RX gain. Signed-off-by: Ping-Ke Shih Signed-off-by: Kalle Valo Link: https://msgid.link/20240215055741.14148-3-pkshih@realtek.com --- drivers/net/wireless/realtek/rtw89/reg.h | 37 +++ drivers/net/wireless/realtek/rtw89/rtw8922a.c | 390 ++++++++++++++++++++++++++ 2 files changed, 427 insertions(+) (limited to 'drivers/net') diff --git a/drivers/net/wireless/realtek/rtw89/reg.h b/drivers/net/wireless/realtek/rtw89/reg.h index ae637203ee8a..9f3d10766b04 100644 --- a/drivers/net/wireless/realtek/rtw89/reg.h +++ b/drivers/net/wireless/realtek/rtw89/reg.h @@ -8448,6 +8448,9 @@ #define B_PATH1_5MDET_SB2 BIT(8) #define B_PATH1_5MDET_SB0 BIT(6) #define B_PATH1_5MDET_TH GENMASK(5, 0) +#define R_S0S1_CSI_WGT 0x4D34 +#define B_S0S1_CSI_WGT_EN BIT(0) +#define B_S0S1_CSI_WGT_TONE_IDX GENMASK(31, 20) #define R_CHINFO_ELM_SRC 0x4D84 #define B_CHINFO_ELM_BITMAP GENMASK(22, 0) #define B_CHINFO_SRC GENMASK(31, 30) @@ -8601,18 +8604,48 @@ #define B_S0_DACKQ8_K GENMASK(15, 8) #define R_DCFO_WEIGHT_V1 0x6244 #define B_DCFO_WEIGHT_MSK_V1 GENMASK(31, 28) +#define R_DAC_CLK 0x625C +#define B_DAC_CLK GENMASK(31, 30) #define R_DCFO_OPT_V1 0x6260 #define B_DCFO_OPT_EN_V1 BIT(17) #define R_TXFCTR 0x627C #define B_TXFCTR_THD GENMASK(19, 10) #define R_TXSCALE 0x6284 #define B_TXFCTR_EN BIT(19) +#define R_PCOEFF01 0x6684 +#define B_PCOEFF01 GENMASK(23, 0) +#define R_PCOEFF23 0x6688 +#define B_PCOEFF23 GENMASK(23, 0) +#define R_PCOEFF45 0x668c +#define B_PCOEFF45 GENMASK(23, 0) +#define R_PCOEFF67 0x6690 +#define B_PCOEFF67 GENMASK(23, 0) +#define R_PCOEFF89 0x6694 +#define B_PCOEFF89 GENMASK(23, 0) +#define R_PCOEFFAB 0x6698 +#define B_PCOEFFAB GENMASK(23, 0) +#define R_PCOEFFCD 0x669c +#define B_PCOEFFCD GENMASK(23, 0) +#define R_PCOEFFEF 0x66a0 +#define B_PCOEFFEF GENMASK(23, 0) +#define R_MGAIN_BIAS 0x672c +#define B_MGAIN_BIAS_BW20 GENMASK(3, 0) +#define B_MGAIN_BIAS_BW40 GENMASK(7, 4) +#define R_CCK_RPL_OFST 0x6750 +#define B_CCK_RPL_OFST GENMASK(7, 0) +#define R_BK_FC0INV 0x6758 +#define B_BK_FC0INV GENMASK(18, 0) +#define R_CCK_FC0INV 0x675c +#define B_CCK_FC0INV GENMASK(18, 0) #define R_SEG0R_EDCCA_LVL_BE 0x69EC #define R_SEG0R_PPDU_LVL_BE 0x69F0 #define R_SEGSND 0x6A14 #define B_SEGSND_EN BIT(31) #define R_DBCC 0x6B48 #define B_DBCC_EN BIT(0) +#define R_FC0 0x6B4C +#define B_BW40_2XFFT BIT(31) +#define B_FC0 GENMASK(12, 0) #define R_FC0INV_SBW 0x6B50 #define B_SMALLBW GENMASK(31, 30) #define B_RX_BT_SG0 GENMASK(25, 22) @@ -9040,6 +9073,10 @@ #define B_DACKN0_V GENMASK(21, 14) #define R_DACKN1_CTL 0xC224 #define B_DACKN1_V GENMASK(21, 14) +#define R_GAIN_MAP0 0xE44C +#define B_GAIN_MAP0_EN BIT(0) +#define R_GAIN_MAP1 0xE54C +#define B_GAIN_MAP1_EN BIT(0) #define R_GOTX_IQKDPK_C0 0xE464 #define R_GOTX_IQKDPK_C1 0xE564 #define B_GOTX_IQKDPK GENMASK(28, 27) diff --git a/drivers/net/wireless/realtek/rtw89/rtw8922a.c b/drivers/net/wireless/realtek/rtw89/rtw8922a.c index ac6fed211070..908d78bbc92c 100644 --- a/drivers/net/wireless/realtek/rtw89/rtw8922a.c +++ b/drivers/net/wireless/realtek/rtw89/rtw8922a.c @@ -11,6 +11,7 @@ #include "reg.h" #include "rtw8922a.h" #include "rtw8922a_rfk.h" +#include "util.h" #define RTW8922A_FW_FORMAT_MAX 0 #define RTW8922A_FW_BASENAME "rtw89/rtw8922a_fw" @@ -862,6 +863,37 @@ static void rtw8922a_set_channel_mac(struct rtw89_dev *rtwdev, } } +static const u32 rtw8922a_sco_barker_threshold[14] = { + 0x1fe4f, 0x1ff5e, 0x2006c, 0x2017b, 0x2028a, 0x20399, 0x204a8, 0x205b6, + 0x206c5, 0x207d4, 0x208e3, 0x209f2, 0x20b00, 0x20d8a +}; + +static const u32 rtw8922a_sco_cck_threshold[14] = { + 0x2bdac, 0x2bf21, 0x2c095, 0x2c209, 0x2c37e, 0x2c4f2, 0x2c666, 0x2c7db, + 0x2c94f, 0x2cac3, 0x2cc38, 0x2cdac, 0x2cf21, 0x2d29e +}; + +static int rtw8922a_ctrl_sco_cck(struct rtw89_dev *rtwdev, + u8 primary_ch, enum rtw89_bandwidth bw, + enum rtw89_phy_idx phy_idx) +{ + u8 ch_element; + + if (primary_ch >= 14) + return -EINVAL; + + ch_element = primary_ch - 1; + + rtw89_phy_write32_idx(rtwdev, R_BK_FC0INV, B_BK_FC0INV, + rtw8922a_sco_barker_threshold[ch_element], + phy_idx); + rtw89_phy_write32_idx(rtwdev, R_CCK_FC0INV, B_CCK_FC0INV, + rtw8922a_sco_cck_threshold[ch_element], + phy_idx); + + return 0; +} + struct rtw8922a_bb_gain { u32 gain_g[BB_PATH_NUM_8922A]; u32 gain_a[BB_PATH_NUM_8922A]; @@ -1022,12 +1054,341 @@ static void rtw8922a_set_gain(struct rtw89_dev *rtwdev, rtw8922a_set_rpl_gain(rtwdev, chan, path, phy_idx); } +static void rtw8922a_set_rx_gain_normal_cck(struct rtw89_dev *rtwdev, + const struct rtw89_chan *chan, + enum rtw89_rf_path path) +{ + struct rtw89_phy_efuse_gain *gain = &rtwdev->efuse_gain; + s8 value = -gain->offset[path][RTW89_GAIN_OFFSET_2G_CCK]; /* S(8,2) */ + u8 fraction = value & 0x3; + + if (fraction) { + rtw89_phy_write32_mask(rtwdev, R_MGAIN_BIAS, B_MGAIN_BIAS_BW20, + (0x4 - fraction) << 1); + rtw89_phy_write32_mask(rtwdev, R_MGAIN_BIAS, B_MGAIN_BIAS_BW40, + (0x4 - fraction) << 1); + + value >>= 2; + rtw89_phy_write32_mask(rtwdev, R_CCK_RPL_OFST, B_CCK_RPL_OFST, + value + 1 + 0xdc); + } else { + rtw89_phy_write32_mask(rtwdev, R_MGAIN_BIAS, B_MGAIN_BIAS_BW20, 0); + rtw89_phy_write32_mask(rtwdev, R_MGAIN_BIAS, B_MGAIN_BIAS_BW40, 0); + + value >>= 2; + rtw89_phy_write32_mask(rtwdev, R_CCK_RPL_OFST, B_CCK_RPL_OFST, + value + 0xdc); + } +} + +static void rtw8922a_set_rx_gain_normal_ofdm(struct rtw89_dev *rtwdev, + const struct rtw89_chan *chan, + enum rtw89_rf_path path) +{ + static const u32 rssi_tb_bias_comp[2] = {0x41f8, 0x45f8}; + static const u32 rssi_tb_ext_comp[2] = {0x4208, 0x4608}; + static const u32 rssi_ofst_addr[2] = {0x40c8, 0x44c8}; + static const u32 rpl_bias_comp[2] = {0x41e8, 0x45e8}; + static const u32 rpl_ext_comp[2] = {0x41f8, 0x45f8}; + struct rtw89_phy_efuse_gain *gain = &rtwdev->efuse_gain; + enum rtw89_gain_offset gain_band; + s8 v1, v2, v3; + s32 value; + + gain_band = rtw89_subband_to_gain_offset_band_of_ofdm(chan->subband_type); + value = gain->offset[path][gain_band]; + rtw89_phy_write32_mask(rtwdev, rssi_ofst_addr[path], 0xff000000, value + 0xF8); + + value *= -4; + v1 = clamp_t(s32, value, S8_MIN, S8_MAX); + value -= v1; + v2 = clamp_t(s32, value, S8_MIN, S8_MAX); + value -= v2; + v3 = clamp_t(s32, value, S8_MIN, S8_MAX); + + rtw89_phy_write32_mask(rtwdev, rpl_bias_comp[path], 0xff, v1); + rtw89_phy_write32_mask(rtwdev, rpl_ext_comp[path], 0xff, v2); + rtw89_phy_write32_mask(rtwdev, rpl_ext_comp[path], 0xff00, v3); + + rtw89_phy_write32_mask(rtwdev, rssi_tb_bias_comp[path], 0xff0000, v1); + rtw89_phy_write32_mask(rtwdev, rssi_tb_ext_comp[path], 0xff0000, v2); + rtw89_phy_write32_mask(rtwdev, rssi_tb_ext_comp[path], 0xff000000, v3); +} + +static void rtw8922a_set_rx_gain_normal(struct rtw89_dev *rtwdev, + const struct rtw89_chan *chan, + enum rtw89_rf_path path) +{ + struct rtw89_phy_efuse_gain *gain = &rtwdev->efuse_gain; + + if (!gain->offset_valid) + return; + + if (chan->band_type == RTW89_BAND_2G) + rtw8922a_set_rx_gain_normal_cck(rtwdev, chan, path); + + rtw8922a_set_rx_gain_normal_ofdm(rtwdev, chan, path); +} + +static void rtw8922a_set_cck_parameters(struct rtw89_dev *rtwdev, u8 central_ch, + enum rtw89_phy_idx phy_idx) +{ + if (central_ch == 14) { + rtw89_phy_write32_idx(rtwdev, R_PCOEFF01, B_PCOEFF01, 0x3b13ff, phy_idx); + rtw89_phy_write32_idx(rtwdev, R_PCOEFF23, B_PCOEFF23, 0x1c42de, phy_idx); + rtw89_phy_write32_idx(rtwdev, R_PCOEFF45, B_PCOEFF45, 0xfdb0ad, phy_idx); + rtw89_phy_write32_idx(rtwdev, R_PCOEFF67, B_PCOEFF67, 0xf60f6e, phy_idx); + rtw89_phy_write32_idx(rtwdev, R_PCOEFF89, B_PCOEFF89, 0xfd8f92, phy_idx); + rtw89_phy_write32_idx(rtwdev, R_PCOEFFAB, B_PCOEFFAB, 0x02d011, phy_idx); + rtw89_phy_write32_idx(rtwdev, R_PCOEFFCD, B_PCOEFFCD, 0x01c02c, phy_idx); + rtw89_phy_write32_idx(rtwdev, R_PCOEFFEF, B_PCOEFFEF, 0xfff00a, phy_idx); + } else { + rtw89_phy_write32_idx(rtwdev, R_PCOEFF01, B_PCOEFF01, 0x3a63ca, phy_idx); + rtw89_phy_write32_idx(rtwdev, R_PCOEFF23, B_PCOEFF23, 0x2a833f, phy_idx); + rtw89_phy_write32_idx(rtwdev, R_PCOEFF45, B_PCOEFF45, 0x1491f8, phy_idx); + rtw89_phy_write32_idx(rtwdev, R_PCOEFF67, B_PCOEFF67, 0x03c0b0, phy_idx); + rtw89_phy_write32_idx(rtwdev, R_PCOEFF89, B_PCOEFF89, 0xfccff1, phy_idx); + rtw89_phy_write32_idx(rtwdev, R_PCOEFFAB, B_PCOEFFAB, 0xfccfc3, phy_idx); + rtw89_phy_write32_idx(rtwdev, R_PCOEFFCD, B_PCOEFFCD, 0xfebfdc, phy_idx); + rtw89_phy_write32_idx(rtwdev, R_PCOEFFEF, B_PCOEFFEF, 0xffdff7, phy_idx); + } +} + static void rtw8922a_ctrl_ch(struct rtw89_dev *rtwdev, const struct rtw89_chan *chan, enum rtw89_phy_idx phy_idx) { + static const u32 band_sel[2] = {0x4160, 0x4560}; + u16 central_freq = chan->freq; + u8 central_ch = chan->channel; + u8 band = chan->band_type; + bool is_2g = band == RTW89_BAND_2G; + u8 chan_idx; + u8 path; + u8 sco; + + if (!central_freq) { + rtw89_warn(rtwdev, "Invalid central_freq\n"); + return; + } + rtw8922a_set_gain(rtwdev, chan, RF_PATH_A, phy_idx); rtw8922a_set_gain(rtwdev, chan, RF_PATH_B, phy_idx); + + for (path = RF_PATH_A; path < BB_PATH_NUM_8922A; path++) + rtw89_phy_write32_idx(rtwdev, band_sel[path], BIT((26)), is_2g, phy_idx); + + rtw8922a_set_rx_gain_normal(rtwdev, chan, RF_PATH_A); + rtw8922a_set_rx_gain_normal(rtwdev, chan, RF_PATH_B); + + rtw89_phy_write32_idx(rtwdev, R_FC0, B_FC0, central_freq, phy_idx); + sco = DIV_ROUND_CLOSEST(1 << 18, central_freq); + rtw89_phy_write32_idx(rtwdev, R_FC0INV_SBW, B_FC0_INV, sco, phy_idx); + + if (band == RTW89_BAND_2G) + rtw8922a_set_cck_parameters(rtwdev, central_ch, phy_idx); + + chan_idx = rtw89_encode_chan_idx(rtwdev, chan->primary_channel, band); + rtw89_phy_write32_idx(rtwdev, R_MAC_PIN_SEL, B_CH_IDX_SEG0, chan_idx, phy_idx); +} + +static void +rtw8922a_ctrl_bw(struct rtw89_dev *rtwdev, u8 pri_sb, u8 bw, + enum rtw89_phy_idx phy_idx) +{ + switch (bw) { + case RTW89_CHANNEL_WIDTH_5: + rtw89_phy_write32_idx(rtwdev, R_ANT_CHBW, B_CHBW_BW, 0x0, phy_idx); + rtw89_phy_write32_idx(rtwdev, R_FC0INV_SBW, B_SMALLBW, 0x1, phy_idx); + rtw89_phy_write32_idx(rtwdev, R_ANT_CHBW, B_CHBW_PRICH, 0x0, phy_idx); + rtw89_phy_write32_idx(rtwdev, R_DAC_CLK, B_DAC_CLK, 0x1, phy_idx); + rtw89_phy_write32_idx(rtwdev, R_GAIN_MAP0, B_GAIN_MAP0_EN, 0x0, phy_idx); + rtw89_phy_write32_idx(rtwdev, R_GAIN_MAP1, B_GAIN_MAP1_EN, 0x0, phy_idx); + break; + case RTW89_CHANNEL_WIDTH_10: + rtw89_phy_write32_idx(rtwdev, R_ANT_CHBW, B_CHBW_BW, 0x0, phy_idx); + rtw89_phy_write32_idx(rtwdev, R_FC0INV_SBW, B_SMALLBW, 0x2, phy_idx); + rtw89_phy_write32_idx(rtwdev, R_ANT_CHBW, B_CHBW_PRICH, 0x0, phy_idx); + rtw89_phy_write32_idx(rtwdev, R_DAC_CLK, B_DAC_CLK, 0x1, phy_idx); + rtw89_phy_write32_idx(rtwdev, R_GAIN_MAP0, B_GAIN_MAP0_EN, 0x0, phy_idx); + rtw89_phy_write32_idx(rtwdev, R_GAIN_MAP1, B_GAIN_MAP1_EN, 0x0, phy_idx); + break; + case RTW89_CHANNEL_WIDTH_20: + rtw89_phy_write32_idx(rtwdev, R_ANT_CHBW, B_CHBW_BW, 0x0, phy_idx); + rtw89_phy_write32_idx(rtwdev, R_FC0INV_SBW, B_SMALLBW, 0x0, phy_idx); + rtw89_phy_write32_idx(rtwdev, R_ANT_CHBW, B_CHBW_PRICH, 0x0, phy_idx); + rtw89_phy_write32_idx(rtwdev, R_DAC_CLK, B_DAC_CLK, 0x1, phy_idx); + rtw89_phy_write32_idx(rtwdev, R_GAIN_MAP0, B_GAIN_MAP0_EN, 0x0, phy_idx); + rtw89_phy_write32_idx(rtwdev, R_GAIN_MAP1, B_GAIN_MAP1_EN, 0x0, phy_idx); + break; + case RTW89_CHANNEL_WIDTH_40: + rtw89_phy_write32_idx(rtwdev, R_ANT_CHBW, B_CHBW_BW, 0x1, phy_idx); + rtw89_phy_write32_idx(rtwdev, R_FC0INV_SBW, B_SMALLBW, 0x0, phy_idx); + rtw89_phy_write32_idx(rtwdev, R_ANT_CHBW, B_CHBW_PRICH, pri_sb, phy_idx); + rtw89_phy_write32_idx(rtwdev, R_DAC_CLK, B_DAC_CLK, 0x1, phy_idx); + rtw89_phy_write32_idx(rtwdev, R_GAIN_MAP0, B_GAIN_MAP0_EN, 0x0, phy_idx); + rtw89_phy_write32_idx(rtwdev, R_GAIN_MAP1, B_GAIN_MAP1_EN, 0x0, phy_idx); + break; + case RTW89_CHANNEL_WIDTH_80: + rtw89_phy_write32_idx(rtwdev, R_ANT_CHBW, B_CHBW_BW, 0x2, phy_idx); + rtw89_phy_write32_idx(rtwdev, R_FC0INV_SBW, B_SMALLBW, 0x0, phy_idx); + rtw89_phy_write32_idx(rtwdev, R_ANT_CHBW, B_CHBW_PRICH, pri_sb, phy_idx); + rtw89_phy_write32_idx(rtwdev, R_DAC_CLK, B_DAC_CLK, 0x1, phy_idx); + rtw89_phy_write32_idx(rtwdev, R_GAIN_MAP0, B_GAIN_MAP0_EN, 0x1, phy_idx); + rtw89_phy_write32_idx(rtwdev, R_GAIN_MAP1, B_GAIN_MAP1_EN, 0x1, phy_idx); + break; + case RTW89_CHANNEL_WIDTH_160: + rtw89_phy_write32_idx(rtwdev, R_ANT_CHBW, B_CHBW_BW, 0x3, phy_idx); + rtw89_phy_write32_idx(rtwdev, R_FC0INV_SBW, B_SMALLBW, 0x0, phy_idx); + rtw89_phy_write32_idx(rtwdev, R_ANT_CHBW, B_CHBW_PRICH, pri_sb, phy_idx); + rtw89_phy_write32_idx(rtwdev, R_DAC_CLK, B_DAC_CLK, 0x1, phy_idx); + rtw89_phy_write32_idx(rtwdev, R_GAIN_MAP0, B_GAIN_MAP0_EN, 0x1, phy_idx); + rtw89_phy_write32_idx(rtwdev, R_GAIN_MAP1, B_GAIN_MAP1_EN, 0x1, phy_idx); + break; + default: + rtw89_warn(rtwdev, "Fail to switch bw (bw:%d, pri_sb:%d)\n", bw, + pri_sb); + break; + } + + if (bw == RTW89_CHANNEL_WIDTH_40) + rtw89_phy_write32_idx(rtwdev, R_FC0, B_BW40_2XFFT, 1, phy_idx); + else + rtw89_phy_write32_idx(rtwdev, R_FC0, B_BW40_2XFFT, 0, phy_idx); +} + +static u32 rtw8922a_spur_freq(struct rtw89_dev *rtwdev, + const struct rtw89_chan *chan) +{ + return 0; +} + +#define CARRIER_SPACING_312_5 312500 /* 312.5 kHz */ +#define CARRIER_SPACING_78_125 78125 /* 78.125 kHz */ +#define MAX_TONE_NUM 2048 + +static void rtw8922a_set_csi_tone_idx(struct rtw89_dev *rtwdev, + const struct rtw89_chan *chan, + enum rtw89_phy_idx phy_idx) +{ + s32 freq_diff, csi_idx, csi_tone_idx; + u32 spur_freq; + + spur_freq = rtw8922a_spur_freq(rtwdev, chan); + if (spur_freq == 0) { + rtw89_phy_write32_idx(rtwdev, R_S0S1_CSI_WGT, B_S0S1_CSI_WGT_EN, + 0, phy_idx); + return; + } + + freq_diff = (spur_freq - chan->freq) * 1000000; + csi_idx = s32_div_u32_round_closest(freq_diff, CARRIER_SPACING_78_125); + s32_div_u32_round_down(csi_idx, MAX_TONE_NUM, &csi_tone_idx); + + rtw89_phy_write32_idx(rtwdev, R_S0S1_CSI_WGT, B_S0S1_CSI_WGT_TONE_IDX, + csi_tone_idx, phy_idx); + rtw89_phy_write32_idx(rtwdev, R_S0S1_CSI_WGT, B_S0S1_CSI_WGT_EN, 1, phy_idx); +} + +static const struct rtw89_nbi_reg_def rtw8922a_nbi_reg_def[] = { + [RF_PATH_A] = { + .notch1_idx = {0x41a0, 0xFF}, + .notch1_frac_idx = {0x41a0, 0xC00}, + .notch1_en = {0x41a0, 0x1000}, + .notch2_idx = {0x41ac, 0xFF}, + .notch2_frac_idx = {0x41ac, 0xC00}, + .notch2_en = {0x41ac, 0x1000}, + }, + [RF_PATH_B] = { + .notch1_idx = {0x45a0, 0xFF}, + .notch1_frac_idx = {0x45a0, 0xC00}, + .notch1_en = {0x45a0, 0x1000}, + .notch2_idx = {0x45ac, 0xFF}, + .notch2_frac_idx = {0x45ac, 0xC00}, + .notch2_en = {0x45ac, 0x1000}, + }, +}; + +static void rtw8922a_set_nbi_tone_idx(struct rtw89_dev *rtwdev, + const struct rtw89_chan *chan, + enum rtw89_rf_path path, + enum rtw89_phy_idx phy_idx) +{ + const struct rtw89_nbi_reg_def *nbi = &rtw8922a_nbi_reg_def[path]; + s32 nbi_frac_idx, nbi_frac_tone_idx; + s32 nbi_idx, nbi_tone_idx; + bool notch2_chk = false; + u32 spur_freq, fc; + s32 freq_diff; + + spur_freq = rtw8922a_spur_freq(rtwdev, chan); + if (spur_freq == 0) { + rtw89_phy_write32_idx(rtwdev, nbi->notch1_en.addr, + nbi->notch1_en.mask, 0, phy_idx); + rtw89_phy_write32_idx(rtwdev, nbi->notch2_en.addr, + nbi->notch2_en.mask, 0, phy_idx); + return; + } + + fc = chan->freq; + if (chan->band_width == RTW89_CHANNEL_WIDTH_160) { + fc = (spur_freq > fc) ? fc + 40 : fc - 40; + if ((fc > spur_freq && + chan->channel < chan->primary_channel) || + (fc < spur_freq && + chan->channel > chan->primary_channel)) + notch2_chk = true; + } + + freq_diff = (spur_freq - fc) * 1000000; + nbi_idx = s32_div_u32_round_down(freq_diff, CARRIER_SPACING_312_5, + &nbi_frac_idx); + + if (chan->band_width == RTW89_CHANNEL_WIDTH_20) { + s32_div_u32_round_down(nbi_idx + 32, 64, &nbi_tone_idx); + } else { + u16 tone_para = (chan->band_width == RTW89_CHANNEL_WIDTH_40) ? + 128 : 256; + + s32_div_u32_round_down(nbi_idx, tone_para, &nbi_tone_idx); + } + nbi_frac_tone_idx = + s32_div_u32_round_closest(nbi_frac_idx, CARRIER_SPACING_78_125); + + if (chan->band_width == RTW89_CHANNEL_WIDTH_160 && notch2_chk) { + rtw89_phy_write32_idx(rtwdev, nbi->notch2_idx.addr, + nbi->notch2_idx.mask, nbi_tone_idx, phy_idx); + rtw89_phy_write32_idx(rtwdev, nbi->notch2_frac_idx.addr, + nbi->notch2_frac_idx.mask, nbi_frac_tone_idx, + phy_idx); + rtw89_phy_write32_idx(rtwdev, nbi->notch2_en.addr, + nbi->notch2_en.mask, 0, phy_idx); + rtw89_phy_write32_idx(rtwdev, nbi->notch2_en.addr, + nbi->notch2_en.mask, 1, phy_idx); + rtw89_phy_write32_idx(rtwdev, nbi->notch1_en.addr, + nbi->notch1_en.mask, 0, phy_idx); + } else { + rtw89_phy_write32_idx(rtwdev, nbi->notch1_idx.addr, + nbi->notch1_idx.mask, nbi_tone_idx, phy_idx); + rtw89_phy_write32_idx(rtwdev, nbi->notch1_frac_idx.addr, + nbi->notch1_frac_idx.mask, nbi_frac_tone_idx, + phy_idx); + rtw89_phy_write32_idx(rtwdev, nbi->notch1_en.addr, + nbi->notch1_en.mask, 0, phy_idx); + rtw89_phy_write32_idx(rtwdev, nbi->notch1_en.addr, + nbi->notch1_en.mask, 1, phy_idx); + rtw89_phy_write32_idx(rtwdev, nbi->notch2_en.addr, + nbi->notch2_en.mask, 0, phy_idx); + } +} + +static void rtw8922a_spur_elimination(struct rtw89_dev *rtwdev, + const struct rtw89_chan *chan, + enum rtw89_phy_idx phy_idx) +{ + rtw8922a_set_csi_tone_idx(rtwdev, chan, phy_idx); + rtw8922a_set_nbi_tone_idx(rtwdev, chan, RF_PATH_A, phy_idx); + rtw8922a_set_nbi_tone_idx(rtwdev, chan, RF_PATH_B, phy_idx); } static void rtw8922a_ctrl_afe_dac(struct rtw89_dev *rtwdev, enum rtw89_bandwidth bw, @@ -1377,11 +1738,40 @@ static void rtw8922a_bb_sethw(struct rtw89_dev *rtwdev) rtw8922a_ctrl_mlo(rtwdev, rtwdev->mlo_dbcc_mode); } +static void rtw8922a_ctrl_cck_en(struct rtw89_dev *rtwdev, bool cck_en, + enum rtw89_phy_idx phy_idx) +{ + if (cck_en) { + rtw89_phy_write32_idx(rtwdev, R_RXCCA_BE1, B_RXCCA_BE1_DIS, 0, phy_idx); + rtw89_phy_write32_idx(rtwdev, R_UPD_CLK_ADC, B_ENABLE_CCK, 1, phy_idx); + rtw89_phy_write32_idx(rtwdev, R_PD_ARBITER_OFF, B_PD_ARBITER_OFF, + 0, phy_idx); + } else { + rtw89_phy_write32_idx(rtwdev, R_RXCCA_BE1, B_RXCCA_BE1_DIS, 1, phy_idx); + rtw89_phy_write32_idx(rtwdev, R_UPD_CLK_ADC, B_ENABLE_CCK, 0, phy_idx); + rtw89_phy_write32_idx(rtwdev, R_PD_ARBITER_OFF, B_PD_ARBITER_OFF, + 1, phy_idx); + } +} + static void rtw8922a_set_channel_bb(struct rtw89_dev *rtwdev, const struct rtw89_chan *chan, enum rtw89_phy_idx phy_idx) { + bool cck_en = chan->band_type == RTW89_BAND_2G; + u8 pri_sb = chan->pri_sb_idx; + + if (cck_en) + rtw8922a_ctrl_sco_cck(rtwdev, chan->primary_channel, + chan->band_width, phy_idx); + rtw8922a_ctrl_ch(rtwdev, chan, phy_idx); + rtw8922a_ctrl_bw(rtwdev, pri_sb, chan->band_width, phy_idx); + rtw8922a_ctrl_cck_en(rtwdev, cck_en, phy_idx); + rtw8922a_spur_elimination(rtwdev, chan, phy_idx); + + rtw89_phy_write32_idx(rtwdev, R_RSTB_ASYNC, B_RSTB_ASYNC_ALL, 1, phy_idx); + rtw8922a_tssi_reset(rtwdev, RF_PATH_AB, phy_idx); } static void rtw8922a_set_channel(struct rtw89_dev *rtwdev, -- cgit v1.2.3 From 2c681cbf6c3a76ef3cdd9b33c3b1644caab209d1 Mon Sep 17 00:00:00 2001 From: Ping-Ke Shih Date: Thu, 15 Feb 2024 13:57:40 +0800 Subject: wifi: rtw89: 8922a: add set_channel RF part Configure RF registers according to band, channel, bandwidth. Since this chip will support MLO, it needs check the operating mode to decide paths we are going to configure. Signed-off-by: Ping-Ke Shih Signed-off-by: Kalle Valo Link: https://msgid.link/20240215055741.14148-4-pkshih@realtek.com --- drivers/net/wireless/realtek/rtw89/phy.c | 72 +++++++++++++ drivers/net/wireless/realtek/rtw89/phy.h | 4 + drivers/net/wireless/realtek/rtw89/reg.h | 8 ++ drivers/net/wireless/realtek/rtw89/rtw8922a.c | 1 + drivers/net/wireless/realtek/rtw89/rtw8922a_rfk.c | 120 ++++++++++++++++++++++ drivers/net/wireless/realtek/rtw89/rtw8922a_rfk.h | 3 + 6 files changed, 208 insertions(+) (limited to 'drivers/net') diff --git a/drivers/net/wireless/realtek/rtw89/phy.c b/drivers/net/wireless/realtek/rtw89/phy.c index dfbf59895e4e..12da63d64307 100644 --- a/drivers/net/wireless/realtek/rtw89/phy.c +++ b/drivers/net/wireless/realtek/rtw89/phy.c @@ -6378,6 +6378,78 @@ void rtw89_phy_edcca_track(struct rtw89_dev *rtwdev) rtw89_phy_edcca_log(rtwdev); } +enum rtw89_rf_path_bit rtw89_phy_get_kpath(struct rtw89_dev *rtwdev, + enum rtw89_phy_idx phy_idx) +{ + rtw89_debug(rtwdev, RTW89_DBG_RFK, + "[RFK] kpath dbcc_en: 0x%x, mode=0x%x, PHY%d\n", + rtwdev->dbcc_en, rtwdev->mlo_dbcc_mode, phy_idx); + + switch (rtwdev->mlo_dbcc_mode) { + case MLO_1_PLUS_1_1RF: + if (phy_idx == RTW89_PHY_0) + return RF_A; + else + return RF_B; + case MLO_1_PLUS_1_2RF: + if (phy_idx == RTW89_PHY_0) + return RF_A; + else + return RF_D; + case MLO_0_PLUS_2_1RF: + case MLO_2_PLUS_0_1RF: + if (phy_idx == RTW89_PHY_0) + return RF_AB; + else + return RF_AB; + case MLO_0_PLUS_2_2RF: + case MLO_2_PLUS_0_2RF: + case MLO_2_PLUS_2_2RF: + default: + if (phy_idx == RTW89_PHY_0) + return RF_AB; + else + return RF_CD; + } +} +EXPORT_SYMBOL(rtw89_phy_get_kpath); + +enum rtw89_rf_path rtw89_phy_get_syn_sel(struct rtw89_dev *rtwdev, + enum rtw89_phy_idx phy_idx) +{ + rtw89_debug(rtwdev, RTW89_DBG_RFK, + "[RFK] kpath dbcc_en: 0x%x, mode=0x%x, PHY%d\n", + rtwdev->dbcc_en, rtwdev->mlo_dbcc_mode, phy_idx); + + switch (rtwdev->mlo_dbcc_mode) { + case MLO_1_PLUS_1_1RF: + if (phy_idx == RTW89_PHY_0) + return RF_PATH_A; + else + return RF_PATH_B; + case MLO_1_PLUS_1_2RF: + if (phy_idx == RTW89_PHY_0) + return RF_PATH_A; + else + return RF_PATH_D; + case MLO_0_PLUS_2_1RF: + case MLO_2_PLUS_0_1RF: + if (phy_idx == RTW89_PHY_0) + return RF_PATH_A; + else + return RF_PATH_B; + case MLO_0_PLUS_2_2RF: + case MLO_2_PLUS_0_2RF: + case MLO_2_PLUS_2_2RF: + default: + if (phy_idx == RTW89_PHY_0) + return RF_PATH_A; + else + return RF_PATH_C; + } +} +EXPORT_SYMBOL(rtw89_phy_get_syn_sel); + static const struct rtw89_ccx_regs rtw89_ccx_regs_ax = { .setting_addr = R_CCX, .edcca_opt_mask = B_CCX_EDCCA_OPT_MSK, diff --git a/drivers/net/wireless/realtek/rtw89/phy.h b/drivers/net/wireless/realtek/rtw89/phy.h index de19f1c7f931..082231ebbee5 100644 --- a/drivers/net/wireless/realtek/rtw89/phy.h +++ b/drivers/net/wireless/realtek/rtw89/phy.h @@ -945,5 +945,9 @@ void rtw89_decode_chan_idx(struct rtw89_dev *rtwdev, u8 chan_idx, void rtw89_phy_config_edcca(struct rtw89_dev *rtwdev, bool scan); void rtw89_phy_edcca_track(struct rtw89_dev *rtwdev); void rtw89_phy_edcca_thre_calc(struct rtw89_dev *rtwdev); +enum rtw89_rf_path_bit rtw89_phy_get_kpath(struct rtw89_dev *rtwdev, + enum rtw89_phy_idx phy_idx); +enum rtw89_rf_path rtw89_phy_get_syn_sel(struct rtw89_dev *rtwdev, + enum rtw89_phy_idx phy_idx); #endif diff --git a/drivers/net/wireless/realtek/rtw89/reg.h b/drivers/net/wireless/realtek/rtw89/reg.h index 9f3d10766b04..37ccd8ffa87a 100644 --- a/drivers/net/wireless/realtek/rtw89/reg.h +++ b/drivers/net/wireless/realtek/rtw89/reg.h @@ -7497,6 +7497,12 @@ #define CFGCH_BAND0_2G 0 #define CFGCH_BAND0_5G 1 #define CFGCH_BAND0_6G 0 +#define RR_CFGCH_BW_V2 GENMASK(12, 10) +#define CFGCH_BW_V2_20M 0 +#define CFGCH_BW_V2_40M 1 +#define CFGCH_BW_V2_80M 2 +#define CFGCH_BW_V2_160M 3 +#define CFGCH_BW_V2_320M 4 #define RR_CFGCH_BW GENMASK(11, 10) #define RR_CFGCH_CH GENMASK(7, 0) #define CFGCH_BW_20M 3 @@ -7683,6 +7689,8 @@ #define RR_MMD 0xd5 #define RR_MMD_RST_EN BIT(8) #define RR_MMD_RST_SYN BIT(6) +#define RR_SMD 0xd6 +#define RR_VCO2 BIT(19) #define RR_IQKPLL 0xdc #define RR_IQKPLL_MOD GENMASK(9, 8) #define RR_SYNLUT 0xdd diff --git a/drivers/net/wireless/realtek/rtw89/rtw8922a.c b/drivers/net/wireless/realtek/rtw89/rtw8922a.c index 908d78bbc92c..7abd7256d1cb 100644 --- a/drivers/net/wireless/realtek/rtw89/rtw8922a.c +++ b/drivers/net/wireless/realtek/rtw89/rtw8922a.c @@ -1781,6 +1781,7 @@ static void rtw8922a_set_channel(struct rtw89_dev *rtwdev, { rtw8922a_set_channel_mac(rtwdev, chan, mac_idx); rtw8922a_set_channel_bb(rtwdev, chan, phy_idx); + rtw8922a_set_channel_rf(rtwdev, chan, phy_idx); } static void rtw8922a_dfs_en_idx(struct rtw89_dev *rtwdev, diff --git a/drivers/net/wireless/realtek/rtw89/rtw8922a_rfk.c b/drivers/net/wireless/realtek/rtw89/rtw8922a_rfk.c index d8ef986e7877..72953b7358df 100644 --- a/drivers/net/wireless/realtek/rtw89/rtw8922a_rfk.c +++ b/drivers/net/wireless/realtek/rtw89/rtw8922a_rfk.c @@ -34,6 +34,126 @@ void rtw8922a_tssi_cont_en_phyidx(struct rtw89_dev *rtwdev, bool en, u8 phy_idx) } } +static +void rtw8922a_ctl_band_ch_bw(struct rtw89_dev *rtwdev, enum rtw89_phy_idx phy, + u8 central_ch, enum rtw89_band band, + enum rtw89_bandwidth bw) +{ + const u32 rf_addr[2] = {RR_CFGCH, RR_CFGCH_V1}; + struct rtw89_hal *hal = &rtwdev->hal; + u32 rf_reg[RF_PATH_NUM_8922A][2]; + u8 synpath; + u32 rf18; + u8 kpath; + u8 path; + u8 i; + + rf_reg[RF_PATH_A][0] = rtw89_read_rf(rtwdev, RF_PATH_A, rf_addr[0], RFREG_MASK); + rf_reg[RF_PATH_A][1] = rtw89_read_rf(rtwdev, RF_PATH_A, rf_addr[1], RFREG_MASK); + rf_reg[RF_PATH_B][0] = rtw89_read_rf(rtwdev, RF_PATH_B, rf_addr[0], RFREG_MASK); + rf_reg[RF_PATH_B][1] = rtw89_read_rf(rtwdev, RF_PATH_B, rf_addr[1], RFREG_MASK); + + kpath = rtw89_phy_get_kpath(rtwdev, phy); + synpath = rtw89_phy_get_syn_sel(rtwdev, phy); + + rf18 = rtw89_read_rf(rtwdev, synpath, RR_CFGCH, RFREG_MASK); + if (rf18 == INV_RF_DATA) { + rtw89_warn(rtwdev, "[RFK] Invalid RF18 value\n"); + return; + } + + for (path = 0; path < RF_PATH_NUM_8922A; path++) { + if (!(kpath & BIT(path))) + continue; + + for (i = 0; i < 2; i++) { + if (rf_reg[path][i] == INV_RF_DATA) { + rtw89_warn(rtwdev, + "[RFK] Invalid RF_0x18 for Path-%d\n", path); + return; + } + + rf_reg[path][i] &= ~(RR_CFGCH_BAND1 | RR_CFGCH_BW | + RR_CFGCH_BAND0 | RR_CFGCH_CH); + rf_reg[path][i] |= u32_encode_bits(central_ch, RR_CFGCH_CH); + + if (band == RTW89_BAND_2G) + rtw89_write_rf(rtwdev, path, RR_SMD, RR_VCO2, 0x0); + else + rtw89_write_rf(rtwdev, path, RR_SMD, RR_VCO2, 0x1); + + switch (band) { + case RTW89_BAND_2G: + default: + break; + case RTW89_BAND_5G: + rf_reg[path][i] |= + u32_encode_bits(CFGCH_BAND1_5G, RR_CFGCH_BAND1) | + u32_encode_bits(CFGCH_BAND0_5G, RR_CFGCH_BAND0); + break; + case RTW89_BAND_6G: + rf_reg[path][i] |= + u32_encode_bits(CFGCH_BAND1_6G, RR_CFGCH_BAND1) | + u32_encode_bits(CFGCH_BAND0_6G, RR_CFGCH_BAND0); + break; + } + + switch (bw) { + case RTW89_CHANNEL_WIDTH_5: + case RTW89_CHANNEL_WIDTH_10: + case RTW89_CHANNEL_WIDTH_20: + default: + break; + case RTW89_CHANNEL_WIDTH_40: + rf_reg[path][i] |= + u32_encode_bits(CFGCH_BW_V2_40M, RR_CFGCH_BW_V2); + break; + case RTW89_CHANNEL_WIDTH_80: + rf_reg[path][i] |= + u32_encode_bits(CFGCH_BW_V2_80M, RR_CFGCH_BW_V2); + break; + case RTW89_CHANNEL_WIDTH_160: + rf_reg[path][i] |= + u32_encode_bits(CFGCH_BW_V2_160M, RR_CFGCH_BW_V2); + break; + case RTW89_CHANNEL_WIDTH_320: + rf_reg[path][i] |= + u32_encode_bits(CFGCH_BW_V2_320M, RR_CFGCH_BW_V2); + break; + } + + rtw89_write_rf(rtwdev, path, rf_addr[i], + RFREG_MASK, rf_reg[path][i]); + fsleep(100); + } + } + + if (hal->cv != CHIP_CAV) + return; + + if (band == RTW89_BAND_2G) { + rtw89_write_rf(rtwdev, RF_PATH_A, RR_LUTWE, RFREG_MASK, 0x80000); + rtw89_write_rf(rtwdev, RF_PATH_A, RR_LUTWA, RFREG_MASK, 0x00003); + rtw89_write_rf(rtwdev, RF_PATH_A, RR_LUTWD1, RFREG_MASK, 0x0c990); + rtw89_write_rf(rtwdev, RF_PATH_A, RR_LUTWD0, RFREG_MASK, 0xebe38); + rtw89_write_rf(rtwdev, RF_PATH_A, RR_LUTWE, RFREG_MASK, 0x00000); + } else { + rtw89_write_rf(rtwdev, RF_PATH_A, RR_LUTWE, RFREG_MASK, 0x80000); + rtw89_write_rf(rtwdev, RF_PATH_A, RR_LUTWA, RFREG_MASK, 0x00003); + rtw89_write_rf(rtwdev, RF_PATH_A, RR_LUTWD1, RFREG_MASK, 0x0c190); + rtw89_write_rf(rtwdev, RF_PATH_A, RR_LUTWD0, RFREG_MASK, 0xebe38); + rtw89_write_rf(rtwdev, RF_PATH_A, RR_LUTWE, RFREG_MASK, 0x00000); + } +} + +void rtw8922a_set_channel_rf(struct rtw89_dev *rtwdev, + const struct rtw89_chan *chan, + enum rtw89_phy_idx phy_idx) +{ + rtw8922a_ctl_band_ch_bw(rtwdev, phy_idx, chan->channel, chan->band_type, + chan->band_width); +} + enum _rf_syn_pow { RF_SYN_ON_OFF, RF_SYN_OFF_ON, diff --git a/drivers/net/wireless/realtek/rtw89/rtw8922a_rfk.h b/drivers/net/wireless/realtek/rtw89/rtw8922a_rfk.h index de5fa6c74530..27a2ff8166d0 100644 --- a/drivers/net/wireless/realtek/rtw89/rtw8922a_rfk.h +++ b/drivers/net/wireless/realtek/rtw89/rtw8922a_rfk.h @@ -8,6 +8,9 @@ #include "core.h" void rtw8922a_tssi_cont_en_phyidx(struct rtw89_dev *rtwdev, bool en, u8 phy_idx); +void rtw8922a_set_channel_rf(struct rtw89_dev *rtwdev, + const struct rtw89_chan *chan, + enum rtw89_phy_idx phy_idx); void rtw8922a_rfk_hw_init(struct rtw89_dev *rtwdev); #endif -- cgit v1.2.3 From 03830bb909a064bd590748127367878cf1d50fb0 Mon Sep 17 00:00:00 2001 From: Ping-Ke Shih Date: Thu, 15 Feb 2024 13:57:41 +0800 Subject: wifi: rtw89: 8922a: add helper of set_channel Reset hardware state to prevent hardware stays at abnormal state during setting channel. Besides, add preparation for MLO/DBCC before setting channel, and reconfigure registers after that. Signed-off-by: Ping-Ke Shih Signed-off-by: Kalle Valo Link: https://msgid.link/20240215055741.14148-5-pkshih@realtek.com --- drivers/net/wireless/realtek/rtw89/rtw8922a.c | 51 +++++++++++++++++++++++ drivers/net/wireless/realtek/rtw89/rtw8922a_rfk.c | 23 ++++++++++ drivers/net/wireless/realtek/rtw89/rtw8922a_rfk.h | 2 + 3 files changed, 76 insertions(+) (limited to 'drivers/net') diff --git a/drivers/net/wireless/realtek/rtw89/rtw8922a.c b/drivers/net/wireless/realtek/rtw89/rtw8922a.c index 7abd7256d1cb..823f0d840df9 100644 --- a/drivers/net/wireless/realtek/rtw89/rtw8922a.c +++ b/drivers/net/wireless/realtek/rtw89/rtw8922a.c @@ -1774,6 +1774,37 @@ static void rtw8922a_set_channel_bb(struct rtw89_dev *rtwdev, rtw8922a_tssi_reset(rtwdev, RF_PATH_AB, phy_idx); } +static void rtw8922a_pre_set_channel_bb(struct rtw89_dev *rtwdev, + enum rtw89_phy_idx phy_idx) +{ + if (!rtwdev->dbcc_en) + return; + + if (phy_idx == RTW89_PHY_0) { + rtw89_phy_write32_mask(rtwdev, R_DBCC, B_DBCC_EN, 0x0); + rtw89_phy_write32_mask(rtwdev, R_EMLSR, B_EMLSR_PARM, 0x6180); + rtw89_phy_write32_mask(rtwdev, R_EMLSR, B_EMLSR_PARM, 0xBBAB); + rtw89_phy_write32_mask(rtwdev, R_EMLSR, B_EMLSR_PARM, 0xABA9); + rtw89_phy_write32_mask(rtwdev, R_EMLSR, B_EMLSR_PARM, 0xEBA9); + rtw89_phy_write32_mask(rtwdev, R_EMLSR, B_EMLSR_PARM, 0xEAA9); + } else { + rtw89_phy_write32_mask(rtwdev, R_DBCC, B_DBCC_EN, 0x0); + rtw89_phy_write32_mask(rtwdev, R_EMLSR, B_EMLSR_PARM, 0xBBAB); + rtw89_phy_write32_mask(rtwdev, R_EMLSR, B_EMLSR_PARM, 0xAFFF); + rtw89_phy_write32_mask(rtwdev, R_EMLSR, B_EMLSR_PARM, 0xEFFF); + rtw89_phy_write32_mask(rtwdev, R_EMLSR, B_EMLSR_PARM, 0xEEFF); + } +} + +static void rtw8922a_post_set_channel_bb(struct rtw89_dev *rtwdev, + enum rtw89_mlo_dbcc_mode mode) +{ + if (!rtwdev->dbcc_en) + return; + + rtw8922a_ctrl_mlo(rtwdev, mode); +} + static void rtw8922a_set_channel(struct rtw89_dev *rtwdev, const struct rtw89_chan *chan, enum rtw89_mac_idx mac_idx, @@ -1863,6 +1894,25 @@ void rtw8922a_hal_reset(struct rtw89_dev *rtwdev, } } +static void rtw8922a_set_channel_help(struct rtw89_dev *rtwdev, bool enter, + struct rtw89_channel_help_params *p, + const struct rtw89_chan *chan, + enum rtw89_mac_idx mac_idx, + enum rtw89_phy_idx phy_idx) +{ + if (enter) { + rtw8922a_pre_set_channel_bb(rtwdev, phy_idx); + rtw8922a_pre_set_channel_rf(rtwdev, phy_idx); + } + + rtw8922a_hal_reset(rtwdev, phy_idx, mac_idx, chan->band_type, &p->tx_en, enter); + + if (!enter) { + rtw8922a_post_set_channel_bb(rtwdev, rtwdev->mlo_dbcc_mode); + rtw8922a_post_set_channel_rf(rtwdev, phy_idx); + } +} + static void rtw8922a_rfk_init(struct rtw89_dev *rtwdev) { struct rtw89_rfk_mcc_info *rfk_mcc = &rtwdev->rfk_mcc; @@ -2169,6 +2219,7 @@ static const struct rtw89_chip_ops rtw8922a_chip_ops = { .read_rf = rtw89_phy_read_rf_v2, .write_rf = rtw89_phy_write_rf_v2, .set_channel = rtw8922a_set_channel, + .set_channel_help = rtw8922a_set_channel_help, .read_efuse = rtw8922a_read_efuse, .read_phycap = rtw8922a_read_phycap, .fem_setup = NULL, diff --git a/drivers/net/wireless/realtek/rtw89/rtw8922a_rfk.c b/drivers/net/wireless/realtek/rtw89/rtw8922a_rfk.c index 72953b7358df..2a371829268c 100644 --- a/drivers/net/wireless/realtek/rtw89/rtw8922a_rfk.c +++ b/drivers/net/wireless/realtek/rtw89/rtw8922a_rfk.c @@ -353,3 +353,26 @@ void rtw8922a_rfk_hw_init(struct rtw89_dev *rtwdev) rtw8922a_rfk_pll_init(rtwdev); } + +void rtw8922a_pre_set_channel_rf(struct rtw89_dev *rtwdev, enum rtw89_phy_idx phy_idx) +{ + bool mlo_1_1; + + if (!rtwdev->dbcc_en) + return; + + mlo_1_1 = rtw89_is_mlo_1_1(rtwdev); + if (mlo_1_1) + rtw8922a_set_syn01(rtwdev, RF_SYN_ALLON); + else if (phy_idx == RTW89_PHY_0) + rtw8922a_set_syn01(rtwdev, RF_SYN_ON_OFF); + else + rtw8922a_set_syn01(rtwdev, RF_SYN_OFF_ON); + + fsleep(1000); +} + +void rtw8922a_post_set_channel_rf(struct rtw89_dev *rtwdev, enum rtw89_phy_idx phy_idx) +{ + rtw8922a_rfk_mlo_ctrl(rtwdev); +} diff --git a/drivers/net/wireless/realtek/rtw89/rtw8922a_rfk.h b/drivers/net/wireless/realtek/rtw89/rtw8922a_rfk.h index 27a2ff8166d0..66bdd57c1eea 100644 --- a/drivers/net/wireless/realtek/rtw89/rtw8922a_rfk.h +++ b/drivers/net/wireless/realtek/rtw89/rtw8922a_rfk.h @@ -12,5 +12,7 @@ void rtw8922a_set_channel_rf(struct rtw89_dev *rtwdev, const struct rtw89_chan *chan, enum rtw89_phy_idx phy_idx); void rtw8922a_rfk_hw_init(struct rtw89_dev *rtwdev); +void rtw8922a_pre_set_channel_rf(struct rtw89_dev *rtwdev, enum rtw89_phy_idx phy_idx); +void rtw8922a_post_set_channel_rf(struct rtw89_dev *rtwdev, enum rtw89_phy_idx phy_idx); #endif -- cgit v1.2.3 From 5d2dbccc2b3cec2db5af6b7305ca144b35200024 Mon Sep 17 00:00:00 2001 From: Alexis Lothoré Date: Thu, 15 Feb 2024 16:36:18 +0100 Subject: wifi: wilc1000: split deeply nested RCU list traversal in dedicated helper MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Move netif_wake_queue and its surrounding RCU operations in a dedicated function to clarify wilc_txq_task and ease refactoring Signed-off-by: Alexis Lothoré Signed-off-by: Kalle Valo Link: https://msgid.link/20240215-wilc_fix_rcu_usage-v1-1-f610e46c6f82@bootlin.com --- drivers/net/wireless/microchip/wilc1000/netdev.c | 25 +++++++++++++----------- 1 file changed, 14 insertions(+), 11 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/microchip/wilc1000/netdev.c b/drivers/net/wireless/microchip/wilc1000/netdev.c index 22f461f477f1..62414ab8846e 100644 --- a/drivers/net/wireless/microchip/wilc1000/netdev.c +++ b/drivers/net/wireless/microchip/wilc1000/netdev.c @@ -140,6 +140,19 @@ int wilc_wlan_get_num_conn_ifcs(struct wilc *wilc) return ret_val; } +static void wilc_wake_tx_queues(struct wilc *wl) +{ + int srcu_idx; + struct wilc_vif *ifc; + + srcu_idx = srcu_read_lock(&wl->srcu); + list_for_each_entry_rcu(ifc, &wl->vif_list, list) { + if (ifc->mac_opened && netif_queue_stopped(ifc->ndev)) + netif_wake_queue(ifc->ndev); + } + srcu_read_unlock(&wl->srcu, srcu_idx); +} + static int wilc_txq_task(void *vp) { int ret; @@ -160,17 +173,7 @@ static int wilc_txq_task(void *vp) do { ret = wilc_wlan_handle_txq(wl, &txq_count); if (txq_count < FLOW_CONTROL_LOWER_THRESHOLD) { - int srcu_idx; - struct wilc_vif *ifc; - - srcu_idx = srcu_read_lock(&wl->srcu); - list_for_each_entry_rcu(ifc, &wl->vif_list, - list) { - if (ifc->mac_opened && - netif_queue_stopped(ifc->ndev)) - netif_wake_queue(ifc->ndev); - } - srcu_read_unlock(&wl->srcu, srcu_idx); + wilc_wake_tx_queues(wl); } if (ret != WILC_VMM_ENTRY_FULL_RETRY) break; -- cgit v1.2.3 From 059d0e3876abacd3967d22b6c59ff1e52d1c10ae Mon Sep 17 00:00:00 2001 From: Alexis Lothoré Date: Thu, 15 Feb 2024 16:36:19 +0100 Subject: wifi: wilc1000: use SRCU instead of RCU for vif list traversal MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Enabling CONFIG_PROVE_RCU_LIST raises many warnings in wilc driver, even on some places already protected by a read critical section. An example of such case is in wilc_get_available_idx: ============================= WARNING: suspicious RCU usage 6.8.0-rc1+ #32 Not tainted ----------------------------- drivers/net/wireless/microchip/wilc1000/netdev.c:944 RCU-list traversed in non-reader section!! [...] stack backtrace: CPU: 0 PID: 26 Comm: kworker/0:3 Not tainted 6.8.0-rc1+ #32 Hardware name: Atmel SAMA5 Workqueue: events_freezable mmc_rescan unwind_backtrace from show_stack+0x18/0x1c show_stack from dump_stack_lvl+0x34/0x58 dump_stack_lvl from wilc_netdev_ifc_init+0x788/0x8ec wilc_netdev_ifc_init from wilc_cfg80211_init+0x690/0x910 wilc_cfg80211_init from wilc_sdio_probe+0x168/0x490 wilc_sdio_probe from sdio_bus_probe+0x230/0x3f4 sdio_bus_probe from really_probe+0x270/0xdf4 really_probe from __driver_probe_device+0x1dc/0x580 __driver_probe_device from driver_probe_device+0x60/0x140 driver_probe_device from __device_attach_driver+0x268/0x364 __device_attach_driver from bus_for_each_drv+0x15c/0x1cc bus_for_each_drv from __device_attach+0x1ec/0x3e8 __device_attach from bus_probe_device+0x190/0x1c0 bus_probe_device from device_add+0x10dc/0x18e4 device_add from sdio_add_func+0x1c0/0x2c0 sdio_add_func from mmc_attach_sdio+0xa08/0xe1c mmc_attach_sdio from mmc_rescan+0xa00/0xfe0 mmc_rescan from process_one_work+0x8d4/0x169c process_one_work from worker_thread+0x8cc/0x1340 worker_thread from kthread+0x448/0x510 kthread from ret_from_fork+0x14/0x28 This warning is due to the section being protected by a srcu critical read section, but the list traversal being done with classic RCU API. Fix the warning by using corresponding SRCU read lock/unlock APIs. While doing so, since we always manipulate the same list (managed through a pointer embedded in struct_wilc), add a macro to reduce the corresponding boilerplate in each call site. Signed-off-by: Alexis Lothoré Signed-off-by: Kalle Valo Link: https://msgid.link/20240215-wilc_fix_rcu_usage-v1-2-f610e46c6f82@bootlin.com --- drivers/net/wireless/microchip/wilc1000/cfg80211.c | 2 +- drivers/net/wireless/microchip/wilc1000/hif.c | 2 +- drivers/net/wireless/microchip/wilc1000/netdev.c | 14 +++++++------- drivers/net/wireless/microchip/wilc1000/netdev.h | 6 ++++++ drivers/net/wireless/microchip/wilc1000/wlan.c | 2 +- 5 files changed, 16 insertions(+), 10 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/microchip/wilc1000/cfg80211.c b/drivers/net/wireless/microchip/wilc1000/cfg80211.c index f03fd15c0c97..33f8e3a41937 100644 --- a/drivers/net/wireless/microchip/wilc1000/cfg80211.c +++ b/drivers/net/wireless/microchip/wilc1000/cfg80211.c @@ -1518,7 +1518,7 @@ static struct wilc_vif *wilc_get_vif_from_type(struct wilc *wl, int type) { struct wilc_vif *vif; - list_for_each_entry_rcu(vif, &wl->vif_list, list) { + wilc_for_each_vif(wl, vif) { if (vif->iftype == type) return vif; } diff --git a/drivers/net/wireless/microchip/wilc1000/hif.c b/drivers/net/wireless/microchip/wilc1000/hif.c index d2b8c2630819..f3800aa9e9f8 100644 --- a/drivers/net/wireless/microchip/wilc1000/hif.c +++ b/drivers/net/wireless/microchip/wilc1000/hif.c @@ -107,7 +107,7 @@ static struct wilc_vif *wilc_get_vif_from_idx(struct wilc *wilc, int idx) if (index < 0 || index >= WILC_NUM_CONCURRENT_IFC) return NULL; - list_for_each_entry_rcu(vif, &wilc->vif_list, list) { + wilc_for_each_vif(wilc, vif) { if (vif->idx == index) return vif; } diff --git a/drivers/net/wireless/microchip/wilc1000/netdev.c b/drivers/net/wireless/microchip/wilc1000/netdev.c index 62414ab8846e..96f239adc078 100644 --- a/drivers/net/wireless/microchip/wilc1000/netdev.c +++ b/drivers/net/wireless/microchip/wilc1000/netdev.c @@ -96,7 +96,7 @@ static struct net_device *get_if_handler(struct wilc *wilc, u8 *mac_header) struct wilc_vif *vif; struct ieee80211_hdr *h = (struct ieee80211_hdr *)mac_header; - list_for_each_entry_rcu(vif, &wilc->vif_list, list) { + wilc_for_each_vif(wilc, vif) { if (vif->iftype == WILC_STATION_MODE) if (ether_addr_equal_unaligned(h->addr2, vif->bssid)) { ndev = vif->ndev; @@ -132,7 +132,7 @@ int wilc_wlan_get_num_conn_ifcs(struct wilc *wilc) struct wilc_vif *vif; srcu_idx = srcu_read_lock(&wilc->srcu); - list_for_each_entry_rcu(vif, &wilc->vif_list, list) { + wilc_for_each_vif(wilc, vif) { if (!is_zero_ether_addr(vif->bssid)) ret_val++; } @@ -146,7 +146,7 @@ static void wilc_wake_tx_queues(struct wilc *wl) struct wilc_vif *ifc; srcu_idx = srcu_read_lock(&wl->srcu); - list_for_each_entry_rcu(ifc, &wl->vif_list, list) { + wilc_for_each_vif(wl, ifc) { if (ifc->mac_opened && netif_queue_stopped(ifc->ndev)) netif_wake_queue(ifc->ndev); } @@ -668,7 +668,7 @@ static int wilc_set_mac_addr(struct net_device *dev, void *p) /* Verify MAC Address is not already in use: */ srcu_idx = srcu_read_lock(&wilc->srcu); - list_for_each_entry_rcu(tmp_vif, &wilc->vif_list, list) { + wilc_for_each_vif(wilc, tmp_vif) { wilc_get_mac_address(tmp_vif, mac_addr); if (ether_addr_equal(addr->sa_data, mac_addr)) { if (vif != tmp_vif) { @@ -771,7 +771,7 @@ netdev_tx_t wilc_mac_xmit(struct sk_buff *skb, struct net_device *ndev) struct wilc_vif *vif; srcu_idx = srcu_read_lock(&wilc->srcu); - list_for_each_entry_rcu(vif, &wilc->vif_list, list) { + wilc_for_each_vif(wilc, vif) { if (vif->mac_opened) netif_stop_queue(vif->ndev); } @@ -858,7 +858,7 @@ void wilc_wfi_mgmt_rx(struct wilc *wilc, u8 *buff, u32 size, bool is_auth) struct wilc_vif *vif; srcu_idx = srcu_read_lock(&wilc->srcu); - list_for_each_entry_rcu(vif, &wilc->vif_list, list) { + wilc_for_each_vif(wilc, vif) { struct ieee80211_mgmt *mgmt = (struct ieee80211_mgmt *)buff; u16 type = le16_to_cpup((__le16 *)buff); u32 type_bit = BIT(type >> 4); @@ -930,7 +930,7 @@ static u8 wilc_get_available_idx(struct wilc *wl) int srcu_idx; srcu_idx = srcu_read_lock(&wl->srcu); - list_for_each_entry_rcu(vif, &wl->vif_list, list) { + wilc_for_each_vif(wl, vif) { if (vif->idx == 0) idx = 1; else diff --git a/drivers/net/wireless/microchip/wilc1000/netdev.h b/drivers/net/wireless/microchip/wilc1000/netdev.h index aafe3dc44ac6..5937d6d45695 100644 --- a/drivers/net/wireless/microchip/wilc1000/netdev.h +++ b/drivers/net/wireless/microchip/wilc1000/netdev.h @@ -13,6 +13,7 @@ #include #include #include +#include #include "hif.h" #include "wlan.h" @@ -29,6 +30,11 @@ #define TX_BACKOFF_WEIGHT_MS 1 +#define wilc_for_each_vif(w, v) \ + struct wilc *_w = w; \ + list_for_each_entry_srcu(v, &_w->vif_list, list, \ + srcu_read_lock_held(&_w->srcu)) + struct wilc_wfi_stats { unsigned long rx_packets; unsigned long tx_packets; diff --git a/drivers/net/wireless/microchip/wilc1000/wlan.c b/drivers/net/wireless/microchip/wilc1000/wlan.c index 68be233c36ce..a9e872a7b2c3 100644 --- a/drivers/net/wireless/microchip/wilc1000/wlan.c +++ b/drivers/net/wireless/microchip/wilc1000/wlan.c @@ -725,7 +725,7 @@ int wilc_wlan_handle_txq(struct wilc *wilc, u32 *txq_count) mutex_lock(&wilc->txq_add_to_head_cs); srcu_idx = srcu_read_lock(&wilc->srcu); - list_for_each_entry_rcu(vif, &wilc->vif_list, list) + wilc_for_each_vif(wilc, vif) wilc_wlan_txq_filter_dup_tcp_ack(vif->ndev); srcu_read_unlock(&wilc->srcu, srcu_idx); -- cgit v1.2.3 From 51e4aa8c449b4c3821170f5438d084bafb003bea Mon Sep 17 00:00:00 2001 From: Alexis Lothoré Date: Thu, 15 Feb 2024 16:36:20 +0100 Subject: wifi: wilc1000: fix declarations ordering MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Fix reverse-christmas tree order in some functions before adding more variables Signed-off-by: Alexis Lothoré Signed-off-by: Kalle Valo Link: https://msgid.link/20240215-wilc_fix_rcu_usage-v1-3-f610e46c6f82@bootlin.com --- drivers/net/wireless/microchip/wilc1000/hif.c | 16 ++++++++-------- drivers/net/wireless/microchip/wilc1000/netdev.c | 6 +++--- 2 files changed, 11 insertions(+), 11 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/microchip/wilc1000/hif.c b/drivers/net/wireless/microchip/wilc1000/hif.c index f3800aa9e9f8..c42859a727c3 100644 --- a/drivers/net/wireless/microchip/wilc1000/hif.c +++ b/drivers/net/wireless/microchip/wilc1000/hif.c @@ -1567,11 +1567,11 @@ int wilc_deinit(struct wilc_vif *vif) void wilc_network_info_received(struct wilc *wilc, u8 *buffer, u32 length) { - int result; - struct host_if_msg *msg; - int id; struct host_if_drv *hif_drv; + struct host_if_msg *msg; struct wilc_vif *vif; + int result; + int id; id = get_unaligned_le32(&buffer[length - 4]); vif = wilc_get_vif_from_idx(wilc, id); @@ -1608,11 +1608,11 @@ void wilc_network_info_received(struct wilc *wilc, u8 *buffer, u32 length) void wilc_gnrl_async_info_received(struct wilc *wilc, u8 *buffer, u32 length) { - int result; - struct host_if_msg *msg; - int id; struct host_if_drv *hif_drv; + struct host_if_msg *msg; struct wilc_vif *vif; + int result; + int id; mutex_lock(&wilc->deinit_lock); @@ -1654,10 +1654,10 @@ void wilc_gnrl_async_info_received(struct wilc *wilc, u8 *buffer, u32 length) void wilc_scan_complete_received(struct wilc *wilc, u8 *buffer, u32 length) { - int result; - int id; struct host_if_drv *hif_drv; struct wilc_vif *vif; + int result; + int id; id = get_unaligned_le32(&buffer[length - 4]); vif = wilc_get_vif_from_idx(wilc, id); diff --git a/drivers/net/wireless/microchip/wilc1000/netdev.c b/drivers/net/wireless/microchip/wilc1000/netdev.c index 96f239adc078..092801d33915 100644 --- a/drivers/net/wireless/microchip/wilc1000/netdev.c +++ b/drivers/net/wireless/microchip/wilc1000/netdev.c @@ -814,12 +814,12 @@ static int wilc_mac_close(struct net_device *ndev) void wilc_frmw_to_host(struct wilc *wilc, u8 *buff, u32 size, u32 pkt_offset) { - unsigned int frame_len = 0; - int stats; unsigned char *buff_to_send = NULL; - struct sk_buff *skb; struct net_device *wilc_netdev; + unsigned int frame_len = 0; struct wilc_vif *vif; + struct sk_buff *skb; + int stats; if (!wilc) return; -- cgit v1.2.3 From dd66185c23f71af36397bebfc99ede608dca07b6 Mon Sep 17 00:00:00 2001 From: Ajay Singh Date: Thu, 15 Feb 2024 16:36:21 +0100 Subject: wifi: wilc1000: add missing read critical sections around vif list traversal MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Some code manipulating the vif list is still missing some srcu_read_lock / srcu_read_unlock, and so can trigger RCU warnings: ============================= WARNING: suspicious RCU usage 6.8.0-rc1+ #37 Not tainted ----------------------------- drivers/net/wireless/microchip/wilc1000/hif.c:110 RCU-list traversed without holding the required lock!! [...] stack backtrace: CPU: 0 PID: 6 Comm: kworker/0:0 Not tainted 6.8.0-rc1+ #37 Hardware name: Atmel SAMA5 Workqueue: events sdio_irq_work unwind_backtrace from show_stack+0x18/0x1c show_stack from dump_stack_lvl+0x34/0x58 dump_stack_lvl from wilc_get_vif_from_idx+0x158/0x180 wilc_get_vif_from_idx from wilc_network_info_received+0x80/0x48c wilc_network_info_received from wilc_handle_isr+0xa10/0xd30 wilc_handle_isr from wilc_sdio_interrupt+0x44/0x58 wilc_sdio_interrupt from process_sdio_pending_irqs+0x1c8/0x60c process_sdio_pending_irqs from sdio_irq_work+0x6c/0x14c sdio_irq_work from process_one_work+0x8d4/0x169c process_one_work from worker_thread+0x8cc/0x1340 worker_thread from kthread+0x448/0x510 kthread from ret_from_fork+0x14/0x28 Fix those warnings by adding the needed lock around the corresponding critical sections Signed-off-by: Ajay Singh Co-developed-by: Alexis Lothoré Signed-off-by: Alexis Lothoré Signed-off-by: Kalle Valo Link: https://msgid.link/20240215-wilc_fix_rcu_usage-v1-4-f610e46c6f82@bootlin.com --- drivers/net/wireless/microchip/wilc1000/hif.c | 52 +++++++++++++----------- drivers/net/wireless/microchip/wilc1000/netdev.c | 8 +++- 2 files changed, 35 insertions(+), 25 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/microchip/wilc1000/hif.c b/drivers/net/wireless/microchip/wilc1000/hif.c index c42859a727c3..f1085ccb7eed 100644 --- a/drivers/net/wireless/microchip/wilc1000/hif.c +++ b/drivers/net/wireless/microchip/wilc1000/hif.c @@ -1570,23 +1570,25 @@ void wilc_network_info_received(struct wilc *wilc, u8 *buffer, u32 length) struct host_if_drv *hif_drv; struct host_if_msg *msg; struct wilc_vif *vif; + int srcu_idx; int result; int id; id = get_unaligned_le32(&buffer[length - 4]); + srcu_idx = srcu_read_lock(&wilc->srcu); vif = wilc_get_vif_from_idx(wilc, id); if (!vif) - return; - hif_drv = vif->hif_drv; + goto out; + hif_drv = vif->hif_drv; if (!hif_drv) { netdev_err(vif->ndev, "driver not init[%p]\n", hif_drv); - return; + goto out; } msg = wilc_alloc_work(vif, handle_rcvd_ntwrk_info, false); if (IS_ERR(msg)) - return; + goto out; msg->body.net_info.frame_len = get_unaligned_le16(&buffer[6]) - 1; msg->body.net_info.rssi = buffer[8]; @@ -1595,7 +1597,7 @@ void wilc_network_info_received(struct wilc *wilc, u8 *buffer, u32 length) GFP_KERNEL); if (!msg->body.net_info.mgmt) { kfree(msg); - return; + goto out; } result = wilc_enqueue_work(msg); @@ -1604,6 +1606,8 @@ void wilc_network_info_received(struct wilc *wilc, u8 *buffer, u32 length) kfree(msg->body.net_info.mgmt); kfree(msg); } +out: + srcu_read_unlock(&wilc->srcu, srcu_idx); } void wilc_gnrl_async_info_received(struct wilc *wilc, u8 *buffer, u32 length) @@ -1611,36 +1615,32 @@ void wilc_gnrl_async_info_received(struct wilc *wilc, u8 *buffer, u32 length) struct host_if_drv *hif_drv; struct host_if_msg *msg; struct wilc_vif *vif; + int srcu_idx; int result; int id; mutex_lock(&wilc->deinit_lock); id = get_unaligned_le32(&buffer[length - 4]); + srcu_idx = srcu_read_lock(&wilc->srcu); vif = wilc_get_vif_from_idx(wilc, id); - if (!vif) { - mutex_unlock(&wilc->deinit_lock); - return; - } + if (!vif) + goto out; hif_drv = vif->hif_drv; if (!hif_drv) { - mutex_unlock(&wilc->deinit_lock); - return; + goto out; } if (!hif_drv->conn_info.conn_result) { netdev_err(vif->ndev, "%s: conn_result is NULL\n", __func__); - mutex_unlock(&wilc->deinit_lock); - return; + goto out; } msg = wilc_alloc_work(vif, handle_rcvd_gnrl_async_info, false); - if (IS_ERR(msg)) { - mutex_unlock(&wilc->deinit_lock); - return; - } + if (IS_ERR(msg)) + goto out; msg->body.mac_info.status = buffer[7]; result = wilc_enqueue_work(msg); @@ -1648,7 +1648,8 @@ void wilc_gnrl_async_info_received(struct wilc *wilc, u8 *buffer, u32 length) netdev_err(vif->ndev, "%s: enqueue work failed\n", __func__); kfree(msg); } - +out: + srcu_read_unlock(&wilc->srcu, srcu_idx); mutex_unlock(&wilc->deinit_lock); } @@ -1656,24 +1657,27 @@ void wilc_scan_complete_received(struct wilc *wilc, u8 *buffer, u32 length) { struct host_if_drv *hif_drv; struct wilc_vif *vif; + int srcu_idx; int result; int id; id = get_unaligned_le32(&buffer[length - 4]); + srcu_idx = srcu_read_lock(&wilc->srcu); vif = wilc_get_vif_from_idx(wilc, id); if (!vif) - return; - hif_drv = vif->hif_drv; + goto out; - if (!hif_drv) - return; + hif_drv = vif->hif_drv; + if (!hif_drv) { + goto out; + } if (hif_drv->usr_scan_req.scan_result) { struct host_if_msg *msg; msg = wilc_alloc_work(vif, handle_scan_complete, false); if (IS_ERR(msg)) - return; + goto out; result = wilc_enqueue_work(msg); if (result) { @@ -1682,6 +1686,8 @@ void wilc_scan_complete_received(struct wilc *wilc, u8 *buffer, u32 length) kfree(msg); } } +out: + srcu_read_unlock(&wilc->srcu, srcu_idx); } int wilc_remain_on_channel(struct wilc_vif *vif, u64 cookie, u16 chan, diff --git a/drivers/net/wireless/microchip/wilc1000/netdev.c b/drivers/net/wireless/microchip/wilc1000/netdev.c index 092801d33915..710e29bea560 100644 --- a/drivers/net/wireless/microchip/wilc1000/netdev.c +++ b/drivers/net/wireless/microchip/wilc1000/netdev.c @@ -819,14 +819,16 @@ void wilc_frmw_to_host(struct wilc *wilc, u8 *buff, u32 size, unsigned int frame_len = 0; struct wilc_vif *vif; struct sk_buff *skb; + int srcu_idx; int stats; if (!wilc) return; + srcu_idx = srcu_read_lock(&wilc->srcu); wilc_netdev = get_if_handler(wilc, buff); if (!wilc_netdev) - return; + goto out; buff += pkt_offset; vif = netdev_priv(wilc_netdev); @@ -837,7 +839,7 @@ void wilc_frmw_to_host(struct wilc *wilc, u8 *buff, u32 size, skb = dev_alloc_skb(frame_len); if (!skb) - return; + goto out; skb->dev = wilc_netdev; @@ -850,6 +852,8 @@ void wilc_frmw_to_host(struct wilc *wilc, u8 *buff, u32 size, stats = netif_rx(skb); netdev_dbg(wilc_netdev, "netif_rx ret value is: %d\n", stats); } +out: + srcu_read_unlock(&wilc->srcu, srcu_idx); } void wilc_wfi_mgmt_rx(struct wilc *wilc, u8 *buff, u32 size, bool is_auth) -- cgit v1.2.3